import { IDecider } from '../domain/decider';
import { ISaga } from '../domain/saga';
/**
 * Event repository interface
 *
 * @typeParam C - Command
 * @typeParam E - Event
 * @typeParam V - Version
 * @typeParam CM - Command Metadata
 * @typeParam EM - Event Metadata
 *
 * @author Иван Дугалић / Ivan Dugalic / @idugalic
 */
export interface IEventRepository<C, E, V, CM, EM> {
    /**
     * Fetch events
     *
     * @param command - Command of type `C`
     *
     * @return list of Events with Version and Event Metadata
     */
    readonly fetch: (command: C) => Promise<readonly (E & V & EM)[]>;
    /**
     * Get the event stream version / sequence
     *
     * @param event - Event of type `E`
     *
     * @return the version / sequence of the event stream that this event belongs to.
     */
    readonly versionProvider: (event: E) => Promise<V | null>;
    /**
     * Save events
     *
     * @param events - list of Events
     * @param commandMetadata - Command Metadata of the command that initiated `events`
     * @param versionProvider - A provider for the Latest Event in this stream and its Version/Sequence
     * @return  a list of newly saved Event(s) of type `E` with Version of type `V` and with Event Metadata of type `EM`
     */
    readonly save: (events: readonly E[], commandMetadata: CM, versionProvider: (e: E) => Promise<V | null>) => Promise<readonly (E & V & EM)[]>;
}
/**
 * Event sourcing aggregate interface is using/delegating a `decider` of type `IDecider`<`C`, `S`, `E`> to handle commands and produce events.
 * In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via `IEventRepository.fetchEvents` function, and then delegate the command to the `decider` which can produce new event(s) as a result.
 *
 * Produced events are then stored via `IEventRepository.save` function.
 *
 * @typeParam C - Commands of type `C` that this aggregate can handle
 * @typeParam S - Aggregate state of type `S`
 * @typeParam E - Events of type `E` that this aggregate can publish
 * @typeParam V - Version
 * @typeParam CM - Command Metadata
 * @typeParam EM - Event Metadata
 *
 * @author Иван Дугалић / Ivan Dugalic / @idugalic
 */
export interface IEventSourcingAggregate<C, S, E, V, CM, EM> extends IDecider<C, S, E>, IEventRepository<C, E, V, CM, EM> {
    /**
     * Handles the command of type `C`, and returns new persisted list of pairs of event and its version.
     *
     * @param command - Command of type `C` with Command Metadata
     * @return list of persisted events with Version and Event Metadata
     */
    readonly handle: (command: C & CM) => Promise<readonly (E & V & EM)[]>;
}
/**
 * Event sourcing orchestrating aggregate interface is using/delegating a `decider` of type `IDecider`<`C`, `S`, `E`> to handle commands and produce events.
 * In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via `IEventRepository.fetchEvents` function, and then delegate the command to the `decider` which can produce new event(s) as a result.
 *
 * If the `decider` is combined out of many deciders via `combine` function, an optional `EventSourcingOrchestratingAggregate.saga` could be used to react on new events and send new commands to the `decider` recursively, in one transaction.
 *
 * Produced events are then stored via `IEventRepository.save` function.
 *
 * @typeParam C - Commands of type `C` that this aggregate can handle
 * @typeParam S - Aggregate state of type `S`
 * @typeParam E - Events of type `E` that this aggregate can publish
 * @typeParam V - Version
 * @typeParam CM - Command Metadata
 * @typeParam EM - Event Metadata
 *
 * @author Иван Дугалић / Ivan Dugalic / @idugalic
 */
export interface IEventSourcingOrchestratingAggregate<C, S, E, V, CM, EM> extends IEventSourcingAggregate<C, S, E, V, CM, EM>, ISaga<E, C> {
}
/**
 * An abstract algorithm to compute new events based on the old events and the command being handled.
 */
export declare abstract class EventComputation<C, S, E> implements IDecider<C, S, E> {
    protected readonly decider: IDecider<C, S, E>;
    protected constructor(decider: IDecider<C, S, E>);
    readonly initialState: S;
    decide(command: C, state: S): readonly E[];
    evolve(state: S, event: E): S;
    protected computeNewEvents(events: readonly E[], command: C): readonly E[];
}
/**
 * An abstract algorithm to compute new events based on the old events and the command being handled.
 * It returns all the events, including the events created by handling commands which are triggered by Saga - orchestration included.
 */
export declare abstract class EventOrchestratingComputation<C, S, E> implements IDecider<C, S, E>, ISaga<E, C> {
    protected readonly decider: IDecider<C, S, E>;
    protected readonly saga: ISaga<E, C>;
    protected constructor(decider: IDecider<C, S, E>, saga: ISaga<E, C>);
    readonly initialState: S;
    decide(command: C, state: S): readonly E[];
    evolve(state: S, event: E): S;
    react(event: E): readonly C[];
    private computeNewEventsInternally;
    protected computeNewEvents(events: readonly E[], command: C, fetch: (c: C) => Promise<readonly E[]>): Promise<readonly E[]>;
}
/**
 * Event sourcing aggregate is using/delegating a `EventSourcingAggregate.decider` of type `IDecider`<`C`, `S`, `E`> to handle commands and produce events.
 * In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via `IEventRepository.fetchEvents` function, and then delegate the command to the `EventSourcingAggregate.decider` which can produce new event(s) as a result.
 *
 *
 * Produced events are then stored via `IEventRepository.save` function.
 *
 * @typeParam C - Commands of type `C` that this aggregate can handle
 * @typeParam S - Aggregate state of type `S`
 * @typeParam E - Events of type `E` that this aggregate can publish
 * @typeParam E - Version
 * @typeParam CM - Command Metadata
 * @typeParam EM - Event Metadata
 *
 * @author Иван Дугалић / Ivan Dugalic / @idugalic
 */
export declare class EventSourcingAggregate<C, S, E, V, CM, EM> extends EventComputation<C, S, E> implements IEventSourcingAggregate<C, S, E, V, CM, EM> {
    protected readonly eventRepository: IEventRepository<C, E, V, CM, EM>;
    constructor(decider: IDecider<C, S, E>, eventRepository: IEventRepository<C, E, V, CM, EM>);
    fetch(command: C): Promise<readonly (E & V & EM)[]>;
    versionProvider(event: E): Promise<V | null>;
    save(events: readonly E[], commandMetadata: CM, versionProvider: (e: E) => Promise<V | null>): Promise<readonly (E & V & EM)[]>;
    handle(command: C & CM): Promise<readonly (E & V & EM)[]>;
}
/**
 * Event sourcing orchestrating aggregate is using/delegating a `EventSourcingOrchestratingAggregate.decider` of type `IDecider`<`C`, `S`, `E`> to handle commands and produce events.
 * In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via `IEventRepository.fetchEvents` function, and then delegate the command to the `EventSourcingOrchestratingAggregate.decider` which can produce new event(s) as a result.
 *
 * If the `EventSourcingOrchestratingAggregate.decider` is combined out of many deciders via `combine` function, an optional `EventSourcingOrchestratingAggregate.saga` could be used to react on new events and send new commands to the `EventSourcingOrchestratingAggregate.decider` recursively, in one transaction.
 *
 * Produced events are then stored via `IEventRepository.save` function.
 *
 * @typeParam C - Commands of type `C` that this aggregate can handle
 * @typeParam S - Aggregate state of type `S`
 * @typeParam E - Events of type `E` that this aggregate can publish
 * @typeParam V - Version
 * @typeParam CM - Command Metadata
 * @typeParam EM - Event Metadata
 *
 * @author Иван Дугалић / Ivan Dugalic / @idugalic
 */
export declare class EventSourcingOrchestratingAggregate<C, S, E, V, CM, EM> extends EventOrchestratingComputation<C, S, E> implements IEventSourcingOrchestratingAggregate<C, S, E, V, CM, EM> {
    protected readonly eventRepository: IEventRepository<C, E, V, CM, EM>;
    constructor(decider: IDecider<C, S, E>, eventRepository: IEventRepository<C, E, V, CM, EM>, saga: ISaga<E, C>);
    fetch(command: C): Promise<readonly (E & V & EM)[]>;
    versionProvider(event: E): Promise<V | null>;
    save(events: readonly E[], commandMetadata: CM, versionProvider: (e: E) => Promise<V | null>): Promise<readonly (E & V & EM)[]>;
    handle(command: C & CM): Promise<readonly (E & V & EM)[]>;
}
