export type HandlerHooks = {
    preRun?: () => Promise<void>;
    postRun?: (events: number, handled: number) => Promise<void>;
};
export type Event = {
    type: string;
};
export type Command = {
    type: string;
};
export type Aggregate = {};
export type StoreEvent<E = unknown, A = unknown> = EventMeta & {
    event: E & {
        __persisted?: A;
    };
};
export type ProviderBookmark = {
    readonly name: string;
    getPosition(): Promise<any>;
    setPosition(position: any): Promise<void>;
};
export type DomainOptions<E extends Event, A extends Aggregate> = {
    aggregate: () => A;
    stream: string;
    fold: Fold<E, A>;
    provider: Provider<E> | Promise<Provider<E>>;
    useCache?: boolean;
};
export type StreamsHandler<T extends {
    [key: string]: Event;
}> = <TStream extends keyof T, TType extends T[TStream]['type']>(stream: TStream, type: TType, handler: (id: string, event: Ext<T[TStream], TType>, meta: EventMeta) => any) => void;
export type HandlerBookmark = string | ProviderBookmark;
export type EventMeta = {
    stream: string;
    position: any;
    version: number;
    timestamp: Date;
    aggregateId: string;
};
export type ErrorCallback = (err: any, stream: string, bookmark: string, event?: Event & {
    [key: string]: any;
}) => any;
type ID = {
    aggregateId: string;
};
export type BaseAggregate = {
    version: number;
    aggregateId: string;
    __pv?: string;
};
export type Fold<E extends Event, A extends Aggregate> = (ev: E, agg: A & BaseAggregate, meta: EventMeta) => Partial<A>;
export type Provider<Evt extends Event> = {
    driver: string;
    onError: ErrorCallback;
    getPosition(bookmark: string): Promise<any>;
    setPosition(bookmark: string, position: any): Promise<void>;
    getEventsFrom(stream: string | string[], position: any, limit?: number): Promise<Array<StoreEvent<Evt>>>;
    getEventsFor(stream: string, aggregateId: string, fromPosition?: any): Promise<Array<StoreEvent<Evt>>>;
    getLastEventFor(stream: string | string[], aggregateId?: string): Promise<StoreEvent<Evt & {
        __persisted?: any;
    }> | undefined>;
    createEvents(stream: string, aggregateId: string, version: number, event: Evt[]): Array<StoreEvent<Evt>>;
    append(stream: string, aggregateId: string, version: number, event: StoreEvent<Evt>[]): Promise<Array<StoreEvent<Evt>>>;
    limit?: number;
};
export type Handler<E extends Event> = {
    start(): void;
    stop(): void;
    reset(): void;
    runOnce(): Promise<number>;
    handle: <T extends E['type']>(type: T, cb: (aggregateId: string, event: Ext<E, T>, meta: EventMeta) => Promise<any>) => void;
    handlers: (body: HandlerBody<E>) => void;
    name: string;
};
export type Ext<E extends Event, T extends E['type']> = E extends {
    type: T;
} ? E : never;
export type CommandHandler<E extends Event, A extends Aggregate, C extends Command> = {
    [key in C['type']]: (cmd: OptCmd<C, key> & ID, agg: A & BaseAggregate) => Promise<E | E[] | void>;
};
type OptCmd<C extends Command, T extends C['type']> = Omit<Ext<C, T>, 'type'> & {
    type: T;
};
export type DomainHandlerOpts = {
    hooks?: HandlerHooks;
    /** Start handling events from the end of the stream */
    tailStream?: boolean;
    /** Every time the handler starts, always start from the end of the stream */
    alwaysTailStream?: boolean;
    /** When a handler throws, continue processing events */
    continueOnError?: boolean;
};
export type Domain<E extends Event, A extends Aggregate, C extends Command> = {
    handler(bookmark: string, options?: DomainHandlerOpts): Handler<E>;
    command: CmdBody<C, A>;
    getAggregate(id: string): Promise<ExecutableAggregate<C, A> & {
        aggregate: Readonly<A & BaseAggregate>;
    }>;
    retry?: boolean;
};
export type CmdBody<C extends Command, A extends Aggregate> = {
    [cmd in C['type']]: (aggId: string, body: ExtCmd<C, cmd>) => Promise<A & BaseAggregate>;
};
export type ExecutableAggregate<C extends Command, A extends Aggregate> = {
    [cmd in C['type']]: (body: ExtCmd<C, cmd>) => Promise<ExecutableAggregate<C, A> & {
        aggregate: Readonly<A & BaseAggregate>;
    }>;
};
type ExtCmd<C extends Command, T extends C['type']> = Omit<Ext<C, T>, 'type'>;
export type HandlerBody<E extends Event> = {
    [evt in E['type']]?: (id: string, evt: Ext<E, evt>, meta: EventMeta) => Promise<any>;
};
export type StorableAggregate<E extends Event = any, A extends Aggregate = any, S extends string = string> = {
    stream: S;
    fold: Fold<E, A>;
    aggregate: () => A;
    version?: string;
    persistAggregate?: boolean;
};
export type AggregateStore = {
    [key: string]: StorableAggregate;
};
export type ProvidedAggregate<E extends Event, A extends Aggregate, S extends string = string> = {
    stream: S;
    provider: Provider<E> | Promise<Provider<E>>;
    getAggregate: (id: string) => Promise<A & BaseAggregate>;
    toNextAggregate: (prev: A & BaseAggregate, event: StoreEvent<E>) => A & BaseAggregate;
    version?: string;
    persistAggregate?: boolean;
};
export {};
