import type DomainMessage from "../../Domain/Event/DomainMessage"; import type DomainEvent from "../../Domain/Event/DomainEvent"; import type CommandBus from "../Bus/Command/CommandBus"; import type Saga from "./Saga"; import type ISagaRepository from "./SagaRepository"; import type { SagaStateSnapshot } from "./SagaState"; import EventListener from "../../EventSourcing/EventBus/EventListener"; /** * Factory function type for creating saga instances. */ export type SagaFactory> = (sagaId: string, correlationId: string) => TSaga; /** * Correlation ID extractor function type. * Extracts the correlation ID from an event for saga routing. */ export type CorrelationIdExtractor = (event: DomainEvent) => string; /** * Manages the lifecycle of sagas (process managers). * * Responsibilities: * - Start new sagas when starting events occur * - Route events to active sagas * - Handle saga completion and failure * - Persist saga state * - Trigger compensating transactions * * @example * ```typescript * const sagaManager = new SagaManager(commandBus, sagaRepository); * * sagaManager.register( * 'OrderFulfillmentSaga', * (id, correlationId) => new OrderFulfillmentSaga(id, {}, correlationId), * ['OrderPlaced'], * (event) => event.orderId * ); * * eventBus.addListener(sagaManager); * ``` */ export default class SagaManager extends EventListener { private readonly commandBus; private readonly repository; /** Registered saga types */ private readonly registrations; /** Event type to saga types mapping for starting events */ private readonly startingEventMap; /** Event type to saga types mapping for all interested events */ private readonly eventInterestMap; /** In-memory cache of active sagas */ private readonly activeSagas; constructor(commandBus: CommandBus, repository: ISagaRepository); /** * Register a saga type with the manager. * * @param sagaType The unique identifier for this saga type * @param factory Factory function to create saga instances * @param startingEvents Events that can start this saga * @param correlationIdExtractor Function to extract correlation ID from events */ register>(sagaType: string, factory: SagaFactory, startingEvents: string[], correlationIdExtractor: CorrelationIdExtractor): SagaManager; /** * Handle an incoming domain event. * Implements EventListener interface. * * @param message The domain message containing the event */ on(message: DomainMessage): Promise; /** * Handle events that can start new sagas. */ private handleStartingEvent; /** * Route an event to all interested active sagas. */ private routeEventToSagas; /** * Setup a saga with the command dispatcher. */ private setupSaga; /** * Create a command dispatcher function. */ private createCommandDispatcher; /** * Persist a saga's current state. */ private persistSaga; /** * Generate a unique saga ID. */ private generateSagaId; /** * Get the current status of a saga by ID. */ getSagaStatus(sagaId: string): Promise; /** * Get all active sagas for a correlation ID. */ getActiveSagasForCorrelation(correlationId: string): Promise; }