From 4f067bd1b443013bcfb46880078d22d1f54139cf Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Wed, 18 Feb 2026 23:47:24 +0100 Subject: [PATCH 1/9] removed kafka-init container (now autoinit) and removed 1 topic/different msg types - now 1-1 --- backend/app/core/providers.py | 59 ----- backend/app/db/docs/replay.py | 4 +- backend/app/dlq/manager.py | 23 +- backend/app/dlq/models.py | 31 ++- backend/app/domain/enums/__init__.py | 4 - backend/app/domain/enums/kafka.py | 64 ----- backend/app/domain/replay/models.py | 4 +- backend/app/events/core/producer.py | 4 +- backend/app/events/handlers.py | 213 ++++++++------- backend/app/infrastructure/kafka/__init__.py | 12 - backend/app/infrastructure/kafka/mappings.py | 134 ---------- backend/app/infrastructure/kafka/topics.py | 242 ++++-------------- backend/app/schemas_pydantic/replays.py | 6 +- backend/app/services/pod_monitor/config.py | 11 +- .../app/services/pod_monitor/event_mapper.py | 4 +- .../services/result_processor/processor.py | 6 +- backend/app/services/sse/redis_bus.py | 22 +- backend/scripts/create_topics.py | 112 -------- backend/tests/e2e/conftest.py | 12 +- backend/tests/e2e/dlq/test_dlq_manager.py | 9 +- .../unit/events/test_mappings_and_types.py | 12 - .../pod_monitor/test_config_and_init.py | 5 +- docker-compose.yaml | 46 ++-- docs/architecture/event-system-design.md | 46 ++-- docs/architecture/kafka-topic-architecture.md | 115 +++++---- docs/operations/deployment.md | 10 +- 26 files changed, 335 insertions(+), 875 deletions(-) delete mode 100644 backend/app/domain/enums/kafka.py delete mode 100644 backend/app/infrastructure/kafka/mappings.py delete mode 100755 backend/scripts/create_topics.py delete mode 100644 backend/tests/unit/events/test_mappings_and_types.py diff --git a/backend/app/core/providers.py b/backend/app/core/providers.py index f9b79ef3..aeb225eb 100644 --- a/backend/app/core/providers.py +++ b/backend/app/core/providers.py @@ -42,8 +42,6 @@ UserSettingsRepository, ) from app.dlq.manager import DLQManager -from app.dlq.models import RetryPolicy, RetryStrategy -from app.domain.enums import KafkaTopic from app.domain.saga import SagaConfig from app.events.core import UnifiedProducer from app.services.admin import AdminEventsService, AdminSettingsService, AdminUserService @@ -192,61 +190,6 @@ def get_idempotency_manager( return IdempotencyManager(IdempotencyConfig(), repo, logger, database_metrics) -def _default_retry_policy() -> RetryPolicy: - """Default retry policy for DLQ messages.""" - return RetryPolicy( - topic="default", - strategy=RetryStrategy.EXPONENTIAL_BACKOFF, - max_retries=4, - base_delay_seconds=60, - max_delay_seconds=1800, - retry_multiplier=2.5, - ) - - -def _default_retry_policies(prefix: str) -> dict[str, RetryPolicy]: - """Topic-specific retry policies for DLQ. - - Keys must match message.original_topic (full prefixed topic name). - """ - execution_events = f"{prefix}{KafkaTopic.EXECUTION_EVENTS}" - pod_events = f"{prefix}{KafkaTopic.POD_EVENTS}" - saga_commands = f"{prefix}{KafkaTopic.SAGA_COMMANDS}" - execution_results = f"{prefix}{KafkaTopic.EXECUTION_RESULTS}" - - return { - execution_events: RetryPolicy( - topic=execution_events, - strategy=RetryStrategy.EXPONENTIAL_BACKOFF, - max_retries=5, - base_delay_seconds=30, - max_delay_seconds=300, - retry_multiplier=2.0, - ), - pod_events: RetryPolicy( - topic=pod_events, - strategy=RetryStrategy.EXPONENTIAL_BACKOFF, - max_retries=3, - base_delay_seconds=60, - max_delay_seconds=600, - retry_multiplier=3.0, - ), - saga_commands: RetryPolicy( - topic=saga_commands, - strategy=RetryStrategy.EXPONENTIAL_BACKOFF, - max_retries=5, - base_delay_seconds=30, - max_delay_seconds=300, - retry_multiplier=2.0, - ), - execution_results: RetryPolicy( - topic=execution_results, - strategy=RetryStrategy.IMMEDIATE, - max_retries=3, - ), - } - - class DLQProvider(Provider): """Provides DLQManager without scheduling. Used by all containers except the DLQ worker.""" @@ -267,8 +210,6 @@ def get_dlq_manager( logger=logger, dlq_metrics=dlq_metrics, repository=repository, - default_retry_policy=_default_retry_policy(), - retry_policies=_default_retry_policies(settings.KAFKA_TOPIC_PREFIX), ) diff --git a/backend/app/db/docs/replay.py b/backend/app/db/docs/replay.py index 0b73fc3e..a53a1a93 100644 --- a/backend/app/db/docs/replay.py +++ b/backend/app/db/docs/replay.py @@ -6,7 +6,7 @@ from pydantic import BaseModel, ConfigDict, Field from pymongo import IndexModel -from app.domain.enums import EventType, KafkaTopic, ReplayStatus, ReplayTarget, ReplayType +from app.domain.enums import EventType, ReplayStatus, ReplayTarget, ReplayType from app.domain.replay import ReplayError, ReplayFilter @@ -25,7 +25,7 @@ class ReplayConfig(BaseModel): batch_size: int = Field(default=100, ge=1, le=1000) max_events: int | None = Field(default=None, ge=1) - target_topics: dict[EventType, KafkaTopic] | None = None + target_topics: dict[EventType, str] | None = None target_file_path: str | None = None skip_errors: bool = True diff --git a/backend/app/dlq/manager.py b/backend/app/dlq/manager.py index 1e23a70f..299b07c8 100644 --- a/backend/app/dlq/manager.py +++ b/backend/app/dlq/manager.py @@ -14,8 +14,9 @@ DLQRetryResult, RetryPolicy, RetryStrategy, + retry_policy_for, ) -from app.domain.enums import KafkaTopic +from app.domain.enums import EventType from app.domain.events import ( DLQMessageDiscardedEvent, DLQMessageReceivedEvent, @@ -40,9 +41,6 @@ def __init__( logger: structlog.stdlib.BoundLogger, dlq_metrics: DLQMetrics, repository: DLQRepository, - default_retry_policy: RetryPolicy, - retry_policies: dict[str, RetryPolicy], - dlq_topic: KafkaTopic = KafkaTopic.DEAD_LETTER_QUEUE, filters: list[Callable[[DLQMessage], bool]] | None = None, ): self.settings = settings @@ -50,9 +48,7 @@ def __init__( self.logger = logger self.metrics = dlq_metrics self.repository = repository - self.dlq_topic = dlq_topic - self.default_retry_policy = default_retry_policy - self._retry_policies = retry_policies + self._retry_overrides: dict[str, RetryPolicy] = {} self._filters: list[Callable[[DLQMessage], bool]] = filters if filters is not None else [ f for f in [ @@ -61,7 +57,7 @@ def __init__( ] if f is not None ] - self._dlq_events_topic = f"{settings.KAFKA_TOPIC_PREFIX}{KafkaTopic.DLQ_EVENTS}" + self._dlq_events_topic = f"{settings.KAFKA_TOPIC_PREFIX}{EventType.DLQ_MESSAGE_RECEIVED}" def _filter_test_events(self, message: DLQMessage) -> bool: return not message.event.event_id.startswith("test-") @@ -71,13 +67,18 @@ def _filter_old_messages(self, message: DLQMessage) -> bool: age_seconds = (datetime.now(timezone.utc) - message.failed_at).total_seconds() return age_seconds < (max_age_days * 24 * 3600) + def _resolve_retry_policy(self, message: DLQMessage) -> RetryPolicy: + if message.original_topic in self._retry_overrides: + return self._retry_overrides[message.original_topic] + return retry_policy_for(message.event.event_type) + async def process_monitoring_cycle(self) -> None: """Process due retries and update queue metrics. Called by APScheduler.""" await self.process_due_retries() await self.update_queue_metrics() async def handle_message(self, message: DLQMessage) -> None: - """Process a single DLQ message: filter → store → decide retry/discard.""" + """Process a single DLQ message: filter -> store -> decide retry/discard.""" for filter_func in self._filters: if not filter_func(message): self.logger.info("Message filtered out", event_id=message.event.event_id) @@ -105,7 +106,7 @@ async def handle_message(self, message: DLQMessage) -> None: topic=self._dlq_events_topic, ) - retry_policy = self._retry_policies.get(message.original_topic, self.default_retry_policy) + retry_policy = self._resolve_retry_policy(message) if not retry_policy.should_retry(message): await self.discard_message(message, "max_retries_exceeded") @@ -207,7 +208,7 @@ async def update_queue_metrics(self) -> None: self.metrics.update_dlq_queue_size(topic, count) def set_retry_policy(self, topic: str, policy: RetryPolicy) -> None: - self._retry_policies[topic] = policy + self._retry_overrides[topic] = policy async def retry_message_manually(self, event_id: str) -> bool: message = await self.repository.get_message_by_id(event_id) diff --git a/backend/app/dlq/models.py b/backend/app/dlq/models.py index 54f6db41..9bc613f9 100644 --- a/backend/app/dlq/models.py +++ b/backend/app/dlq/models.py @@ -75,7 +75,6 @@ class DLQMessageFilter: class RetryPolicy: """Retry policy configuration for DLQ messages.""" - topic: str strategy: RetryStrategy max_retries: int = 5 base_delay_seconds: float = 60.0 @@ -111,6 +110,36 @@ def get_next_retry_time(self, message: DLQMessage) -> datetime: return datetime.now(timezone.utc) + timedelta(seconds=delay) +AGGRESSIVE_RETRY = RetryPolicy( + strategy=RetryStrategy.EXPONENTIAL_BACKOFF, + max_retries=5, base_delay_seconds=30, max_delay_seconds=300, retry_multiplier=2.0, +) +CAUTIOUS_RETRY = RetryPolicy( + strategy=RetryStrategy.EXPONENTIAL_BACKOFF, + max_retries=3, base_delay_seconds=60, max_delay_seconds=600, retry_multiplier=3.0, +) +IMMEDIATE_RETRY = RetryPolicy(strategy=RetryStrategy.IMMEDIATE, max_retries=3) +DEFAULT_RETRY = RetryPolicy( + strategy=RetryStrategy.EXPONENTIAL_BACKOFF, + max_retries=4, base_delay_seconds=60, max_delay_seconds=1800, retry_multiplier=2.5, +) + + +def retry_policy_for(event_type: EventType) -> RetryPolicy: + """Determine retry policy from event type using category sets.""" + from app.infrastructure.kafka.topics import COMMAND_TYPES, EXECUTION_TYPES, POD_TYPES, RESULT_TYPES + + if event_type in EXECUTION_TYPES: + return AGGRESSIVE_RETRY + if event_type in POD_TYPES: + return CAUTIOUS_RETRY + if event_type in COMMAND_TYPES: + return AGGRESSIVE_RETRY + if event_type in RESULT_TYPES: + return IMMEDIATE_RETRY + return DEFAULT_RETRY + + @dataclass class DLQRetryResult: """Result of a single retry operation.""" diff --git a/backend/app/domain/enums/__init__.py b/backend/app/domain/enums/__init__.py index dac9a236..64ef713b 100644 --- a/backend/app/domain/enums/__init__.py +++ b/backend/app/domain/enums/__init__.py @@ -2,7 +2,6 @@ from app.domain.enums.common import Environment, ErrorType, ExportFormat, SortOrder, Theme from app.domain.enums.events import EventType from app.domain.enums.execution import CancelStatus, ExecutionStatus, QueuePriority -from app.domain.enums.kafka import GroupId, KafkaTopic from app.domain.enums.notification import ( NotificationChannel, NotificationSeverity, @@ -30,9 +29,6 @@ "CancelStatus", "ExecutionStatus", "QueuePriority", - # Kafka - "GroupId", - "KafkaTopic", # Notification "NotificationChannel", "NotificationSeverity", diff --git a/backend/app/domain/enums/kafka.py b/backend/app/domain/enums/kafka.py deleted file mode 100644 index fbb5d692..00000000 --- a/backend/app/domain/enums/kafka.py +++ /dev/null @@ -1,64 +0,0 @@ -from app.core.utils import StringEnum - - -class KafkaTopic(StringEnum): - """Kafka topic names used throughout the system.""" - - EXECUTION_EVENTS = "execution_events" - EXECUTION_COMPLETED = "execution_completed" - EXECUTION_FAILED = "execution_failed" - EXECUTION_TIMEOUT = "execution_timeout" - EXECUTION_REQUESTS = "execution_requests" - EXECUTION_COMMANDS = "execution_commands" - EXECUTION_TASKS = "execution_tasks" - - # Pod topics - POD_EVENTS = "pod_events" - POD_STATUS_UPDATES = "pod_status_updates" - POD_RESULTS = "pod_results" - - # Result topics - EXECUTION_RESULTS = "execution_results" - - # User topics - USER_EVENTS = "user_events" - USER_NOTIFICATIONS = "user_notifications" - USER_SETTINGS_EVENTS = "user_settings_events" - - # Script topics - SCRIPT_EVENTS = "script_events" - - # Security topics - SECURITY_EVENTS = "security_events" - - # Resource topics - RESOURCE_EVENTS = "resource_events" - - # Notification topics - NOTIFICATION_EVENTS = "notification_events" - - # System topics - SYSTEM_EVENTS = "system_events" - - # Saga topics - SAGA_EVENTS = "saga_events" - SAGA_COMMANDS = "saga_commands" - - # Infrastructure topics - DEAD_LETTER_QUEUE = "dead_letter_queue" - DLQ_EVENTS = "dlq_events" - WEBSOCKET_EVENTS = "websocket_events" - - -class GroupId(StringEnum): - """Kafka consumer group IDs.""" - - EXECUTION_COORDINATOR = "execution-coordinator" - K8S_WORKER = "k8s-worker" - POD_MONITOR = "pod-monitor" - RESULT_PROCESSOR = "result-processor" - SAGA_ORCHESTRATOR = "saga-orchestrator" - EVENT_STORE_CONSUMER = "event-store-consumer" - WEBSOCKET_GATEWAY = "websocket-gateway" - NOTIFICATION_SERVICE = "notification-service" - DLQ_MANAGER = "dlq-manager" diff --git a/backend/app/domain/replay/models.py b/backend/app/domain/replay/models.py index 712c698e..b085fb39 100644 --- a/backend/app/domain/replay/models.py +++ b/backend/app/domain/replay/models.py @@ -3,7 +3,7 @@ from typing import Any from uuid import uuid4 -from app.domain.enums import EventType, KafkaTopic, ReplayStatus, ReplayTarget, ReplayType +from app.domain.enums import EventType, ReplayStatus, ReplayTarget, ReplayType @dataclass @@ -126,7 +126,7 @@ class ReplayConfig: batch_size: int = 100 max_events: int | None = None - target_topics: dict[EventType, KafkaTopic] | None = None + target_topics: dict[EventType, str] | None = None target_file_path: str | None = None skip_errors: bool = True diff --git a/backend/app/events/core/producer.py b/backend/app/events/core/producer.py index aab668bc..dfb4b43a 100644 --- a/backend/app/events/core/producer.py +++ b/backend/app/events/core/producer.py @@ -4,7 +4,6 @@ from app.core.metrics import EventMetrics from app.db.repositories import EventRepository from app.domain.events import DomainEvent -from app.infrastructure.kafka.mappings import EVENT_TYPE_TO_TOPIC from app.settings import Settings @@ -32,7 +31,7 @@ def __init__( async def produce(self, event_to_produce: DomainEvent, key: str) -> None: """Persist event to MongoDB, then publish to Kafka.""" await self._event_repository.store_event(event_to_produce) - topic = f"{self._topic_prefix}{EVENT_TYPE_TO_TOPIC[event_to_produce.event_type]}" + topic = f"{self._topic_prefix}{event_to_produce.event_type}" try: await self._broker.publish( message=event_to_produce, @@ -47,4 +46,3 @@ async def produce(self, event_to_produce: DomainEvent, key: str) -> None: self._event_metrics.record_kafka_production_error(topic=topic, error_type=type(e).__name__) self.logger.error(f"Failed to produce message: {e}") raise - diff --git a/backend/app/events/handlers.py b/backend/app/events/handlers.py index 1b22febc..c29da363 100644 --- a/backend/app/events/handlers.py +++ b/backend/app/events/handlers.py @@ -1,17 +1,15 @@ import asyncio from collections.abc import Awaitable, Callable from datetime import datetime, timezone -from typing import Any import structlog from dishka.integrations.faststream import FromDishka from faststream import AckPolicy from faststream.kafka import KafkaBroker, KafkaMessage -from faststream.message import decode_message from app.dlq.manager import DLQManager from app.dlq.models import DLQMessage -from app.domain.enums import EventType, GroupId, KafkaTopic +from app.domain.enums import EventType from app.domain.events import ( CreatePodCommandEvent, DeletePodCommandEvent, @@ -23,7 +21,6 @@ ExecutionTimeoutEvent, ) from app.domain.idempotency import KeyStrategy -from app.infrastructure.kafka.mappings import CONSUMER_GROUP_SUBSCRIPTIONS from app.services.coordinator import ExecutionCoordinator from app.services.idempotency import IdempotencyManager from app.services.k8s_worker import KubernetesWorker @@ -61,26 +58,14 @@ async def with_idempotency( # --8<-- [end:with_idempotency] -def _topics(settings: Settings, group_id: GroupId) -> list[str]: - return [ - f"{settings.KAFKA_TOPIC_PREFIX}{t}" - for t in CONSUMER_GROUP_SUBSCRIPTIONS[group_id] - ] - - -def _event_type_filter(msg: Any, expected: str) -> bool: - """Body-based event_type filter for @sub(filter=...) lambdas.""" - return decode_message(msg).get("event_type") == expected # type: ignore[union-attr] - - def register_coordinator_subscriber(broker: KafkaBroker, settings: Settings) -> None: - sub = broker.subscriber( - *_topics(settings, GroupId.EXECUTION_COORDINATOR), - group_id=GroupId.EXECUTION_COORDINATOR, + prefix = settings.KAFKA_TOPIC_PREFIX + + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_REQUESTED}", + group_id="execution-coordinator", ack_policy=AckPolicy.ACK, ) - - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_REQUESTED)) async def on_execution_requested( body: ExecutionRequestedEvent, coordinator: FromDishka[ExecutionCoordinator], @@ -91,7 +76,11 @@ async def on_execution_requested( body, coordinator.handle_execution_requested, idem, KeyStrategy.EVENT_BASED, 7200, logger, ) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_COMPLETED)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_COMPLETED}", + group_id="execution-coordinator", + ack_policy=AckPolicy.ACK, + ) async def on_execution_completed( body: ExecutionCompletedEvent, coordinator: FromDishka[ExecutionCoordinator], @@ -102,7 +91,11 @@ async def on_execution_completed( body, coordinator.handle_execution_completed, idem, KeyStrategy.EVENT_BASED, 7200, logger, ) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_FAILED)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_FAILED}", + group_id="execution-coordinator", + ack_policy=AckPolicy.ACK, + ) async def on_execution_failed( body: ExecutionFailedEvent, coordinator: FromDishka[ExecutionCoordinator], @@ -113,7 +106,11 @@ async def on_execution_failed( body, coordinator.handle_execution_failed, idem, KeyStrategy.EVENT_BASED, 7200, logger, ) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_CANCELLED)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_CANCELLED}", + group_id="execution-coordinator", + ack_policy=AckPolicy.ACK, + ) async def on_execution_cancelled( body: ExecutionCancelledEvent, coordinator: FromDishka[ExecutionCoordinator], @@ -124,19 +121,15 @@ async def on_execution_cancelled( body, coordinator.handle_execution_cancelled, idem, KeyStrategy.EVENT_BASED, 7200, logger, ) - @sub - async def on_unhandled(body: DomainEvent) -> None: - pass - def register_k8s_worker_subscriber(broker: KafkaBroker, settings: Settings) -> None: - sub = broker.subscriber( - *_topics(settings, GroupId.K8S_WORKER), - group_id=GroupId.K8S_WORKER, + prefix = settings.KAFKA_TOPIC_PREFIX + + @broker.subscriber( + f"{prefix}{EventType.CREATE_POD_COMMAND}", + group_id="k8s-worker", ack_policy=AckPolicy.ACK, ) - - @sub(filter=lambda msg: _event_type_filter(msg, EventType.CREATE_POD_COMMAND)) async def on_create_pod( body: CreatePodCommandEvent, worker: FromDishka[KubernetesWorker], @@ -147,7 +140,11 @@ async def on_create_pod( body, worker.handle_create_pod_command, idem, KeyStrategy.CONTENT_HASH, 3600, logger, ) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.DELETE_POD_COMMAND)) + @broker.subscriber( + f"{prefix}{EventType.DELETE_POD_COMMAND}", + group_id="k8s-worker", + ack_policy=AckPolicy.ACK, + ) async def on_delete_pod( body: DeletePodCommandEvent, worker: FromDishka[KubernetesWorker], @@ -158,21 +155,17 @@ async def on_delete_pod( body, worker.handle_delete_pod_command, idem, KeyStrategy.CONTENT_HASH, 3600, logger, ) - @sub - async def on_unhandled(body: DomainEvent) -> None: - pass - def register_result_processor_subscriber(broker: KafkaBroker, settings: Settings) -> None: - sub = broker.subscriber( - *_topics(settings, GroupId.RESULT_PROCESSOR), - group_id=GroupId.RESULT_PROCESSOR, + prefix = settings.KAFKA_TOPIC_PREFIX + + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_COMPLETED}", + group_id="result-processor", ack_policy=AckPolicy.ACK, max_poll_records=1, auto_offset_reset="earliest", ) - - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_COMPLETED)) async def on_execution_completed( body: ExecutionCompletedEvent, processor: FromDishka[ResultProcessor], @@ -183,7 +176,13 @@ async def on_execution_completed( body, processor.handle_execution_completed, idem, KeyStrategy.CONTENT_HASH, 7200, logger, ) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_FAILED)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_FAILED}", + group_id="result-processor", + ack_policy=AckPolicy.ACK, + max_poll_records=1, + auto_offset_reset="earliest", + ) async def on_execution_failed( body: ExecutionFailedEvent, processor: FromDishka[ResultProcessor], @@ -194,7 +193,13 @@ async def on_execution_failed( body, processor.handle_execution_failed, idem, KeyStrategy.CONTENT_HASH, 7200, logger, ) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_TIMEOUT)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_TIMEOUT}", + group_id="result-processor", + ack_policy=AckPolicy.ACK, + max_poll_records=1, + auto_offset_reset="earliest", + ) async def on_execution_timeout( body: ExecutionTimeoutEvent, processor: FromDishka[ResultProcessor], @@ -205,104 +210,139 @@ async def on_execution_timeout( body, processor.handle_execution_timeout, idem, KeyStrategy.CONTENT_HASH, 7200, logger, ) - @sub - async def on_unhandled(body: DomainEvent) -> None: - pass - def register_saga_subscriber(broker: KafkaBroker, settings: Settings) -> None: - sub = broker.subscriber( - *_topics(settings, GroupId.SAGA_ORCHESTRATOR), - group_id=GroupId.SAGA_ORCHESTRATOR, - ack_policy=AckPolicy.ACK, - ) + prefix = settings.KAFKA_TOPIC_PREFIX # No with_idempotency — the saga state machine provides its own # deduplication via status checks before each transition. - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_REQUESTED)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_REQUESTED}", + group_id="saga-orchestrator", + ack_policy=AckPolicy.ACK, + ) async def on_execution_requested( body: ExecutionRequestedEvent, orchestrator: FromDishka[SagaOrchestrator], ) -> None: await orchestrator.handle_execution_requested(body) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_COMPLETED)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_COMPLETED}", + group_id="saga-orchestrator", + ack_policy=AckPolicy.ACK, + ) async def on_execution_completed( body: ExecutionCompletedEvent, orchestrator: FromDishka[SagaOrchestrator], ) -> None: await orchestrator.handle_execution_completed(body) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_FAILED)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_FAILED}", + group_id="saga-orchestrator", + ack_policy=AckPolicy.ACK, + ) async def on_execution_failed( body: ExecutionFailedEvent, orchestrator: FromDishka[SagaOrchestrator], ) -> None: await orchestrator.handle_execution_failed(body) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_TIMEOUT)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_TIMEOUT}", + group_id="saga-orchestrator", + ack_policy=AckPolicy.ACK, + ) async def on_execution_timeout( body: ExecutionTimeoutEvent, orchestrator: FromDishka[SagaOrchestrator], ) -> None: await orchestrator.handle_execution_timeout(body) - @sub - async def on_unhandled(body: DomainEvent) -> None: - pass +_SSE_EVENT_TYPES = [ + EventType.EXECUTION_REQUESTED, + EventType.EXECUTION_QUEUED, + EventType.EXECUTION_STARTED, + EventType.EXECUTION_RUNNING, + EventType.EXECUTION_COMPLETED, + EventType.EXECUTION_FAILED, + EventType.EXECUTION_TIMEOUT, + EventType.EXECUTION_CANCELLED, + EventType.RESULT_STORED, + EventType.POD_CREATED, + EventType.POD_SCHEDULED, + EventType.POD_RUNNING, + EventType.POD_SUCCEEDED, + EventType.POD_FAILED, + EventType.POD_TERMINATED, + EventType.POD_DELETED, +] def register_sse_subscriber(broker: KafkaBroker, settings: Settings) -> None: - @broker.subscriber( - *_topics(settings, GroupId.WEBSOCKET_GATEWAY), - group_id="sse-bridge-pool", - ack_policy=AckPolicy.ACK_FIRST, - auto_offset_reset="latest", - max_workers=settings.SSE_CONSUMER_POOL_SIZE, - ) - async def on_sse_event( - body: DomainEvent, - sse_bus: FromDishka[SSERedisBus], - ) -> None: - if body.event_type in SSERedisBus.SSE_ROUTED_EVENTS: + prefix = settings.KAFKA_TOPIC_PREFIX + + for et in _SSE_EVENT_TYPES: + topic = f"{prefix}{et}" + + @broker.subscriber( + topic, + group_id="sse-bridge-pool", + ack_policy=AckPolicy.ACK_FIRST, + auto_offset_reset="latest", + max_workers=settings.SSE_CONSUMER_POOL_SIZE, + ) + async def on_sse_event( + body: DomainEvent, + sse_bus: FromDishka[SSERedisBus], + ) -> None: await sse_bus.route_domain_event(body) def register_notification_subscriber(broker: KafkaBroker, settings: Settings) -> None: - sub = broker.subscriber( - *_topics(settings, GroupId.NOTIFICATION_SERVICE), - group_id=GroupId.NOTIFICATION_SERVICE, + prefix = settings.KAFKA_TOPIC_PREFIX + + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_COMPLETED}", + group_id="notification-service", ack_policy=AckPolicy.ACK, max_poll_records=10, auto_offset_reset="latest", ) - - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_COMPLETED)) async def on_execution_completed( body: ExecutionCompletedEvent, service: FromDishka[NotificationService], ) -> None: await service.handle_execution_completed(body) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_FAILED)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_FAILED}", + group_id="notification-service", + ack_policy=AckPolicy.ACK, + max_poll_records=10, + auto_offset_reset="latest", + ) async def on_execution_failed( body: ExecutionFailedEvent, service: FromDishka[NotificationService], ) -> None: await service.handle_execution_failed(body) - @sub(filter=lambda msg: _event_type_filter(msg, EventType.EXECUTION_TIMEOUT)) + @broker.subscriber( + f"{prefix}{EventType.EXECUTION_TIMEOUT}", + group_id="notification-service", + ack_policy=AckPolicy.ACK, + max_poll_records=10, + auto_offset_reset="latest", + ) async def on_execution_timeout( body: ExecutionTimeoutEvent, service: FromDishka[NotificationService], ) -> None: await service.handle_execution_timeout(body) - @sub - async def on_unhandled(body: DomainEvent) -> None: - pass - def register_dlq_subscriber(broker: KafkaBroker, settings: Settings) -> None: """Register a DLQ subscriber that consumes dead-letter messages. @@ -310,11 +350,10 @@ def register_dlq_subscriber(broker: KafkaBroker, settings: Settings) -> None: DLQ messages are JSON-encoded DLQMessage models (Pydantic serialization via FastStream). All DLQ metadata is in the message body — no Kafka headers needed. """ - topic_name = f"{settings.KAFKA_TOPIC_PREFIX}{KafkaTopic.DEAD_LETTER_QUEUE}" @broker.subscriber( - topic_name, - group_id=GroupId.DLQ_MANAGER, + f"{settings.KAFKA_TOPIC_PREFIX}dead_letter_queue", + group_id="dlq-manager", ack_policy=AckPolicy.ACK, auto_offset_reset="earliest", ) diff --git a/backend/app/infrastructure/kafka/__init__.py b/backend/app/infrastructure/kafka/__init__.py index fae49311..e69de29b 100644 --- a/backend/app/infrastructure/kafka/__init__.py +++ b/backend/app/infrastructure/kafka/__init__.py @@ -1,12 +0,0 @@ -from app.domain.events import DomainEvent, EventMetadata -from app.infrastructure.kafka.mappings import get_event_class_for_type, get_topic_for_event -from app.infrastructure.kafka.topics import get_all_topics, get_topic_configs - -__all__ = [ - "DomainEvent", - "EventMetadata", - "get_all_topics", - "get_topic_configs", - "get_event_class_for_type", - "get_topic_for_event", -] diff --git a/backend/app/infrastructure/kafka/mappings.py b/backend/app/infrastructure/kafka/mappings.py deleted file mode 100644 index dc339728..00000000 --- a/backend/app/infrastructure/kafka/mappings.py +++ /dev/null @@ -1,134 +0,0 @@ -from functools import lru_cache -from typing import get_args, get_origin - -from app.domain.enums import EventType, GroupId, KafkaTopic - -# EventType -> KafkaTopic routing -EVENT_TYPE_TO_TOPIC: dict[EventType, KafkaTopic] = { - # Execution events - EventType.EXECUTION_REQUESTED: KafkaTopic.EXECUTION_EVENTS, - EventType.EXECUTION_ACCEPTED: KafkaTopic.EXECUTION_EVENTS, - EventType.EXECUTION_QUEUED: KafkaTopic.EXECUTION_EVENTS, - EventType.EXECUTION_STARTED: KafkaTopic.EXECUTION_EVENTS, - EventType.EXECUTION_RUNNING: KafkaTopic.EXECUTION_EVENTS, - EventType.EXECUTION_COMPLETED: KafkaTopic.EXECUTION_EVENTS, - EventType.EXECUTION_FAILED: KafkaTopic.EXECUTION_EVENTS, - EventType.EXECUTION_TIMEOUT: KafkaTopic.EXECUTION_EVENTS, - EventType.EXECUTION_CANCELLED: KafkaTopic.EXECUTION_EVENTS, - # Pod events - EventType.POD_CREATED: KafkaTopic.POD_EVENTS, - EventType.POD_SCHEDULED: KafkaTopic.POD_EVENTS, - EventType.POD_RUNNING: KafkaTopic.POD_EVENTS, - EventType.POD_SUCCEEDED: KafkaTopic.POD_EVENTS, - EventType.POD_FAILED: KafkaTopic.POD_EVENTS, - EventType.POD_TERMINATED: KafkaTopic.POD_EVENTS, - EventType.POD_DELETED: KafkaTopic.POD_EVENTS, - # Result events - EventType.RESULT_STORED: KafkaTopic.EXECUTION_RESULTS, - EventType.RESULT_FAILED: KafkaTopic.EXECUTION_RESULTS, - # User events - EventType.USER_REGISTERED: KafkaTopic.USER_EVENTS, - EventType.USER_LOGIN: KafkaTopic.USER_EVENTS, - EventType.USER_LOGGED_IN: KafkaTopic.USER_EVENTS, - EventType.USER_LOGGED_OUT: KafkaTopic.USER_EVENTS, - EventType.USER_UPDATED: KafkaTopic.USER_EVENTS, - EventType.USER_DELETED: KafkaTopic.USER_EVENTS, - EventType.USER_SETTINGS_UPDATED: KafkaTopic.USER_SETTINGS_EVENTS, - # Notification events - EventType.NOTIFICATION_CREATED: KafkaTopic.NOTIFICATION_EVENTS, - EventType.NOTIFICATION_SENT: KafkaTopic.NOTIFICATION_EVENTS, - EventType.NOTIFICATION_DELIVERED: KafkaTopic.NOTIFICATION_EVENTS, - EventType.NOTIFICATION_FAILED: KafkaTopic.NOTIFICATION_EVENTS, - EventType.NOTIFICATION_READ: KafkaTopic.NOTIFICATION_EVENTS, - EventType.NOTIFICATION_CLICKED: KafkaTopic.NOTIFICATION_EVENTS, - EventType.NOTIFICATION_PREFERENCES_UPDATED: KafkaTopic.NOTIFICATION_EVENTS, - # Script events - EventType.SCRIPT_SAVED: KafkaTopic.SCRIPT_EVENTS, - EventType.SCRIPT_DELETED: KafkaTopic.SCRIPT_EVENTS, - EventType.SCRIPT_SHARED: KafkaTopic.SCRIPT_EVENTS, - # Security events - EventType.SECURITY_VIOLATION: KafkaTopic.SECURITY_EVENTS, - EventType.RATE_LIMIT_EXCEEDED: KafkaTopic.SECURITY_EVENTS, - EventType.AUTH_FAILED: KafkaTopic.SECURITY_EVENTS, - # Resource events - EventType.RESOURCE_LIMIT_EXCEEDED: KafkaTopic.RESOURCE_EVENTS, - EventType.QUOTA_EXCEEDED: KafkaTopic.RESOURCE_EVENTS, - # System events - EventType.SYSTEM_ERROR: KafkaTopic.SYSTEM_EVENTS, - EventType.SERVICE_UNHEALTHY: KafkaTopic.SYSTEM_EVENTS, - EventType.SERVICE_RECOVERED: KafkaTopic.SYSTEM_EVENTS, - # Saga events - EventType.SAGA_STARTED: KafkaTopic.SAGA_EVENTS, - EventType.SAGA_COMPLETED: KafkaTopic.SAGA_EVENTS, - EventType.SAGA_FAILED: KafkaTopic.SAGA_EVENTS, - EventType.SAGA_CANCELLED: KafkaTopic.SAGA_EVENTS, - EventType.SAGA_COMPENSATING: KafkaTopic.SAGA_EVENTS, - EventType.SAGA_COMPENSATED: KafkaTopic.SAGA_EVENTS, - # Saga command events - EventType.CREATE_POD_COMMAND: KafkaTopic.SAGA_COMMANDS, - EventType.DELETE_POD_COMMAND: KafkaTopic.SAGA_COMMANDS, - EventType.ALLOCATE_RESOURCES_COMMAND: KafkaTopic.SAGA_COMMANDS, - EventType.RELEASE_RESOURCES_COMMAND: KafkaTopic.SAGA_COMMANDS, - # DLQ events - EventType.DLQ_MESSAGE_RECEIVED: KafkaTopic.DLQ_EVENTS, - EventType.DLQ_MESSAGE_RETRIED: KafkaTopic.DLQ_EVENTS, - EventType.DLQ_MESSAGE_DISCARDED: KafkaTopic.DLQ_EVENTS, -} - - -@lru_cache(maxsize=1) -def _get_event_type_to_class() -> dict[EventType, type]: - """Build mapping from EventType to event class using DomainEvent union.""" - from app.domain.events.typed import DomainEvent - - union_type = get_args(DomainEvent)[0] - classes = list(get_args(union_type)) if get_origin(union_type) is not None else [union_type] - return {cls.model_fields["event_type"].default: cls for cls in classes} - - -@lru_cache(maxsize=128) -def get_event_class_for_type(event_type: EventType) -> type | None: - """Get the event class for a given event type.""" - return _get_event_type_to_class().get(event_type) - - -@lru_cache(maxsize=128) -def get_topic_for_event(event_type: EventType) -> KafkaTopic: - """Get the Kafka topic for a given event type.""" - return EVENT_TYPE_TO_TOPIC.get(event_type, KafkaTopic.SYSTEM_EVENTS) - - - -CONSUMER_GROUP_SUBSCRIPTIONS: dict[GroupId, set[KafkaTopic]] = { - GroupId.EXECUTION_COORDINATOR: { - KafkaTopic.EXECUTION_EVENTS, - KafkaTopic.EXECUTION_RESULTS, - }, - GroupId.K8S_WORKER: { - KafkaTopic.SAGA_COMMANDS, - }, - GroupId.POD_MONITOR: { - KafkaTopic.POD_EVENTS, - KafkaTopic.POD_STATUS_UPDATES, - }, - GroupId.RESULT_PROCESSOR: { - KafkaTopic.EXECUTION_EVENTS, - }, - GroupId.SAGA_ORCHESTRATOR: { - KafkaTopic.EXECUTION_EVENTS, - KafkaTopic.SAGA_COMMANDS, - }, - GroupId.WEBSOCKET_GATEWAY: { - KafkaTopic.EXECUTION_EVENTS, - KafkaTopic.EXECUTION_RESULTS, - KafkaTopic.POD_EVENTS, - KafkaTopic.POD_STATUS_UPDATES, - }, - GroupId.NOTIFICATION_SERVICE: { - KafkaTopic.NOTIFICATION_EVENTS, - KafkaTopic.EXECUTION_EVENTS, - }, - GroupId.DLQ_MANAGER: { - KafkaTopic.DEAD_LETTER_QUEUE, - }, -} diff --git a/backend/app/infrastructure/kafka/topics.py b/backend/app/infrastructure/kafka/topics.py index a664bb19..8f3da192 100644 --- a/backend/app/infrastructure/kafka/topics.py +++ b/backend/app/infrastructure/kafka/topics.py @@ -1,201 +1,51 @@ -from typing import Any +from app.domain.enums import EventType -from app.domain.enums import KafkaTopic +EXECUTION_TYPES: set[EventType] = { + EventType.EXECUTION_REQUESTED, + EventType.EXECUTION_ACCEPTED, + EventType.EXECUTION_QUEUED, + EventType.EXECUTION_STARTED, + EventType.EXECUTION_RUNNING, + EventType.EXECUTION_COMPLETED, + EventType.EXECUTION_FAILED, + EventType.EXECUTION_TIMEOUT, + EventType.EXECUTION_CANCELLED, +} +POD_TYPES: set[EventType] = { + EventType.POD_CREATED, + EventType.POD_SCHEDULED, + EventType.POD_RUNNING, + EventType.POD_SUCCEEDED, + EventType.POD_FAILED, + EventType.POD_TERMINATED, + EventType.POD_DELETED, +} -def get_all_topics() -> set[KafkaTopic]: - """Get all Kafka topics.""" - return set(KafkaTopic) +COMMAND_TYPES: set[EventType] = { + EventType.CREATE_POD_COMMAND, + EventType.DELETE_POD_COMMAND, + EventType.ALLOCATE_RESOURCES_COMMAND, + EventType.RELEASE_RESOURCES_COMMAND, +} +RESULT_TYPES: set[EventType] = { + EventType.RESULT_STORED, + EventType.RESULT_FAILED, +} -def get_topic_configs() -> dict[KafkaTopic, dict[str, Any]]: - """Get configuration for all Kafka topics.""" - return { - # High-volume execution topics - KafkaTopic.EXECUTION_EVENTS: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - KafkaTopic.EXECUTION_COMPLETED: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - KafkaTopic.EXECUTION_FAILED: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - KafkaTopic.EXECUTION_TIMEOUT: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - KafkaTopic.EXECUTION_REQUESTS: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - KafkaTopic.EXECUTION_COMMANDS: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "86400000", # 1 day - "compression.type": "gzip", - }, - }, - KafkaTopic.EXECUTION_TASKS: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "86400000", # 1 day - "compression.type": "gzip", - }, - }, - # Pod lifecycle topics - KafkaTopic.POD_EVENTS: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "86400000", # 1 day - "compression.type": "gzip", - }, - }, - KafkaTopic.POD_STATUS_UPDATES: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "86400000", # 1 day - "compression.type": "gzip", - }, - }, - KafkaTopic.POD_RESULTS: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - # Result topics - KafkaTopic.EXECUTION_RESULTS: { - "num_partitions": 10, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - # User topics - KafkaTopic.USER_EVENTS: { - "num_partitions": 5, - "replication_factor": 1, - "config": { - "retention.ms": "2592000000", # 30 days - "compression.type": "gzip", - }, - }, - KafkaTopic.USER_NOTIFICATIONS: { - "num_partitions": 5, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - KafkaTopic.USER_SETTINGS_EVENTS: { - "num_partitions": 3, - "replication_factor": 1, - "config": { - "retention.ms": "2592000000", # 30 days - "compression.type": "gzip", - }, - }, - # Script topics - KafkaTopic.SCRIPT_EVENTS: { - "num_partitions": 3, - "replication_factor": 1, - "config": { - "retention.ms": "2592000000", # 30 days - "compression.type": "gzip", - }, - }, - # Security topics - KafkaTopic.SECURITY_EVENTS: { - "num_partitions": 5, - "replication_factor": 1, - "config": { - "retention.ms": "2592000000", # 30 days - "compression.type": "gzip", - }, - }, - # Resource topics - KafkaTopic.RESOURCE_EVENTS: { - "num_partitions": 5, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - # Notification topics - KafkaTopic.NOTIFICATION_EVENTS: { - "num_partitions": 5, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - # System topics - KafkaTopic.SYSTEM_EVENTS: { - "num_partitions": 5, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - # Saga topics - KafkaTopic.SAGA_EVENTS: { - "num_partitions": 5, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - # Infrastructure topics - KafkaTopic.DEAD_LETTER_QUEUE: { - "num_partitions": 3, - "replication_factor": 1, - "config": { - "retention.ms": "1209600000", # 14 days - "compression.type": "gzip", - }, - }, - KafkaTopic.WEBSOCKET_EVENTS: { - "num_partitions": 5, - "replication_factor": 1, - "config": { - "retention.ms": "86400000", # 1 day - "compression.type": "gzip", - }, - }, - } +SECURITY_TYPES: set[EventType] = { + EventType.SECURITY_VIOLATION, + EventType.RATE_LIMIT_EXCEEDED, + EventType.AUTH_FAILED, +} + +USER_TYPES: set[EventType] = { + EventType.USER_REGISTERED, + EventType.USER_LOGIN, + EventType.USER_LOGGED_IN, + EventType.USER_LOGGED_OUT, + EventType.USER_UPDATED, + EventType.USER_DELETED, + EventType.USER_SETTINGS_UPDATED, +} diff --git a/backend/app/schemas_pydantic/replays.py b/backend/app/schemas_pydantic/replays.py index 8d2849b6..fb03a467 100644 --- a/backend/app/schemas_pydantic/replays.py +++ b/backend/app/schemas_pydantic/replays.py @@ -3,7 +3,7 @@ from pydantic import BaseModel, ConfigDict, Field, computed_field -from app.domain.enums import EventType, KafkaTopic, ReplayStatus, ReplayTarget, ReplayType +from app.domain.enums import EventType, ReplayStatus, ReplayTarget, ReplayType from app.domain.replay.models import ReplayError, ReplayFilter @@ -33,7 +33,7 @@ class ReplayConfigSchema(BaseModel): batch_size: int = Field(default=100, ge=1, le=1000) max_events: int | None = Field(default=None, ge=1) - target_topics: dict[EventType, KafkaTopic] | None = None + target_topics: dict[EventType, str] | None = None target_file_path: str | None = None skip_errors: bool = True @@ -76,7 +76,7 @@ class ReplayRequest(BaseModel): max_events: int | None = Field(default=None, ge=1) skip_errors: bool = True target_file_path: str | None = None - target_topics: dict[EventType, KafkaTopic] | None = None + target_topics: dict[EventType, str] | None = None retry_failed: bool = False retry_attempts: int = Field(default=3, ge=1, le=10) enable_progress_tracking: bool = True diff --git a/backend/app/services/pod_monitor/config.py b/backend/app/services/pod_monitor/config.py index 97b12aa6..e1a757a3 100644 --- a/backend/app/services/pod_monitor/config.py +++ b/backend/app/services/pod_monitor/config.py @@ -1,7 +1,6 @@ from dataclasses import dataclass, field -from app.domain.enums import EventType, KafkaTopic -from app.infrastructure.kafka import get_topic_for_event +from app.domain.enums import EventType from app.services.pod_monitor.event_mapper import PodPhase @@ -10,10 +9,10 @@ class PodMonitorConfig: """Configuration for PodMonitor service""" # Kafka settings - pod_events_topic: KafkaTopic = get_topic_for_event(EventType.POD_CREATED) - execution_events_topic: KafkaTopic = get_topic_for_event(EventType.EXECUTION_REQUESTED) - execution_completed_topic: KafkaTopic = get_topic_for_event(EventType.EXECUTION_COMPLETED) - execution_failed_topic: KafkaTopic = get_topic_for_event(EventType.EXECUTION_FAILED) + pod_events_topic: str = EventType.POD_CREATED + execution_events_topic: str = EventType.EXECUTION_REQUESTED + execution_completed_topic: str = EventType.EXECUTION_COMPLETED + execution_failed_topic: str = EventType.EXECUTION_FAILED # Kubernetes settings namespace: str = "integr8scode" diff --git a/backend/app/services/pod_monitor/event_mapper.py b/backend/app/services/pod_monitor/event_mapper.py index e8e73943..439d35c5 100644 --- a/backend/app/services/pod_monitor/event_mapper.py +++ b/backend/app/services/pod_monitor/event_mapper.py @@ -7,7 +7,7 @@ from kubernetes_asyncio import client as k8s_client from app.core.utils import StringEnum -from app.domain.enums import ExecutionErrorType, GroupId +from app.domain.enums import ExecutionErrorType from app.domain.events import ( ContainerStatusInfo, DomainEvent, @@ -183,7 +183,7 @@ def _create_metadata(self, pod: k8s_client.V1Pod) -> EventMetadata: md = EventMetadata( user_id=labels.get("user-id", str(uuid4())), - service_name=GroupId.POD_MONITOR, + service_name="pod-monitor", service_version="1.0.0", ) self.logger.info(f"POD-EVENT: metadata user_id={md.user_id} name={pod.metadata.name}") diff --git a/backend/app/services/result_processor/processor.py b/backend/app/services/result_processor/processor.py index 69f33ce7..915e5411 100644 --- a/backend/app/services/result_processor/processor.py +++ b/backend/app/services/result_processor/processor.py @@ -2,7 +2,7 @@ from app.core.metrics import ExecutionMetrics from app.db.repositories import ExecutionRepository -from app.domain.enums import ExecutionErrorType, ExecutionStatus, GroupId, StorageType +from app.domain.enums import ExecutionErrorType, ExecutionStatus, StorageType from app.domain.events import ( DomainEvent, EventMetadata, @@ -144,7 +144,7 @@ async def _publish_result_stored(self, result: ExecutionResultDomain, user_id: s size_bytes=size_bytes, storage_type=StorageType.DATABASE, metadata=EventMetadata( - service_name=GroupId.RESULT_PROCESSOR, + service_name="result-processor", service_version="1.0.0", user_id=user_id, ), @@ -159,7 +159,7 @@ async def _publish_result_failed( execution_id=execution_id, error=error_message, metadata=EventMetadata( - service_name=GroupId.RESULT_PROCESSOR, + service_name="result-processor", service_version="1.0.0", user_id=user_id, ), diff --git a/backend/app/services/sse/redis_bus.py b/backend/app/services/sse/redis_bus.py index 50998a95..7ffb5a6b 100644 --- a/backend/app/services/sse/redis_bus.py +++ b/backend/app/services/sse/redis_bus.py @@ -1,12 +1,11 @@ from __future__ import annotations -from typing import Any, ClassVar, TypeVar +from typing import Any, TypeVar import redis.asyncio as redis import structlog from pydantic import TypeAdapter -from app.domain.enums import EventType from app.domain.events import DomainEvent from app.domain.sse import RedisNotificationMessage, RedisSSEMessage @@ -50,25 +49,6 @@ async def close(self) -> None: class SSERedisBus: """Redis-backed pub/sub bus for SSE event fan-out across workers.""" - SSE_ROUTED_EVENTS: ClassVar[list[EventType]] = [ - EventType.EXECUTION_REQUESTED, - EventType.EXECUTION_QUEUED, - EventType.EXECUTION_STARTED, - EventType.EXECUTION_RUNNING, - EventType.EXECUTION_COMPLETED, - EventType.EXECUTION_FAILED, - EventType.EXECUTION_TIMEOUT, - EventType.EXECUTION_CANCELLED, - EventType.RESULT_STORED, - EventType.POD_CREATED, - EventType.POD_SCHEDULED, - EventType.POD_RUNNING, - EventType.POD_SUCCEEDED, - EventType.POD_FAILED, - EventType.POD_TERMINATED, - EventType.POD_DELETED, - ] - def __init__( self, redis_client: redis.Redis, diff --git a/backend/scripts/create_topics.py b/backend/scripts/create_topics.py deleted file mode 100755 index 75477ac9..00000000 --- a/backend/scripts/create_topics.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python3 -""" -Create all required Kafka topics for the Integr8sCode backend. -""" - -import asyncio -import sys - -from aiokafka.admin import AIOKafkaAdminClient, NewTopic -from aiokafka.errors import TopicAlreadyExistsError -from app.core.logging import setup_logger -from app.infrastructure.kafka.topics import get_all_topics, get_topic_configs -from app.settings import Settings - -settings = Settings() -logger = setup_logger(settings.LOG_LEVEL) - - -async def create_topics(settings: Settings) -> None: - """Create all required Kafka topics using provided settings.""" - - # Create admin client - admin_client = AIOKafkaAdminClient( - bootstrap_servers=settings.KAFKA_BOOTSTRAP_SERVERS, - client_id="topic-creator", - ) - - try: - await admin_client.start() - logger.info(f"Connected to Kafka brokers: {settings.KAFKA_BOOTSTRAP_SERVERS}") - - # Get existing topics - existing_topics: list[str] = await admin_client.list_topics() - existing_topics_set = set(existing_topics) - logger.info(f"Existing topics: {existing_topics_set}") - - # Get all required topics and their configs - all_topics = get_all_topics() - topic_configs = get_topic_configs() - topic_prefix = settings.KAFKA_TOPIC_PREFIX - logger.info(f"Total required topics: {len(all_topics)} (prefix: '{topic_prefix}')") - - # Create topics - topics_to_create: list[NewTopic] = [] - - for topic in all_topics: - # Apply topic prefix for consistency with consumers/producers - topic_name = f"{topic_prefix}{topic}" - if topic_name not in existing_topics_set: - # Get config from topic_configs - config = topic_configs.get( - topic, - { - "num_partitions": 3, - "replication_factor": 1, - "config": { - "retention.ms": "604800000", # 7 days - "compression.type": "gzip", - }, - }, - ) - - new_topic = NewTopic( - name=topic_name, - num_partitions=config.get("num_partitions", 3), - replication_factor=config.get("replication_factor", 1), - topic_configs=config.get("config", {}), - ) - topics_to_create.append(new_topic) - logger.info(f"Will create topic: {topic_name}") - else: - logger.info(f"Topic already exists: {topic_name}") - - if topics_to_create: - try: - await admin_client.create_topics(topics_to_create) - for topic in topics_to_create: - logger.info(f"Successfully created topic: {topic.name}") - except TopicAlreadyExistsError as e: - logger.warning(f"Some topics already exist: {e}") - except Exception as e: - logger.error(f"Error creating topics: {e}") - raise - else: - logger.info("All topics already exist") - - # List final topics - final_topics: list[str] = await admin_client.list_topics() - logger.info(f"Final topics count: {len(final_topics)}") - for topic_name in sorted(final_topics): - if not topic_name.startswith("__"): # Skip internal topics - logger.info(f" - {topic_name}") - - finally: - await admin_client.close() - - -async def main() -> None: - """Main entry point - loads settings from config.toml.""" - logger.info("Starting Kafka topic creation...") - - try: - await create_topics(settings) - logger.info("Topic creation completed successfully") - except Exception as e: - logger.error(f"Topic creation failed: {e}") - sys.exit(1) - - -if __name__ == "__main__": - # Run with proper event loop - asyncio.run(main()) diff --git a/backend/tests/e2e/conftest.py b/backend/tests/e2e/conftest.py index f2e7ff8e..9098aa68 100644 --- a/backend/tests/e2e/conftest.py +++ b/backend/tests/e2e/conftest.py @@ -9,7 +9,7 @@ import pytest_asyncio from aiokafka import AIOKafkaConsumer from app.db.docs.saga import SagaDocument -from app.domain.enums import EventType, KafkaTopic, UserRole +from app.domain.enums import EventType, UserRole from app.domain.events import DomainEvent, DomainEventAdapter, SagaStartedEvent from app.schemas_pydantic.execution import ExecutionRequest, ExecutionResponse from app.schemas_pydantic.notification import NotificationListResponse, NotificationResponse @@ -138,16 +138,10 @@ async def wait_for_notification_created(self, execution_id: str, timeout: float async def event_waiter(test_settings: Settings) -> AsyncGenerator[EventWaiter, None]: """Session-scoped Kafka event waiter. Starts before any test produces events.""" prefix = test_settings.KAFKA_TOPIC_PREFIX - topics = [ - f"{prefix}{KafkaTopic.EXECUTION_EVENTS}", - f"{prefix}{KafkaTopic.EXECUTION_RESULTS}", - f"{prefix}{KafkaTopic.SAGA_EVENTS}", - f"{prefix}{KafkaTopic.SAGA_COMMANDS}", - f"{prefix}{KafkaTopic.NOTIFICATION_EVENTS}", - ] + topics = [f"{prefix}{et}" for et in EventType] waiter = EventWaiter(test_settings.KAFKA_BOOTSTRAP_SERVERS, topics) await waiter.start() - _logger.info("EventWaiter started on %s", topics) + _logger.info("EventWaiter started on %d topics", len(topics)) yield waiter await waiter.stop() diff --git a/backend/tests/e2e/dlq/test_dlq_manager.py b/backend/tests/e2e/dlq/test_dlq_manager.py index d0b7c3d4..0c28cfbf 100644 --- a/backend/tests/e2e/dlq/test_dlq_manager.py +++ b/backend/tests/e2e/dlq/test_dlq_manager.py @@ -7,11 +7,10 @@ import pytest from aiokafka import AIOKafkaConsumer from app.core.metrics import DLQMetrics -from app.core.providers import _default_retry_policies, _default_retry_policy from app.db.repositories import DLQRepository from app.dlq.manager import DLQManager from app.dlq.models import DLQMessage -from app.domain.enums import EventType, KafkaTopic +from app.domain.enums import EventType from app.domain.events import DLQMessageReceivedEvent, DomainEventAdapter from app.settings import Settings from dishka import AsyncContainer @@ -39,7 +38,7 @@ async def test_dlq_manager_persists_and_emits_event(scope: AsyncContainer, test_ received_future: asyncio.Future[DLQMessageReceivedEvent] = asyncio.get_running_loop().create_future() # Create consumer for DLQ events topic - dlq_events_topic = f"{prefix}{KafkaTopic.DLQ_EVENTS}" + dlq_events_topic = f"{prefix}{EventType.DLQ_MESSAGE_RECEIVED}" events_consumer = AIOKafkaConsumer( dlq_events_topic, bootstrap_servers=test_settings.KAFKA_BOOTSTRAP_SERVERS, @@ -79,14 +78,12 @@ async def consume_dlq_events() -> None: logger=_test_logger, dlq_metrics=dlq_metrics, repository=repository, - default_retry_policy=_default_retry_policy(), - retry_policies=_default_retry_policies(test_settings.KAFKA_TOPIC_PREFIX), ) # Build a DLQMessage directly and call handle_message (no internal consumer loop) dlq_msg = DLQMessage( event=ev, - original_topic=f"{prefix}{KafkaTopic.EXECUTION_EVENTS}", + original_topic=f"{prefix}{EventType.EXECUTION_REQUESTED}", error="handler failed", retry_count=0, failed_at=datetime.now(timezone.utc), diff --git a/backend/tests/unit/events/test_mappings_and_types.py b/backend/tests/unit/events/test_mappings_and_types.py deleted file mode 100644 index ce32da44..00000000 --- a/backend/tests/unit/events/test_mappings_and_types.py +++ /dev/null @@ -1,12 +0,0 @@ -from app.domain.enums import EventType, KafkaTopic -from app.infrastructure.kafka.mappings import ( - get_event_class_for_type, - get_topic_for_event, -) - - -def test_event_mappings_topics() -> None: - # A few spot checks - assert get_topic_for_event(EventType.EXECUTION_REQUESTED) == KafkaTopic.EXECUTION_EVENTS - cls = get_event_class_for_type(EventType.CREATE_POD_COMMAND) - assert cls is not None diff --git a/backend/tests/unit/services/pod_monitor/test_config_and_init.py b/backend/tests/unit/services/pod_monitor/test_config_and_init.py index 8e2c14d6..5f3e52d4 100644 --- a/backend/tests/unit/services/pod_monitor/test_config_and_init.py +++ b/backend/tests/unit/services/pod_monitor/test_config_and_init.py @@ -1,7 +1,6 @@ import importlib import pytest -from app.domain.enums import KafkaTopic from app.services.pod_monitor import PodMonitorConfig pytestmark = pytest.mark.unit @@ -10,8 +9,8 @@ def test_pod_monitor_config_defaults() -> None: cfg = PodMonitorConfig() assert cfg.namespace == "integr8scode" - assert isinstance(cfg.pod_events_topic, KafkaTopic) and cfg.pod_events_topic - assert isinstance(cfg.execution_completed_topic, KafkaTopic) + assert isinstance(cfg.pod_events_topic, str) and cfg.pod_events_topic + assert isinstance(cfg.execution_completed_topic, str) assert cfg.ignored_pod_phases == [] diff --git a/docker-compose.yaml b/docker-compose.yaml index 5c5dad29..60c121f0 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -226,6 +226,7 @@ services: # Topic management KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'true' KAFKA_DELETE_TOPIC_ENABLE: 'true' + KAFKA_NUM_PARTITIONS: 3 KAFKA_LOG_RETENTION_HOURS: 168 # Production settings @@ -276,23 +277,6 @@ services: networks: - app-network - # Kafka topic initialization - kafka-init: - image: ghcr.io/hardmax71/integr8scode/backend:${IMAGE_TAG:-latest} - container_name: kafka-init - depends_on: - kafka: - condition: service_healthy - environment: - - KAFKA_BOOTSTRAP_SERVERS=kafka:29092 - volumes: - - ./backend/config.toml:/app/config.toml:ro - - ./backend/secrets.toml:/app/secrets.toml:ro - command: ["python", "-m", "scripts.create_topics"] - networks: - - app-network - restart: "no" # Run once and exit - # Seed default users (runs once after mongo is ready) user-seed: image: ghcr.io/hardmax71/integr8scode/backend:${IMAGE_TAG:-latest} @@ -318,8 +302,8 @@ services: mem_limit: 160m command: ["python", "workers/run_coordinator.py"] depends_on: - kafka-init: - condition: service_completed_successfully + kafka: + condition: service_healthy mongo: condition: service_started volumes: @@ -338,8 +322,8 @@ services: mem_limit: 160m command: ["python", "workers/run_k8s_worker.py"] depends_on: - kafka-init: - condition: service_completed_successfully + kafka: + condition: service_healthy mongo: condition: service_started volumes: @@ -361,8 +345,8 @@ services: mem_limit: 160m command: ["python", "workers/run_pod_monitor.py"] depends_on: - kafka-init: - condition: service_completed_successfully + kafka: + condition: service_healthy volumes: - ./backend/app:/app/app:ro - ./backend/workers:/app/workers:ro @@ -382,8 +366,8 @@ services: mem_limit: 160m command: ["python", "workers/run_result_processor.py"] depends_on: - kafka-init: - condition: service_completed_successfully + kafka: + condition: service_healthy mongo: condition: service_started volumes: @@ -405,8 +389,8 @@ services: mem_limit: 160m command: ["python", "workers/run_saga_orchestrator.py"] depends_on: - kafka-init: - condition: service_completed_successfully + kafka: + condition: service_healthy mongo: condition: service_started volumes: @@ -447,8 +431,8 @@ services: mem_limit: 160m command: ["python", "workers/run_event_replay.py"] depends_on: - kafka-init: - condition: service_completed_successfully + kafka: + condition: service_healthy mongo: condition: service_started volumes: @@ -468,8 +452,8 @@ services: mem_limit: 160m command: ["python", "workers/run_dlq_processor.py"] depends_on: - kafka-init: - condition: service_completed_successfully + kafka: + condition: service_healthy mongo: condition: service_started volumes: diff --git a/docs/architecture/event-system-design.md b/docs/architecture/event-system-design.md index ab0d2c8c..4af61a60 100644 --- a/docs/architecture/event-system-design.md +++ b/docs/architecture/event-system-design.md @@ -16,17 +16,12 @@ graph LR DE[Domain Events
typed.py
extends BaseModel] end - subgraph "Infrastructure" - M[Mappings
kafka/mappings.py] - end - ET --> DE - DE --> M - M --> Kafka[(Kafka Topics)] + DE --> Kafka[(Kafka Topics)] DE --> MongoDB[(MongoDB)] ``` -The `EventType` enum defines all possible event types as strings. Domain events are Pydantic `BaseModel` subclasses, making them usable for both MongoDB storage and Kafka transport. FastStream handles JSON serialization natively when publishing and deserializing when consuming. The mappings module routes events to the correct Kafka topics. +The `EventType` enum defines all possible event types as strings. Each `EventType` value IS the Kafka topic name (1:1 mapping). Domain events are Pydantic `BaseModel` subclasses, making them usable for both MongoDB storage and Kafka transport. FastStream handles JSON serialization natively when publishing and deserializing when consuming. This design eliminates duplication between "domain events" and "Kafka events" by making the domain event the single source of truth. @@ -44,9 +39,7 @@ The unified approach addresses these issues: - **Single definition**: Each event is defined once in `domain/events/typed.py` - **JSON-native**: `BaseEvent` extends Pydantic `BaseModel`; FastStream serializes to JSON automatically - **Storage-ready**: Events include storage fields (`stored_at`, `ttl_expires_at`) that MongoDB uses -- **Topic routing**: The `EVENT_TYPE_TO_TOPIC` mapping in `infrastructure/kafka/mappings.py` handles routing - -Infrastructure concerns (Kafka topics) are kept separate through the mappings module rather than embedded in event classes. +- **1:1 topic mapping**: Topic name = `EventType` value — no mapping layer needed ## How discriminated unions work @@ -115,29 +108,19 @@ Since `BaseEvent` is a plain Pydantic model, FastStream handles serialization an ## Topic routing -Events are routed to Kafka topics through the `EVENT_TYPE_TO_TOPIC` mapping: +Each `EventType` maps 1:1 to a Kafka topic. The topic name is the `EventType` string value itself. Since `EventType` extends `StringEnum` (which extends `StrEnum` extends `str`), the event type IS the topic name: ```python -# infrastructure/kafka/mappings.py -EVENT_TYPE_TO_TOPIC: Dict[EventType, KafkaTopic] = { - EventType.EXECUTION_REQUESTED: KafkaTopic.EXECUTION_EVENTS, - EventType.EXECUTION_COMPLETED: KafkaTopic.EXECUTION_EVENTS, - EventType.POD_CREATED: KafkaTopic.EXECUTION_EVENTS, - EventType.SAGA_STARTED: KafkaTopic.SAGA_EVENTS, - # ... all event types -} -``` - -Helper functions provide type-safe access: +# Producer — topic derived directly from event type +topic = f"{prefix}{event.event_type}" -```python -def get_topic_for_event(event_type: EventType) -> KafkaTopic: - return EVENT_TYPE_TO_TOPIC.get(event_type, KafkaTopic.SYSTEM_EVENTS) - -def get_event_class_for_type(event_type: EventType) -> type | None: - return _get_event_type_to_class().get(event_type) +# Consumer — one subscriber per event type +@broker.subscriber(f"{prefix}{EventType.EXECUTION_REQUESTED}", group_id="execution-coordinator") +async def on_execution_requested(body: ExecutionRequestedEvent): ... ``` +No mapping layer, no routing table, no `EVENT_TYPE_TO_TOPIC` dict. Each handler subscribes to exactly the topic it cares about. + ## Keeping things in sync With the unified model, there's less risk of drift since each event is defined once. The `test_event_schema_coverage.py` test suite validates: @@ -152,7 +135,8 @@ When adding a new event type: 1. Add the value to `EventType` enum 2. Create the event class in `typed.py` with the correct `event_type` default 3. Add it to the `DomainEvent` union -4. Add the topic mapping in `infrastructure/kafka/mappings.py` + +The topic is automatically available since topic name = event type string. If you miss a step, the test tells you exactly what's missing. @@ -178,7 +162,7 @@ graph TB When publishing events, the `UnifiedProducer`: 1. Persists the event to MongoDB via `EventRepository` -2. Looks up the topic via `EVENT_TYPE_TO_TOPIC` +2. Derives the topic name from `event_type` directly 3. Publishes the Pydantic model to Kafka through `broker.publish()` (FastStream handles JSON serialization) The producer handles both storage in MongoDB and publishing to Kafka in a single flow. @@ -189,7 +173,7 @@ The producer handles both storage in MongoDB and publishing to Kafka in a single |------|---------| | [`domain/enums/events.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/app/domain/enums/events.py) | `EventType` enum with all event type values | | [`domain/events/typed.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/app/domain/events/typed.py) | All domain event classes and `DomainEvent` union | -| [`infrastructure/kafka/mappings.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/app/infrastructure/kafka/mappings.py) | Event-to-topic routing and helper functions | +| [`infrastructure/kafka/topics.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/app/infrastructure/kafka/topics.py) | Category-based topic configs for partition/retention tuning | | [`events/core/producer.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/app/events/core/producer.py) | UnifiedProducer — persists to MongoDB then publishes to Kafka | | [`tests/unit/domain/events/test_event_schema_coverage.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/tests/unit/domain/events/test_event_schema_coverage.py) | Validates correspondence between enum and event classes | diff --git a/docs/architecture/kafka-topic-architecture.md b/docs/architecture/kafka-topic-architecture.md index 6c59ac09..0130069e 100644 --- a/docs/architecture/kafka-topic-architecture.md +++ b/docs/architecture/kafka-topic-architecture.md @@ -1,82 +1,85 @@ # Kafka topic architecture -## Why two topics? +## 1-topic-per-event-type -The system uses *two separate Kafka topics* for execution flow: `execution_events` and `execution_tasks`. This might seem redundant since both can contain the same `ExecutionRequestedEvent`, but the separation is essential for scalability and maintainability. +The system uses a **1:1 mapping** between `EventType` enum values and Kafka topics. Each event type gets its own dedicated topic. The topic name IS the `EventType` string value (with an optional prefix for environment isolation). -## Events vs tasks - -**execution_events** is the system's *event stream* — an append-only log capturing everything that happens to executions throughout their lifecycle: - -- User requests an execution -- Execution starts, completes, or fails -- Pods are created or terminated -- Status updates and log entries - -Multiple services consume this topic: SSE streams updates to users, projection service maintains read-optimized views, saga orchestrator manages workflows, monitoring tracks health. These consumers care about *completeness and ordering* because they're building a comprehensive picture of system state. - -**execution_tasks** is a *work queue*. It contains only events representing actual work to be done — executions that have been validated, authorized, rate-limited, and scheduled. When the coordinator publishes to `execution_tasks`, it's saying "this needs to be done now" rather than "this happened." The Kubernetes worker, the *sole consumer* of this topic, just needs to know what pods to create. - -## Request flow - -When a user submits code, the API creates an `ExecutionRequestedEvent` and publishes it to `execution_events`. This acknowledges the request and makes it part of the permanent record. - -The coordinator subscribes to `execution_events` and begins validation: - -- Has the user exceeded their rate limit? -- Is the queue full? -- Should this execution be prioritized or queued? +``` +Topic name = f"{KAFKA_TOPIC_PREFIX}{EventType.EXECUTION_REQUESTED}" + = f"dev_{EventType.EXECUTION_REQUESTED}" + = "dev_execution_requested" +``` -Some requests get rejected immediately. Others sit in a priority queue waiting for resources. Still others get cancelled before starting. +Since `EventType` extends `StringEnum` (which extends `str`), no `.value` accessor is needed — the enum member IS the string. -Only when the coordinator determines an execution is *ready to proceed* does it republish to `execution_tasks`. This represents a state transition — the event has moved from being a request to being *scheduled work*. +## Why one topic per event type? -The Kubernetes worker then consumes from `execution_tasks`, creates resources (ConfigMaps, Pods), and publishes a `PodCreatedEvent` back to `execution_events`. It doesn't need to know about rate limits or queuing — all that complexity has been handled upstream. +Previous designs multiplexed many event types onto shared topics (e.g. `execution_events` carried 9 different event types consumed by 4 separate consumer groups). This created problems: -## Performance and scaling +- **Body-based filtering**: Every consumer decoded every message just to check `event_type`, wasting CPU +- **Catch-all handlers**: Unmatched events were silently dropped by `on_unhandled` handlers +- **Tight coupling**: Unrelated event types shared partition counts, retention policies, and consumer group offsets +- **Debugging difficulty**: Hard to reason about which consumer is processing what -The `execution_events` topic is busy. For every execution, there might be a dozen or more events: requested, queued, started, pod status updates, log entries, completion, cleanup. Hundreds of executions per minute means *thousands* of events flowing through. +The 1:1 approach eliminates all of these: -If the Kubernetes worker had to consume from this firehose, it would receive every event type and need to filter down to just the ready-to-process `ExecutionRequestedEvents`. This filtering would consume CPU and bandwidth, and couple worker performance to overall event volume. +- **No filtering**: Each `@broker.subscriber(topic)` receives exactly one event type with its typed Pydantic model +- **No catch-alls**: Nothing to drop — every message on a topic matches the subscriber's type +- **Independent tuning**: Each topic can have its own partition count and retention policy +- **Clear ownership**: Easy to see which consumer groups subscribe to which event types -With separate topics, the worker receives *only what it needs*. If `execution_events` processes 1000 events/minute but only 50 executions are scheduled, the worker sees only those 50. This allows focus on the core responsibility: creating and managing pods. +## Topic categories and configuration -The separation enables independent scaling: +Topics are grouped into categories for configuration purposes (partition count, retention): -- `execution_events`: many partitions for high throughput, numerous concurrent consumers -- `execution_tasks`: fewer partitions optimized for the worker's pattern (pod creation is expensive, less parallelism is sometimes better) +| Category | Partitions | Retention | Event Types | +|----------|-----------|-----------|-------------| +| Execution | 6 | 7 days | `execution_requested`, `execution_completed`, `execution_failed`, etc. | +| Pod | 3 | 1 day | `pod_created`, `pod_scheduled`, `pod_running`, etc. | +| Command | 3 | 1 day | `create_pod_command`, `delete_pod_command`, etc. | +| User/Security | 3 | 30 days | `user_registered`, `security_violation`, etc. | +| Default | 3 | 7 days | Everything else (saga, notification, DLQ, etc.) | +| DLQ | 3 | 14 days | `dead_letter_queue` | -## Operations +Configuration is defined in `infrastructure/kafka/topics.py` using category sets. -Separate topics provide crucial isolation. When troubleshooting: +## Consumer groups -- If `execution_tasks` is backing up → the Kubernetes worker is struggling -- If `execution_events` is backing up → need to identify which consumer is the bottleneck +Each worker subscribes to only the topics it needs, with its own consumer group: -Different retention policies make sense too. `execution_events` needs long retention (90+ days) as the audit log and source of truth. `execution_tasks` can have short retention — once processed, a few days is enough for recovery scenarios. +| Consumer Group | Subscribed Topics | +|---------------|-------------------| +| `execution-coordinator` | `execution_requested`, `execution_completed`, `execution_failed`, `execution_cancelled` | +| `k8s-worker` | `create_pod_command`, `delete_pod_command` | +| `result-processor` | `execution_completed`, `execution_failed`, `execution_timeout` | +| `saga-orchestrator` | `execution_requested`, `execution_completed`, `execution_failed`, `execution_timeout` | +| `notification-service` | `execution_completed`, `execution_failed`, `execution_timeout` | +| `sse-bridge-pool` | 16 event types (execution + pod lifecycle + result) | +| `dlq-manager` | `dead_letter_queue` | -Monitoring becomes more precise. Different SLAs for different stages: +Multiple consumer groups can subscribe to the same topic — Kafka delivers each message to every group independently. -- `ExecutionRequestedEvent` in `execution_events` within 100ms of API receipt -- Up to 30 seconds acceptable before appearing in `execution_tasks` +## Request flow -## Failure handling +When a user submits code, the API creates an `ExecutionRequestedEvent` and publishes it to the `execution_requested` topic. Multiple consumers receive it: -If the Kubernetes worker crashes, `execution_tasks` accumulates messages but the rest of the system continues normally. Users can submit executions, the coordinator validates and queues them, other services process `execution_events`. When the worker recovers, it picks up where it left off. +1. **Coordinator**: Validates, rate-limits, orchestrates the execution flow +2. **Saga orchestrator**: Creates a saga to track the distributed transaction +3. **SSE bridge**: Pushes the event to the user's browser in real-time -In a single-topic architecture, a slow worker would cause backpressure affecting *all* consumers. SSE might delay updates. Projections might fall behind. The entire system degrades because one component can't keep up. +The coordinator publishes `CreatePodCommandEvent` to the `create_pod_command` topic. The K8s worker — the sole consumer — creates the pod. Pod lifecycle events flow back through their respective topics. -The coordinator acts as a *shock absorber* between user requests and pod creation. It implements queuing and prioritization without affecting upstream producers or downstream workers. During high load, the coordinator holds executions in its internal queue while still acknowledging receipt. +## Scaling -## Extensibility +With dedicated topics per event type, each can be scaled independently: -This pattern provides flexibility for evolution: +- High-throughput execution events get 6 partitions +- Lower-volume pod events use 3 partitions +- Command topics (work queues) use 3 partitions, optimized for the worker's consumption pattern -- Add GPU workers or long-running job workers → introduce additional task topics without modifying core event flow -- Add security scanning or batch processing stages → insert between `execution_events` and `execution_tasks` -- Add scheduled executions → `schedule_events` for audit, `schedule_tasks` for scheduling work +## Failure isolation -The pattern of separating *event streams* from *task queues* applies broadly. +If the K8s worker crashes, only `create_pod_command` and `delete_pod_command` topics accumulate messages. The rest of the system continues normally — SSE streams updates, the coordinator processes requests, notifications fire. ## Sagas @@ -128,13 +131,13 @@ Create a replay session with filters (time range, event type), and ReplayService ```mermaid graph LR - Consumer[Consumer] -->|"failure"| DLQ[(DLQ Topic)] + Consumer[Consumer] -->|"failure"| DLQ[(dead_letter_queue topic)] DLQ <--> Manager[DLQ Manager] Manager -->|"retry"| Original[(Original Topic)] Admin[Admin API] --> Manager ``` -When a consumer fails to process an event after multiple retries, it lands in the dead letter queue. The DLQ manager handles retry logic with *exponential backoff* and configurable thresholds. +When a consumer fails to process an event after multiple retries, it lands in the dead letter queue. The DLQ manager handles retry logic with *exponential backoff* and configurable thresholds. Retry policies are determined by event type category (execution events get aggressive retries, pod events get cautious retries). Admins can: @@ -148,8 +151,8 @@ Admins can: Key files: - `domain/events/typed.py` — all Pydantic event models (plain `BaseModel` subclasses) -- `infrastructure/kafka/mappings.py` — event-to-topic routing and helper functions +- `infrastructure/kafka/topics.py` — category-based topic configs (partitions, retention) - `events/core/producer.py` — UnifiedProducer (persists to MongoDB, publishes to Kafka) - `events/handlers.py` — FastStream subscriber registrations for all workers -All events are Pydantic models with strict typing. FastStream handles JSON serialization natively — the producer publishes Pydantic instances directly via `broker.publish()`, and subscribers receive typed model instances. The mappings module routes each event type to its destination topic via `EVENT_TYPE_TO_TOPIC`. Pydantic validation on both ends ensures structural agreement between producers and consumers. +All events are Pydantic models with strict typing. FastStream handles JSON serialization natively — the producer publishes Pydantic instances directly via `broker.publish()`, and subscribers receive typed model instances. Pydantic validation on both ends ensures structural agreement between producers and consumers. diff --git a/docs/operations/deployment.md b/docs/operations/deployment.md index ca48a8e8..e9dc26b3 100644 --- a/docs/operations/deployment.md +++ b/docs/operations/deployment.md @@ -42,8 +42,8 @@ with health checks and dependency ordering, so containers start in the correct s ``` This brings up MongoDB, Redis, Kafka (KRaft mode), all seven workers, the backend API, and the -frontend. Two initialization containers run automatically: `kafka-init` creates required Kafka topics, and `user-seed` -populates the database with default user accounts. +frontend. One initialization container runs automatically: `user-seed` populates the database with default user accounts. +Kafka topics are created on-demand via `auto.create.topics.enable` when producers first publish or consumers subscribe. Once the stack is running, you can access the services at their default ports. @@ -166,18 +166,18 @@ docker compose logs backend | Issue | Cause | Solution | |-----------------------|-----------------------------------|---------------------------------------------------| -| Unknown topic errors | kafka-init failed or wrong prefix | Check `docker compose logs kafka-init` | +| Unknown topic errors | Kafka not ready or wrong prefix | Check `docker compose logs kafka` | | MongoDB auth errors | Password mismatch | Verify `secrets.toml` matches compose env vars | | Worker crash loop | Config file missing | Ensure `config..toml` exists | ### Kafka topic debugging ```bash -docker compose logs kafka-init +docker compose logs kafka docker compose exec kafka kafka-topics --list --bootstrap-server localhost:29092 ``` -Topics should be prefixed (e.g., `prefexecution_events` not `execution_events`). +Topics are auto-created on first use. Each topic name = event type value with prefix (e.g., `dev_execution_requested`). ### k3s crash loop after VPN or IP change From 2b5c8eb6b14ba4138fbc2369a224280f2ed12dea Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Wed, 18 Feb 2026 23:58:41 +0100 Subject: [PATCH 2/9] docs update, schemas and stuff regenerate --- backend/app/services/pod_monitor/config.py | 7 -- .../pod_monitor/test_config_and_init.py | 2 - docs/reference/openapi.json | 73 +++---------------- frontend/src/lib/api/client/client.gen.ts | 73 +++++++------------ frontend/src/lib/api/client/types.gen.ts | 52 +++---------- frontend/src/lib/api/client/utils.gen.ts | 28 ++----- frontend/src/lib/api/core/auth.gen.ts | 3 +- .../src/lib/api/core/bodySerializer.gen.ts | 26 ++----- frontend/src/lib/api/core/params.gen.ts | 13 +--- .../src/lib/api/core/pathSerializer.gen.ts | 18 +---- .../lib/api/core/queryKeySerializer.gen.ts | 31 ++------ .../src/lib/api/core/serverSentEvents.gen.ts | 39 ++-------- frontend/src/lib/api/core/types.gen.ts | 22 +----- frontend/src/lib/api/core/utils.gen.ts | 5 +- frontend/src/lib/api/index.ts | 2 +- frontend/src/lib/api/types.gen.ts | 43 ++--------- frontend/src/lib/editor/execution.svelte.ts | 6 +- 17 files changed, 97 insertions(+), 346 deletions(-) diff --git a/backend/app/services/pod_monitor/config.py b/backend/app/services/pod_monitor/config.py index e1a757a3..33c7d497 100644 --- a/backend/app/services/pod_monitor/config.py +++ b/backend/app/services/pod_monitor/config.py @@ -1,6 +1,5 @@ from dataclasses import dataclass, field -from app.domain.enums import EventType from app.services.pod_monitor.event_mapper import PodPhase @@ -8,12 +7,6 @@ class PodMonitorConfig: """Configuration for PodMonitor service""" - # Kafka settings - pod_events_topic: str = EventType.POD_CREATED - execution_events_topic: str = EventType.EXECUTION_REQUESTED - execution_completed_topic: str = EventType.EXECUTION_COMPLETED - execution_failed_topic: str = EventType.EXECUTION_FAILED - # Kubernetes settings namespace: str = "integr8scode" kubeconfig_path: str | None = None diff --git a/backend/tests/unit/services/pod_monitor/test_config_and_init.py b/backend/tests/unit/services/pod_monitor/test_config_and_init.py index 5f3e52d4..de5f2719 100644 --- a/backend/tests/unit/services/pod_monitor/test_config_and_init.py +++ b/backend/tests/unit/services/pod_monitor/test_config_and_init.py @@ -9,8 +9,6 @@ def test_pod_monitor_config_defaults() -> None: cfg = PodMonitorConfig() assert cfg.namespace == "integr8scode" - assert isinstance(cfg.pod_events_topic, str) and cfg.pod_events_topic - assert isinstance(cfg.execution_completed_topic, str) assert cfg.ignored_pod_phases == [] diff --git a/docs/reference/openapi.json b/docs/reference/openapi.json index eb1b2a57..a102e7ef 100644 --- a/docs/reference/openapi.json +++ b/docs/reference/openapi.json @@ -1969,7 +1969,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SSEExecutionEventData" + "$ref": "#/components/schemas/SSEExecutionEventSchema" } } } @@ -2826,16 +2826,6 @@ } } }, - "500": { - "description": "Failed to update user", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, "422": { "description": "Validation Error", "content": { @@ -4753,8 +4743,7 @@ "required": [ "name" ], - "title": "ContainerStatusInfo", - "description": "Container status information from Kubernetes pod." + "title": "ContainerStatusInfo" }, "CreatePodCommandEvent": { "properties": { @@ -6198,8 +6187,7 @@ "algorithm", "remaining" ], - "title": "EndpointUsageStats", - "description": "Usage statistics for a single endpoint (IETF RateLimit-style)." + "title": "EndpointUsageStats" }, "Environment": { "type": "string", @@ -6924,8 +6912,7 @@ "service_name", "service_version" ], - "title": "EventMetadata", - "description": "Event metadata - embedded in all events." + "title": "EventMetadata" }, "EventReplayRequest": { "properties": { @@ -7364,8 +7351,7 @@ "event_type", "timestamp" ], - "title": "EventSummary", - "description": "Lightweight event summary for lists and previews." + "title": "EventSummary" }, "EventType": { "type": "string", @@ -8422,37 +8408,6 @@ ], "title": "HourlyEventCount" }, - "KafkaTopic": { - "type": "string", - "enum": [ - "execution_events", - "execution_completed", - "execution_failed", - "execution_timeout", - "execution_requests", - "execution_commands", - "execution_tasks", - "pod_events", - "pod_status_updates", - "pod_results", - "execution_results", - "user_events", - "user_notifications", - "user_settings_events", - "script_events", - "security_events", - "resource_events", - "notification_events", - "system_events", - "saga_events", - "saga_commands", - "dead_letter_queue", - "dlq_events", - "websocket_events" - ], - "title": "KafkaTopic", - "description": "Kafka topic names used throughout the system." - }, "LanguageInfo": { "properties": { "versions": { @@ -10426,7 +10381,7 @@ "anyOf": [ { "additionalProperties": { - "$ref": "#/components/schemas/KafkaTopic" + "type": "string" }, "type": "object" }, @@ -10513,8 +10468,7 @@ "timestamp", "error" ], - "title": "ReplayError", - "description": "Error details for replay operations.\n\nAttributes:\n timestamp: When the error occurred.\n error: Human-readable error message.\n error_type: Python exception class name (e.g., \"ValueError\", \"KafkaException\").\n This is the result of `type(exception).__name__`, NOT the ErrorType enum.\n Present for session-level errors.\n event_id: ID of the event that failed to replay. Present for event-level errors." + "title": "ReplayError" }, "ReplayFilter": { "properties": { @@ -10811,7 +10765,7 @@ "anyOf": [ { "additionalProperties": { - "$ref": "#/components/schemas/KafkaTopic" + "type": "string" }, "type": "object" }, @@ -11158,8 +11112,7 @@ } }, "type": "object", - "title": "ResourceUsageDomain", - "description": "Resource usage metrics from script execution." + "title": "ResourceUsageDomain" }, "RestoreSettingsRequest": { "properties": { @@ -11390,7 +11343,7 @@ "title": "SSEControlEvent", "description": "Control events for execution SSE streams (not from Kafka)." }, - "SSEExecutionEventData": { + "SSEExecutionEventSchema": { "properties": { "event_type": { "anyOf": [ @@ -11545,7 +11498,7 @@ "event_type", "execution_id" ], - "title": "SSEExecutionEventData", + "title": "SSEExecutionEventSchema", "description": "API schema for SSE execution stream event payload (OpenAPI docs)." }, "SagaCancellationResponse": { @@ -13144,13 +13097,11 @@ }, "memory_limit": { "type": "string", - "pattern": "^[1-9]\\d*(Ki|Mi|Gi)$", "title": "Memory Limit", "default": "512Mi" }, "cpu_limit": { "type": "string", - "pattern": "^[1-9]\\d*m$", "title": "Cpu Limit", "default": "2000m" }, @@ -13215,7 +13166,7 @@ }, "type": "object", "title": "SystemSettingsSchema", - "description": "API schema for system settings \u2014 inherits all fields from domain model." + "description": "API schema for system settings with validation." }, "Theme": { "type": "string", diff --git a/frontend/src/lib/api/client/client.gen.ts b/frontend/src/lib/api/client/client.gen.ts index d4cbcce5..d2e55a14 100644 --- a/frontend/src/lib/api/client/client.gen.ts +++ b/frontend/src/lib/api/client/client.gen.ts @@ -3,12 +3,7 @@ import { createSseClient } from '../core/serverSentEvents.gen'; import type { HttpMethod } from '../core/types.gen'; import { getValidRequestBody } from '../core/utils.gen'; -import type { - Client, - Config, - RequestOptions, - ResolvedRequestOptions, -} from './types.gen'; +import type { Client, Config, RequestOptions, ResolvedRequestOptions } from './types.gen'; import { buildUrl, createConfig, @@ -34,12 +29,7 @@ export const createClient = (config: Config = {}): Client => { return getConfig(); }; - const interceptors = createInterceptors< - Request, - Response, - unknown, - ResolvedRequestOptions - >(); + const interceptors = createInterceptors(); const beforeRequest = async (options: RequestOptions) => { const opts = { @@ -105,12 +95,7 @@ export const createClient = (config: Config = {}): Client => { for (const fn of interceptors.error.fns) { if (fn) { - finalError = (await fn( - error, - undefined as any, - request, - opts, - )) as unknown; + finalError = (await fn(error, undefined as any, request, opts)) as unknown; } } @@ -147,10 +132,7 @@ export const createClient = (config: Config = {}): Client => { ? getParseAs(response.headers.get('Content-Type')) : opts.parseAs) ?? 'json'; - if ( - response.status === 204 || - response.headers.get('Content-Length') === '0' - ) { + if (response.status === 204 || response.headers.get('Content-Length') === '0') { let emptyData: any; switch (parseAs) { case 'arrayBuffer': @@ -252,34 +234,29 @@ export const createClient = (config: Config = {}): Client => { }; }; - const makeMethodFn = - (method: Uppercase) => (options: RequestOptions) => - request({ ...options, method }); + const makeMethodFn = (method: Uppercase) => (options: RequestOptions) => + request({ ...options, method }); - const makeSseFn = - (method: Uppercase) => async (options: RequestOptions) => { - const { opts, url } = await beforeRequest(options); - return createSseClient({ - ...opts, - body: opts.body as BodyInit | null | undefined, - headers: opts.headers as unknown as Record, - method, - onRequest: async (url, init) => { - let request = new Request(url, init); - for (const fn of interceptors.request.fns) { - if (fn) { - request = await fn(request, opts); - } + const makeSseFn = (method: Uppercase) => async (options: RequestOptions) => { + const { opts, url } = await beforeRequest(options); + return createSseClient({ + ...opts, + body: opts.body as BodyInit | null | undefined, + headers: opts.headers as unknown as Record, + method, + onRequest: async (url, init) => { + let request = new Request(url, init); + for (const fn of interceptors.request.fns) { + if (fn) { + request = await fn(request, opts); } - return request; - }, - serializedBody: getValidRequestBody(opts) as - | BodyInit - | null - | undefined, - url, - }); - }; + } + return request; + }, + serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined, + url, + }); + }; return { buildUrl, diff --git a/frontend/src/lib/api/client/types.gen.ts b/frontend/src/lib/api/client/types.gen.ts index b4a499cc..cb6d0d54 100644 --- a/frontend/src/lib/api/client/types.gen.ts +++ b/frontend/src/lib/api/client/types.gen.ts @@ -5,17 +5,13 @@ import type { ServerSentEventsOptions, ServerSentEventsResult, } from '../core/serverSentEvents.gen'; -import type { - Client as CoreClient, - Config as CoreConfig, -} from '../core/types.gen'; +import type { Client as CoreClient, Config as CoreConfig } from '../core/types.gen'; import type { Middleware } from './utils.gen'; export type ResponseStyle = 'data' | 'fields'; export interface Config - extends Omit, - CoreConfig { + extends Omit, CoreConfig { /** * Base URL for all requests made by this client. */ @@ -42,14 +38,7 @@ export interface Config * * @default 'auto' */ - parseAs?: - | 'arrayBuffer' - | 'auto' - | 'blob' - | 'formData' - | 'json' - | 'stream' - | 'text'; + parseAs?: 'arrayBuffer' | 'auto' | 'blob' | 'formData' | 'json' | 'stream' | 'text'; /** * Should we return only data or multiple fields (data, error, response, etc.)? * @@ -69,7 +58,9 @@ export interface RequestOptions< TResponseStyle extends ResponseStyle = 'fields', ThrowOnError extends boolean = boolean, Url extends string = string, -> extends Config<{ +> + extends + Config<{ responseStyle: TResponseStyle; throwOnError: ThrowOnError; }>, @@ -116,32 +107,22 @@ export type RequestResult< ? TData[keyof TData] : TData : { - data: TData extends Record - ? TData[keyof TData] - : TData; + data: TData extends Record ? TData[keyof TData] : TData; request: Request; response: Response; } > : Promise< TResponseStyle extends 'data' - ? - | (TData extends Record - ? TData[keyof TData] - : TData) - | undefined + ? (TData extends Record ? TData[keyof TData] : TData) | undefined : ( | { - data: TData extends Record - ? TData[keyof TData] - : TData; + data: TData extends Record ? TData[keyof TData] : TData; error: undefined; } | { data: undefined; - error: TError extends Record - ? TError[keyof TError] - : TError; + error: TError extends Record ? TError[keyof TError] : TError; } ) & { request: Request; @@ -180,10 +161,7 @@ type RequestFn = < TResponseStyle extends ResponseStyle = 'fields', >( options: Omit, 'method'> & - Pick< - Required>, - 'method' - >, + Pick>, 'method'>, ) => RequestResult; type BuildUrlFn = < @@ -197,13 +175,7 @@ type BuildUrlFn = < options: TData & Options, ) => string; -export type Client = CoreClient< - RequestFn, - Config, - MethodFn, - BuildUrlFn, - SseFn -> & { +export type Client = CoreClient & { interceptors: Middleware; }; diff --git a/frontend/src/lib/api/client/utils.gen.ts b/frontend/src/lib/api/client/utils.gen.ts index 4c48a9ee..b4bd2435 100644 --- a/frontend/src/lib/api/client/utils.gen.ts +++ b/frontend/src/lib/api/client/utils.gen.ts @@ -65,9 +65,7 @@ export const createQuerySerializer = ({ /** * Infers parseAs value from provided Content-Type header. */ -export const getParseAs = ( - contentType: string | null, -): Exclude => { +export const getParseAs = (contentType: string | null): Exclude => { if (!contentType) { // If no Content-Type header is provided, the best we can do is return the raw response body, // which is effectively the same as the 'stream' option. @@ -80,10 +78,7 @@ export const getParseAs = ( return; } - if ( - cleanContent.startsWith('application/json') || - cleanContent.endsWith('+json') - ) { + if (cleanContent.startsWith('application/json') || cleanContent.endsWith('+json')) { return 'json'; } @@ -92,9 +87,7 @@ export const getParseAs = ( } if ( - ['application/', 'audio/', 'image/', 'video/'].some((type) => - cleanContent.startsWith(type), - ) + ['application/', 'audio/', 'image/', 'video/'].some((type) => cleanContent.startsWith(type)) ) { return 'blob'; } @@ -201,10 +194,7 @@ export const mergeHeaders = ( continue; } - const iterator = - header instanceof Headers - ? headersEntries(header) - : Object.entries(header); + const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header); for (const [key, value] of iterator) { if (value === null) { @@ -233,10 +223,7 @@ type ErrInterceptor = ( options: Options, ) => Err | Promise; -type ReqInterceptor = ( - request: Req, - options: Options, -) => Req | Promise; +type ReqInterceptor = (request: Req, options: Options) => Req | Promise; type ResInterceptor = ( response: Res, @@ -270,10 +257,7 @@ class Interceptors { return this.fns.indexOf(id); } - update( - id: number | Interceptor, - fn: Interceptor, - ): number | Interceptor | false { + update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false { const index = this.getInterceptorIndex(id); if (this.fns[index]) { this.fns[index] = fn; diff --git a/frontend/src/lib/api/core/auth.gen.ts b/frontend/src/lib/api/core/auth.gen.ts index f8a73266..3ebf9947 100644 --- a/frontend/src/lib/api/core/auth.gen.ts +++ b/frontend/src/lib/api/core/auth.gen.ts @@ -23,8 +23,7 @@ export const getAuthToken = async ( auth: Auth, callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, ): Promise => { - const token = - typeof callback === 'function' ? await callback(auth) : callback; + const token = typeof callback === 'function' ? await callback(auth) : callback; if (!token) { return; diff --git a/frontend/src/lib/api/core/bodySerializer.gen.ts b/frontend/src/lib/api/core/bodySerializer.gen.ts index 552b50f7..8ad92c9f 100644 --- a/frontend/src/lib/api/core/bodySerializer.gen.ts +++ b/frontend/src/lib/api/core/bodySerializer.gen.ts @@ -1,10 +1,6 @@ // This file is auto-generated by @hey-api/openapi-ts -import type { - ArrayStyle, - ObjectStyle, - SerializerOptions, -} from './pathSerializer.gen'; +import type { ArrayStyle, ObjectStyle, SerializerOptions } from './pathSerializer.gen'; export type QuerySerializer = (query: Record) => string; @@ -24,11 +20,7 @@ export type QuerySerializerOptions = QuerySerializerOptionsObject & { parameters?: Record; }; -const serializeFormDataPair = ( - data: FormData, - key: string, - value: unknown, -): void => { +const serializeFormDataPair = (data: FormData, key: string, value: unknown): void => { if (typeof value === 'string' || value instanceof Blob) { data.append(key, value); } else if (value instanceof Date) { @@ -38,11 +30,7 @@ const serializeFormDataPair = ( } }; -const serializeUrlSearchParamsPair = ( - data: URLSearchParams, - key: string, - value: unknown, -): void => { +const serializeUrlSearchParamsPair = (data: URLSearchParams, key: string, value: unknown): void => { if (typeof value === 'string') { data.append(key, value); } else { @@ -73,15 +61,11 @@ export const formDataBodySerializer = { export const jsonBodySerializer = { bodySerializer: (body: T): string => - JSON.stringify(body, (_key, value) => - typeof value === 'bigint' ? value.toString() : value, - ), + JSON.stringify(body, (_key, value) => (typeof value === 'bigint' ? value.toString() : value)), }; export const urlSearchParamsBodySerializer = { - bodySerializer: | Array>>( - body: T, - ): string => { + bodySerializer: | Array>>(body: T): string => { const data = new URLSearchParams(); Object.entries(body).forEach(([key, value]) => { diff --git a/frontend/src/lib/api/core/params.gen.ts b/frontend/src/lib/api/core/params.gen.ts index 602715c4..6099cab1 100644 --- a/frontend/src/lib/api/core/params.gen.ts +++ b/frontend/src/lib/api/core/params.gen.ts @@ -102,10 +102,7 @@ const stripEmptySlots = (params: Params) => { } }; -export const buildClientParams = ( - args: ReadonlyArray, - fields: FieldsConfig, -) => { +export const buildClientParams = (args: ReadonlyArray, fields: FieldsConfig) => { const params: Params = { body: {}, headers: {}, @@ -148,15 +145,11 @@ export const buildClientParams = ( params[field.map] = value; } } else { - const extra = extraPrefixes.find(([prefix]) => - key.startsWith(prefix), - ); + const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix)); if (extra) { const [prefix, slot] = extra; - (params[slot] as Record)[ - key.slice(prefix.length) - ] = value; + (params[slot] as Record)[key.slice(prefix.length)] = value; } else if ('allowExtra' in config && config.allowExtra) { for (const [slot, allowed] of Object.entries(config.allowExtra)) { if (allowed) { diff --git a/frontend/src/lib/api/core/pathSerializer.gen.ts b/frontend/src/lib/api/core/pathSerializer.gen.ts index 8d999310..994b2848 100644 --- a/frontend/src/lib/api/core/pathSerializer.gen.ts +++ b/frontend/src/lib/api/core/pathSerializer.gen.ts @@ -1,8 +1,6 @@ // This file is auto-generated by @hey-api/openapi-ts -interface SerializeOptions - extends SerializePrimitiveOptions, - SerializerOptions {} +interface SerializeOptions extends SerializePrimitiveOptions, SerializerOptions {} interface SerializePrimitiveOptions { allowReserved?: boolean; @@ -105,9 +103,7 @@ export const serializeArrayParam = ({ }); }) .join(separator); - return style === 'label' || style === 'matrix' - ? separator + joinedValues - : joinedValues; + return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; }; export const serializePrimitiveParam = ({ @@ -146,11 +142,7 @@ export const serializeObjectParam = ({ if (style !== 'deepObject' && !explode) { let values: string[] = []; Object.entries(value).forEach(([key, v]) => { - values = [ - ...values, - key, - allowReserved ? (v as string) : encodeURIComponent(v as string), - ]; + values = [...values, key, allowReserved ? (v as string) : encodeURIComponent(v as string)]; }); const joinedValues = values.join(','); switch (style) { @@ -175,7 +167,5 @@ export const serializeObjectParam = ({ }), ) .join(separator); - return style === 'label' || style === 'matrix' - ? separator + joinedValues - : joinedValues; + return style === 'label' || style === 'matrix' ? separator + joinedValues : joinedValues; }; diff --git a/frontend/src/lib/api/core/queryKeySerializer.gen.ts b/frontend/src/lib/api/core/queryKeySerializer.gen.ts index d3bb6839..5000df60 100644 --- a/frontend/src/lib/api/core/queryKeySerializer.gen.ts +++ b/frontend/src/lib/api/core/queryKeySerializer.gen.ts @@ -15,11 +15,7 @@ export type JsonValue = * Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes. */ export const queryKeyJsonReplacer = (_key: string, value: unknown) => { - if ( - value === undefined || - typeof value === 'function' || - typeof value === 'symbol' - ) { + if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { return undefined; } if (typeof value === 'bigint') { @@ -61,9 +57,7 @@ const isPlainObject = (value: unknown): value is Record => { * Turns URLSearchParams into a sorted JSON object for deterministic keys. */ const serializeSearchParams = (params: URLSearchParams): JsonValue => { - const entries = Array.from(params.entries()).sort(([a], [b]) => - a.localeCompare(b), - ); + const entries = Array.from(params.entries()).sort(([a], [b]) => a.localeCompare(b)); const result: Record = {}; for (const [key, value] of entries) { @@ -86,26 +80,16 @@ const serializeSearchParams = (params: URLSearchParams): JsonValue => { /** * Normalizes any accepted value into a JSON-friendly shape for query keys. */ -export const serializeQueryKeyValue = ( - value: unknown, -): JsonValue | undefined => { +export const serializeQueryKeyValue = (value: unknown): JsonValue | undefined => { if (value === null) { return null; } - if ( - typeof value === 'string' || - typeof value === 'number' || - typeof value === 'boolean' - ) { + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { return value; } - if ( - value === undefined || - typeof value === 'function' || - typeof value === 'symbol' - ) { + if (value === undefined || typeof value === 'function' || typeof value === 'symbol') { return undefined; } @@ -121,10 +105,7 @@ export const serializeQueryKeyValue = ( return stringifyToJsonValue(value); } - if ( - typeof URLSearchParams !== 'undefined' && - value instanceof URLSearchParams - ) { + if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) { return serializeSearchParams(value); } diff --git a/frontend/src/lib/api/core/serverSentEvents.gen.ts b/frontend/src/lib/api/core/serverSentEvents.gen.ts index 343d25af..6aa6cf02 100644 --- a/frontend/src/lib/api/core/serverSentEvents.gen.ts +++ b/frontend/src/lib/api/core/serverSentEvents.gen.ts @@ -2,10 +2,7 @@ import type { Config } from './types.gen'; -export type ServerSentEventsOptions = Omit< - RequestInit, - 'method' -> & +export type ServerSentEventsOptions = Omit & Pick & { /** * Fetch API implementation. You can use this option to provide a custom @@ -74,11 +71,7 @@ export interface StreamEvent { retry?: number; } -export type ServerSentEventsResult< - TData = unknown, - TReturn = void, - TNext = unknown, -> = { +export type ServerSentEventsResult = { stream: AsyncGenerator< TData extends Record ? TData[keyof TData] : TData, TReturn, @@ -101,9 +94,7 @@ export const createSseClient = ({ }: ServerSentEventsOptions): ServerSentEventsResult => { let lastEventId: string | undefined; - const sleep = - sseSleepFn ?? - ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); + const sleep = sseSleepFn ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); const createStream = async function* () { let retryDelay: number = sseDefaultRetryDelay ?? 3000; @@ -141,16 +132,11 @@ export const createSseClient = ({ const _fetch = options.fetch ?? globalThis.fetch; const response = await _fetch(request); - if (!response.ok) - throw new Error( - `SSE failed: ${response.status} ${response.statusText}`, - ); + if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`); if (!response.body) throw new Error('No body in SSE response'); - const reader = response.body - .pipeThrough(new TextDecoderStream()) - .getReader(); + const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); let buffer = ''; @@ -188,10 +174,7 @@ export const createSseClient = ({ } else if (line.startsWith('id:')) { lastEventId = line.replace(/^id:\s*/, ''); } else if (line.startsWith('retry:')) { - const parsed = Number.parseInt( - line.replace(/^retry:\s*/, ''), - 10, - ); + const parsed = Number.parseInt(line.replace(/^retry:\s*/, ''), 10); if (!Number.isNaN(parsed)) { retryDelay = parsed; } @@ -243,18 +226,12 @@ export const createSseClient = ({ // connection failed or aborted; retry after delay onSseError?.(error); - if ( - sseMaxRetryAttempts !== undefined && - attempt >= sseMaxRetryAttempts - ) { + if (sseMaxRetryAttempts !== undefined && attempt >= sseMaxRetryAttempts) { break; // stop after firing error } // exponential backoff: double retry each attempt, cap at 30s - const backoff = Math.min( - retryDelay * 2 ** (attempt - 1), - sseMaxRetryDelay ?? 30000, - ); + const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 30000); await sleep(backoff); } } diff --git a/frontend/src/lib/api/core/types.gen.ts b/frontend/src/lib/api/core/types.gen.ts index 643c070c..97463257 100644 --- a/frontend/src/lib/api/core/types.gen.ts +++ b/frontend/src/lib/api/core/types.gen.ts @@ -1,11 +1,7 @@ // This file is auto-generated by @hey-api/openapi-ts import type { Auth, AuthToken } from './auth.gen'; -import type { - BodySerializer, - QuerySerializer, - QuerySerializerOptions, -} from './bodySerializer.gen'; +import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from './bodySerializer.gen'; export type HttpMethod = | 'connect' @@ -34,9 +30,7 @@ export type Client< setConfig: (config: Config) => Config; } & { [K in HttpMethod]: MethodFn; -} & ([SseFn] extends [never] - ? { sse?: never } - : { sse: { [K in HttpMethod]: SseFn } }); +} & ([SseFn] extends [never] ? { sse?: never } : { sse: { [K in HttpMethod]: SseFn } }); export interface Config { /** @@ -59,13 +53,7 @@ export interface Config { | RequestInit['headers'] | Record< string, - | string - | number - | boolean - | (string | number | boolean)[] - | null - | undefined - | unknown + string | number | boolean | (string | number | boolean)[] | null | undefined | unknown >; /** * The request method. @@ -112,7 +100,5 @@ type IsExactlyNeverOrNeverUndefined = [T] extends [never] : false; export type OmitNever> = { - [K in keyof T as IsExactlyNeverOrNeverUndefined extends true - ? never - : K]: T[K]; + [K in keyof T as IsExactlyNeverOrNeverUndefined extends true ? never : K]: T[K]; }; diff --git a/frontend/src/lib/api/core/utils.gen.ts b/frontend/src/lib/api/core/utils.gen.ts index 0b5389d0..e7ddbe35 100644 --- a/frontend/src/lib/api/core/utils.gen.ts +++ b/frontend/src/lib/api/core/utils.gen.ts @@ -44,10 +44,7 @@ export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { } if (Array.isArray(value)) { - url = url.replace( - match, - serializeArrayParam({ explode, name, style, value }), - ); + url = url.replace(match, serializeArrayParam({ explode, name, style, value })); continue; } diff --git a/frontend/src/lib/api/index.ts b/frontend/src/lib/api/index.ts index c355c8d6..41bcbfc2 100644 --- a/frontend/src/lib/api/index.ts +++ b/frontend/src/lib/api/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts export { browseEventsApiV1AdminEventsBrowsePost, cancelExecutionApiV1ExecutionsExecutionIdCancelPost, cancelReplaySessionApiV1ReplaySessionsSessionIdCancelPost, cancelSagaApiV1SagasSagaIdCancelPost, cleanupOldSessionsApiV1ReplayCleanupPost, createExecutionApiV1ExecutePost, createReplaySessionApiV1ReplaySessionsPost, createSavedScriptApiV1ScriptsPost, createUserApiV1AdminUsersPost, deleteEventApiV1AdminEventsEventIdDelete, deleteExecutionApiV1ExecutionsExecutionIdDelete, deleteNotificationApiV1NotificationsNotificationIdDelete, deleteSavedScriptApiV1ScriptsScriptIdDelete, deleteUserApiV1AdminUsersUserIdDelete, discardDlqMessageApiV1DlqMessagesEventIdDelete, executionEventsApiV1EventsExecutionsExecutionIdGet, exportEventsApiV1AdminEventsExportExportFormatGet, getCurrentUserProfileApiV1AuthMeGet, getDlqMessageApiV1DlqMessagesEventIdGet, getDlqMessagesApiV1DlqMessagesGet, getDlqTopicsApiV1DlqTopicsGet, getEventDetailApiV1AdminEventsEventIdGet, getEventStatsApiV1AdminEventsStatsGet, getExampleScriptsApiV1ExampleScriptsGet, getExecutionEventsApiV1ExecutionsExecutionIdEventsGet, getExecutionSagasApiV1SagasExecutionExecutionIdGet, getK8sResourceLimitsApiV1K8sLimitsGet, getNotificationsApiV1NotificationsGet, getReplaySessionApiV1ReplaySessionsSessionIdGet, getReplayStatusApiV1AdminEventsReplaySessionIdStatusGet, getResultApiV1ExecutionsExecutionIdResultGet, getSagaStatusApiV1SagasSagaIdGet, getSavedScriptApiV1ScriptsScriptIdGet, getSettingsHistoryApiV1UserSettingsHistoryGet, getSubscriptionsApiV1NotificationsSubscriptionsGet, getSystemSettingsApiV1AdminSettingsGet, getUnreadCountApiV1NotificationsUnreadCountGet, getUserApiV1AdminUsersUserIdGet, getUserExecutionsApiV1UserExecutionsGet, getUserOverviewApiV1AdminUsersUserIdOverviewGet, getUserRateLimitsApiV1AdminUsersUserIdRateLimitsGet, getUserSettingsApiV1UserSettingsGet, listReplaySessionsApiV1ReplaySessionsGet, listSagasApiV1SagasGet, listSavedScriptsApiV1ScriptsGet, listUsersApiV1AdminUsersGet, livenessApiV1HealthLiveGet, loginApiV1AuthLoginPost, logoutApiV1AuthLogoutPost, markAllReadApiV1NotificationsMarkAllReadPost, markNotificationReadApiV1NotificationsNotificationIdReadPut, notificationStreamApiV1EventsNotificationsStreamGet, type Options, pauseReplaySessionApiV1ReplaySessionsSessionIdPausePost, registerApiV1AuthRegisterPost, replayEventsApiV1AdminEventsReplayPost, resetSystemSettingsApiV1AdminSettingsResetPost, resetUserPasswordApiV1AdminUsersUserIdResetPasswordPost, resetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPost, restoreSettingsApiV1UserSettingsRestorePost, resumeReplaySessionApiV1ReplaySessionsSessionIdResumePost, retryDlqMessagesApiV1DlqRetryPost, retryExecutionApiV1ExecutionsExecutionIdRetryPost, setRetryPolicyApiV1DlqRetryPolicyPost, startReplaySessionApiV1ReplaySessionsSessionIdStartPost, unlockUserApiV1AdminUsersUserIdUnlockPost, updateCustomSettingApiV1UserSettingsCustomKeyPut, updateEditorSettingsApiV1UserSettingsEditorPut, updateNotificationSettingsApiV1UserSettingsNotificationsPut, updateSavedScriptApiV1ScriptsScriptIdPut, updateSubscriptionApiV1NotificationsSubscriptionsChannelPut, updateSystemSettingsApiV1AdminSettingsPut, updateThemeApiV1UserSettingsThemePut, updateUserApiV1AdminUsersUserIdPut, updateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPut, updateUserSettingsApiV1UserSettingsPut } from './sdk.gen'; -export type { AdminUserOverview, AllocateResourcesCommandEvent, AuthFailedEvent, BodyLoginApiV1AuthLoginPost, BrowseEventsApiV1AdminEventsBrowsePostData, BrowseEventsApiV1AdminEventsBrowsePostError, BrowseEventsApiV1AdminEventsBrowsePostErrors, BrowseEventsApiV1AdminEventsBrowsePostResponse, BrowseEventsApiV1AdminEventsBrowsePostResponses, CancelExecutionApiV1ExecutionsExecutionIdCancelPostData, CancelExecutionApiV1ExecutionsExecutionIdCancelPostError, CancelExecutionApiV1ExecutionsExecutionIdCancelPostErrors, CancelExecutionApiV1ExecutionsExecutionIdCancelPostResponse, CancelExecutionApiV1ExecutionsExecutionIdCancelPostResponses, CancelExecutionRequest, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostData, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostError, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostErrors, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostResponse, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostResponses, CancelResponse, CancelSagaApiV1SagasSagaIdCancelPostData, CancelSagaApiV1SagasSagaIdCancelPostError, CancelSagaApiV1SagasSagaIdCancelPostErrors, CancelSagaApiV1SagasSagaIdCancelPostResponse, CancelSagaApiV1SagasSagaIdCancelPostResponses, CancelStatus, CleanupOldSessionsApiV1ReplayCleanupPostData, CleanupOldSessionsApiV1ReplayCleanupPostError, CleanupOldSessionsApiV1ReplayCleanupPostErrors, CleanupOldSessionsApiV1ReplayCleanupPostResponse, CleanupOldSessionsApiV1ReplayCleanupPostResponses, CleanupResponse, ClientOptions, ContainerStatusInfo, CreateExecutionApiV1ExecutePostData, CreateExecutionApiV1ExecutePostError, CreateExecutionApiV1ExecutePostErrors, CreateExecutionApiV1ExecutePostResponse, CreateExecutionApiV1ExecutePostResponses, CreatePodCommandEvent, CreateReplaySessionApiV1ReplaySessionsPostData, CreateReplaySessionApiV1ReplaySessionsPostError, CreateReplaySessionApiV1ReplaySessionsPostErrors, CreateReplaySessionApiV1ReplaySessionsPostResponse, CreateReplaySessionApiV1ReplaySessionsPostResponses, CreateSavedScriptApiV1ScriptsPostData, CreateSavedScriptApiV1ScriptsPostError, CreateSavedScriptApiV1ScriptsPostErrors, CreateSavedScriptApiV1ScriptsPostResponse, CreateSavedScriptApiV1ScriptsPostResponses, CreateUserApiV1AdminUsersPostData, CreateUserApiV1AdminUsersPostError, CreateUserApiV1AdminUsersPostErrors, CreateUserApiV1AdminUsersPostResponse, CreateUserApiV1AdminUsersPostResponses, DeleteEventApiV1AdminEventsEventIdDeleteData, DeleteEventApiV1AdminEventsEventIdDeleteError, DeleteEventApiV1AdminEventsEventIdDeleteErrors, DeleteEventApiV1AdminEventsEventIdDeleteResponse, DeleteEventApiV1AdminEventsEventIdDeleteResponses, DeleteExecutionApiV1ExecutionsExecutionIdDeleteData, DeleteExecutionApiV1ExecutionsExecutionIdDeleteError, DeleteExecutionApiV1ExecutionsExecutionIdDeleteErrors, DeleteExecutionApiV1ExecutionsExecutionIdDeleteResponse, DeleteExecutionApiV1ExecutionsExecutionIdDeleteResponses, DeleteNotificationApiV1NotificationsNotificationIdDeleteData, DeleteNotificationApiV1NotificationsNotificationIdDeleteError, DeleteNotificationApiV1NotificationsNotificationIdDeleteErrors, DeleteNotificationApiV1NotificationsNotificationIdDeleteResponse, DeleteNotificationApiV1NotificationsNotificationIdDeleteResponses, DeleteNotificationResponse, DeletePodCommandEvent, DeleteResponse, DeleteSavedScriptApiV1ScriptsScriptIdDeleteData, DeleteSavedScriptApiV1ScriptsScriptIdDeleteError, DeleteSavedScriptApiV1ScriptsScriptIdDeleteErrors, DeleteSavedScriptApiV1ScriptsScriptIdDeleteResponse, DeleteSavedScriptApiV1ScriptsScriptIdDeleteResponses, DeleteUserApiV1AdminUsersUserIdDeleteData, DeleteUserApiV1AdminUsersUserIdDeleteError, DeleteUserApiV1AdminUsersUserIdDeleteErrors, DeleteUserApiV1AdminUsersUserIdDeleteResponse, DeleteUserApiV1AdminUsersUserIdDeleteResponses, DeleteUserResponse, DerivedCounts, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteData, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteError, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteErrors, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponse, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponses, DlqBatchRetryResponse, DlqMessageDetail, DlqMessageDiscardedEvent, DlqMessageReceivedEvent, DlqMessageResponse, DlqMessageRetriedEvent, DlqMessagesResponse, DlqMessageStatus, DlqRetryResult, DlqTopicSummaryResponse, EditorSettings, EndpointGroup, EndpointUsageStats, Environment, ErrorResponse, EventBrowseRequest, EventBrowseResponse, EventDeleteResponse, EventDetailResponse, EventFilter, EventMetadata, EventReplayRequest, EventReplayResponse, EventReplayStatusResponse, EventReplayStatusResponseWritable, EventStatistics, EventStatsResponse, EventSummary, EventType, EventTypeCount, ExampleScripts, ExecutionAcceptedEvent, ExecutionCancelledEvent, ExecutionCompletedEvent, ExecutionErrorType, ExecutionEventsApiV1EventsExecutionsExecutionIdGetData, ExecutionEventsApiV1EventsExecutionsExecutionIdGetError, ExecutionEventsApiV1EventsExecutionsExecutionIdGetErrors, ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponse, ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponses, ExecutionFailedEvent, ExecutionListResponse, ExecutionQueuedEvent, ExecutionRequest, ExecutionRequestedEvent, ExecutionResponse, ExecutionResult, ExecutionRunningEvent, ExecutionStartedEvent, ExecutionStatus, ExecutionTimeoutEvent, ExportEventsApiV1AdminEventsExportExportFormatGetData, ExportEventsApiV1AdminEventsExportExportFormatGetError, ExportEventsApiV1AdminEventsExportExportFormatGetErrors, ExportEventsApiV1AdminEventsExportExportFormatGetResponses, ExportFormat, GetCurrentUserProfileApiV1AuthMeGetData, GetCurrentUserProfileApiV1AuthMeGetResponse, GetCurrentUserProfileApiV1AuthMeGetResponses, GetDlqMessageApiV1DlqMessagesEventIdGetData, GetDlqMessageApiV1DlqMessagesEventIdGetError, GetDlqMessageApiV1DlqMessagesEventIdGetErrors, GetDlqMessageApiV1DlqMessagesEventIdGetResponse, GetDlqMessageApiV1DlqMessagesEventIdGetResponses, GetDlqMessagesApiV1DlqMessagesGetData, GetDlqMessagesApiV1DlqMessagesGetError, GetDlqMessagesApiV1DlqMessagesGetErrors, GetDlqMessagesApiV1DlqMessagesGetResponse, GetDlqMessagesApiV1DlqMessagesGetResponses, GetDlqTopicsApiV1DlqTopicsGetData, GetDlqTopicsApiV1DlqTopicsGetResponse, GetDlqTopicsApiV1DlqTopicsGetResponses, GetEventDetailApiV1AdminEventsEventIdGetData, GetEventDetailApiV1AdminEventsEventIdGetError, GetEventDetailApiV1AdminEventsEventIdGetErrors, GetEventDetailApiV1AdminEventsEventIdGetResponse, GetEventDetailApiV1AdminEventsEventIdGetResponses, GetEventStatsApiV1AdminEventsStatsGetData, GetEventStatsApiV1AdminEventsStatsGetError, GetEventStatsApiV1AdminEventsStatsGetErrors, GetEventStatsApiV1AdminEventsStatsGetResponse, GetEventStatsApiV1AdminEventsStatsGetResponses, GetExampleScriptsApiV1ExampleScriptsGetData, GetExampleScriptsApiV1ExampleScriptsGetResponse, GetExampleScriptsApiV1ExampleScriptsGetResponses, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetData, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetError, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetErrors, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetResponse, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetResponses, GetExecutionSagasApiV1SagasExecutionExecutionIdGetData, GetExecutionSagasApiV1SagasExecutionExecutionIdGetError, GetExecutionSagasApiV1SagasExecutionExecutionIdGetErrors, GetExecutionSagasApiV1SagasExecutionExecutionIdGetResponse, GetExecutionSagasApiV1SagasExecutionExecutionIdGetResponses, GetK8sResourceLimitsApiV1K8sLimitsGetData, GetK8sResourceLimitsApiV1K8sLimitsGetResponse, GetK8sResourceLimitsApiV1K8sLimitsGetResponses, GetNotificationsApiV1NotificationsGetData, GetNotificationsApiV1NotificationsGetError, GetNotificationsApiV1NotificationsGetErrors, GetNotificationsApiV1NotificationsGetResponse, GetNotificationsApiV1NotificationsGetResponses, GetReplaySessionApiV1ReplaySessionsSessionIdGetData, GetReplaySessionApiV1ReplaySessionsSessionIdGetError, GetReplaySessionApiV1ReplaySessionsSessionIdGetErrors, GetReplaySessionApiV1ReplaySessionsSessionIdGetResponse, GetReplaySessionApiV1ReplaySessionsSessionIdGetResponses, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetData, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetError, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetErrors, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetResponse, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetResponses, GetResultApiV1ExecutionsExecutionIdResultGetData, GetResultApiV1ExecutionsExecutionIdResultGetError, GetResultApiV1ExecutionsExecutionIdResultGetErrors, GetResultApiV1ExecutionsExecutionIdResultGetResponse, GetResultApiV1ExecutionsExecutionIdResultGetResponses, GetSagaStatusApiV1SagasSagaIdGetData, GetSagaStatusApiV1SagasSagaIdGetError, GetSagaStatusApiV1SagasSagaIdGetErrors, GetSagaStatusApiV1SagasSagaIdGetResponse, GetSagaStatusApiV1SagasSagaIdGetResponses, GetSavedScriptApiV1ScriptsScriptIdGetData, GetSavedScriptApiV1ScriptsScriptIdGetError, GetSavedScriptApiV1ScriptsScriptIdGetErrors, GetSavedScriptApiV1ScriptsScriptIdGetResponse, GetSavedScriptApiV1ScriptsScriptIdGetResponses, GetSettingsHistoryApiV1UserSettingsHistoryGetData, GetSettingsHistoryApiV1UserSettingsHistoryGetError, GetSettingsHistoryApiV1UserSettingsHistoryGetErrors, GetSettingsHistoryApiV1UserSettingsHistoryGetResponse, GetSettingsHistoryApiV1UserSettingsHistoryGetResponses, GetSubscriptionsApiV1NotificationsSubscriptionsGetData, GetSubscriptionsApiV1NotificationsSubscriptionsGetResponse, GetSubscriptionsApiV1NotificationsSubscriptionsGetResponses, GetSystemSettingsApiV1AdminSettingsGetData, GetSystemSettingsApiV1AdminSettingsGetError, GetSystemSettingsApiV1AdminSettingsGetErrors, GetSystemSettingsApiV1AdminSettingsGetResponse, GetSystemSettingsApiV1AdminSettingsGetResponses, GetUnreadCountApiV1NotificationsUnreadCountGetData, GetUnreadCountApiV1NotificationsUnreadCountGetResponse, GetUnreadCountApiV1NotificationsUnreadCountGetResponses, GetUserApiV1AdminUsersUserIdGetData, GetUserApiV1AdminUsersUserIdGetError, GetUserApiV1AdminUsersUserIdGetErrors, GetUserApiV1AdminUsersUserIdGetResponse, GetUserApiV1AdminUsersUserIdGetResponses, GetUserExecutionsApiV1UserExecutionsGetData, GetUserExecutionsApiV1UserExecutionsGetError, GetUserExecutionsApiV1UserExecutionsGetErrors, GetUserExecutionsApiV1UserExecutionsGetResponse, GetUserExecutionsApiV1UserExecutionsGetResponses, GetUserOverviewApiV1AdminUsersUserIdOverviewGetData, GetUserOverviewApiV1AdminUsersUserIdOverviewGetError, GetUserOverviewApiV1AdminUsersUserIdOverviewGetErrors, GetUserOverviewApiV1AdminUsersUserIdOverviewGetResponse, GetUserOverviewApiV1AdminUsersUserIdOverviewGetResponses, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetData, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetError, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetErrors, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetResponse, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetResponses, GetUserSettingsApiV1UserSettingsGetData, GetUserSettingsApiV1UserSettingsGetResponse, GetUserSettingsApiV1UserSettingsGetResponses, HourlyEventCount, HttpValidationError, KafkaTopic, LanguageInfo, ListReplaySessionsApiV1ReplaySessionsGetData, ListReplaySessionsApiV1ReplaySessionsGetError, ListReplaySessionsApiV1ReplaySessionsGetErrors, ListReplaySessionsApiV1ReplaySessionsGetResponse, ListReplaySessionsApiV1ReplaySessionsGetResponses, ListSagasApiV1SagasGetData, ListSagasApiV1SagasGetError, ListSagasApiV1SagasGetErrors, ListSagasApiV1SagasGetResponse, ListSagasApiV1SagasGetResponses, ListSavedScriptsApiV1ScriptsGetData, ListSavedScriptsApiV1ScriptsGetResponse, ListSavedScriptsApiV1ScriptsGetResponses, ListUsersApiV1AdminUsersGetData, ListUsersApiV1AdminUsersGetError, ListUsersApiV1AdminUsersGetErrors, ListUsersApiV1AdminUsersGetResponse, ListUsersApiV1AdminUsersGetResponses, LivenessApiV1HealthLiveGetData, LivenessApiV1HealthLiveGetResponse, LivenessApiV1HealthLiveGetResponses, LivenessResponse, LoginApiV1AuthLoginPostData, LoginApiV1AuthLoginPostError, LoginApiV1AuthLoginPostErrors, LoginApiV1AuthLoginPostResponse, LoginApiV1AuthLoginPostResponses, LoginMethod, LoginResponse, LogLevel, LogoutApiV1AuthLogoutPostData, LogoutApiV1AuthLogoutPostResponse, LogoutApiV1AuthLogoutPostResponses, ManualRetryRequest, MarkAllReadApiV1NotificationsMarkAllReadPostData, MarkAllReadApiV1NotificationsMarkAllReadPostResponse, MarkAllReadApiV1NotificationsMarkAllReadPostResponses, MarkNotificationReadApiV1NotificationsNotificationIdReadPutData, MarkNotificationReadApiV1NotificationsNotificationIdReadPutError, MarkNotificationReadApiV1NotificationsNotificationIdReadPutErrors, MarkNotificationReadApiV1NotificationsNotificationIdReadPutResponse, MarkNotificationReadApiV1NotificationsNotificationIdReadPutResponses, MessageResponse, NotificationAllReadEvent, NotificationChannel, NotificationClickedEvent, NotificationCreatedEvent, NotificationDeliveredEvent, NotificationFailedEvent, NotificationListResponse, NotificationPreferencesUpdatedEvent, NotificationReadEvent, NotificationResponse, NotificationSentEvent, NotificationSettings, NotificationSeverity, NotificationStatus, NotificationStreamApiV1EventsNotificationsStreamGetData, NotificationStreamApiV1EventsNotificationsStreamGetResponse, NotificationStreamApiV1EventsNotificationsStreamGetResponses, NotificationSubscription, PasswordResetRequest, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostData, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostError, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostErrors, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostResponse, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostResponses, PodCreatedEvent, PodDeletedEvent, PodFailedEvent, PodRunningEvent, PodScheduledEvent, PodSucceededEvent, PodTerminatedEvent, QueuePriority, QuotaExceededEvent, RateLimitAlgorithm, RateLimitExceededEvent, RateLimitRuleRequest, RateLimitRuleResponse, RateLimitSummary, RateLimitUpdateRequest, RateLimitUpdateResponse, RegisterApiV1AuthRegisterPostData, RegisterApiV1AuthRegisterPostError, RegisterApiV1AuthRegisterPostErrors, RegisterApiV1AuthRegisterPostResponse, RegisterApiV1AuthRegisterPostResponses, ReleaseResourcesCommandEvent, ReplayConfigSchema, ReplayError, ReplayEventsApiV1AdminEventsReplayPostData, ReplayEventsApiV1AdminEventsReplayPostError, ReplayEventsApiV1AdminEventsReplayPostErrors, ReplayEventsApiV1AdminEventsReplayPostResponse, ReplayEventsApiV1AdminEventsReplayPostResponses, ReplayFilter, ReplayFilterSchema, ReplayRequest, ReplayResponse, ReplaySession, ReplayStatus, ReplayTarget, ReplayType, ResetSystemSettingsApiV1AdminSettingsResetPostData, ResetSystemSettingsApiV1AdminSettingsResetPostError, ResetSystemSettingsApiV1AdminSettingsResetPostErrors, ResetSystemSettingsApiV1AdminSettingsResetPostResponse, ResetSystemSettingsApiV1AdminSettingsResetPostResponses, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostData, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostError, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostErrors, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostResponse, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostResponses, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostData, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostError, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostErrors, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostResponse, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostResponses, ResourceLimitExceededEvent, ResourceLimits, ResourceUsage, ResourceUsageDomain, RestoreSettingsApiV1UserSettingsRestorePostData, RestoreSettingsApiV1UserSettingsRestorePostError, RestoreSettingsApiV1UserSettingsRestorePostErrors, RestoreSettingsApiV1UserSettingsRestorePostResponse, RestoreSettingsApiV1UserSettingsRestorePostResponses, RestoreSettingsRequest, ResultFailedEvent, ResultStoredEvent, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostData, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostError, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostErrors, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostResponse, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostResponses, RetryDlqMessagesApiV1DlqRetryPostData, RetryDlqMessagesApiV1DlqRetryPostError, RetryDlqMessagesApiV1DlqRetryPostErrors, RetryDlqMessagesApiV1DlqRetryPostResponse, RetryDlqMessagesApiV1DlqRetryPostResponses, RetryExecutionApiV1ExecutionsExecutionIdRetryPostData, RetryExecutionApiV1ExecutionsExecutionIdRetryPostError, RetryExecutionApiV1ExecutionsExecutionIdRetryPostErrors, RetryExecutionApiV1ExecutionsExecutionIdRetryPostResponse, RetryExecutionApiV1ExecutionsExecutionIdRetryPostResponses, RetryPolicyRequest, RetryStrategy, SagaCancellationResponse, SagaCancelledEvent, SagaCompensatedEvent, SagaCompensatingEvent, SagaCompletedEvent, SagaFailedEvent, SagaListResponse, SagaStartedEvent, SagaState, SagaStatusResponse, SavedScriptCreateRequest, SavedScriptListResponse, SavedScriptResponse, SavedScriptUpdate, ScriptDeletedEvent, ScriptSavedEvent, ScriptSharedEvent, SecurityViolationEvent, ServiceEventCount, ServiceRecoveredEvent, ServiceUnhealthyEvent, SessionConfigSummary, SessionSummary, SessionSummaryWritable, SetRetryPolicyApiV1DlqRetryPolicyPostData, SetRetryPolicyApiV1DlqRetryPolicyPostError, SetRetryPolicyApiV1DlqRetryPolicyPostErrors, SetRetryPolicyApiV1DlqRetryPolicyPostResponse, SetRetryPolicyApiV1DlqRetryPolicyPostResponses, SettingsHistoryEntry, SettingsHistoryResponse, SseControlEvent, SseExecutionEventData, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostData, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostError, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostErrors, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostResponse, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostResponses, StorageType, SubscriptionsResponse, SubscriptionUpdate, SystemErrorEvent, SystemSettingsSchema, Theme, ThemeUpdateRequest, UnlockResponse, UnlockUserApiV1AdminUsersUserIdUnlockPostData, UnlockUserApiV1AdminUsersUserIdUnlockPostError, UnlockUserApiV1AdminUsersUserIdUnlockPostErrors, UnlockUserApiV1AdminUsersUserIdUnlockPostResponse, UnlockUserApiV1AdminUsersUserIdUnlockPostResponses, UnreadCountResponse, UpdateCustomSettingApiV1UserSettingsCustomKeyPutData, UpdateCustomSettingApiV1UserSettingsCustomKeyPutError, UpdateCustomSettingApiV1UserSettingsCustomKeyPutErrors, UpdateCustomSettingApiV1UserSettingsCustomKeyPutResponse, UpdateCustomSettingApiV1UserSettingsCustomKeyPutResponses, UpdateEditorSettingsApiV1UserSettingsEditorPutData, UpdateEditorSettingsApiV1UserSettingsEditorPutError, UpdateEditorSettingsApiV1UserSettingsEditorPutErrors, UpdateEditorSettingsApiV1UserSettingsEditorPutResponse, UpdateEditorSettingsApiV1UserSettingsEditorPutResponses, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutData, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutError, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutErrors, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutResponse, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutResponses, UpdateSavedScriptApiV1ScriptsScriptIdPutData, UpdateSavedScriptApiV1ScriptsScriptIdPutError, UpdateSavedScriptApiV1ScriptsScriptIdPutErrors, UpdateSavedScriptApiV1ScriptsScriptIdPutResponse, UpdateSavedScriptApiV1ScriptsScriptIdPutResponses, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutData, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutError, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutErrors, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutResponse, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutResponses, UpdateSystemSettingsApiV1AdminSettingsPutData, UpdateSystemSettingsApiV1AdminSettingsPutError, UpdateSystemSettingsApiV1AdminSettingsPutErrors, UpdateSystemSettingsApiV1AdminSettingsPutResponse, UpdateSystemSettingsApiV1AdminSettingsPutResponses, UpdateThemeApiV1UserSettingsThemePutData, UpdateThemeApiV1UserSettingsThemePutError, UpdateThemeApiV1UserSettingsThemePutErrors, UpdateThemeApiV1UserSettingsThemePutResponse, UpdateThemeApiV1UserSettingsThemePutResponses, UpdateUserApiV1AdminUsersUserIdPutData, UpdateUserApiV1AdminUsersUserIdPutError, UpdateUserApiV1AdminUsersUserIdPutErrors, UpdateUserApiV1AdminUsersUserIdPutResponse, UpdateUserApiV1AdminUsersUserIdPutResponses, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutData, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutError, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutErrors, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutResponse, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutResponses, UpdateUserSettingsApiV1UserSettingsPutData, UpdateUserSettingsApiV1UserSettingsPutError, UpdateUserSettingsApiV1UserSettingsPutErrors, UpdateUserSettingsApiV1UserSettingsPutResponse, UpdateUserSettingsApiV1UserSettingsPutResponses, UserCreate, UserDeletedEvent, UserEventCount, UserListResponse, UserLoggedInEvent, UserLoggedOutEvent, UserLoginEvent, UserRateLimitConfigResponse, UserRateLimitsResponse, UserRegisteredEvent, UserResponse, UserRole, UserSettings, UserSettingsUpdate, UserSettingsUpdatedEvent, UserUpdate, UserUpdatedEvent, ValidationError } from './types.gen'; +export type { AdminUserOverview, AllocateResourcesCommandEvent, AuthFailedEvent, BodyLoginApiV1AuthLoginPost, BrowseEventsApiV1AdminEventsBrowsePostData, BrowseEventsApiV1AdminEventsBrowsePostError, BrowseEventsApiV1AdminEventsBrowsePostErrors, BrowseEventsApiV1AdminEventsBrowsePostResponse, BrowseEventsApiV1AdminEventsBrowsePostResponses, CancelExecutionApiV1ExecutionsExecutionIdCancelPostData, CancelExecutionApiV1ExecutionsExecutionIdCancelPostError, CancelExecutionApiV1ExecutionsExecutionIdCancelPostErrors, CancelExecutionApiV1ExecutionsExecutionIdCancelPostResponse, CancelExecutionApiV1ExecutionsExecutionIdCancelPostResponses, CancelExecutionRequest, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostData, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostError, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostErrors, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostResponse, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostResponses, CancelResponse, CancelSagaApiV1SagasSagaIdCancelPostData, CancelSagaApiV1SagasSagaIdCancelPostError, CancelSagaApiV1SagasSagaIdCancelPostErrors, CancelSagaApiV1SagasSagaIdCancelPostResponse, CancelSagaApiV1SagasSagaIdCancelPostResponses, CancelStatus, CleanupOldSessionsApiV1ReplayCleanupPostData, CleanupOldSessionsApiV1ReplayCleanupPostError, CleanupOldSessionsApiV1ReplayCleanupPostErrors, CleanupOldSessionsApiV1ReplayCleanupPostResponse, CleanupOldSessionsApiV1ReplayCleanupPostResponses, CleanupResponse, ClientOptions, ContainerStatusInfo, CreateExecutionApiV1ExecutePostData, CreateExecutionApiV1ExecutePostError, CreateExecutionApiV1ExecutePostErrors, CreateExecutionApiV1ExecutePostResponse, CreateExecutionApiV1ExecutePostResponses, CreatePodCommandEvent, CreateReplaySessionApiV1ReplaySessionsPostData, CreateReplaySessionApiV1ReplaySessionsPostError, CreateReplaySessionApiV1ReplaySessionsPostErrors, CreateReplaySessionApiV1ReplaySessionsPostResponse, CreateReplaySessionApiV1ReplaySessionsPostResponses, CreateSavedScriptApiV1ScriptsPostData, CreateSavedScriptApiV1ScriptsPostError, CreateSavedScriptApiV1ScriptsPostErrors, CreateSavedScriptApiV1ScriptsPostResponse, CreateSavedScriptApiV1ScriptsPostResponses, CreateUserApiV1AdminUsersPostData, CreateUserApiV1AdminUsersPostError, CreateUserApiV1AdminUsersPostErrors, CreateUserApiV1AdminUsersPostResponse, CreateUserApiV1AdminUsersPostResponses, DeleteEventApiV1AdminEventsEventIdDeleteData, DeleteEventApiV1AdminEventsEventIdDeleteError, DeleteEventApiV1AdminEventsEventIdDeleteErrors, DeleteEventApiV1AdminEventsEventIdDeleteResponse, DeleteEventApiV1AdminEventsEventIdDeleteResponses, DeleteExecutionApiV1ExecutionsExecutionIdDeleteData, DeleteExecutionApiV1ExecutionsExecutionIdDeleteError, DeleteExecutionApiV1ExecutionsExecutionIdDeleteErrors, DeleteExecutionApiV1ExecutionsExecutionIdDeleteResponse, DeleteExecutionApiV1ExecutionsExecutionIdDeleteResponses, DeleteNotificationApiV1NotificationsNotificationIdDeleteData, DeleteNotificationApiV1NotificationsNotificationIdDeleteError, DeleteNotificationApiV1NotificationsNotificationIdDeleteErrors, DeleteNotificationApiV1NotificationsNotificationIdDeleteResponse, DeleteNotificationApiV1NotificationsNotificationIdDeleteResponses, DeleteNotificationResponse, DeletePodCommandEvent, DeleteResponse, DeleteSavedScriptApiV1ScriptsScriptIdDeleteData, DeleteSavedScriptApiV1ScriptsScriptIdDeleteError, DeleteSavedScriptApiV1ScriptsScriptIdDeleteErrors, DeleteSavedScriptApiV1ScriptsScriptIdDeleteResponse, DeleteSavedScriptApiV1ScriptsScriptIdDeleteResponses, DeleteUserApiV1AdminUsersUserIdDeleteData, DeleteUserApiV1AdminUsersUserIdDeleteError, DeleteUserApiV1AdminUsersUserIdDeleteErrors, DeleteUserApiV1AdminUsersUserIdDeleteResponse, DeleteUserApiV1AdminUsersUserIdDeleteResponses, DeleteUserResponse, DerivedCounts, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteData, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteError, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteErrors, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponse, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponses, DlqBatchRetryResponse, DlqMessageDetail, DlqMessageDiscardedEvent, DlqMessageReceivedEvent, DlqMessageResponse, DlqMessageRetriedEvent, DlqMessagesResponse, DlqMessageStatus, DlqRetryResult, DlqTopicSummaryResponse, EditorSettings, EndpointGroup, EndpointUsageStats, Environment, ErrorResponse, EventBrowseRequest, EventBrowseResponse, EventDeleteResponse, EventDetailResponse, EventFilter, EventMetadata, EventReplayRequest, EventReplayResponse, EventReplayStatusResponse, EventReplayStatusResponseWritable, EventStatistics, EventStatsResponse, EventSummary, EventType, EventTypeCount, ExampleScripts, ExecutionAcceptedEvent, ExecutionCancelledEvent, ExecutionCompletedEvent, ExecutionErrorType, ExecutionEventsApiV1EventsExecutionsExecutionIdGetData, ExecutionEventsApiV1EventsExecutionsExecutionIdGetError, ExecutionEventsApiV1EventsExecutionsExecutionIdGetErrors, ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponse, ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponses, ExecutionFailedEvent, ExecutionListResponse, ExecutionQueuedEvent, ExecutionRequest, ExecutionRequestedEvent, ExecutionResponse, ExecutionResult, ExecutionRunningEvent, ExecutionStartedEvent, ExecutionStatus, ExecutionTimeoutEvent, ExportEventsApiV1AdminEventsExportExportFormatGetData, ExportEventsApiV1AdminEventsExportExportFormatGetError, ExportEventsApiV1AdminEventsExportExportFormatGetErrors, ExportEventsApiV1AdminEventsExportExportFormatGetResponses, ExportFormat, GetCurrentUserProfileApiV1AuthMeGetData, GetCurrentUserProfileApiV1AuthMeGetResponse, GetCurrentUserProfileApiV1AuthMeGetResponses, GetDlqMessageApiV1DlqMessagesEventIdGetData, GetDlqMessageApiV1DlqMessagesEventIdGetError, GetDlqMessageApiV1DlqMessagesEventIdGetErrors, GetDlqMessageApiV1DlqMessagesEventIdGetResponse, GetDlqMessageApiV1DlqMessagesEventIdGetResponses, GetDlqMessagesApiV1DlqMessagesGetData, GetDlqMessagesApiV1DlqMessagesGetError, GetDlqMessagesApiV1DlqMessagesGetErrors, GetDlqMessagesApiV1DlqMessagesGetResponse, GetDlqMessagesApiV1DlqMessagesGetResponses, GetDlqTopicsApiV1DlqTopicsGetData, GetDlqTopicsApiV1DlqTopicsGetResponse, GetDlqTopicsApiV1DlqTopicsGetResponses, GetEventDetailApiV1AdminEventsEventIdGetData, GetEventDetailApiV1AdminEventsEventIdGetError, GetEventDetailApiV1AdminEventsEventIdGetErrors, GetEventDetailApiV1AdminEventsEventIdGetResponse, GetEventDetailApiV1AdminEventsEventIdGetResponses, GetEventStatsApiV1AdminEventsStatsGetData, GetEventStatsApiV1AdminEventsStatsGetError, GetEventStatsApiV1AdminEventsStatsGetErrors, GetEventStatsApiV1AdminEventsStatsGetResponse, GetEventStatsApiV1AdminEventsStatsGetResponses, GetExampleScriptsApiV1ExampleScriptsGetData, GetExampleScriptsApiV1ExampleScriptsGetResponse, GetExampleScriptsApiV1ExampleScriptsGetResponses, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetData, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetError, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetErrors, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetResponse, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetResponses, GetExecutionSagasApiV1SagasExecutionExecutionIdGetData, GetExecutionSagasApiV1SagasExecutionExecutionIdGetError, GetExecutionSagasApiV1SagasExecutionExecutionIdGetErrors, GetExecutionSagasApiV1SagasExecutionExecutionIdGetResponse, GetExecutionSagasApiV1SagasExecutionExecutionIdGetResponses, GetK8sResourceLimitsApiV1K8sLimitsGetData, GetK8sResourceLimitsApiV1K8sLimitsGetResponse, GetK8sResourceLimitsApiV1K8sLimitsGetResponses, GetNotificationsApiV1NotificationsGetData, GetNotificationsApiV1NotificationsGetError, GetNotificationsApiV1NotificationsGetErrors, GetNotificationsApiV1NotificationsGetResponse, GetNotificationsApiV1NotificationsGetResponses, GetReplaySessionApiV1ReplaySessionsSessionIdGetData, GetReplaySessionApiV1ReplaySessionsSessionIdGetError, GetReplaySessionApiV1ReplaySessionsSessionIdGetErrors, GetReplaySessionApiV1ReplaySessionsSessionIdGetResponse, GetReplaySessionApiV1ReplaySessionsSessionIdGetResponses, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetData, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetError, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetErrors, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetResponse, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetResponses, GetResultApiV1ExecutionsExecutionIdResultGetData, GetResultApiV1ExecutionsExecutionIdResultGetError, GetResultApiV1ExecutionsExecutionIdResultGetErrors, GetResultApiV1ExecutionsExecutionIdResultGetResponse, GetResultApiV1ExecutionsExecutionIdResultGetResponses, GetSagaStatusApiV1SagasSagaIdGetData, GetSagaStatusApiV1SagasSagaIdGetError, GetSagaStatusApiV1SagasSagaIdGetErrors, GetSagaStatusApiV1SagasSagaIdGetResponse, GetSagaStatusApiV1SagasSagaIdGetResponses, GetSavedScriptApiV1ScriptsScriptIdGetData, GetSavedScriptApiV1ScriptsScriptIdGetError, GetSavedScriptApiV1ScriptsScriptIdGetErrors, GetSavedScriptApiV1ScriptsScriptIdGetResponse, GetSavedScriptApiV1ScriptsScriptIdGetResponses, GetSettingsHistoryApiV1UserSettingsHistoryGetData, GetSettingsHistoryApiV1UserSettingsHistoryGetError, GetSettingsHistoryApiV1UserSettingsHistoryGetErrors, GetSettingsHistoryApiV1UserSettingsHistoryGetResponse, GetSettingsHistoryApiV1UserSettingsHistoryGetResponses, GetSubscriptionsApiV1NotificationsSubscriptionsGetData, GetSubscriptionsApiV1NotificationsSubscriptionsGetResponse, GetSubscriptionsApiV1NotificationsSubscriptionsGetResponses, GetSystemSettingsApiV1AdminSettingsGetData, GetSystemSettingsApiV1AdminSettingsGetError, GetSystemSettingsApiV1AdminSettingsGetErrors, GetSystemSettingsApiV1AdminSettingsGetResponse, GetSystemSettingsApiV1AdminSettingsGetResponses, GetUnreadCountApiV1NotificationsUnreadCountGetData, GetUnreadCountApiV1NotificationsUnreadCountGetResponse, GetUnreadCountApiV1NotificationsUnreadCountGetResponses, GetUserApiV1AdminUsersUserIdGetData, GetUserApiV1AdminUsersUserIdGetError, GetUserApiV1AdminUsersUserIdGetErrors, GetUserApiV1AdminUsersUserIdGetResponse, GetUserApiV1AdminUsersUserIdGetResponses, GetUserExecutionsApiV1UserExecutionsGetData, GetUserExecutionsApiV1UserExecutionsGetError, GetUserExecutionsApiV1UserExecutionsGetErrors, GetUserExecutionsApiV1UserExecutionsGetResponse, GetUserExecutionsApiV1UserExecutionsGetResponses, GetUserOverviewApiV1AdminUsersUserIdOverviewGetData, GetUserOverviewApiV1AdminUsersUserIdOverviewGetError, GetUserOverviewApiV1AdminUsersUserIdOverviewGetErrors, GetUserOverviewApiV1AdminUsersUserIdOverviewGetResponse, GetUserOverviewApiV1AdminUsersUserIdOverviewGetResponses, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetData, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetError, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetErrors, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetResponse, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetResponses, GetUserSettingsApiV1UserSettingsGetData, GetUserSettingsApiV1UserSettingsGetResponse, GetUserSettingsApiV1UserSettingsGetResponses, HourlyEventCount, HttpValidationError, LanguageInfo, ListReplaySessionsApiV1ReplaySessionsGetData, ListReplaySessionsApiV1ReplaySessionsGetError, ListReplaySessionsApiV1ReplaySessionsGetErrors, ListReplaySessionsApiV1ReplaySessionsGetResponse, ListReplaySessionsApiV1ReplaySessionsGetResponses, ListSagasApiV1SagasGetData, ListSagasApiV1SagasGetError, ListSagasApiV1SagasGetErrors, ListSagasApiV1SagasGetResponse, ListSagasApiV1SagasGetResponses, ListSavedScriptsApiV1ScriptsGetData, ListSavedScriptsApiV1ScriptsGetResponse, ListSavedScriptsApiV1ScriptsGetResponses, ListUsersApiV1AdminUsersGetData, ListUsersApiV1AdminUsersGetError, ListUsersApiV1AdminUsersGetErrors, ListUsersApiV1AdminUsersGetResponse, ListUsersApiV1AdminUsersGetResponses, LivenessApiV1HealthLiveGetData, LivenessApiV1HealthLiveGetResponse, LivenessApiV1HealthLiveGetResponses, LivenessResponse, LoginApiV1AuthLoginPostData, LoginApiV1AuthLoginPostError, LoginApiV1AuthLoginPostErrors, LoginApiV1AuthLoginPostResponse, LoginApiV1AuthLoginPostResponses, LoginMethod, LoginResponse, LogLevel, LogoutApiV1AuthLogoutPostData, LogoutApiV1AuthLogoutPostResponse, LogoutApiV1AuthLogoutPostResponses, ManualRetryRequest, MarkAllReadApiV1NotificationsMarkAllReadPostData, MarkAllReadApiV1NotificationsMarkAllReadPostResponse, MarkAllReadApiV1NotificationsMarkAllReadPostResponses, MarkNotificationReadApiV1NotificationsNotificationIdReadPutData, MarkNotificationReadApiV1NotificationsNotificationIdReadPutError, MarkNotificationReadApiV1NotificationsNotificationIdReadPutErrors, MarkNotificationReadApiV1NotificationsNotificationIdReadPutResponse, MarkNotificationReadApiV1NotificationsNotificationIdReadPutResponses, MessageResponse, NotificationAllReadEvent, NotificationChannel, NotificationClickedEvent, NotificationCreatedEvent, NotificationDeliveredEvent, NotificationFailedEvent, NotificationListResponse, NotificationPreferencesUpdatedEvent, NotificationReadEvent, NotificationResponse, NotificationSentEvent, NotificationSettings, NotificationSeverity, NotificationStatus, NotificationStreamApiV1EventsNotificationsStreamGetData, NotificationStreamApiV1EventsNotificationsStreamGetResponse, NotificationStreamApiV1EventsNotificationsStreamGetResponses, NotificationSubscription, PasswordResetRequest, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostData, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostError, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostErrors, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostResponse, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostResponses, PodCreatedEvent, PodDeletedEvent, PodFailedEvent, PodRunningEvent, PodScheduledEvent, PodSucceededEvent, PodTerminatedEvent, QueuePriority, QuotaExceededEvent, RateLimitAlgorithm, RateLimitExceededEvent, RateLimitRuleRequest, RateLimitRuleResponse, RateLimitSummary, RateLimitUpdateRequest, RateLimitUpdateResponse, RegisterApiV1AuthRegisterPostData, RegisterApiV1AuthRegisterPostError, RegisterApiV1AuthRegisterPostErrors, RegisterApiV1AuthRegisterPostResponse, RegisterApiV1AuthRegisterPostResponses, ReleaseResourcesCommandEvent, ReplayConfigSchema, ReplayError, ReplayEventsApiV1AdminEventsReplayPostData, ReplayEventsApiV1AdminEventsReplayPostError, ReplayEventsApiV1AdminEventsReplayPostErrors, ReplayEventsApiV1AdminEventsReplayPostResponse, ReplayEventsApiV1AdminEventsReplayPostResponses, ReplayFilter, ReplayFilterSchema, ReplayRequest, ReplayResponse, ReplaySession, ReplayStatus, ReplayTarget, ReplayType, ResetSystemSettingsApiV1AdminSettingsResetPostData, ResetSystemSettingsApiV1AdminSettingsResetPostError, ResetSystemSettingsApiV1AdminSettingsResetPostErrors, ResetSystemSettingsApiV1AdminSettingsResetPostResponse, ResetSystemSettingsApiV1AdminSettingsResetPostResponses, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostData, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostError, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostErrors, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostResponse, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostResponses, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostData, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostError, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostErrors, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostResponse, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostResponses, ResourceLimitExceededEvent, ResourceLimits, ResourceUsage, ResourceUsageDomain, RestoreSettingsApiV1UserSettingsRestorePostData, RestoreSettingsApiV1UserSettingsRestorePostError, RestoreSettingsApiV1UserSettingsRestorePostErrors, RestoreSettingsApiV1UserSettingsRestorePostResponse, RestoreSettingsApiV1UserSettingsRestorePostResponses, RestoreSettingsRequest, ResultFailedEvent, ResultStoredEvent, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostData, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostError, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostErrors, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostResponse, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostResponses, RetryDlqMessagesApiV1DlqRetryPostData, RetryDlqMessagesApiV1DlqRetryPostError, RetryDlqMessagesApiV1DlqRetryPostErrors, RetryDlqMessagesApiV1DlqRetryPostResponse, RetryDlqMessagesApiV1DlqRetryPostResponses, RetryExecutionApiV1ExecutionsExecutionIdRetryPostData, RetryExecutionApiV1ExecutionsExecutionIdRetryPostError, RetryExecutionApiV1ExecutionsExecutionIdRetryPostErrors, RetryExecutionApiV1ExecutionsExecutionIdRetryPostResponse, RetryExecutionApiV1ExecutionsExecutionIdRetryPostResponses, RetryPolicyRequest, RetryStrategy, SagaCancellationResponse, SagaCancelledEvent, SagaCompensatedEvent, SagaCompensatingEvent, SagaCompletedEvent, SagaFailedEvent, SagaListResponse, SagaStartedEvent, SagaState, SagaStatusResponse, SavedScriptCreateRequest, SavedScriptListResponse, SavedScriptResponse, SavedScriptUpdate, ScriptDeletedEvent, ScriptSavedEvent, ScriptSharedEvent, SecurityViolationEvent, ServiceEventCount, ServiceRecoveredEvent, ServiceUnhealthyEvent, SessionConfigSummary, SessionSummary, SessionSummaryWritable, SetRetryPolicyApiV1DlqRetryPolicyPostData, SetRetryPolicyApiV1DlqRetryPolicyPostError, SetRetryPolicyApiV1DlqRetryPolicyPostErrors, SetRetryPolicyApiV1DlqRetryPolicyPostResponse, SetRetryPolicyApiV1DlqRetryPolicyPostResponses, SettingsHistoryEntry, SettingsHistoryResponse, SseControlEvent, SseExecutionEventSchema, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostData, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostError, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostErrors, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostResponse, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostResponses, StorageType, SubscriptionsResponse, SubscriptionUpdate, SystemErrorEvent, SystemSettingsSchema, Theme, ThemeUpdateRequest, UnlockResponse, UnlockUserApiV1AdminUsersUserIdUnlockPostData, UnlockUserApiV1AdminUsersUserIdUnlockPostError, UnlockUserApiV1AdminUsersUserIdUnlockPostErrors, UnlockUserApiV1AdminUsersUserIdUnlockPostResponse, UnlockUserApiV1AdminUsersUserIdUnlockPostResponses, UnreadCountResponse, UpdateCustomSettingApiV1UserSettingsCustomKeyPutData, UpdateCustomSettingApiV1UserSettingsCustomKeyPutError, UpdateCustomSettingApiV1UserSettingsCustomKeyPutErrors, UpdateCustomSettingApiV1UserSettingsCustomKeyPutResponse, UpdateCustomSettingApiV1UserSettingsCustomKeyPutResponses, UpdateEditorSettingsApiV1UserSettingsEditorPutData, UpdateEditorSettingsApiV1UserSettingsEditorPutError, UpdateEditorSettingsApiV1UserSettingsEditorPutErrors, UpdateEditorSettingsApiV1UserSettingsEditorPutResponse, UpdateEditorSettingsApiV1UserSettingsEditorPutResponses, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutData, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutError, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutErrors, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutResponse, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutResponses, UpdateSavedScriptApiV1ScriptsScriptIdPutData, UpdateSavedScriptApiV1ScriptsScriptIdPutError, UpdateSavedScriptApiV1ScriptsScriptIdPutErrors, UpdateSavedScriptApiV1ScriptsScriptIdPutResponse, UpdateSavedScriptApiV1ScriptsScriptIdPutResponses, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutData, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutError, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutErrors, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutResponse, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutResponses, UpdateSystemSettingsApiV1AdminSettingsPutData, UpdateSystemSettingsApiV1AdminSettingsPutError, UpdateSystemSettingsApiV1AdminSettingsPutErrors, UpdateSystemSettingsApiV1AdminSettingsPutResponse, UpdateSystemSettingsApiV1AdminSettingsPutResponses, UpdateThemeApiV1UserSettingsThemePutData, UpdateThemeApiV1UserSettingsThemePutError, UpdateThemeApiV1UserSettingsThemePutErrors, UpdateThemeApiV1UserSettingsThemePutResponse, UpdateThemeApiV1UserSettingsThemePutResponses, UpdateUserApiV1AdminUsersUserIdPutData, UpdateUserApiV1AdminUsersUserIdPutError, UpdateUserApiV1AdminUsersUserIdPutErrors, UpdateUserApiV1AdminUsersUserIdPutResponse, UpdateUserApiV1AdminUsersUserIdPutResponses, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutData, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutError, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutErrors, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutResponse, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutResponses, UpdateUserSettingsApiV1UserSettingsPutData, UpdateUserSettingsApiV1UserSettingsPutError, UpdateUserSettingsApiV1UserSettingsPutErrors, UpdateUserSettingsApiV1UserSettingsPutResponse, UpdateUserSettingsApiV1UserSettingsPutResponses, UserCreate, UserDeletedEvent, UserEventCount, UserListResponse, UserLoggedInEvent, UserLoggedOutEvent, UserLoginEvent, UserRateLimitConfigResponse, UserRateLimitsResponse, UserRegisteredEvent, UserResponse, UserRole, UserSettings, UserSettingsUpdate, UserSettingsUpdatedEvent, UserUpdate, UserUpdatedEvent, ValidationError } from './types.gen'; diff --git a/frontend/src/lib/api/types.gen.ts b/frontend/src/lib/api/types.gen.ts index 34652d67..3f9cc123 100644 --- a/frontend/src/lib/api/types.gen.ts +++ b/frontend/src/lib/api/types.gen.ts @@ -302,8 +302,6 @@ export type CleanupResponse = { /** * ContainerStatusInfo - * - * Container status information from Kubernetes pod. */ export type ContainerStatusInfo = { /** @@ -1180,8 +1178,6 @@ export type EndpointGroup = 'execution' | 'admin' | 'sse' | 'websocket' | 'auth' /** * EndpointUsageStats - * - * Usage statistics for a single endpoint (IETF RateLimit-style). */ export type EndpointUsageStats = { algorithm: RateLimitAlgorithm; @@ -1559,8 +1555,6 @@ export type EventFilter = { /** * EventMetadata - * - * Event metadata - embedded in all events. */ export type EventMetadata = { /** @@ -1778,8 +1772,6 @@ export type EventStatsResponse = { /** * EventSummary - * - * Lightweight event summary for lists and previews. */ export type EventSummary = { /** @@ -2393,13 +2385,6 @@ export type HourlyEventCount = { count: number; }; -/** - * KafkaTopic - * - * Kafka topic names used throughout the system. - */ -export type KafkaTopic = 'execution_events' | 'execution_completed' | 'execution_failed' | 'execution_timeout' | 'execution_requests' | 'execution_commands' | 'execution_tasks' | 'pod_events' | 'pod_status_updates' | 'pod_results' | 'execution_results' | 'user_events' | 'user_notifications' | 'user_settings_events' | 'script_events' | 'security_events' | 'resource_events' | 'notification_events' | 'system_events' | 'saga_events' | 'saga_commands' | 'dead_letter_queue' | 'dlq_events' | 'websocket_events'; - /** * LanguageInfo * @@ -3616,7 +3601,7 @@ export type ReplayConfigSchema = { * Target Topics */ target_topics?: { - [key: string]: KafkaTopic; + [key: string]: string; } | null; /** * Target File Path @@ -3642,16 +3627,6 @@ export type ReplayConfigSchema = { /** * ReplayError - * - * Error details for replay operations. - * - * Attributes: - * timestamp: When the error occurred. - * error: Human-readable error message. - * error_type: Python exception class name (e.g., "ValueError", "KafkaException"). - * This is the result of `type(exception).__name__`, NOT the ErrorType enum. - * Present for session-level errors. - * event_id: ID of the event that failed to replay. Present for event-level errors. */ export type ReplayError = { /** @@ -3793,7 +3768,7 @@ export type ReplayRequest = { * Target Topics */ target_topics?: { - [key: string]: KafkaTopic; + [key: string]: string; } | null; /** * Retry Failed @@ -3992,8 +3967,6 @@ export type ResourceUsage = { /** * ResourceUsageDomain - * - * Resource usage metrics from script execution. */ export type ResourceUsageDomain = { /** @@ -4150,11 +4123,11 @@ export type RetryStrategy = 'immediate' | 'exponential_backoff' | 'fixed_interva export type SseControlEvent = 'connected' | 'subscribed' | 'status'; /** - * SSEExecutionEventData + * SSEExecutionEventSchema * * API schema for SSE execution stream event payload (OpenAPI docs). */ -export type SseExecutionEventData = { +export type SseExecutionEventSchema = { /** * Event Type * @@ -5197,7 +5170,7 @@ export type SystemErrorEvent = { /** * SystemSettingsSchema * - * API schema for system settings — inherits all fields from domain model. + * API schema for system settings with validation. */ export type SystemSettingsSchema = { /** @@ -7117,7 +7090,7 @@ export type ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponses = { /** * Successful Response */ - 200: SseExecutionEventData; + 200: SseExecutionEventSchema; }; export type ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponse = ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponses[keyof ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponses]; @@ -7630,10 +7603,6 @@ export type UpdateUserApiV1AdminUsersUserIdPutErrors = { * Validation Error */ 422: HttpValidationError; - /** - * Failed to update user - */ - 500: ErrorResponse; }; export type UpdateUserApiV1AdminUsersUserIdPutError = UpdateUserApiV1AdminUsersUserIdPutErrors[keyof UpdateUserApiV1AdminUsersUserIdPutErrors]; diff --git a/frontend/src/lib/editor/execution.svelte.ts b/frontend/src/lib/editor/execution.svelte.ts index c72a1c7b..2a973acc 100644 --- a/frontend/src/lib/editor/execution.svelte.ts +++ b/frontend/src/lib/editor/execution.svelte.ts @@ -5,7 +5,7 @@ import { type ExecutionStatus, type EventType, type SseControlEvent, - type SseExecutionEventData, + type SseExecutionEventSchema, } from '$lib/api'; import { getErrorMessage } from '$lib/api-interceptors'; @@ -91,9 +91,9 @@ export function createExecutionState() { for (const line of lines) { if (!line.startsWith('data:')) continue; - let eventData: SseExecutionEventData; + let eventData: SseExecutionEventSchema; try { - eventData = JSON.parse(line.slice(5).trim()) as SseExecutionEventData; + eventData = JSON.parse(line.slice(5).trim()) as SseExecutionEventSchema; } catch { continue; // Skip malformed SSE events } From 60c145b536dd81e33be0cd467669ce3807f112a2 Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Thu, 19 Feb 2026 00:20:47 +0100 Subject: [PATCH 3/9] removed dlq api: dlq is handled by internal dlq manager, nothing from frontend side uses it --- backend/app/api/routes/dlq.py | 99 -- backend/app/main.py | 2 - backend/app/schemas_pydantic/dlq.py | 104 -- backend/tests/e2e/test_dlq_routes.py | 301 ----- docs/reference/openapi.json | 1619 +++----------------------- frontend/src/lib/api/index.ts | 4 +- frontend/src/lib/api/sdk.gen.ts | 58 +- frontend/src/lib/api/types.gen.ts | 798 +------------ 8 files changed, 231 insertions(+), 2754 deletions(-) delete mode 100644 backend/app/api/routes/dlq.py delete mode 100644 backend/app/schemas_pydantic/dlq.py delete mode 100644 backend/tests/e2e/test_dlq_routes.py diff --git a/backend/app/api/routes/dlq.py b/backend/app/api/routes/dlq.py deleted file mode 100644 index 99c27382..00000000 --- a/backend/app/api/routes/dlq.py +++ /dev/null @@ -1,99 +0,0 @@ -from typing import Annotated - -from dishka import FromDishka -from dishka.integrations.fastapi import DishkaRoute -from fastapi import APIRouter, Depends, HTTPException, Query - -from app.api.dependencies import admin_user -from app.db.repositories import DLQRepository -from app.dlq import RetryPolicy -from app.dlq.manager import DLQManager -from app.dlq.models import DLQMessageStatus -from app.domain.enums import EventType -from app.schemas_pydantic.common import ErrorResponse -from app.schemas_pydantic.dlq import ( - DLQBatchRetryResponse, - DLQMessageDetail, - DLQMessagesResponse, - DLQTopicSummaryResponse, - ManualRetryRequest, - RetryPolicyRequest, -) -from app.schemas_pydantic.user import MessageResponse - -router = APIRouter( - prefix="/dlq", tags=["Dead Letter Queue"], route_class=DishkaRoute, dependencies=[Depends(admin_user)] -) - - -@router.get("/messages", response_model=DLQMessagesResponse) -async def get_dlq_messages( - repository: FromDishka[DLQRepository], - status: Annotated[DLQMessageStatus | None, Query(description="Filter by message status")] = None, - topic: Annotated[str | None, Query(description="Filter by source Kafka topic")] = None, - event_type: Annotated[EventType | None, Query(description="Filter by event type")] = None, - limit: Annotated[int, Query(ge=1, le=1000)] = 50, - offset: Annotated[int, Query(ge=0)] = 0, -) -> DLQMessagesResponse: - """List DLQ messages with optional filtering.""" - result = await repository.get_messages( - status=status, topic=topic, event_type=event_type, limit=limit, offset=offset - ) - - return DLQMessagesResponse.model_validate(result) - - -@router.get( - "/messages/{event_id}", - response_model=DLQMessageDetail, - responses={404: {"model": ErrorResponse, "description": "DLQ message not found"}}, -) -async def get_dlq_message(event_id: str, repository: FromDishka[DLQRepository]) -> DLQMessageDetail: - """Get details of a specific DLQ message.""" - message = await repository.get_message_by_id(event_id) - if not message: - raise HTTPException(status_code=404, detail="Message not found") - return DLQMessageDetail.model_validate(message) - - -@router.post("/retry", response_model=DLQBatchRetryResponse) -async def retry_dlq_messages( - retry_request: ManualRetryRequest, dlq_manager: FromDishka[DLQManager] -) -> DLQBatchRetryResponse: - """Retry a batch of DLQ messages by their event IDs.""" - result = await dlq_manager.retry_messages_batch(retry_request.event_ids) - return DLQBatchRetryResponse.model_validate(result) - - -@router.post("/retry-policy", response_model=MessageResponse) -async def set_retry_policy(policy_request: RetryPolicyRequest, dlq_manager: FromDishka[DLQManager]) -> MessageResponse: - """Configure a retry policy for a specific Kafka topic.""" - policy = RetryPolicy(**policy_request.model_dump()) - - dlq_manager.set_retry_policy(policy_request.topic, policy) - - return MessageResponse(message=f"Retry policy set for topic {policy_request.topic}") - - -@router.delete( - "/messages/{event_id}", - response_model=MessageResponse, - responses={404: {"model": ErrorResponse, "description": "Message not found or already in terminal state"}}, -) -async def discard_dlq_message( - event_id: str, - dlq_manager: FromDishka[DLQManager], - reason: Annotated[str, Query(description="Reason for discarding")], -) -> MessageResponse: - """Permanently discard a DLQ message with a reason.""" - success = await dlq_manager.discard_message_manually(event_id, f"manual: {reason}") - if not success: - raise HTTPException(status_code=404, detail="Message not found or already in terminal state") - return MessageResponse(message=f"Message {event_id} discarded") - - -@router.get("/topics", response_model=list[DLQTopicSummaryResponse]) -async def get_dlq_topics(repository: FromDishka[DLQRepository]) -> list[DLQTopicSummaryResponse]: - """Get a per-topic summary of DLQ message counts.""" - topics = await repository.get_topics_summary() - return [DLQTopicSummaryResponse.model_validate(topic) for topic in topics] diff --git a/backend/app/main.py b/backend/app/main.py index 1ed18784..4ebdf5b2 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -5,7 +5,6 @@ from app.api.routes import ( auth, - dlq, execution, health, notifications, @@ -100,7 +99,6 @@ def create_app(settings: Settings | None = None) -> FastAPI: app.include_router(replay.router, prefix=settings.API_V1_STR) # Lightweight health endpoints for liveness/readiness app.include_router(health.router, prefix=settings.API_V1_STR) - app.include_router(dlq.router, prefix=settings.API_V1_STR) app.include_router(sse.router, prefix=settings.API_V1_STR) app.include_router(admin_events_router, prefix=settings.API_V1_STR) app.include_router(admin_settings_router, prefix=settings.API_V1_STR) diff --git a/backend/app/schemas_pydantic/dlq.py b/backend/app/schemas_pydantic/dlq.py deleted file mode 100644 index bef631f4..00000000 --- a/backend/app/schemas_pydantic/dlq.py +++ /dev/null @@ -1,104 +0,0 @@ -from datetime import datetime - -from pydantic import BaseModel, ConfigDict - -from app.dlq import ( - DLQMessageStatus, - DLQRetryResult, - RetryStrategy, -) -from app.domain.events import DomainEvent - - -class DLQMessageResponse(BaseModel): - """Response model for a DLQ message. Mirrors DLQMessage for direct model_validate.""" - - model_config = ConfigDict(from_attributes=True) - - event: DomainEvent - original_topic: str - error: str - retry_count: int - failed_at: datetime - status: DLQMessageStatus - producer_id: str - dlq_offset: int | None = None - dlq_partition: int | None = None - last_error: str | None = None - next_retry_at: datetime | None = None - - -class RetryPolicyRequest(BaseModel): - """Request model for setting a retry policy.""" - - topic: str - strategy: RetryStrategy - max_retries: int = 5 - base_delay_seconds: float = 60.0 - max_delay_seconds: float = 3600.0 - retry_multiplier: float = 2.0 - - -class ManualRetryRequest(BaseModel): - """Request model for manual retry of messages.""" - - event_ids: list[str] - - -class DLQMessagesResponse(BaseModel): - """Response model for listing DLQ messages.""" - - model_config = ConfigDict(from_attributes=True) - - messages: list[DLQMessageResponse] - total: int - offset: int - limit: int - - -class DLQBatchRetryResponse(BaseModel): - """Response model for batch retry operation.""" - - model_config = ConfigDict(from_attributes=True) - - total: int - successful: int - failed: int - details: list[DLQRetryResult] - - -class DLQTopicSummaryResponse(BaseModel): - """Response model for topic summary.""" - - model_config = ConfigDict(from_attributes=True) - - topic: str - total_messages: int - status_breakdown: dict[DLQMessageStatus, int] - oldest_message: datetime - newest_message: datetime - avg_retry_count: float - max_retry_count: int - - -class DLQMessageDetail(BaseModel): - """Detailed DLQ message response. Mirrors DLQMessage for direct model_validate.""" - - model_config = ConfigDict(from_attributes=True) - - event: DomainEvent - original_topic: str - error: str - retry_count: int - failed_at: datetime - status: DLQMessageStatus - producer_id: str - created_at: datetime | None = None - last_updated: datetime | None = None - next_retry_at: datetime | None = None - retried_at: datetime | None = None - discarded_at: datetime | None = None - discard_reason: str | None = None - dlq_offset: int | None = None - dlq_partition: int | None = None - last_error: str | None = None diff --git a/backend/tests/e2e/test_dlq_routes.py b/backend/tests/e2e/test_dlq_routes.py deleted file mode 100644 index fcc1a3af..00000000 --- a/backend/tests/e2e/test_dlq_routes.py +++ /dev/null @@ -1,301 +0,0 @@ -import pytest -import pytest_asyncio -from app.db.docs.dlq import DLQMessageDocument -from app.dlq.models import DLQMessageStatus, RetryStrategy -from app.domain.enums import EventType -from app.schemas_pydantic.dlq import ( - DLQBatchRetryResponse, - DLQMessageDetail, - DLQMessagesResponse, - DLQTopicSummaryResponse, -) -from app.schemas_pydantic.user import MessageResponse -from httpx import AsyncClient - -from tests.conftest import make_execution_requested_event - -pytestmark = [pytest.mark.e2e, pytest.mark.kafka] - - -@pytest_asyncio.fixture -async def stored_dlq_message() -> DLQMessageDocument: - """Insert a DLQ message directly into MongoDB and return it.""" - event = make_execution_requested_event() - doc = DLQMessageDocument( - event=event, - original_topic="execution-events", - error="Simulated failure for E2E testing", - retry_count=0, - status=DLQMessageStatus.PENDING, - producer_id="e2e-test", - ) - await doc.insert() - return doc - - -class TestGetDLQMessages: - """Tests for GET /api/v1/dlq/messages.""" - - @pytest.mark.asyncio - async def test_get_dlq_messages(self, test_admin: AsyncClient) -> None: - """Get DLQ messages list.""" - response = await test_admin.get("/api/v1/dlq/messages") - - assert response.status_code == 200 - result = DLQMessagesResponse.model_validate(response.json()) - - assert result.offset == 0 - assert result.limit == 50 # default - - @pytest.mark.asyncio - async def test_get_dlq_messages_with_pagination( - self, test_admin: AsyncClient - ) -> None: - """Pagination parameters work correctly.""" - response = await test_admin.get( - "/api/v1/dlq/messages", - params={"limit": 10, "offset": 0}, - ) - - assert response.status_code == 200 - result = DLQMessagesResponse.model_validate(response.json()) - assert result.limit == 10 - assert result.offset == 0 - - @pytest.mark.asyncio - async def test_get_dlq_messages_by_status( - self, test_admin: AsyncClient - ) -> None: - """Filter DLQ messages by status.""" - response = await test_admin.get( - "/api/v1/dlq/messages", - params={"status": DLQMessageStatus.PENDING}, - ) - - assert response.status_code == 200 - result = DLQMessagesResponse.model_validate(response.json()) - - for msg in result.messages: - assert msg.status == DLQMessageStatus.PENDING - - @pytest.mark.asyncio - async def test_get_dlq_messages_by_topic( - self, test_admin: AsyncClient - ) -> None: - """Filter DLQ messages by topic.""" - response = await test_admin.get( - "/api/v1/dlq/messages", - params={"topic": "execution-events"}, - ) - - assert response.status_code == 200 - DLQMessagesResponse.model_validate(response.json()) - - @pytest.mark.asyncio - async def test_get_dlq_messages_by_event_type( - self, test_admin: AsyncClient - ) -> None: - """Filter DLQ messages by event type.""" - response = await test_admin.get( - "/api/v1/dlq/messages", - params={"event_type": EventType.EXECUTION_REQUESTED}, - ) - - assert response.status_code == 200 - DLQMessagesResponse.model_validate(response.json()) - - -class TestGetDLQMessage: - """Tests for GET /api/v1/dlq/messages/{event_id}.""" - - @pytest.mark.asyncio - async def test_get_dlq_message_not_found( - self, test_admin: AsyncClient - ) -> None: - """Get nonexistent DLQ message returns 404.""" - response = await test_admin.get( - "/api/v1/dlq/messages/nonexistent-event-id" - ) - assert response.status_code == 404 - - @pytest.mark.asyncio - async def test_get_dlq_message_detail( - self, test_admin: AsyncClient, stored_dlq_message: DLQMessageDocument - ) -> None: - """Get DLQ message detail by event_id.""" - event_id = stored_dlq_message.event.event_id - - response = await test_admin.get( - f"/api/v1/dlq/messages/{event_id}" - ) - assert response.status_code == 200 - detail = DLQMessageDetail.model_validate(response.json()) - assert detail.event.event_id == event_id - assert detail.original_topic == "execution-events" - assert detail.error == "Simulated failure for E2E testing" - assert detail.retry_count == 0 - - -class TestRetryDLQMessages: - """Tests for POST /api/v1/dlq/retry.""" - - @pytest.mark.asyncio - async def test_retry_dlq_messages( - self, test_admin: AsyncClient, stored_dlq_message: DLQMessageDocument - ) -> None: - """Retry a known DLQ message.""" - event_ids = [stored_dlq_message.event.event_id] - - response = await test_admin.post( - "/api/v1/dlq/retry", - json={"event_ids": event_ids}, - ) - assert response.status_code == 200 - retry_result = DLQBatchRetryResponse.model_validate( - response.json() - ) - - assert retry_result.total == 1 - assert retry_result.successful + retry_result.failed == 1 - - @pytest.mark.asyncio - async def test_retry_dlq_messages_empty_list( - self, test_admin: AsyncClient - ) -> None: - """Retry with empty event IDs list.""" - response = await test_admin.post( - "/api/v1/dlq/retry", - json={"event_ids": []}, - ) - - assert response.status_code == 200 - result = DLQBatchRetryResponse.model_validate(response.json()) - assert result.total == 0 - - @pytest.mark.asyncio - async def test_retry_dlq_messages_nonexistent( - self, test_admin: AsyncClient - ) -> None: - """Retry nonexistent messages.""" - response = await test_admin.post( - "/api/v1/dlq/retry", - json={"event_ids": ["nonexistent-1", "nonexistent-2"]}, - ) - - # May succeed with failures reported in details - assert response.status_code == 200 - result = DLQBatchRetryResponse.model_validate(response.json()) - assert result.total == 2 - assert result.failed == 2 - - -class TestSetRetryPolicy: - """Tests for POST /api/v1/dlq/retry-policy.""" - - @pytest.mark.asyncio - @pytest.mark.parametrize( - ("strategy", "topic"), - [ - (RetryStrategy.EXPONENTIAL_BACKOFF, "execution-events"), - (RetryStrategy.FIXED_INTERVAL, "test-topic"), - (RetryStrategy.SCHEDULED, "notifications-topic"), - ], - ids=str, - ) - async def test_set_retry_policy( - self, test_admin: AsyncClient, strategy: RetryStrategy, topic: str - ) -> None: - """Set retry policy for each strategy type.""" - response = await test_admin.post( - "/api/v1/dlq/retry-policy", - json={ - "topic": topic, - "strategy": strategy, - "max_retries": 5, - "base_delay_seconds": 60.0, - "max_delay_seconds": 3600.0, - "retry_multiplier": 2.0, - }, - ) - - assert response.status_code == 200 - result = MessageResponse.model_validate(response.json()) - assert topic in result.message - - -class TestDiscardDLQMessage: - """Tests for DELETE /api/v1/dlq/messages/{event_id}.""" - - @pytest.mark.asyncio - async def test_discard_dlq_message_not_found( - self, test_admin: AsyncClient - ) -> None: - """Discard nonexistent message returns 404.""" - response = await test_admin.delete( - "/api/v1/dlq/messages/nonexistent-event-id", - params={"reason": "Test discard"}, - ) - assert response.status_code == 404 - - @pytest.mark.asyncio - async def test_discard_dlq_message( - self, test_admin: AsyncClient, stored_dlq_message: DLQMessageDocument - ) -> None: - """Discard a known DLQ message.""" - event_id = stored_dlq_message.event.event_id - - response = await test_admin.delete( - f"/api/v1/dlq/messages/{event_id}", - params={"reason": "Test discard for E2E testing"}, - ) - assert response.status_code == 200 - msg_result = MessageResponse.model_validate( - response.json() - ) - assert event_id in msg_result.message - assert "discarded" in msg_result.message.lower() - - # Verify message is actually gone or marked discarded - get_resp = await test_admin.get(f"/api/v1/dlq/messages/{event_id}") - if get_resp.status_code == 200: - detail = DLQMessageDetail.model_validate(get_resp.json()) - assert detail.status == DLQMessageStatus.DISCARDED - - @pytest.mark.asyncio - async def test_discard_dlq_message_requires_reason( - self, test_admin: AsyncClient - ) -> None: - """Discard requires reason parameter.""" - response = await test_admin.delete( - "/api/v1/dlq/messages/some-event-id" - ) - assert response.status_code == 422 - - -class TestGetDLQTopics: - """Tests for GET /api/v1/dlq/topics.""" - - @pytest.mark.asyncio - async def test_get_dlq_topics(self, test_admin: AsyncClient) -> None: - """Get DLQ topics summary.""" - response = await test_admin.get("/api/v1/dlq/topics") - - assert response.status_code == 200 - topics = [ - DLQTopicSummaryResponse.model_validate(t) - for t in response.json() - ] - - for topic in topics: - assert topic.topic - assert topic.total_messages >= 0 - assert topic.avg_retry_count >= 0 - assert topic.max_retry_count >= 0 - - @pytest.mark.asyncio - async def test_get_dlq_topics_unauthenticated( - self, client: AsyncClient - ) -> None: - """Unauthenticated request returns 401.""" - response = await client.get("/api/v1/dlq/topics") - assert response.status_code == 401 diff --git a/docs/reference/openapi.json b/docs/reference/openapi.json index a102e7ef..3d38ee52 100644 --- a/docs/reference/openapi.json +++ b/docs/reference/openapi.json @@ -1586,110 +1586,21 @@ } } }, - "/api/v1/dlq/messages": { + "/api/v1/events/notifications/stream": { "get": { "tags": [ - "Dead Letter Queue" - ], - "summary": "Get Dlq Messages", - "description": "List DLQ messages with optional filtering.", - "operationId": "get_dlq_messages_api_v1_dlq_messages_get", - "parameters": [ - { - "name": "status", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/DLQMessageStatus" - }, - { - "type": "null" - } - ], - "description": "Filter by message status", - "title": "Status" - }, - "description": "Filter by message status" - }, - { - "name": "topic", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Filter by source Kafka topic", - "title": "Topic" - }, - "description": "Filter by source Kafka topic" - }, - { - "name": "event_type", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/EventType" - }, - { - "type": "null" - } - ], - "description": "Filter by event type", - "title": "Event Type" - }, - "description": "Filter by event type" - }, - { - "name": "limit", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "maximum": 1000, - "minimum": 1, - "default": 50, - "title": "Limit" - } - }, - { - "name": "offset", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "minimum": 0, - "default": 0, - "title": "Offset" - } - } + "sse" ], + "summary": "Notification Stream", + "description": "Stream notifications for authenticated user.", + "operationId": "notification_stream_api_v1_events_notifications_stream_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DLQMessagesResponse" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" + "$ref": "#/components/schemas/NotificationResponse" } } } @@ -1697,85 +1608,23 @@ } } }, - "/api/v1/dlq/messages/{event_id}": { + "/api/v1/events/executions/{execution_id}": { "get": { "tags": [ - "Dead Letter Queue" - ], - "summary": "Get Dlq Message", - "description": "Get details of a specific DLQ message.", - "operationId": "get_dlq_message_api_v1_dlq_messages__event_id__get", - "parameters": [ - { - "name": "event_id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Event Id" - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DLQMessageDetail" - } - } - } - }, - "404": { - "description": "DLQ message not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Dead Letter Queue" + "sse" ], - "summary": "Discard Dlq Message", - "description": "Permanently discard a DLQ message with a reason.", - "operationId": "discard_dlq_message_api_v1_dlq_messages__event_id__delete", + "summary": "Execution Events", + "description": "Stream events for specific execution.", + "operationId": "execution_events_api_v1_events_executions__execution_id__get", "parameters": [ { - "name": "event_id", + "name": "execution_id", "in": "path", "required": true, "schema": { "type": "string", - "title": "Event Id" + "title": "Execution Id" } - }, - { - "name": "reason", - "in": "query", - "required": true, - "schema": { - "type": "string", - "description": "Reason for discarding", - "title": "Reason" - }, - "description": "Reason for discarding" } ], "responses": { @@ -1784,17 +1633,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/MessageResponse" - } - } - } - }, - "404": { - "description": "Message not found or already in terminal state", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" + "$ref": "#/components/schemas/SSEExecutionEventSchema" } } } @@ -1812,19 +1651,19 @@ } } }, - "/api/v1/dlq/retry": { + "/api/v1/admin/events/browse": { "post": { "tags": [ - "Dead Letter Queue" + "admin-events" ], - "summary": "Retry Dlq Messages", - "description": "Retry a batch of DLQ messages by their event IDs.", - "operationId": "retry_dlq_messages_api_v1_dlq_retry_post", + "summary": "Browse Events", + "description": "Browse events with filtering, sorting, and pagination.", + "operationId": "browse_events_api_v1_admin_events_browse_post", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ManualRetryRequest" + "$ref": "#/components/schemas/EventBrowseRequest" } } }, @@ -1836,7 +1675,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DLQBatchRetryResponse" + "$ref": "#/components/schemas/EventBrowseResponse" } } } @@ -1854,31 +1693,37 @@ } } }, - "/api/v1/dlq/retry-policy": { - "post": { + "/api/v1/admin/events/stats": { + "get": { "tags": [ - "Dead Letter Queue" + "admin-events" + ], + "summary": "Get Event Stats", + "description": "Get event statistics for a given lookback window.", + "operationId": "get_event_stats_api_v1_admin_events_stats_get", + "parameters": [ + { + "name": "hours", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 168, + "minimum": 1, + "description": "Lookback window in hours (max 168)", + "default": 24, + "title": "Hours" + }, + "description": "Lookback window in hours (max 168)" + } ], - "summary": "Set Retry Policy", - "description": "Configure a retry policy for a specific Kafka topic.", - "operationId": "set_retry_policy_api_v1_dlq_retry_policy_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RetryPolicyRequest" - } - } - }, - "required": true - }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/MessageResponse" + "$ref": "#/components/schemas/EventStatsResponse" } } } @@ -1896,202 +1741,21 @@ } } }, - "/api/v1/dlq/topics": { - "get": { - "tags": [ - "Dead Letter Queue" - ], - "summary": "Get Dlq Topics", - "description": "Get a per-topic summary of DLQ message counts.", - "operationId": "get_dlq_topics_api_v1_dlq_topics_get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/DLQTopicSummaryResponse" - }, - "type": "array", - "title": "Response Get Dlq Topics Api V1 Dlq Topics Get" - } - } - } - } - } - } - }, - "/api/v1/events/notifications/stream": { - "get": { - "tags": [ - "sse" - ], - "summary": "Notification Stream", - "description": "Stream notifications for authenticated user.", - "operationId": "notification_stream_api_v1_events_notifications_stream_get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotificationResponse" - } - } - } - } - } - } - }, - "/api/v1/events/executions/{execution_id}": { + "/api/v1/admin/events/export/{export_format}": { "get": { "tags": [ - "sse" + "admin-events" ], - "summary": "Execution Events", - "description": "Stream events for specific execution.", - "operationId": "execution_events_api_v1_events_executions__execution_id__get", + "summary": "Export Events", + "description": "Export filtered events as a downloadable file.", + "operationId": "export_events_api_v1_admin_events_export__export_format__get", "parameters": [ { - "name": "execution_id", + "name": "export_format", "in": "path", "required": true, "schema": { - "type": "string", - "title": "Execution Id" - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SSEExecutionEventSchema" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/v1/admin/events/browse": { - "post": { - "tags": [ - "admin-events" - ], - "summary": "Browse Events", - "description": "Browse events with filtering, sorting, and pagination.", - "operationId": "browse_events_api_v1_admin_events_browse_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EventBrowseRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EventBrowseResponse" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/v1/admin/events/stats": { - "get": { - "tags": [ - "admin-events" - ], - "summary": "Get Event Stats", - "description": "Get event statistics for a given lookback window.", - "operationId": "get_event_stats_api_v1_admin_events_stats_get", - "parameters": [ - { - "name": "hours", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "maximum": 168, - "minimum": 1, - "description": "Lookback window in hours (max 168)", - "default": 24, - "title": "Hours" - }, - "description": "Lookback window in hours (max 168)" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EventStatsResponse" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/api/v1/admin/events/export/{export_format}": { - "get": { - "tags": [ - "admin-events" - ], - "summary": "Export Events", - "description": "Export filtered events as a downloadable file.", - "operationId": "export_events_api_v1_admin_events_export__export_format__get", - "parameters": [ - { - "name": "export_format", - "in": "path", - "required": true, - "schema": { - "$ref": "#/components/schemas/ExportFormat" + "$ref": "#/components/schemas/ExportFormat" } }, { @@ -4831,879 +4495,55 @@ "type": "string", "title": "Memory Limit" }, - "cpu_request": { - "type": "string", - "title": "Cpu Request" - }, - "memory_request": { - "type": "string", - "title": "Memory Request" - }, - "priority": { - "$ref": "#/components/schemas/QueuePriority", - "default": "normal" - } - }, - "type": "object", - "required": [ - "event_id", - "event_type", - "event_version", - "timestamp", - "metadata" - ], - "title": "CreatePodCommandEvent" - }, - "DLQBatchRetryResponse": { - "properties": { - "total": { - "type": "integer", - "title": "Total" - }, - "successful": { - "type": "integer", - "title": "Successful" - }, - "failed": { - "type": "integer", - "title": "Failed" - }, - "details": { - "items": { - "$ref": "#/components/schemas/DLQRetryResult" - }, - "type": "array", - "title": "Details" - } - }, - "type": "object", - "required": [ - "total", - "successful", - "failed", - "details" - ], - "title": "DLQBatchRetryResponse", - "description": "Response model for batch retry operation." - }, - "DLQMessageDetail": { - "properties": { - "event": { - "oneOf": [ - { - "$ref": "#/components/schemas/ExecutionRequestedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionAcceptedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionQueuedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionStartedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionRunningEvent" - }, - { - "$ref": "#/components/schemas/ExecutionCompletedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionFailedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionTimeoutEvent" - }, - { - "$ref": "#/components/schemas/ExecutionCancelledEvent" - }, - { - "$ref": "#/components/schemas/PodCreatedEvent" - }, - { - "$ref": "#/components/schemas/PodScheduledEvent" - }, - { - "$ref": "#/components/schemas/PodRunningEvent" - }, - { - "$ref": "#/components/schemas/PodSucceededEvent" - }, - { - "$ref": "#/components/schemas/PodFailedEvent" - }, - { - "$ref": "#/components/schemas/PodTerminatedEvent" - }, - { - "$ref": "#/components/schemas/PodDeletedEvent" - }, - { - "$ref": "#/components/schemas/ResultStoredEvent" - }, - { - "$ref": "#/components/schemas/ResultFailedEvent" - }, - { - "$ref": "#/components/schemas/UserSettingsUpdatedEvent" - }, - { - "$ref": "#/components/schemas/UserRegisteredEvent" - }, - { - "$ref": "#/components/schemas/UserLoginEvent" - }, - { - "$ref": "#/components/schemas/UserLoggedInEvent" - }, - { - "$ref": "#/components/schemas/UserLoggedOutEvent" - }, - { - "$ref": "#/components/schemas/UserUpdatedEvent" - }, - { - "$ref": "#/components/schemas/UserDeletedEvent" - }, - { - "$ref": "#/components/schemas/NotificationCreatedEvent" - }, - { - "$ref": "#/components/schemas/NotificationSentEvent" - }, - { - "$ref": "#/components/schemas/NotificationDeliveredEvent" - }, - { - "$ref": "#/components/schemas/NotificationFailedEvent" - }, - { - "$ref": "#/components/schemas/NotificationReadEvent" - }, - { - "$ref": "#/components/schemas/NotificationAllReadEvent" - }, - { - "$ref": "#/components/schemas/NotificationClickedEvent" - }, - { - "$ref": "#/components/schemas/NotificationPreferencesUpdatedEvent" - }, - { - "$ref": "#/components/schemas/SagaStartedEvent" - }, - { - "$ref": "#/components/schemas/SagaCompletedEvent" - }, - { - "$ref": "#/components/schemas/SagaFailedEvent" - }, - { - "$ref": "#/components/schemas/SagaCancelledEvent" - }, - { - "$ref": "#/components/schemas/SagaCompensatingEvent" - }, - { - "$ref": "#/components/schemas/SagaCompensatedEvent" - }, - { - "$ref": "#/components/schemas/CreatePodCommandEvent" - }, - { - "$ref": "#/components/schemas/DeletePodCommandEvent" - }, - { - "$ref": "#/components/schemas/AllocateResourcesCommandEvent" - }, - { - "$ref": "#/components/schemas/ReleaseResourcesCommandEvent" - }, - { - "$ref": "#/components/schemas/ScriptSavedEvent" - }, - { - "$ref": "#/components/schemas/ScriptDeletedEvent" - }, - { - "$ref": "#/components/schemas/ScriptSharedEvent" - }, - { - "$ref": "#/components/schemas/SecurityViolationEvent" - }, - { - "$ref": "#/components/schemas/RateLimitExceededEvent" - }, - { - "$ref": "#/components/schemas/AuthFailedEvent" - }, - { - "$ref": "#/components/schemas/ResourceLimitExceededEvent" - }, - { - "$ref": "#/components/schemas/QuotaExceededEvent" - }, - { - "$ref": "#/components/schemas/SystemErrorEvent" - }, - { - "$ref": "#/components/schemas/ServiceUnhealthyEvent" - }, - { - "$ref": "#/components/schemas/ServiceRecoveredEvent" - }, - { - "$ref": "#/components/schemas/DLQMessageReceivedEvent" - }, - { - "$ref": "#/components/schemas/DLQMessageRetriedEvent" - }, - { - "$ref": "#/components/schemas/DLQMessageDiscardedEvent" - } - ], - "title": "Event", - "discriminator": { - "propertyName": "event_type", - "mapping": { - "allocate_resources_command": "#/components/schemas/AllocateResourcesCommandEvent", - "auth_failed": "#/components/schemas/AuthFailedEvent", - "create_pod_command": "#/components/schemas/CreatePodCommandEvent", - "delete_pod_command": "#/components/schemas/DeletePodCommandEvent", - "dlq_message_discarded": "#/components/schemas/DLQMessageDiscardedEvent", - "dlq_message_received": "#/components/schemas/DLQMessageReceivedEvent", - "dlq_message_retried": "#/components/schemas/DLQMessageRetriedEvent", - "execution_accepted": "#/components/schemas/ExecutionAcceptedEvent", - "execution_cancelled": "#/components/schemas/ExecutionCancelledEvent", - "execution_completed": "#/components/schemas/ExecutionCompletedEvent", - "execution_failed": "#/components/schemas/ExecutionFailedEvent", - "execution_queued": "#/components/schemas/ExecutionQueuedEvent", - "execution_requested": "#/components/schemas/ExecutionRequestedEvent", - "execution_running": "#/components/schemas/ExecutionRunningEvent", - "execution_started": "#/components/schemas/ExecutionStartedEvent", - "execution_timeout": "#/components/schemas/ExecutionTimeoutEvent", - "notification_all_read": "#/components/schemas/NotificationAllReadEvent", - "notification_clicked": "#/components/schemas/NotificationClickedEvent", - "notification_created": "#/components/schemas/NotificationCreatedEvent", - "notification_delivered": "#/components/schemas/NotificationDeliveredEvent", - "notification_failed": "#/components/schemas/NotificationFailedEvent", - "notification_preferences_updated": "#/components/schemas/NotificationPreferencesUpdatedEvent", - "notification_read": "#/components/schemas/NotificationReadEvent", - "notification_sent": "#/components/schemas/NotificationSentEvent", - "pod_created": "#/components/schemas/PodCreatedEvent", - "pod_deleted": "#/components/schemas/PodDeletedEvent", - "pod_failed": "#/components/schemas/PodFailedEvent", - "pod_running": "#/components/schemas/PodRunningEvent", - "pod_scheduled": "#/components/schemas/PodScheduledEvent", - "pod_succeeded": "#/components/schemas/PodSucceededEvent", - "pod_terminated": "#/components/schemas/PodTerminatedEvent", - "quota_exceeded": "#/components/schemas/QuotaExceededEvent", - "rate_limit_exceeded": "#/components/schemas/RateLimitExceededEvent", - "release_resources_command": "#/components/schemas/ReleaseResourcesCommandEvent", - "resource_limit_exceeded": "#/components/schemas/ResourceLimitExceededEvent", - "result_failed": "#/components/schemas/ResultFailedEvent", - "result_stored": "#/components/schemas/ResultStoredEvent", - "saga_cancelled": "#/components/schemas/SagaCancelledEvent", - "saga_compensated": "#/components/schemas/SagaCompensatedEvent", - "saga_compensating": "#/components/schemas/SagaCompensatingEvent", - "saga_completed": "#/components/schemas/SagaCompletedEvent", - "saga_failed": "#/components/schemas/SagaFailedEvent", - "saga_started": "#/components/schemas/SagaStartedEvent", - "script_deleted": "#/components/schemas/ScriptDeletedEvent", - "script_saved": "#/components/schemas/ScriptSavedEvent", - "script_shared": "#/components/schemas/ScriptSharedEvent", - "security_violation": "#/components/schemas/SecurityViolationEvent", - "service_recovered": "#/components/schemas/ServiceRecoveredEvent", - "service_unhealthy": "#/components/schemas/ServiceUnhealthyEvent", - "system_error": "#/components/schemas/SystemErrorEvent", - "user_deleted": "#/components/schemas/UserDeletedEvent", - "user_logged_in": "#/components/schemas/UserLoggedInEvent", - "user_logged_out": "#/components/schemas/UserLoggedOutEvent", - "user_login": "#/components/schemas/UserLoginEvent", - "user_registered": "#/components/schemas/UserRegisteredEvent", - "user_settings_updated": "#/components/schemas/UserSettingsUpdatedEvent", - "user_updated": "#/components/schemas/UserUpdatedEvent" - } - } - }, - "original_topic": { - "type": "string", - "title": "Original Topic" - }, - "error": { - "type": "string", - "title": "Error" - }, - "retry_count": { - "type": "integer", - "title": "Retry Count" - }, - "failed_at": { - "type": "string", - "format": "date-time", - "title": "Failed At" - }, - "status": { - "$ref": "#/components/schemas/DLQMessageStatus" - }, - "producer_id": { - "type": "string", - "title": "Producer Id" - }, - "created_at": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Created At" - }, - "last_updated": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Last Updated" - }, - "next_retry_at": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Next Retry At" - }, - "retried_at": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Retried At" - }, - "discarded_at": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Discarded At" - }, - "discard_reason": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Discard Reason" - }, - "dlq_offset": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Dlq Offset" - }, - "dlq_partition": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Dlq Partition" - }, - "last_error": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Last Error" - } - }, - "type": "object", - "required": [ - "event", - "original_topic", - "error", - "retry_count", - "failed_at", - "status", - "producer_id" - ], - "title": "DLQMessageDetail", - "description": "Detailed DLQ message response. Mirrors DLQMessage for direct model_validate." - }, - "DLQMessageDiscardedEvent": { - "properties": { - "event_id": { - "type": "string", - "title": "Event Id" - }, - "event_type": { - "type": "string", - "enum": [ - "dlq_message_discarded" - ], - "const": "dlq_message_discarded", - "title": "Event Type", - "default": "dlq_message_discarded" - }, - "event_version": { - "type": "string", - "title": "Event Version", - "default": "1.0" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "title": "Timestamp" - }, - "aggregate_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Aggregate Id" - }, - "metadata": { - "$ref": "#/components/schemas/EventMetadata" - }, - "dlq_event_id": { - "type": "string", - "title": "Dlq Event Id" - }, - "original_topic": { - "type": "string", - "title": "Original Topic" - }, - "original_event_type": { - "$ref": "#/components/schemas/EventType" - }, - "reason": { - "type": "string", - "title": "Reason" - }, - "retry_count": { - "type": "integer", - "title": "Retry Count" - } - }, - "type": "object", - "required": [ - "event_id", - "event_type", - "event_version", - "timestamp", - "metadata" - ], - "title": "DLQMessageDiscardedEvent", - "description": "Emitted when a DLQ message is discarded (max retries exceeded or manual discard)." - }, - "DLQMessageReceivedEvent": { - "properties": { - "event_id": { - "type": "string", - "title": "Event Id" - }, - "event_type": { - "type": "string", - "enum": [ - "dlq_message_received" - ], - "const": "dlq_message_received", - "title": "Event Type", - "default": "dlq_message_received" - }, - "event_version": { - "type": "string", - "title": "Event Version", - "default": "1.0" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "title": "Timestamp" - }, - "aggregate_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Aggregate Id" - }, - "metadata": { - "$ref": "#/components/schemas/EventMetadata" - }, - "dlq_event_id": { - "type": "string", - "title": "Dlq Event Id" - }, - "original_topic": { - "type": "string", - "title": "Original Topic" - }, - "original_event_type": { - "$ref": "#/components/schemas/EventType" - }, - "error": { - "type": "string", - "title": "Error" - }, - "retry_count": { - "type": "integer", - "title": "Retry Count" - }, - "producer_id": { - "type": "string", - "title": "Producer Id" - }, - "failed_at": { - "type": "string", - "format": "date-time", - "title": "Failed At" - } - }, - "type": "object", - "required": [ - "event_id", - "event_type", - "event_version", - "timestamp", - "metadata" - ], - "title": "DLQMessageReceivedEvent", - "description": "Emitted when a message is received and persisted in the DLQ." - }, - "DLQMessageResponse": { - "properties": { - "event": { - "oneOf": [ - { - "$ref": "#/components/schemas/ExecutionRequestedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionAcceptedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionQueuedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionStartedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionRunningEvent" - }, - { - "$ref": "#/components/schemas/ExecutionCompletedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionFailedEvent" - }, - { - "$ref": "#/components/schemas/ExecutionTimeoutEvent" - }, - { - "$ref": "#/components/schemas/ExecutionCancelledEvent" - }, - { - "$ref": "#/components/schemas/PodCreatedEvent" - }, - { - "$ref": "#/components/schemas/PodScheduledEvent" - }, - { - "$ref": "#/components/schemas/PodRunningEvent" - }, - { - "$ref": "#/components/schemas/PodSucceededEvent" - }, - { - "$ref": "#/components/schemas/PodFailedEvent" - }, - { - "$ref": "#/components/schemas/PodTerminatedEvent" - }, - { - "$ref": "#/components/schemas/PodDeletedEvent" - }, - { - "$ref": "#/components/schemas/ResultStoredEvent" - }, - { - "$ref": "#/components/schemas/ResultFailedEvent" - }, - { - "$ref": "#/components/schemas/UserSettingsUpdatedEvent" - }, - { - "$ref": "#/components/schemas/UserRegisteredEvent" - }, - { - "$ref": "#/components/schemas/UserLoginEvent" - }, - { - "$ref": "#/components/schemas/UserLoggedInEvent" - }, - { - "$ref": "#/components/schemas/UserLoggedOutEvent" - }, - { - "$ref": "#/components/schemas/UserUpdatedEvent" - }, - { - "$ref": "#/components/schemas/UserDeletedEvent" - }, - { - "$ref": "#/components/schemas/NotificationCreatedEvent" - }, - { - "$ref": "#/components/schemas/NotificationSentEvent" - }, - { - "$ref": "#/components/schemas/NotificationDeliveredEvent" - }, - { - "$ref": "#/components/schemas/NotificationFailedEvent" - }, - { - "$ref": "#/components/schemas/NotificationReadEvent" - }, - { - "$ref": "#/components/schemas/NotificationAllReadEvent" - }, - { - "$ref": "#/components/schemas/NotificationClickedEvent" - }, - { - "$ref": "#/components/schemas/NotificationPreferencesUpdatedEvent" - }, - { - "$ref": "#/components/schemas/SagaStartedEvent" - }, - { - "$ref": "#/components/schemas/SagaCompletedEvent" - }, - { - "$ref": "#/components/schemas/SagaFailedEvent" - }, - { - "$ref": "#/components/schemas/SagaCancelledEvent" - }, - { - "$ref": "#/components/schemas/SagaCompensatingEvent" - }, - { - "$ref": "#/components/schemas/SagaCompensatedEvent" - }, - { - "$ref": "#/components/schemas/CreatePodCommandEvent" - }, - { - "$ref": "#/components/schemas/DeletePodCommandEvent" - }, - { - "$ref": "#/components/schemas/AllocateResourcesCommandEvent" - }, - { - "$ref": "#/components/schemas/ReleaseResourcesCommandEvent" - }, - { - "$ref": "#/components/schemas/ScriptSavedEvent" - }, - { - "$ref": "#/components/schemas/ScriptDeletedEvent" - }, - { - "$ref": "#/components/schemas/ScriptSharedEvent" - }, - { - "$ref": "#/components/schemas/SecurityViolationEvent" - }, - { - "$ref": "#/components/schemas/RateLimitExceededEvent" - }, - { - "$ref": "#/components/schemas/AuthFailedEvent" - }, - { - "$ref": "#/components/schemas/ResourceLimitExceededEvent" - }, - { - "$ref": "#/components/schemas/QuotaExceededEvent" - }, - { - "$ref": "#/components/schemas/SystemErrorEvent" - }, - { - "$ref": "#/components/schemas/ServiceUnhealthyEvent" - }, - { - "$ref": "#/components/schemas/ServiceRecoveredEvent" - }, - { - "$ref": "#/components/schemas/DLQMessageReceivedEvent" - }, - { - "$ref": "#/components/schemas/DLQMessageRetriedEvent" - }, - { - "$ref": "#/components/schemas/DLQMessageDiscardedEvent" - } - ], - "title": "Event", - "discriminator": { - "propertyName": "event_type", - "mapping": { - "allocate_resources_command": "#/components/schemas/AllocateResourcesCommandEvent", - "auth_failed": "#/components/schemas/AuthFailedEvent", - "create_pod_command": "#/components/schemas/CreatePodCommandEvent", - "delete_pod_command": "#/components/schemas/DeletePodCommandEvent", - "dlq_message_discarded": "#/components/schemas/DLQMessageDiscardedEvent", - "dlq_message_received": "#/components/schemas/DLQMessageReceivedEvent", - "dlq_message_retried": "#/components/schemas/DLQMessageRetriedEvent", - "execution_accepted": "#/components/schemas/ExecutionAcceptedEvent", - "execution_cancelled": "#/components/schemas/ExecutionCancelledEvent", - "execution_completed": "#/components/schemas/ExecutionCompletedEvent", - "execution_failed": "#/components/schemas/ExecutionFailedEvent", - "execution_queued": "#/components/schemas/ExecutionQueuedEvent", - "execution_requested": "#/components/schemas/ExecutionRequestedEvent", - "execution_running": "#/components/schemas/ExecutionRunningEvent", - "execution_started": "#/components/schemas/ExecutionStartedEvent", - "execution_timeout": "#/components/schemas/ExecutionTimeoutEvent", - "notification_all_read": "#/components/schemas/NotificationAllReadEvent", - "notification_clicked": "#/components/schemas/NotificationClickedEvent", - "notification_created": "#/components/schemas/NotificationCreatedEvent", - "notification_delivered": "#/components/schemas/NotificationDeliveredEvent", - "notification_failed": "#/components/schemas/NotificationFailedEvent", - "notification_preferences_updated": "#/components/schemas/NotificationPreferencesUpdatedEvent", - "notification_read": "#/components/schemas/NotificationReadEvent", - "notification_sent": "#/components/schemas/NotificationSentEvent", - "pod_created": "#/components/schemas/PodCreatedEvent", - "pod_deleted": "#/components/schemas/PodDeletedEvent", - "pod_failed": "#/components/schemas/PodFailedEvent", - "pod_running": "#/components/schemas/PodRunningEvent", - "pod_scheduled": "#/components/schemas/PodScheduledEvent", - "pod_succeeded": "#/components/schemas/PodSucceededEvent", - "pod_terminated": "#/components/schemas/PodTerminatedEvent", - "quota_exceeded": "#/components/schemas/QuotaExceededEvent", - "rate_limit_exceeded": "#/components/schemas/RateLimitExceededEvent", - "release_resources_command": "#/components/schemas/ReleaseResourcesCommandEvent", - "resource_limit_exceeded": "#/components/schemas/ResourceLimitExceededEvent", - "result_failed": "#/components/schemas/ResultFailedEvent", - "result_stored": "#/components/schemas/ResultStoredEvent", - "saga_cancelled": "#/components/schemas/SagaCancelledEvent", - "saga_compensated": "#/components/schemas/SagaCompensatedEvent", - "saga_compensating": "#/components/schemas/SagaCompensatingEvent", - "saga_completed": "#/components/schemas/SagaCompletedEvent", - "saga_failed": "#/components/schemas/SagaFailedEvent", - "saga_started": "#/components/schemas/SagaStartedEvent", - "script_deleted": "#/components/schemas/ScriptDeletedEvent", - "script_saved": "#/components/schemas/ScriptSavedEvent", - "script_shared": "#/components/schemas/ScriptSharedEvent", - "security_violation": "#/components/schemas/SecurityViolationEvent", - "service_recovered": "#/components/schemas/ServiceRecoveredEvent", - "service_unhealthy": "#/components/schemas/ServiceUnhealthyEvent", - "system_error": "#/components/schemas/SystemErrorEvent", - "user_deleted": "#/components/schemas/UserDeletedEvent", - "user_logged_in": "#/components/schemas/UserLoggedInEvent", - "user_logged_out": "#/components/schemas/UserLoggedOutEvent", - "user_login": "#/components/schemas/UserLoginEvent", - "user_registered": "#/components/schemas/UserRegisteredEvent", - "user_settings_updated": "#/components/schemas/UserSettingsUpdatedEvent", - "user_updated": "#/components/schemas/UserUpdatedEvent" - } - } - }, - "original_topic": { - "type": "string", - "title": "Original Topic" - }, - "error": { - "type": "string", - "title": "Error" - }, - "retry_count": { - "type": "integer", - "title": "Retry Count" - }, - "failed_at": { + "cpu_request": { "type": "string", - "format": "date-time", - "title": "Failed At" + "title": "Cpu Request" }, - "status": { - "$ref": "#/components/schemas/DLQMessageStatus" + "memory_request": { + "type": "string", + "title": "Memory Request" }, - "producer_id": { + "priority": { + "$ref": "#/components/schemas/QueuePriority", + "default": "normal" + } + }, + "type": "object", + "required": [ + "event_id", + "event_type", + "event_version", + "timestamp", + "metadata" + ], + "title": "CreatePodCommandEvent" + }, + "DLQMessageDiscardedEvent": { + "properties": { + "event_id": { "type": "string", - "title": "Producer Id" + "title": "Event Id" }, - "dlq_offset": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } + "event_type": { + "type": "string", + "enum": [ + "dlq_message_discarded" ], - "title": "Dlq Offset" + "const": "dlq_message_discarded", + "title": "Event Type", + "default": "dlq_message_discarded" }, - "dlq_partition": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Dlq Partition" + "event_version": { + "type": "string", + "title": "Event Version", + "default": "1.0" }, - "last_error": { + "timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp" + }, + "aggregate_id": { "anyOf": [ { "type": "string" @@ -5712,35 +4552,43 @@ "type": "null" } ], - "title": "Last Error" + "title": "Aggregate Id" }, - "next_retry_at": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Next Retry At" + "metadata": { + "$ref": "#/components/schemas/EventMetadata" + }, + "dlq_event_id": { + "type": "string", + "title": "Dlq Event Id" + }, + "original_topic": { + "type": "string", + "title": "Original Topic" + }, + "original_event_type": { + "$ref": "#/components/schemas/EventType" + }, + "reason": { + "type": "string", + "title": "Reason" + }, + "retry_count": { + "type": "integer", + "title": "Retry Count" } }, "type": "object", "required": [ - "event", - "original_topic", - "error", - "retry_count", - "failed_at", - "status", - "producer_id" + "event_id", + "event_type", + "event_version", + "timestamp", + "metadata" ], - "title": "DLQMessageResponse", - "description": "Response model for a DLQ message. Mirrors DLQMessage for direct model_validate." + "title": "DLQMessageDiscardedEvent", + "description": "Emitted when a DLQ message is discarded (max retries exceeded or manual discard)." }, - "DLQMessageRetriedEvent": { + "DLQMessageReceivedEvent": { "properties": { "event_id": { "type": "string", @@ -5749,11 +4597,11 @@ "event_type": { "type": "string", "enum": [ - "dlq_message_retried" + "dlq_message_received" ], - "const": "dlq_message_retried", + "const": "dlq_message_received", "title": "Event Type", - "default": "dlq_message_retried" + "default": "dlq_message_received" }, "event_version": { "type": "string", @@ -5790,13 +4638,22 @@ "original_event_type": { "$ref": "#/components/schemas/EventType" }, + "error": { + "type": "string", + "title": "Error" + }, "retry_count": { "type": "integer", "title": "Retry Count" }, - "retry_topic": { + "producer_id": { "type": "string", - "title": "Retry Topic" + "title": "Producer Id" + }, + "failed_at": { + "type": "string", + "format": "date-time", + "title": "Failed At" } }, "type": "object", @@ -5807,63 +4664,35 @@ "timestamp", "metadata" ], - "title": "DLQMessageRetriedEvent", - "description": "Emitted when a DLQ message is retried." - }, - "DLQMessageStatus": { - "type": "string", - "enum": [ - "pending", - "scheduled", - "retried", - "discarded" - ], - "title": "DLQMessageStatus", - "description": "Status of a message in the Dead Letter Queue." - }, - "DLQMessagesResponse": { - "properties": { - "messages": { - "items": { - "$ref": "#/components/schemas/DLQMessageResponse" - }, - "type": "array", - "title": "Messages" - }, - "total": { - "type": "integer", - "title": "Total" - }, - "offset": { - "type": "integer", - "title": "Offset" - }, - "limit": { - "type": "integer", - "title": "Limit" - } - }, - "type": "object", - "required": [ - "messages", - "total", - "offset", - "limit" - ], - "title": "DLQMessagesResponse", - "description": "Response model for listing DLQ messages." + "title": "DLQMessageReceivedEvent", + "description": "Emitted when a message is received and persisted in the DLQ." }, - "DLQRetryResult": { + "DLQMessageRetriedEvent": { "properties": { "event_id": { "type": "string", "title": "Event Id" }, - "status": { + "event_type": { "type": "string", - "title": "Status" + "enum": [ + "dlq_message_retried" + ], + "const": "dlq_message_retried", + "title": "Event Type", + "default": "dlq_message_retried" }, - "error": { + "event_version": { + "type": "string", + "title": "Event Version", + "default": "1.0" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp" + }, + "aggregate_id": { "anyOf": [ { "type": "string" @@ -5872,64 +4701,41 @@ "type": "null" } ], - "title": "Error" - } - }, - "type": "object", - "required": [ - "event_id", - "status" - ], - "title": "DLQRetryResult" - }, - "DLQTopicSummaryResponse": { - "properties": { - "topic": { - "type": "string", - "title": "Topic" - }, - "total_messages": { - "type": "integer", - "title": "Total Messages" + "title": "Aggregate Id" }, - "status_breakdown": { - "additionalProperties": { - "type": "integer" - }, - "type": "object", - "title": "Status Breakdown" + "metadata": { + "$ref": "#/components/schemas/EventMetadata" }, - "oldest_message": { + "dlq_event_id": { "type": "string", - "format": "date-time", - "title": "Oldest Message" + "title": "Dlq Event Id" }, - "newest_message": { + "original_topic": { "type": "string", - "format": "date-time", - "title": "Newest Message" + "title": "Original Topic" }, - "avg_retry_count": { - "type": "number", - "title": "Avg Retry Count" + "original_event_type": { + "$ref": "#/components/schemas/EventType" }, - "max_retry_count": { + "retry_count": { "type": "integer", - "title": "Max Retry Count" + "title": "Retry Count" + }, + "retry_topic": { + "type": "string", + "title": "Retry Topic" } }, "type": "object", "required": [ - "topic", - "total_messages", - "status_breakdown", - "oldest_message", - "newest_message", - "avg_retry_count", - "max_retry_count" + "event_id", + "event_type", + "event_version", + "timestamp", + "metadata" ], - "title": "DLQTopicSummaryResponse", - "description": "Response model for topic summary." + "title": "DLQMessageRetriedEvent", + "description": "Emitted when a DLQ message is retried." }, "DeleteNotificationResponse": { "properties": { @@ -8509,23 +7315,6 @@ "title": "LoginResponse", "description": "Response model for successful login" }, - "ManualRetryRequest": { - "properties": { - "event_ids": { - "items": { - "type": "string" - }, - "type": "array", - "title": "Event Ids" - } - }, - "type": "object", - "required": [ - "event_ids" - ], - "title": "ManualRetryRequest", - "description": "Request model for manual retry of messages." - }, "MessageResponse": { "properties": { "message": { @@ -11283,56 +10072,6 @@ ], "title": "ResultStoredEvent" }, - "RetryPolicyRequest": { - "properties": { - "topic": { - "type": "string", - "title": "Topic" - }, - "strategy": { - "$ref": "#/components/schemas/RetryStrategy" - }, - "max_retries": { - "type": "integer", - "title": "Max Retries", - "default": 5 - }, - "base_delay_seconds": { - "type": "number", - "title": "Base Delay Seconds", - "default": 60.0 - }, - "max_delay_seconds": { - "type": "number", - "title": "Max Delay Seconds", - "default": 3600.0 - }, - "retry_multiplier": { - "type": "number", - "title": "Retry Multiplier", - "default": 2.0 - } - }, - "type": "object", - "required": [ - "topic", - "strategy" - ], - "title": "RetryPolicyRequest", - "description": "Request model for setting a retry policy." - }, - "RetryStrategy": { - "type": "string", - "enum": [ - "immediate", - "exponential_backoff", - "fixed_interval", - "scheduled", - "manual" - ], - "title": "RetryStrategy", - "description": "Retry strategies for DLQ messages." - }, "SSEControlEvent": { "type": "string", "enum": [ diff --git a/frontend/src/lib/api/index.ts b/frontend/src/lib/api/index.ts index 41bcbfc2..7419bfd3 100644 --- a/frontend/src/lib/api/index.ts +++ b/frontend/src/lib/api/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { browseEventsApiV1AdminEventsBrowsePost, cancelExecutionApiV1ExecutionsExecutionIdCancelPost, cancelReplaySessionApiV1ReplaySessionsSessionIdCancelPost, cancelSagaApiV1SagasSagaIdCancelPost, cleanupOldSessionsApiV1ReplayCleanupPost, createExecutionApiV1ExecutePost, createReplaySessionApiV1ReplaySessionsPost, createSavedScriptApiV1ScriptsPost, createUserApiV1AdminUsersPost, deleteEventApiV1AdminEventsEventIdDelete, deleteExecutionApiV1ExecutionsExecutionIdDelete, deleteNotificationApiV1NotificationsNotificationIdDelete, deleteSavedScriptApiV1ScriptsScriptIdDelete, deleteUserApiV1AdminUsersUserIdDelete, discardDlqMessageApiV1DlqMessagesEventIdDelete, executionEventsApiV1EventsExecutionsExecutionIdGet, exportEventsApiV1AdminEventsExportExportFormatGet, getCurrentUserProfileApiV1AuthMeGet, getDlqMessageApiV1DlqMessagesEventIdGet, getDlqMessagesApiV1DlqMessagesGet, getDlqTopicsApiV1DlqTopicsGet, getEventDetailApiV1AdminEventsEventIdGet, getEventStatsApiV1AdminEventsStatsGet, getExampleScriptsApiV1ExampleScriptsGet, getExecutionEventsApiV1ExecutionsExecutionIdEventsGet, getExecutionSagasApiV1SagasExecutionExecutionIdGet, getK8sResourceLimitsApiV1K8sLimitsGet, getNotificationsApiV1NotificationsGet, getReplaySessionApiV1ReplaySessionsSessionIdGet, getReplayStatusApiV1AdminEventsReplaySessionIdStatusGet, getResultApiV1ExecutionsExecutionIdResultGet, getSagaStatusApiV1SagasSagaIdGet, getSavedScriptApiV1ScriptsScriptIdGet, getSettingsHistoryApiV1UserSettingsHistoryGet, getSubscriptionsApiV1NotificationsSubscriptionsGet, getSystemSettingsApiV1AdminSettingsGet, getUnreadCountApiV1NotificationsUnreadCountGet, getUserApiV1AdminUsersUserIdGet, getUserExecutionsApiV1UserExecutionsGet, getUserOverviewApiV1AdminUsersUserIdOverviewGet, getUserRateLimitsApiV1AdminUsersUserIdRateLimitsGet, getUserSettingsApiV1UserSettingsGet, listReplaySessionsApiV1ReplaySessionsGet, listSagasApiV1SagasGet, listSavedScriptsApiV1ScriptsGet, listUsersApiV1AdminUsersGet, livenessApiV1HealthLiveGet, loginApiV1AuthLoginPost, logoutApiV1AuthLogoutPost, markAllReadApiV1NotificationsMarkAllReadPost, markNotificationReadApiV1NotificationsNotificationIdReadPut, notificationStreamApiV1EventsNotificationsStreamGet, type Options, pauseReplaySessionApiV1ReplaySessionsSessionIdPausePost, registerApiV1AuthRegisterPost, replayEventsApiV1AdminEventsReplayPost, resetSystemSettingsApiV1AdminSettingsResetPost, resetUserPasswordApiV1AdminUsersUserIdResetPasswordPost, resetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPost, restoreSettingsApiV1UserSettingsRestorePost, resumeReplaySessionApiV1ReplaySessionsSessionIdResumePost, retryDlqMessagesApiV1DlqRetryPost, retryExecutionApiV1ExecutionsExecutionIdRetryPost, setRetryPolicyApiV1DlqRetryPolicyPost, startReplaySessionApiV1ReplaySessionsSessionIdStartPost, unlockUserApiV1AdminUsersUserIdUnlockPost, updateCustomSettingApiV1UserSettingsCustomKeyPut, updateEditorSettingsApiV1UserSettingsEditorPut, updateNotificationSettingsApiV1UserSettingsNotificationsPut, updateSavedScriptApiV1ScriptsScriptIdPut, updateSubscriptionApiV1NotificationsSubscriptionsChannelPut, updateSystemSettingsApiV1AdminSettingsPut, updateThemeApiV1UserSettingsThemePut, updateUserApiV1AdminUsersUserIdPut, updateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPut, updateUserSettingsApiV1UserSettingsPut } from './sdk.gen'; -export type { AdminUserOverview, AllocateResourcesCommandEvent, AuthFailedEvent, BodyLoginApiV1AuthLoginPost, BrowseEventsApiV1AdminEventsBrowsePostData, BrowseEventsApiV1AdminEventsBrowsePostError, BrowseEventsApiV1AdminEventsBrowsePostErrors, BrowseEventsApiV1AdminEventsBrowsePostResponse, BrowseEventsApiV1AdminEventsBrowsePostResponses, CancelExecutionApiV1ExecutionsExecutionIdCancelPostData, CancelExecutionApiV1ExecutionsExecutionIdCancelPostError, CancelExecutionApiV1ExecutionsExecutionIdCancelPostErrors, CancelExecutionApiV1ExecutionsExecutionIdCancelPostResponse, CancelExecutionApiV1ExecutionsExecutionIdCancelPostResponses, CancelExecutionRequest, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostData, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostError, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostErrors, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostResponse, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostResponses, CancelResponse, CancelSagaApiV1SagasSagaIdCancelPostData, CancelSagaApiV1SagasSagaIdCancelPostError, CancelSagaApiV1SagasSagaIdCancelPostErrors, CancelSagaApiV1SagasSagaIdCancelPostResponse, CancelSagaApiV1SagasSagaIdCancelPostResponses, CancelStatus, CleanupOldSessionsApiV1ReplayCleanupPostData, CleanupOldSessionsApiV1ReplayCleanupPostError, CleanupOldSessionsApiV1ReplayCleanupPostErrors, CleanupOldSessionsApiV1ReplayCleanupPostResponse, CleanupOldSessionsApiV1ReplayCleanupPostResponses, CleanupResponse, ClientOptions, ContainerStatusInfo, CreateExecutionApiV1ExecutePostData, CreateExecutionApiV1ExecutePostError, CreateExecutionApiV1ExecutePostErrors, CreateExecutionApiV1ExecutePostResponse, CreateExecutionApiV1ExecutePostResponses, CreatePodCommandEvent, CreateReplaySessionApiV1ReplaySessionsPostData, CreateReplaySessionApiV1ReplaySessionsPostError, CreateReplaySessionApiV1ReplaySessionsPostErrors, CreateReplaySessionApiV1ReplaySessionsPostResponse, CreateReplaySessionApiV1ReplaySessionsPostResponses, CreateSavedScriptApiV1ScriptsPostData, CreateSavedScriptApiV1ScriptsPostError, CreateSavedScriptApiV1ScriptsPostErrors, CreateSavedScriptApiV1ScriptsPostResponse, CreateSavedScriptApiV1ScriptsPostResponses, CreateUserApiV1AdminUsersPostData, CreateUserApiV1AdminUsersPostError, CreateUserApiV1AdminUsersPostErrors, CreateUserApiV1AdminUsersPostResponse, CreateUserApiV1AdminUsersPostResponses, DeleteEventApiV1AdminEventsEventIdDeleteData, DeleteEventApiV1AdminEventsEventIdDeleteError, DeleteEventApiV1AdminEventsEventIdDeleteErrors, DeleteEventApiV1AdminEventsEventIdDeleteResponse, DeleteEventApiV1AdminEventsEventIdDeleteResponses, DeleteExecutionApiV1ExecutionsExecutionIdDeleteData, DeleteExecutionApiV1ExecutionsExecutionIdDeleteError, DeleteExecutionApiV1ExecutionsExecutionIdDeleteErrors, DeleteExecutionApiV1ExecutionsExecutionIdDeleteResponse, DeleteExecutionApiV1ExecutionsExecutionIdDeleteResponses, DeleteNotificationApiV1NotificationsNotificationIdDeleteData, DeleteNotificationApiV1NotificationsNotificationIdDeleteError, DeleteNotificationApiV1NotificationsNotificationIdDeleteErrors, DeleteNotificationApiV1NotificationsNotificationIdDeleteResponse, DeleteNotificationApiV1NotificationsNotificationIdDeleteResponses, DeleteNotificationResponse, DeletePodCommandEvent, DeleteResponse, DeleteSavedScriptApiV1ScriptsScriptIdDeleteData, DeleteSavedScriptApiV1ScriptsScriptIdDeleteError, DeleteSavedScriptApiV1ScriptsScriptIdDeleteErrors, DeleteSavedScriptApiV1ScriptsScriptIdDeleteResponse, DeleteSavedScriptApiV1ScriptsScriptIdDeleteResponses, DeleteUserApiV1AdminUsersUserIdDeleteData, DeleteUserApiV1AdminUsersUserIdDeleteError, DeleteUserApiV1AdminUsersUserIdDeleteErrors, DeleteUserApiV1AdminUsersUserIdDeleteResponse, DeleteUserApiV1AdminUsersUserIdDeleteResponses, DeleteUserResponse, DerivedCounts, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteData, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteError, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteErrors, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponse, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponses, DlqBatchRetryResponse, DlqMessageDetail, DlqMessageDiscardedEvent, DlqMessageReceivedEvent, DlqMessageResponse, DlqMessageRetriedEvent, DlqMessagesResponse, DlqMessageStatus, DlqRetryResult, DlqTopicSummaryResponse, EditorSettings, EndpointGroup, EndpointUsageStats, Environment, ErrorResponse, EventBrowseRequest, EventBrowseResponse, EventDeleteResponse, EventDetailResponse, EventFilter, EventMetadata, EventReplayRequest, EventReplayResponse, EventReplayStatusResponse, EventReplayStatusResponseWritable, EventStatistics, EventStatsResponse, EventSummary, EventType, EventTypeCount, ExampleScripts, ExecutionAcceptedEvent, ExecutionCancelledEvent, ExecutionCompletedEvent, ExecutionErrorType, ExecutionEventsApiV1EventsExecutionsExecutionIdGetData, ExecutionEventsApiV1EventsExecutionsExecutionIdGetError, ExecutionEventsApiV1EventsExecutionsExecutionIdGetErrors, ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponse, ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponses, ExecutionFailedEvent, ExecutionListResponse, ExecutionQueuedEvent, ExecutionRequest, ExecutionRequestedEvent, ExecutionResponse, ExecutionResult, ExecutionRunningEvent, ExecutionStartedEvent, ExecutionStatus, ExecutionTimeoutEvent, ExportEventsApiV1AdminEventsExportExportFormatGetData, ExportEventsApiV1AdminEventsExportExportFormatGetError, ExportEventsApiV1AdminEventsExportExportFormatGetErrors, ExportEventsApiV1AdminEventsExportExportFormatGetResponses, ExportFormat, GetCurrentUserProfileApiV1AuthMeGetData, GetCurrentUserProfileApiV1AuthMeGetResponse, GetCurrentUserProfileApiV1AuthMeGetResponses, GetDlqMessageApiV1DlqMessagesEventIdGetData, GetDlqMessageApiV1DlqMessagesEventIdGetError, GetDlqMessageApiV1DlqMessagesEventIdGetErrors, GetDlqMessageApiV1DlqMessagesEventIdGetResponse, GetDlqMessageApiV1DlqMessagesEventIdGetResponses, GetDlqMessagesApiV1DlqMessagesGetData, GetDlqMessagesApiV1DlqMessagesGetError, GetDlqMessagesApiV1DlqMessagesGetErrors, GetDlqMessagesApiV1DlqMessagesGetResponse, GetDlqMessagesApiV1DlqMessagesGetResponses, GetDlqTopicsApiV1DlqTopicsGetData, GetDlqTopicsApiV1DlqTopicsGetResponse, GetDlqTopicsApiV1DlqTopicsGetResponses, GetEventDetailApiV1AdminEventsEventIdGetData, GetEventDetailApiV1AdminEventsEventIdGetError, GetEventDetailApiV1AdminEventsEventIdGetErrors, GetEventDetailApiV1AdminEventsEventIdGetResponse, GetEventDetailApiV1AdminEventsEventIdGetResponses, GetEventStatsApiV1AdminEventsStatsGetData, GetEventStatsApiV1AdminEventsStatsGetError, GetEventStatsApiV1AdminEventsStatsGetErrors, GetEventStatsApiV1AdminEventsStatsGetResponse, GetEventStatsApiV1AdminEventsStatsGetResponses, GetExampleScriptsApiV1ExampleScriptsGetData, GetExampleScriptsApiV1ExampleScriptsGetResponse, GetExampleScriptsApiV1ExampleScriptsGetResponses, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetData, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetError, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetErrors, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetResponse, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetResponses, GetExecutionSagasApiV1SagasExecutionExecutionIdGetData, GetExecutionSagasApiV1SagasExecutionExecutionIdGetError, GetExecutionSagasApiV1SagasExecutionExecutionIdGetErrors, GetExecutionSagasApiV1SagasExecutionExecutionIdGetResponse, GetExecutionSagasApiV1SagasExecutionExecutionIdGetResponses, GetK8sResourceLimitsApiV1K8sLimitsGetData, GetK8sResourceLimitsApiV1K8sLimitsGetResponse, GetK8sResourceLimitsApiV1K8sLimitsGetResponses, GetNotificationsApiV1NotificationsGetData, GetNotificationsApiV1NotificationsGetError, GetNotificationsApiV1NotificationsGetErrors, GetNotificationsApiV1NotificationsGetResponse, GetNotificationsApiV1NotificationsGetResponses, GetReplaySessionApiV1ReplaySessionsSessionIdGetData, GetReplaySessionApiV1ReplaySessionsSessionIdGetError, GetReplaySessionApiV1ReplaySessionsSessionIdGetErrors, GetReplaySessionApiV1ReplaySessionsSessionIdGetResponse, GetReplaySessionApiV1ReplaySessionsSessionIdGetResponses, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetData, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetError, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetErrors, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetResponse, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetResponses, GetResultApiV1ExecutionsExecutionIdResultGetData, GetResultApiV1ExecutionsExecutionIdResultGetError, GetResultApiV1ExecutionsExecutionIdResultGetErrors, GetResultApiV1ExecutionsExecutionIdResultGetResponse, GetResultApiV1ExecutionsExecutionIdResultGetResponses, GetSagaStatusApiV1SagasSagaIdGetData, GetSagaStatusApiV1SagasSagaIdGetError, GetSagaStatusApiV1SagasSagaIdGetErrors, GetSagaStatusApiV1SagasSagaIdGetResponse, GetSagaStatusApiV1SagasSagaIdGetResponses, GetSavedScriptApiV1ScriptsScriptIdGetData, GetSavedScriptApiV1ScriptsScriptIdGetError, GetSavedScriptApiV1ScriptsScriptIdGetErrors, GetSavedScriptApiV1ScriptsScriptIdGetResponse, GetSavedScriptApiV1ScriptsScriptIdGetResponses, GetSettingsHistoryApiV1UserSettingsHistoryGetData, GetSettingsHistoryApiV1UserSettingsHistoryGetError, GetSettingsHistoryApiV1UserSettingsHistoryGetErrors, GetSettingsHistoryApiV1UserSettingsHistoryGetResponse, GetSettingsHistoryApiV1UserSettingsHistoryGetResponses, GetSubscriptionsApiV1NotificationsSubscriptionsGetData, GetSubscriptionsApiV1NotificationsSubscriptionsGetResponse, GetSubscriptionsApiV1NotificationsSubscriptionsGetResponses, GetSystemSettingsApiV1AdminSettingsGetData, GetSystemSettingsApiV1AdminSettingsGetError, GetSystemSettingsApiV1AdminSettingsGetErrors, GetSystemSettingsApiV1AdminSettingsGetResponse, GetSystemSettingsApiV1AdminSettingsGetResponses, GetUnreadCountApiV1NotificationsUnreadCountGetData, GetUnreadCountApiV1NotificationsUnreadCountGetResponse, GetUnreadCountApiV1NotificationsUnreadCountGetResponses, GetUserApiV1AdminUsersUserIdGetData, GetUserApiV1AdminUsersUserIdGetError, GetUserApiV1AdminUsersUserIdGetErrors, GetUserApiV1AdminUsersUserIdGetResponse, GetUserApiV1AdminUsersUserIdGetResponses, GetUserExecutionsApiV1UserExecutionsGetData, GetUserExecutionsApiV1UserExecutionsGetError, GetUserExecutionsApiV1UserExecutionsGetErrors, GetUserExecutionsApiV1UserExecutionsGetResponse, GetUserExecutionsApiV1UserExecutionsGetResponses, GetUserOverviewApiV1AdminUsersUserIdOverviewGetData, GetUserOverviewApiV1AdminUsersUserIdOverviewGetError, GetUserOverviewApiV1AdminUsersUserIdOverviewGetErrors, GetUserOverviewApiV1AdminUsersUserIdOverviewGetResponse, GetUserOverviewApiV1AdminUsersUserIdOverviewGetResponses, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetData, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetError, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetErrors, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetResponse, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetResponses, GetUserSettingsApiV1UserSettingsGetData, GetUserSettingsApiV1UserSettingsGetResponse, GetUserSettingsApiV1UserSettingsGetResponses, HourlyEventCount, HttpValidationError, LanguageInfo, ListReplaySessionsApiV1ReplaySessionsGetData, ListReplaySessionsApiV1ReplaySessionsGetError, ListReplaySessionsApiV1ReplaySessionsGetErrors, ListReplaySessionsApiV1ReplaySessionsGetResponse, ListReplaySessionsApiV1ReplaySessionsGetResponses, ListSagasApiV1SagasGetData, ListSagasApiV1SagasGetError, ListSagasApiV1SagasGetErrors, ListSagasApiV1SagasGetResponse, ListSagasApiV1SagasGetResponses, ListSavedScriptsApiV1ScriptsGetData, ListSavedScriptsApiV1ScriptsGetResponse, ListSavedScriptsApiV1ScriptsGetResponses, ListUsersApiV1AdminUsersGetData, ListUsersApiV1AdminUsersGetError, ListUsersApiV1AdminUsersGetErrors, ListUsersApiV1AdminUsersGetResponse, ListUsersApiV1AdminUsersGetResponses, LivenessApiV1HealthLiveGetData, LivenessApiV1HealthLiveGetResponse, LivenessApiV1HealthLiveGetResponses, LivenessResponse, LoginApiV1AuthLoginPostData, LoginApiV1AuthLoginPostError, LoginApiV1AuthLoginPostErrors, LoginApiV1AuthLoginPostResponse, LoginApiV1AuthLoginPostResponses, LoginMethod, LoginResponse, LogLevel, LogoutApiV1AuthLogoutPostData, LogoutApiV1AuthLogoutPostResponse, LogoutApiV1AuthLogoutPostResponses, ManualRetryRequest, MarkAllReadApiV1NotificationsMarkAllReadPostData, MarkAllReadApiV1NotificationsMarkAllReadPostResponse, MarkAllReadApiV1NotificationsMarkAllReadPostResponses, MarkNotificationReadApiV1NotificationsNotificationIdReadPutData, MarkNotificationReadApiV1NotificationsNotificationIdReadPutError, MarkNotificationReadApiV1NotificationsNotificationIdReadPutErrors, MarkNotificationReadApiV1NotificationsNotificationIdReadPutResponse, MarkNotificationReadApiV1NotificationsNotificationIdReadPutResponses, MessageResponse, NotificationAllReadEvent, NotificationChannel, NotificationClickedEvent, NotificationCreatedEvent, NotificationDeliveredEvent, NotificationFailedEvent, NotificationListResponse, NotificationPreferencesUpdatedEvent, NotificationReadEvent, NotificationResponse, NotificationSentEvent, NotificationSettings, NotificationSeverity, NotificationStatus, NotificationStreamApiV1EventsNotificationsStreamGetData, NotificationStreamApiV1EventsNotificationsStreamGetResponse, NotificationStreamApiV1EventsNotificationsStreamGetResponses, NotificationSubscription, PasswordResetRequest, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostData, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostError, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostErrors, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostResponse, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostResponses, PodCreatedEvent, PodDeletedEvent, PodFailedEvent, PodRunningEvent, PodScheduledEvent, PodSucceededEvent, PodTerminatedEvent, QueuePriority, QuotaExceededEvent, RateLimitAlgorithm, RateLimitExceededEvent, RateLimitRuleRequest, RateLimitRuleResponse, RateLimitSummary, RateLimitUpdateRequest, RateLimitUpdateResponse, RegisterApiV1AuthRegisterPostData, RegisterApiV1AuthRegisterPostError, RegisterApiV1AuthRegisterPostErrors, RegisterApiV1AuthRegisterPostResponse, RegisterApiV1AuthRegisterPostResponses, ReleaseResourcesCommandEvent, ReplayConfigSchema, ReplayError, ReplayEventsApiV1AdminEventsReplayPostData, ReplayEventsApiV1AdminEventsReplayPostError, ReplayEventsApiV1AdminEventsReplayPostErrors, ReplayEventsApiV1AdminEventsReplayPostResponse, ReplayEventsApiV1AdminEventsReplayPostResponses, ReplayFilter, ReplayFilterSchema, ReplayRequest, ReplayResponse, ReplaySession, ReplayStatus, ReplayTarget, ReplayType, ResetSystemSettingsApiV1AdminSettingsResetPostData, ResetSystemSettingsApiV1AdminSettingsResetPostError, ResetSystemSettingsApiV1AdminSettingsResetPostErrors, ResetSystemSettingsApiV1AdminSettingsResetPostResponse, ResetSystemSettingsApiV1AdminSettingsResetPostResponses, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostData, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostError, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostErrors, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostResponse, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostResponses, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostData, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostError, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostErrors, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostResponse, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostResponses, ResourceLimitExceededEvent, ResourceLimits, ResourceUsage, ResourceUsageDomain, RestoreSettingsApiV1UserSettingsRestorePostData, RestoreSettingsApiV1UserSettingsRestorePostError, RestoreSettingsApiV1UserSettingsRestorePostErrors, RestoreSettingsApiV1UserSettingsRestorePostResponse, RestoreSettingsApiV1UserSettingsRestorePostResponses, RestoreSettingsRequest, ResultFailedEvent, ResultStoredEvent, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostData, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostError, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostErrors, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostResponse, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostResponses, RetryDlqMessagesApiV1DlqRetryPostData, RetryDlqMessagesApiV1DlqRetryPostError, RetryDlqMessagesApiV1DlqRetryPostErrors, RetryDlqMessagesApiV1DlqRetryPostResponse, RetryDlqMessagesApiV1DlqRetryPostResponses, RetryExecutionApiV1ExecutionsExecutionIdRetryPostData, RetryExecutionApiV1ExecutionsExecutionIdRetryPostError, RetryExecutionApiV1ExecutionsExecutionIdRetryPostErrors, RetryExecutionApiV1ExecutionsExecutionIdRetryPostResponse, RetryExecutionApiV1ExecutionsExecutionIdRetryPostResponses, RetryPolicyRequest, RetryStrategy, SagaCancellationResponse, SagaCancelledEvent, SagaCompensatedEvent, SagaCompensatingEvent, SagaCompletedEvent, SagaFailedEvent, SagaListResponse, SagaStartedEvent, SagaState, SagaStatusResponse, SavedScriptCreateRequest, SavedScriptListResponse, SavedScriptResponse, SavedScriptUpdate, ScriptDeletedEvent, ScriptSavedEvent, ScriptSharedEvent, SecurityViolationEvent, ServiceEventCount, ServiceRecoveredEvent, ServiceUnhealthyEvent, SessionConfigSummary, SessionSummary, SessionSummaryWritable, SetRetryPolicyApiV1DlqRetryPolicyPostData, SetRetryPolicyApiV1DlqRetryPolicyPostError, SetRetryPolicyApiV1DlqRetryPolicyPostErrors, SetRetryPolicyApiV1DlqRetryPolicyPostResponse, SetRetryPolicyApiV1DlqRetryPolicyPostResponses, SettingsHistoryEntry, SettingsHistoryResponse, SseControlEvent, SseExecutionEventSchema, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostData, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostError, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostErrors, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostResponse, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostResponses, StorageType, SubscriptionsResponse, SubscriptionUpdate, SystemErrorEvent, SystemSettingsSchema, Theme, ThemeUpdateRequest, UnlockResponse, UnlockUserApiV1AdminUsersUserIdUnlockPostData, UnlockUserApiV1AdminUsersUserIdUnlockPostError, UnlockUserApiV1AdminUsersUserIdUnlockPostErrors, UnlockUserApiV1AdminUsersUserIdUnlockPostResponse, UnlockUserApiV1AdminUsersUserIdUnlockPostResponses, UnreadCountResponse, UpdateCustomSettingApiV1UserSettingsCustomKeyPutData, UpdateCustomSettingApiV1UserSettingsCustomKeyPutError, UpdateCustomSettingApiV1UserSettingsCustomKeyPutErrors, UpdateCustomSettingApiV1UserSettingsCustomKeyPutResponse, UpdateCustomSettingApiV1UserSettingsCustomKeyPutResponses, UpdateEditorSettingsApiV1UserSettingsEditorPutData, UpdateEditorSettingsApiV1UserSettingsEditorPutError, UpdateEditorSettingsApiV1UserSettingsEditorPutErrors, UpdateEditorSettingsApiV1UserSettingsEditorPutResponse, UpdateEditorSettingsApiV1UserSettingsEditorPutResponses, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutData, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutError, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutErrors, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutResponse, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutResponses, UpdateSavedScriptApiV1ScriptsScriptIdPutData, UpdateSavedScriptApiV1ScriptsScriptIdPutError, UpdateSavedScriptApiV1ScriptsScriptIdPutErrors, UpdateSavedScriptApiV1ScriptsScriptIdPutResponse, UpdateSavedScriptApiV1ScriptsScriptIdPutResponses, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutData, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutError, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutErrors, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutResponse, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutResponses, UpdateSystemSettingsApiV1AdminSettingsPutData, UpdateSystemSettingsApiV1AdminSettingsPutError, UpdateSystemSettingsApiV1AdminSettingsPutErrors, UpdateSystemSettingsApiV1AdminSettingsPutResponse, UpdateSystemSettingsApiV1AdminSettingsPutResponses, UpdateThemeApiV1UserSettingsThemePutData, UpdateThemeApiV1UserSettingsThemePutError, UpdateThemeApiV1UserSettingsThemePutErrors, UpdateThemeApiV1UserSettingsThemePutResponse, UpdateThemeApiV1UserSettingsThemePutResponses, UpdateUserApiV1AdminUsersUserIdPutData, UpdateUserApiV1AdminUsersUserIdPutError, UpdateUserApiV1AdminUsersUserIdPutErrors, UpdateUserApiV1AdminUsersUserIdPutResponse, UpdateUserApiV1AdminUsersUserIdPutResponses, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutData, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutError, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutErrors, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutResponse, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutResponses, UpdateUserSettingsApiV1UserSettingsPutData, UpdateUserSettingsApiV1UserSettingsPutError, UpdateUserSettingsApiV1UserSettingsPutErrors, UpdateUserSettingsApiV1UserSettingsPutResponse, UpdateUserSettingsApiV1UserSettingsPutResponses, UserCreate, UserDeletedEvent, UserEventCount, UserListResponse, UserLoggedInEvent, UserLoggedOutEvent, UserLoginEvent, UserRateLimitConfigResponse, UserRateLimitsResponse, UserRegisteredEvent, UserResponse, UserRole, UserSettings, UserSettingsUpdate, UserSettingsUpdatedEvent, UserUpdate, UserUpdatedEvent, ValidationError } from './types.gen'; +export { browseEventsApiV1AdminEventsBrowsePost, cancelExecutionApiV1ExecutionsExecutionIdCancelPost, cancelReplaySessionApiV1ReplaySessionsSessionIdCancelPost, cancelSagaApiV1SagasSagaIdCancelPost, cleanupOldSessionsApiV1ReplayCleanupPost, createExecutionApiV1ExecutePost, createReplaySessionApiV1ReplaySessionsPost, createSavedScriptApiV1ScriptsPost, createUserApiV1AdminUsersPost, deleteEventApiV1AdminEventsEventIdDelete, deleteExecutionApiV1ExecutionsExecutionIdDelete, deleteNotificationApiV1NotificationsNotificationIdDelete, deleteSavedScriptApiV1ScriptsScriptIdDelete, deleteUserApiV1AdminUsersUserIdDelete, executionEventsApiV1EventsExecutionsExecutionIdGet, exportEventsApiV1AdminEventsExportExportFormatGet, getCurrentUserProfileApiV1AuthMeGet, getEventDetailApiV1AdminEventsEventIdGet, getEventStatsApiV1AdminEventsStatsGet, getExampleScriptsApiV1ExampleScriptsGet, getExecutionEventsApiV1ExecutionsExecutionIdEventsGet, getExecutionSagasApiV1SagasExecutionExecutionIdGet, getK8sResourceLimitsApiV1K8sLimitsGet, getNotificationsApiV1NotificationsGet, getReplaySessionApiV1ReplaySessionsSessionIdGet, getReplayStatusApiV1AdminEventsReplaySessionIdStatusGet, getResultApiV1ExecutionsExecutionIdResultGet, getSagaStatusApiV1SagasSagaIdGet, getSavedScriptApiV1ScriptsScriptIdGet, getSettingsHistoryApiV1UserSettingsHistoryGet, getSubscriptionsApiV1NotificationsSubscriptionsGet, getSystemSettingsApiV1AdminSettingsGet, getUnreadCountApiV1NotificationsUnreadCountGet, getUserApiV1AdminUsersUserIdGet, getUserExecutionsApiV1UserExecutionsGet, getUserOverviewApiV1AdminUsersUserIdOverviewGet, getUserRateLimitsApiV1AdminUsersUserIdRateLimitsGet, getUserSettingsApiV1UserSettingsGet, listReplaySessionsApiV1ReplaySessionsGet, listSagasApiV1SagasGet, listSavedScriptsApiV1ScriptsGet, listUsersApiV1AdminUsersGet, livenessApiV1HealthLiveGet, loginApiV1AuthLoginPost, logoutApiV1AuthLogoutPost, markAllReadApiV1NotificationsMarkAllReadPost, markNotificationReadApiV1NotificationsNotificationIdReadPut, notificationStreamApiV1EventsNotificationsStreamGet, type Options, pauseReplaySessionApiV1ReplaySessionsSessionIdPausePost, registerApiV1AuthRegisterPost, replayEventsApiV1AdminEventsReplayPost, resetSystemSettingsApiV1AdminSettingsResetPost, resetUserPasswordApiV1AdminUsersUserIdResetPasswordPost, resetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPost, restoreSettingsApiV1UserSettingsRestorePost, resumeReplaySessionApiV1ReplaySessionsSessionIdResumePost, retryExecutionApiV1ExecutionsExecutionIdRetryPost, startReplaySessionApiV1ReplaySessionsSessionIdStartPost, unlockUserApiV1AdminUsersUserIdUnlockPost, updateCustomSettingApiV1UserSettingsCustomKeyPut, updateEditorSettingsApiV1UserSettingsEditorPut, updateNotificationSettingsApiV1UserSettingsNotificationsPut, updateSavedScriptApiV1ScriptsScriptIdPut, updateSubscriptionApiV1NotificationsSubscriptionsChannelPut, updateSystemSettingsApiV1AdminSettingsPut, updateThemeApiV1UserSettingsThemePut, updateUserApiV1AdminUsersUserIdPut, updateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPut, updateUserSettingsApiV1UserSettingsPut } from './sdk.gen'; +export type { AdminUserOverview, AllocateResourcesCommandEvent, AuthFailedEvent, BodyLoginApiV1AuthLoginPost, BrowseEventsApiV1AdminEventsBrowsePostData, BrowseEventsApiV1AdminEventsBrowsePostError, BrowseEventsApiV1AdminEventsBrowsePostErrors, BrowseEventsApiV1AdminEventsBrowsePostResponse, BrowseEventsApiV1AdminEventsBrowsePostResponses, CancelExecutionApiV1ExecutionsExecutionIdCancelPostData, CancelExecutionApiV1ExecutionsExecutionIdCancelPostError, CancelExecutionApiV1ExecutionsExecutionIdCancelPostErrors, CancelExecutionApiV1ExecutionsExecutionIdCancelPostResponse, CancelExecutionApiV1ExecutionsExecutionIdCancelPostResponses, CancelExecutionRequest, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostData, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostError, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostErrors, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostResponse, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostResponses, CancelResponse, CancelSagaApiV1SagasSagaIdCancelPostData, CancelSagaApiV1SagasSagaIdCancelPostError, CancelSagaApiV1SagasSagaIdCancelPostErrors, CancelSagaApiV1SagasSagaIdCancelPostResponse, CancelSagaApiV1SagasSagaIdCancelPostResponses, CancelStatus, CleanupOldSessionsApiV1ReplayCleanupPostData, CleanupOldSessionsApiV1ReplayCleanupPostError, CleanupOldSessionsApiV1ReplayCleanupPostErrors, CleanupOldSessionsApiV1ReplayCleanupPostResponse, CleanupOldSessionsApiV1ReplayCleanupPostResponses, CleanupResponse, ClientOptions, ContainerStatusInfo, CreateExecutionApiV1ExecutePostData, CreateExecutionApiV1ExecutePostError, CreateExecutionApiV1ExecutePostErrors, CreateExecutionApiV1ExecutePostResponse, CreateExecutionApiV1ExecutePostResponses, CreatePodCommandEvent, CreateReplaySessionApiV1ReplaySessionsPostData, CreateReplaySessionApiV1ReplaySessionsPostError, CreateReplaySessionApiV1ReplaySessionsPostErrors, CreateReplaySessionApiV1ReplaySessionsPostResponse, CreateReplaySessionApiV1ReplaySessionsPostResponses, CreateSavedScriptApiV1ScriptsPostData, CreateSavedScriptApiV1ScriptsPostError, CreateSavedScriptApiV1ScriptsPostErrors, CreateSavedScriptApiV1ScriptsPostResponse, CreateSavedScriptApiV1ScriptsPostResponses, CreateUserApiV1AdminUsersPostData, CreateUserApiV1AdminUsersPostError, CreateUserApiV1AdminUsersPostErrors, CreateUserApiV1AdminUsersPostResponse, CreateUserApiV1AdminUsersPostResponses, DeleteEventApiV1AdminEventsEventIdDeleteData, DeleteEventApiV1AdminEventsEventIdDeleteError, DeleteEventApiV1AdminEventsEventIdDeleteErrors, DeleteEventApiV1AdminEventsEventIdDeleteResponse, DeleteEventApiV1AdminEventsEventIdDeleteResponses, DeleteExecutionApiV1ExecutionsExecutionIdDeleteData, DeleteExecutionApiV1ExecutionsExecutionIdDeleteError, DeleteExecutionApiV1ExecutionsExecutionIdDeleteErrors, DeleteExecutionApiV1ExecutionsExecutionIdDeleteResponse, DeleteExecutionApiV1ExecutionsExecutionIdDeleteResponses, DeleteNotificationApiV1NotificationsNotificationIdDeleteData, DeleteNotificationApiV1NotificationsNotificationIdDeleteError, DeleteNotificationApiV1NotificationsNotificationIdDeleteErrors, DeleteNotificationApiV1NotificationsNotificationIdDeleteResponse, DeleteNotificationApiV1NotificationsNotificationIdDeleteResponses, DeleteNotificationResponse, DeletePodCommandEvent, DeleteResponse, DeleteSavedScriptApiV1ScriptsScriptIdDeleteData, DeleteSavedScriptApiV1ScriptsScriptIdDeleteError, DeleteSavedScriptApiV1ScriptsScriptIdDeleteErrors, DeleteSavedScriptApiV1ScriptsScriptIdDeleteResponse, DeleteSavedScriptApiV1ScriptsScriptIdDeleteResponses, DeleteUserApiV1AdminUsersUserIdDeleteData, DeleteUserApiV1AdminUsersUserIdDeleteError, DeleteUserApiV1AdminUsersUserIdDeleteErrors, DeleteUserApiV1AdminUsersUserIdDeleteResponse, DeleteUserApiV1AdminUsersUserIdDeleteResponses, DeleteUserResponse, DerivedCounts, DlqMessageDiscardedEvent, DlqMessageReceivedEvent, DlqMessageRetriedEvent, EditorSettings, EndpointGroup, EndpointUsageStats, Environment, ErrorResponse, EventBrowseRequest, EventBrowseResponse, EventDeleteResponse, EventDetailResponse, EventFilter, EventMetadata, EventReplayRequest, EventReplayResponse, EventReplayStatusResponse, EventReplayStatusResponseWritable, EventStatistics, EventStatsResponse, EventSummary, EventType, EventTypeCount, ExampleScripts, ExecutionAcceptedEvent, ExecutionCancelledEvent, ExecutionCompletedEvent, ExecutionErrorType, ExecutionEventsApiV1EventsExecutionsExecutionIdGetData, ExecutionEventsApiV1EventsExecutionsExecutionIdGetError, ExecutionEventsApiV1EventsExecutionsExecutionIdGetErrors, ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponse, ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponses, ExecutionFailedEvent, ExecutionListResponse, ExecutionQueuedEvent, ExecutionRequest, ExecutionRequestedEvent, ExecutionResponse, ExecutionResult, ExecutionRunningEvent, ExecutionStartedEvent, ExecutionStatus, ExecutionTimeoutEvent, ExportEventsApiV1AdminEventsExportExportFormatGetData, ExportEventsApiV1AdminEventsExportExportFormatGetError, ExportEventsApiV1AdminEventsExportExportFormatGetErrors, ExportEventsApiV1AdminEventsExportExportFormatGetResponses, ExportFormat, GetCurrentUserProfileApiV1AuthMeGetData, GetCurrentUserProfileApiV1AuthMeGetResponse, GetCurrentUserProfileApiV1AuthMeGetResponses, GetEventDetailApiV1AdminEventsEventIdGetData, GetEventDetailApiV1AdminEventsEventIdGetError, GetEventDetailApiV1AdminEventsEventIdGetErrors, GetEventDetailApiV1AdminEventsEventIdGetResponse, GetEventDetailApiV1AdminEventsEventIdGetResponses, GetEventStatsApiV1AdminEventsStatsGetData, GetEventStatsApiV1AdminEventsStatsGetError, GetEventStatsApiV1AdminEventsStatsGetErrors, GetEventStatsApiV1AdminEventsStatsGetResponse, GetEventStatsApiV1AdminEventsStatsGetResponses, GetExampleScriptsApiV1ExampleScriptsGetData, GetExampleScriptsApiV1ExampleScriptsGetResponse, GetExampleScriptsApiV1ExampleScriptsGetResponses, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetData, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetError, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetErrors, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetResponse, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetResponses, GetExecutionSagasApiV1SagasExecutionExecutionIdGetData, GetExecutionSagasApiV1SagasExecutionExecutionIdGetError, GetExecutionSagasApiV1SagasExecutionExecutionIdGetErrors, GetExecutionSagasApiV1SagasExecutionExecutionIdGetResponse, GetExecutionSagasApiV1SagasExecutionExecutionIdGetResponses, GetK8sResourceLimitsApiV1K8sLimitsGetData, GetK8sResourceLimitsApiV1K8sLimitsGetResponse, GetK8sResourceLimitsApiV1K8sLimitsGetResponses, GetNotificationsApiV1NotificationsGetData, GetNotificationsApiV1NotificationsGetError, GetNotificationsApiV1NotificationsGetErrors, GetNotificationsApiV1NotificationsGetResponse, GetNotificationsApiV1NotificationsGetResponses, GetReplaySessionApiV1ReplaySessionsSessionIdGetData, GetReplaySessionApiV1ReplaySessionsSessionIdGetError, GetReplaySessionApiV1ReplaySessionsSessionIdGetErrors, GetReplaySessionApiV1ReplaySessionsSessionIdGetResponse, GetReplaySessionApiV1ReplaySessionsSessionIdGetResponses, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetData, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetError, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetErrors, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetResponse, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetResponses, GetResultApiV1ExecutionsExecutionIdResultGetData, GetResultApiV1ExecutionsExecutionIdResultGetError, GetResultApiV1ExecutionsExecutionIdResultGetErrors, GetResultApiV1ExecutionsExecutionIdResultGetResponse, GetResultApiV1ExecutionsExecutionIdResultGetResponses, GetSagaStatusApiV1SagasSagaIdGetData, GetSagaStatusApiV1SagasSagaIdGetError, GetSagaStatusApiV1SagasSagaIdGetErrors, GetSagaStatusApiV1SagasSagaIdGetResponse, GetSagaStatusApiV1SagasSagaIdGetResponses, GetSavedScriptApiV1ScriptsScriptIdGetData, GetSavedScriptApiV1ScriptsScriptIdGetError, GetSavedScriptApiV1ScriptsScriptIdGetErrors, GetSavedScriptApiV1ScriptsScriptIdGetResponse, GetSavedScriptApiV1ScriptsScriptIdGetResponses, GetSettingsHistoryApiV1UserSettingsHistoryGetData, GetSettingsHistoryApiV1UserSettingsHistoryGetError, GetSettingsHistoryApiV1UserSettingsHistoryGetErrors, GetSettingsHistoryApiV1UserSettingsHistoryGetResponse, GetSettingsHistoryApiV1UserSettingsHistoryGetResponses, GetSubscriptionsApiV1NotificationsSubscriptionsGetData, GetSubscriptionsApiV1NotificationsSubscriptionsGetResponse, GetSubscriptionsApiV1NotificationsSubscriptionsGetResponses, GetSystemSettingsApiV1AdminSettingsGetData, GetSystemSettingsApiV1AdminSettingsGetError, GetSystemSettingsApiV1AdminSettingsGetErrors, GetSystemSettingsApiV1AdminSettingsGetResponse, GetSystemSettingsApiV1AdminSettingsGetResponses, GetUnreadCountApiV1NotificationsUnreadCountGetData, GetUnreadCountApiV1NotificationsUnreadCountGetResponse, GetUnreadCountApiV1NotificationsUnreadCountGetResponses, GetUserApiV1AdminUsersUserIdGetData, GetUserApiV1AdminUsersUserIdGetError, GetUserApiV1AdminUsersUserIdGetErrors, GetUserApiV1AdminUsersUserIdGetResponse, GetUserApiV1AdminUsersUserIdGetResponses, GetUserExecutionsApiV1UserExecutionsGetData, GetUserExecutionsApiV1UserExecutionsGetError, GetUserExecutionsApiV1UserExecutionsGetErrors, GetUserExecutionsApiV1UserExecutionsGetResponse, GetUserExecutionsApiV1UserExecutionsGetResponses, GetUserOverviewApiV1AdminUsersUserIdOverviewGetData, GetUserOverviewApiV1AdminUsersUserIdOverviewGetError, GetUserOverviewApiV1AdminUsersUserIdOverviewGetErrors, GetUserOverviewApiV1AdminUsersUserIdOverviewGetResponse, GetUserOverviewApiV1AdminUsersUserIdOverviewGetResponses, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetData, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetError, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetErrors, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetResponse, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetResponses, GetUserSettingsApiV1UserSettingsGetData, GetUserSettingsApiV1UserSettingsGetResponse, GetUserSettingsApiV1UserSettingsGetResponses, HourlyEventCount, HttpValidationError, LanguageInfo, ListReplaySessionsApiV1ReplaySessionsGetData, ListReplaySessionsApiV1ReplaySessionsGetError, ListReplaySessionsApiV1ReplaySessionsGetErrors, ListReplaySessionsApiV1ReplaySessionsGetResponse, ListReplaySessionsApiV1ReplaySessionsGetResponses, ListSagasApiV1SagasGetData, ListSagasApiV1SagasGetError, ListSagasApiV1SagasGetErrors, ListSagasApiV1SagasGetResponse, ListSagasApiV1SagasGetResponses, ListSavedScriptsApiV1ScriptsGetData, ListSavedScriptsApiV1ScriptsGetResponse, ListSavedScriptsApiV1ScriptsGetResponses, ListUsersApiV1AdminUsersGetData, ListUsersApiV1AdminUsersGetError, ListUsersApiV1AdminUsersGetErrors, ListUsersApiV1AdminUsersGetResponse, ListUsersApiV1AdminUsersGetResponses, LivenessApiV1HealthLiveGetData, LivenessApiV1HealthLiveGetResponse, LivenessApiV1HealthLiveGetResponses, LivenessResponse, LoginApiV1AuthLoginPostData, LoginApiV1AuthLoginPostError, LoginApiV1AuthLoginPostErrors, LoginApiV1AuthLoginPostResponse, LoginApiV1AuthLoginPostResponses, LoginMethod, LoginResponse, LogLevel, LogoutApiV1AuthLogoutPostData, LogoutApiV1AuthLogoutPostResponse, LogoutApiV1AuthLogoutPostResponses, MarkAllReadApiV1NotificationsMarkAllReadPostData, MarkAllReadApiV1NotificationsMarkAllReadPostResponse, MarkAllReadApiV1NotificationsMarkAllReadPostResponses, MarkNotificationReadApiV1NotificationsNotificationIdReadPutData, MarkNotificationReadApiV1NotificationsNotificationIdReadPutError, MarkNotificationReadApiV1NotificationsNotificationIdReadPutErrors, MarkNotificationReadApiV1NotificationsNotificationIdReadPutResponse, MarkNotificationReadApiV1NotificationsNotificationIdReadPutResponses, MessageResponse, NotificationAllReadEvent, NotificationChannel, NotificationClickedEvent, NotificationCreatedEvent, NotificationDeliveredEvent, NotificationFailedEvent, NotificationListResponse, NotificationPreferencesUpdatedEvent, NotificationReadEvent, NotificationResponse, NotificationSentEvent, NotificationSettings, NotificationSeverity, NotificationStatus, NotificationStreamApiV1EventsNotificationsStreamGetData, NotificationStreamApiV1EventsNotificationsStreamGetResponse, NotificationStreamApiV1EventsNotificationsStreamGetResponses, NotificationSubscription, PasswordResetRequest, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostData, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostError, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostErrors, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostResponse, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostResponses, PodCreatedEvent, PodDeletedEvent, PodFailedEvent, PodRunningEvent, PodScheduledEvent, PodSucceededEvent, PodTerminatedEvent, QueuePriority, QuotaExceededEvent, RateLimitAlgorithm, RateLimitExceededEvent, RateLimitRuleRequest, RateLimitRuleResponse, RateLimitSummary, RateLimitUpdateRequest, RateLimitUpdateResponse, RegisterApiV1AuthRegisterPostData, RegisterApiV1AuthRegisterPostError, RegisterApiV1AuthRegisterPostErrors, RegisterApiV1AuthRegisterPostResponse, RegisterApiV1AuthRegisterPostResponses, ReleaseResourcesCommandEvent, ReplayConfigSchema, ReplayError, ReplayEventsApiV1AdminEventsReplayPostData, ReplayEventsApiV1AdminEventsReplayPostError, ReplayEventsApiV1AdminEventsReplayPostErrors, ReplayEventsApiV1AdminEventsReplayPostResponse, ReplayEventsApiV1AdminEventsReplayPostResponses, ReplayFilter, ReplayFilterSchema, ReplayRequest, ReplayResponse, ReplaySession, ReplayStatus, ReplayTarget, ReplayType, ResetSystemSettingsApiV1AdminSettingsResetPostData, ResetSystemSettingsApiV1AdminSettingsResetPostError, ResetSystemSettingsApiV1AdminSettingsResetPostErrors, ResetSystemSettingsApiV1AdminSettingsResetPostResponse, ResetSystemSettingsApiV1AdminSettingsResetPostResponses, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostData, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostError, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostErrors, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostResponse, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostResponses, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostData, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostError, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostErrors, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostResponse, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostResponses, ResourceLimitExceededEvent, ResourceLimits, ResourceUsage, ResourceUsageDomain, RestoreSettingsApiV1UserSettingsRestorePostData, RestoreSettingsApiV1UserSettingsRestorePostError, RestoreSettingsApiV1UserSettingsRestorePostErrors, RestoreSettingsApiV1UserSettingsRestorePostResponse, RestoreSettingsApiV1UserSettingsRestorePostResponses, RestoreSettingsRequest, ResultFailedEvent, ResultStoredEvent, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostData, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostError, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostErrors, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostResponse, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostResponses, RetryExecutionApiV1ExecutionsExecutionIdRetryPostData, RetryExecutionApiV1ExecutionsExecutionIdRetryPostError, RetryExecutionApiV1ExecutionsExecutionIdRetryPostErrors, RetryExecutionApiV1ExecutionsExecutionIdRetryPostResponse, RetryExecutionApiV1ExecutionsExecutionIdRetryPostResponses, SagaCancellationResponse, SagaCancelledEvent, SagaCompensatedEvent, SagaCompensatingEvent, SagaCompletedEvent, SagaFailedEvent, SagaListResponse, SagaStartedEvent, SagaState, SagaStatusResponse, SavedScriptCreateRequest, SavedScriptListResponse, SavedScriptResponse, SavedScriptUpdate, ScriptDeletedEvent, ScriptSavedEvent, ScriptSharedEvent, SecurityViolationEvent, ServiceEventCount, ServiceRecoveredEvent, ServiceUnhealthyEvent, SessionConfigSummary, SessionSummary, SessionSummaryWritable, SettingsHistoryEntry, SettingsHistoryResponse, SseControlEvent, SseExecutionEventSchema, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostData, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostError, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostErrors, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostResponse, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostResponses, StorageType, SubscriptionsResponse, SubscriptionUpdate, SystemErrorEvent, SystemSettingsSchema, Theme, ThemeUpdateRequest, UnlockResponse, UnlockUserApiV1AdminUsersUserIdUnlockPostData, UnlockUserApiV1AdminUsersUserIdUnlockPostError, UnlockUserApiV1AdminUsersUserIdUnlockPostErrors, UnlockUserApiV1AdminUsersUserIdUnlockPostResponse, UnlockUserApiV1AdminUsersUserIdUnlockPostResponses, UnreadCountResponse, UpdateCustomSettingApiV1UserSettingsCustomKeyPutData, UpdateCustomSettingApiV1UserSettingsCustomKeyPutError, UpdateCustomSettingApiV1UserSettingsCustomKeyPutErrors, UpdateCustomSettingApiV1UserSettingsCustomKeyPutResponse, UpdateCustomSettingApiV1UserSettingsCustomKeyPutResponses, UpdateEditorSettingsApiV1UserSettingsEditorPutData, UpdateEditorSettingsApiV1UserSettingsEditorPutError, UpdateEditorSettingsApiV1UserSettingsEditorPutErrors, UpdateEditorSettingsApiV1UserSettingsEditorPutResponse, UpdateEditorSettingsApiV1UserSettingsEditorPutResponses, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutData, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutError, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutErrors, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutResponse, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutResponses, UpdateSavedScriptApiV1ScriptsScriptIdPutData, UpdateSavedScriptApiV1ScriptsScriptIdPutError, UpdateSavedScriptApiV1ScriptsScriptIdPutErrors, UpdateSavedScriptApiV1ScriptsScriptIdPutResponse, UpdateSavedScriptApiV1ScriptsScriptIdPutResponses, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutData, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutError, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutErrors, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutResponse, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutResponses, UpdateSystemSettingsApiV1AdminSettingsPutData, UpdateSystemSettingsApiV1AdminSettingsPutError, UpdateSystemSettingsApiV1AdminSettingsPutErrors, UpdateSystemSettingsApiV1AdminSettingsPutResponse, UpdateSystemSettingsApiV1AdminSettingsPutResponses, UpdateThemeApiV1UserSettingsThemePutData, UpdateThemeApiV1UserSettingsThemePutError, UpdateThemeApiV1UserSettingsThemePutErrors, UpdateThemeApiV1UserSettingsThemePutResponse, UpdateThemeApiV1UserSettingsThemePutResponses, UpdateUserApiV1AdminUsersUserIdPutData, UpdateUserApiV1AdminUsersUserIdPutError, UpdateUserApiV1AdminUsersUserIdPutErrors, UpdateUserApiV1AdminUsersUserIdPutResponse, UpdateUserApiV1AdminUsersUserIdPutResponses, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutData, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutError, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutErrors, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutResponse, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutResponses, UpdateUserSettingsApiV1UserSettingsPutData, UpdateUserSettingsApiV1UserSettingsPutError, UpdateUserSettingsApiV1UserSettingsPutErrors, UpdateUserSettingsApiV1UserSettingsPutResponse, UpdateUserSettingsApiV1UserSettingsPutResponses, UserCreate, UserDeletedEvent, UserEventCount, UserListResponse, UserLoggedInEvent, UserLoggedOutEvent, UserLoginEvent, UserRateLimitConfigResponse, UserRateLimitsResponse, UserRegisteredEvent, UserResponse, UserRole, UserSettings, UserSettingsUpdate, UserSettingsUpdatedEvent, UserUpdate, UserUpdatedEvent, ValidationError } from './types.gen'; diff --git a/frontend/src/lib/api/sdk.gen.ts b/frontend/src/lib/api/sdk.gen.ts index 0443ada6..54de5d8b 100644 --- a/frontend/src/lib/api/sdk.gen.ts +++ b/frontend/src/lib/api/sdk.gen.ts @@ -2,7 +2,7 @@ import { type Client, type Options as Options2, type TDataShape, urlSearchParamsBodySerializer } from './client'; import { client } from './client.gen'; -import type { BrowseEventsApiV1AdminEventsBrowsePostData, BrowseEventsApiV1AdminEventsBrowsePostErrors, BrowseEventsApiV1AdminEventsBrowsePostResponses, CancelExecutionApiV1ExecutionsExecutionIdCancelPostData, CancelExecutionApiV1ExecutionsExecutionIdCancelPostErrors, CancelExecutionApiV1ExecutionsExecutionIdCancelPostResponses, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostData, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostErrors, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostResponses, CancelSagaApiV1SagasSagaIdCancelPostData, CancelSagaApiV1SagasSagaIdCancelPostErrors, CancelSagaApiV1SagasSagaIdCancelPostResponses, CleanupOldSessionsApiV1ReplayCleanupPostData, CleanupOldSessionsApiV1ReplayCleanupPostErrors, CleanupOldSessionsApiV1ReplayCleanupPostResponses, CreateExecutionApiV1ExecutePostData, CreateExecutionApiV1ExecutePostErrors, CreateExecutionApiV1ExecutePostResponses, CreateReplaySessionApiV1ReplaySessionsPostData, CreateReplaySessionApiV1ReplaySessionsPostErrors, CreateReplaySessionApiV1ReplaySessionsPostResponses, CreateSavedScriptApiV1ScriptsPostData, CreateSavedScriptApiV1ScriptsPostErrors, CreateSavedScriptApiV1ScriptsPostResponses, CreateUserApiV1AdminUsersPostData, CreateUserApiV1AdminUsersPostErrors, CreateUserApiV1AdminUsersPostResponses, DeleteEventApiV1AdminEventsEventIdDeleteData, DeleteEventApiV1AdminEventsEventIdDeleteErrors, DeleteEventApiV1AdminEventsEventIdDeleteResponses, DeleteExecutionApiV1ExecutionsExecutionIdDeleteData, DeleteExecutionApiV1ExecutionsExecutionIdDeleteErrors, DeleteExecutionApiV1ExecutionsExecutionIdDeleteResponses, DeleteNotificationApiV1NotificationsNotificationIdDeleteData, DeleteNotificationApiV1NotificationsNotificationIdDeleteErrors, DeleteNotificationApiV1NotificationsNotificationIdDeleteResponses, DeleteSavedScriptApiV1ScriptsScriptIdDeleteData, DeleteSavedScriptApiV1ScriptsScriptIdDeleteErrors, DeleteSavedScriptApiV1ScriptsScriptIdDeleteResponses, DeleteUserApiV1AdminUsersUserIdDeleteData, DeleteUserApiV1AdminUsersUserIdDeleteErrors, DeleteUserApiV1AdminUsersUserIdDeleteResponses, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteData, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteErrors, DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponses, ExecutionEventsApiV1EventsExecutionsExecutionIdGetData, ExecutionEventsApiV1EventsExecutionsExecutionIdGetErrors, ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponses, ExportEventsApiV1AdminEventsExportExportFormatGetData, ExportEventsApiV1AdminEventsExportExportFormatGetErrors, ExportEventsApiV1AdminEventsExportExportFormatGetResponses, GetCurrentUserProfileApiV1AuthMeGetData, GetCurrentUserProfileApiV1AuthMeGetResponses, GetDlqMessageApiV1DlqMessagesEventIdGetData, GetDlqMessageApiV1DlqMessagesEventIdGetErrors, GetDlqMessageApiV1DlqMessagesEventIdGetResponses, GetDlqMessagesApiV1DlqMessagesGetData, GetDlqMessagesApiV1DlqMessagesGetErrors, GetDlqMessagesApiV1DlqMessagesGetResponses, GetDlqTopicsApiV1DlqTopicsGetData, GetDlqTopicsApiV1DlqTopicsGetResponses, GetEventDetailApiV1AdminEventsEventIdGetData, GetEventDetailApiV1AdminEventsEventIdGetErrors, GetEventDetailApiV1AdminEventsEventIdGetResponses, GetEventStatsApiV1AdminEventsStatsGetData, GetEventStatsApiV1AdminEventsStatsGetErrors, GetEventStatsApiV1AdminEventsStatsGetResponses, GetExampleScriptsApiV1ExampleScriptsGetData, GetExampleScriptsApiV1ExampleScriptsGetResponses, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetData, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetErrors, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetResponses, GetExecutionSagasApiV1SagasExecutionExecutionIdGetData, GetExecutionSagasApiV1SagasExecutionExecutionIdGetErrors, GetExecutionSagasApiV1SagasExecutionExecutionIdGetResponses, GetK8sResourceLimitsApiV1K8sLimitsGetData, GetK8sResourceLimitsApiV1K8sLimitsGetResponses, GetNotificationsApiV1NotificationsGetData, GetNotificationsApiV1NotificationsGetErrors, GetNotificationsApiV1NotificationsGetResponses, GetReplaySessionApiV1ReplaySessionsSessionIdGetData, GetReplaySessionApiV1ReplaySessionsSessionIdGetErrors, GetReplaySessionApiV1ReplaySessionsSessionIdGetResponses, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetData, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetErrors, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetResponses, GetResultApiV1ExecutionsExecutionIdResultGetData, GetResultApiV1ExecutionsExecutionIdResultGetErrors, GetResultApiV1ExecutionsExecutionIdResultGetResponses, GetSagaStatusApiV1SagasSagaIdGetData, GetSagaStatusApiV1SagasSagaIdGetErrors, GetSagaStatusApiV1SagasSagaIdGetResponses, GetSavedScriptApiV1ScriptsScriptIdGetData, GetSavedScriptApiV1ScriptsScriptIdGetErrors, GetSavedScriptApiV1ScriptsScriptIdGetResponses, GetSettingsHistoryApiV1UserSettingsHistoryGetData, GetSettingsHistoryApiV1UserSettingsHistoryGetErrors, GetSettingsHistoryApiV1UserSettingsHistoryGetResponses, GetSubscriptionsApiV1NotificationsSubscriptionsGetData, GetSubscriptionsApiV1NotificationsSubscriptionsGetResponses, GetSystemSettingsApiV1AdminSettingsGetData, GetSystemSettingsApiV1AdminSettingsGetErrors, GetSystemSettingsApiV1AdminSettingsGetResponses, GetUnreadCountApiV1NotificationsUnreadCountGetData, GetUnreadCountApiV1NotificationsUnreadCountGetResponses, GetUserApiV1AdminUsersUserIdGetData, GetUserApiV1AdminUsersUserIdGetErrors, GetUserApiV1AdminUsersUserIdGetResponses, GetUserExecutionsApiV1UserExecutionsGetData, GetUserExecutionsApiV1UserExecutionsGetErrors, GetUserExecutionsApiV1UserExecutionsGetResponses, GetUserOverviewApiV1AdminUsersUserIdOverviewGetData, GetUserOverviewApiV1AdminUsersUserIdOverviewGetErrors, GetUserOverviewApiV1AdminUsersUserIdOverviewGetResponses, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetData, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetErrors, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetResponses, GetUserSettingsApiV1UserSettingsGetData, GetUserSettingsApiV1UserSettingsGetResponses, ListReplaySessionsApiV1ReplaySessionsGetData, ListReplaySessionsApiV1ReplaySessionsGetErrors, ListReplaySessionsApiV1ReplaySessionsGetResponses, ListSagasApiV1SagasGetData, ListSagasApiV1SagasGetErrors, ListSagasApiV1SagasGetResponses, ListSavedScriptsApiV1ScriptsGetData, ListSavedScriptsApiV1ScriptsGetResponses, ListUsersApiV1AdminUsersGetData, ListUsersApiV1AdminUsersGetErrors, ListUsersApiV1AdminUsersGetResponses, LivenessApiV1HealthLiveGetData, LivenessApiV1HealthLiveGetResponses, LoginApiV1AuthLoginPostData, LoginApiV1AuthLoginPostErrors, LoginApiV1AuthLoginPostResponses, LogoutApiV1AuthLogoutPostData, LogoutApiV1AuthLogoutPostResponses, MarkAllReadApiV1NotificationsMarkAllReadPostData, MarkAllReadApiV1NotificationsMarkAllReadPostResponses, MarkNotificationReadApiV1NotificationsNotificationIdReadPutData, MarkNotificationReadApiV1NotificationsNotificationIdReadPutErrors, MarkNotificationReadApiV1NotificationsNotificationIdReadPutResponses, NotificationStreamApiV1EventsNotificationsStreamGetData, NotificationStreamApiV1EventsNotificationsStreamGetResponses, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostData, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostErrors, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostResponses, RegisterApiV1AuthRegisterPostData, RegisterApiV1AuthRegisterPostErrors, RegisterApiV1AuthRegisterPostResponses, ReplayEventsApiV1AdminEventsReplayPostData, ReplayEventsApiV1AdminEventsReplayPostErrors, ReplayEventsApiV1AdminEventsReplayPostResponses, ResetSystemSettingsApiV1AdminSettingsResetPostData, ResetSystemSettingsApiV1AdminSettingsResetPostErrors, ResetSystemSettingsApiV1AdminSettingsResetPostResponses, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostData, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostErrors, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostResponses, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostData, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostErrors, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostResponses, RestoreSettingsApiV1UserSettingsRestorePostData, RestoreSettingsApiV1UserSettingsRestorePostErrors, RestoreSettingsApiV1UserSettingsRestorePostResponses, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostData, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostErrors, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostResponses, RetryDlqMessagesApiV1DlqRetryPostData, RetryDlqMessagesApiV1DlqRetryPostErrors, RetryDlqMessagesApiV1DlqRetryPostResponses, RetryExecutionApiV1ExecutionsExecutionIdRetryPostData, RetryExecutionApiV1ExecutionsExecutionIdRetryPostErrors, RetryExecutionApiV1ExecutionsExecutionIdRetryPostResponses, SetRetryPolicyApiV1DlqRetryPolicyPostData, SetRetryPolicyApiV1DlqRetryPolicyPostErrors, SetRetryPolicyApiV1DlqRetryPolicyPostResponses, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostData, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostErrors, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostResponses, UnlockUserApiV1AdminUsersUserIdUnlockPostData, UnlockUserApiV1AdminUsersUserIdUnlockPostErrors, UnlockUserApiV1AdminUsersUserIdUnlockPostResponses, UpdateCustomSettingApiV1UserSettingsCustomKeyPutData, UpdateCustomSettingApiV1UserSettingsCustomKeyPutErrors, UpdateCustomSettingApiV1UserSettingsCustomKeyPutResponses, UpdateEditorSettingsApiV1UserSettingsEditorPutData, UpdateEditorSettingsApiV1UserSettingsEditorPutErrors, UpdateEditorSettingsApiV1UserSettingsEditorPutResponses, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutData, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutErrors, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutResponses, UpdateSavedScriptApiV1ScriptsScriptIdPutData, UpdateSavedScriptApiV1ScriptsScriptIdPutErrors, UpdateSavedScriptApiV1ScriptsScriptIdPutResponses, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutData, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutErrors, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutResponses, UpdateSystemSettingsApiV1AdminSettingsPutData, UpdateSystemSettingsApiV1AdminSettingsPutErrors, UpdateSystemSettingsApiV1AdminSettingsPutResponses, UpdateThemeApiV1UserSettingsThemePutData, UpdateThemeApiV1UserSettingsThemePutErrors, UpdateThemeApiV1UserSettingsThemePutResponses, UpdateUserApiV1AdminUsersUserIdPutData, UpdateUserApiV1AdminUsersUserIdPutErrors, UpdateUserApiV1AdminUsersUserIdPutResponses, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutData, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutErrors, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutResponses, UpdateUserSettingsApiV1UserSettingsPutData, UpdateUserSettingsApiV1UserSettingsPutErrors, UpdateUserSettingsApiV1UserSettingsPutResponses } from './types.gen'; +import type { BrowseEventsApiV1AdminEventsBrowsePostData, BrowseEventsApiV1AdminEventsBrowsePostErrors, BrowseEventsApiV1AdminEventsBrowsePostResponses, CancelExecutionApiV1ExecutionsExecutionIdCancelPostData, CancelExecutionApiV1ExecutionsExecutionIdCancelPostErrors, CancelExecutionApiV1ExecutionsExecutionIdCancelPostResponses, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostData, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostErrors, CancelReplaySessionApiV1ReplaySessionsSessionIdCancelPostResponses, CancelSagaApiV1SagasSagaIdCancelPostData, CancelSagaApiV1SagasSagaIdCancelPostErrors, CancelSagaApiV1SagasSagaIdCancelPostResponses, CleanupOldSessionsApiV1ReplayCleanupPostData, CleanupOldSessionsApiV1ReplayCleanupPostErrors, CleanupOldSessionsApiV1ReplayCleanupPostResponses, CreateExecutionApiV1ExecutePostData, CreateExecutionApiV1ExecutePostErrors, CreateExecutionApiV1ExecutePostResponses, CreateReplaySessionApiV1ReplaySessionsPostData, CreateReplaySessionApiV1ReplaySessionsPostErrors, CreateReplaySessionApiV1ReplaySessionsPostResponses, CreateSavedScriptApiV1ScriptsPostData, CreateSavedScriptApiV1ScriptsPostErrors, CreateSavedScriptApiV1ScriptsPostResponses, CreateUserApiV1AdminUsersPostData, CreateUserApiV1AdminUsersPostErrors, CreateUserApiV1AdminUsersPostResponses, DeleteEventApiV1AdminEventsEventIdDeleteData, DeleteEventApiV1AdminEventsEventIdDeleteErrors, DeleteEventApiV1AdminEventsEventIdDeleteResponses, DeleteExecutionApiV1ExecutionsExecutionIdDeleteData, DeleteExecutionApiV1ExecutionsExecutionIdDeleteErrors, DeleteExecutionApiV1ExecutionsExecutionIdDeleteResponses, DeleteNotificationApiV1NotificationsNotificationIdDeleteData, DeleteNotificationApiV1NotificationsNotificationIdDeleteErrors, DeleteNotificationApiV1NotificationsNotificationIdDeleteResponses, DeleteSavedScriptApiV1ScriptsScriptIdDeleteData, DeleteSavedScriptApiV1ScriptsScriptIdDeleteErrors, DeleteSavedScriptApiV1ScriptsScriptIdDeleteResponses, DeleteUserApiV1AdminUsersUserIdDeleteData, DeleteUserApiV1AdminUsersUserIdDeleteErrors, DeleteUserApiV1AdminUsersUserIdDeleteResponses, ExecutionEventsApiV1EventsExecutionsExecutionIdGetData, ExecutionEventsApiV1EventsExecutionsExecutionIdGetErrors, ExecutionEventsApiV1EventsExecutionsExecutionIdGetResponses, ExportEventsApiV1AdminEventsExportExportFormatGetData, ExportEventsApiV1AdminEventsExportExportFormatGetErrors, ExportEventsApiV1AdminEventsExportExportFormatGetResponses, GetCurrentUserProfileApiV1AuthMeGetData, GetCurrentUserProfileApiV1AuthMeGetResponses, GetEventDetailApiV1AdminEventsEventIdGetData, GetEventDetailApiV1AdminEventsEventIdGetErrors, GetEventDetailApiV1AdminEventsEventIdGetResponses, GetEventStatsApiV1AdminEventsStatsGetData, GetEventStatsApiV1AdminEventsStatsGetErrors, GetEventStatsApiV1AdminEventsStatsGetResponses, GetExampleScriptsApiV1ExampleScriptsGetData, GetExampleScriptsApiV1ExampleScriptsGetResponses, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetData, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetErrors, GetExecutionEventsApiV1ExecutionsExecutionIdEventsGetResponses, GetExecutionSagasApiV1SagasExecutionExecutionIdGetData, GetExecutionSagasApiV1SagasExecutionExecutionIdGetErrors, GetExecutionSagasApiV1SagasExecutionExecutionIdGetResponses, GetK8sResourceLimitsApiV1K8sLimitsGetData, GetK8sResourceLimitsApiV1K8sLimitsGetResponses, GetNotificationsApiV1NotificationsGetData, GetNotificationsApiV1NotificationsGetErrors, GetNotificationsApiV1NotificationsGetResponses, GetReplaySessionApiV1ReplaySessionsSessionIdGetData, GetReplaySessionApiV1ReplaySessionsSessionIdGetErrors, GetReplaySessionApiV1ReplaySessionsSessionIdGetResponses, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetData, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetErrors, GetReplayStatusApiV1AdminEventsReplaySessionIdStatusGetResponses, GetResultApiV1ExecutionsExecutionIdResultGetData, GetResultApiV1ExecutionsExecutionIdResultGetErrors, GetResultApiV1ExecutionsExecutionIdResultGetResponses, GetSagaStatusApiV1SagasSagaIdGetData, GetSagaStatusApiV1SagasSagaIdGetErrors, GetSagaStatusApiV1SagasSagaIdGetResponses, GetSavedScriptApiV1ScriptsScriptIdGetData, GetSavedScriptApiV1ScriptsScriptIdGetErrors, GetSavedScriptApiV1ScriptsScriptIdGetResponses, GetSettingsHistoryApiV1UserSettingsHistoryGetData, GetSettingsHistoryApiV1UserSettingsHistoryGetErrors, GetSettingsHistoryApiV1UserSettingsHistoryGetResponses, GetSubscriptionsApiV1NotificationsSubscriptionsGetData, GetSubscriptionsApiV1NotificationsSubscriptionsGetResponses, GetSystemSettingsApiV1AdminSettingsGetData, GetSystemSettingsApiV1AdminSettingsGetErrors, GetSystemSettingsApiV1AdminSettingsGetResponses, GetUnreadCountApiV1NotificationsUnreadCountGetData, GetUnreadCountApiV1NotificationsUnreadCountGetResponses, GetUserApiV1AdminUsersUserIdGetData, GetUserApiV1AdminUsersUserIdGetErrors, GetUserApiV1AdminUsersUserIdGetResponses, GetUserExecutionsApiV1UserExecutionsGetData, GetUserExecutionsApiV1UserExecutionsGetErrors, GetUserExecutionsApiV1UserExecutionsGetResponses, GetUserOverviewApiV1AdminUsersUserIdOverviewGetData, GetUserOverviewApiV1AdminUsersUserIdOverviewGetErrors, GetUserOverviewApiV1AdminUsersUserIdOverviewGetResponses, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetData, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetErrors, GetUserRateLimitsApiV1AdminUsersUserIdRateLimitsGetResponses, GetUserSettingsApiV1UserSettingsGetData, GetUserSettingsApiV1UserSettingsGetResponses, ListReplaySessionsApiV1ReplaySessionsGetData, ListReplaySessionsApiV1ReplaySessionsGetErrors, ListReplaySessionsApiV1ReplaySessionsGetResponses, ListSagasApiV1SagasGetData, ListSagasApiV1SagasGetErrors, ListSagasApiV1SagasGetResponses, ListSavedScriptsApiV1ScriptsGetData, ListSavedScriptsApiV1ScriptsGetResponses, ListUsersApiV1AdminUsersGetData, ListUsersApiV1AdminUsersGetErrors, ListUsersApiV1AdminUsersGetResponses, LivenessApiV1HealthLiveGetData, LivenessApiV1HealthLiveGetResponses, LoginApiV1AuthLoginPostData, LoginApiV1AuthLoginPostErrors, LoginApiV1AuthLoginPostResponses, LogoutApiV1AuthLogoutPostData, LogoutApiV1AuthLogoutPostResponses, MarkAllReadApiV1NotificationsMarkAllReadPostData, MarkAllReadApiV1NotificationsMarkAllReadPostResponses, MarkNotificationReadApiV1NotificationsNotificationIdReadPutData, MarkNotificationReadApiV1NotificationsNotificationIdReadPutErrors, MarkNotificationReadApiV1NotificationsNotificationIdReadPutResponses, NotificationStreamApiV1EventsNotificationsStreamGetData, NotificationStreamApiV1EventsNotificationsStreamGetResponses, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostData, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostErrors, PauseReplaySessionApiV1ReplaySessionsSessionIdPausePostResponses, RegisterApiV1AuthRegisterPostData, RegisterApiV1AuthRegisterPostErrors, RegisterApiV1AuthRegisterPostResponses, ReplayEventsApiV1AdminEventsReplayPostData, ReplayEventsApiV1AdminEventsReplayPostErrors, ReplayEventsApiV1AdminEventsReplayPostResponses, ResetSystemSettingsApiV1AdminSettingsResetPostData, ResetSystemSettingsApiV1AdminSettingsResetPostErrors, ResetSystemSettingsApiV1AdminSettingsResetPostResponses, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostData, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostErrors, ResetUserPasswordApiV1AdminUsersUserIdResetPasswordPostResponses, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostData, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostErrors, ResetUserRateLimitsApiV1AdminUsersUserIdRateLimitsResetPostResponses, RestoreSettingsApiV1UserSettingsRestorePostData, RestoreSettingsApiV1UserSettingsRestorePostErrors, RestoreSettingsApiV1UserSettingsRestorePostResponses, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostData, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostErrors, ResumeReplaySessionApiV1ReplaySessionsSessionIdResumePostResponses, RetryExecutionApiV1ExecutionsExecutionIdRetryPostData, RetryExecutionApiV1ExecutionsExecutionIdRetryPostErrors, RetryExecutionApiV1ExecutionsExecutionIdRetryPostResponses, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostData, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostErrors, StartReplaySessionApiV1ReplaySessionsSessionIdStartPostResponses, UnlockUserApiV1AdminUsersUserIdUnlockPostData, UnlockUserApiV1AdminUsersUserIdUnlockPostErrors, UnlockUserApiV1AdminUsersUserIdUnlockPostResponses, UpdateCustomSettingApiV1UserSettingsCustomKeyPutData, UpdateCustomSettingApiV1UserSettingsCustomKeyPutErrors, UpdateCustomSettingApiV1UserSettingsCustomKeyPutResponses, UpdateEditorSettingsApiV1UserSettingsEditorPutData, UpdateEditorSettingsApiV1UserSettingsEditorPutErrors, UpdateEditorSettingsApiV1UserSettingsEditorPutResponses, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutData, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutErrors, UpdateNotificationSettingsApiV1UserSettingsNotificationsPutResponses, UpdateSavedScriptApiV1ScriptsScriptIdPutData, UpdateSavedScriptApiV1ScriptsScriptIdPutErrors, UpdateSavedScriptApiV1ScriptsScriptIdPutResponses, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutData, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutErrors, UpdateSubscriptionApiV1NotificationsSubscriptionsChannelPutResponses, UpdateSystemSettingsApiV1AdminSettingsPutData, UpdateSystemSettingsApiV1AdminSettingsPutErrors, UpdateSystemSettingsApiV1AdminSettingsPutResponses, UpdateThemeApiV1UserSettingsThemePutData, UpdateThemeApiV1UserSettingsThemePutErrors, UpdateThemeApiV1UserSettingsThemePutResponses, UpdateUserApiV1AdminUsersUserIdPutData, UpdateUserApiV1AdminUsersUserIdPutErrors, UpdateUserApiV1AdminUsersUserIdPutResponses, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutData, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutErrors, UpdateUserRateLimitsApiV1AdminUsersUserIdRateLimitsPutResponses, UpdateUserSettingsApiV1UserSettingsPutData, UpdateUserSettingsApiV1UserSettingsPutErrors, UpdateUserSettingsApiV1UserSettingsPutResponses } from './types.gen'; export type Options = Options2 & { /** @@ -257,62 +257,6 @@ export const cleanupOldSessionsApiV1ReplayCleanupPost = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/health/live', ...options }); -/** - * Get Dlq Messages - * - * List DLQ messages with optional filtering. - */ -export const getDlqMessagesApiV1DlqMessagesGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/dlq/messages', ...options }); - -/** - * Discard Dlq Message - * - * Permanently discard a DLQ message with a reason. - */ -export const discardDlqMessageApiV1DlqMessagesEventIdDelete = (options: Options) => (options.client ?? client).delete({ url: '/api/v1/dlq/messages/{event_id}', ...options }); - -/** - * Get Dlq Message - * - * Get details of a specific DLQ message. - */ -export const getDlqMessageApiV1DlqMessagesEventIdGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/dlq/messages/{event_id}', ...options }); - -/** - * Retry Dlq Messages - * - * Retry a batch of DLQ messages by their event IDs. - */ -export const retryDlqMessagesApiV1DlqRetryPost = (options: Options) => (options.client ?? client).post({ - url: '/api/v1/dlq/retry', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options.headers - } -}); - -/** - * Set Retry Policy - * - * Configure a retry policy for a specific Kafka topic. - */ -export const setRetryPolicyApiV1DlqRetryPolicyPost = (options: Options) => (options.client ?? client).post({ - url: '/api/v1/dlq/retry-policy', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options.headers - } -}); - -/** - * Get Dlq Topics - * - * Get a per-topic summary of DLQ message counts. - */ -export const getDlqTopicsApiV1DlqTopicsGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/dlq/topics', ...options }); - /** * Notification Stream * diff --git a/frontend/src/lib/api/types.gen.ts b/frontend/src/lib/api/types.gen.ts index 3f9cc123..90251825 100644 --- a/frontend/src/lib/api/types.gen.ts +++ b/frontend/src/lib/api/types.gen.ts @@ -402,213 +402,6 @@ export type CreatePodCommandEvent = { priority?: QueuePriority; }; -/** - * DLQBatchRetryResponse - * - * Response model for batch retry operation. - */ -export type DlqBatchRetryResponse = { - /** - * Total - */ - total: number; - /** - * Successful - */ - successful: number; - /** - * Failed - */ - failed: number; - /** - * Details - */ - details: Array; -}; - -/** - * DLQMessageDetail - * - * Detailed DLQ message response. Mirrors DLQMessage for direct model_validate. - */ -export type DlqMessageDetail = { - /** - * Event - */ - event: ({ - event_type: 'execution_requested'; - } & ExecutionRequestedEvent) | ({ - event_type: 'execution_accepted'; - } & ExecutionAcceptedEvent) | ({ - event_type: 'execution_queued'; - } & ExecutionQueuedEvent) | ({ - event_type: 'execution_started'; - } & ExecutionStartedEvent) | ({ - event_type: 'execution_running'; - } & ExecutionRunningEvent) | ({ - event_type: 'execution_completed'; - } & ExecutionCompletedEvent) | ({ - event_type: 'execution_failed'; - } & ExecutionFailedEvent) | ({ - event_type: 'execution_timeout'; - } & ExecutionTimeoutEvent) | ({ - event_type: 'execution_cancelled'; - } & ExecutionCancelledEvent) | ({ - event_type: 'pod_created'; - } & PodCreatedEvent) | ({ - event_type: 'pod_scheduled'; - } & PodScheduledEvent) | ({ - event_type: 'pod_running'; - } & PodRunningEvent) | ({ - event_type: 'pod_succeeded'; - } & PodSucceededEvent) | ({ - event_type: 'pod_failed'; - } & PodFailedEvent) | ({ - event_type: 'pod_terminated'; - } & PodTerminatedEvent) | ({ - event_type: 'pod_deleted'; - } & PodDeletedEvent) | ({ - event_type: 'result_stored'; - } & ResultStoredEvent) | ({ - event_type: 'result_failed'; - } & ResultFailedEvent) | ({ - event_type: 'user_settings_updated'; - } & UserSettingsUpdatedEvent) | ({ - event_type: 'user_registered'; - } & UserRegisteredEvent) | ({ - event_type: 'user_login'; - } & UserLoginEvent) | ({ - event_type: 'user_logged_in'; - } & UserLoggedInEvent) | ({ - event_type: 'user_logged_out'; - } & UserLoggedOutEvent) | ({ - event_type: 'user_updated'; - } & UserUpdatedEvent) | ({ - event_type: 'user_deleted'; - } & UserDeletedEvent) | ({ - event_type: 'notification_created'; - } & NotificationCreatedEvent) | ({ - event_type: 'notification_sent'; - } & NotificationSentEvent) | ({ - event_type: 'notification_delivered'; - } & NotificationDeliveredEvent) | ({ - event_type: 'notification_failed'; - } & NotificationFailedEvent) | ({ - event_type: 'notification_read'; - } & NotificationReadEvent) | ({ - event_type: 'notification_all_read'; - } & NotificationAllReadEvent) | ({ - event_type: 'notification_clicked'; - } & NotificationClickedEvent) | ({ - event_type: 'notification_preferences_updated'; - } & NotificationPreferencesUpdatedEvent) | ({ - event_type: 'saga_started'; - } & SagaStartedEvent) | ({ - event_type: 'saga_completed'; - } & SagaCompletedEvent) | ({ - event_type: 'saga_failed'; - } & SagaFailedEvent) | ({ - event_type: 'saga_cancelled'; - } & SagaCancelledEvent) | ({ - event_type: 'saga_compensating'; - } & SagaCompensatingEvent) | ({ - event_type: 'saga_compensated'; - } & SagaCompensatedEvent) | ({ - event_type: 'create_pod_command'; - } & CreatePodCommandEvent) | ({ - event_type: 'delete_pod_command'; - } & DeletePodCommandEvent) | ({ - event_type: 'allocate_resources_command'; - } & AllocateResourcesCommandEvent) | ({ - event_type: 'release_resources_command'; - } & ReleaseResourcesCommandEvent) | ({ - event_type: 'script_saved'; - } & ScriptSavedEvent) | ({ - event_type: 'script_deleted'; - } & ScriptDeletedEvent) | ({ - event_type: 'script_shared'; - } & ScriptSharedEvent) | ({ - event_type: 'security_violation'; - } & SecurityViolationEvent) | ({ - event_type: 'rate_limit_exceeded'; - } & RateLimitExceededEvent) | ({ - event_type: 'auth_failed'; - } & AuthFailedEvent) | ({ - event_type: 'resource_limit_exceeded'; - } & ResourceLimitExceededEvent) | ({ - event_type: 'quota_exceeded'; - } & QuotaExceededEvent) | ({ - event_type: 'system_error'; - } & SystemErrorEvent) | ({ - event_type: 'service_unhealthy'; - } & ServiceUnhealthyEvent) | ({ - event_type: 'service_recovered'; - } & ServiceRecoveredEvent) | ({ - event_type: 'dlq_message_received'; - } & DlqMessageReceivedEvent) | ({ - event_type: 'dlq_message_retried'; - } & DlqMessageRetriedEvent) | ({ - event_type: 'dlq_message_discarded'; - } & DlqMessageDiscardedEvent); - /** - * Original Topic - */ - original_topic: string; - /** - * Error - */ - error: string; - /** - * Retry Count - */ - retry_count: number; - /** - * Failed At - */ - failed_at: string; - status: DlqMessageStatus; - /** - * Producer Id - */ - producer_id: string; - /** - * Created At - */ - created_at?: string | null; - /** - * Last Updated - */ - last_updated?: string | null; - /** - * Next Retry At - */ - next_retry_at?: string | null; - /** - * Retried At - */ - retried_at?: string | null; - /** - * Discarded At - */ - discarded_at?: string | null; - /** - * Discard Reason - */ - discard_reason?: string | null; - /** - * Dlq Offset - */ - dlq_offset?: number | null; - /** - * Dlq Partition - */ - dlq_partition?: number | null; - /** - * Last Error - */ - last_error?: string | null; -}; - /** * DLQMessageDiscardedEvent * @@ -626,258 +419,41 @@ export type DlqMessageDiscardedEvent = { /** * Event Version */ - event_version: string; - /** - * Timestamp - */ - timestamp: string; - /** - * Aggregate Id - */ - aggregate_id?: string | null; - metadata: EventMetadata; - /** - * Dlq Event Id - */ - dlq_event_id?: string; - /** - * Original Topic - */ - original_topic?: string; - original_event_type?: EventType; - /** - * Reason - */ - reason?: string; - /** - * Retry Count - */ - retry_count?: number; -}; - -/** - * DLQMessageReceivedEvent - * - * Emitted when a message is received and persisted in the DLQ. - */ -export type DlqMessageReceivedEvent = { - /** - * Event Id - */ - event_id: string; - /** - * Event Type - */ - event_type: 'dlq_message_received'; - /** - * Event Version - */ - event_version: string; - /** - * Timestamp - */ - timestamp: string; - /** - * Aggregate Id - */ - aggregate_id?: string | null; - metadata: EventMetadata; - /** - * Dlq Event Id - */ - dlq_event_id?: string; - /** - * Original Topic - */ - original_topic?: string; - original_event_type?: EventType; - /** - * Error - */ - error?: string; - /** - * Retry Count - */ - retry_count?: number; - /** - * Producer Id - */ - producer_id?: string; - /** - * Failed At - */ - failed_at?: string; -}; - -/** - * DLQMessageResponse - * - * Response model for a DLQ message. Mirrors DLQMessage for direct model_validate. - */ -export type DlqMessageResponse = { - /** - * Event - */ - event: ({ - event_type: 'execution_requested'; - } & ExecutionRequestedEvent) | ({ - event_type: 'execution_accepted'; - } & ExecutionAcceptedEvent) | ({ - event_type: 'execution_queued'; - } & ExecutionQueuedEvent) | ({ - event_type: 'execution_started'; - } & ExecutionStartedEvent) | ({ - event_type: 'execution_running'; - } & ExecutionRunningEvent) | ({ - event_type: 'execution_completed'; - } & ExecutionCompletedEvent) | ({ - event_type: 'execution_failed'; - } & ExecutionFailedEvent) | ({ - event_type: 'execution_timeout'; - } & ExecutionTimeoutEvent) | ({ - event_type: 'execution_cancelled'; - } & ExecutionCancelledEvent) | ({ - event_type: 'pod_created'; - } & PodCreatedEvent) | ({ - event_type: 'pod_scheduled'; - } & PodScheduledEvent) | ({ - event_type: 'pod_running'; - } & PodRunningEvent) | ({ - event_type: 'pod_succeeded'; - } & PodSucceededEvent) | ({ - event_type: 'pod_failed'; - } & PodFailedEvent) | ({ - event_type: 'pod_terminated'; - } & PodTerminatedEvent) | ({ - event_type: 'pod_deleted'; - } & PodDeletedEvent) | ({ - event_type: 'result_stored'; - } & ResultStoredEvent) | ({ - event_type: 'result_failed'; - } & ResultFailedEvent) | ({ - event_type: 'user_settings_updated'; - } & UserSettingsUpdatedEvent) | ({ - event_type: 'user_registered'; - } & UserRegisteredEvent) | ({ - event_type: 'user_login'; - } & UserLoginEvent) | ({ - event_type: 'user_logged_in'; - } & UserLoggedInEvent) | ({ - event_type: 'user_logged_out'; - } & UserLoggedOutEvent) | ({ - event_type: 'user_updated'; - } & UserUpdatedEvent) | ({ - event_type: 'user_deleted'; - } & UserDeletedEvent) | ({ - event_type: 'notification_created'; - } & NotificationCreatedEvent) | ({ - event_type: 'notification_sent'; - } & NotificationSentEvent) | ({ - event_type: 'notification_delivered'; - } & NotificationDeliveredEvent) | ({ - event_type: 'notification_failed'; - } & NotificationFailedEvent) | ({ - event_type: 'notification_read'; - } & NotificationReadEvent) | ({ - event_type: 'notification_all_read'; - } & NotificationAllReadEvent) | ({ - event_type: 'notification_clicked'; - } & NotificationClickedEvent) | ({ - event_type: 'notification_preferences_updated'; - } & NotificationPreferencesUpdatedEvent) | ({ - event_type: 'saga_started'; - } & SagaStartedEvent) | ({ - event_type: 'saga_completed'; - } & SagaCompletedEvent) | ({ - event_type: 'saga_failed'; - } & SagaFailedEvent) | ({ - event_type: 'saga_cancelled'; - } & SagaCancelledEvent) | ({ - event_type: 'saga_compensating'; - } & SagaCompensatingEvent) | ({ - event_type: 'saga_compensated'; - } & SagaCompensatedEvent) | ({ - event_type: 'create_pod_command'; - } & CreatePodCommandEvent) | ({ - event_type: 'delete_pod_command'; - } & DeletePodCommandEvent) | ({ - event_type: 'allocate_resources_command'; - } & AllocateResourcesCommandEvent) | ({ - event_type: 'release_resources_command'; - } & ReleaseResourcesCommandEvent) | ({ - event_type: 'script_saved'; - } & ScriptSavedEvent) | ({ - event_type: 'script_deleted'; - } & ScriptDeletedEvent) | ({ - event_type: 'script_shared'; - } & ScriptSharedEvent) | ({ - event_type: 'security_violation'; - } & SecurityViolationEvent) | ({ - event_type: 'rate_limit_exceeded'; - } & RateLimitExceededEvent) | ({ - event_type: 'auth_failed'; - } & AuthFailedEvent) | ({ - event_type: 'resource_limit_exceeded'; - } & ResourceLimitExceededEvent) | ({ - event_type: 'quota_exceeded'; - } & QuotaExceededEvent) | ({ - event_type: 'system_error'; - } & SystemErrorEvent) | ({ - event_type: 'service_unhealthy'; - } & ServiceUnhealthyEvent) | ({ - event_type: 'service_recovered'; - } & ServiceRecoveredEvent) | ({ - event_type: 'dlq_message_received'; - } & DlqMessageReceivedEvent) | ({ - event_type: 'dlq_message_retried'; - } & DlqMessageRetriedEvent) | ({ - event_type: 'dlq_message_discarded'; - } & DlqMessageDiscardedEvent); - /** - * Original Topic - */ - original_topic: string; - /** - * Error - */ - error: string; - /** - * Retry Count - */ - retry_count: number; + event_version: string; /** - * Failed At + * Timestamp */ - failed_at: string; - status: DlqMessageStatus; + timestamp: string; /** - * Producer Id + * Aggregate Id */ - producer_id: string; + aggregate_id?: string | null; + metadata: EventMetadata; /** - * Dlq Offset + * Dlq Event Id */ - dlq_offset?: number | null; + dlq_event_id?: string; /** - * Dlq Partition + * Original Topic */ - dlq_partition?: number | null; + original_topic?: string; + original_event_type?: EventType; /** - * Last Error + * Reason */ - last_error?: string | null; + reason?: string; /** - * Next Retry At + * Retry Count */ - next_retry_at?: string | null; + retry_count?: number; }; /** - * DLQMessageRetriedEvent + * DLQMessageReceivedEvent * - * Emitted when a DLQ message is retried. + * Emitted when a message is received and persisted in the DLQ. */ -export type DlqMessageRetriedEvent = { +export type DlqMessageReceivedEvent = { /** * Event Id */ @@ -885,7 +461,7 @@ export type DlqMessageRetriedEvent = { /** * Event Type */ - event_type: 'dlq_message_retried'; + event_type: 'dlq_message_received'; /** * Event Version */ @@ -909,100 +485,67 @@ export type DlqMessageRetriedEvent = { original_topic?: string; original_event_type?: EventType; /** - * Retry Count - */ - retry_count?: number; - /** - * Retry Topic - */ - retry_topic?: string; -}; - -/** - * DLQMessageStatus - * - * Status of a message in the Dead Letter Queue. - */ -export type DlqMessageStatus = 'pending' | 'scheduled' | 'retried' | 'discarded'; - -/** - * DLQMessagesResponse - * - * Response model for listing DLQ messages. - */ -export type DlqMessagesResponse = { - /** - * Messages + * Error */ - messages: Array; + error?: string; /** - * Total + * Retry Count */ - total: number; + retry_count?: number; /** - * Offset + * Producer Id */ - offset: number; + producer_id?: string; /** - * Limit + * Failed At */ - limit: number; + failed_at?: string; }; /** - * DLQRetryResult + * DLQMessageRetriedEvent + * + * Emitted when a DLQ message is retried. */ -export type DlqRetryResult = { +export type DlqMessageRetriedEvent = { /** * Event Id */ event_id: string; /** - * Status - */ - status: string; - /** - * Error + * Event Type */ - error?: string | null; -}; - -/** - * DLQTopicSummaryResponse - * - * Response model for topic summary. - */ -export type DlqTopicSummaryResponse = { + event_type: 'dlq_message_retried'; /** - * Topic + * Event Version */ - topic: string; + event_version: string; /** - * Total Messages + * Timestamp */ - total_messages: number; + timestamp: string; /** - * Status Breakdown + * Aggregate Id */ - status_breakdown: { - [key: string]: number; - }; + aggregate_id?: string | null; + metadata: EventMetadata; /** - * Oldest Message + * Dlq Event Id */ - oldest_message: string; + dlq_event_id?: string; /** - * Newest Message + * Original Topic */ - newest_message: string; + original_topic?: string; + original_event_type?: EventType; /** - * Avg Retry Count + * Retry Count */ - avg_retry_count: number; + retry_count?: number; /** - * Max Retry Count + * Retry Topic */ - max_retry_count: number; + retry_topic?: string; }; /** @@ -2462,18 +2005,6 @@ export type LoginResponse = { csrf_token: string; }; -/** - * ManualRetryRequest - * - * Request model for manual retry of messages. - */ -export type ManualRetryRequest = { - /** - * Event Ids - */ - event_ids: Array; -}; - /** * MessageResponse * @@ -4079,42 +3610,6 @@ export type ResultStoredEvent = { size_bytes?: number; }; -/** - * RetryPolicyRequest - * - * Request model for setting a retry policy. - */ -export type RetryPolicyRequest = { - /** - * Topic - */ - topic: string; - strategy: RetryStrategy; - /** - * Max Retries - */ - max_retries?: number; - /** - * Base Delay Seconds - */ - base_delay_seconds?: number; - /** - * Max Delay Seconds - */ - max_delay_seconds?: number; - /** - * Retry Multiplier - */ - retry_multiplier?: number; -}; - -/** - * RetryStrategy - * - * Retry strategies for DLQ messages. - */ -export type RetryStrategy = 'immediate' | 'exponential_backoff' | 'fixed_interval' | 'scheduled' | 'manual'; - /** * SSEControlEvent * @@ -6854,201 +6349,6 @@ export type LivenessApiV1HealthLiveGetResponses = { export type LivenessApiV1HealthLiveGetResponse = LivenessApiV1HealthLiveGetResponses[keyof LivenessApiV1HealthLiveGetResponses]; -export type GetDlqMessagesApiV1DlqMessagesGetData = { - body?: never; - path?: never; - query?: { - /** - * Status - * - * Filter by message status - */ - status?: DlqMessageStatus | null; - /** - * Topic - * - * Filter by source Kafka topic - */ - topic?: string | null; - /** - * Event Type - * - * Filter by event type - */ - event_type?: EventType | null; - /** - * Limit - */ - limit?: number; - /** - * Offset - */ - offset?: number; - }; - url: '/api/v1/dlq/messages'; -}; - -export type GetDlqMessagesApiV1DlqMessagesGetErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type GetDlqMessagesApiV1DlqMessagesGetError = GetDlqMessagesApiV1DlqMessagesGetErrors[keyof GetDlqMessagesApiV1DlqMessagesGetErrors]; - -export type GetDlqMessagesApiV1DlqMessagesGetResponses = { - /** - * Successful Response - */ - 200: DlqMessagesResponse; -}; - -export type GetDlqMessagesApiV1DlqMessagesGetResponse = GetDlqMessagesApiV1DlqMessagesGetResponses[keyof GetDlqMessagesApiV1DlqMessagesGetResponses]; - -export type DiscardDlqMessageApiV1DlqMessagesEventIdDeleteData = { - body?: never; - path: { - /** - * Event Id - */ - event_id: string; - }; - query: { - /** - * Reason - * - * Reason for discarding - */ - reason: string; - }; - url: '/api/v1/dlq/messages/{event_id}'; -}; - -export type DiscardDlqMessageApiV1DlqMessagesEventIdDeleteErrors = { - /** - * Message not found or already in terminal state - */ - 404: ErrorResponse; - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type DiscardDlqMessageApiV1DlqMessagesEventIdDeleteError = DiscardDlqMessageApiV1DlqMessagesEventIdDeleteErrors[keyof DiscardDlqMessageApiV1DlqMessagesEventIdDeleteErrors]; - -export type DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponses = { - /** - * Successful Response - */ - 200: MessageResponse; -}; - -export type DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponse = DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponses[keyof DiscardDlqMessageApiV1DlqMessagesEventIdDeleteResponses]; - -export type GetDlqMessageApiV1DlqMessagesEventIdGetData = { - body?: never; - path: { - /** - * Event Id - */ - event_id: string; - }; - query?: never; - url: '/api/v1/dlq/messages/{event_id}'; -}; - -export type GetDlqMessageApiV1DlqMessagesEventIdGetErrors = { - /** - * DLQ message not found - */ - 404: ErrorResponse; - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type GetDlqMessageApiV1DlqMessagesEventIdGetError = GetDlqMessageApiV1DlqMessagesEventIdGetErrors[keyof GetDlqMessageApiV1DlqMessagesEventIdGetErrors]; - -export type GetDlqMessageApiV1DlqMessagesEventIdGetResponses = { - /** - * Successful Response - */ - 200: DlqMessageDetail; -}; - -export type GetDlqMessageApiV1DlqMessagesEventIdGetResponse = GetDlqMessageApiV1DlqMessagesEventIdGetResponses[keyof GetDlqMessageApiV1DlqMessagesEventIdGetResponses]; - -export type RetryDlqMessagesApiV1DlqRetryPostData = { - body: ManualRetryRequest; - path?: never; - query?: never; - url: '/api/v1/dlq/retry'; -}; - -export type RetryDlqMessagesApiV1DlqRetryPostErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type RetryDlqMessagesApiV1DlqRetryPostError = RetryDlqMessagesApiV1DlqRetryPostErrors[keyof RetryDlqMessagesApiV1DlqRetryPostErrors]; - -export type RetryDlqMessagesApiV1DlqRetryPostResponses = { - /** - * Successful Response - */ - 200: DlqBatchRetryResponse; -}; - -export type RetryDlqMessagesApiV1DlqRetryPostResponse = RetryDlqMessagesApiV1DlqRetryPostResponses[keyof RetryDlqMessagesApiV1DlqRetryPostResponses]; - -export type SetRetryPolicyApiV1DlqRetryPolicyPostData = { - body: RetryPolicyRequest; - path?: never; - query?: never; - url: '/api/v1/dlq/retry-policy'; -}; - -export type SetRetryPolicyApiV1DlqRetryPolicyPostErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type SetRetryPolicyApiV1DlqRetryPolicyPostError = SetRetryPolicyApiV1DlqRetryPolicyPostErrors[keyof SetRetryPolicyApiV1DlqRetryPolicyPostErrors]; - -export type SetRetryPolicyApiV1DlqRetryPolicyPostResponses = { - /** - * Successful Response - */ - 200: MessageResponse; -}; - -export type SetRetryPolicyApiV1DlqRetryPolicyPostResponse = SetRetryPolicyApiV1DlqRetryPolicyPostResponses[keyof SetRetryPolicyApiV1DlqRetryPolicyPostResponses]; - -export type GetDlqTopicsApiV1DlqTopicsGetData = { - body?: never; - path?: never; - query?: never; - url: '/api/v1/dlq/topics'; -}; - -export type GetDlqTopicsApiV1DlqTopicsGetResponses = { - /** - * Response Get Dlq Topics Api V1 Dlq Topics Get - * - * Successful Response - */ - 200: Array; -}; - -export type GetDlqTopicsApiV1DlqTopicsGetResponse = GetDlqTopicsApiV1DlqTopicsGetResponses[keyof GetDlqTopicsApiV1DlqTopicsGetResponses]; - export type NotificationStreamApiV1EventsNotificationsStreamGetData = { body?: never; path?: never; From a9a3652fce07be59813cded0ad6fb7c2c9710839 Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Thu, 19 Feb 2026 00:34:31 +0100 Subject: [PATCH 4/9] refactored tests: the ones that dont need e2e setup are moved to unit --- backend/tests/e2e/app/test_main_app.py | 253 ------------------------ backend/tests/unit/app/__init__.py | 0 backend/tests/unit/app/test_main_app.py | 186 +++++++++++++++++ 3 files changed, 186 insertions(+), 253 deletions(-) create mode 100644 backend/tests/unit/app/__init__.py create mode 100644 backend/tests/unit/app/test_main_app.py diff --git a/backend/tests/e2e/app/test_main_app.py b/backend/tests/e2e/app/test_main_app.py index b1e7a914..a4e898e2 100644 --- a/backend/tests/e2e/app/test_main_app.py +++ b/backend/tests/e2e/app/test_main_app.py @@ -1,228 +1,13 @@ -from importlib import import_module -from typing import Any - import pytest import redis.asyncio as aioredis from app.db.docs import UserDocument -from app.domain.exceptions import DomainError from app.settings import Settings from dishka import AsyncContainer from fastapi import FastAPI -from starlette.routing import Mount, Route pytestmark = pytest.mark.e2e -class TestAppInstance: - """Tests for FastAPI app instance creation.""" - - def test_app_is_fastapi_instance(self, app: FastAPI) -> None: - """App is a FastAPI instance.""" - assert isinstance(app, FastAPI) - - def test_app_title_matches_settings( - self, app: FastAPI, test_settings: Settings - ) -> None: - """App title matches PROJECT_NAME from settings.""" - assert app.title == test_settings.PROJECT_NAME - - def test_openapi_disabled_for_security(self, app: FastAPI) -> None: - """OpenAPI/docs endpoints are disabled in production mode.""" - # OpenAPI is disabled in create_app for security - assert app.openapi_url is None - assert app.docs_url is None - assert app.redoc_url is None - - -class TestRouterConfiguration: - """Tests for API router registration.""" - - def test_api_routes_registered(self, app: FastAPI) -> None: - """API routes are registered under /api/ prefix.""" - paths = {r.path for r in app.router.routes if isinstance(r, Route)} - assert any(p.startswith("/api/") for p in paths) - - def test_health_routes_registered(self, app: FastAPI) -> None: - """Health check routes are registered.""" - paths = self._get_all_paths(app) - assert "/api/v1/health/live" in paths - - def test_auth_routes_registered(self, app: FastAPI) -> None: - """Authentication routes are registered.""" - paths = self._get_all_paths(app) - assert "/api/v1/auth/login" in paths - assert "/api/v1/auth/register" in paths - assert "/api/v1/auth/logout" in paths - assert "/api/v1/auth/me" in paths - - def test_execution_routes_registered(self, app: FastAPI) -> None: - """Execution routes are registered.""" - paths = self._get_all_paths(app) - assert "/api/v1/execute" in paths - assert "/api/v1/user/executions" in paths - assert "/api/v1/k8s-limits" in paths - assert "/api/v1/example-scripts" in paths - - def test_saved_scripts_routes_registered(self, app: FastAPI) -> None: - """Saved scripts routes are registered.""" - paths = self._get_all_paths(app) - assert "/api/v1/scripts" in paths - - def test_user_settings_routes_registered(self, app: FastAPI) -> None: - """User settings routes are registered.""" - paths = self._get_all_paths(app) - assert any(p.startswith("/api/v1/user/settings") for p in paths) - - def test_notifications_routes_registered(self, app: FastAPI) -> None: - """Notification routes are registered.""" - paths = self._get_all_paths(app) - assert "/api/v1/notifications" in paths - - def test_saga_routes_registered(self, app: FastAPI) -> None: - """Saga routes are registered.""" - paths = self._get_all_paths(app) - assert any(p.startswith("/api/v1/sagas") for p in paths) - - def test_replay_routes_registered(self, app: FastAPI) -> None: - """Replay routes are registered (admin only).""" - paths = self._get_all_paths(app) - assert "/api/v1/replay/sessions" in paths - - def test_dlq_routes_registered(self, app: FastAPI) -> None: - """DLQ routes are registered.""" - paths = self._get_all_paths(app) - assert "/api/v1/dlq/messages" in paths - - def test_events_routes_registered(self, app: FastAPI) -> None: - """Events routes are registered.""" - paths = self._get_all_paths(app) - # SSE endpoint - assert any("/api/v1/events" in p for p in paths) - - def test_admin_routes_registered(self, app: FastAPI) -> None: - """Admin routes are registered.""" - paths = self._get_all_paths(app) - assert any(p.startswith("/api/v1/admin/users") for p in paths) - assert any(p.startswith("/api/v1/admin/settings") for p in paths) - assert any(p.startswith("/api/v1/admin/events") for p in paths) - - def _get_all_paths(self, app: FastAPI) -> set[str]: - """Extract all route paths from app, including mounted routers.""" - paths: set[str] = set() - for route in app.router.routes: - if isinstance(route, Route): - paths.add(route.path) - elif isinstance(route, Mount) and route.routes is not None: - # For mounted routers, combine mount path with route paths - for sub_route in route.routes: - if isinstance(sub_route, Route): - paths.add(f"{route.path}{sub_route.path}") - return paths - - -class TestMiddlewareStack: - """Tests for middleware configuration.""" - - def test_cors_middleware_configured(self, app: FastAPI) -> None: - """CORS middleware is configured.""" - middleware_classes = self._get_middleware_class_names(app) - assert "CORSMiddleware" in middleware_classes - - def test_request_size_limit_middleware_configured(self, app: FastAPI) -> None: - """Request size limit middleware is configured.""" - middleware_classes = self._get_middleware_class_names(app) - assert "RequestSizeLimitMiddleware" in middleware_classes - - def test_cache_control_middleware_configured(self, app: FastAPI) -> None: - """Cache control middleware is configured.""" - middleware_classes = self._get_middleware_class_names(app) - assert "CacheControlMiddleware" in middleware_classes - - def test_metrics_middleware_configured(self, app: FastAPI) -> None: - """Metrics middleware is configured.""" - middleware_classes = self._get_middleware_class_names(app) - assert "MetricsMiddleware" in middleware_classes - - def test_rate_limit_middleware_configured(self, app: FastAPI) -> None: - """Rate limit middleware is configured.""" - middleware_classes = self._get_middleware_class_names(app) - assert "RateLimitMiddleware" in middleware_classes - - def test_csrf_middleware_configured(self, app: FastAPI) -> None: - """CSRF middleware is configured.""" - middleware_classes = self._get_middleware_class_names(app) - assert "CSRFMiddleware" in middleware_classes - - def test_middleware_count(self, app: FastAPI) -> None: - """Expected number of middlewares are configured.""" - # CORS, RequestSizeLimit, CacheControl, Metrics, RateLimit, CSRF - middleware_classes = self._get_middleware_class_names(app) - expected_middlewares = { - "CORSMiddleware", - "RequestSizeLimitMiddleware", - "CacheControlMiddleware", - "MetricsMiddleware", - "RateLimitMiddleware", - "CSRFMiddleware", - } - assert expected_middlewares.issubset(middleware_classes) - - def _get_middleware_class_names(self, app: FastAPI) -> set[str]: - """Get set of middleware class names from app.""" - return { - getattr(m.cls, "__name__", str(m.cls)) for m in app.user_middleware - } - - -class TestCorsConfiguration: - """Tests for CORS middleware configuration.""" - - def test_cors_allows_localhost_origins(self, app: FastAPI) -> None: - """CORS allows localhost origins for development.""" - cors_kwargs = self._get_cors_kwargs(app) - assert cors_kwargs is not None - - # Check allowed origins - allowed = cors_kwargs.get("allow_origins", []) - assert "https://localhost:5001" in allowed - assert "https://127.0.0.1:5001" in allowed - assert "https://localhost" in allowed - - def test_cors_allows_credentials(self, app: FastAPI) -> None: - """CORS allows credentials for cookie-based auth.""" - cors_kwargs = self._get_cors_kwargs(app) - assert cors_kwargs is not None - assert cors_kwargs.get("allow_credentials") is True - - def test_cors_allows_required_methods(self, app: FastAPI) -> None: - """CORS allows required HTTP methods.""" - cors_kwargs = self._get_cors_kwargs(app) - assert cors_kwargs is not None - - methods = cors_kwargs.get("allow_methods", []) - assert "GET" in methods - assert "POST" in methods - assert "PUT" in methods - assert "DELETE" in methods - - def test_cors_allows_required_headers(self, app: FastAPI) -> None: - """CORS allows required headers.""" - cors_kwargs = self._get_cors_kwargs(app) - assert cors_kwargs is not None - - headers = cors_kwargs.get("allow_headers", []) - assert "Authorization" in headers - assert "Content-Type" in headers - assert "X-CSRF-Token" in headers - - def _get_cors_kwargs(self, app: FastAPI) -> dict[str, Any] | None: - """Get CORS middleware kwargs from app.""" - for m in app.user_middleware: - if getattr(m.cls, "__name__", "") == "CORSMiddleware": - return dict(m.kwargs) - return None - - class TestDishkaContainer: """Tests for Dishka DI container configuration.""" @@ -251,23 +36,12 @@ async def test_container_resolves_logger(self, scope: AsyncContainer) -> None: assert hasattr(logger, "bind") -class TestExceptionHandlers: - """Tests for exception handler configuration.""" - - def test_domain_error_handler_registered(self, app: FastAPI) -> None: - """DomainError exception handler is registered.""" - # Exception handlers are stored in app.exception_handlers - assert DomainError in app.exception_handlers - - class TestLifespanInitialization: """Tests for app state after lifespan initialization.""" @pytest.mark.asyncio async def test_beanie_initialized(self, app: FastAPI) -> None: """Beanie ODM is initialized with document models.""" - # app fixture runs lifespan which initializes Beanie - # get_settings() raises CollectionWasNotInitialized if not initialized settings = UserDocument.get_settings() assert settings.name == "users" @@ -275,32 +49,5 @@ async def test_beanie_initialized(self, app: FastAPI) -> None: async def test_redis_connected(self, scope: AsyncContainer) -> None: """Redis client is connected and functional.""" redis_client = await scope.get(aioredis.Redis) - # Ping returns a coroutine for async client pong = await redis_client.ping() # type: ignore[misc] assert pong is True - - -class TestCreateAppFunction: - """Tests for create_app factory function.""" - - def test_create_app_returns_fastapi(self, test_settings: Settings) -> None: - """create_app returns a FastAPI instance.""" - create_app = import_module("app.main").create_app - instance = create_app(settings=test_settings) - assert isinstance(instance, FastAPI) - - def test_create_app_uses_provided_settings( - self, test_settings: Settings - ) -> None: - """create_app uses provided settings instead of loading from env.""" - create_app = import_module("app.main").create_app - instance = create_app(settings=test_settings) - assert instance.title == test_settings.PROJECT_NAME - - def test_create_app_without_settings_uses_defaults(self) -> None: - """create_app without settings argument creates default Settings.""" - create_app = import_module("app.main").create_app - # This will create a Settings() from env/defaults - # Just verify it doesn't crash - instance = create_app() - assert isinstance(instance, FastAPI) diff --git a/backend/tests/unit/app/__init__.py b/backend/tests/unit/app/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/tests/unit/app/test_main_app.py b/backend/tests/unit/app/test_main_app.py new file mode 100644 index 00000000..4a8861c2 --- /dev/null +++ b/backend/tests/unit/app/test_main_app.py @@ -0,0 +1,186 @@ +from importlib import import_module +from typing import Any + +import pytest +from app.domain.exceptions import DomainError +from app.main import create_app +from app.settings import Settings +from fastapi import FastAPI +from starlette.routing import Mount, Route + +pytestmark = pytest.mark.unit + + +def _get_all_paths(app: FastAPI) -> set[str]: + """Extract all route paths from app, including mounted routers.""" + paths: set[str] = set() + for route in app.router.routes: + if isinstance(route, Route): + paths.add(route.path) + elif isinstance(route, Mount) and route.routes is not None: + for sub_route in route.routes: + if isinstance(sub_route, Route): + paths.add(f"{route.path}{sub_route.path}") + return paths + + +@pytest.fixture(scope="module") +def app(test_settings: Settings) -> FastAPI: + """Lightweight app without lifespan — no MongoDB, Kafka, or Redis.""" + return create_app(settings=test_settings) + + +class TestAppInstance: + """Tests for FastAPI app instance creation.""" + + def test_app_is_fastapi_instance(self, app: FastAPI) -> None: + assert isinstance(app, FastAPI) + + def test_app_title_matches_settings(self, app: FastAPI, test_settings: Settings) -> None: + assert app.title == test_settings.PROJECT_NAME + + def test_openapi_disabled_for_security(self, app: FastAPI) -> None: + assert app.openapi_url is None + assert app.docs_url is None + assert app.redoc_url is None + + +class TestRouterConfiguration: + """Tests for API router registration.""" + + def test_api_routes_registered(self, app: FastAPI) -> None: + paths = {r.path for r in app.router.routes if isinstance(r, Route)} + assert any(p.startswith("/api/") for p in paths) + + def test_health_routes_registered(self, app: FastAPI) -> None: + assert "/api/v1/health/live" in _get_all_paths(app) + + def test_auth_routes_registered(self, app: FastAPI) -> None: + paths = _get_all_paths(app) + assert "/api/v1/auth/login" in paths + assert "/api/v1/auth/register" in paths + assert "/api/v1/auth/logout" in paths + assert "/api/v1/auth/me" in paths + + def test_execution_routes_registered(self, app: FastAPI) -> None: + paths = _get_all_paths(app) + assert "/api/v1/execute" in paths + assert "/api/v1/user/executions" in paths + assert "/api/v1/k8s-limits" in paths + assert "/api/v1/example-scripts" in paths + + def test_saved_scripts_routes_registered(self, app: FastAPI) -> None: + assert "/api/v1/scripts" in _get_all_paths(app) + + def test_user_settings_routes_registered(self, app: FastAPI) -> None: + assert any(p.startswith("/api/v1/user/settings") for p in _get_all_paths(app)) + + def test_notifications_routes_registered(self, app: FastAPI) -> None: + assert "/api/v1/notifications" in _get_all_paths(app) + + def test_saga_routes_registered(self, app: FastAPI) -> None: + assert any(p.startswith("/api/v1/sagas") for p in _get_all_paths(app)) + + def test_replay_routes_registered(self, app: FastAPI) -> None: + assert "/api/v1/replay/sessions" in _get_all_paths(app) + + def test_events_routes_registered(self, app: FastAPI) -> None: + assert any("/api/v1/events" in p for p in _get_all_paths(app)) + + def test_admin_routes_registered(self, app: FastAPI) -> None: + paths = _get_all_paths(app) + assert any(p.startswith("/api/v1/admin/users") for p in paths) + assert any(p.startswith("/api/v1/admin/settings") for p in paths) + assert any(p.startswith("/api/v1/admin/events") for p in paths) + + +class TestMiddlewareStack: + """Tests for middleware configuration.""" + + def _get_middleware_class_names(self, app: FastAPI) -> set[str]: + return {getattr(m.cls, "__name__", str(m.cls)) for m in app.user_middleware} + + def test_cors_middleware_configured(self, app: FastAPI) -> None: + assert "CORSMiddleware" in self._get_middleware_class_names(app) + + def test_request_size_limit_middleware_configured(self, app: FastAPI) -> None: + assert "RequestSizeLimitMiddleware" in self._get_middleware_class_names(app) + + def test_cache_control_middleware_configured(self, app: FastAPI) -> None: + assert "CacheControlMiddleware" in self._get_middleware_class_names(app) + + def test_metrics_middleware_configured(self, app: FastAPI) -> None: + assert "MetricsMiddleware" in self._get_middleware_class_names(app) + + def test_rate_limit_middleware_configured(self, app: FastAPI) -> None: + assert "RateLimitMiddleware" in self._get_middleware_class_names(app) + + def test_csrf_middleware_configured(self, app: FastAPI) -> None: + assert "CSRFMiddleware" in self._get_middleware_class_names(app) + + def test_middleware_count(self, app: FastAPI) -> None: + expected = { + "CORSMiddleware", "RequestSizeLimitMiddleware", "CacheControlMiddleware", + "MetricsMiddleware", "RateLimitMiddleware", "CSRFMiddleware", + } + assert expected.issubset(self._get_middleware_class_names(app)) + + +class TestCorsConfiguration: + """Tests for CORS middleware configuration.""" + + def _get_cors_kwargs(self, app: FastAPI) -> dict[str, Any] | None: + for m in app.user_middleware: + if getattr(m.cls, "__name__", "") == "CORSMiddleware": + return dict(m.kwargs) + return None + + def test_cors_allows_localhost_origins(self, app: FastAPI) -> None: + cors_kwargs = self._get_cors_kwargs(app) + assert cors_kwargs is not None + allowed = cors_kwargs.get("allow_origins", []) + assert "https://localhost:5001" in allowed + assert "https://127.0.0.1:5001" in allowed + assert "https://localhost" in allowed + + def test_cors_allows_credentials(self, app: FastAPI) -> None: + cors_kwargs = self._get_cors_kwargs(app) + assert cors_kwargs is not None + assert cors_kwargs.get("allow_credentials") is True + + def test_cors_allows_required_methods(self, app: FastAPI) -> None: + cors_kwargs = self._get_cors_kwargs(app) + assert cors_kwargs is not None + methods = cors_kwargs.get("allow_methods", []) + for m in ("GET", "POST", "PUT", "DELETE"): + assert m in methods + + def test_cors_allows_required_headers(self, app: FastAPI) -> None: + cors_kwargs = self._get_cors_kwargs(app) + assert cors_kwargs is not None + headers = cors_kwargs.get("allow_headers", []) + for h in ("Authorization", "Content-Type", "X-CSRF-Token"): + assert h in headers + + +class TestExceptionHandlers: + """Tests for exception handler configuration.""" + + def test_domain_error_handler_registered(self, app: FastAPI) -> None: + assert DomainError in app.exception_handlers + + +class TestCreateAppFunction: + """Tests for create_app factory function.""" + + def test_create_app_returns_fastapi(self, test_settings: Settings) -> None: + create_app_fn = import_module("app.main").create_app + assert isinstance(create_app_fn(settings=test_settings), FastAPI) + + def test_create_app_uses_provided_settings(self, test_settings: Settings) -> None: + create_app_fn = import_module("app.main").create_app + assert create_app_fn(settings=test_settings).title == test_settings.PROJECT_NAME + + def test_create_app_without_settings_uses_defaults(self) -> None: + create_app_fn = import_module("app.main").create_app + assert isinstance(create_app_fn(), FastAPI) From a0aa487c6e54e1e0b46be7cb4867f252cf0ea9ea Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Thu, 19 Feb 2026 01:06:58 +0100 Subject: [PATCH 5/9] handlers: replace in-loop creation of subscribers with a single subscriber handling all 16 ropics --- backend/app/events/handlers.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/backend/app/events/handlers.py b/backend/app/events/handlers.py index c29da363..dd73b097 100644 --- a/backend/app/events/handlers.py +++ b/backend/app/events/handlers.py @@ -283,22 +283,20 @@ async def on_execution_timeout( def register_sse_subscriber(broker: KafkaBroker, settings: Settings) -> None: prefix = settings.KAFKA_TOPIC_PREFIX + topics = [f"{prefix}{et}" for et in _SSE_EVENT_TYPES] - for et in _SSE_EVENT_TYPES: - topic = f"{prefix}{et}" - - @broker.subscriber( - topic, - group_id="sse-bridge-pool", - ack_policy=AckPolicy.ACK_FIRST, - auto_offset_reset="latest", - max_workers=settings.SSE_CONSUMER_POOL_SIZE, - ) - async def on_sse_event( - body: DomainEvent, - sse_bus: FromDishka[SSERedisBus], - ) -> None: - await sse_bus.route_domain_event(body) + @broker.subscriber( + *topics, + group_id="sse-bridge-pool", + ack_policy=AckPolicy.ACK_FIRST, + auto_offset_reset="latest", + max_workers=settings.SSE_CONSUMER_POOL_SIZE, + ) + async def on_sse_event( + body: DomainEvent, + sse_bus: FromDishka[SSERedisBus], + ) -> None: + await sse_bus.route_domain_event(body) def register_notification_subscriber(broker: KafkaBroker, settings: Settings) -> None: From 50c48d9e995301d744eea218747d518ee82cfc8c Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Thu, 19 Feb 2026 07:54:57 +0100 Subject: [PATCH 6/9] removed prefix from topics' names --- backend/app/core/dishka_lifespan.py | 2 +- backend/app/core/providers.py | 3 +- backend/app/dlq/manager.py | 2 +- backend/app/events/core/producer.py | 5 +- backend/app/events/handlers.py | 61 ++++++++----------- backend/app/settings.py | 1 - backend/tests/e2e/conftest.py | 3 +- backend/tests/e2e/dlq/test_dlq_manager.py | 5 +- backend/workers/run_coordinator.py | 2 +- backend/workers/run_dlq_processor.py | 2 +- backend/workers/run_k8s_worker.py | 2 +- backend/workers/run_result_processor.py | 2 +- backend/workers/run_saga_orchestrator.py | 2 +- docs/architecture/kafka-topic-architecture.md | 7 +-- 14 files changed, 39 insertions(+), 60 deletions(-) diff --git a/backend/app/core/dishka_lifespan.py b/backend/app/core/dishka_lifespan.py index 3eef6169..389050e2 100644 --- a/backend/app/core/dishka_lifespan.py +++ b/backend/app/core/dishka_lifespan.py @@ -65,7 +65,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: # Register subscribers BEFORE broker.start() - FastStream requirement register_sse_subscriber(broker, settings) - register_notification_subscriber(broker, settings) + register_notification_subscriber(broker) logger.info("Kafka subscribers registered") # Set up FastStream DI integration (must be before start per Dishka docs) diff --git a/backend/app/core/providers.py b/backend/app/core/providers.py index aeb225eb..82260bed 100644 --- a/backend/app/core/providers.py +++ b/backend/app/core/providers.py @@ -171,10 +171,9 @@ def get_unified_producer( broker: KafkaBroker, event_repository: EventRepository, logger: structlog.stdlib.BoundLogger, - settings: Settings, event_metrics: EventMetrics, ) -> UnifiedProducer: - return UnifiedProducer(broker, event_repository, logger, settings, event_metrics) + return UnifiedProducer(broker, event_repository, logger, event_metrics) @provide def get_idempotency_repository(self, redis_client: redis.Redis) -> RedisIdempotencyRepository: diff --git a/backend/app/dlq/manager.py b/backend/app/dlq/manager.py index 299b07c8..17718641 100644 --- a/backend/app/dlq/manager.py +++ b/backend/app/dlq/manager.py @@ -57,7 +57,7 @@ def __init__( ] if f is not None ] - self._dlq_events_topic = f"{settings.KAFKA_TOPIC_PREFIX}{EventType.DLQ_MESSAGE_RECEIVED}" + self._dlq_events_topic: str = EventType.DLQ_MESSAGE_RECEIVED def _filter_test_events(self, message: DLQMessage) -> bool: return not message.event.event_id.startswith("test-") diff --git a/backend/app/events/core/producer.py b/backend/app/events/core/producer.py index dfb4b43a..d4d82919 100644 --- a/backend/app/events/core/producer.py +++ b/backend/app/events/core/producer.py @@ -4,7 +4,6 @@ from app.core.metrics import EventMetrics from app.db.repositories import EventRepository from app.domain.events import DomainEvent -from app.settings import Settings class UnifiedProducer: @@ -19,19 +18,17 @@ def __init__( broker: KafkaBroker, event_repository: EventRepository, logger: structlog.stdlib.BoundLogger, - settings: Settings, event_metrics: EventMetrics, ): self._broker = broker self._event_repository = event_repository self.logger = logger self._event_metrics = event_metrics - self._topic_prefix = settings.KAFKA_TOPIC_PREFIX async def produce(self, event_to_produce: DomainEvent, key: str) -> None: """Persist event to MongoDB, then publish to Kafka.""" await self._event_repository.store_event(event_to_produce) - topic = f"{self._topic_prefix}{event_to_produce.event_type}" + topic = event_to_produce.event_type try: await self._broker.publish( message=event_to_produce, diff --git a/backend/app/events/handlers.py b/backend/app/events/handlers.py index dd73b097..b9b06267 100644 --- a/backend/app/events/handlers.py +++ b/backend/app/events/handlers.py @@ -58,11 +58,9 @@ async def with_idempotency( # --8<-- [end:with_idempotency] -def register_coordinator_subscriber(broker: KafkaBroker, settings: Settings) -> None: - prefix = settings.KAFKA_TOPIC_PREFIX - +def register_coordinator_subscriber(broker: KafkaBroker) -> None: @broker.subscriber( - f"{prefix}{EventType.EXECUTION_REQUESTED}", + EventType.EXECUTION_REQUESTED, group_id="execution-coordinator", ack_policy=AckPolicy.ACK, ) @@ -77,7 +75,7 @@ async def on_execution_requested( ) @broker.subscriber( - f"{prefix}{EventType.EXECUTION_COMPLETED}", + EventType.EXECUTION_COMPLETED, group_id="execution-coordinator", ack_policy=AckPolicy.ACK, ) @@ -92,7 +90,7 @@ async def on_execution_completed( ) @broker.subscriber( - f"{prefix}{EventType.EXECUTION_FAILED}", + EventType.EXECUTION_FAILED, group_id="execution-coordinator", ack_policy=AckPolicy.ACK, ) @@ -107,7 +105,7 @@ async def on_execution_failed( ) @broker.subscriber( - f"{prefix}{EventType.EXECUTION_CANCELLED}", + EventType.EXECUTION_CANCELLED, group_id="execution-coordinator", ack_policy=AckPolicy.ACK, ) @@ -122,11 +120,9 @@ async def on_execution_cancelled( ) -def register_k8s_worker_subscriber(broker: KafkaBroker, settings: Settings) -> None: - prefix = settings.KAFKA_TOPIC_PREFIX - +def register_k8s_worker_subscriber(broker: KafkaBroker) -> None: @broker.subscriber( - f"{prefix}{EventType.CREATE_POD_COMMAND}", + EventType.CREATE_POD_COMMAND, group_id="k8s-worker", ack_policy=AckPolicy.ACK, ) @@ -141,7 +137,7 @@ async def on_create_pod( ) @broker.subscriber( - f"{prefix}{EventType.DELETE_POD_COMMAND}", + EventType.DELETE_POD_COMMAND, group_id="k8s-worker", ack_policy=AckPolicy.ACK, ) @@ -156,11 +152,9 @@ async def on_delete_pod( ) -def register_result_processor_subscriber(broker: KafkaBroker, settings: Settings) -> None: - prefix = settings.KAFKA_TOPIC_PREFIX - +def register_result_processor_subscriber(broker: KafkaBroker) -> None: @broker.subscriber( - f"{prefix}{EventType.EXECUTION_COMPLETED}", + EventType.EXECUTION_COMPLETED, group_id="result-processor", ack_policy=AckPolicy.ACK, max_poll_records=1, @@ -177,7 +171,7 @@ async def on_execution_completed( ) @broker.subscriber( - f"{prefix}{EventType.EXECUTION_FAILED}", + EventType.EXECUTION_FAILED, group_id="result-processor", ack_policy=AckPolicy.ACK, max_poll_records=1, @@ -194,7 +188,7 @@ async def on_execution_failed( ) @broker.subscriber( - f"{prefix}{EventType.EXECUTION_TIMEOUT}", + EventType.EXECUTION_TIMEOUT, group_id="result-processor", ack_policy=AckPolicy.ACK, max_poll_records=1, @@ -211,13 +205,11 @@ async def on_execution_timeout( ) -def register_saga_subscriber(broker: KafkaBroker, settings: Settings) -> None: - prefix = settings.KAFKA_TOPIC_PREFIX - +def register_saga_subscriber(broker: KafkaBroker) -> None: # No with_idempotency — the saga state machine provides its own # deduplication via status checks before each transition. @broker.subscriber( - f"{prefix}{EventType.EXECUTION_REQUESTED}", + EventType.EXECUTION_REQUESTED, group_id="saga-orchestrator", ack_policy=AckPolicy.ACK, ) @@ -228,7 +220,7 @@ async def on_execution_requested( await orchestrator.handle_execution_requested(body) @broker.subscriber( - f"{prefix}{EventType.EXECUTION_COMPLETED}", + EventType.EXECUTION_COMPLETED, group_id="saga-orchestrator", ack_policy=AckPolicy.ACK, ) @@ -239,7 +231,7 @@ async def on_execution_completed( await orchestrator.handle_execution_completed(body) @broker.subscriber( - f"{prefix}{EventType.EXECUTION_FAILED}", + EventType.EXECUTION_FAILED, group_id="saga-orchestrator", ack_policy=AckPolicy.ACK, ) @@ -250,7 +242,7 @@ async def on_execution_failed( await orchestrator.handle_execution_failed(body) @broker.subscriber( - f"{prefix}{EventType.EXECUTION_TIMEOUT}", + EventType.EXECUTION_TIMEOUT, group_id="saga-orchestrator", ack_policy=AckPolicy.ACK, ) @@ -282,11 +274,8 @@ async def on_execution_timeout( def register_sse_subscriber(broker: KafkaBroker, settings: Settings) -> None: - prefix = settings.KAFKA_TOPIC_PREFIX - topics = [f"{prefix}{et}" for et in _SSE_EVENT_TYPES] - @broker.subscriber( - *topics, + *_SSE_EVENT_TYPES, group_id="sse-bridge-pool", ack_policy=AckPolicy.ACK_FIRST, auto_offset_reset="latest", @@ -299,11 +288,9 @@ async def on_sse_event( await sse_bus.route_domain_event(body) -def register_notification_subscriber(broker: KafkaBroker, settings: Settings) -> None: - prefix = settings.KAFKA_TOPIC_PREFIX - +def register_notification_subscriber(broker: KafkaBroker) -> None: @broker.subscriber( - f"{prefix}{EventType.EXECUTION_COMPLETED}", + EventType.EXECUTION_COMPLETED, group_id="notification-service", ack_policy=AckPolicy.ACK, max_poll_records=10, @@ -316,7 +303,7 @@ async def on_execution_completed( await service.handle_execution_completed(body) @broker.subscriber( - f"{prefix}{EventType.EXECUTION_FAILED}", + EventType.EXECUTION_FAILED, group_id="notification-service", ack_policy=AckPolicy.ACK, max_poll_records=10, @@ -329,7 +316,7 @@ async def on_execution_failed( await service.handle_execution_failed(body) @broker.subscriber( - f"{prefix}{EventType.EXECUTION_TIMEOUT}", + EventType.EXECUTION_TIMEOUT, group_id="notification-service", ack_policy=AckPolicy.ACK, max_poll_records=10, @@ -342,7 +329,7 @@ async def on_execution_timeout( await service.handle_execution_timeout(body) -def register_dlq_subscriber(broker: KafkaBroker, settings: Settings) -> None: +def register_dlq_subscriber(broker: KafkaBroker) -> None: """Register a DLQ subscriber that consumes dead-letter messages. DLQ messages are JSON-encoded DLQMessage models (Pydantic serialization via FastStream). @@ -350,7 +337,7 @@ def register_dlq_subscriber(broker: KafkaBroker, settings: Settings) -> None: """ @broker.subscriber( - f"{settings.KAFKA_TOPIC_PREFIX}dead_letter_queue", + "dead_letter_queue", group_id="dlq-manager", ack_policy=AckPolicy.ACK, auto_offset_reset="earliest", diff --git a/backend/app/settings.py b/backend/app/settings.py index 51c01116..94793289 100644 --- a/backend/app/settings.py +++ b/backend/app/settings.py @@ -92,7 +92,6 @@ def __init__( KAFKA_BOOTSTRAP_SERVERS: str = "kafka:29092" ENABLE_EVENT_STREAMING: bool = False EVENT_RETENTION_DAYS: int = 30 - KAFKA_TOPIC_PREFIX: str = "pref" KAFKA_CONSUMER_GROUP_ID: str = "integr8scode-backend" KAFKA_AUTO_OFFSET_RESET: str = "earliest" KAFKA_ENABLE_AUTO_COMMIT: bool = True diff --git a/backend/tests/e2e/conftest.py b/backend/tests/e2e/conftest.py index 9098aa68..a7e340f6 100644 --- a/backend/tests/e2e/conftest.py +++ b/backend/tests/e2e/conftest.py @@ -137,8 +137,7 @@ async def wait_for_notification_created(self, execution_id: str, timeout: float @pytest_asyncio.fixture(scope="session") async def event_waiter(test_settings: Settings) -> AsyncGenerator[EventWaiter, None]: """Session-scoped Kafka event waiter. Starts before any test produces events.""" - prefix = test_settings.KAFKA_TOPIC_PREFIX - topics = [f"{prefix}{et}" for et in EventType] + topics: list[str] = list(EventType) waiter = EventWaiter(test_settings.KAFKA_BOOTSTRAP_SERVERS, topics) await waiter.start() _logger.info("EventWaiter started on %d topics", len(topics)) diff --git a/backend/tests/e2e/dlq/test_dlq_manager.py b/backend/tests/e2e/dlq/test_dlq_manager.py index 0c28cfbf..fa9f4a15 100644 --- a/backend/tests/e2e/dlq/test_dlq_manager.py +++ b/backend/tests/e2e/dlq/test_dlq_manager.py @@ -31,14 +31,13 @@ async def test_dlq_manager_persists_and_emits_event(scope: AsyncContainer, test_ """Test that DLQ manager persists messages and emits DLQMessageReceivedEvent.""" dlq_metrics: DLQMetrics = await scope.get(DLQMetrics) - prefix = test_settings.KAFKA_TOPIC_PREFIX ev = make_execution_requested_event(execution_id=f"exec-dlq-persist-{uuid.uuid4().hex[:8]}") # Future resolves when DLQMessageReceivedEvent is consumed received_future: asyncio.Future[DLQMessageReceivedEvent] = asyncio.get_running_loop().create_future() # Create consumer for DLQ events topic - dlq_events_topic = f"{prefix}{EventType.DLQ_MESSAGE_RECEIVED}" + dlq_events_topic = EventType.DLQ_MESSAGE_RECEIVED events_consumer = AIOKafkaConsumer( dlq_events_topic, bootstrap_servers=test_settings.KAFKA_BOOTSTRAP_SERVERS, @@ -83,7 +82,7 @@ async def consume_dlq_events() -> None: # Build a DLQMessage directly and call handle_message (no internal consumer loop) dlq_msg = DLQMessage( event=ev, - original_topic=f"{prefix}{EventType.EXECUTION_REQUESTED}", + original_topic=EventType.EXECUTION_REQUESTED, error="handler failed", retry_count=0, failed_at=datetime.now(timezone.utc), diff --git a/backend/workers/run_coordinator.py b/backend/workers/run_coordinator.py index 32bd60db..476e73e4 100644 --- a/backend/workers/run_coordinator.py +++ b/backend/workers/run_coordinator.py @@ -37,7 +37,7 @@ async def run() -> None: broker: KafkaBroker = await container.get(KafkaBroker) # Register subscriber and set up DI integration - register_coordinator_subscriber(broker, settings) + register_coordinator_subscriber(broker) setup_dishka(container, broker=broker, auto_inject=True) app = FastStream(broker, on_shutdown=[container.close]) diff --git a/backend/workers/run_dlq_processor.py b/backend/workers/run_dlq_processor.py index 333f3d1b..a6812d50 100644 --- a/backend/workers/run_dlq_processor.py +++ b/backend/workers/run_dlq_processor.py @@ -39,7 +39,7 @@ async def run() -> None: broker: KafkaBroker = await container.get(KafkaBroker) # Register DLQ subscriber and set up DI integration - register_dlq_subscriber(broker, settings) + register_dlq_subscriber(broker) setup_dishka(container, broker=broker, auto_inject=True) scheduler = AsyncIOScheduler() diff --git a/backend/workers/run_k8s_worker.py b/backend/workers/run_k8s_worker.py index 4e5df1c9..1677c650 100644 --- a/backend/workers/run_k8s_worker.py +++ b/backend/workers/run_k8s_worker.py @@ -38,7 +38,7 @@ async def run() -> None: broker: KafkaBroker = await container.get(KafkaBroker) # Register subscriber and set up DI integration - register_k8s_worker_subscriber(broker, settings) + register_k8s_worker_subscriber(broker) setup_dishka(container, broker=broker, auto_inject=True) async def init_k8s_worker() -> None: diff --git a/backend/workers/run_result_processor.py b/backend/workers/run_result_processor.py index 0d508f99..d298d358 100644 --- a/backend/workers/run_result_processor.py +++ b/backend/workers/run_result_processor.py @@ -37,7 +37,7 @@ async def run() -> None: broker: KafkaBroker = await container.get(KafkaBroker) # Register subscriber and set up DI integration - register_result_processor_subscriber(broker, settings) + register_result_processor_subscriber(broker) setup_dishka(container, broker=broker, auto_inject=True) app = FastStream(broker, on_shutdown=[container.close]) diff --git a/backend/workers/run_saga_orchestrator.py b/backend/workers/run_saga_orchestrator.py index f8f61821..23756d7e 100644 --- a/backend/workers/run_saga_orchestrator.py +++ b/backend/workers/run_saga_orchestrator.py @@ -39,7 +39,7 @@ async def run() -> None: broker: KafkaBroker = await container.get(KafkaBroker) # Register subscriber and set up DI integration - register_saga_subscriber(broker, settings) + register_saga_subscriber(broker) setup_dishka(container, broker=broker, auto_inject=True) scheduler = AsyncIOScheduler() diff --git a/docs/architecture/kafka-topic-architecture.md b/docs/architecture/kafka-topic-architecture.md index 0130069e..ebcc97bd 100644 --- a/docs/architecture/kafka-topic-architecture.md +++ b/docs/architecture/kafka-topic-architecture.md @@ -2,12 +2,11 @@ ## 1-topic-per-event-type -The system uses a **1:1 mapping** between `EventType` enum values and Kafka topics. Each event type gets its own dedicated topic. The topic name IS the `EventType` string value (with an optional prefix for environment isolation). +The system uses a **1:1 mapping** between `EventType` enum values and Kafka topics. Each event type gets its own dedicated topic. The topic name IS the `EventType` string value — no prefix, no transformation. ``` -Topic name = f"{KAFKA_TOPIC_PREFIX}{EventType.EXECUTION_REQUESTED}" - = f"dev_{EventType.EXECUTION_REQUESTED}" - = "dev_execution_requested" +Topic name = EventType.EXECUTION_REQUESTED + = "execution_requested" ``` Since `EventType` extends `StringEnum` (which extends `str`), no `.value` accessor is needed — the enum member IS the string. From 116c26aeb206a3f65de8a10037388c458229fbd0 Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Fri, 20 Feb 2026 00:13:12 +0100 Subject: [PATCH 7/9] dlq: removed general dlq_events topic, added new ones for consistency with general idea --- backend/app/dlq/manager.py | 7 ++-- backend/app/events/handlers.py | 40 +------------------ backend/workers/run_dlq_processor.py | 5 +-- docs/architecture/kafka-topic-architecture.md | 17 ++------ 4 files changed, 10 insertions(+), 59 deletions(-) diff --git a/backend/app/dlq/manager.py b/backend/app/dlq/manager.py index 17718641..ab65c1ac 100644 --- a/backend/app/dlq/manager.py +++ b/backend/app/dlq/manager.py @@ -57,7 +57,6 @@ def __init__( ] if f is not None ] - self._dlq_events_topic: str = EventType.DLQ_MESSAGE_RECEIVED def _filter_test_events(self, message: DLQMessage) -> bool: return not message.event.event_id.startswith("test-") @@ -103,7 +102,7 @@ async def handle_message(self, message: DLQMessage) -> None: user_id=message.event.metadata.user_id, ), ), - topic=self._dlq_events_topic, + topic=EventType.DLQ_MESSAGE_RECEIVED, ) retry_policy = self._resolve_retry_policy(message) @@ -157,7 +156,7 @@ async def retry_message(self, message: DLQMessage) -> None: user_id=message.event.metadata.user_id, ), ), - topic=self._dlq_events_topic, + topic=EventType.DLQ_MESSAGE_RETRIED, ) self.logger.info("Successfully retried message", event_id=message.event.event_id) @@ -187,7 +186,7 @@ async def discard_message(self, message: DLQMessage, reason: str) -> None: user_id=message.event.metadata.user_id, ), ), - topic=self._dlq_events_topic, + topic=EventType.DLQ_MESSAGE_DISCARDED, ) self.logger.warning("Discarded message", event_id=message.event.event_id, reason=reason) diff --git a/backend/app/events/handlers.py b/backend/app/events/handlers.py index b9b06267..6e9932e9 100644 --- a/backend/app/events/handlers.py +++ b/backend/app/events/handlers.py @@ -1,14 +1,10 @@ -import asyncio from collections.abc import Awaitable, Callable -from datetime import datetime, timezone import structlog from dishka.integrations.faststream import FromDishka from faststream import AckPolicy -from faststream.kafka import KafkaBroker, KafkaMessage +from faststream.kafka import KafkaBroker -from app.dlq.manager import DLQManager -from app.dlq.models import DLQMessage from app.domain.enums import EventType from app.domain.events import ( CreatePodCommandEvent, @@ -329,37 +325,3 @@ async def on_execution_timeout( await service.handle_execution_timeout(body) -def register_dlq_subscriber(broker: KafkaBroker) -> None: - """Register a DLQ subscriber that consumes dead-letter messages. - - DLQ messages are JSON-encoded DLQMessage models (Pydantic serialization via FastStream). - All DLQ metadata is in the message body — no Kafka headers needed. - """ - - @broker.subscriber( - "dead_letter_queue", - group_id="dlq-manager", - ack_policy=AckPolicy.ACK, - auto_offset_reset="earliest", - ) - async def on_dlq_message( - body: DLQMessage, - msg: KafkaMessage, - manager: FromDishka[DLQManager], - logger: FromDishka[structlog.stdlib.BoundLogger], - ) -> None: - start = asyncio.get_running_loop().time() - raw = msg.raw_message - assert not isinstance(raw, tuple) - body.dlq_offset = raw.offset - body.dlq_partition = raw.partition - - await manager.handle_message(body) - - manager.metrics.record_dlq_message_received(body.original_topic, body.event.event_type) - manager.metrics.record_dlq_message_age( - (datetime.now(timezone.utc) - body.failed_at).total_seconds() - ) - manager.metrics.record_dlq_processing_duration( - asyncio.get_running_loop().time() - start, "process" - ) diff --git a/backend/workers/run_dlq_processor.py b/backend/workers/run_dlq_processor.py index a6812d50..5f52f7e0 100644 --- a/backend/workers/run_dlq_processor.py +++ b/backend/workers/run_dlq_processor.py @@ -5,7 +5,6 @@ from app.core.logging import setup_logger from app.db.docs import ALL_DOCUMENTS from app.dlq.manager import DLQManager -from app.events.handlers import register_dlq_subscriber from app.settings import Settings from apscheduler.schedulers.asyncio import AsyncIOScheduler from beanie import init_beanie @@ -38,8 +37,8 @@ async def run() -> None: # Get broker from DI broker: KafkaBroker = await container.get(KafkaBroker) - # Register DLQ subscriber and set up DI integration - register_dlq_subscriber(broker) + # Set up DI integration (no subscribers — DLQ manager uses APScheduler, + # broker is only needed for publishing retry/status events) setup_dishka(container, broker=broker, auto_inject=True) scheduler = AsyncIOScheduler() diff --git a/docs/architecture/kafka-topic-architecture.md b/docs/architecture/kafka-topic-architecture.md index ebcc97bd..d07bd2b6 100644 --- a/docs/architecture/kafka-topic-architecture.md +++ b/docs/architecture/kafka-topic-architecture.md @@ -38,7 +38,6 @@ Topics are grouped into categories for configuration purposes (partition count, | Command | 3 | 1 day | `create_pod_command`, `delete_pod_command`, etc. | | User/Security | 3 | 30 days | `user_registered`, `security_violation`, etc. | | Default | 3 | 7 days | Everything else (saga, notification, DLQ, etc.) | -| DLQ | 3 | 14 days | `dead_letter_queue` | Configuration is defined in `infrastructure/kafka/topics.py` using category sets. @@ -54,7 +53,6 @@ Each worker subscribes to only the topics it needs, with its own consumer group: | `saga-orchestrator` | `execution_requested`, `execution_completed`, `execution_failed`, `execution_timeout` | | `notification-service` | `execution_completed`, `execution_failed`, `execution_timeout` | | `sse-bridge-pool` | 16 event types (execution + pod lifecycle + result) | -| `dlq-manager` | `dead_letter_queue` | Multiple consumer groups can subscribe to the same topic — Kafka delivers each message to every group independently. @@ -130,20 +128,13 @@ Create a replay session with filters (time range, event type), and ReplayService ```mermaid graph LR - Consumer[Consumer] -->|"failure"| DLQ[(dead_letter_queue topic)] - DLQ <--> Manager[DLQ Manager] + Consumer[Consumer] -->|"failure"| Manager[DLQ Manager] + Manager -->|"persist"| MongoDB[(MongoDB)] Manager -->|"retry"| Original[(Original Topic)] - Admin[Admin API] --> Manager + Manager -->|"status events"| Kafka[(dlq_* topics)] ``` -When a consumer fails to process an event after multiple retries, it lands in the dead letter queue. The DLQ manager handles retry logic with *exponential backoff* and configurable thresholds. Retry policies are determined by event type category (execution events get aggressive retries, pod events get cautious retries). - -Admins can: - -- Inspect failed events through the API -- Fix the underlying issue -- Replay events back to the original topic -- Delete or archive events that repeatedly fail +When a consumer fails to process an event, the DLQ manager receives it via direct `handle_message()` calls (not Kafka consumption). Messages are persisted to MongoDB and the manager handles retry logic with *exponential backoff* and configurable thresholds. Retry policies are determined by event type category (execution events get aggressive retries, pod events get cautious retries). Status events (`dlq_message_received`, `dlq_message_retried`, `dlq_message_discarded`) are published to their own per-event-type topics. ## Event schemas From a9c37cd7d2ec3a65cde420b45a1023495c4bc3de Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Fri, 20 Feb 2026 00:37:09 +0100 Subject: [PATCH 8/9] extra handler for exec cancelled events + misc fixes --- backend/app/api/routes/sse.py | 13 +++++++++++-- backend/app/events/handlers.py | 11 +++++++++++ backend/app/services/saga/saga_orchestrator.py | 9 +++++++++ docs/architecture/kafka-topic-architecture.md | 2 +- docs/reference/openapi.json | 8 +++++--- frontend/src/lib/api/sdk.gen.ts | 4 ++-- 6 files changed, 39 insertions(+), 8 deletions(-) diff --git a/backend/app/api/routes/sse.py b/backend/app/api/routes/sse.py index fd0613dd..96d2b1de 100644 --- a/backend/app/api/routes/sse.py +++ b/backend/app/api/routes/sse.py @@ -11,12 +11,21 @@ from app.schemas_pydantic.sse import SSEExecutionEventSchema from app.services.sse import SSEService + +class _SSEResponse(EventSourceResponse): + """Workaround: sse-starlette sets media_type only in __init__, not as a + class attribute. FastAPI reads the class attribute for OpenAPI generation, + so without this subclass every SSE endpoint shows application/json.""" + + media_type = "text/event-stream" + + router = APIRouter(prefix="/events", tags=["sse"], route_class=DishkaRoute) @router.get( "/notifications/stream", - response_class=EventSourceResponse, + response_class=_SSEResponse, responses={200: {"model": NotificationResponse}}, ) async def notification_stream( @@ -32,7 +41,7 @@ async def notification_stream( @router.get( "/executions/{execution_id}", - response_class=EventSourceResponse, + response_class=_SSEResponse, responses={200: {"model": SSEExecutionEventSchema}}, ) async def execution_events( diff --git a/backend/app/events/handlers.py b/backend/app/events/handlers.py index 6e9932e9..00569ced 100644 --- a/backend/app/events/handlers.py +++ b/backend/app/events/handlers.py @@ -248,6 +248,17 @@ async def on_execution_timeout( ) -> None: await orchestrator.handle_execution_timeout(body) + @broker.subscriber( + EventType.EXECUTION_CANCELLED, + group_id="saga-orchestrator", + ack_policy=AckPolicy.ACK, + ) + async def on_execution_cancelled( + body: ExecutionCancelledEvent, + orchestrator: FromDishka[SagaOrchestrator], + ) -> None: + await orchestrator.handle_execution_cancelled(body) + _SSE_EVENT_TYPES = [ EventType.EXECUTION_REQUESTED, diff --git a/backend/app/services/saga/saga_orchestrator.py b/backend/app/services/saga/saga_orchestrator.py index c27d23cd..50bf98d2 100644 --- a/backend/app/services/saga/saga_orchestrator.py +++ b/backend/app/services/saga/saga_orchestrator.py @@ -11,6 +11,7 @@ from app.domain.events import ( DomainEvent, EventMetadata, + ExecutionCancelledEvent, ExecutionCompletedEvent, ExecutionFailedEvent, ExecutionRequestedEvent, @@ -77,6 +78,14 @@ async def handle_execution_timeout(self, event: DomainEvent) -> None: event.execution_id, SagaState.TIMEOUT, f"Execution timed out after {event.timeout_seconds} seconds" ) + async def handle_execution_cancelled(self, event: DomainEvent) -> None: + """Handle EXECUTION_CANCELLED — marks saga as cancelled.""" + if not isinstance(event, ExecutionCancelledEvent): + raise TypeError(f"Expected ExecutionCancelledEvent, got {type(event).__name__}") + await self._resolve_completion( + event.execution_id, SagaState.CANCELLED, event.reason + ) + async def _resolve_completion( self, execution_id: str, state: SagaState, error_message: str | None = None ) -> None: diff --git a/docs/architecture/kafka-topic-architecture.md b/docs/architecture/kafka-topic-architecture.md index d07bd2b6..398eb83a 100644 --- a/docs/architecture/kafka-topic-architecture.md +++ b/docs/architecture/kafka-topic-architecture.md @@ -50,7 +50,7 @@ Each worker subscribes to only the topics it needs, with its own consumer group: | `execution-coordinator` | `execution_requested`, `execution_completed`, `execution_failed`, `execution_cancelled` | | `k8s-worker` | `create_pod_command`, `delete_pod_command` | | `result-processor` | `execution_completed`, `execution_failed`, `execution_timeout` | -| `saga-orchestrator` | `execution_requested`, `execution_completed`, `execution_failed`, `execution_timeout` | +| `saga-orchestrator` | `execution_requested`, `execution_completed`, `execution_failed`, `execution_timeout`, `execution_cancelled` | | `notification-service` | `execution_completed`, `execution_failed`, `execution_timeout` | | `sse-bridge-pool` | 16 event types (execution + pod lifecycle + result) | diff --git a/docs/reference/openapi.json b/docs/reference/openapi.json index 3d38ee52..b298b24d 100644 --- a/docs/reference/openapi.json +++ b/docs/reference/openapi.json @@ -1598,9 +1598,10 @@ "200": { "description": "Successful Response", "content": { - "application/json": { + "text/event-stream": { "schema": { - "$ref": "#/components/schemas/NotificationResponse" + "$ref": "#/components/schemas/NotificationResponse", + "type": "string" } } } @@ -1631,8 +1632,9 @@ "200": { "description": "Successful Response", "content": { - "application/json": { + "text/event-stream": { "schema": { + "type": "string", "$ref": "#/components/schemas/SSEExecutionEventSchema" } } diff --git a/frontend/src/lib/api/sdk.gen.ts b/frontend/src/lib/api/sdk.gen.ts index 54de5d8b..31f31516 100644 --- a/frontend/src/lib/api/sdk.gen.ts +++ b/frontend/src/lib/api/sdk.gen.ts @@ -262,14 +262,14 @@ export const livenessApiV1HealthLiveGet = * * Stream notifications for authenticated user. */ -export const notificationStreamApiV1EventsNotificationsStreamGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/v1/events/notifications/stream', ...options }); +export const notificationStreamApiV1EventsNotificationsStreamGet = (options?: Options) => (options?.client ?? client).sse.get({ url: '/api/v1/events/notifications/stream', ...options }); /** * Execution Events * * Stream events for specific execution. */ -export const executionEventsApiV1EventsExecutionsExecutionIdGet = (options: Options) => (options.client ?? client).get({ url: '/api/v1/events/executions/{execution_id}', ...options }); +export const executionEventsApiV1EventsExecutionsExecutionIdGet = (options: Options) => (options.client ?? client).sse.get({ url: '/api/v1/events/executions/{execution_id}', ...options }); /** * Browse Events From 7d0ceb52b0696d741a53e053669036e8477d104f Mon Sep 17 00:00:00 2001 From: HardMax71 Date: Fri, 20 Feb 2026 00:47:38 +0100 Subject: [PATCH 9/9] added missing event to sse events, updated docs --- backend/app/events/handlers.py | 1 + docs/architecture/event-system-design.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/app/events/handlers.py b/backend/app/events/handlers.py index 00569ced..69dcea4d 100644 --- a/backend/app/events/handlers.py +++ b/backend/app/events/handlers.py @@ -270,6 +270,7 @@ async def on_execution_cancelled( EventType.EXECUTION_TIMEOUT, EventType.EXECUTION_CANCELLED, EventType.RESULT_STORED, + EventType.RESULT_FAILED, EventType.POD_CREATED, EventType.POD_SCHEDULED, EventType.POD_RUNNING, diff --git a/docs/architecture/event-system-design.md b/docs/architecture/event-system-design.md index 4af61a60..cf627481 100644 --- a/docs/architecture/event-system-design.md +++ b/docs/architecture/event-system-design.md @@ -173,7 +173,7 @@ The producer handles both storage in MongoDB and publishing to Kafka in a single |------|---------| | [`domain/enums/events.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/app/domain/enums/events.py) | `EventType` enum with all event type values | | [`domain/events/typed.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/app/domain/events/typed.py) | All domain event classes and `DomainEvent` union | -| [`infrastructure/kafka/topics.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/app/infrastructure/kafka/topics.py) | Category-based topic configs for partition/retention tuning | +| [`infrastructure/kafka/topics.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/app/infrastructure/kafka/topics.py) | Event-type category sets (`EXECUTION_TYPES`, `POD_TYPES`, `COMMAND_TYPES`, etc.) for DLQ retry policy resolution and grouping | | [`events/core/producer.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/app/events/core/producer.py) | UnifiedProducer — persists to MongoDB then publishes to Kafka | | [`tests/unit/domain/events/test_event_schema_coverage.py`](https://github.com/HardMax71/Integr8sCode/blob/main/backend/tests/unit/domain/events/test_event_schema_coverage.py) | Validates correspondence between enum and event classes |