.unloaded` | Plugin déchargé | `{"name"}` | Cleanup |
-| `permission.deny` | Permission refusée | `{"plugin", "resource", "action"}` | Audit sécurité |
-| `security.violation` | Scan AST échoué | `{"plugin", "errors"}` | Alertes sécurité |
-| `user.created` | Custom: utilisateur créé | `{"id", "email"}` | Welcome email |
-| `user.deleted` | Custom: utilisateur supprimé | `{"id"}` | Cleanup données |
-
-### Exemple: Subscriber aux Événements Système
-
-```python
-from xcore.sdk import TrustedBase, on, Event
-
-class Plugin(TrustedBase):
-
- @on("xcore.plugins.booted", priority=200)
- async def _on_system_boot(self, event: Event):
- """Exécuté quand TOUS les plugins sont chargés."""
- report = event.data.get("report", {})
- loaded_count = report.get("loaded", 0)
- self.logger.info(f"🚀 Système prêt : {loaded_count} plugins chargés")
-
- @on("plugin.auth_plugin.loaded", priority=100)
- async def _on_auth_ready(self, event: Event):
- """Exécuté quand le plugin auth est prêt."""
- self.logger.info("✅ Plugin auth disponible")
- # Initialiser la connexion avec le plugin auth
-
- @on("permission.deny", priority=50)
- async def _on_permission_denied(self, event: Event):
- """Logging de toutes les permissions refusées."""
- plugin = event.data.get("plugin")
- resource = event.data.get("resource")
- self.logger.warning(f"🚫 Permission refusée: {plugin} → {resource}")
-```
-
----
-
-## 3. Best Practices pour les Événements
-
-```mermaid
-flowchart TB
- subgraph Do["✅ Bonnes Pratiques"]
- D1[Handlers légers]
- D2[Priorités claires]
- D3[Cleanup handlers]
- D4[Événements nommés]
- end
-
- subgraph Dont["❌ Erreurs à Éviter"]
- A1[Tâches lourdes]
- A2[Priorités magiques]
- A3[Memory leaks]
- A4[Noms obscurs]
- end
-
- Do -.->|Au lieu de| Dont
-
- style Do fill:#E8F5E9,stroke:#388E3C
- style Dont fill:#FFEBEE,stroke:#C62828
-```
-
-### 1. Handlers Légers
-
-```python
-# ❌ MAUVAIS: Handler lourd (bloque l'event loop)
-@on("user.created")
-async def bad_handler(self, event):
- # Envoi email synchrone (lent !)
- send_email_sync(event.data["email"])
-
- # Traitement lourd
- for i in range(1000000):
- process(i)
-
-# ✅ BON: Déléguer au scheduler
-@on("user.created")
-async def good_handler(self, event):
- # Quick: queue la tâche
- await self.scheduler.add_job(
- self._send_welcome_email,
- args=[event.data["email"]]
- )
-```
-
-### 2. Priorités Explicites
-
-```python
-# ❌ MAUVAIS: Priorités arbitraires
-@on("user.created", priority=42)
-@on("user.created", priority=99)
-
-# ✅ BON: Priorités sémantiques
-PRIORITY_LOGGING = 100 # Logging en premier
-PRIORITY_BUSINESS = 50 # Logique métier
-PRIORITY_CLEANUP = 10 # Cleanup en dernier
-
-@on("user.created", priority=PRIORITY_LOGGING)
-@on("user.created", priority=PRIORITY_BUSINESS)
-```
-
-### 3. Nommage des Événements
-
-```python
-# ❌ MAUVAIS: Noms obscurs
-await self.ctx.events.emit("stuff.happened", data)
-await self.ctx.events.emit("do_thing", data)
-
-# ✅ BON: Noms sémantiques (domain.event)
-await self.ctx.events.emit("user.created", data)
-await self.ctx.events.emit("user.deleted", data)
-await self.ctx.events.emit("order.completed", data)
-```
-
-### 4. Stop Propagation (Usage Avancé)
-
-```python
-from xcore.sdk import TrustedBase, on, Event
-
-class Plugin(TrustedBase):
-
- @on("user.created", priority=100)
- async def validate_user(self, event: Event):
- """Validation en premier, peut bloquer les autres handlers."""
- if not self._is_valid(event.data):
- self.logger.error("Utilisateur invalide")
- event.stop_propagation() # ⚠️ Stop les handlers suivants
- return
-
- @on("user.created", priority=50)
- async def send_welcome(self, event: Event):
- """Ne s'exécute que si validation passe."""
- if event.propagation_stopped:
- self.logger.debug("Propagation stoppée, skip welcome")
- return
-
- # Envoyer email...
-```
-
----
-
-## 4. Hooks Synchrones
-
-Les hooks permettent de modifier des données ou d'exécuter de la logique synchrone pendant un processus spécifique.
-
-### Architecture du HookManager
-
-```mermaid
-flowchart LR
- subgraph Filters["🔄 Filters (Transformation)"]
- F1[Value] --> F2[Hook 1]
- F2 --> F3[Hook 2]
- F3 --> F4[Hook 3]
- F4 --> F5[Modified Value]
- end
-
- subgraph Actions["⚡ Actions (Side Effects)"]
- A1[Trigger] --> A2[Hook 1]
- A2 --> A3[Hook 2]
- A3 --> A4[Hook 3]
- A4 --> A5[Done]
- end
-
- style Filters fill:#E3F2FD,stroke:#1976D2
- style Actions fill:#FFF3E0,stroke:#F57C00
-```
-
-### A. Filters (Transformation de Données)
-
-Les filters permettent de "faire passer une valeur dans une chaîne" pour laisser d'autres plugins la modifier.
-
-```mermaid
-flowchart LR
- V[Valeur Originale] --> H1[Hook 1]
- H1 -->|Modifie| H2[Hook 2]
- H2 -->|Modifie| H3[Hook 3]
- H3 -->|Modifie| R[Valeur Finale]
-
- style V fill:#E8F5E9
- style R fill:#C8E6C9
-```
-
-```python
-# Côté Kernel ou Plugin
-class Plugin(TrustedBase):
-
- async def render_page(self):
- # 1. Valeur de base
- title = "Bienvenue sur XCore"
-
- # 2. Appliquer les filters
- title = self.ctx.hooks.apply_filters("page_title", title)
-
- # title peut maintenant être modifié par d'autres plugins
- # Ex: "Bienvenue sur XCore | Dashboard"
-
- return f"{title}
"
-
- # 3. Enregistrer un filter
- @filter("page_title")
- def modify_title(self, title: str) -> str:
- """Ajoute le suffixe au titre."""
- return f"{title} | Mon App"
-```
-
-### B. Actions (Side Effects Sync)
-
-Les actions sont des side effects synchrones qui ne retournent pas de valeur.
-
-```python
-# Côté Kernel ou Plugin
-class Plugin(TrustedBase):
-
- async def render_template(self, template_name: str):
- # 1. Trigger action avant rendu
- self.ctx.hooks.do_action("before_render", template=template_name)
-
- # 2. Rendu du template
- result = self._render(template_name)
-
- # 3. Trigger action après rendu
- self.ctx.hooks.do_action("after_render", template=template_name, result=result)
-
- return result
-
- # 4. Enregistrer un action hook
- @action_hook("before_render")
- def on_before_render(self, template: str):
- """Log chaque rendu de template."""
- self.logger.debug(f"Rendu du template: {template}")
-```
-
----
-
-## 5. Différence Entre Events et Hooks
-
-| Caractéristique | Events | Hooks |
-| :--- | :--- | :--- |
-| **Exécution** | Asynchrone (`async def`) | Synchrone (`def`) |
-| **Retourne Valeur** | ❌ Non | ✅ Oui (Filters) |
-| **Parallèle** | ✅ Oui (`asyncio.gather`) | ❌ Non (Séquentiel) |
-| **Propagation** | ✅ `stop_propagation()` | ❌ N/A |
-| **Priorités** | ✅ Oui | ⚠️ Ordre d'enregistrement |
-| **Use Case** | Side effects découplés | Transformation de données |
-
-### Quand Utiliser Quoi ?
-
-```mermaid
-flowchart TB
- Start{Besoin ?}
-
- Start -->|Modifier données| Hooks
- Start -->|Side effect| Events
-
- Start -->|Synchrone requis| Hooks
- Start -->|Async OK| Events
-
- Start -->|Plusieurs listeners| Events
- Start -->|Chaîne transformation| Hooks
-
- Hooks --> H[🪝 Hooks]
- Events --> E[📡 Events]
-
- style H fill:#FFF3E0,stroke:#F57C00
- style E fill:#E3F2FD,stroke:#1976D2
-```
-
-### Exemple Comparatif
-
-```python
-# 📡 EVENT: Pour side effect découplé
-@on("user.created")
-async def send_welcome_email(self, event):
- # Envoi email async (ne modifie pas les données)
- await self.email_service.send(event.data["email"])
-
-# 🪝 HOOK FILTER: Pour modifier des données
-@filter("user.profile_data")
-def add_premium_badge(self, profile_data: dict) -> dict:
- # Modifie les données avant retour
- if self._is_premium(user_id):
- profile_data["badge"] = "premium"
- return profile_data
-
-# 🪝 HOOK ACTION: Pour side effect synchrone
-@action_hook("before_user_save")
-def log_user_change(self, user_data: dict):
- # Logging synchrone
- self.logger.debug(f"User update: {user_data}")
-```
-
----
-
-## 6. Exemple Complet: Système de Notification
-
-```python
-from xcore.sdk import TrustedBase, on, action, ok, filter
-
-class NotificationPlugin(TrustedBase):
- """
- Plugin de notification qui démontre Events + Hooks.
- """
-
- async def on_load(self):
- # S'abonner aux événements système
- self.ctx.events.on("user.created", self._on_user_created, priority=50)
- self.ctx.events.on("order.completed", self._on_order_completed, priority=50)
-
- @on("user.created")
- async def _on_user_created(self, event):
- """Envoyer email de bienvenue."""
- email = event.data.get("email")
- await self._send_email(email, "Bienvenue !")
-
- @on("order.completed")
- async def _on_order_completed(self, event):
- """Envoyer confirmation de commande."""
- email = event.data.get("email")
- await self._send_email(email, "Commande confirmée !")
-
- @filter("notification.message")
- def add_disclaimer(self, message: str) -> str:
- """Ajouter un disclaimer à tous les messages."""
- return f"{message}\n\n-- Ceci est un message automatique"
-
- @action("send_notification")
- async def send_notification(self, payload: dict):
- """Action publique pour envoyer une notification."""
- # Appliquer les filters
- message = self.ctx.hooks.apply_filters(
- "notification.message",
- payload.get("message", "")
- )
-
- # Émettre un événement pour logging
- await self.ctx.events.emit("notification.sent", {
- "to": payload.get("to"),
- "message": message
- })
-
- return ok(status="sent")
-```
-
----
-
-## 7. Debugging et Monitoring
-
-### Voir les Handlers Enregistrés
-
-```bash
-# Lister tous les handlers d'événements
-xcore events list
-
-# Lister tous les hooks
-xcore hooks list
-```
-
-### Tracing des Événements
-
-```python
-# Activer le debug logging
-# xcore.yaml
-logging:
- level: DEBUG
- events: true # Log tous les événements émis
-```
-
-### Diagnostic des Problèmes
-
-| Problème | Cause Possible | Solution |
-| :--- | :--- | :--- |
-| Handler non appelé | Mauvais nom d'événement | Vérifier le nom exact |
-| Handler appelé trop tard | Priorité trop basse | Augmenter priority |
-| Memory leak | Handler non unsubscribed | Unsubscribe dans `on_unload` |
-| Event loop bloquée | Handler trop lourd | Déléguer au scheduler |
-
----
-
-## Prochaines Lectures
-
-| 📚 Guide | Objectif |
-| :--- | :--- |
-| [Creating Plugins](creating-plugins.md) | Développer des plugins |
-| [Services](services.md) | Utiliser les services partagés |
-| [Monitoring](monitoring.md) | Observer les événements en prod |
diff --git a/docs-tech/guides/marketplace.md b/docs-tech/guides/marketplace.md
deleted file mode 100644
index 14ce7b42..00000000
--- a/docs-tech/guides/marketplace.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# Marketplace Guide
-
-The XCore Marketplace is a central repository for sharing and discovering plugins. It allows you to extend your application with pre-built components like authentication providers, payment gateways, and logging tools.
-
----
-
-## 1. Using the Marketplace CLI
-
-The `xcore marketplace` command set allows you to interact with the official registry.
-
-### Searching for Plugins
-Search by name or description:
-```bash
-xcore marketplace search "notification"
-```
-
-### Getting Plugin Details
-View metadata, version history, and required permissions before installing:
-```bash
-xcore marketplace info notify-provider
-```
-
-### Installing a Plugin
-Downloads the plugin and extracts it into your `./plugins` directory:
-```bash
-xcore marketplace install notify-provider
-```
-
----
-
-## 2. Marketplace Configuration
-
-In your `xcore.yaml`, you can configure custom registry URLs or provide API keys for private marketplaces.
-
-```yaml
-marketplace:
- url: "https://marketplace.xcore.dev"
- api_key: "${MARKETPLACE_KEY}"
- timeout: 10
-```
-
----
-
-## 3. Security in the Marketplace
-
-The XCore team performs automated and manual security audits on marketplace plugins:
-
-- **Automatic Scanning**: All plugins are scanned by the XCore `ASTScanner` and `Bandit` during submission.
-- **Verification**: "Verified" plugins undergo a manual code review.
-- **Sandboxing**: We recommend running marketplace plugins in `sandboxed` mode unless you trust the author explicitly.
-
----
-
-## 4. Publishing Your Own Plugin
-
-Coming Soon: The publishing process is currently in private beta. To join, contact the XCore team at `marketplace@xcore.dev`.
diff --git a/docs-tech/guides/monitoring.md b/docs-tech/guides/monitoring.md
deleted file mode 100644
index 9790505c..00000000
--- a/docs-tech/guides/monitoring.md
+++ /dev/null
@@ -1,139 +0,0 @@
-# Monitoring & Observability
-
-XCore provides a comprehensive observability system to monitor your plugins and services in production.
-
-## Overview
-
-The XCore observability system is built on four pillars:
-
-1. **Metrics**: Counters, gauges, and histograms to measure performance.
-2. **Health Checks**: Real-time status monitoring of services and plugins.
-3. **Logging**: Structured logging with configurable levels and rotation.
-4. **Tracing**: Distributed tracing for debugging complex request flows.
-
-## Metrics
-
-The metrics registry supports three primary types:
-
-- **Counter**: Values that only increase (e.g., total requests).
-- **Gauge**: Values that can go up or down (e.g., active connections).
-- **Histogram**: Distribution of values (e.g., request latency).
-
-### Basic Usage
-
-```python
-from xcore.kernel.observability.metrics import MetricsRegistry
-from xcore.sdk import TrustedBase
-
-class Plugin(TrustedBase):
- async def on_load(self) -> None:
- self.metrics = MetricsRegistry()
-
- # Define metrics
- self.request_count = self.metrics.counter("http.requests.total")
- self.active_connections = self.metrics.gauge("connections.active")
- self.request_latency = self.metrics.histogram("http.request.duration")
-
- def get_router(self):
- from fastapi import APIRouter
- import time
- router = APIRouter()
-
- @router.get("/data")
- async def get_data():
- start = time.monotonic()
- self.active_connections.inc()
- try:
- # Logic here...
- self.request_count.inc()
- return {"status": "ok"}
- finally:
- self.request_latency.observe(time.monotonic() - start)
- self.active_connections.dec()
- return router
-```
-
-### Metrics with Labels
-
-Labels allow you to add dimensions to your metrics for more granular analysis.
-
-```python
-self.request_count = self.metrics.counter(
- "http.requests.total",
- labels={"plugin": "my_plugin", "method": "GET"}
-)
-```
-
-## Health Checks
-
-Health checks allow you to monitor the status of your dependencies and internal state.
-
-### Registering Checks
-
-```python
-from xcore.kernel.observability.health import HealthChecker
-
-class Plugin(TrustedBase):
- async def on_load(self) -> None:
- self.health = HealthChecker()
- self.db = self.get_service("db")
-
- @self.health.register("database")
- async def check_db():
- try:
- async with self.db.session() as session:
- await session.execute("SELECT 1")
- return True, "Database OK"
- except Exception as e:
- return False, str(e)
-```
-
-## Logging
-
-XCore uses structured logging to make logs easier to parse and analyze.
-
-### Configuration (`xcore.yaml`)
-
-```yaml
-observability:
- logging:
- level: INFO
- format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
- file: "logs/app.log"
-```
-
-### Usage in Plugins
-
-```python
-import logging
-logger = logging.getLogger("xcore.plugin.my_plugin")
-
-class Plugin(TrustedBase):
- async def on_load(self):
- logger.info("Plugin loaded successfully", extra={"version": "1.0.0"})
-```
-
-## Tracing
-
-Tracing helps you visualize the flow of requests across multiple plugins and services.
-
-```python
-from xcore.kernel.observability.tracing import Tracer
-
-class Plugin(TrustedBase):
- async def on_load(self):
- self.tracer = Tracer(service_name="my_plugin")
-
- async def handle(self, action, payload):
- with self.tracer.span("process_action", action=action) as span:
- # Operation logic...
- span.set_attribute("result", "success")
- return ok()
-```
-
-## Best Practices
-
-1. **Meaningful Names**: Use clear, dot-separated names for metrics (e.g., `api.user.login_success`).
-2. **Avoid High Cardinality**: Don't use unique IDs (like user IDs) as labels in metrics.
-3. **Use Appropriate Levels**: Use `DEBUG` for verbose info, `INFO` for general flow, and `ERROR` for actual failures.
-4. **Monitor Dependencies**: Always include health checks for external APIs or databases your plugin relies on.
diff --git a/docs-tech/guides/scaling.md b/docs-tech/guides/scaling.md
deleted file mode 100644
index e8e5e6d3..00000000
--- a/docs-tech/guides/scaling.md
+++ /dev/null
@@ -1,147 +0,0 @@
-# Scaling & High Availability
-
-This guide covers scaling strategies for deploying XCore in production environments with high availability.
-
-## Overview
-
-XCore supports several deployment modes to meet varying scale requirements:
-
-- **Single Instance**: Development and small workloads.
-- **Multi-Instance**: Horizontal scaling with a load balancer.
-- **Cluster Mode**: Multiple nodes with shared coordination (via Redis).
-
-## Scaling Architecture
-
-```text
- ┌─────────────────┐
- │ Load Balancer │
- │ (Nginx/HAProxy)│
- └────────┬────────┘
- │
- ┌────────────────────┼────────────────────┐
- │ │ │
- ┌────▼────┐ ┌────▼────┐ ┌────▼────┐
- │ XCore 1 │ │ XCore 2 │ │ XCore 3 │
- │ │ │ │ │ │
- │ Plugins │ │ Plugins │ │ Plugins │
- └────┬────┘ └────┬────┘ └────┬────┘
- │ │ │
- └────────────────────┼────────────────────┘
- │
- ┌────────▼────────┐
- │ Redis Cluster │
- │ (Cache + Queue) │
- └─────────────────┘
- │
- ┌──────────────┼──────────────┐
- │ │ │
- ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
- │ PostgreSQL │ │ PostgreSQL │ │ PostgreSQL │
- │ Primary │ │ Replica │ │ Replica │
- └─────────────┘ └─────────────┘ └─────────────┘
-```
-
-## Multi-Instance Configuration
-
-### 1. Load Balancer (Nginx)
-
-```nginx
-upstream xcore_backend {
- least_conn; # Load balance by connection count
- server 192.168.1.10:8080 weight=5;
- server 192.168.1.11:8080 weight=5;
- server 192.168.1.12:8080 weight=5 backup;
- keepalive 32;
-}
-
-server {
- listen 80;
- server_name api.example.com;
-
- location / {
- proxy_pass http://xcore_backend;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-
- # Timeouts
- proxy_connect_timeout 30s;
- proxy_send_timeout 30s;
- proxy_read_timeout 30s;
- }
-}
-```
-
-### 2. Redis Cluster Configuration
-
-```yaml
-# xcore.yaml
-services:
- cache:
- backend: redis
- url: "redis://redis-cluster:6379"
- cluster:
- enabled: true
- nodes:
- - "redis://192.168.1.20:6379"
- - "redis://192.168.1.21:6379"
-
- scheduler:
- enabled: true
- backend: redis
- url: "redis://redis-cluster:6379"
-```
-
-### 3. Database with Replication
-
-```yaml
-services:
- databases:
- primary:
- type: postgresql
- url: "${DATABASE_PRIMARY_URL}"
- pool_size: 20
-
- replica1:
- type: postgresql
- url: "${DATABASE_REPLICA1_URL}"
- pool_size: 10
- read_only: true
-```
-
-## Session & State Distribution
-
-### External Sessions
-
-To ensure "statelessness", always store user sessions and shared state in an external cache (Redis) rather than in memory.
-
-```python
-class SessionManager(TrustedBase):
- async def on_load(self) -> None:
- self.cache = self.get_service("cache")
-
- async def get_session(self, session_id: str) -> dict | None:
- # Sessions are shared across all XCore instances via Redis
- return await self.cache.get(f"session:{session_id}")
-```
-
-## Distributed Rate Limiting
-
-By using the Redis cache backend, XCore's built-in rate limiter becomes distributed automatically across all running instances.
-
-```yaml
-# plugin.yaml
-resources:
- rate_limit:
- calls: 100
- period_seconds: 60
-```
-*Note: This limit applies globally across all instances.*
-
-## Best Practices
-
-1. **Stateless Design**: Never store state locally in a plugin; use Redis or a Database.
-2. **Graceful Shutdown**: Always handle `SIGTERM` to allow tasks to complete before an instance stops.
-3. **Circuit Breaker**: Use circuit breakers when calling external APIs to prevent cascading failures.
-4. **Auto-Scaling**: Use metrics (CPU/RAM/Request Rate) to scale instances automatically in Kubernetes or AWS.
-5. **Database Connection Pooling**: Configure appropriate pool sizes for each instance to avoid overwhelming the database.
diff --git a/docs-tech/guides/security.md b/docs-tech/guides/security.md
deleted file mode 100644
index 3ba8354e..00000000
--- a/docs-tech/guides/security.md
+++ /dev/null
@@ -1,639 +0,0 @@
-# Security Deep Dive
-
-XCore suit un modèle **"Zero Trust"** pour les plugins. Même les plugins trusted sont restreints de modifier l'état du kernel, tandis que les plugins sandboxed sont isolés aux niveaux OS et Runtime.
-
----
-
-## Vue d'Ensemble de la Sécurité
-
-```mermaid
-flowchart TB
- subgraph Defense["Défense en Profondeur"]
- direction TB
- L1[🛡️ Couche 1: AST Scan
Analyse statique]
- L2[🛡️ Couche 2: Process Isolation
Sandbox OS]
- L3[🛡️ Couche 3: Resource Limits
Memory/CPU]
- L4[🛡️ Couche 4: Permissions
Policy Engine]
- L5[🛡️ Couche 5: Signature
HMAC Verification]
- end
-
- subgraph Attaques["Attaques Bloquées"]
- A1[Code Injection]
- A2[Sandbox Escape]
- A3[DoS Resource]
- A4[Accès Non Autorisé]
- A5[Tampering]
- end
-
- L1 -.->|Bloque| A1
- L2 -.->|Bloque| A2
- L3 -.->|Bloque| A3
- L4 -.->|Bloque| A4
- L5 -.->|Bloque| A5
-
- style Defense fill:#E8F5E9,stroke:#388E3C
- style L1 fill:#C8E6C9
- style L2 fill:#C8E6C9
- style L3 fill:#C8E6C9
- style L4 fill:#C8E6C9
- style L5 fill:#C8E6C9
-```
-
----
-
-## 1. Le Multi-Layer Sandbox
-
-Quand `execution_mode: sandboxed` est défini, le kernel applique **3 couches de protection** successives.
-
-### Vue d'Ensemble du Flux
-
-```mermaid
-flowchart LR
- subgraph PreExec["Pré-Exécution"]
- A[Code Source] --> B[🔍 AST Scanner]
- B --> C{Scan OK ?}
- C -->|Non| D[❌ Rejeté]
- C -->|Oui| E[📦 Spawn Worker]
- end
-
- subgraph Exec["Exécution"]
- E --> F[📡 JSON-RPC IPC]
- F --> G[⏱️ Timeout Monitor]
- G --> H[🧠 Memory Monitor]
- end
-
- subgraph PostExec["Post-Exécution"]
- H --> I{Limites OK ?}
- I -->|Non| J[❌ Kill Worker]
- I -->|Oui| K[✅ Résultat]
- end
-
- style PreExec fill:#FFF3E0,stroke:#F57C00
- style Exec fill:#E3F2FD,stroke:#1976D2
- style PostExec fill:#E8F5E9,stroke:#388E3C
-```
-
----
-
-### Couche 1: Analyse Statique (AST)
-
-Avant l'exécution, l'`ASTScanner` parse l'arbre syntaxique du plugin avec un `ast.NodeVisitor`.
-
-```mermaid
-flowchart TB
- subgraph AST["🔍 AST Scanner"]
- S[Code Source] --> P[Parser AST]
- P --> N[NodeVisitor]
-
- N --> F1[Forbidden Names]
- N --> F2[Forbidden Attributes]
- N --> F3[Import Whitelist]
-
- F1 --> B1[❌ eval, exec]
- F1 --> B2[❌ globals, locals]
- F1 --> B3[❌ __import__]
-
- F2 --> B4[❌ __class__]
- F2 --> B5[❌ __globals__]
- F2 --> B6[❌ __subclasses__]
-
- F3 --> B7[❌ os, subprocess]
- F3 --> B8[❌ socket, requests]
- end
-
- style AST fill:#FFEBEE,stroke:#C62828
- style B1 fill:#FFCDD2
- style B2 fill:#FFCDD2
- style B3 fill:#FFCDD2
- style B4 fill:#FFCDD2
- style B5 fill:#FFCDD2
- style B6 fill:#FFCDD2
- style B7 fill:#FFCDD2
- style B8 fill:#FFCDD2
-```
-
-#### Liste Complète des Restrictions
-
-```python
-# ❌ Forbidden Names (bloqués par l'AST)
-FORBIDDEN_NAMES = {
- 'eval', 'exec', 'compile',
- 'globals', 'locals', 'vars',
- '__import__', 'open', 'input',
- 'breakpoint', 'delattr', 'setattr'
-}
-
-# ❌ Forbidden Attributes (sandboxes escapes courants)
-FORBIDDEN_ATTRIBUTES = {
- '__class__', '__bases__', '__subclasses__',
- '__globals__', '__code__', '__closure__',
- '__builtins__', '__import__', 'gi_frame',
- 'cr_frame', 'f_globals', 'f_locals'
-}
-
-# ❌ Forbidden Modules (nécessite allowed_imports)
-FORBIDDEN_MODULES = {
- 'os', 'sys', 'subprocess', 'multiprocessing',
- 'socket', 'requests', 'urllib', 'http',
- 'pickle', 'marshal', 'shelve'
-}
-```
-
-#### Exemple de Configuration
-
-```yaml
-# plugin.yaml
-# Pour utiliser des modules normalement restreints
-allowed_imports:
- - datetime # ✅ Autorisé
- - json # ✅ Autorisé
- - hashlib # ✅ Autorisé (si besoin)
- - re # ✅ Autorisé
-
-# Tentative d'import bloqué :
-# import os # ❌ Erreur: Module 'os' non autorisé
-```
-
----
-
-### Couche 2: Isolation Processus
-
-Les plugins sandboxed s'exécutent dans un **processus OS dédié** via le module `multiprocessing`.
-
-```mermaid
-sequenceDiagram
- participant K as 🎯 Kernel Process
- participant M as 📡 Multiprocessing Manager
- participant W as 📦 Sandbox Worker
-
- Note over K: Boot du kernel
- K->>M: spawn_worker(plugin_path)
-
- Note over M: Création processus
- M->>W: fork()/spawn()
- W->>W: Charger code plugin
-
- Note over K,W: Communication via pipes
- K->>W: {"jsonrpc":"2.0","method":"call",...}
- Note over K,W: JSON uniquement
⚠️ Pas de pickle !
-
- W->>W: Exécuter handler
- W->>K: {"jsonrpc":"2.0","result":...}
-
- Note over K: Désérialiser résultat
-```
-
-#### Transport: JSON-RPC 2.0 sur Pipes OS
-
-```python
-# Format des messages Kernel → Worker
-{
- "jsonrpc": "2.0",
- "id": "uuid-1234-5678",
- "method": "call",
- "params": {
- "action": "greet",
- "payload": {"name": "World"}
- }
-}
-
-# Format des messages Worker → Kernel
-{
- "jsonrpc": "2.0",
- "id": "uuid-1234-5678",
- "result": {"status": "ok", "message": "Hello !"}
-}
-
-# Ou en cas d'erreur
-{
- "jsonrpc": "2.0",
- "id": "uuid-1234-5678",
- "error": {
- "code": -32000,
- "message": "Action not found"
- }
-}
-```
-
-#### Pourquoi JSON-RPC ?
-
-| Avantage | Description |
-| :--- | :--- |
-| **Sérialisation sûre** | Seulement types JSON (pas de `pickle` → pas de RCE) |
-| **Langage-agnostique** | Pourrait être implémenté dans tout langage |
-| **Debug-friendly** | Messages lisibles en clair |
-| **Standardisé** | Spécification JSON-RPC 2.0 |
-
----
-
-### Couche 3: Limites de Ressources OS
-
-Le kernel monitorle RSS (Resident Set Size) et le temps CPU du worker.
-
-```mermaid
-flowchart LR
- subgraph Monitors["📊 Resource Monitors"]
- MM[🧠 Memory Monitor
RSS Tracker]
- TM[⏱️ Timeout Monitor
Execution Timer]
- CM[📈 CPU Monitor
CPU Time Tracker]
- end
-
- subgraph Limits["⚠️ Limites"]
- ML[Max: max_memory_mb]
- TL[Max: timeout_seconds]
- CL[Max: cpu_seconds]
- end
-
- subgraph Actions["🔥 Actions"]
- MA[⚠️ Warning]
- KA[❌ Kill Process]
- RA[📝 Log Violation]
- end
-
- MM --> ML --> MA --> KA
- TM --> TL --> KA
- CM --> CL --> KA
-
- style Monitors fill:#E3F2FD,stroke:#1976D2
- style Limits fill:#FFF3E0,stroke:#F57C00
- style Actions fill:#FFEBEE,stroke:#C62828
-```
-
-#### Configuration des Limites
-
-```yaml
-# plugin.yaml
-resources:
- # Mémoire maximale (Mo)
- max_memory_mb: 256
-
- # Timeout d'exécution (secondes)
- timeout_seconds: 30
-
- # Rate limiting
- rate_limit:
- calls: 1000
- period_seconds: 60
-```
-
-#### Comportement en Cas de Dépassement
-
-| Ressource | Limite | Comportement |
-| :--- | :--- | :--- |
-| **Mémoire** | `max_memory_mb` | Warning à 80%, Kill à 100% |
-| **Timeout** | `timeout_seconds` | Kill immédiat + erreur timeout |
-| **Rate Limit** | `calls/period` | Erreur 429 Too Many Requests |
-
----
-
-## 2. Permission Engine
-
-Chaque appel inter-plugin et accès service est audité par le **PermissionEngine**.
-
-### Modèle d'Évaluation
-
-```mermaid
-flowchart TB
- subgraph Evaluation["🔍 Évaluation Permission"]
- Start[Début Évaluation]
- CheckDeny[Vérifier DENY explicite ?]
- CheckAllow[Vérifier ALLOW explicite ?]
- DefaultDeny[❌ DENY par défaut]
- Allow[✅ ALLOW]
- Deny[❌ DENY]
- end
-
- Start --> CheckDeny
- CheckDeny -->|Oui| Deny
- CheckDeny -->|Non| CheckAllow
- CheckAllow -->|Oui| Allow
- CheckAllow -->|Non| DefaultDeny
-
- style Deny fill:#FFCDD2,stroke:#C62828
- style Allow fill:#C8E6C9,stroke:#388E3C
- style DefaultDeny fill:#FFCDD2,stroke:#C62828
-```
-
-### Modèle "Fail-Closed"
-
-XCore utilise un modèle **"Fail-Closed"** : si aucune policy n'autorise explicitement une action, elle est **refusée**.
-
-```
-1. Vérifier DENY explicite → Si trouvé: ❌ REFUSÉ
-2. Vérifier ALLOW explicite → Si trouvé: ✅ AUTORISÉ
-3. Aucun match → ❌ REFUSÉ (défaut)
-```
-
-### Patterns de Permissions
-
-#### Wildcards sur les Ressources
-
-```yaml
-permissions:
- # ✅ Autorise lecture sur TOUTES les tables 'users_*'
- - resource: "db.users.*"
- actions: ["read"]
- effect: allow
-
- # ✅ Autorise lecture/écriture sur cache global
- - resource: "cache.global"
- actions: ["read", "write"]
- effect: allow
-
- # ✅ Autorise TOUS les actions sur une resource
- - resource: "logs.*"
- actions: ["*"]
- effect: allow
-
- # ❌ DENY explicite (priorité haute)
- - resource: "db.admin.*"
- actions: ["*"]
- effect: deny
-```
-
-#### Exemple Complet de Policy
-
-```yaml
-# plugin.yaml
-permissions:
- # Lecture seule sur la DB principale
- - resource: "db.main.users"
- actions: ["read"]
- effect: allow
-
- - resource: "db.main.posts"
- actions: ["read"]
- effect: allow
-
- # Écriture sur cache
- - resource: "cache.global"
- actions: ["read", "write"]
- effect: allow
-
- # Accès scheduler
- - resource: "scheduler.jobs"
- actions: ["create", "delete"]
- effect: allow
-
- # Interdiction explicite (sécurité défense)
- - resource: "db.admin.*"
- actions: ["*"]
- effect: deny
-
- - resource: "kernel.*"
- actions: ["*"]
- effect: deny
-```
-
-### Flux d'Évaluation
-
-```mermaid
-sequenceDiagram
- participant A as Plugin A
- participant S as Supervisor
- participant P as PermissionEngine
- participant L as Policy Loader
-
- A->>S: call("plugin_b", "get_user")
- S->>P: evaluate("plugin_a", "plugin_b.get_user")
-
- P->>L: Charger policies de plugin_a
- L-->>P: Retourner rules
-
- P->>P: Vérifier DENY explicite
- Note over P: ❌ Aucun DENY trouvé
-
- P->>P: Vérifier ALLOW explicite
- Note over P: ✅ Rule trouvée !
-
- P-->>S: ✅ Autorisé
- S->>A: Procéder à l'appel
-```
-
----
-
-## 3. Signature des Plugins Trusted
-
-En production, le mode `strict_trusted` garantit que les plugins trusted n'ont pas été altérés.
-
-### Architecture de Signature
-
-```mermaid
-flowchart TB
- subgraph Sign["📝 Signature (Développement)"]
- D1[Fichiers Plugin] --> D2[Calcul HMAC-SHA256]
- D2 --> D3[Générer plugin.sig]
- end
-
- subgraph Verify["🔍 Vérification (Production)"]
- V1[Charger plugin.sig] --> V2[Re-calculer hashes]
- V2 --> V3{Match ?}
- V3 -->|Oui| V4[✅ Charger]
- V3 -->|Non| V5[❌ Rejeté]
- end
-
- Sign --> Verify
-
- style Sign fill:#E8F5E9,stroke:#388E3C
- style Verify fill:#FFEBEE,stroke:#C62828
-```
-
-### Générer une Signature
-
-```bash
-# Signer un plugin trusted
-xcore plugin sign plugins/my_plugin/
-
-# Le fichier plugin.sig est créé/mis à jour
-```
-
-### Structure de `plugin.sig`
-
-```json
-{
- "plugin": "my_plugin",
- "version": "1.0.0",
- "timestamp": "2024-01-15T10:30:00Z",
- "files": {
- "plugin.yaml": "a1b2c3d4e5f6...",
- "src/main.py": "f6e5d4c3b2a1...",
- "src/utils.py": "1234567890ab..."
- },
- "signature": "hmac-sha256-signature-here"
-}
-```
-
-### Vérification au Boot
-
-```mermaid
-sequenceDiagram
- participant K as Kernel
- participant S as SignatureVerifier
- participant F as Fichiers Plugin
- participant Sig as plugin.sig
-
- K->>S: verify_trusted("my_plugin")
-
- S->>Sig: Charger signature
- S->>F: Lire fichiers actuels
- S->>S: Calculer hashes actuels
-
- S->>S: Comparer avec plugin.sig
- alt Hashes correspondent
- S-->>K: ✅ Vérifié
- K->>K: Charger plugin
- else Hashes différents
- S-->>K: ❌ Tampering détecté
- K->>K: ❌ Refuser chargement
- end
-```
-
----
-
-## 4. Bonnes Pratiques pour les Développeurs
-
-### Checklist de Sécurité
-
-```mermaid
-flowchart LR
- subgraph Do["✅ À Faire"]
- D1[Sandboxed par défaut]
- D2[Permissions minimales]
- D3[Valider inputs]
- D4[Pas d'état local]
- D5[Signer en prod]
- end
-
- subgraph Dont["❌ À Éviter"]
- A1[Trusted sans besoin]
- A2[Permissions larges]
- A3[Inputs non validés]
- A4[État dans le plugin]
- A5[Code non signé]
- end
-
- Do -.->|Au lieu de| Dont
-
- style Do fill:#E8F5E9,stroke:#388E3C
- style Dont fill:#FFEBEE,stroke:#C62828
-```
-
-### 1. Utiliser le Sandboxing par Défaut
-
-```yaml
-# ✅ RECOMMANDÉ: Sandboxed pour isolation maximale
-execution_mode: sandboxed
-
-# ⚠️ UNIQUEMENT SI NÉCESSAIRE: Trusted pour accès kernel
-execution_mode: trusted
-# Nécessite: accès FastAPI hooks, objets kernel complexes
-```
-
-### 2. Demander des Permissions Minimales
-
-```yaml
-# ❌ TROP LARGE
-permissions:
- - resource: "db.*"
- actions: ["*"]
- effect: allow
-
-# ✅ MINIMAL
-permissions:
- - resource: "db.main.users"
- actions: ["read"]
- effect: allow
- - resource: "db.main.posts"
- actions: ["read", "write"]
- effect: allow
-```
-
-### 3. Valider Tous les Inputs
-
-```python
-from xcore.sdk import TrustedBase, AutoDispatchMixin, action, ok
-from pydantic import BaseModel, Field
-
-# ✅ Schema de validation
-class GreetInput(BaseModel):
- name: str = Field(min_length=1, max_length=100)
- language: str = Field(default="fr")
-
-class Plugin(AutoDispatchMixin, TrustedBase):
-
- @action("greet")
- async def greet(self, payload: dict):
- # Valider l'input
- try:
- validated = GreetInput(**payload)
- except ValidationError as e:
- return error(msg=str(e), code="invalid_input")
-
- return ok(message=f"Bonjour, {validated.name} !")
-```
-
-### 4. Pas d'État Local
-
-```python
-# ❌ MAUVAIS: État dans le plugin
-class Plugin(TrustedBase):
- def __init__(self):
- self.cache_local = {} # ⚠️ Perdu au reload !
-
-# ✅ BON: État dans les services
-class Plugin(TrustedBase):
- async def on_load(self):
- self.cache = self.get_service("cache") # ✅ Persistant
-
- async def store(self, key, value):
- await self.cache.set(key, value) # ✅ Sauvegardé
-```
-
-### 5. Signer en Production
-
-```bash
-# Développement
-# Pas de signature requise
-
-# Production (strict_trusted activé)
-xcore plugin sign plugins/my_plugin/
-
-# Vérifier
-xcore plugin validate plugins/my_plugin/
-```
-
----
-
-## 5. matrice de Sécurité
-
-### Comparaison Trusted vs Sandboxed
-
-| Caractéristique | Trusted | Sandboxed |
-| :--- | :--- | :--- |
-| **Processus** | Principal | Isolé (OS) |
-| **Performance** | ⚡ Rapide | 🐌 IPC overhead |
-| **Isolation** | 🔶 Logique | 🔒 Physique |
-| **Accès Kernel** | ✅ Complet | ❌ Via IPC uniquement |
-| **AST Scan** | ⚠️ Partiel | ✅ Complet |
-| **Usage** | Dev / Confiance | Prod / Tiers |
-
-### Tableau des Permissions par Défaut
-
-| Action | Trusted | Sandboxed |
-| :--- | :--- | :--- |
-| Appeler autre plugin | ✅ (avec permission) | ✅ (avec permission) |
-| Accéder DB publique | ✅ | ✅ |
-| Accéder DB privée | ❌ | ❌ |
-| Modifier kernel | ❌ | ❌ |
-| Import restreint | ⚠️ (whitelist) | ❌ (bloqué AST) |
-| Route HTTP | ✅ | ✅ (via IPC) |
-
----
-
-## Prochaines Lectures
-
-| 📚 Guide | Objectif |
-| :--- | :--- |
-| [Event System](events.md) | Messagerie sécurisée |
-| [Plugin Creation](creating-plugins.md) | Développer des plugins |
-| [Troubleshooting](troubleshooting.md) | Déboguer les erreurs |
diff --git a/docs-tech/guides/services.md b/docs-tech/guides/services.md
deleted file mode 100644
index 326e5b5b..00000000
--- a/docs-tech/guides/services.md
+++ /dev/null
@@ -1,95 +0,0 @@
-# Working with Services
-
-The `ServiceContainer` provides access to global infrastructure shared across all plugins.
-
----
-
-## 1. Database Service (`db`)
-
-The `db` service supports multiple engines and provides typed adapters for SQL and NoSQL.
-
-### A. SQL Patterns (PostgreSQL/SQLite)
-We recommend using the `AsyncSQLAdapter` for non-blocking database operations.
-
-```python
-async def get_user_tasks(self, user_id: int):
- db = self.get_service("db")
- async with db.session() as session:
- result = await session.execute(
- "SELECT * FROM tasks WHERE user_id = :uid",
- {"uid": user_id}
- )
- return [dict(row) for row in result.fetchall()]
-```
-
-### B. Redis Patterns
-The Redis service is ideal for distributed locks, counters, and high-frequency data.
-
-```python
-async def rate_limit_check(self, user_id: str):
- redis = self.get_service("redis")
- key = f"limit:{user_id}"
- count = await redis.incr(key)
- if count == 1:
- await redis.expire(key, 60)
- return count <= 100
-```
-
----
-
-## 2. Cache Service (`cache`)
-
-Unified interface for `memory` and `redis` backends.
-
-### `get_or_set` Pattern
-Simplifies the "check cache, then fetch" logic.
-
-```python
-data = await self.cache.get_or_set(
- f"profile:{id}",
- factory=lambda: self._fetch_profile_from_db(id),
- ttl=3600
-)
-```
-
----
-
-## 3. Scheduler Service (`scheduler`)
-
-Powered by APScheduler, allowing both one-time and recurring tasks.
-
-```python
-def sync_data(self):
- print("Syncing data...")
-
-async def on_load(self):
- scheduler = self.get_service("scheduler")
- # Add a CRON job
- scheduler.add_job(
- self.sync_data,
- trigger="cron",
- hour="0",
- minute="0",
- id="daily_sync"
- )
-```
-
----
-
-## 4. Custom Extensions
-
-Extensions are global services loaded from the `extensions/` directory.
-
-```python
-# In extensions/my_ext/extension.py
-class MyExtension:
- def __init__(self, config):
- self.config = config
- def ping(self):
- return "pong"
-
-# In your Plugin
-async def on_load(self):
- ext = self.get_service("ext.my_ext")
- print(ext.ping())
-```
diff --git a/docs-tech/guides/troubleshooting.md b/docs-tech/guides/troubleshooting.md
deleted file mode 100644
index 3e497d7e..00000000
--- a/docs-tech/guides/troubleshooting.md
+++ /dev/null
@@ -1,373 +0,0 @@
-# Troubleshooting Guide
-
-Common issues and solutions for XCore.
-
-## Installation Issues
-
-### Poetry Installation Fails
-
-**Problem**: Poetry installation fails or command not found
-
-**Solutions**:
-
-```bash
-# Install Poetry
-pip install --user poetry
-
-# Add to PATH
-export PATH="$HOME/.local/bin:$PATH"
-
-# Or use pipx
-pipx install poetry
-```
-
-### Dependency Conflicts
-
-**Problem**: Poetry dependency resolution fails
-
-**Solutions**:
-
-```bash
-# Clear Poetry cache
-poetry cache clear pypi --all
-
-# Update lock file
-poetry lock --no-update
-
-# Install with specific Python
-poetry env use python3.11
-poetry install
-```
-
-## Runtime Issues
-
-### Plugin Not Loading
-
-**Problem**: Plugin doesn't appear in loaded plugins
-
-**Check**:
-
-```bash
-# Verify plugin structure
-ls -la plugins/my_plugin/
-# Should show: plugin.yaml, src/main.py
-
-# Check plugin.yaml syntax
-cat plugins/my_plugin/plugin.yaml | python -c "import yaml, sys; yaml.safe_load(sys.stdin)"
-
-# Check logs
-poetry run xcore plugin list
-```
-
-**Solutions**:
-
-1. Check `plugin.yaml` is valid YAML
-2. Verify `entry_point` path exists
-3. Ensure `name` is unique
-4. Check for syntax errors in `main.py`
-
-### Database Connection Errors
-
-**Problem**: Cannot connect to database
-
-**Error Messages**:
-```
-ConnectionRefusedError: [Errno 111] Connection refused
-psycopg2.OperationalError: could not connect to server
-```
-
-**Solutions**:
-
-```bash
-# Check database is running
-pg_isready -h localhost -p 5432
-
-# Test connection
-psql $DATABASE_URL -c "SELECT 1"
-
-# Verify environment variables
-echo $DATABASE_URL
-
-# Check firewall/network
-nc -zv localhost 5432
-```
-
-### Redis Connection Errors
-
-**Problem**: Cannot connect to Redis
-
-**Solutions**:
-
-```bash
-# Check Redis is running
-redis-cli ping
-
-# Test with Python
-python -c "import redis; r = redis.from_url('$REDIS_URL'); print(r.ping())"
-
-# Check URL format
-# Correct: redis://:password@host:6379/0
-```
-
-## Service Issues
-
-### Cache Not Working
-
-**Problem**: Cache returns None or doesn't persist
-
-**Solutions**:
-
-```python
-# Check cache configuration
-assert xcore.services.has("cache")
-
-cache = xcore.services.get("cache")
-
-# Test basic operations
-await cache.set("test", "value", ttl=60)
-value = await cache.get("test")
-assert value == "value"
-```
-
-### Scheduler Not Running Jobs
-
-**Problem**: Scheduled jobs don't execute
-
-**Solutions**:
-
-```yaml
-# Verify scheduler is enabled
-services:
- scheduler:
- enabled: true
- backend: redis # or memory
-```
-
-```python
-# Check scheduler
-scheduler = xcore.services.get("scheduler")
-jobs = scheduler.get_jobs()
-print(f"Scheduled jobs: {len(jobs)}")
-
-# Add test job
-def test_job():
- print("Job executed!")
-
-scheduler.add_job(test_job, trigger="interval", seconds=5)
-```
-
-## Plugin Development Issues
-
-### Import Errors
-
-**Problem**: Cannot import from xcore.sdk
-
-**Solutions**:
-
-```python
-# Correct imports
-from xcore.sdk import TrustedBase, ok, error
-
-# If import fails, check:
-# 1. Poetry shell is activated
-# 2. Package is installed: poetry install
-# 3. Python path includes xcore
-```
-
-### Service Access Errors
-
-**Problem**: `KeyError: Service 'db' not found`
-
-**Solutions**:
-
-```python
-class Plugin(TrustedBase):
- async def on_load(self) -> None:
- # Wait for context to be injected
- if self.ctx is None:
- raise RuntimeError("Context not injected")
-
- # Check service exists before getting
- if not self.ctx.services.has("db"):
- raise RuntimeError("Database service not available")
-
- self.db = self.get_service("db")
-```
-
-### Async/Await Issues
-
-**Problem**: `RuntimeWarning: coroutine was never awaited`
-
-**Solutions**:
-
-```python
-# Correct async/await usage
-async def handle(self, action: str, payload: dict) -> dict:
- # Must await async functions
- result = await self.db.fetch("SELECT 1")
-
- # For sync operations in async context
- import asyncio
- loop = asyncio.get_event_loop()
- result = await loop.run_in_executor(None, sync_function)
-
- return ok()
-```
-
-## Performance Issues
-
-### High Memory Usage
-
-**Problem**: Application uses too much memory
-
-**Solutions**:
-
-```yaml
-# Reduce connection pool sizes
-services:
- databases:
- default:
- pool_size: 10
- max_overflow: 5
-
- cache:
- backend: memory
- max_size: 5000
-```
-
-```python
-# Clear caches periodically
-await self.cache.clear()
-
-# Use streaming for large datasets
-async for row in self.db.iter_rows("SELECT * FROM large_table"):
- yield row
-```
-
-### Slow Plugin Calls
-
-**Problem**: Plugin actions take too long
-
-**Solutions**:
-
-1. **Use caching**:
-```python
-async def get_data(self, key):
- return await self.cache.get_or_set(
- key,
- factory=lambda: self._fetch_expensive_data(key),
- ttl=300
- )
-```
-
-2. **Database indexing**:
-```sql
-CREATE INDEX idx_users_email ON users(email);
-```
-
-3. **Async operations**:
-```python
-# Parallel calls
-results = await asyncio.gather(
- self.get_service("db").fetch("..."),
- self.get_service("cache").get("..."),
-)
-```
-
-## Debugging
-
-### Enable Debug Logging
-
-```yaml
-# In config
-observability:
- logging:
- level: DEBUG
-```
-
-```python
-# In plugin
-import logging
-
-logger = logging.getLogger("my_plugin")
-
-async def handle(self, action: str, payload: dict) -> dict:
- logger.debug(f"Received action: {action}")
- logger.debug(f"Payload: {payload}")
-
- try:
- result = self._process(payload)
- logger.info(f"Action {action} completed")
- return ok(data=result)
- except Exception as e:
- logger.exception(f"Error in {action}")
- return error(str(e))
-```
-
-### Using PDB
-
-```python
-async def handle(self, action: str, payload: dict) -> dict:
- import pdb; pdb.set_trace() # Breakpoint
-
- # Debug with:
- # (Pdb) p payload
- # (Pdb) p self.ctx.services
- # (Pdb) c # continue
-
- return ok()
-```
-
-### Health Check Endpoints
-
-```python
-def get_router(self):
- from fastapi import APIRouter
- router = APIRouter()
-
- @router.get("/health")
- async def health():
- checks = {
- "database": await self._check_db(),
- "cache": await self._check_cache(),
- "memory": self._check_memory()
- }
-
- healthy = all(checks.values())
- return {
- "status": "healthy" if healthy else "unhealthy",
- "checks": checks
- }
-
- return router
-```
-
-## Common Error Messages
-
-| Error | Cause | Solution |
-|-------|-------|----------|
-| `Context not injected` | Accessing ctx before on_load | Wait for on_load to complete |
-| `Service 'x' not found` | Service not configured | Check integration.yaml |
-| `Plugin not found` | Plugin name incorrect | Check plugin.yaml name |
-| `Rate limit exceeded` | Too many calls | Adjust rate_limit config |
-| `Signature invalid` | Wrong secret key | Verify PLUGIN_SECRET_KEY |
-| `Import error` | Forbidden import in sandbox | Use allowed imports only |
-
-## Getting Help
-
-If you can't resolve your issue:
-
-1. Check [GitHub Issues](https://github.com/traoreera/xcore/issues)
-2. Search [Documentation](https://xcore.readthedocs.io)
-3. Ask in [Discussions](https://github.com/traoreera/xcore/discussions)
-4. Create a minimal reproduction case
-
-### Reporting Bugs
-
-Include:
-- XCore version
-- Python version
-- Operating system
-- Full error traceback
-- Steps to reproduce
-- Minimal code example
diff --git a/docs-tech/index.md b/docs-tech/index.md
deleted file mode 100644
index beb079f6..00000000
--- a/docs-tech/index.md
+++ /dev/null
@@ -1,333 +0,0 @@
-# XCore Framework
-
-**XCore** est un framework Python de niveau production, conçu pour construire des applications modulaires, extensibles et sécurisées. Basé sur **FastAPI** et **asyncio**, il suit une architecture **Modular Monolith** où chaque fonctionnalité est encapsulée dans des plugins isolés.
-
----
-
-
-
-- :material-rocket-launch:{ .lg .middle } **Haute Performance**
-
- Construit sur FastAPI et asyncio pour un débit maximal avec un overhead minimal.
-
-- :material-shield-lock:{ .lg .middle } **Sécurité par Design**
-
- Sandbox multi-couche, validation AST, et moteur de permissions granulaire.
-
-- :material-puzzle-outline:{ .lg .middle } **Architecture Plugin-First**
-
- Tout est un plugin. Chargement, déchargement et rechargement à chaud sans downtime.
-
-- :material-database:{ .lg .middle } **Services Intégrés**
-
- Bases SQL/NoSQL, cache Redis, et scheduling de tâches inclus.
-
-- :material-lightning-bolt:{ .lg .middle } **Événements & Hooks**
-
- Système de messagerie asynchrone pour un couplage lâche entre composants.
-
-- :material-scale-balance:{ .lg .middle } **Isolation Garantie**
-
- Plugins trusted (processus principal) ou sandboxed (processus OS isolé).
-
-
-
----
-
-## Pourquoi XCore ?
-
-Les applications modernes oscillent entre deux extrêmes : le **monolithe rigide** difficile à maintenir et les **microservices complexes** à orchestrer. XCore propose une troisième voie : le **Monolithe Modulaire**.
-
-```mermaid
-flowchart LR
- subgraph Traduction["Spectre des Architectures"]
- direction LR
- M[Monolithe
Rigide] <--> MM[**Monolithe Modulaire**
XCore] <--> MS[Microservices
Complexes]
- end
-
- style MM fill:#4CAF50,color:#fff,stroke:#2E7D32
- style M fill:#FFC107,color:#000
- style MS fill:#FFC107,color:#000
-```
-
-### Les Avantages du Modular Monolith
-
-| Aspect | Monolithe Classique | XCore (Modular Monolith) | Microservices |
-| :--- | :--- | :--- | :--- |
-| **Déploiement** | Unique, risqué | Unique, plugins isolés | Multiple, complexe |
-| **Isolation** | Aucune | Sandbox par plugin | Processus/network |
-| **Scalabilité** | Verticale | Plugins scalables | Horizontale |
-| **Complexité** | Faible | Moyenne | Élevée |
-| **Temps de dev** | Rapide | Rapide | Lent |
-
----
-
-## Architecture en un Coup d'Œil
-
-```mermaid
-flowchart TB
- subgraph App["Application FastAPI"]
- FA[Routes HTTP]
- end
-
- subgraph Kernel["XCore Kernel (Orchestrateur)"]
- direction TB
- X[Xcore Engine
Point d'entrée]
- SC[Service Container
DB, Cache, Scheduler]
- PS[Plugin Supervisor
Cycle de vie]
- EB[Event Bus
Messagerie async]
- PE[Permission Engine
Contrôle d'accès]
- end
-
- subgraph Plugins["Écosystème Plugins"]
- direction LR
- TP[Plugins Trusted
Processus principal]
- SP[Plugins Sandboxed
Processus isolé]
- end
-
- subgraph Services["Services Partagés"]
- DB[(Base de données
SQL/NoSQL)]
- CACHE[(Cache
Redis/Memory)]
- SCHED[Scheduler
APScheduler]
- end
-
- FA --> X
- X --> SC
- X --> PS
- X --> EB
- X --> PE
-
- SC --> Services
- PS --> TP
- PS --> SP
-
- EB -.->|Événements| TP
- EB -.->|Événements| SP
- PE -.->|Permissions| PS
-
- style Kernel fill:#E3F2FD,stroke:#1976D2
- style Plugins fill:#FFF3E0,stroke:#F57C00
- style Services fill:#E8F5E9,stroke:#388E3C
-```
-
----
-
-## Comment XCore Fonctionne
-
-### 1. Initialisation (Boot Sequence)
-
-```mermaid
-sequenceDiagram
- participant Dev as Développeur
- participant App as FastAPI
- participant Kernel as XCore Engine
- participant Services as Services
- participant Loader as PluginLoader
- participant P as Plugins
-
- Dev->>App: Lance l'application
- App->>Kernel: boot(app)
-
- Note over Kernel: 1. Configuration
- Kernel->>Kernel: Charge xcore.yaml + .env
-
- Note over Kernel: 2. Services
- Kernel->>Services: Initialise DB, Cache, Scheduler
- Services-->>Kernel: Services prêts
-
- Note over Kernel: 3. Plugins
- Kernel->>Loader: Découvre les plugins
- Loader->>Loader: Build DAG de dépendances
- Loader->>Loader: Tri topologique
-
- loop Chargement par vagues
- Loader->>P: Load (Trusted/Sandboxed)
- P-->>Loader: Ready
- end
-
- Kernel->>App: Monte les routes plugins
- App-->>Dev: Serveur prêt !
-```
-
-### 2. Cycle de Vie d'un Plugin
-
-```mermaid
-stateDiagram-v2
- [*] --> UNLOADED: Plugin découvert
-
- UNLOADED --> LOADING: supervisor.load()
- LOADING --> READY: on_load() ✅
- LOADING --> FAILED: Erreur ❌
-
- READY --> RELOADING: supervisor.reload()
- RELOADING --> READY: Mise à jour ✅
- RELOADING --> FAILED: Échec ❌
-
- READY --> UNLOADED: supervisor.unload()
- FAILED --> UNLOADED: Cleanup
- FAILED --> RELOADING: Retry
-
- note right of READY
- Plugin opérationnel
- Routes montées
- Événements abonnés
- end note
-
- note right of FAILED
- Erreur de syntaxe
- Dépendance manquante
- Permission refusée
- end note
-```
-
-### 3. Communication Inter-Plugins
-
-Quand le **Plugin A** appelle le **Plugin B**, l'appel transite par le **Supervisor** qui applique un pipeline de sécurité :
-
-```mermaid
-flowchart LR
- subgraph PluginA["Plugin A (Appelant)"]
- A[Code: ctx.plugins.call]
- end
-
- subgraph Supervisor["Pipeline Supervisor"]
- direction TB
- M1[📍 Tracing
Span]
- M2[🛑 Rate Limit
Quota]
- M3[🔐 Permissions
Audit]
- M4[🔄 Retry
Logic]
- end
-
- subgraph PluginB["Plugin B (Cible)"]
- B[Handler @action]
- end
-
- A -- "call()" --> M1
- M1 --> M2
- M2 --> M3
- M3 --> M4
- M4 -- "exécute" --> B
- B -- "résultat" --> A
-
- style Supervisor fill:#FFEBEE,stroke:#C62828
- style M3 fill:#C62828,color:#fff
-```
-
----
-
-## Démarrage Rapide
-
-### Étape 1 : Installation
-
-```bash
-# Avec Poetry (recommandé)
-poetry add xcore-framework
-
-# Ou avec pip
-pip install xcore-framework
-```
-
-### Étape 2 : Configuration
-
-Créez un fichier `xcore.yaml` :
-
-```yaml
-app:
- name: "Mon Application"
- debug: true
-
-services:
- db:
- backend: "sqlite"
- url: "sqlite+aiosqlite:///./app.db"
-
- cache:
- backend: "memory"
- ttl: 300
-```
-
-### Étape 3 : Point d'Entrée
-
-```python
-from fastapi import FastAPI
-from xcore import Xcore
-
-app = FastAPI(title="Mon App XCore")
-core = Xcore(config_path="xcore.yaml")
-
-@app.on_event("startup")
-async def startup():
- await core.boot(app) # 🚀 Boot du kernel
-
-@app.on_event("shutdown")
-async def shutdown():
- await core.shutdown() # 🛑 Cleanup
-```
-
-### Étape 4 : Premier Plugin
-
-```
-plugins/hello/
-├── plugin.yaml
-└── src/
- └── main.py
-```
-
-**plugin.yaml** :
-```yaml
-name: hello
-version: "1.0.0"
-execution_mode: trusted
-entry_point: src/main.py
-```
-
-**src/main.py** :
-```python
-from xcore.sdk import TrustedBase, AutoDispatchMixin, action, ok
-
-class Plugin(AutoDispatchMixin, TrustedBase):
-
- @action("greet")
- async def greet(self, payload: dict):
- name = payload.get("name", "Monde")
- return ok(message=f"Bonjour, {name} !")
-```
-
-### Étape 5 : Tester
-
-```bash
-# Via CLI
-xcore plugin call hello greet '{"name": "Développeur"}'
-
-# Résultat : {"status": "ok", "message": "Bonjour, Développeur !"}
-```
-
----
-
-## Parcours de Documentation
-
-| 📚 Section | Description |
-| :--- | :--- |
-| [🚀 Installation](getting-started/installation.md) | Configurer l'environnement de développement |
-| [⚡ Quick Start](getting-started/quickstart.md) | Créer votre premier plugin en 5 minutes |
-| [🧩 Créer un Plugin](guides/creating-plugins.md) | Guide complet du développement de plugins |
-| [🏗️ Architecture](architecture/overview.md) | Comprendre les internals du framework |
-| [🛡️ Sécurité](guides/security.md) | Sandbox, permissions et isolation |
-| [📡 Événements](guides/events.md) | Système de messagerie et hooks |
-| [🔧 Services](guides/services.md) | Utiliser DB, Cache et Scheduler |
-| [📖 SDK Reference](reference/sdk.md) | API complète du SDK |
-
----
-
-## Ressources Supplémentaires
-
-- [Exemples de code](examples/README.md) - Plugins de base à avancés
-- [CLI Reference](reference/cli.md) - Commandes de gestion
-- [Troubleshooting](guides/troubleshooting.md) - Résolution de problèmes
-- [Contributing](development/contributing.md) - Guide de contribution
-
----
-
-
- XCore Framework — Construit avec ❤️ par l'équipe XCore
-
diff --git a/docs-tech/reference/api.md b/docs-tech/reference/api.md
deleted file mode 100644
index 03fec0e3..00000000
--- a/docs-tech/reference/api.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# Kernel API Reference
-
-This document covers the internal APIs of the XCore kernel, available to `Trusted` plugins via `self.ctx`.
-
-## 1. `PluginSupervisor`
-
-Manages the lifecycle and execution of plugins.
-
-- **`async call(plugin_name: str, action: str, payload: dict, *, resource: str = None) -> dict`**: Executes a cross-plugin call with full middleware support (Security, RateLimit, Tracing).
-- **`async load(plugin_name: str) -> None`**: Dynamically loads a plugin from disk.
-- **`async reload(plugin_name: str) -> None`**: Performs a hot-reload of a plugin.
-- **`async unload(plugin_name: str) -> None`**: Gracefully stops and removes a plugin.
-- **`status() -> dict`**: Returns the health and state of all managed plugins.
-
----
-
-## 2. `ServiceContainer`
-
-Registry for shared resources and infrastructure.
-
-- **`get(name: str) -> Any`**: Retrieves a registered service (e.g., `db`, `cache`).
-- **`has(name: str) -> bool`**: Checks if a service is registered.
-- **`register_service(name: str, service: Any) -> None`**: Manually registers a new service instance.
-- **`async health() -> dict`**: Aggregates health status from all services.
-
----
-
-## 3. `EventBus`
-
-Asynchronous event distribution.
-
-- **`async emit(event: str, data: dict = None, source: str = None)`**: Dispatches an event to all subscribers.
-- **`on(event: str, priority: int = 50)`**: Decorator to subscribe to an event.
-- **`once(event: str)`**: Subscribes for the next occurrence only.
-
----
-
-## 4. `HookManager`
-
-Synchronous filters and actions for fine-grained extensibility.
-
-- **`apply_filters(hook_name: str, value: Any, **kwargs) -> Any`**: Passes a value through a chain of filter functions.
-- **`do_action(hook_name: str, **kwargs)`**: Executes a chain of side-effect actions.
-
----
-
-## 5. `PermissionEngine`
-
-Evaluates security policies.
-
-- **`check(plugin: str, resource: str, action: str) -> None`**: Validates access and raises `PermissionDenied` if unauthorized.
-- **`allows(plugin: str, resource: str, action: str) -> bool`**: Returns boolean status.
diff --git a/docs-tech/reference/cli.md b/docs-tech/reference/cli.md
deleted file mode 100644
index 6ee0dea7..00000000
--- a/docs-tech/reference/cli.md
+++ /dev/null
@@ -1,111 +0,0 @@
-# CLI Reference
-
-The `xcore` CLI is the primary tool for managing plugins, sandboxes, and the marketplace from the terminal.
-
-## General Usage
-
-```bash
-PYTHONPATH=. python -m xcore.cli.main [COMMAND] [OPTIONS]
-```
-*(If installed via pip/poetry, you can simply use `xcore [COMMAND]`)*
-
----
-
-## 1. Plugin Management (`plugin`)
-
-Commands for interacting with the framework's plugins.
-
-### `list`
-Lists all discovered plugins and their current status.
-```bash
-xcore plugin list
-```
-
-### `load` / `unload`
-Manually load or unload a plugin.
-```bash
-xcore plugin load my_plugin
-xcore plugin unload my_plugin
-```
-
-### `reload`
-Hot-reloads a plugin's code and manifest.
-```bash
-xcore plugin reload my_plugin
-```
-
-### `call`
-Invokes an IPC action on a running plugin.
-```bash
-xcore plugin call my_plugin my_action '{"key": "value"}'
-```
-
-### `sign`
-Generates a `plugin.sig` HMAC signature for a plugin directory.
-```bash
-xcore plugin sign ./plugins/my_plugin --key YOUR_SECRET_KEY
-```
-
----
-
-## 2. Sandbox Management (`sandbox`)
-
-Tools for inspecting and testing sandboxed plugins.
-
-### `limits`
-Displays the resource limits and current consumption for a sandboxed plugin.
-```bash
-xcore sandbox limits my_plugin
-```
-
-### `network`
-Audits and displays the network access policy for a sandbox.
-```bash
-xcore sandbox network my_plugin
-```
-
-### `fs`
-Displays the allowed and denied filesystem paths for a sandbox.
-```bash
-xcore sandbox fs my_plugin
-```
-
----
-
-## 3. Marketplace (`marketplace`)
-
-Commands for interacting with the official XCore Marketplace.
-
-### `search`
-Search for plugins in the marketplace.
-```bash
-xcore marketplace search "auth"
-```
-
-### `info`
-Get detailed metadata for a specific marketplace plugin.
-```bash
-xcore marketplace info auth-provider
-```
-
-### `install`
-Downloads and installs a plugin from the marketplace.
-```bash
-xcore marketplace install auth-provider
-```
-
----
-
-## 4. Validation & Utility
-
-### `validate`
-Checks a plugin's `plugin.yaml` and `src/` for syntax errors and security violations.
-```bash
-xcore validate ./plugins/my_plugin
-```
-
-### `health`
-Displays the health status of the kernel and all registered services.
-```bash
-xcore health
-```
diff --git a/docs-tech/reference/configuration.md b/docs-tech/reference/configuration.md
deleted file mode 100644
index de9149ed..00000000
--- a/docs-tech/reference/configuration.md
+++ /dev/null
@@ -1,109 +0,0 @@
-# Exhaustive Configuration Reference
-
-This reference covers every configuration key available in XCore's system and plugin manifests.
-
----
-
-## 1. System Configuration (`xcore.yaml`)
-
-The root configuration file controls the kernel and shared services. It supports environment variable injection using `${VARIABLE_NAME}`.
-
-### `app` Section: Global Identity
-| Key | Type | Default | Description |
-| :--- | :--- | :--- | :--- |
-| `name` | `str` | `xcore-app` | Logical name for the application. |
-| `env` | `str` | `development` | Environment mode: `development`, `staging`, `production`. |
-| `debug` | `bool` | `false` | Enables verbose logging and detailed error responses. |
-| `secret_key` | `str` | - | Primary key for cryptographic operations. |
-| `server_key` | `str` | - | High-entropy key for core-to-plugin authentication. |
-| `plugin_prefix` | `str` | `/plugin` | Base URL prefix for all plugin-exposed HTTP routes. |
-
-### `plugins` Section: Lifecycle & Discovery
-| Key | Type | Default | Description |
-| :--- | :--- | :--- | :--- |
-| `directory` | `str` | `./plugins` | Filesystem path to search for plugins. |
-| `autoload` | `bool` | `true` | Automatically load all valid plugins found in the directory. |
-| `strict_trusted` | `bool` | `true` | In production, `trusted` plugins MUST have a valid `plugin.sig`. |
-| `interval` | `int` | `2` | Polling interval (seconds) for the hot-reload watcher. |
-| `entry_point` | `str` | `src/main.py` | Default entry point file for all plugins. |
-
-### `services` Section: Shared Infrastructure
-
-#### `database`
-| Key | Type | Default | Description |
-| :--- | :--- | :--- | :--- |
-| `enabled` | `bool` | `true` | Enable/disable the global database manager. |
-| `databases` | `dict` | `{}` | Map of named database configurations (see below). |
-
-**Individual Database Entry:**
-- `type`: `sqlite`, `postgresql`, `mysql`, `mongodb`.
-- `url`: Connection string (e.g., `postgresql+asyncpg://...`).
-- `pool_size`: Number of persistent connections (SQL only).
-- `max_overflow`: Extra connections allowed during peak load (SQL only).
-- `echo`: Log all SQL queries to the console.
-
-#### `cache`
-| Key | Type | Default | Description |
-| :--- | :--- | :--- | :--- |
-| `backend` | `str` | `memory` | `memory` or `redis`. |
-| `url` | `str` | - | Redis URL (required if backend is `redis`). |
-| `ttl` | `int` | `300` | Default expiration time in seconds. |
-| `max_size` | `int` | `1000` | Maximum number of items for `memory` backend. |
-
-#### `scheduler`
-| Key | Type | Default | Description |
-| :--- | :--- | :--- | :--- |
-| `enabled` | `bool` | `true` | Enable/disable the APScheduler integration. |
-| `backend` | `str` | `memory` | `memory` or `redis` (for persistent jobs). |
-| `timezone` | `str` | `UTC` | Timezone for cron triggers. |
-
-### `observability` Section: Monitoring
-- **`logging`**: `level` (DEBUG/INFO/WARN/ERROR), `format`, `file`, `max_bytes`, `backup_count`.
-- **`metrics`**: `enabled` (bool), `backend` (`prometheus`/`statsd`), `prefix`.
-- **`tracing`**: `enabled` (bool), `backend` (`opentelemetry`/`jaeger`), `endpoint`.
-
----
-
-## 2. Plugin Manifest (`plugin.yaml`)
-
-Each plugin must have a `plugin.yaml` in its root directory.
-
-### Identity
-- `name` (str): Unique plugin ID.
-- `version` (str): Semantic version.
-- `execution_mode` (str): `trusted` (in-process) or `sandboxed` (isolated process).
-- `entry_point` (str): Relative path to the `.py` file containing the `Plugin` class.
-
-### Dependencies & Imports
-- `requires` (list): List of plugins needed before this one can start.
-- `allowed_imports` (list): Modules allowed in `sandboxed` mode (e.g., `math`, `json`, `pydantic`).
-
-### Security (Permissions)
-A list of policy rules:
-```yaml
-permissions:
- - resource: "db.users.*" # Pattern matching
- actions: ["read", "write"]
- effect: allow # allow | deny
-```
-
-### Resource Management (`resources`)
-- `timeout_seconds` (int): Max time an IPC call can take.
-- `max_memory_mb` (int): RAM limit for sandboxed processes.
-- `max_disk_mb` (int): Disk limit for sandboxed processes.
-- `rate_limit`:
- - `calls` (int): Max calls allowed in the period.
- - `period_seconds` (int): Rolling window duration.
-
-### Runtime Behavior (`runtime`)
-- `health_check`:
- - `enabled` (bool): Enable automatic health polling.
- - `interval_seconds` (int): Frequency.
-- `retry`:
- - `max_attempts` (int): Retries on IPC failure.
- - `backoff_seconds` (float): Delay between retries.
-
-### Filesystem & Env
-- `filesystem.allowed_paths` (list): Paths relative to plugin root.
-- `env` (dict): Environment variables passed to the plugin.
-- `envconfiguration.inject` (bool): Automatically load a local `.env` file.
diff --git a/docs-tech/reference/sdk.md b/docs-tech/reference/sdk.md
deleted file mode 100644
index 7d478da3..00000000
--- a/docs-tech/reference/sdk.md
+++ /dev/null
@@ -1,736 +0,0 @@
-# XCore SDK Reference
-
-Le SDK XCore est une bibliothèque haut niveau conçue pour faciliter le développement de plugins sécurisés, scalables et maintenables.
-
----
-
-## Vue d'Ensemble du SDK
-
-```mermaid
-flowchart TB
- subgraph Core["🎯 Classes Core"]
- TB[TrustedBase
Base plugins trusted]
- BP[BasePlugin
Interface low-level]
- SB[SandboxedBase
Base plugins sandboxed]
- end
-
- subgraph Mixins["🔧 Mixins"]
- ADM[AutoDispatchMixin
Routage @action]
- RP[RoutedPlugin
Routes HTTP]
- VM[ValidateMixin
Validation Pydantic]
- end
-
- subgraph Decorators["📝 Décorateurs"]
- D1[@action]
- D2[@route]
- D3[@validate_payload]
- D4[@on / @filter]
- end
-
- subgraph Helpers["🛠️ Helpers"]
- H1[ok / error]
- H2[Event]
- H3[Response types]
- end
-
- Core --> Mixins
- Mixins --> Decorators
- Decorators --> Helpers
-
- style Core fill:#E3F2FD,stroke:#1976D2
- style Mixins fill:#FFF3E0,stroke:#F57C00
- style Decorators fill:#E8F5E9,stroke:#388E3C
- style Helpers fill:#F3E5F5,stroke:#7B1FA2
-```
-
----
-
-## 1. Classes Core
-
-### `TrustedBase`
-
-Classe de base principale pour les plugins qui s'exécutent dans le **processus principal** XCore.
-
-```mermaid
-classDiagram
- class TrustedBase {
- #ctx: PluginContext
- #logger: Logger
- +name: str
- +version: str
- +async on_load() None
- +async on_unload() None
- +async on_reload() None
- +async handle(action, payload) dict
- +get_service(name) Any
- +call_plugin(name, action, payload) Future
- }
-
- class AutoDispatchMixin {
- +async handle(action, payload) dict
- #_find_action_handler(action) Method
- }
-
- class RoutedPlugin {
- #_routes: List[Route]
- #discover_routes() None
- #get_routes() List[Route]
- }
-
- TrustedBase <|-- AutoDispatchMixin
- TrustedBase <|-- RoutedPlugin
-
- note for TrustedBase "Base class pour plugins trusted"
- note for AutoDispatchMixin "Routage automatique via @action"
- note for RoutedPlugin "Support des routes HTTP"
-```
-
-#### Cycle de Vie
-
-```mermaid
-sequenceDiagram
- participant S as Supervisor
- participant P as Plugin Instance
- participant L as on_load
- participant U as on_unload
-
- S->>P: Instancier
- S->>L: on_load()
- Note over L: Initialiser services
Subscrire événements
- L-->>S: ✅ Ready
-
- Note over P: Plugin opérationnel...
-
- S->>U: on_unload()
- Note over U: Cleanup ressources
Unsubscribe événements
- U-->>S: ✅ Unloaded
-```
-
-#### Implémentation Complète
-
-```python
-from xcore.sdk import TrustedBase, AutoDispatchMixin, action, ok, error
-from pydantic import BaseModel, Field
-from typing import Optional
-
-class GreetInput(BaseModel):
- """Schema de validation pour l'action greet."""
- name: str = Field(min_length=1, max_length=100, description="Nom à saluer")
- language: str = Field(default="fr", description="Langue")
-
-class Plugin(AutoDispatchMixin, TrustedBase):
- """
- Plugin de démonstration montrant toutes les fonctionnalités de TrustedBase.
- """
-
- async def on_load(self) -> None:
- """
- 🎯 Point d'entrée au chargement du plugin.
-
- Initialiser ici :
- - Les services (db, cache, scheduler)
- - Les subscriptions d'événements
- - L'état interne
- """
- self.logger.info(f"🚀 Chargement de {self.name} v{self.version}")
-
- # Initialiser les services
- self.db = self.get_service("db")
- self.cache = self.get_service("cache")
- self.scheduler = self.get_service("scheduler")
-
- # S'abonner à un événement
- self.ctx.events.on("user.created", self._on_user_created, priority=50)
-
- self.logger.info("✅ Plugin prêt")
-
- async def on_unload(self) -> None:
- """
- 🧹 Point de cleanup au déchargement.
-
- Nettoyer ici :
- - Connexions ouvertes
- - Subscriptions événements
- - Tâches scheduler
- """
- self.logger.info(f"👋 Déchargement de {self.name}")
- # Cleanup si nécessaire
-
- async def on_reload(self) -> None:
- """
- 🔄 Appelé lors d'un hot-reload.
-
- Re-initialiser l'état sans perdre les connexions.
- """
- self.logger.info(f"🔄 Rechargement de {self.name}")
- await self.on_load() # Ré-initialiser
-
- @action("greet")
- async def greet(self, payload: dict) -> dict:
- """
- 🎯 Action: Saluer un utilisateur.
-
- Args:
- payload: {"name": "Votre nom", "language": "fr"}
-
- Returns:
- {"status": "ok", "message": "Bonjour, X !"}
- """
- # Valider l'input
- try:
- input_data = GreetInput(**payload)
- except ValidationError as e:
- return error(msg=str(e), code="invalid_input", status_code=400)
-
- # Logique métier
- greetings = {
- "fr": "Bonjour",
- "en": "Hello",
- "es": "Hola"
- }
- greeting = greetings.get(input_data.language, "Hello")
- message = f"{greeting}, {input_data.name} !"
-
- self.logger.info(f"Salutation: {message}")
- return ok(message=message)
-
- @on("user.created")
- async def _on_user_created(self, event: Event) -> None:
- """Handler pour l'événement user.created."""
- user_email = event.data.get("email")
- self.logger.info(f"Nouvel utilisateur: {user_email}")
-```
-
----
-
-### `BasePlugin`
-
-Interface low-level pour tous les types de plugins. Utilisé pour la logique interne du framework ou pour construire des runners personnalisés.
-
-```python
-from xcore.sdk import BasePlugin
-
-class CustomPluginRunner(BasePlugin):
- """
- Implémentation personnalisée d'un runner de plugin.
- """
-
- async def initialize(self, config: dict) -> None:
- """Initialisation personnalisée."""
- pass
-
- async def execute(self, action: str, payload: dict) -> dict:
- """Exécution personnalisée."""
- return {"status": "ok", "result": "custom"}
-
- async def cleanup(self) -> None:
- """Cleanup personnalisé."""
- pass
-```
-
----
-
-## 2. Décorateurs
-
-### `@action(name: str)`
-
-Définit une méthode comme handler d'action IPC. Nécessite `AutoDispatchMixin`.
-
-```mermaid
-flowchart LR
- A[Appel IPC
action="greet"] --> B[AutoDispatchMixin.handle]
- B --> C{Rechercher
@action("greet")}
- C -->|Trouvé| D[Exécuter handler]
- C -->|Non trouvé| E[❌ Error 404]
- D --> F[Retourner résultat]
-
- style B fill:#E3F2FD,stroke:#1976D2
- style D fill:#E8F5E9,stroke:#388E3C
- style E fill:#FFEBEE,stroke:#C62828
-```
-
-```python
-from xcore.sdk import TrustedBase, AutoDispatchMixin, action, ok
-
-class Plugin(AutoDispatchMixin, TrustedBase):
-
- @action("ping")
- async def ping(self, payload: dict) -> dict:
- """Health check simple."""
- return ok(status="pong", timestamp=self._now())
-
- @action("add")
- async def add(self, payload: dict) -> dict:
- """Additionne deux nombres."""
- a = payload.get("a", 0)
- b = payload.get("b", 0)
- return ok(result=a + b)
-
- @action("complex_operation")
- async def complex_op(self, payload: dict) -> dict:
- """Opération avec validation et services."""
- # Accéder au service
- db = self.get_service("db")
-
- # Vérifier le cache
- cache_key = f"op:{payload.get('id')}"
- cached = await self.cache.get(cache_key)
- if cached:
- return ok(result=cached, source="cache")
-
- # Exécuter l'opération
- result = await self._do_operation(payload)
-
- # Caster le résultat
- await self.cache.set(cache_key, result, ttl=300)
-
- return ok(result=result, source="computed")
-```
-
----
-
-### `@route(path: str, method: str, ...)`
-
-Définit une route FastAPI directement sur la classe du plugin. Nécessite le mixin `RoutedPlugin`.
-
-```mermaid
-flowchart TB
- subgraph Plugin["🧩 Plugin"]
- R1[@route("/users", GET)]
- R2[@route("/users/{id}", GET)]
- R3[@route("/users", POST)]
- end
-
- subgraph Mount["📡 FastAPI Mount"]
- M1[/plugin/my_plugin/users]
- M2[/plugin/my_plugin/users/{id}]
- end
-
- R1 --> M1
- R2 --> M2
- R3 --> M1
-
- style Plugin fill:#FFF3E0,stroke:#F57C00
- style Mount fill:#E3F2FD,stroke:#1976D2
-```
-
-#### Paramètres du Décorateur
-
-| Paramètre | Type | Défaut | Description |
-| :--- | :--- | :--- | :--- |
-| `path` | str | Requis | Chemin de la route |
-| `method` | str | "GET" | Méthode HTTP |
-| `tags` | list | None | Tags pour OpenAPI |
-| `summary` | str | None | Résumé pour docs |
-| `status_code` | int | 200 | Code de statut par défaut |
-| `dependencies` | list | None | Dépendances FastAPI |
-| `permissions` | list | None | Permissions requises |
-
-#### Exemple Complet
-
-```python
-from xcore.sdk import TrustedBase, RoutedPlugin, route, ok, error
-from fastapi import Depends, HTTPException
-from pydantic import BaseModel, EmailStr
-
-class UserCreate(BaseModel):
- email: EmailStr
- name: str
- password: str
-
-class UserResponse(BaseModel):
- id: int
- email: str
- name: str
-
-class Plugin(RoutedPlugin, TrustedBase):
- """Plugin avec routes HTTP complètes."""
-
- @route("/users", method="GET", tags=["users"], summary="Lister les utilisateurs")
- async def list_users(self, limit: int = 100, offset: int = 0) -> dict:
- """
- Liste tous les utilisateurs avec pagination.
-
- - **limit**: Nombre maximum d'utilisateurs
- - **offset**: Décalage pour la pagination
- """
- db = self.get_service("db")
- async with db.session() as session:
- query = f"SELECT * FROM users LIMIT {limit} OFFSET {offset}"
- result = await session.execute(query)
- users = result.fetchall()
-
- return ok(users=[dict(u) for u in users], total=len(users))
-
- @route("/users/{user_id}", method="GET", tags=["users"])
- async def get_user(self, user_id: int) -> dict:
- """Récupérer un utilisateur par ID."""
- db = self.get_service("db")
- async with db.session() as session:
- query = "SELECT * FROM users WHERE id = :id"
- result = await session.execute(query, {"id": user_id})
- user = result.fetchone()
-
- if not user:
- return error(msg="Utilisateur non trouvé", code="not_found", status_code=404)
-
- return ok(user=dict(user))
-
- @route("/users", method="POST", tags=["users"], status_code=201)
- async def create_user(self, data: UserCreate) -> dict:
- """Créer un nouvel utilisateur."""
- db = self.get_service("db")
-
- async with db.session() as session:
- query = "INSERT INTO users (email, name) VALUES (:email, :name) RETURNING *"
- result = await session.execute(query, dict(data))
- user = result.fetchone()
- await session.commit()
-
- # Émettre un événement
- await self.ctx.events.emit("user.created", {
- "id": user.id,
- "email": user.email
- })
-
- return ok(user=dict(user))
-
- @route("/health", method="GET", tags=["system"])
- async def health_check(self) -> dict:
- """Endpoint de santé du plugin."""
- return ok(
- plugin=self.name,
- version=self.version,
- status="healthy"
- )
-```
-
----
-
-### `@validate_payload(schema: Type[BaseModel], type_response="dict")`
-
-Valide automatiquement le payload IPC contre un modèle Pydantic.
-
-```mermaid
-flowchart TB
- A[Payload Reçu] --> B[@validate_payload]
- B --> C{Validation}
- C -->|✅ Valide| D[Handler exécuté]
- C -->|❌ Invalide| E[Erreur 400]
-
- D --> F{type_response ?}
- F -->|dict| G[Dict validé]
- F -->|pydantic| H[Instance Pydantic]
-
- style B fill:#E3F2FD,stroke:#1976D2
- style E fill:#FFEBEE,stroke:#C62828
-```
-
-#### Modes de Retour
-
-```python
-from xcore.sdk import TrustedBase, AutoDispatchMixin, action, ok
-from xcore.sdk.decorators import validate_payload
-from pydantic import BaseModel
-
-class CreateUserInput(BaseModel):
- email: str
- name: str
- age: int = Field(ge=0, le=150)
-
-class Plugin(AutoDispatchMixin, TrustedBase):
-
- # Mode 1: Retourne un dict validé
- @action("create_user_dict")
- @validate_payload(CreateUserInput, type_response="dict")
- async def create_user_dict(self, payload: dict) -> dict:
- # payload est un dict validé
- email = payload["email"]
- name = payload["name"]
- return ok(email=email, name=name)
-
- # Mode 2: Retourne l'instance Pydantic
- @action("create_user_model")
- @validate_payload(CreateUserInput, type_response="pydantic")
- async def create_user_model(self, payload: CreateUserInput) -> dict:
- # payload est une instance CreateUserInput
- email = payload.email
- name = payload.name
- age = payload.age
- return ok(email=email, name=name, age=age)
-```
-
----
-
-### `@trusted` / `@sandboxed`
-
-Markers pour s'assurer qu'une méthode s'exécute uniquement dans le mode spécifié.
-
-```python
-from xcore.sdk import TrustedBase, trusted, sandboxed, action
-
-class Plugin(TrustedBase):
-
- @action("trusted_only")
- @trusted
- async def trusted_operation(self, payload: dict) -> dict:
- """Ne s'exécute que en mode trusted."""
- return ok(result="trusted")
-
- @action("sandboxed_only")
- @sandboxed
- async def sandboxed_operation(self, payload: dict) -> dict:
- """Ne s'exécute que en mode sandboxed."""
- return ok(result="sandboxed")
-```
-
----
-
-### `@on(event_name: str, priority: int = 50)`
-
-Subscribe un handler à un événement.
-
-```python
-from xcore.sdk import TrustedBase, on, Event
-
-class Plugin(TrustedBase):
-
- @on("user.created", priority=100)
- async def handle_user_created(self, event: Event):
- """Handler avec haute priorité."""
- pass
-
- @on("order.completed", priority=50)
- async def handle_order_completed(self, event: Event):
- """Handler avec priorité normale."""
- pass
-```
-
----
-
-### `@filter(hook_name: str)` et `@action_hook(hook_name: str)`
-
-Enregistre un hook filter ou action.
-
-```python
-from xcore.sdk import TrustedBase, filter, action_hook
-
-class Plugin(TrustedBase):
-
- @filter("page_title")
- def modify_title(self, title: str) -> str:
- """Filter: modifie le titre de page."""
- return f"{title} | Mon App"
-
- @action_hook("before_render")
- def before_render_log(self, template: str):
- """Action hook: log avant rendu."""
- self.logger.info(f"Rendu: {template}")
-```
-
----
-
-## 3. Mixins
-
-### `AutoDispatchMixin`
-
-Fournit une implémentation automatique de `handle()` en routant vers les méthodes décorées avec `@action`.
-
-```mermaid
-flowchart TB
- A[IPC: handle("greet", payload)] --> B[AutoDispatchMixin.handle]
- B --> C[Rechercher @action("greet")]
- C --> D{Trouvé ?}
- D -->|Oui| E[Exécuter greet(payload)]
- D -->|Non| F[Erreur: Action inconnue]
- E --> G[Retourner résultat]
- F --> H[Retourner error()]
-
- style B fill:#E3F2FD,stroke:#1976D2
- style E fill:#E8F5E9,stroke:#388E3C
- style F fill:#FFEBEE,stroke:#C62828
-```
-
-```python
-# Sans AutoDispatchMixin (verbeux)
-class Plugin(TrustedBase):
- async def handle(self, action: str, payload: dict) -> dict:
- if action == "ping":
- return await self.ping(payload)
- elif action == "greet":
- return await self.greet(payload)
- else:
- return error(f"Action inconnue: {action}", code="not_found")
-
-# Avec AutoDispatchMixin (concis)
-class Plugin(AutoDispatchMixin, TrustedBase):
-
- @action("ping")
- async def ping(self, payload: dict) -> dict:
- return ok(status="pong")
-
- @action("greet")
- async def greet(self, payload: dict) -> dict:
- return ok(message=f"Hello !")
-```
-
----
-
-### `RoutedPlugin`
-
-Active la découverte automatique et le montage des routes FastAPI.
-
-```python
-from xcore.sdk import TrustedBase, RoutedPlugin, route
-
-class Plugin(RoutedPlugin, TrustedBase):
- """Les routes sont automatiquement montées sur /plugin/{name}/..."""
-
- @route("/hello", methods=["GET"])
- async def hello(self):
- return {"message": "Hello"}
-
- @route("/hello/{name}", methods=["GET"])
- async def hello_name(self, name: str):
- return {"message": f"Hello, {name}!"}
-```
-
-**Routes montées :**
-- `GET /plugin/my_plugin/hello`
-- `GET /plugin/my_plugin/hello/{name}`
-
----
-
-## 4. Helpers
-
-### `ok(**kwargs) -> dict`
-
-Génère une réponse de succès standardisée.
-
-```python
-from xcore.sdk import ok
-
-# Simple
-ok(message="Succès")
-# → {"status": "ok", "message": "Succès"}
-
-# Multiple
-ok(user_id=123, email="test@example.com")
-# → {"status": "ok", "user_id": 123, "email": "test@example.com"}
-
-# Avec données complexes
-ok(users=[...], total=100, page=1)
-# → {"status": "ok", "users": [...], "total": 100, "page": 1}
-```
-
-### `error(msg: str, code: str, status_code: int = 400) -> dict`
-
-Génère une réponse d'erreur standardisée.
-
-```python
-from xcore.sdk import error
-
-# Erreur de validation
-error(msg="Champ requis manquant", code="validation_error", status_code=400)
-# → {"status": "error", "msg": "Champ requis manquant", "code": "validation_error"}
-
-# Erreur not found
-error(msg="Ressource non trouvée", code="not_found", status_code=404)
-# → {"status": "error", "msg": "Ressource non trouvée", "code": "not_found"}
-
-# Erreur serveur
-error(msg="Erreur interne", code="internal_error", status_code=500)
-```
-
----
-
-## 5. Repositories & Data Access
-
-### `BaseAsyncRepository`
-
-Classe de base pour les interactions asynchrones avec la base de données.
-
-```python
-from xcore.repositories import BaseAsyncRepository
-from typing import TypeVar, Generic, List, Optional
-from pydantic import BaseModel
-
-class User(BaseModel):
- id: int
- email: str
- name: str
-
-class UserRepository(BaseAsyncRepository):
- """Repository pour les opérations sur les utilisateurs."""
-
- async def get_by_email(self, email: str) -> Optional[User]:
- """Récupérer un utilisateur par email."""
- query = "SELECT * FROM users WHERE email = :email"
- result = await self.session.execute(query, {"email": email})
- row = result.fetchone()
- return User(**dict(row)) if row else None
-
- async def list_all(self, limit: int = 100) -> List[User]:
- """Lister tous les utilisateurs."""
- query = "SELECT * FROM users LIMIT :limit"
- result = await self.session.execute(query, {"limit": limit})
- return [User(**dict(row)) for row in result.fetchall()]
-
- async def create(self, data: dict) -> User:
- """Créer un nouvel utilisateur."""
- query = "INSERT INTO users (email, name) VALUES (:email, :name) RETURNING *"
- result = await self.session.execute(query, data)
- row = result.fetchone()
- await self.session.commit()
- return User(**dict(row))
-```
-
----
-
-## 6. RBAC Checker
-
-Dépendance FastAPI pour appliquer le contrôle d'accès basé sur les rôles.
-
-```python
-from fastapi import Depends
-from xcore.security import RBACChecker, require_role
-
-checker = RBACChecker()
-
-@route("/admin/users", methods=["GET"], dependencies=[Depends(require_role("admin"))])
-async def list_users_admin():
- """Route protégée: nécessite le rôle admin."""
- pass
-
-@route("/profile", methods=["GET"], dependencies=[Depends(require_role("user"))])
-async def get_profile():
- """Route protégée: nécessite le rôle user."""
- pass
-```
-
----
-
-## 7. Tableau Récapitulatif
-
-| Composant | Usage | Exemple |
-| :--- | :--- | :--- |
-| `TrustedBase` | Base class plugins | `class Plugin(TrustedBase)` |
-| `AutoDispatchMixin` | Routage @action | `class Plugin(AutoDispatchMixin, TrustedBase)` |
-| `RoutedPlugin` | Routes HTTP | `@route("/path")` |
-| `@action` | Handler IPC | `@action("greet")` |
-| `@route` | Route HTTP | `@route("/users/{id}")` |
-| `@validate_payload` | Validation Pydantic | `@validate_payload(UserSchema)` |
-| `@on` | Subscription événement | `@on("user.created")` |
-| `@filter` | Hook filter | `@filter("page_title")` |
-| `ok()` | Réponse succès | `ok(message="OK")` |
-| `error()` | Réponse erreur | `error(msg="Error", code="bad")` |
-
----
-
-## Prochaines Lectures
-
-| 📚 Guide | Objectif |
-| :--- | :--- |
-| [Creating Plugins](../guides/creating-plugins.md) | Tutoriel complet |
-| [Security](../guides/security.md) | Bonnes pratiques sécurité |
-| [Events](../guides/events.md) | Système d'événements |
diff --git a/docs-tech/requirements.txt b/docs-tech/requirements.txt
deleted file mode 100644
index a28673ed..00000000
--- a/docs-tech/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-mkdocs ==1.6.1
-mkdocs-material ==9.7.3
-mkdocs-minify-plugin ==0.8.0
-mkdocstrings ==1.0.3
diff --git a/docs-tech/scaling_analysis.md b/docs-tech/scaling_analysis.md
deleted file mode 100644
index ebaf6973..00000000
--- a/docs-tech/scaling_analysis.md
+++ /dev/null
@@ -1,108 +0,0 @@
-# XCore Architectural Scaling & Audit Report
-
-## 1. Executive Summary
-The XCore architecture is a robust "Modular Monolith" designed to manage dynamic plugins with strong isolation and dependency injection. While the current version (v2.0.0) successfully addresses several initial design flaws (e.g., namespace isolation), our audit identifies critical coupling points and anti-patterns that will hinder scalability and maintenance as the ecosystem grows.
-
-This report outlines our findings and provides a concrete roadmap for future refactorings.
-
----
-
-## 2. Layer Analysis & Audit
-
-### Core Kernel (`xcore.kernel`)
-- **Shared State Contention:** The framework relies on a shared `dict[str, Any]` for service discovery. This lacks encapsulation and is prone to race conditions during concurrent plugin operations.
-- **Manual Orchestration:** `PluginSupervisor` manually configures permissions, rate limits, and routing. This approach is not extensible; adding new cross-cutting concerns (e.g., logging, circuit breakers) requires modifying the core.
-
-### Plugins & Sandbox
-- **Divergent Activation:** Trusted and Sandboxed plugins follow different activation paths, leading to code duplication in `PluginLoader`.
-- **Fragile Isolation:** Trusted plugins use `sys.modules` manipulation for isolation, which can lead to memory leaks or stale state if sub-modules are not perfectly purged.
-
-### Services Layer (`xcore.services`)
-- **Open/Closed Violation:** Core service providers are hardcoded in the `ServiceContainer`. Adding a new core service requires a framework-level change.
-
----
-
-## 3. Detected Anti-Patterns & Risks
-
-| Anti-Pattern | Location | Impact | Risk Level |
-| :--- | :--- | :--- | :--- |
-| **Hardcoded Providers** | `container.py` | Violates Open/Closed Principle | Medium |
-| **Manual Middleware Config**| `supervisor.py` | Hinders extensibility | High |
-| **Cryptic Naming** | `lifecycle.py` | Increases cognitive load (`mems`) | Low (Fixed) |
-| **Direct State Mutation** | `LifecycleManager` | Risk of inconsistent system state | High |
-
-> **Note:** The cryptic `mems` method has been refactored to `propagate_services` as part of this audit to improve maintainability.
-
----
-
-## 4. Proposed Refactorings & Improvements
-
-### A. Unified & Scoped Service Registry
-Merge `PluginRegistry` and `ServiceContainer` into a single, thread-safe registry that supports private vs. public scoping.
-
-```python
-from dataclasses import dataclass, field
-from typing import Any, Dict
-import threading
-
-@dataclass
-class ServiceEntry:
- obj: Any
- plugin: str
- scope: str = "public" # "public", "private", or "protected"
- metadata: Dict[str, Any] = field(default_factory=dict)
-
-class UnifiedServiceRegistry:
- def __init__(self):
- self._services: Dict[str, ServiceEntry] = {}
- self._lock = threading.Lock()
-
- def register(self, name: str, service: Any, plugin: str, scope: str = "public"):
- with self._lock:
- if name in self._services and self._services[name].scope == "protected":
- raise PermissionError(f"Cannot overwrite protected service: {name}")
- self._services[name] = ServiceEntry(obj=service, plugin=plugin, scope=scope)
-
- def get(self, name: str, requester: str = None) -> Any:
- entry = self._services.get(name)
- if not entry:
- raise KeyError(f"Service not found: {name}")
-
- if entry.scope == "private" and entry.plugin != requester:
- raise PermissionError(f"Access to private service '{name}' denied to '{requester}'")
-
- return entry.obj
-```
-
-### B. Event-Driven Lifecycle Hooks
-Transition from manual orchestration to a reactive lifecycle using the `EventBus`. This decouples the core from individual plugin configurations.
-
-```python
-# In LifecycleManager.load()
-async def load(self):
- await self._do_load()
- # Replace manual calls with events
- await self._events.emit("plugin.activated", {
- "name": self.manifest.name,
- "mode": self.manifest.execution_mode,
- "services": self._instance.get_exposed_services()
- })
-
-# In PluginSupervisor (or a new PluginLifecycleObserver)
-async def on_plugin_activated(self, event):
- # Reactive configuration of cross-cutting concerns
- name = event["name"]
- self._registry.register_all(name, event["services"])
- self._permissions.auto_load(name, self._loader.get(name).manifest)
- self._rate_limiter.auto_register(name, self._loader.get(name).manifest)
-```
-
-### C. Standardized IPC for Sandboxed Services
-Expose services from sandboxed plugins via a standardized RPC-over-IPC protocol. This would allow the core to treat sandboxed services as "remote objects," unifying the API for developers regardless of the plugin's execution mode.
-
----
-
-## 5. Final Recommendations
-1. **Unify Service Discovery:** Implement the `UnifiedServiceRegistry` to centralize access control.
-2. **Move to Reactive Lifecycle:** Use events to handle plugin startup and shutdown to improve extensibility.
-3. **Enhance Sandbox Transparency:** Build a proxy layer so sandboxed services can be injected just like trusted ones.
diff --git a/docs-tech/versions.md b/docs-tech/versions.md
deleted file mode 100644
index 81d76651..00000000
--- a/docs-tech/versions.md
+++ /dev/null
@@ -1,394 +0,0 @@
-# XCore Versions
-
-This page lists the version history of the XCore framework, major changes, and update notes.
-
-## Current Version
-
-### XCore v2.0.0 (Stable)
-
-**Release Date**: March 2025
-
-**Status**: ✅ Stable and Recommended
-
-Version 2.0 is a complete rewrite of the framework with a plugin-first architecture, a reinforced sandboxing system, and native service integration.
-
-#### Main Features
-
-- **🏗️ Plugin-First Architecture** — The core is minimal; all features are implemented as plugins.
-- **🔒 Sandboxing System** — Isolated plugin execution with AST and IPC restrictions.
-- **⚡ Native FastAPI Integration** — Plugins can expose their own HTTP routes seamlessly.
-- **🔄 Hot Reloading** — Dynamic plugin reloading without server restarts.
-- **📊 Built-in Observability** — Structured logging, Prometheus metrics, and OpenTelemetry tracing.
-- **🗄️ Multi-Database Support** — Support for PostgreSQL, MySQL, SQLite, MongoDB, and Redis.
-- **⏰ Integrated Scheduler** — APScheduler with Redis persistence.
-- **🔐 Reinforced Security** — HMAC signatures, granular permissions, and rate limiting.
-
-#### Changes from v1.x
-
-| Feature | v1.x | v2.0 |
-|---------|------|------|
-| Architecture | Monolithic | Plugin-first |
-| Isolation | Basic Process | AST Sandboxing + IPC |
-| HTTP Routes | Limited | Full via `get_router()` |
-| Plugin Types | Trusted Only | Trusted + Sandboxed |
-| Configuration | Python-only | YAML + Environment |
-| Database | SQL Only | SQL + NoSQL + Cache |
-| EventBus | Basic | Priorities + Hooks |
-| Reloading | Manual | Automatic (Watchdog) |
-
-#### Migration from v1.x
-
-See the detailed migration guide in [Migrations](#migration-from-v1x).
-
----
-
-## Version History
-
-### v2.0.0 (2025-03-21)
-
-**Major New Features**
-
-- Complete architectural shift to plugin-first.
-- Introduction of the sandboxing system with process-level isolation.
-- Support for Sandboxed plugins via IPC.
-- Full FastAPI integration with automatic router mounting.
-- ServiceContainer with typed dependency injection.
-- EventBus with priorities (HIGH, NORMAL, LOW).
-- HookManager for filters and actions.
-- PermissionEngine for granular access control.
-- Per-plugin RateLimiter with YAML configuration.
-- Integrated health checks for all services.
-- Redis support as a cache and scheduler backend.
-- Comprehensive CLI (`xcore plugin`, `xcore sandbox`, `xcore services`).
-- Auto-discovery and automatic plugin loading.
-
-**Breaking Changes**
-
-- The `Plugin` class from v1 is replaced by `TrustedBase`.
-- Imports have changed: `from xcore import Xcore, TrustedBase`.
-- Configuration file moved from `config.py` to `xcore.yaml`.
-- Plugins must now define a `plugin.yaml` manifest.
-
-**Fixes**
-
-- Complete plugin isolation (no module name conflicts).
-- Clean lifecycle management (load/reload/unload).
-- Memory leaks fixed during reloading.
-
----
-
-### v1.2.0 (2024-11-15)
-
-**New Features**
-
-- Support for Python 3.12.
-- Performance improvements for PluginLoader.
-- New CLI commands.
-
-**Fixes**
-
-- Memory leak in plugin reloading.
-- Race condition in EventBus.
-
----
-
-### v1.1.0 (2024-08-20)
-
-**New Features**
-
-- Redis support for distributed cache.
-- Logging system improvements.
-- MkDocs documentation.
-
-**Fixes**
-
-- Async DB connection issue.
-- Timeouts too short for some plugins.
-
----
-
-### v1.0.0 (2024-06-01)
-
-**First Stable Version**
-
-- Basic plugin system.
-- Support for PostgreSQL and SQLite.
-- Simple EventBus.
-- Python-based configuration.
-- Minimal CLI.
-
----
-
-### v0.9.0-beta (2024-04-10)
-
-**Initial Beta Version**
-
-- Core architecture.
-- Dynamic plugin loading.
-- Basic FastAPI support.
-
----
-
-## Roadmap
-
-### v2.1.0 (Planned - Q2 2025)
-
-**Planned Features**
-
-- [ ] Integrated Plugin Marketplace.
-- [ ] GraphQL support for plugins.
-- [ ] Native WebSocket for real-time communication.
-- [ ] Automatic auto-scaling of sandbox workers.
-- [ ] Web-based monitoring dashboard.
-
-### v2.2.0 (Planned - Q3 2025)
-
-**Planned Features**
-
-- [ ] gRPC support for inter-service communication.
-- [ ] Integrated Circuit Breaker.
-- [ ] End-to-end encryption for IPC.
-- [ ] Plugin marketplace with automatic verification.
-
-### v3.0.0 (Planned - 2026)
-
-**Long-term Goals**
-
-- WebAssembly support for ultra-isolated plugins.
-- Distributed XCore (multi-node cluster).
-- Integrated Machine Learning for auto-scaling.
-
----
-
-## Support Policy
-
-| Version | Status | Supported Until |
-|---------|--------|------------------|
-| v2.0.x | ✅ Active | March 2026 |
-| v1.2.x | 🛟 Maintenance | June 2025 |
-| v1.1.x | ❌ End of Life | November 2024 |
-| v1.0.x | ❌ End of Life | August 2024 |
-| < v1.0 | ❌ End of Life | June 2024 |
-
-**Legend**:
-
-- ✅ **Active** — Receives all fixes and new features.
-- 🛟 **Maintenance** — Security fixes only.
-- ❌ **End of Life** — No longer supported; update recommended.
-
----
-
-## Detailed Release Notes
-
-### XCore v2.0.0
-
-#### Kernel Architecture
-
-The XCore v2 kernel is designed around several key components:
-
-```
-XCore
-├── PluginSupervisor # Plugin orchestration
-├── ServiceContainer # Service management
-├── EventBus # Event-driven communication
-├── HookManager # Hooks and filters
-└── PluginRegistry # Plugin registry
-```
-
-#### Plugin Types
-
-**Trusted Plugins**
-
-- Run in the main process.
-- Full access to services.
-- Can expose HTTP routes.
-- HMAC signature required in strict mode.
-
-**Sandboxed Plugins**
-
-- Run in isolated processes.
-- AST restrictions on imports.
-- Communication via IPC.
-- Resource limits (memory, CPU, time).
-
-#### Integrated Services
-
-| Service | Description | Configuration |
-|---------|-------------|---------------|
-| Database | SQL and NoSQL | `services.databases` |
-| Cache | Memory or Redis | `services.cache` |
-| Scheduler | Scheduled tasks | `services.scheduler` |
-| Extensions | Custom services | `services.extensions` |
-
-#### Migration from v1.x
-
-**Step 1**: Update imports
-
-```python
-# v1.x
-from xcore import Plugin
-
-# v2.0
-from xcore import TrustedBase
-```
-
-**Step 2**: Create `plugin.yaml`
-
-```yaml
-# plugin.yaml
-name: my_plugin
-version: "2.0.0"
-execution_mode: trusted
-entry_point: src/main.py
-```
-
-**Step 3**: Migrate configuration
-
-```yaml
-# xcore.yaml (new)
-app:
- name: my-app
- env: production
-
-plugins:
- directory: ./plugins
-
-services:
- databases:
- default:
- type: postgresql
- url: "${DATABASE_URL}"
-```
-
-**Step 4**: Adapt lifecycle hooks
-
-```python
-# v1.x
-class Plugin:
- def load(self):
- pass
-
-# v2.0
-class Plugin(TrustedBase):
- async def on_load(self):
- pass
-
- async def on_unload(self):
- pass
-```
-
----
-
-## Specific Version Installation
-
-### Via Poetry
-
-```bash
-# Latest version
-poetry add xcore
-
-# Specific version
-poetry add xcore@2.0.0
-
-# Version constraint
-poetry add "xcore@^2.0"
-```
-
-### Via pip
-
-```bash
-# Latest version
-pip install xcore
-
-# Specific version
-pip install xcore==2.0.0
-
-# Minimum version
-pip install "xcore>=2.0.0"
-```
-
-### Via git
-
-```bash
-# Latest stable version
-git clone https://github.com/traoreera/xcore.git
-cd xcore
-poetry install
-
-# Specific tag
-git checkout v2.0.0
-poetry install
-```
-
----
-
-## Reporting Issues
-
-If you encounter issues with a specific version:
-
-1. Check [GitHub issues](https://github.com/traoreera/xcore/issues).
-2. Verify if the issue exists in the latest version.
-3. Create an issue including:
- - XCore version.
- - Python version.
- - Operating system.
- - Description of the issue.
- - Reproduction code.
-
----
-
-## Verify Your Version
-
-```python
-import xcore
-
-print(xcore.__version__) # "2.0.0"
-print(xcore.__version_info__) # (2, 0, 0)
-```
-
-Via CLI:
-
-```bash
-poetry run xcore --version
-# xcore v2.0.0
-```
-
----
-
-## Compatibility
-
-### Python
-
-| XCore Version | Python 3.11 | Python 3.12 | Python 3.13 |
-|---------------|-------------|-------------|-------------|
-| v2.0.x | ✅ | ✅ | ✅ |
-| v1.2.x | ✅ | ✅ | ⚠️ |
-| v1.1.x | ✅ | ⚠️ | ❌ |
-| v1.0.x | ✅ | ❌ | ❌ |
-
-### Major Dependencies
-
-| XCore | FastAPI | SQLAlchemy | Pydantic |
-|-------|---------|------------|----------|
-| v2.0.x | 0.118+ | 2.0+ | 2.11+ |
-| v1.2.x | 0.100+ | 1.4+ | 1.10+ |
-| v1.1.x | 0.95+ | 1.4+ | 1.10+ |
-| v1.0.x | 0.90+ | 1.3+ | 1.10+ |
-
----
-
-## Contributing
-
-To contribute to XCore development:
-
-1. Fork the repository.
-2. Create a feature branch (`git checkout -b feature/amazing`).
-3. Commit your changes (`git commit -m 'Add amazing feature'`).
-4. Push to the branch (`git push origin feature/amazing`).
-5. Open a Pull Request.
-
-See the [contribution guide](development/contributing.md) for more details.
-
----
-
-*Last updated: March 21, 2025*
diff --git a/mkdocs.yml b/mkdocs.yml
index b49360f6..3fa0c9de 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,8 +1,5 @@
-# mkdocs.yml
-# Configuration for MkDocs documentation
-
site_name: XCore Framework
-site_description: Production-grade plugin-first Python framework
+site_description: Plugin-first orchestration framework built on FastAPI
site_author: XCore Team
site_url: https://xcore.readthedocs.io
@@ -12,7 +9,6 @@ site_dir: docs
theme:
name: material
palette:
- # Light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: indigo
@@ -20,7 +16,6 @@ theme:
toggle:
icon: material/brightness-7
name: Switch to dark mode
- # Dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: indigo
@@ -60,7 +55,11 @@ plugins:
markdown_extensions:
- admonition
- pymdownx.details
- - pymdownx.superfences
+ - pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format
- pymdownx.highlight:
anchor_linenums: true
- pymdownx.inlinehilite
@@ -76,36 +75,37 @@ markdown_extensions:
permalink: true
nav:
- - Home: index.md
+ - Accueil: index.md
- Getting Started:
- - getting-started/installation.md
- - getting-started/quickstart.md
+ - Installation: getting-started/installation.md
+ - Quick Start: getting-started/quickstart.md
- Guides:
- - guides/creating-plugins.md
- - guides/creating-services.md
- - guides/services.md
- - guides/events.md
- - guides/security.md
- - guides/monitoring.md
- - guides/scaling.md
- - guides/troubleshooting.md
+ - Créer un Plugin: guides/creating-plugins.md
+ - Services (DB, Cache, Scheduler): guides/services.md
+ - Événements & Hooks: guides/events.md
+ - Sécurité: guides/security.md
+ - Monitoring: guides/monitoring.md
+ - Scalabilité: guides/scaling.md
+ - Troubleshooting: guides/troubleshooting.md
- Reference:
- - reference/sdk.md
- - reference/configuration.md
- - reference/api.md
+ - SDK: reference/sdk.md
+ - Configuration: reference/configuration.md
+ - CLI: reference/cli.md
+ - API: reference/api.md
+ - Benchmarks: reference/benchmarks.md
- Architecture:
- - architecture/overview.md
+ - Vue d'ensemble: architecture/overview.md
+ - Décisions: architecture/decisions.md
- Deployment:
- - deployment/guide.md
+ - Guide: deployment/guide.md
- Development:
- - development/testing.md
- - development/contributing.md
- - Examples:
- - examples/basic-plugin.md
- - examples/complete-plugin.md
- - examples/trusted-plugin.md
- - examples/sandboxed-plugin.md
- - About:
- - versions.md
+ - Tests: development/testing.md
+ - Contribuer: development/contributing.md
+ - Exemples:
+ - Plugin basique: examples/basic-plugin.md
+ - Plugin complet: examples/complete-plugin.md
+ - Plugin Trusted: examples/trusted-plugin.md
+ - Plugin Sandboxed: examples/sandboxed-plugin.md
+ - Changelog: versions.md
-copyright: Copyright © 2023 XCore Team
+copyright: Copyright © 2026 XCore Team
diff --git a/poetry.lock b/poetry.lock
index f0d20760..c5943697 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 2.3.4 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand.
[[package]]
name = "aiocache"
@@ -18,17 +18,175 @@ msgpack = ["msgpack (>=0.5.5)"]
redis = ["redis (>=4.2.0)"]
[[package]]
-name = "aiofiles"
-version = "25.1.0"
-description = "File support for asyncio."
+name = "aiohappyeyeballs"
+version = "2.6.1"
+description = "Happy Eyeballs for asyncio"
optional = false
python-versions = ">=3.9"
groups = ["dev"]
files = [
- {file = "aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695"},
- {file = "aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2"},
+ {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"},
+ {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"},
]
+[[package]]
+name = "aiohttp"
+version = "3.13.5"
+description = "Async http client/server framework (asyncio)"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "aiohttp-3.13.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:02222e7e233295f40e011c1b00e3b0bd451f22cf853a0304c3595633ee47da4b"},
+ {file = "aiohttp-3.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bace460460ed20614fa6bc8cb09966c0b8517b8c58ad8046828c6078d25333b5"},
+ {file = "aiohttp-3.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f546a4dc1e6a5edbb9fd1fd6ad18134550e096a5a43f4ad74acfbd834fc6670"},
+ {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c86969d012e51b8e415a8c6ce96f7857d6a87d6207303ab02d5d11ef0cad2274"},
+ {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b6f6cd1560c5fa427e3b6074bb24d2c64e225afbb7165008903bd42e4e33e28a"},
+ {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:636bc362f0c5bbc7372bc3ae49737f9e3030dbce469f0f422c8f38079780363d"},
+ {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6a7cbeb06d1070f1d14895eeeed4dac5913b22d7b456f2eb969f11f4b3993796"},
+ {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca9ef7517fd7874a1a08970ae88f497bf5c984610caa0bf40bd7e8450852b95"},
+ {file = "aiohttp-3.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:019a67772e034a0e6b9b17c13d0a8fe56ad9fb150fc724b7f3ffd3724288d9e5"},
+ {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f34ecee82858e41dd217734f0c41a532bd066bcaab636ad830f03a30b2a96f2a"},
+ {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4eac02d9af4813ee289cd63a361576da36dba57f5a1ab36377bc2600db0cbb73"},
+ {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4beac52e9fe46d6abf98b0176a88154b742e878fdf209d2248e99fcdf73cd297"},
+ {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c180f480207a9b2475f2b8d8bd7204e47aec952d084b2a2be58a782ffcf96074"},
+ {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2837fb92951564d6339cedae4a7231692aa9f73cbc4fb2e04263b96844e03b4e"},
+ {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9010032a0b9710f58012a1e9c222528763d860ba2ee1422c03473eab47703e7"},
+ {file = "aiohttp-3.13.5-cp310-cp310-win32.whl", hash = "sha256:7c4b6668b2b2b9027f209ddf647f2a4407784b5d88b8be4efcc72036f365baf9"},
+ {file = "aiohttp-3.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:cd3db5927bf9167d5a6157ddb2f036f6b6b0ad001ac82355d43e97a4bde76d76"},
+ {file = "aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6"},
+ {file = "aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d"},
+ {file = "aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c"},
+ {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb"},
+ {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6"},
+ {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13"},
+ {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174"},
+ {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc"},
+ {file = "aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6"},
+ {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49"},
+ {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8"},
+ {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d"},
+ {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c"},
+ {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac"},
+ {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3"},
+ {file = "aiohttp-3.13.5-cp311-cp311-win32.whl", hash = "sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06"},
+ {file = "aiohttp-3.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8"},
+ {file = "aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9"},
+ {file = "aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416"},
+ {file = "aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2"},
+ {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60eaa2d440cd4707696b52e40ed3e2b0f73f65be07fd0ef23b6b539c9c0b0b4"},
+ {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:55b3bdd3292283295774ab585160c4004f4f2f203946997f49aac032c84649e9"},
+ {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2b2355dc094e5f7d45a7bb262fe7207aa0460b37a0d87027dcf21b5d890e7d5"},
+ {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b38765950832f7d728297689ad78f5f2cf79ff82487131c4d26fe6ceecdc5f8e"},
+ {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b18f31b80d5a33661e08c89e202edabf1986e9b49c42b4504371daeaa11b47c1"},
+ {file = "aiohttp-3.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:33add2463dde55c4f2d9635c6ab33ce154e5ecf322bd26d09af95c5f81cfa286"},
+ {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:327cc432fdf1356fb4fbc6fe833ad4e9f6aacb71a8acaa5f1855e4b25910e4a9"},
+ {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7c35b0bf0b48a70b4cb4fc5d7bed9b932532728e124874355de1a0af8ec4bc88"},
+ {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:df23d57718f24badef8656c49743e11a89fd6f5358fa8a7b96e728fda2abf7d3"},
+ {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:02e048037a6501a5ec1f6fc9736135aec6eb8a004ce48838cb951c515f32c80b"},
+ {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31cebae8b26f8a615d2b546fee45d5ffb76852ae6450e2a03f42c9102260d6fe"},
+ {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:888e78eb5ca55a615d285c3c09a7a91b42e9dd6fc699b166ebd5dee87c9ccf14"},
+ {file = "aiohttp-3.13.5-cp312-cp312-win32.whl", hash = "sha256:8bd3ec6376e68a41f9f95f5ed170e2fcf22d4eb27a1f8cb361d0508f6e0557f3"},
+ {file = "aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1"},
+ {file = "aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61"},
+ {file = "aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832"},
+ {file = "aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9"},
+ {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090"},
+ {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b"},
+ {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a"},
+ {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8"},
+ {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665"},
+ {file = "aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540"},
+ {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb"},
+ {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46"},
+ {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8"},
+ {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d"},
+ {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6"},
+ {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c"},
+ {file = "aiohttp-3.13.5-cp313-cp313-win32.whl", hash = "sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc"},
+ {file = "aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83"},
+ {file = "aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c"},
+ {file = "aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be"},
+ {file = "aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25"},
+ {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56"},
+ {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2"},
+ {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a"},
+ {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be"},
+ {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b"},
+ {file = "aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94"},
+ {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d"},
+ {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7"},
+ {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772"},
+ {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5"},
+ {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1"},
+ {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b"},
+ {file = "aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3"},
+ {file = "aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8"},
+ {file = "aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9"},
+ {file = "aiohttp-3.13.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:347542f0ea3f95b2a955ee6656461fa1c776e401ac50ebce055a6c38454a0adf"},
+ {file = "aiohttp-3.13.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:178c7b5e62b454c2bc790786e6058c3cc968613b4419251b478c153a4aec32b1"},
+ {file = "aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af545c2cffdb0967a96b6249e6f5f7b0d92cdfd267f9d5238d5b9ca63e8edb10"},
+ {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:206b7b3ef96e4ce211754f0cd003feb28b7d81f0ad26b8d077a5d5161436067f"},
+ {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ee5e86776273de1795947d17bddd6bb19e0365fd2af4289c0d2c5454b6b1d36b"},
+ {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:95d14ca7abefde230f7639ec136ade282655431fd5db03c343b19dda72dd1643"},
+ {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:912d4b6af530ddb1338a66229dac3a25ff11d4448be3ec3d6340583995f56031"},
+ {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e999f0c88a458c836d5fb521814e92ed2172c649200336a6df514987c1488258"},
+ {file = "aiohttp-3.13.5-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39380e12bd1f2fdab4285b6e055ad48efbaed5c836433b142ed4f5b9be71036a"},
+ {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9efcc0f11d850cefcafdd9275b9576ad3bfb539bed96807663b32ad99c4d4b88"},
+ {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:147b4f501d0292077f29d5268c16bb7c864a1f054d7001c4c1812c0421ea1ed0"},
+ {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d147004fede1b12f6013a6dbb2a26a986a671a03c6ea740ddc76500e5f1c399f"},
+ {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:9277145d36a01653863899c665243871434694bcc3431922c3b35c978061bdb8"},
+ {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4e704c52438f66fdd89588346183d898bb42167cf88f8b7ff1c0f9fc957c348f"},
+ {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8a4d3427e8de1312ddf309cc482186466c79895b3a139fed3259fc01dfa9a5b"},
+ {file = "aiohttp-3.13.5-cp39-cp39-win32.whl", hash = "sha256:6f497a6876aa4b1a102b04996ce4c1170c7040d83faa9387dd921c16e30d5c83"},
+ {file = "aiohttp-3.13.5-cp39-cp39-win_amd64.whl", hash = "sha256:cb979826071c0986a5f08333a36104153478ce6018c58cba7f9caddaf63d5d67"},
+ {file = "aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1"},
+]
+
+[package.dependencies]
+aiohappyeyeballs = ">=2.5.0"
+aiosignal = ">=1.4.0"
+attrs = ">=17.3.0"
+frozenlist = ">=1.1.1"
+multidict = ">=4.5,<7.0"
+propcache = ">=0.2.0"
+yarl = ">=1.17.0,<2.0"
+
+[package.extras]
+speedups = ["Brotli (>=1.2) ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "backports.zstd ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "brotlicffi (>=1.2) ; platform_python_implementation != \"CPython\""]
+
+[[package]]
+name = "aiosignal"
+version = "1.4.0"
+description = "aiosignal: a list of registered asynchronous callbacks"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"},
+ {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"},
+]
+
+[package.dependencies]
+frozenlist = ">=1.1.0"
+typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""}
+
[[package]]
name = "aiosqlite"
version = "0.22.1"
@@ -83,7 +241,7 @@ version = "0.7.0"
description = "Reusable constraint types to use with typing.Annotated"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
+groups = ["main"]
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
@@ -149,6 +307,33 @@ files = [
{file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"},
]
+[[package]]
+name = "attrs"
+version = "26.1.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309"},
+ {file = "attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32"},
+]
+
+[[package]]
+name = "autoflake"
+version = "2.3.3"
+description = "Removes unused imports and unused variables"
+optional = false
+python-versions = ">=3.10"
+groups = ["dev"]
+files = [
+ {file = "autoflake-2.3.3-py3-none-any.whl", hash = "sha256:a51a3412aff16135ee5b3ec25922459fef10c1f23ce6d6c4977188df859e8b53"},
+ {file = "autoflake-2.3.3.tar.gz", hash = "sha256:c24809541e23999f7a7b0d2faadf15deb0bc04cdde49728a2fd943a0c8055504"},
+]
+
+[package.dependencies]
+pyflakes = ">=3.0.0"
+
[[package]]
name = "autopep8"
version = "2.3.2"
@@ -199,6 +384,31 @@ files = [
[package.extras]
extras = ["regex"]
+[[package]]
+name = "bandit"
+version = "1.9.4"
+description = "Security oriented static analyser for python code."
+optional = false
+python-versions = ">=3.10"
+groups = ["dev"]
+files = [
+ {file = "bandit-1.9.4-py3-none-any.whl", hash = "sha256:f89ffa663767f5a0585ea075f01020207e966a9c0f2b9ef56a57c7963a3f6f8e"},
+ {file = "bandit-1.9.4.tar.gz", hash = "sha256:b589e5de2afe70bd4d53fa0c1da6199f4085af666fde00e8a034f152a52cd628"},
+]
+
+[package.dependencies]
+colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""}
+PyYAML = ">=5.3.1"
+rich = "*"
+stevedore = ">=1.20.0"
+
+[package.extras]
+baseline = ["GitPython (>=3.1.30)"]
+sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"]
+test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"]
+toml = ["tomli (>=1.1.0) ; python_version < \"3.11\""]
+yaml = ["PyYAML"]
+
[[package]]
name = "black"
version = "26.3.1"
@@ -263,103 +473,17 @@ files = [
]
[[package]]
-name = "cffi"
-version = "2.0.0"
-description = "Foreign Function Interface for Python calling C code."
+name = "cfgv"
+version = "3.5.0"
+description = "Validate configuration and produce human readable error messages."
optional = false
-python-versions = ">=3.9"
+python-versions = ">=3.10"
groups = ["dev"]
-markers = "platform_python_implementation != \"PyPy\""
-files = [
- {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"},
- {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"},
- {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"},
- {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"},
- {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"},
- {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"},
- {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"},
- {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"},
- {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"},
- {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"},
- {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"},
- {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"},
- {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"},
- {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"},
- {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"},
- {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"},
- {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"},
- {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"},
- {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"},
- {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"},
- {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"},
- {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"},
- {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"},
- {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"},
- {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"},
- {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"},
- {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"},
- {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"},
- {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"},
- {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"},
- {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"},
- {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"},
- {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"},
- {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"},
- {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"},
- {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"},
- {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"},
- {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"},
- {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"},
- {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"},
- {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"},
- {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"},
- {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"},
- {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"},
- {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"},
- {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"},
- {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"},
- {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"},
- {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"},
- {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"},
- {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"},
- {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"},
- {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"},
- {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"},
- {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"},
- {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"},
- {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"},
- {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"},
- {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"},
- {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"},
- {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"},
- {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"},
- {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"},
- {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"},
- {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"},
- {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"},
- {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"},
- {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"},
- {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"},
- {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"},
- {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"},
- {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"},
- {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"},
- {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"},
- {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"},
- {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"},
- {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"},
- {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"},
- {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"},
- {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"},
- {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"},
- {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"},
- {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"},
- {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"},
+files = [
+ {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"},
+ {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"},
]
-[package.dependencies]
-pycparser = {version = "*", markers = "implementation_name != \"PyPy\""}
-
[[package]]
name = "charset-normalizer"
version = "3.4.7"
@@ -533,7 +657,7 @@ version = "7.13.5"
description = "Code coverage measurement for Python"
optional = false
python-versions = ">=3.10"
-groups = ["main"]
+groups = ["dev"]
files = [
{file = "coverage-7.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0723d2c96324561b9aa76fb982406e11d93cdb388a7a7da2b16e04719cf7ca5"},
{file = "coverage-7.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52f444e86475992506b32d4e5ca55c24fc88d73bcbda0e9745095b28ef4dc0cf"},
@@ -646,78 +770,6 @@ files = [
[package.extras]
toml = ["tomli ; python_full_version <= \"3.11.0a6\""]
-[[package]]
-name = "cryptography"
-version = "46.0.7"
-description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
-optional = false
-python-versions = "!=3.9.0,!=3.9.1,>=3.8"
-groups = ["dev"]
-files = [
- {file = "cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4"},
- {file = "cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325"},
- {file = "cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308"},
- {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77"},
- {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1"},
- {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef"},
- {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de"},
- {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83"},
- {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb"},
- {file = "cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b"},
- {file = "cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85"},
- {file = "cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e"},
- {file = "cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457"},
- {file = "cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b"},
- {file = "cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842"},
- {file = "cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c"},
- {file = "cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902"},
- {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d"},
- {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022"},
- {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce"},
- {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f"},
- {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99"},
- {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1"},
- {file = "cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2"},
- {file = "cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e"},
- {file = "cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee"},
- {file = "cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298"},
- {file = "cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb"},
- {file = "cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4"},
- {file = "cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7"},
- {file = "cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832"},
- {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163"},
- {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2"},
- {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067"},
- {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0"},
- {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba"},
- {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006"},
- {file = "cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0"},
- {file = "cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85"},
- {file = "cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e"},
- {file = "cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246"},
- {file = "cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3"},
- {file = "cryptography-46.0.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fc9ab8856ae6cf7c9358430e49b368f3108f050031442eaeb6b9d87e4dcf4e4f"},
- {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15"},
- {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455"},
- {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65"},
- {file = "cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968"},
- {file = "cryptography-46.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:258514877e15963bd43b558917bc9f54cf7cf866c38aa576ebf47a77ddbc43a4"},
- {file = "cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5"},
-]
-
-[package.dependencies]
-cffi = {version = ">=2.0.0", markers = "python_full_version >= \"3.9.0\" and platform_python_implementation != \"PyPy\""}
-
-[package.extras]
-docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"]
-docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"]
-nox = ["nox[uv] (>=2024.4.15)"]
-pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"]
-sdist = ["build (>=1.0.0)"]
-ssh = ["bcrypt (>=3.1.5)"]
-test = ["certifi (>=2024)", "cryptography-vectors (==46.0.7)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
-test-randomorder = ["pytest-randomly"]
-
[[package]]
name = "csscompressor"
version = "0.9.5"
@@ -729,6 +781,18 @@ files = [
{file = "csscompressor-0.9.5.tar.gz", hash = "sha256:afa22badbcf3120a4f392e4d22f9fff485c044a1feda4a950ecc5eba9dd31a05"},
]
+[[package]]
+name = "distlib"
+version = "0.4.0"
+description = "Distribution utilities"
+optional = false
+python-versions = "*"
+groups = ["dev"]
+files = [
+ {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"},
+ {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"},
+]
+
[[package]]
name = "dnspython"
version = "2.8.0"
@@ -756,7 +820,7 @@ version = "0.19.2"
description = "ECDSA cryptographic signature library (pure python)"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.6"
-groups = ["main", "dev"]
+groups = ["main"]
files = [
{file = "ecdsa-0.19.2-py2.py3-none-any.whl", hash = "sha256:840f5dc5e375c68f36c1a7a5b9caad28f95daa65185c9253c0c08dd952bb7399"},
{file = "ecdsa-0.19.2.tar.gz", hash = "sha256:62635b0ac1ca2e027f82122b5b81cb706edc38cd91c63dda28e4f3455a2bf930"},
@@ -785,6 +849,21 @@ files = [
dnspython = ">=2.0.0"
idna = ">=2.0.0"
+[[package]]
+name = "faker"
+version = "37.12.0"
+description = "Faker is a Python package that generates fake data for you."
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "faker-37.12.0-py3-none-any.whl", hash = "sha256:afe7ccc038da92f2fbae30d8e16d19d91e92e242f8401ce9caf44de892bab4c4"},
+ {file = "faker-37.12.0.tar.gz", hash = "sha256:7505e59a7e02fa9010f06c3e1e92f8250d4cfbb30632296140c2d6dbef09b0fa"},
+]
+
+[package.dependencies]
+tzdata = "*"
+
[[package]]
name = "fastapi"
version = "0.135.4"
@@ -1018,6 +1097,18 @@ files = [
{file = "fastar-0.11.0.tar.gz", hash = "sha256:aa7f100f7313c03fdb20f1385927ba95671071ba308ad0c1763fef295e1895ce"},
]
+[[package]]
+name = "filelock"
+version = "3.29.0"
+description = "A platform independent file lock."
+optional = false
+python-versions = ">=3.10"
+groups = ["dev"]
+files = [
+ {file = "filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258"},
+ {file = "filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90"},
+]
+
[[package]]
name = "flake8"
version = "7.3.0"
@@ -1035,6 +1126,146 @@ mccabe = ">=0.7.0,<0.8.0"
pycodestyle = ">=2.14.0,<2.15.0"
pyflakes = ">=3.4.0,<3.5.0"
+[[package]]
+name = "frozenlist"
+version = "1.8.0"
+description = "A list-like structure which implements collections.abc.MutableSequence"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011"},
+ {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565"},
+ {file = "frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad"},
+ {file = "frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2"},
+ {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186"},
+ {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e"},
+ {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450"},
+ {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef"},
+ {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4"},
+ {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff"},
+ {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c"},
+ {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f"},
+ {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7"},
+ {file = "frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a"},
+ {file = "frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6"},
+ {file = "frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e"},
+ {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84"},
+ {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9"},
+ {file = "frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93"},
+ {file = "frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f"},
+ {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695"},
+ {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52"},
+ {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581"},
+ {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567"},
+ {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b"},
+ {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92"},
+ {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d"},
+ {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd"},
+ {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967"},
+ {file = "frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25"},
+ {file = "frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b"},
+ {file = "frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a"},
+ {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1"},
+ {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b"},
+ {file = "frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4"},
+ {file = "frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383"},
+ {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4"},
+ {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8"},
+ {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b"},
+ {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52"},
+ {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29"},
+ {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3"},
+ {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143"},
+ {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608"},
+ {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa"},
+ {file = "frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf"},
+ {file = "frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746"},
+ {file = "frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd"},
+ {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a"},
+ {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7"},
+ {file = "frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40"},
+ {file = "frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027"},
+ {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822"},
+ {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121"},
+ {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5"},
+ {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e"},
+ {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11"},
+ {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1"},
+ {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1"},
+ {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8"},
+ {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed"},
+ {file = "frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496"},
+ {file = "frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231"},
+ {file = "frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888"},
+ {file = "frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042"},
+ {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0"},
+ {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f"},
+ {file = "frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c"},
+ {file = "frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2"},
+ {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8"},
+ {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686"},
+ {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e"},
+ {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a"},
+ {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128"},
+ {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f"},
+ {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7"},
+ {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30"},
+ {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7"},
+ {file = "frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806"},
+ {file = "frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0"},
+ {file = "frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd"},
+ {file = "frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79"},
+ {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47"},
+ {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca"},
+ {file = "frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068"},
+ {file = "frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95"},
+ {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459"},
+ {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675"},
+ {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61"},
+ {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6"},
+ {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5"},
+ {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3"},
+ {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1"},
+ {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178"},
+ {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda"},
+ {file = "frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087"},
+ {file = "frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a"},
+ {file = "frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103"},
+ {file = "frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d"},
+ {file = "frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad"},
+]
+
[[package]]
name = "ghp-import"
version = "2.1.0"
@@ -1380,6 +1611,21 @@ http2 = ["h2 (>=3,<5)"]
socks = ["socksio (==1.*)"]
zstd = ["zstandard (>=0.18.0)"]
+[[package]]
+name = "identify"
+version = "2.6.19"
+description = "File identification library for Python"
+optional = false
+python-versions = ">=3.10"
+groups = ["dev"]
+files = [
+ {file = "identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a"},
+ {file = "identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842"},
+]
+
+[package.extras]
+license = ["ukkonen"]
+
[[package]]
name = "idna"
version = "3.11"
@@ -1401,7 +1647,7 @@ version = "2.3.0"
description = "brain-dead simple config-ini parsing"
optional = false
python-versions = ">=3.10"
-groups = ["main", "dev"]
+groups = ["dev"]
files = [
{file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"},
{file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"},
@@ -1813,6 +2059,162 @@ griffelib = ">=2.0"
mkdocs-autorefs = ">=1.4"
mkdocstrings = ">=0.30"
+[[package]]
+name = "multidict"
+version = "6.7.1"
+description = "multidict implementation"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5"},
+ {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8"},
+ {file = "multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872"},
+ {file = "multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991"},
+ {file = "multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03"},
+ {file = "multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981"},
+ {file = "multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6"},
+ {file = "multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190"},
+ {file = "multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92"},
+ {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee"},
+ {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2"},
+ {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568"},
+ {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40"},
+ {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962"},
+ {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505"},
+ {file = "multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122"},
+ {file = "multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df"},
+ {file = "multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db"},
+ {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d"},
+ {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e"},
+ {file = "multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855"},
+ {file = "multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3"},
+ {file = "multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e"},
+ {file = "multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a"},
+ {file = "multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8"},
+ {file = "multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0"},
+ {file = "multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144"},
+ {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49"},
+ {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71"},
+ {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3"},
+ {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c"},
+ {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0"},
+ {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa"},
+ {file = "multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a"},
+ {file = "multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b"},
+ {file = "multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6"},
+ {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172"},
+ {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd"},
+ {file = "multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7"},
+ {file = "multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53"},
+ {file = "multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75"},
+ {file = "multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b"},
+ {file = "multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733"},
+ {file = "multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a"},
+ {file = "multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961"},
+ {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582"},
+ {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e"},
+ {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3"},
+ {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6"},
+ {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a"},
+ {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba"},
+ {file = "multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511"},
+ {file = "multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19"},
+ {file = "multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf"},
+ {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23"},
+ {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2"},
+ {file = "multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445"},
+ {file = "multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177"},
+ {file = "multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23"},
+ {file = "multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060"},
+ {file = "multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d"},
+ {file = "multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed"},
+ {file = "multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429"},
+ {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6"},
+ {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9"},
+ {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c"},
+ {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84"},
+ {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d"},
+ {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33"},
+ {file = "multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3"},
+ {file = "multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5"},
+ {file = "multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df"},
+ {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1"},
+ {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963"},
+ {file = "multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34"},
+ {file = "multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65"},
+ {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292"},
+ {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43"},
+ {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca"},
+ {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd"},
+ {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7"},
+ {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3"},
+ {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4"},
+ {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8"},
+ {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c"},
+ {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52"},
+ {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108"},
+ {file = "multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32"},
+ {file = "multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8"},
+ {file = "multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118"},
+ {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee"},
+ {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2"},
+ {file = "multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1"},
+ {file = "multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d"},
+ {file = "multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31"},
+ {file = "multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048"},
+ {file = "multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362"},
+ {file = "multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37"},
+ {file = "multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709"},
+ {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0"},
+ {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb"},
+ {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd"},
+ {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601"},
+ {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1"},
+ {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b"},
+ {file = "multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d"},
+ {file = "multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f"},
+ {file = "multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5"},
+ {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581"},
+ {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a"},
+ {file = "multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c"},
+ {file = "multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262"},
+ {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59"},
+ {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889"},
+ {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4"},
+ {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d"},
+ {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609"},
+ {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489"},
+ {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c"},
+ {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e"},
+ {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c"},
+ {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9"},
+ {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2"},
+ {file = "multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7"},
+ {file = "multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5"},
+ {file = "multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2"},
+ {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f"},
+ {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358"},
+ {file = "multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5"},
+ {file = "multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0"},
+ {file = "multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8"},
+ {file = "multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0"},
+ {file = "multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f"},
+ {file = "multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f"},
+ {file = "multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e"},
+ {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2"},
+ {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8"},
+ {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941"},
+ {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a"},
+ {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de"},
+ {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5"},
+ {file = "multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0"},
+ {file = "multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4"},
+ {file = "multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9"},
+ {file = "multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56"},
+ {file = "multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d"},
+]
+
[[package]]
name = "mypy-extensions"
version = "1.1.0"
@@ -1869,38 +2271,24 @@ telemetry = ["opentelemetry-api (==1.33.1)", "opentelemetry-exporter-otlp-proto-
webauthn = ["fido2 (==1.1.2)"]
[[package]]
-name = "opshero"
-version = "0.1.6"
-description = "OpsHero CLI — Analyze CI/CD pipeline errors from your terminal"
+name = "nodeenv"
+version = "1.10.0"
+description = "Node.js virtual environment builder"
optional = false
-python-versions = ">=3.11"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
groups = ["dev"]
files = [
- {file = "opshero-0.1.6-py3-none-any.whl", hash = "sha256:af06323e77bfd423fd9245fa3f9b904153747bf2efd5bbf04de024f7a5bd2d96"},
- {file = "opshero-0.1.6.tar.gz", hash = "sha256:e0892e048acb9971620ca56bd8c94fb85ad6bccb036d979c8b46ba6a24fcdbd1"},
+ {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"},
+ {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"},
]
-[package.dependencies]
-aiofiles = ">=23.2.0"
-anyio = ">=4.4.0"
-click = ">=8.1.0"
-httpx = ">=0.27.0"
-platformdirs = ">=4.2.0"
-pydantic = ">=2.7.0"
-pydantic-settings = ">=2.3.0"
-python-jose = {version = ">=3.3.0", extras = ["cryptography"]}
-rich = ">=13.7.0"
-
-[package.extras]
-dev = ["pytest (>=8.0.0)", "pytest-asyncio (>=0.23.0)", "pytest-httpx (>=0.30.0)", "ruff (>=0.4.0)"]
-
[[package]]
name = "packaging"
version = "26.1"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev", "docs"]
+groups = ["dev", "docs"]
files = [
{file = "packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f"},
{file = "packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de"},
@@ -2049,18 +2437,6 @@ test-arrow = ["arro3-compute", "arro3-core", "nanoarrow", "pyarrow"]
tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma (>=5)", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"]
xmp = ["defusedxml"]
-[[package]]
-name = "pip"
-version = "26.0.1"
-description = "The PyPA recommended tool for installing Python packages."
-optional = false
-python-versions = ">=3.9"
-groups = ["main"]
-files = [
- {file = "pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b"},
- {file = "pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8"},
-]
-
[[package]]
name = "platformdirs"
version = "4.9.6"
@@ -2079,7 +2455,7 @@ version = "1.6.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.9"
-groups = ["main", "dev"]
+groups = ["dev"]
files = [
{file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"},
{file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"},
@@ -2089,6 +2465,157 @@ files = [
dev = ["pre-commit", "tox"]
testing = ["coverage", "pytest", "pytest-benchmark"]
+[[package]]
+name = "pre-commit"
+version = "4.6.0"
+description = "A framework for managing and maintaining multi-language pre-commit hooks."
+optional = false
+python-versions = ">=3.10"
+groups = ["dev"]
+files = [
+ {file = "pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b"},
+ {file = "pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9"},
+]
+
+[package.dependencies]
+cfgv = ">=2.0.0"
+identify = ">=1.0.0"
+nodeenv = ">=0.11.1"
+pyyaml = ">=5.1"
+virtualenv = ">=20.10.0"
+
+[[package]]
+name = "propcache"
+version = "0.4.1"
+description = "Accelerated property cache"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db"},
+ {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8"},
+ {file = "propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925"},
+ {file = "propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21"},
+ {file = "propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5"},
+ {file = "propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db"},
+ {file = "propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7"},
+ {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4"},
+ {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60"},
+ {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f"},
+ {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900"},
+ {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c"},
+ {file = "propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb"},
+ {file = "propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37"},
+ {file = "propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581"},
+ {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf"},
+ {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5"},
+ {file = "propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e"},
+ {file = "propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566"},
+ {file = "propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165"},
+ {file = "propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc"},
+ {file = "propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48"},
+ {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570"},
+ {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85"},
+ {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e"},
+ {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757"},
+ {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f"},
+ {file = "propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1"},
+ {file = "propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6"},
+ {file = "propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239"},
+ {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2"},
+ {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403"},
+ {file = "propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207"},
+ {file = "propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72"},
+ {file = "propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367"},
+ {file = "propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4"},
+ {file = "propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf"},
+ {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3"},
+ {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778"},
+ {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6"},
+ {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9"},
+ {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75"},
+ {file = "propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8"},
+ {file = "propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db"},
+ {file = "propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1"},
+ {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf"},
+ {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311"},
+ {file = "propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74"},
+ {file = "propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe"},
+ {file = "propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af"},
+ {file = "propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c"},
+ {file = "propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f"},
+ {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1"},
+ {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24"},
+ {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa"},
+ {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61"},
+ {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66"},
+ {file = "propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81"},
+ {file = "propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e"},
+ {file = "propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1"},
+ {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b"},
+ {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566"},
+ {file = "propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835"},
+ {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e"},
+ {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859"},
+ {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b"},
+ {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0"},
+ {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af"},
+ {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393"},
+ {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874"},
+ {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7"},
+ {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1"},
+ {file = "propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717"},
+ {file = "propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37"},
+ {file = "propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a"},
+ {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12"},
+ {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c"},
+ {file = "propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded"},
+ {file = "propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641"},
+ {file = "propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4"},
+ {file = "propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44"},
+ {file = "propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d"},
+ {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b"},
+ {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e"},
+ {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f"},
+ {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49"},
+ {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144"},
+ {file = "propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f"},
+ {file = "propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153"},
+ {file = "propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992"},
+ {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f"},
+ {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393"},
+ {file = "propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0"},
+ {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a"},
+ {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be"},
+ {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc"},
+ {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a"},
+ {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89"},
+ {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726"},
+ {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367"},
+ {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36"},
+ {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455"},
+ {file = "propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85"},
+ {file = "propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1"},
+ {file = "propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9"},
+ {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d233076ccf9e450c8b3bc6720af226b898ef5d051a2d145f7d765e6e9f9bcff"},
+ {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:357f5bb5c377a82e105e44bd3d52ba22b616f7b9773714bff93573988ef0a5fb"},
+ {file = "propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbc3b6dfc728105b2a57c06791eb07a94229202ea75c59db644d7d496b698cac"},
+ {file = "propcache-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:182b51b421f0501952d938dc0b0eb45246a5b5153c50d42b495ad5fb7517c888"},
+ {file = "propcache-0.4.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b536b39c5199b96fc6245eb5fb796c497381d3942f169e44e8e392b29c9ebcc"},
+ {file = "propcache-0.4.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db65d2af507bbfbdcedb254a11149f894169d90488dd3e7190f7cdcb2d6cd57a"},
+ {file = "propcache-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd2dbc472da1f772a4dae4fa24be938a6c544671a912e30529984dd80400cd88"},
+ {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:daede9cd44e0f8bdd9e6cc9a607fc81feb80fae7a5fc6cecaff0e0bb32e42d00"},
+ {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:71b749281b816793678ae7f3d0d84bd36e694953822eaad408d682efc5ca18e0"},
+ {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0002004213ee1f36cfb3f9a42b5066100c44276b9b72b4e1504cddd3d692e86e"},
+ {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fe49d0a85038f36ba9e3ffafa1103e61170b28e95b16622e11be0a0ea07c6781"},
+ {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99d43339c83aaf4d32bda60928231848eee470c6bda8d02599cc4cebe872d183"},
+ {file = "propcache-0.4.1-cp39-cp39-win32.whl", hash = "sha256:a129e76735bc792794d5177069691c3217898b9f5cee2b2661471e52ffe13f19"},
+ {file = "propcache-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:948dab269721ae9a87fd16c514a0a2c2a1bdb23a9a61b969b0f9d9ee2968546f"},
+ {file = "propcache-0.4.1-cp39-cp39-win_arm64.whl", hash = "sha256:5fd37c406dd6dc85aa743e214cef35dc54bbdd1419baac4f6ae5e5b1a2976938"},
+ {file = "propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237"},
+ {file = "propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d"},
+]
+
[[package]]
name = "psutil"
version = "7.2.2"
@@ -2159,27 +2686,12 @@ version = "0.6.3"
description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
optional = false
python-versions = ">=3.8"
-groups = ["main", "dev"]
+groups = ["main"]
files = [
{file = "pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde"},
{file = "pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf"},
]
-[[package]]
-name = "pybind11"
-version = "3.0.4"
-description = "Seamless operability between C++11 and Python"
-optional = false
-python-versions = ">=3.8"
-groups = ["main"]
-files = [
- {file = "pybind11-3.0.4-py3-none-any.whl", hash = "sha256:961720ee652da51d531b7b2451a6bd2bc042b0106e6d9baa48ecb7d58034ce63"},
- {file = "pybind11-3.0.4.tar.gz", hash = "sha256:3286b59c8a774b9ee650169302dd5a4eedc30a8617905a0560dd8ee44775130c"},
-]
-
-[package.extras]
-global = ["pybind11-global (==3.0.4)"]
-
[[package]]
name = "pycodestyle"
version = "2.14.0"
@@ -2192,26 +2704,13 @@ files = [
{file = "pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783"},
]
-[[package]]
-name = "pycparser"
-version = "3.0"
-description = "C parser in Python"
-optional = false
-python-versions = ">=3.10"
-groups = ["dev"]
-markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""
-files = [
- {file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"},
- {file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"},
-]
-
[[package]]
name = "pydantic"
version = "2.13.3"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.9"
-groups = ["main", "dev"]
+groups = ["main"]
files = [
{file = "pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927"},
{file = "pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d"},
@@ -2234,7 +2733,7 @@ version = "2.46.3"
description = "Core functionality for Pydantic validation and serialization"
optional = false
python-versions = ">=3.9"
-groups = ["main", "dev"]
+groups = ["main"]
files = [
{file = "pydantic_core-2.46.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:1da3786b8018e60349680720158cc19161cc3b4bdd815beb0a321cd5ce1ad5b1"},
{file = "pydantic_core-2.46.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc0988cb29d21bf4a9d5cf2ef970b5c0e38d8d8e107a493278c05dc6c1dda69f"},
@@ -2393,7 +2892,7 @@ version = "2.14.0"
description = "Settings management using Pydantic"
optional = false
python-versions = ">=3.10"
-groups = ["main", "dev"]
+groups = ["main"]
files = [
{file = "pydantic_settings-2.14.0-py3-none-any.whl", hash = "sha256:fc8d5d692eb7092e43c8647c1c35a3ecd00e040fcf02ed86f4cb5458ca62182e"},
{file = "pydantic_settings-2.14.0.tar.gz", hash = "sha256:24285fd4b0e0c06507dd9fdfd331ee23794305352aaec8fc4eb92d4047aeb67d"},
@@ -2459,26 +2958,46 @@ extra = ["pygments (>=2.19.1)"]
[[package]]
name = "pytest"
-version = "9.0.3"
+version = "8.4.2"
description = "pytest: simple powerful testing with Python"
optional = false
-python-versions = ">=3.10"
-groups = ["main", "dev"]
+python-versions = ">=3.9"
+groups = ["dev"]
files = [
- {file = "pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9"},
- {file = "pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c"},
+ {file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"},
+ {file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"},
]
[package.dependencies]
colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""}
-iniconfig = ">=1.0.1"
-packaging = ">=22"
+iniconfig = ">=1"
+packaging = ">=20"
pluggy = ">=1.5,<2"
pygments = ">=2.7.2"
[package.extras]
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"]
+[[package]]
+name = "pytest-asyncio"
+version = "1.3.0"
+description = "Pytest support for asyncio"
+optional = false
+python-versions = ">=3.10"
+groups = ["dev"]
+files = [
+ {file = "pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5"},
+ {file = "pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5"},
+]
+
+[package.dependencies]
+pytest = ">=8.2,<10"
+typing-extensions = {version = ">=4.12", markers = "python_version < \"3.13\""}
+
+[package.extras]
+docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"]
+testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"]
+
[[package]]
name = "pytest-benchmark"
version = "5.2.3"
@@ -2506,7 +3025,7 @@ version = "7.1.0"
description = "Pytest plugin for measuring coverage."
optional = false
python-versions = ">=3.9"
-groups = ["main"]
+groups = ["dev"]
files = [
{file = "pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678"},
{file = "pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2"},
@@ -2535,13 +3054,33 @@ files = [
[package.dependencies]
six = ">=1.5"
+[[package]]
+name = "python-discovery"
+version = "1.2.2"
+description = "Python interpreter discovery"
+optional = false
+python-versions = ">=3.8"
+groups = ["dev"]
+files = [
+ {file = "python_discovery-1.2.2-py3-none-any.whl", hash = "sha256:e1ae95d9af875e78f15e19aed0c6137ab1bb49c200f21f5061786490c9585c7a"},
+ {file = "python_discovery-1.2.2.tar.gz", hash = "sha256:876e9c57139eb757cb5878cbdd9ae5379e5d96266c99ef731119e04fffe533bb"},
+]
+
+[package.dependencies]
+filelock = ">=3.15.4"
+platformdirs = ">=4.3.6,<5"
+
+[package.extras]
+docs = ["furo (>=2025.12.19)", "sphinx (>=9.1)", "sphinx-autodoc-typehints (>=3.6.3)", "sphinxcontrib-mermaid (>=2)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.5.4)", "pytest (>=8.3.5)", "pytest-mock (>=3.14)", "setuptools (>=75.1)"]
+
[[package]]
name = "python-dotenv"
version = "1.2.2"
description = "Read key-value pairs from a .env file and set them as environment variables"
optional = false
python-versions = ">=3.10"
-groups = ["main", "dev"]
+groups = ["main"]
files = [
{file = "python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a"},
{file = "python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"},
@@ -2556,14 +3095,13 @@ version = "3.5.0"
description = "JOSE implementation in Python"
optional = false
python-versions = ">=3.9"
-groups = ["main", "dev"]
+groups = ["main"]
files = [
{file = "python_jose-3.5.0-py2.py3-none-any.whl", hash = "sha256:abd1202f23d34dfad2c3d28cb8617b90acf34132c7afd60abd0b0b7d3cb55771"},
{file = "python_jose-3.5.0.tar.gz", hash = "sha256:fb4eaa44dbeb1c26dcc69e4bd7ec54a1cb8dd64d3b4d81ef08d90ff453f2b01b"},
]
[package.dependencies]
-cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"cryptography\""}
ecdsa = "!=0.15"
pyasn1 = ">=0.5.0"
rsa = ">=4.0,<4.1.1 || >4.1.1,<4.4 || >4.4,<5.0"
@@ -2647,7 +3185,7 @@ version = "6.0.3"
description = "YAML parser and emitter for Python"
optional = false
python-versions = ">=3.8"
-groups = ["main", "docs"]
+groups = ["main", "dev", "docs"]
files = [
{file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"},
{file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"},
@@ -2991,7 +3529,7 @@ version = "4.9.1"
description = "Pure-Python RSA implementation"
optional = false
python-versions = "<4,>=3.6"
-groups = ["main", "dev"]
+groups = ["main"]
files = [
{file = "rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762"},
{file = "rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75"},
@@ -3064,27 +3602,6 @@ statsig = ["statsig (>=0.55.3)"]
tornado = ["tornado (>=6)"]
unleash = ["UnleashClient (>=6.0.1)"]
-[[package]]
-name = "setuptools"
-version = "82.0.1"
-description = "Most extensible Python build backend with support for C/C++ extension modules"
-optional = false
-python-versions = ">=3.9"
-groups = ["main"]
-files = [
- {file = "setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb"},
- {file = "setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9"},
-]
-
-[package.extras]
-check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.13.0) ; sys_platform != \"cygwin\""]
-core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"]
-cover = ["pytest-cov"]
-doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
-enabler = ["pytest-enabler (>=2.2)"]
-test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"]
-type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.18.*)", "pytest-mypy"]
-
[[package]]
name = "shellingham"
version = "1.5.4"
@@ -3103,7 +3620,7 @@ version = "1.17.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
-groups = ["main", "dev", "docs"]
+groups = ["main", "docs"]
files = [
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
@@ -3231,20 +3748,17 @@ typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""
full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"]
[[package]]
-name = "tabulate"
-version = "0.10.0"
-description = "Pretty-print tabular data"
+name = "stevedore"
+version = "5.7.0"
+description = "Manage dynamic plugins for Python applications"
optional = false
python-versions = ">=3.10"
groups = ["dev"]
files = [
- {file = "tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3"},
- {file = "tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d"},
+ {file = "stevedore-5.7.0-py3-none-any.whl", hash = "sha256:fd25efbb32f1abb4c9e502f385f0018632baac11f9ee5d1b70f88cc5e22ad4ed"},
+ {file = "stevedore-5.7.0.tar.gz", hash = "sha256:31dd6fe6b3cbe921e21dcefabc9a5f1cf848cf538a1f27543721b8ca09948aa3"},
]
-[package.extras]
-widechars = ["wcwidth"]
-
[[package]]
name = "toml"
version = "0.10.2"
@@ -3286,6 +3800,7 @@ files = [
{file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"},
{file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"},
]
+markers = {dev = "python_version < \"3.13\""}
[[package]]
name = "typing-inspection"
@@ -3293,7 +3808,7 @@ version = "0.4.2"
description = "Runtime typing introspection tools"
optional = false
python-versions = ">=3.9"
-groups = ["main", "dev"]
+groups = ["main"]
files = [
{file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"},
{file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"},
@@ -3308,12 +3823,12 @@ version = "2026.1"
description = "Provider of IANA time zone data"
optional = false
python-versions = ">=2"
-groups = ["main"]
-markers = "platform_system == \"Windows\""
+groups = ["main", "dev"]
files = [
{file = "tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9"},
{file = "tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98"},
]
+markers = {main = "platform_system == \"Windows\""}
[[package]]
name = "tzlocal"
@@ -3488,6 +4003,24 @@ dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"]
docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx_rtd_theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"]
test = ["aiohttp (>=3.10.5)", "flake8 (>=6.1,<7.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=25.3.0,<25.4.0)", "pycodestyle (>=2.11.0,<2.12.0)"]
+[[package]]
+name = "virtualenv"
+version = "21.3.0"
+description = "Virtual Python Environment builder"
+optional = false
+python-versions = ">=3.8"
+groups = ["dev"]
+files = [
+ {file = "virtualenv-21.3.0-py3-none-any.whl", hash = "sha256:4d28ee41f6d9ec8f1f00cd472b9ffbcedda1b3d3b9a575b5c94a2d004fd51bd7"},
+ {file = "virtualenv-21.3.0.tar.gz", hash = "sha256:733750db978ec95c2d8eb4feadaa57091002bce404cb39ba69899cf7bd28944e"},
+]
+
+[package.dependencies]
+distlib = ">=0.3.7,<1"
+filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""}
+platformdirs = ">=3.9.1,<5"
+python-discovery = ">=1.2.2"
+
[[package]]
name = "watchdog"
version = "6.0.0"
@@ -3724,7 +4257,150 @@ files = [
{file = "websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5"},
]
+[[package]]
+name = "yarl"
+version = "1.23.0"
+description = "Yet another URL library"
+optional = false
+python-versions = ">=3.10"
+groups = ["dev"]
+files = [
+ {file = "yarl-1.23.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cff6d44cb13d39db2663a22b22305d10855efa0fa8015ddeacc40bc59b9d8107"},
+ {file = "yarl-1.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c53f8347cd4200f0d70a48ad059cabaf24f5adc6ba08622a23423bc7efa10d"},
+ {file = "yarl-1.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a6940a074fb3c48356ed0158a3ca5699c955ee4185b4d7d619be3c327143e05"},
+ {file = "yarl-1.23.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ed5f69ce7be7902e5c70ea19eb72d20abf7d725ab5d49777d696e32d4fc1811d"},
+ {file = "yarl-1.23.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:389871e65468400d6283c0308e791a640b5ab5c83bcee02a2f51295f95e09748"},
+ {file = "yarl-1.23.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dda608c88cf709b1d406bdfcd84d8d63cff7c9e577a403c6108ce8ce9dcc8764"},
+ {file = "yarl-1.23.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c4fe09e0780c6c3bf2b7d4af02ee2394439d11a523bbcf095cf4747c2932007"},
+ {file = "yarl-1.23.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c9921eb8bd12633b41ad27686bbb0b1a2a9b8452bfdf221e34f311e9942ed4"},
+ {file = "yarl-1.23.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5f10fd85e4b75967468af655228fbfd212bdf66db1c0d135065ce288982eda26"},
+ {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dbf507e9ef5688bada447a24d68b4b58dd389ba93b7afc065a2ba892bea54769"},
+ {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:85e9beda1f591bc73e77ea1c51965c68e98dafd0fec72cdd745f77d727466716"},
+ {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0e1fdaa14ef51366d7757b45bde294e95f6c8c049194e793eedb8387c86d5993"},
+ {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:75e3026ab649bf48f9a10c0134512638725b521340293f202a69b567518d94e0"},
+ {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:80e6d33a3d42a7549b409f199857b4fb54e2103fc44fb87605b6663b7a7ff750"},
+ {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5ec2f42d41ccbd5df0270d7df31618a8ee267bfa50997f5d720ddba86c4a83a6"},
+ {file = "yarl-1.23.0-cp310-cp310-win32.whl", hash = "sha256:debe9c4f41c32990771be5c22b56f810659f9ddf3d63f67abfdcaa2c6c9c5c1d"},
+ {file = "yarl-1.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f043cb8a2d71c981c09c510da013bc79fd661f5c60139f00dd3c3cc4f2ffb"},
+ {file = "yarl-1.23.0-cp310-cp310-win_arm64.whl", hash = "sha256:263cd4f47159c09b8b685890af949195b51d1aa82ba451c5847ca9bc6413c220"},
+ {file = "yarl-1.23.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99"},
+ {file = "yarl-1.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c"},
+ {file = "yarl-1.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432"},
+ {file = "yarl-1.23.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a"},
+ {file = "yarl-1.23.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05"},
+ {file = "yarl-1.23.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83"},
+ {file = "yarl-1.23.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c"},
+ {file = "yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598"},
+ {file = "yarl-1.23.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b"},
+ {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c"},
+ {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788"},
+ {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222"},
+ {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb"},
+ {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc"},
+ {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2"},
+ {file = "yarl-1.23.0-cp311-cp311-win32.whl", hash = "sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5"},
+ {file = "yarl-1.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46"},
+ {file = "yarl-1.23.0-cp311-cp311-win_arm64.whl", hash = "sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928"},
+ {file = "yarl-1.23.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860"},
+ {file = "yarl-1.23.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069"},
+ {file = "yarl-1.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25"},
+ {file = "yarl-1.23.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cbf44c5cb4a7633d078788e1b56387e3d3cf2b8139a3be38040b22d6c3221c8"},
+ {file = "yarl-1.23.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53ad387048f6f09a8969631e4de3f1bf70c50e93545d64af4f751b2498755072"},
+ {file = "yarl-1.23.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4a59ba56f340334766f3a4442e0efd0af895fae9e2b204741ef885c446b3a1a8"},
+ {file = "yarl-1.23.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:803a3c3ce4acc62eaf01eaca1208dcf0783025ef27572c3336502b9c232005e7"},
+ {file = "yarl-1.23.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3d2bff8f37f8d0f96c7ec554d16945050d54462d6e95414babaa18bfafc7f51"},
+ {file = "yarl-1.23.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c75eb09e8d55bceb4367e83496ff8ef2bc7ea6960efb38e978e8073ea59ecb67"},
+ {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877b0738624280e34c55680d6054a307aa94f7d52fa0e3034a9cc6e790871da7"},
+ {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b5405bb8f0e783a988172993cfc627e4d9d00432d6bbac65a923041edacf997d"},
+ {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c3a3598a832590c5a3ce56ab5576361b5688c12cb1d39429cf5dba30b510760"},
+ {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8419ebd326430d1cbb7efb5292330a2cf39114e82df5cc3d83c9a0d5ebeaf2f2"},
+ {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:be61f6fff406ca40e3b1d84716fde398fc08bc63dd96d15f3a14230a0973ed86"},
+ {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ceb13c5c858d01321b5d9bb65e4cf37a92169ea470b70fec6f236b2c9dd7e34"},
+ {file = "yarl-1.23.0-cp312-cp312-win32.whl", hash = "sha256:fffc45637bcd6538de8b85f51e3df3223e4ad89bccbfca0481c08c7fc8b7ed7d"},
+ {file = "yarl-1.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:f69f57305656a4852f2a7203efc661d8c042e6cc67f7acd97d8667fb448a426e"},
+ {file = "yarl-1.23.0-cp312-cp312-win_arm64.whl", hash = "sha256:6e87a6e8735b44816e7db0b2fbc9686932df473c826b0d9743148432e10bb9b9"},
+ {file = "yarl-1.23.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e"},
+ {file = "yarl-1.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5"},
+ {file = "yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b"},
+ {file = "yarl-1.23.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035"},
+ {file = "yarl-1.23.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5"},
+ {file = "yarl-1.23.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735"},
+ {file = "yarl-1.23.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401"},
+ {file = "yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4"},
+ {file = "yarl-1.23.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f"},
+ {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a"},
+ {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2"},
+ {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f"},
+ {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b"},
+ {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a"},
+ {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543"},
+ {file = "yarl-1.23.0-cp313-cp313-win32.whl", hash = "sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957"},
+ {file = "yarl-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3"},
+ {file = "yarl-1.23.0-cp313-cp313-win_arm64.whl", hash = "sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3"},
+ {file = "yarl-1.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa"},
+ {file = "yarl-1.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120"},
+ {file = "yarl-1.23.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59"},
+ {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512"},
+ {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4"},
+ {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1"},
+ {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea"},
+ {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9"},
+ {file = "yarl-1.23.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123"},
+ {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24"},
+ {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de"},
+ {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b"},
+ {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6"},
+ {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6"},
+ {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5"},
+ {file = "yarl-1.23.0-cp313-cp313t-win32.whl", hash = "sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595"},
+ {file = "yarl-1.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090"},
+ {file = "yarl-1.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144"},
+ {file = "yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912"},
+ {file = "yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474"},
+ {file = "yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719"},
+ {file = "yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319"},
+ {file = "yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434"},
+ {file = "yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723"},
+ {file = "yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039"},
+ {file = "yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52"},
+ {file = "yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c"},
+ {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae"},
+ {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e"},
+ {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85"},
+ {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd"},
+ {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6"},
+ {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe"},
+ {file = "yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169"},
+ {file = "yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70"},
+ {file = "yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e"},
+ {file = "yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679"},
+ {file = "yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412"},
+ {file = "yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4"},
+ {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c"},
+ {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4"},
+ {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94"},
+ {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28"},
+ {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6"},
+ {file = "yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277"},
+ {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4"},
+ {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a"},
+ {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb"},
+ {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41"},
+ {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2"},
+ {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4"},
+ {file = "yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4"},
+ {file = "yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2"},
+ {file = "yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25"},
+ {file = "yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f"},
+ {file = "yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5"},
+]
+
+[package.dependencies]
+idna = ">=2.0"
+multidict = ">=4.0"
+propcache = ">=0.2.1"
+
[metadata]
lock-version = "2.1"
python-versions = ">=3.11,<4.0"
-content-hash = "3fc39d181a1260ea8c089aa5795d75d637eabf367df2e52ed3d0c31d9abb48ee"
+content-hash = "23a4d623eba940f87e97f0c92080279edb8a46ec2d9979d2dbc7e0e6e2279946"
diff --git a/pyproject.toml b/pyproject.toml
index 10b5a842..df80c6d2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,111 +1,106 @@
-[tool.poetry]
+[project]
name = "xcore"
version = "2.1.2"
-description = "for base html core app"
-authors = ["Eliezer Traore <68350805+traoreera@users.noreply.github.com>"]
+description = "Plugin-first orchestration framework built on FastAPI"
+authors = [
+ { name = "Eliezer Traore", email = "68350805+traoreera@users.noreply.github.com" },
+]
license = "MIT"
readme = "README.md"
+requires-python = ">=3.11,<4.0"
+
+dependencies = [
+ # Web
+ "fastapi[standard]>=0.135.1,<1.0.0",
+ "uvicorn>=0.38.0,<1.0.0",
+ "user-agents>=2.2.0,<3.0.0",
+
+ # Data validation
+ "pydantic[email]>=2.11.7,<3.0.0",
+ "pydantic-settings>=2.12.0,<3.0.0",
+
+ # Database & ORM
+ "sqlalchemy>=2.0.41,<3.0.0",
+ "alembic>=1.16.1,<2.0.0",
+ "psycopg2>=2.9.11,<3.0.0",
+ "aiosqlite>=0.22.1,<1.0.0",
+ "mysql-connector-python>=9.4.0,<10.0.0",
+
+ # Cache
+ "redis[hiredis]>=7.0.0,<8.0.0",
+ "aiocache>=0.12.3,<1.0.0",
+
+ # Scheduling
+ "apscheduler>=3.11.0,<4.0.0",
+
+ # Security
+ "python-jose>=3.4.0,<4.0.0",
+
+ # Configuration & environment
+ "python-dotenv>=1.1.0,<2.0.0",
+ "pyyaml>=6.0.3,<7.0.0",
+ "toml>=0.10.2,<1.0.0",
+
+ # Observability & utilities
+ "rich>=14.0.0,<15.0.0",
+ "psutil>=7.0.0,<8.0.0",
+ "watchdog>=6.0.0,<7.0.0",
+ "markdown>=3.8.2,<4.0.0",
+ "pillow>=11.2.1,<13.0.0",
+]
-[tool.poetry.dependencies]
-
-# environment
-python-dotenv = ">=1.1.0,<2.0.0"
-
-# database migration
-alembic = ">=1.16.1,<2.0.0"
-
-# tools
-apscheduler = ">=3.11.0,<4.0.0"
-rich = ">=14.0.0,<15.0.0"
-watchdog = ">=6.0.0,<7.0.0"
-markdown = ">=3.8.2,<4.0.0"
-pillow = ">=11.2.1,<13.0.0"
-psutil = ">=7.0.0,<8.0.0"
-toml = "^0.10.2"
-uvicorn = "^0.38.0"
-
-# security
-python-jose = ">=3.4.0,<4.0.0"
-
-
-# python
-pip = "==26.0.1"
-python = ">=3.11,<4.0"
+[project.scripts]
+xcore = "xcore.cli.main:main"
-# http
-user-agents = "^2.2.0"
+# ── Build system ──────────────────────────────────────────────────────────────
+[build-system]
+requires = ["poetry-core>=2.0.0,<3.0.0"]
+build-backend = "poetry.core.masonry.api"
-# data validation
-pydantic = { extras = ["email"], version = ">=2.11.7,<3.0.0" }
-pydantic-settings = "^2.12.0"
+# ── Development dependencies ──────────────────────────────────────────────────
-# database
-psycopg2 = "^2.9.11"
-aiosqlite = "^0.22.1"
-mysql-connector-python = "^9.4.0"
-sqlalchemy = ">=2.0.41,<3.0.0"
-fastapi = {extras = ["standard"], version = "^0.135.1"}
-aiocache = "^0.12.3"
-redis = {extras = ["hiredis"], version = "^7.0.0"}
-pyyaml = "^6.0.3"
-pybind11 = "^3.0.3"
-setuptools = "^82.0.1"
+[tool.poetry.group.dev.dependencies]
+# Testing
+pytest = "^8.4.2"
+pytest-asyncio = "^1.2.0"
pytest-cov = "^7.1.0"
+pytest-benchmark = "^5.2.3"
+httpx = "^0.28.1"
+aiohttp = "^3.13.3"
+faker = "^37.8.0"
-
-[tool.poetry.group.dev.dependencies]
-pre-commit = "^4.6.0"
-isort = "^8.0.1"
+# Linting & formatting
black = "^26.3.1"
+isort = "^8.0.1"
flake8 = "^7.3.0"
autoflake = "^2.3.1"
autopep8 = "^2.3.2"
-pytest = "^8.4.2"
-pytest-asyncio = "^1.2.0"
-httpx = "^0.28.1"
-faker = "^37.8.0"
-pytest-cov = "^7.0.0"
+# Security audit
bandit = "^1.8.6"
-aiohttp = "^3.13.3"
+# Hooks
+pre-commit = "^4.6.0"
+
+# ── Docs dependencies ─────────────────────────────────────────────────────────
[tool.poetry.group.docs.dependencies]
mkdocs = "^1.6.1"
mkdocs-material = "^9.7.3"
mkdocs-minify-plugin = "^0.8.0"
mkdocstrings = "^1.0.3"
+mkdocstrings-python = ">=2.0.3,<3.0.0"
-[build-system]
-requires = ["poetry-core>=2.0.0,<3.0.0"]
-build-backend = "poetry.core.masonry.api"
+# ── Tool configuration ────────────────────────────────────────────────────────
-[dependency-groups]
-dev = [
- "autopep8>=2.3.2",
- "opshero (>=0.1.2,<0.2.0)",
- "isort (>=8.0.1,<9.0.0)",
- "flake8 (>=7.3.0,<8.0.0)",
- "black (>=26.3.1,<27.0.0)",
- "pytest-benchmark (>=5.2.3,<6.0.0)",
- "tabulate (>=0.10.0,<0.11.0)",
-]
-docs = [
- "mkdocs (==1.6.1)",
- "mkdocs-material (==9.7.3)",
- "mkdocs-minify-plugin (==0.8.0)",
- "mkdocstrings (==1.0.3)",
- "mkdocstrings-python (>=2.0.3,<3.0.0)",
-]
[tool.flake8]
max-line-length = 88
+[tool.black]
+line-length = 88
+target-version = ["py311"]
-
-[tool.poetry.scripts]
-xcore = "xcore.cli.main:main"
-
-[tool.setuptools.packages.find]
-where = ["."]
-include = ["xcore*"]
+[tool.isort]
+profile = "black"
+line_length = 88
diff --git a/scripts/benchmarks.py b/scripts/benchmarks.py
index 4312c464..ff192c87 100644
--- a/scripts/benchmarks.py
+++ b/scripts/benchmarks.py
@@ -274,25 +274,141 @@ def _make_xcore_config(plugins_dir: Path) -> str:
cfg_file.write_text(
textwrap.dedent(
f"""
- app:
- name: xcore-bench
- secret_key: bench-secret-key-minimum-32-chars!!
- server_key: bench-server-key-minimum-32-chars!!
- env: development
-
- plugins:
- directory: {plugins_dir}
- strict_trusted: false
- interval: 0
-
- services:
- databases: {{}}
- cache:
- backend: memory
- ttl: 300
- max_size: 100000
- scheduler:
- enabled: false
+ app:
+ name: my-app
+ env: development
+ debug: true
+ secret_key: "vjherbvjhe"
+ #dotenv: "./extensions/.env"
+ plugin_prefix: "/app"
+ server_key: "rhverujierf"
+ server_key_iterations: 100000
+ plugin_tags:
+ - "test"
+
+ # ── Plugins ───────────────────────────────────────────────────
+ plugins:
+ directory: {plugins_dir}
+
+ # Clé HMAC-SHA256 utilisée pour vérifier plugin.sig
+ secret_key: "12345"
+
+ # true = refuse tout plugin Trusted non signé
+ strict_trusted: false
+
+ # Intervalle du watcher de rechargement à chaud (secondes)
+ # Mettre à 0 pour désactiver en prod si tu gères les reloads via API
+ interval: 10
+
+ entry_point: src/main.py
+
+ # Fichiers/extensions exclus du snapshot de détection de changements
+ snapshot:
+ extensions: [".log", ".pyc", ".html", ".map", ".min.js"]
+ filenames: ["__pycache__", "__init__.py", ".env", ".DS_Store"]
+ hidden: true
+
+ # ── Services ──────────────────────────────────────────────────
+ services:
+ # ── Bases de données ────────────────────────────────────────
+ databases:
+ db:
+ type: sqlasync
+ url: sqlite+aiosqlite:///db.sqlite3
+ echo: false
+ redis_db:
+ type: redis
+ url: redis://localhost:6379/0
+ max_connections: 50
+
+ # ── Cache ────────────────────────────────────────────────────
+ cache:
+ backend: redisrhverujierf
+ url: redis://localhost:6379/0
+ ttl: 300 # TTL par défaut en secondes
+ max_size: 10000 # ignoré en mode redis, actif en mode memory
+
+ # ── Scheduler ────────────────────────────────────────────────
+ scheduler:
+ enabled: true
+ backend: redis # redis = tâches persistantes, survivent au redémarrage
+ timezone: Europe/Paris
+
+ # Jobs déclarés statiquement (optionnel)
+ #jobs:
+ # # Nettoyage des sessions expirées chaque nuit à 2h
+ # - id: cleanup_sessions
+ # func: myapp.tasks.maintenance:cleanup_sessions
+ # trigger: cron
+ # hour: 2
+ # minute: 0
+ #
+ # # Snapshot des métriques toutes les 5 minutes
+ # - id: metrics_snapshot
+ # func: myapp.tasks.monitoring:snapshot_metrics
+ # trigger: interval
+ # minutes: 5
+
+ # ── Observabilité ─────────────────────────────────────────────
+
+ observability:
+ logging:
+ enabled: true
+ level: DEBUG # DEBUG | INFO | WARNING | ERROR | CRITICAL
+ format: "%(asctime)s [%(levelname)s] [%(name)s] %(message)s"
+ file: log/app.log
+ max_bytes: 52428800 # 50 MB par fichier
+ backup_count: 10 # 10 fichiers de rotation = 500 MB max
+
+ metrics:
+ enabled: true
+ backend: prometheus # memory | prometheus | statsd
+ prefix: myapp # préfixe des métriques exposées sur /metrics
+
+ tracing:
+ enabled: false # true si tu utilises OpenTelemetry / Jaeger
+ backend: noop # noop | opentelemetry | jaeger
+ service_name: my-app
+ endpoint: null # ex: http://jaeger:4317 (OTLP gRPC)
+
+ # ── Sécurité ──────────────────────────────────────────────────
+ security:
+ # Imports Python autorisés dans les plugins Sandboxed (whitelist AST)
+ # Les plugins Trusted ne sont pas limités par cette liste
+ allowed_imports:
+ - argparse
+ - fastapi
+ - json
+ - re
+ - math
+ - random
+ - datetime
+ - time
+ - pathlib
+ - typing
+ - dataclasses
+ - enum
+ - functools
+ - itertools
+ - collections
+ - string
+ - hashlib
+ - base64
+ - asyncio
+ - logging
+ - uuid
+ - decimal
+ - copy
+
+ # Imports explicitement interdits (surcharge les allowed_imports)
+ forbidden_imports:
+ - os
+
+ # Rate limit appliqué par défaut à chaque plugin non configuré
+ rate_limit_default:
+ calls: 200
+ period_seconds: 60
+
"""
).strip()
)
@@ -314,7 +430,6 @@ async def bench_single_load_unload(self, n_runs: int = 20) -> list[BenchResult]:
results = []
tmp = Path(tempfile.mkdtemp(prefix="xcore_bench_"))
try:
- from xcore.kernel.context import KernelContext
from xcore.kernel.runtime.lifecycle import LifecycleManager
from xcore.kernel.security.validation import ManifestValidator
@@ -431,7 +546,6 @@ async def bench_reload(self, n_runs: int = 15) -> list[BenchResult]:
samples: list[float] = []
errors = 0
try:
- from xcore.kernel.context import KernelContext
from xcore.kernel.runtime.lifecycle import LifecycleManager
from xcore.kernel.security.validation import ManifestValidator
@@ -1103,9 +1217,8 @@ async def run_suite(args) -> BenchReport:
bench = PluginCallBench()
for r in await bench.bench_sequential_calls(n_calls=args.calls):
report.add(r)
- print(
- f" ✓ {r.name}: mean={r.mean_ms:.3f}ms, {r.throughput_ops_sec:.0f} ops/s"
- )
+ ops = r.throughput_ops_sec
+ print(f" ✓ {r.name}: mean={r.mean_ms:.3f}ms, {ops:.0f} ops/s")
for r in await bench.bench_concurrent_calls([10, 50, 100]):
report.add(r)
print(f" ✓ {r.name}: {r.throughput_ops_sec:.0f} ops/s")
@@ -1119,9 +1232,8 @@ async def run_suite(args) -> BenchReport:
bench = MiddlewareBench()
for r in await bench.bench_pipeline_overhead(n=2000):
report.add(r)
- print(
- f" ✓ {r.name}: mean={r.mean_ms:.4f}ms, {r.throughput_ops_sec:.0f} ops/s"
- )
+ ops = r.throughput_ops_sec
+ print(f" ✓ {r.name}: mean={r.mean_ms:.4f}ms, {ops:.0f} ops/s")
# ── 4. Events ─────────────────────────────────────────────
if "events" in suites_to_run:
@@ -1129,9 +1241,8 @@ async def run_suite(args) -> BenchReport:
bench = EventsBench()
for r in await bench.bench_eventbus(n=2000):
report.add(r)
- print(
- f" ✓ {r.name}: mean={r.mean_ms:.4f}ms, {r.throughput_ops_sec:.0f} ops/s"
- )
+ ops = r.throughput_ops_sec
+ print(f" ✓ {r.name}: mean={r.mean_ms:.4f}ms, {ops:.0f} ops/s")
for r in await bench.bench_hookmanager(n=1000):
report.add(r)
print(f" ✓ {r.name}: mean={r.mean_ms:.4f}ms")
@@ -1142,9 +1253,8 @@ async def run_suite(args) -> BenchReport:
bench = PermissionsBench()
for r in bench.bench_engine(n=30000):
report.add(r)
- print(
- f" ✓ {r.name}: mean={r.mean_ms:.5f}ms, {r.throughput_ops_sec:.0f} ops/s"
- )
+ ops = r.throughput_ops_sec
+ print(f" ✓ {r.name}: mean={r.mean_ms:.5f}ms, {ops:.0f} ops/s")
# ── 6. Cache ──────────────────────────────────────────────
if "cache" in suites_to_run:
@@ -1152,9 +1262,8 @@ async def run_suite(args) -> BenchReport:
bench = CacheBench()
for r in await bench.bench_memory_backend(n=3000):
report.add(r)
- print(
- f" ✓ {r.name}: mean={r.mean_ms:.4f}ms, {r.throughput_ops_sec:.0f} ops/s"
- )
+ ops = r.throughput_ops_sec
+ print(f" ✓ {r.name}: mean={r.mean_ms:.4f}ms, {ops:.0f} ops/s")
# ── 7. Capacity ───────────────────────────────────────────
if "capacity" in suites_to_run or args.capacity:
@@ -1262,7 +1371,7 @@ def print_report(report: BenchReport) -> None:
if _HAS_PSUTIL:
avail_mb = psutil.virtual_memory().available / 1024**2
theoretical_max = int(avail_mb / avg_mb)
- print(f"\n Extrapolation:")
+ print("\n Extrapolation:")
print(
f" Average {avg_mb:.3f}MB/plugin — "
f"{avail_mb:.0f}MB available → "
@@ -1282,7 +1391,7 @@ def print_report(report: BenchReport) -> None:
print(
f" • Plugin call latency (ping): {r.mean_ms:.3f}ms mean, "
f"{r.p99_ms:.3f}ms P99 — "
- f"{'✅ excellent' if r.mean_ms < 1 else '⚠ acceptable' if r.mean_ms < 5 else '❌ slow'}"
+ f"{'✅ excellent' if r.mean_ms < 1 else '⚠ ok' if r.mean_ms < 5 else '❌'}"
)
if (
diff --git a/uv.lock b/uv.lock
deleted file mode 100644
index 06c3066e..00000000
--- a/uv.lock
+++ /dev/null
@@ -1,525 +0,0 @@
-version = 1
-revision = 3
-requires-python = ">=3.12"
-
-[manifest]
-
-[manifest.dependency-groups]
-dev = [
- { name = "autopep8", specifier = ">=2.3.2" },
- { name = "opshero", specifier = ">=0.1.2,<0.2.0" },
-]
-
-[[package]]
-name = "aiofiles"
-version = "25.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/41/c3/534eac40372d8ee36ef40df62ec129bee4fdb5ad9706e58a29be53b2c970/aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2", size = 46354, upload-time = "2025-10-09T20:51:04.358Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668, upload-time = "2025-10-09T20:51:03.174Z" },
-]
-
-[[package]]
-name = "annotated-types"
-version = "0.7.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
-]
-
-[[package]]
-name = "anyio"
-version = "4.13.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "idna" },
- { name = "typing-extensions", marker = "python_full_version < '3.13'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
-]
-
-[[package]]
-name = "autopep8"
-version = "2.3.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "pycodestyle" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/50/d8/30873d2b7b57dee9263e53d142da044c4600a46f2d28374b3e38b023df16/autopep8-2.3.2.tar.gz", hash = "sha256:89440a4f969197b69a995e4ce0661b031f455a9f776d2c5ba3dbd83466931758", size = 92210, upload-time = "2025-01-14T14:46:18.454Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl", hash = "sha256:ce8ad498672c845a0c3de2629c15b635ec2b05ef8177a6e7c91c74f3e9b51128", size = 45807, upload-time = "2025-01-14T14:46:15.466Z" },
-]
-
-[[package]]
-name = "certifi"
-version = "2026.2.25"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
-]
-
-[[package]]
-name = "cffi"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "pycparser", marker = "implementation_name != 'PyPy'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
- { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
- { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
- { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
- { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
- { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
- { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
- { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
- { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
- { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
- { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
- { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
- { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
- { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
- { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
- { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
- { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
- { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
- { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
- { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
- { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
- { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
- { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
- { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
- { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
- { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
- { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
- { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
- { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
- { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
- { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
- { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
- { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
- { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
- { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
- { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
- { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
- { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
- { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
- { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
- { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
- { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
- { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
- { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
- { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
- { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
-]
-
-[[package]]
-name = "click"
-version = "8.3.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "colorama", marker = "sys_platform == 'win32'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/57/75/31212c6bf2503fdf920d87fee5d7a86a2e3bcf444984126f13d8e4016804/click-8.3.2.tar.gz", hash = "sha256:14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5", size = 302856, upload-time = "2026-04-03T19:14:45.118Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d", size = 108379, upload-time = "2026-04-03T19:14:43.505Z" },
-]
-
-[[package]]
-name = "colorama"
-version = "0.4.6"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
-]
-
-[[package]]
-name = "cryptography"
-version = "46.0.7"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" },
- { url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" },
- { url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" },
- { url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" },
- { url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" },
- { url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" },
- { url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" },
- { url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" },
- { url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" },
- { url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" },
- { url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" },
- { url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" },
- { url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" },
- { url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" },
- { url = "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842", size = 7119671, upload-time = "2026-04-08T01:56:44Z" },
- { url = "https://files.pythonhosted.org/packages/74/66/e3ce040721b0b5599e175ba91ab08884c75928fbeb74597dd10ef13505d2/cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c", size = 4268551, upload-time = "2026-04-08T01:56:46.071Z" },
- { url = "https://files.pythonhosted.org/packages/03/11/5e395f961d6868269835dee1bafec6a1ac176505a167f68b7d8818431068/cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902", size = 4408887, upload-time = "2026-04-08T01:56:47.718Z" },
- { url = "https://files.pythonhosted.org/packages/40/53/8ed1cf4c3b9c8e611e7122fb56f1c32d09e1fff0f1d77e78d9ff7c82653e/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d", size = 4271354, upload-time = "2026-04-08T01:56:49.312Z" },
- { url = "https://files.pythonhosted.org/packages/50/46/cf71e26025c2e767c5609162c866a78e8a2915bbcfa408b7ca495c6140c4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022", size = 4905845, upload-time = "2026-04-08T01:56:50.916Z" },
- { url = "https://files.pythonhosted.org/packages/c0/ea/01276740375bac6249d0a971ebdf6b4dc9ead0ee0a34ef3b5a88c1a9b0d4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce", size = 4444641, upload-time = "2026-04-08T01:56:52.882Z" },
- { url = "https://files.pythonhosted.org/packages/3d/4c/7d258f169ae71230f25d9f3d06caabcff8c3baf0978e2b7d65e0acac3827/cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f", size = 3967749, upload-time = "2026-04-08T01:56:54.597Z" },
- { url = "https://files.pythonhosted.org/packages/b5/2a/2ea0767cad19e71b3530e4cad9605d0b5e338b6a1e72c37c9c1ceb86c333/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99", size = 4270942, upload-time = "2026-04-08T01:56:56.416Z" },
- { url = "https://files.pythonhosted.org/packages/41/3d/fe14df95a83319af25717677e956567a105bb6ab25641acaa093db79975d/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1", size = 4871079, upload-time = "2026-04-08T01:56:58.31Z" },
- { url = "https://files.pythonhosted.org/packages/9c/59/4a479e0f36f8f378d397f4eab4c850b4ffb79a2f0d58704b8fa0703ddc11/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2", size = 4443999, upload-time = "2026-04-08T01:57:00.508Z" },
- { url = "https://files.pythonhosted.org/packages/28/17/b59a741645822ec6d04732b43c5d35e4ef58be7bfa84a81e5ae6f05a1d33/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e", size = 4399191, upload-time = "2026-04-08T01:57:02.654Z" },
- { url = "https://files.pythonhosted.org/packages/59/6a/bb2e166d6d0e0955f1e9ff70f10ec4b2824c9cfcdb4da772c7dd69cc7d80/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee", size = 4655782, upload-time = "2026-04-08T01:57:04.592Z" },
- { url = "https://files.pythonhosted.org/packages/95/b6/3da51d48415bcb63b00dc17c2eff3a651b7c4fed484308d0f19b30e8cb2c/cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298", size = 3002227, upload-time = "2026-04-08T01:57:06.91Z" },
- { url = "https://files.pythonhosted.org/packages/32/a8/9f0e4ed57ec9cebe506e58db11ae472972ecb0c659e4d52bbaee80ca340a/cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb", size = 3475332, upload-time = "2026-04-08T01:57:08.807Z" },
- { url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" },
- { url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" },
- { url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" },
- { url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" },
- { url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" },
- { url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" },
- { url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" },
- { url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" },
- { url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" },
- { url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" },
- { url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" },
- { url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" },
- { url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" },
- { url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" },
-]
-
-[[package]]
-name = "ecdsa"
-version = "0.19.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "six" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/25/ca/8de7744cb3bc966c85430ca2d0fcaeea872507c6a4cf6e007f7fe269ed9d/ecdsa-0.19.2.tar.gz", hash = "sha256:62635b0ac1ca2e027f82122b5b81cb706edc38cd91c63dda28e4f3455a2bf930", size = 202432, upload-time = "2026-03-26T09:58:17.675Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/51/79/119091c98e2bf49e24ed9f3ae69f816d715d2904aefa6a2baa039a2ba0b0/ecdsa-0.19.2-py2.py3-none-any.whl", hash = "sha256:840f5dc5e375c68f36c1a7a5b9caad28f95daa65185c9253c0c08dd952bb7399", size = 150818, upload-time = "2026-03-26T09:58:15.808Z" },
-]
-
-[[package]]
-name = "h11"
-version = "0.16.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
-]
-
-[[package]]
-name = "httpcore"
-version = "1.0.9"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "certifi" },
- { name = "h11" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
-]
-
-[[package]]
-name = "httpx"
-version = "0.28.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "anyio" },
- { name = "certifi" },
- { name = "httpcore" },
- { name = "idna" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
-]
-
-[[package]]
-name = "idna"
-version = "3.11"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
-]
-
-[[package]]
-name = "markdown-it-py"
-version = "4.0.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "mdurl" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
-]
-
-[[package]]
-name = "mdurl"
-version = "0.1.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
-]
-
-[[package]]
-name = "opshero"
-version = "0.1.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "aiofiles" },
- { name = "anyio" },
- { name = "click" },
- { name = "httpx" },
- { name = "platformdirs" },
- { name = "pydantic" },
- { name = "pydantic-settings" },
- { name = "python-jose", extra = ["cryptography"] },
- { name = "rich" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/0f/51/84e3285212e26f7b1b4bde8ef9e578672c73bb3ba195e3d502ff14aabc7d/opshero-0.1.2.tar.gz", hash = "sha256:83d4a4d637986dd898d18cd414bde7f8bc169bb293de9bc64c9909506ed0ed2c", size = 33389, upload-time = "2026-03-06T16:38:16.405Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/fc/a6/2192729736b31cb94b625dc8680b71dfe01188b4081d26c73e9464a03baf/opshero-0.1.2-py3-none-any.whl", hash = "sha256:1dbd6c1d44388e5121d7a20fc5277f0340fef9d965263c15c0fef8df59e0a757", size = 40217, upload-time = "2026-03-06T16:38:15.303Z" },
-]
-
-[[package]]
-name = "platformdirs"
-version = "4.9.6"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" },
-]
-
-[[package]]
-name = "pyasn1"
-version = "0.6.3"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" },
-]
-
-[[package]]
-name = "pycodestyle"
-version = "2.14.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/11/e0/abfd2a0d2efe47670df87f3e3a0e2edda42f055053c85361f19c0e2c1ca8/pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783", size = 39472, upload-time = "2025-06-20T18:49:48.75Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d", size = 31594, upload-time = "2025-06-20T18:49:47.491Z" },
-]
-
-[[package]]
-name = "pycparser"
-version = "3.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
-]
-
-[[package]]
-name = "pydantic"
-version = "2.13.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "annotated-types" },
- { name = "pydantic-core" },
- { name = "typing-extensions" },
- { name = "typing-inspection" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/84/6b/69fd5c7194b21ebde0f8637e2a4ddc766ada29d472bfa6a5ca533d79549a/pydantic-2.13.0.tar.gz", hash = "sha256:b89b575b6e670ebf6e7448c01b41b244f471edd276cd0b6fe02e7e7aca320070", size = 843468, upload-time = "2026-04-13T10:51:35.571Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/01/d7/c3a52c61f5b7be648e919005820fbac33028c6149994cd64453f49951c17/pydantic-2.13.0-py3-none-any.whl", hash = "sha256:ab0078b90da5f3e2fd2e71e3d9b457ddcb35d0350854fbda93b451e28d56baaf", size = 471872, upload-time = "2026-04-13T10:51:33.343Z" },
-]
-
-[[package]]
-name = "pydantic-core"
-version = "2.46.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/6f/0a/9414cddf82eda3976b14048cc0fa8f5b5d1aecb0b22e1dcd2dbfe0e139b1/pydantic_core-2.46.0.tar.gz", hash = "sha256:82d2498c96be47b47e903e1378d1d0f770097ec56ea953322f39936a7cf34977", size = 471441, upload-time = "2026-04-13T09:06:33.813Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/a7/d2/206c72ad47071559142a35f71efc29eb16448a4a5ae9487230ab8e4e292b/pydantic_core-2.46.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:66ccedb02c934622612448489824955838a221b3a35875458970521ef17b2f9c", size = 2117060, upload-time = "2026-04-13T09:04:47.443Z" },
- { url = "https://files.pythonhosted.org/packages/17/2c/7a53b33f91c8b77e696b1a6aa3bed609bf9374bdc0f8dcda681bc7d922b8/pydantic_core-2.46.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a44f27f4d2788ef9876ec47a43739b118c5904d74f418f53398f6ced3bbcacf2", size = 1951802, upload-time = "2026-04-13T09:05:34.591Z" },
- { url = "https://files.pythonhosted.org/packages/fc/20/90e548c1f6d38800ef11c915881525770ce270d8e5e887563ff046a08674/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26a1032bcce6ca4b4670eb3f7d8195bd0a8b8f255f1307823e217ca3cfa7c27", size = 1976621, upload-time = "2026-04-13T09:04:03.909Z" },
- { url = "https://files.pythonhosted.org/packages/20/3c/9c5810ca70b60c623488cdd80f7e9ee1a0812df81e97098b64788719860f/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b8d1412f725060527e56675904b17a2d421dddcf861eecf7c75b9dda47921a4", size = 2056721, upload-time = "2026-04-13T09:04:40.992Z" },
- { url = "https://files.pythonhosted.org/packages/1a/a3/d6e5f4cdec84278431c75540f90838c9d0a4dfe9402a8f3902073660ff28/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc3d1569edd859cabaa476cabce9eecd05049a7966af7b4a33b541bfd4ca1104", size = 2239634, upload-time = "2026-04-13T09:03:52.478Z" },
- { url = "https://files.pythonhosted.org/packages/46/42/ef58aacf330d8de6e309d62469aa1f80e945eaf665929b4037ac1bfcebc1/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:38108976f2d8afaa8f5067fd1390a8c9f5cc580175407cda636e76bc76e88054", size = 2315739, upload-time = "2026-04-13T09:05:04.971Z" },
- { url = "https://files.pythonhosted.org/packages/8b/86/c63b12fafa2d86a515bfd1840b39c23a49302f02b653161bf9c3a0566c50/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5a06d8ed01dad5575056b5187e5959b336793c6047920a3441ee5b03533836", size = 2098169, upload-time = "2026-04-13T09:07:27.151Z" },
- { url = "https://files.pythonhosted.org/packages/76/19/b5b33a2f6be4755b21a20434293c4364be255f4c1a108f125d101d4cc4ee/pydantic_core-2.46.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:04017ace142da9ce27cafd423a480872571b5c7e80382aec22f7d715ca8eb870", size = 2170830, upload-time = "2026-04-13T09:04:39.448Z" },
- { url = "https://files.pythonhosted.org/packages/99/ae/7559f99a29b7d440012ddb4da897359304988a881efaca912fd2f655652e/pydantic_core-2.46.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2629ad992ed1b1c012e6067f5ffafd3336fcb9b54569449fabb85621f1444ed3", size = 2203901, upload-time = "2026-04-13T09:04:01.048Z" },
- { url = "https://files.pythonhosted.org/packages/dd/0e/b0ef945a39aeb4ac58da316813e1106b7fbdfbf20ac141c1c27904355ac5/pydantic_core-2.46.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3068b1e7bd986aebc88f6859f8353e72072538dcf92a7fb9cf511a0f61c5e729", size = 2191789, upload-time = "2026-04-13T09:06:39.915Z" },
- { url = "https://files.pythonhosted.org/packages/90/f4/830484e07188c1236b013995818888ab93bab8fd88aa9689b1d8fd22220d/pydantic_core-2.46.0-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:1e366916ff69ff700aa9326601634e688581bc24c5b6b4f8738d809ec7d72611", size = 2344423, upload-time = "2026-04-13T09:05:12.252Z" },
- { url = "https://files.pythonhosted.org/packages/fd/ba/e455c18cbdc333177af754e740be4fe9d1de173d65bbe534daf88da02ac0/pydantic_core-2.46.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:485a23e8f4618a1b8e23ac744180acde283fffe617f96923d25507d5cade62ec", size = 2384037, upload-time = "2026-04-13T09:06:24.503Z" },
- { url = "https://files.pythonhosted.org/packages/78/1f/b35d20d73144a41e78de0ae398e60fdd8bed91667daa1a5a92ab958551ba/pydantic_core-2.46.0-cp312-cp312-win32.whl", hash = "sha256:520940e1b702fe3b33525d0351777f25e9924f1818ca7956447dabacf2d339fd", size = 1967068, upload-time = "2026-04-13T09:05:23.374Z" },
- { url = "https://files.pythonhosted.org/packages/d1/84/4b6252e9606e8295647b848233cc4137ee0a04ebba8f0f9fb2977655b38c/pydantic_core-2.46.0-cp312-cp312-win_amd64.whl", hash = "sha256:90d2048e0339fa365e5a66aefe760ddd3b3d0a45501e088bc5bc7f4ed9ff9571", size = 2071008, upload-time = "2026-04-13T09:05:21.392Z" },
- { url = "https://files.pythonhosted.org/packages/39/95/d08eb508d4d5560ccbd226ee5971e5ef9b749aba9b413c0c4ed6e406d4f6/pydantic_core-2.46.0-cp312-cp312-win_arm64.whl", hash = "sha256:a70247649b7dffe36648e8f34be5ce8c5fa0a27ff07b071ea780c20a738c05ce", size = 2036634, upload-time = "2026-04-13T09:05:48.299Z" },
- { url = "https://files.pythonhosted.org/packages/df/05/ab3b0742bad1d51822f1af0c4232208408902bdcfc47601f3b812e09e6c2/pydantic_core-2.46.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:a05900c37264c070c683c650cbca8f83d7cbb549719e645fcd81a24592eac788", size = 2116814, upload-time = "2026-04-13T09:04:12.41Z" },
- { url = "https://files.pythonhosted.org/packages/98/08/30b43d9569d69094a0899a199711c43aa58fce6ce80f6a8f7693673eb995/pydantic_core-2.46.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de8e482fd4f1e3f36c50c6aac46d044462615d8f12cfafc6bebeaa0909eea22", size = 1951867, upload-time = "2026-04-13T09:04:02.364Z" },
- { url = "https://files.pythonhosted.org/packages/db/a0/bf9a1ba34537c2ed3872a48195291138fdec8fe26c4009776f00d63cf0c8/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c525ecf8a4cdf198327b65030a7d081867ad8e60acb01a7214fff95cf9832d47", size = 1977040, upload-time = "2026-04-13T09:06:16.088Z" },
- { url = "https://files.pythonhosted.org/packages/71/70/0ba03c20e1e118219fc18c5417b008b7e880f0e3fb38560ec4465984d471/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f14581aeb12e61542ce73b9bfef2bca5439d65d9ab3efe1a4d8e346b61838f9b", size = 2055284, upload-time = "2026-04-13T09:05:25.125Z" },
- { url = "https://files.pythonhosted.org/packages/58/cf/1e320acefbde7fb7158a9e5def55e0adf9a4634636098ce28dc6b978e0d3/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c108067f2f7e190d0dbd81247d789ec41f9ea50ccd9265a3a46710796ac60530", size = 2238896, upload-time = "2026-04-13T09:05:01.345Z" },
- { url = "https://files.pythonhosted.org/packages/df/f5/ea8ba209756abe9eba891bb0ef3772b4c59a894eb9ad86cd5bd0dd4e3e52/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ac10967e9a7bb1b96697374513f9a1a90a59e2fb41566b5e00ee45392beac59", size = 2314353, upload-time = "2026-04-13T09:06:07.942Z" },
- { url = "https://files.pythonhosted.org/packages/e8/f8/5885350203b72e96438eee7f94de0d8f0442f4627237ca8ef75de34db1cd/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7897078fe8a13b73623c0955dfb2b3d2c9acb7177aac25144758c9e5a5265aaa", size = 2098522, upload-time = "2026-04-13T09:04:23.239Z" },
- { url = "https://files.pythonhosted.org/packages/bf/88/5930b0e828e371db5a556dd3189565417ddc3d8316bb001058168aadcf5f/pydantic_core-2.46.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:e69ce405510a419a082a78faed65bb4249cfb51232293cc675645c12f7379bf7", size = 2168757, upload-time = "2026-04-13T09:07:12.46Z" },
- { url = "https://files.pythonhosted.org/packages/da/75/63d563d3035a0548e721c38b5b69fd5626fdd51da0f09ff4467503915b82/pydantic_core-2.46.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fd28d13eea0d8cf351dc1fe274b5070cc8e1cca2644381dee5f99de629e77cf3", size = 2202518, upload-time = "2026-04-13T09:05:44.418Z" },
- { url = "https://files.pythonhosted.org/packages/a7/53/1958eacbfddc41aadf5ae86dd85041bf054b675f34a2fa76385935f96070/pydantic_core-2.46.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:ee1547a6b8243e73dd10f585555e5a263395e55ce6dea618a078570a1e889aef", size = 2190148, upload-time = "2026-04-13T09:06:56.151Z" },
- { url = "https://files.pythonhosted.org/packages/c7/17/098cc6d3595e4623186f2bc6604a6195eb182e126702a90517236391e9ce/pydantic_core-2.46.0-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:c3dc68dcf62db22a18ddfc3ad4960038f72b75908edc48ae014d7ac8b391d57a", size = 2342925, upload-time = "2026-04-13T09:04:17.286Z" },
- { url = "https://files.pythonhosted.org/packages/71/a7/abdb924620b1ac535c690b36ad5b8871f376104090f8842c08625cecf1d3/pydantic_core-2.46.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:004a2081c881abfcc6854a4623da6a09090a0d7c1398a6ae7133ca1256cee70b", size = 2383167, upload-time = "2026-04-13T09:04:52.643Z" },
- { url = "https://files.pythonhosted.org/packages/d7/c9/2ddd10f50e4b7350d2574629a0f53d8d4eb6573f9c19a6b43e6b1487a31d/pydantic_core-2.46.0-cp313-cp313-win32.whl", hash = "sha256:59d24ec8d5eaabad93097525a69d0f00f2667cb353eb6cda578b1cfff203ceef", size = 1965660, upload-time = "2026-04-13T09:06:05.877Z" },
- { url = "https://files.pythonhosted.org/packages/b5/e7/1efc38ed6f2680c032bcefa0e3ebd496a8c77e92dfdb86b07d0f2fc632b1/pydantic_core-2.46.0-cp313-cp313-win_amd64.whl", hash = "sha256:71186dad5ac325c64d68fe0e654e15fd79802e7cc42bc6f0ff822d5ad8b1ab25", size = 2069563, upload-time = "2026-04-13T09:07:14.738Z" },
- { url = "https://files.pythonhosted.org/packages/c3/1e/a325b4989e742bf7e72ed35fa124bc611fd76539c9f8cd2a9a7854473533/pydantic_core-2.46.0-cp313-cp313-win_arm64.whl", hash = "sha256:8e4503f3213f723842c9a3b53955c88a9cfbd0b288cbd1c1ae933aebeec4a1b4", size = 2034966, upload-time = "2026-04-13T09:04:21.629Z" },
- { url = "https://files.pythonhosted.org/packages/36/3b/914891d384cdbf9a6f464eb13713baa22ea1e453d4da80fb7da522079370/pydantic_core-2.46.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:4fc801c290342350ffc82d77872054a934b2e24163727263362170c1db5416ca", size = 2113349, upload-time = "2026-04-13T09:04:59.407Z" },
- { url = "https://files.pythonhosted.org/packages/35/95/3a0c6f65e231709fb3463e32943c69d10285cb50203a2130a4732053a06d/pydantic_core-2.46.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0a36f2cc88170cc177930afcc633a8c15907ea68b59ac16bd180c2999d714940", size = 1949170, upload-time = "2026-04-13T09:06:09.935Z" },
- { url = "https://files.pythonhosted.org/packages/d1/63/d845c36a608469fe7bee226edeff0984c33dbfe7aecd755b0e7ab5a275c4/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a3912e0c568a1f99d4d6d3e41def40179d61424c0ca1c8c87c4877d7f6fd7fb", size = 1977914, upload-time = "2026-04-13T09:04:56.16Z" },
- { url = "https://files.pythonhosted.org/packages/08/6f/f2e7a7f85931fb31671f5378d1c7fc70606e4b36d59b1b48e1bd1ef5d916/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3534c3415ed1a19ab23096b628916a827f7858ec8db49ad5d7d1e44dc13c0d7b", size = 2050538, upload-time = "2026-04-13T09:05:06.789Z" },
- { url = "https://files.pythonhosted.org/packages/8c/97/f4aa7181dd9a16dd9059a99fc48fdab0c2aab68307283a5c04cf56de68c4/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21067396fc285609323a4db2f63a87570044abe0acddfcca8b135fc7948e3db7", size = 2236294, upload-time = "2026-04-13T09:07:03.2Z" },
- { url = "https://files.pythonhosted.org/packages/24/c1/6a5042fc32765c87101b500f394702890af04239c318b6002cfd627b710d/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2afd85b7be186e2fe7cdbb09a3d964bcc2042f65bbcc64ad800b3c7915032655", size = 2312954, upload-time = "2026-04-13T09:06:11.919Z" },
- { url = "https://files.pythonhosted.org/packages/cb/e4/566101a561492ce8454f0844ca29c3b675a6b3a7b3ff577db85ed05c8c50/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67e2c2e171b78db8154da602de72ffdc473c6ee51de8a9d80c0f1cd4051abfc7", size = 2102533, upload-time = "2026-04-13T09:06:58.664Z" },
- { url = "https://files.pythonhosted.org/packages/3e/ac/adc11ee1646a5c4dd9abb09a00e7909e6dc25beddc0b1310ca734bb9b48e/pydantic_core-2.46.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c16ae1f3170267b1a37e16dba5c297bdf60c8b5657b147909ca8774ce7366644", size = 2169447, upload-time = "2026-04-13T09:04:11.143Z" },
- { url = "https://files.pythonhosted.org/packages/26/73/408e686b45b82d28ac19e8229e07282254dbee6a5d24c5c7cf3cf3716613/pydantic_core-2.46.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:133b69e1c1ba34d3702eed73f19f7f966928f9aa16663b55c2ebce0893cca42e", size = 2200672, upload-time = "2026-04-13T09:03:54.056Z" },
- { url = "https://files.pythonhosted.org/packages/0a/3b/807d5b035ec891b57b9079ce881f48263936c37bd0d154a056e7fd152afb/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:15ed8e5bde505133d96b41702f31f06829c46b05488211a5b1c7877e11de5eb5", size = 2188293, upload-time = "2026-04-13T09:07:07.614Z" },
- { url = "https://files.pythonhosted.org/packages/f1/ed/719b307516285099d1196c52769fdbe676fd677da007b9c349ae70b7226d/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:8cfc29a1c66a7f0fcb36262e92f353dd0b9c4061d558fceb022e698a801cb8ae", size = 2335023, upload-time = "2026-04-13T09:04:05.176Z" },
- { url = "https://files.pythonhosted.org/packages/8d/90/8718e4ae98c4e8a7325afdc079be82be1e131d7a47cb6c098844a9531ffe/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e1155708540f13845bf68d5ac511a55c76cfe2e057ed12b4bf3adac1581fc5c2", size = 2377155, upload-time = "2026-04-13T09:06:18.081Z" },
- { url = "https://files.pythonhosted.org/packages/dd/dc/7172789283b963f81da2fc92b186e22de55687019079f71c4d570822502b/pydantic_core-2.46.0-cp314-cp314-win32.whl", hash = "sha256:de5635a48df6b2eef161d10ea1bc2626153197333662ba4cd700ee7ec1aba7f5", size = 1963078, upload-time = "2026-04-13T09:05:30.615Z" },
- { url = "https://files.pythonhosted.org/packages/e0/69/03a7ea4b6264def3a44eabf577528bcec2f49468c5698b2044dea54dc07e/pydantic_core-2.46.0-cp314-cp314-win_amd64.whl", hash = "sha256:f07a5af60c5e7cf53dd1ff734228bd72d0dc9938e64a75b5bb308ca350d9681e", size = 2068439, upload-time = "2026-04-13T09:04:57.729Z" },
- { url = "https://files.pythonhosted.org/packages/f5/eb/1c3afcfdee2ab6634b802ab0a0f1966df4c8b630028ec56a1cb0a710dc58/pydantic_core-2.46.0-cp314-cp314-win_arm64.whl", hash = "sha256:e7a77eca3c7d5108ff509db20aae6f80d47c7ed7516d8b96c387aacc42f3ce0f", size = 2026470, upload-time = "2026-04-13T09:05:08.654Z" },
- { url = "https://files.pythonhosted.org/packages/5c/30/1177dde61b200785c4739665e3aa03a9d4b2c25d2d0408b07d585e633965/pydantic_core-2.46.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5e7cdd4398bee1aaeafe049ac366b0f887451d9ae418fd8785219c13fea2f928", size = 2107447, upload-time = "2026-04-13T09:05:46.314Z" },
- { url = "https://files.pythonhosted.org/packages/b1/60/4e0f61f99bdabbbc309d364a2791e1ba31e778a4935bc43391a7bdec0744/pydantic_core-2.46.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5c2c92d82808e27cef3f7ab3ed63d657d0c755e0dbe5b8a58342e37bdf09bd2e", size = 1926927, upload-time = "2026-04-13T09:06:20.371Z" },
- { url = "https://files.pythonhosted.org/packages/1d/d0/67f89a8269152c1d6eaa81f04e75a507372ebd8ca7382855a065222caa80/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bab80af91cd7014b45d1089303b5f844a9d91d7da60eabf3d5f9694b32a6655", size = 1966613, upload-time = "2026-04-13T09:07:05.389Z" },
- { url = "https://files.pythonhosted.org/packages/cd/07/8dfdc3edc78f29a80fb31f366c50203ec904cff6a4c923599bf50ac0d0ff/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e49ffdb714bc990f00b39d1ad1d683033875b5af15582f60c1f34ad3eeccfaa", size = 2032902, upload-time = "2026-04-13T09:06:42.47Z" },
- { url = "https://files.pythonhosted.org/packages/b0/2a/111c5e8fe24f99c46bcad7d3a82a8f6dbc738066e2c72c04c71f827d8c78/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca877240e8dbdeef3a66f751dc41e5a74893767d510c22a22fc5c0199844f0ce", size = 2244456, upload-time = "2026-04-13T09:05:36.484Z" },
- { url = "https://files.pythonhosted.org/packages/6b/7c/cfc5d11c15a63ece26e148572c77cfbb2c7f08d315a7b63ef0fe0711d753/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87e6843f89ecd2f596d7294e33196c61343186255b9880c4f1b725fde8b0e20d", size = 2294535, upload-time = "2026-04-13T09:06:01.689Z" },
- { url = "https://files.pythonhosted.org/packages/c4/2c/f0d744e3dab7bd026a3f4670a97a295157cff923a2666d30a15a70a7e3d0/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e20bc5add1dd9bc3b9a3600d40632e679376569098345500799a6ad7c5d46c72", size = 2104621, upload-time = "2026-04-13T09:04:34.388Z" },
- { url = "https://files.pythonhosted.org/packages/a7/64/e7cc4698dc024264d214b51d5a47a2404221b12060dd537d76f831b2120a/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:ee6ff79a5f0289d64a9d6696a3ce1f98f925b803dd538335a118231e26d6d827", size = 2130718, upload-time = "2026-04-13T09:04:26.23Z" },
- { url = "https://files.pythonhosted.org/packages/0b/a8/224e655fec21f7d4441438ad2ecaccb33b5a3876ce7bb2098c74a49efc14/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:52d35cfb58c26323101c7065508d7bb69bb56338cda9ea47a7b32be581af055d", size = 2180738, upload-time = "2026-04-13T09:05:50.253Z" },
- { url = "https://files.pythonhosted.org/packages/32/7b/b3025618ed4c4e4cbaa9882731c19625db6669896b621760ea95bc1125ef/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d14cc5a6f260fa78e124061eebc5769af6534fc837e9a62a47f09a2c341fa4ea", size = 2171222, upload-time = "2026-04-13T09:07:29.929Z" },
- { url = "https://files.pythonhosted.org/packages/7b/e3/68170aa1d891920af09c1f2f34df61dc5ff3a746400027155523e3400e89/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:4f7ff859d663b6635f6307a10803d07f0d09487e16c3d36b1744af51dbf948b2", size = 2320040, upload-time = "2026-04-13T09:06:35.732Z" },
- { url = "https://files.pythonhosted.org/packages/67/1b/5e65807001b84972476300c1f49aea2b4971b7e9fffb5c2654877dadd274/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:8ef749be6ed0d69dba31902aaa8255a9bb269ae50c93888c4df242d8bb7acd9e", size = 2377062, upload-time = "2026-04-13T09:07:39.945Z" },
- { url = "https://files.pythonhosted.org/packages/75/03/48caa9dd5f28f7662bd52bff454d9a451f6b7e5e4af95e289e5e170749c9/pydantic_core-2.46.0-cp314-cp314t-win32.whl", hash = "sha256:d93ca72870133f86360e4bb0c78cd4e6ba2a0f9f3738a6486909ffc031463b32", size = 1951028, upload-time = "2026-04-13T09:04:20.224Z" },
- { url = "https://files.pythonhosted.org/packages/87/ed/e97ff55fe28c0e6e3cba641d622b15e071370b70e5f07c496b07b65db7c9/pydantic_core-2.46.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6ebb2668afd657e2127cb40f2ceb627dd78e74e9dfde14d9bf6cdd532a29ff59", size = 2048519, upload-time = "2026-04-13T09:05:10.464Z" },
- { url = "https://files.pythonhosted.org/packages/b6/51/e0db8267a287994546925f252e329eeae4121b1e77e76353418da5a3adf0/pydantic_core-2.46.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4864f5bbb7993845baf9209bae1669a8a76769296a018cb569ebda9dcb4241f5", size = 2026791, upload-time = "2026-04-13T09:04:37.724Z" },
- { url = "https://files.pythonhosted.org/packages/74/0c/106ed5cc50393d90523f09adcc50d05e42e748eb107dc06aea971137f02d/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:bc0e2fefe384152d7da85b5c2fe8ce2bf24752f68a58e3f3ea42e28a29dfdeb2", size = 2104968, upload-time = "2026-04-13T09:06:26.967Z" },
- { url = "https://files.pythonhosted.org/packages/f5/71/b494cef3165e3413ee9bbbb5a9eedc9af0ea7b88d8638beef6c2061b110e/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:a2ab0e785548be1b4362a62c4004f9217598b7ee465f1f420fc2123e2a5b5b02", size = 1940442, upload-time = "2026-04-13T09:06:29.332Z" },
- { url = "https://files.pythonhosted.org/packages/7e/3e/a4d578c8216c443e26a1124f8c1e07c0654264ce5651143d3883d85ff140/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16d45aecb18b8cba1c68eeb17c2bb2d38627ceed04c5b30b882fc9134e01f187", size = 1999672, upload-time = "2026-04-13T09:04:42.798Z" },
- { url = "https://files.pythonhosted.org/packages/cd/c1/9114560468685525a21770138382fd0cb849aaf351ff2c7b97f760d121e0/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5078f6c377b002428e984259ac327ef8902aacae6c14b7de740dd4869a491501", size = 2154533, upload-time = "2026-04-13T09:04:50.868Z" },
-]
-
-[[package]]
-name = "pydantic-settings"
-version = "2.13.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "pydantic" },
- { name = "python-dotenv" },
- { name = "typing-inspection" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/52/6d/fffca34caecc4a3f97bda81b2098da5e8ab7efc9a66e819074a11955d87e/pydantic_settings-2.13.1.tar.gz", hash = "sha256:b4c11847b15237fb0171e1462bf540e294affb9b86db4d9aa5c01730bdbe4025", size = 223826, upload-time = "2026-02-19T13:45:08.055Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", hash = "sha256:d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237", size = 58929, upload-time = "2026-02-19T13:45:06.034Z" },
-]
-
-[[package]]
-name = "pygments"
-version = "2.20.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
-]
-
-[[package]]
-name = "python-dotenv"
-version = "1.2.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
-]
-
-[[package]]
-name = "python-jose"
-version = "3.5.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "ecdsa" },
- { name = "pyasn1" },
- { name = "rsa" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/c6/77/3a1c9039db7124eb039772b935f2244fbb73fc8ee65b9acf2375da1c07bf/python_jose-3.5.0.tar.gz", hash = "sha256:fb4eaa44dbeb1c26dcc69e4bd7ec54a1cb8dd64d3b4d81ef08d90ff453f2b01b", size = 92726, upload-time = "2025-05-28T17:31:54.288Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/d9/c3/0bd11992072e6a1c513b16500a5d07f91a24017c5909b02c72c62d7ad024/python_jose-3.5.0-py2.py3-none-any.whl", hash = "sha256:abd1202f23d34dfad2c3d28cb8617b90acf34132c7afd60abd0b0b7d3cb55771", size = 34624, upload-time = "2025-05-28T17:31:52.802Z" },
-]
-
-[package.optional-dependencies]
-cryptography = [
- { name = "cryptography" },
-]
-
-[[package]]
-name = "rich"
-version = "15.0.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "markdown-it-py" },
- { name = "pygments" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" },
-]
-
-[[package]]
-name = "rsa"
-version = "4.9.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "pyasn1" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" },
-]
-
-[[package]]
-name = "six"
-version = "1.17.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
-]
-
-[[package]]
-name = "typing-extensions"
-version = "4.15.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
-]
-
-[[package]]
-name = "typing-inspection"
-version = "0.4.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
- { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
-]
diff --git a/xcore_bench_report.json b/xcore_bench_report.json
new file mode 100644
index 00000000..de74e37f
--- /dev/null
+++ b/xcore_bench_report.json
@@ -0,0 +1,461 @@
+{
+ "meta": {
+ "xcore_version": "2.1.2",
+ "python_version": "3.14.4",
+ "platform": "linux",
+ "timestamp": "2026-04-29T11:02:58.798418",
+ "cpu_count": 8,
+ "total_duration_s": 3.172987825999371,
+ "system_info": {
+ "cpu_count": 8,
+ "cpu_freq_mhz": 1379.54425,
+ "total_ram_gb": 15.3,
+ "available_ram_gb": 8.4
+ }
+ },
+ "results": [
+ {
+ "name": "single_plugin_load",
+ "category": "plugin_lifecycle",
+ "iterations": 20,
+ "total_ms": 23.769449999235803,
+ "mean_ms": 1.1884724999617902,
+ "median_ms": 1.1223724995943485,
+ "p95_ms": 2.5641230004112003,
+ "p99_ms": 2.5641230004112003,
+ "min_ms": 0.9731579993967898,
+ "max_ms": 2.5641230004112003,
+ "std_ms": 0.3313133053575544,
+ "throughput_ops_sec": 841.4161876123767,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": "20 runs"
+ },
+ {
+ "name": "single_plugin_unload",
+ "category": "plugin_lifecycle",
+ "iterations": 20,
+ "total_ms": 5.08798499686236,
+ "mean_ms": 0.254399249843118,
+ "median_ms": 0.24472649874951458,
+ "p95_ms": 0.3115250001428649,
+ "p99_ms": 0.3115250001428649,
+ "min_ms": 0.2223270003014477,
+ "max_ms": 0.3115250001428649,
+ "std_ms": 0.024043957390132698,
+ "throughput_ops_sec": 3930.829201016419,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": "20 runs"
+ },
+ {
+ "name": "plugin_reload",
+ "category": "plugin_lifecycle",
+ "iterations": 20,
+ "total_ms": 12.287289991945727,
+ "mean_ms": 0.6143644995972863,
+ "median_ms": 0.6017319992679404,
+ "p95_ms": 0.736632999178255,
+ "p99_ms": 0.736632999178255,
+ "min_ms": 0.5194500008656178,
+ "max_ms": 0.736632999178255,
+ "std_ms": 0.055637530881803024,
+ "throughput_ops_sec": 1627.6982160517027,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "batch_load_5_plugins",
+ "category": "plugin_lifecycle",
+ "iterations": 5,
+ "total_ms": 334.2003189991374,
+ "mean_ms": 66.84006379982748,
+ "median_ms": 66.84006379982748,
+ "p95_ms": 100.26009569974121,
+ "p99_ms": 133.68012759965495,
+ "min_ms": 0,
+ "max_ms": 334.2003189991374,
+ "std_ms": 0,
+ "throughput_ops_sec": 14.961086856451821,
+ "memory_delta_mb": 8.98046875,
+ "errors": 4,
+ "notes": "1/5 loaded, 1.80MB/plugin"
+ },
+ {
+ "name": "batch_load_20_plugins",
+ "category": "plugin_lifecycle",
+ "iterations": 20,
+ "total_ms": 98.60400199977448,
+ "mean_ms": 4.930200099988724,
+ "median_ms": 4.930200099988724,
+ "p95_ms": 7.395300149983086,
+ "p99_ms": 9.860400199977448,
+ "min_ms": 0,
+ "max_ms": 98.60400199977448,
+ "std_ms": 0,
+ "throughput_ops_sec": 202.83152401913406,
+ "memory_delta_mb": 0.0078125,
+ "errors": 19,
+ "notes": "1/20 loaded, 0.00MB/plugin"
+ },
+ {
+ "name": "batch_load_50_plugins",
+ "category": "plugin_lifecycle",
+ "iterations": 50,
+ "total_ms": 217.12198100067326,
+ "mean_ms": 4.342439620013465,
+ "median_ms": 4.342439620013465,
+ "p95_ms": 6.513659430020198,
+ "p99_ms": 8.68487924002693,
+ "min_ms": 0,
+ "max_ms": 217.12198100067326,
+ "std_ms": 0,
+ "throughput_ops_sec": 230.28529755283026,
+ "memory_delta_mb": 0.0078125,
+ "errors": 49,
+ "notes": "1/50 loaded, 0.00MB/plugin"
+ },
+ {
+ "name": "sequential_call_ping",
+ "category": "plugin_calls",
+ "iterations": 300,
+ "total_ms": 0.43731200457841624,
+ "mean_ms": 0.0014577066819280542,
+ "median_ms": 0.0013984999895910732,
+ "p95_ms": 0.0015459991118405014,
+ "p99_ms": 0.003385999661986716,
+ "min_ms": 0.0013400003808783367,
+ "max_ms": 0.00393899972550571,
+ "std_ms": 0.0002761582529130064,
+ "throughput_ops_sec": 686009.0664312092,
+ "memory_delta_mb": 0.0,
+ "errors": 300,
+ "notes": "single plugin, 300 calls"
+ },
+ {
+ "name": "sequential_call_echo_payload",
+ "category": "plugin_calls",
+ "iterations": 300,
+ "total_ms": 0.4002499863418052,
+ "mean_ms": 0.0013341666211393506,
+ "median_ms": 0.0013040007615927607,
+ "p95_ms": 0.0014170000213198364,
+ "p99_ms": 0.002333999873371795,
+ "min_ms": 0.001186999725177884,
+ "max_ms": 0.0084509993030224,
+ "std_ms": 0.0004493578761466993,
+ "throughput_ops_sec": 749531.5683628937,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "concurrent_10_calls",
+ "category": "plugin_calls",
+ "iterations": 10,
+ "total_ms": 0.1259989985555876,
+ "mean_ms": 0.01259989985555876,
+ "median_ms": 0.01259989985555876,
+ "p95_ms": 0.01637986981222639,
+ "p99_ms": 0.01889984978333814,
+ "min_ms": 0,
+ "max_ms": 0.1259989985555876,
+ "std_ms": 0,
+ "throughput_ops_sec": 79365.71016148395,
+ "memory_delta_mb": 0.0,
+ "errors": 10,
+ "notes": "asyncio.gather(10)"
+ },
+ {
+ "name": "concurrent_50_calls",
+ "category": "plugin_calls",
+ "iterations": 50,
+ "total_ms": 0.9103359989239834,
+ "mean_ms": 0.01820671997847967,
+ "median_ms": 0.01820671997847967,
+ "p95_ms": 0.02366873597202357,
+ "p99_ms": 0.027310079967719503,
+ "min_ms": 0,
+ "max_ms": 0.9103359989239834,
+ "std_ms": 0,
+ "throughput_ops_sec": 54924.77509304253,
+ "memory_delta_mb": 0.0,
+ "errors": 50,
+ "notes": "asyncio.gather(50)"
+ },
+ {
+ "name": "concurrent_100_calls",
+ "category": "plugin_calls",
+ "iterations": 100,
+ "total_ms": 0.977535000856733,
+ "mean_ms": 0.00977535000856733,
+ "median_ms": 0.00977535000856733,
+ "p95_ms": 0.012707955011137528,
+ "p99_ms": 0.014663025012850994,
+ "min_ms": 0,
+ "max_ms": 0.977535000856733,
+ "std_ms": 0,
+ "throughput_ops_sec": 102298.12734312104,
+ "memory_delta_mb": 0.0,
+ "errors": 100,
+ "notes": "asyncio.gather(100)"
+ },
+ {
+ "name": "routing_5_plugins",
+ "category": "plugin_calls",
+ "iterations": 200,
+ "total_ms": 36.704412994367885,
+ "mean_ms": 0.18352206497183943,
+ "median_ms": 0.053088499953446444,
+ "p95_ms": 0.09035499897436239,
+ "p99_ms": 1.3090060001559323,
+ "min_ms": 0.04803100091521628,
+ "max_ms": 23.589220998474048,
+ "std_ms": 1.6658224108825137,
+ "throughput_ops_sec": 5448.936072910062,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": "1 loaded, 200 calls round-robin"
+ },
+ {
+ "name": "routing_20_plugins",
+ "category": "plugin_calls",
+ "iterations": 200,
+ "total_ms": 27.830518991322606,
+ "mean_ms": 0.13915259495661303,
+ "median_ms": 0.04957249984727241,
+ "p95_ms": 0.05526799941435456,
+ "p99_ms": 0.15645399980712682,
+ "min_ms": 0.04550499943434261,
+ "max_ms": 17.677613999694586,
+ "std_ms": 1.2464368919166002,
+ "throughput_ops_sec": 7186.3553842585125,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": "1 loaded, 200 calls round-robin"
+ },
+ {
+ "name": "pipeline_0_middlewares",
+ "category": "middleware",
+ "iterations": 2000,
+ "total_ms": 6.2837549648975255,
+ "mean_ms": 0.0031418774824487627,
+ "median_ms": 0.0030020000849617645,
+ "p95_ms": 0.003402001311769709,
+ "p99_ms": 0.005285000952426344,
+ "min_ms": 0.0028329995984677225,
+ "max_ms": 0.027694000891642645,
+ "std_ms": 0.0007802001839578725,
+ "throughput_ops_sec": 318281.02960291284,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "pipeline_4_middlewares",
+ "category": "middleware",
+ "iterations": 2000,
+ "total_ms": 15.405727997858776,
+ "mean_ms": 0.007702863998929388,
+ "median_ms": 0.00762699892220553,
+ "p95_ms": 0.007886999810580164,
+ "p99_ms": 0.008286000593216158,
+ "min_ms": 0.007045999154797755,
+ "max_ms": 0.038139998650876805,
+ "std_ms": 0.0009654246622238234,
+ "throughput_ops_sec": 129821.84290661095,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "eventbus_emit_no_handlers",
+ "category": "events",
+ "iterations": 2000,
+ "total_ms": 5.895346959732706,
+ "mean_ms": 0.002947673479866353,
+ "median_ms": 0.002868000592570752,
+ "p95_ms": 0.0030080009310040623,
+ "p99_ms": 0.0050319995352765545,
+ "min_ms": 0.002712999048526399,
+ "max_ms": 0.043355999878258444,
+ "std_ms": 0.001064872533143774,
+ "throughput_ops_sec": 339250.6011369142,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "eventbus_emit_1_handler",
+ "category": "events",
+ "iterations": 2000,
+ "total_ms": 60.01824601298722,
+ "mean_ms": 0.03000912300649361,
+ "median_ms": 0.02952399881905876,
+ "p95_ms": 0.03320500036352314,
+ "p99_ms": 0.041909999708877876,
+ "min_ms": 0.02584400135674514,
+ "max_ms": 0.2899190003518015,
+ "std_ms": 0.006676347765717948,
+ "throughput_ops_sec": 33323.199741079145,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "eventbus_emit_10_handlers",
+ "category": "events",
+ "iterations": 2000,
+ "total_ms": 188.12697701469006,
+ "mean_ms": 0.09406348850734503,
+ "median_ms": 0.09339999996882398,
+ "p95_ms": 0.10070899952552281,
+ "p99_ms": 0.14355000166688114,
+ "min_ms": 0.08609399992565159,
+ "max_ms": 0.22089699996286072,
+ "std_ms": 0.009094239149095826,
+ "throughput_ops_sec": 10631.11751295418,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "eventbus_wildcard_matching",
+ "category": "events",
+ "iterations": 2000,
+ "total_ms": 61.01844501426967,
+ "mean_ms": 0.030509222507134837,
+ "median_ms": 0.030687499929626938,
+ "p95_ms": 0.03206899964425247,
+ "p99_ms": 0.03860600008920301,
+ "min_ms": 0.02817599852278363,
+ "max_ms": 0.11208199975953903,
+ "std_ms": 0.002674307538655587,
+ "throughput_ops_sec": 32776.97423348437,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "hookmanager_5_priority_hooks",
+ "category": "events",
+ "iterations": 1000,
+ "total_ms": 583.6400079806481,
+ "mean_ms": 0.5836400079806481,
+ "median_ms": 0.5261955002424656,
+ "p95_ms": 0.8773120007390389,
+ "p99_ms": 1.2226449998706812,
+ "min_ms": 0.4424439994181739,
+ "max_ms": 1.6500950005138293,
+ "std_ms": 0.15156558065797768,
+ "throughput_ops_sec": 1713.384939904869,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "permission_check_cold",
+ "category": "permissions",
+ "iterations": 30000,
+ "total_ms": 95.54461987681862,
+ "mean_ms": 0.0031848206625606206,
+ "median_ms": 0.0024439996195724234,
+ "p95_ms": 0.004006000381195918,
+ "p99_ms": 0.005276000592857599,
+ "min_ms": 0.0021680007193936035,
+ "max_ms": 16.837430999657954,
+ "std_ms": 0.09720053431247311,
+ "throughput_ops_sec": 313989.4223105147,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "permission_check_cached",
+ "category": "permissions",
+ "iterations": 30000,
+ "total_ms": 47.549882936436916,
+ "mean_ms": 0.0015849960978812304,
+ "median_ms": 0.0014399993233382702,
+ "p95_ms": 0.002587999915704131,
+ "p99_ms": 0.0039810001908335835,
+ "min_ms": 0.0012749987945426255,
+ "max_ms": 0.18682699919736478,
+ "std_ms": 0.0013853130015427815,
+ "throughput_ops_sec": 630916.3797543517,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "cache_set_single",
+ "category": "cache",
+ "iterations": 3000,
+ "total_ms": 9.143716904873145,
+ "mean_ms": 0.003047905634957715,
+ "median_ms": 0.0027790010790340602,
+ "p95_ms": 0.003654000465758145,
+ "p99_ms": 0.0054299998737405986,
+ "min_ms": 0.0024029995984165,
+ "max_ms": 0.1521260001027258,
+ "std_ms": 0.0034273297951717763,
+ "throughput_ops_sec": 328094.147184407,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "cache_get_hot",
+ "category": "cache",
+ "iterations": 3000,
+ "total_ms": 4.200314024274121,
+ "mean_ms": 0.0014001046747580403,
+ "median_ms": 0.0013295002645463683,
+ "p95_ms": 0.0017040001694113016,
+ "p99_ms": 0.0024310011212946847,
+ "min_ms": 0.0011490010365378112,
+ "max_ms": 0.019130999135086313,
+ "std_ms": 0.000579013570229349,
+ "throughput_ops_sec": 714232.3127896244,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "cache_mset_100_keys",
+ "category": "cache",
+ "iterations": 300,
+ "total_ms": 31.199731001834152,
+ "mean_ms": 0.10399910333944717,
+ "median_ms": 0.09965949993784307,
+ "p95_ms": 0.12172499918960966,
+ "p99_ms": 0.14522600031341426,
+ "min_ms": 0.09780799882719293,
+ "max_ms": 0.15260500003932975,
+ "std_ms": 0.008374501325396673,
+ "throughput_ops_sec": 9615.467517407884,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ },
+ {
+ "name": "cache_mget_100_keys",
+ "category": "cache",
+ "iterations": 300,
+ "total_ms": 13.054071996521088,
+ "mean_ms": 0.04351357332173696,
+ "median_ms": 0.04144000013184268,
+ "p95_ms": 0.05062099990027491,
+ "p99_ms": 0.07507800000894349,
+ "min_ms": 0.04022000030090567,
+ "max_ms": 0.08977200013760012,
+ "std_ms": 0.0059871690475594725,
+ "throughput_ops_sec": 22981.33487236397,
+ "memory_delta_mb": 0.0,
+ "errors": 0,
+ "notes": ""
+ }
+ ],
+ "capacity": {}
+}