@event-driven-io/emmett-esdb 0.43.0-beta.11 → 0.43.0-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../emmett/src/config/plugins/index.ts","../../emmett/src/validation/index.ts","../../emmett/src/errors/index.ts","../../emmett/src/validation/dates.ts","../../emmett/src/eventStore/afterCommit/afterEventStoreCommitHandler.ts","../../emmett/src/eventStore/afterCommit/forwardToMessageBus.ts","../../emmett/src/typing/command.ts","../../emmett/src/typing/event.ts","../../emmett/src/typing/message.ts","../../emmett/src/typing/index.ts","../../emmett/src/eventStore/events/index.ts","../../emmett/src/eventStore/eventStore.ts","../../emmett/src/eventStore/expectedVersion.ts","../../emmett/src/eventStore/inMemoryEventStore.ts","../../emmett/src/database/inMemoryDatabase.ts","../../emmett/src/utils/collections/duplicates.ts","../../emmett/src/utils/collections/merge.ts","../../emmett/src/utils/collections/index.ts","../../emmett/src/utils/deepEquals.ts","../../emmett/src/utils/iterators.ts","../../emmett/src/taskProcessing/executionGuards.ts","../../emmett/src/taskProcessing/taskProcessor.ts","../../emmett/src/utils/locking/index.ts","../../emmett/src/utils/numbers/bigint.ts","../../emmett/src/utils/promises.ts","../../emmett/src/utils/retry.ts","../../emmett/src/serialization/json/jsonSerializer.ts","../../emmett/src/utils/shutdown/gracefulShutdown.ts","../../emmett/src/utils/strings/hashText.ts","../../emmett/src/database/utils.ts","../../emmett/src/processors/processors.ts","../../emmett/src/processors/inMemoryProcessors.ts","../../emmett/src/eventStore/projections/inMemory/inMemoryProjection.ts","../../emmett/src/eventStore/projections/inMemory/inMemoryProjectionSpec.ts","../../emmett/src/testing/assertions.ts","../../emmett/src/testing/deciderSpecification.ts","../../emmett/src/testing/workflowSpecification.ts","../../emmett/src/testing/wrapEventStore.ts","../../emmett/src/eventStore/versioning/downcasting.ts","../../emmett/src/eventStore/versioning/upcasting.ts","../../emmett/src/commandHandling/handleCommand.ts","../../emmett/src/commandHandling/handleCommandWithDecider.ts","../../emmett/src/messageBus/index.ts","../../emmett/src/projections/index.ts","../../emmett/src/workflows/handleWorkflow.ts","../../emmett/src/workflows/workflow.ts","../../emmett/src/workflows/workflowProcessor.ts","../src/eventStore/consumers/eventStoreDBEventStoreConsumer.ts","../src/eventStore/consumers/subscriptions/index.ts","../src/eventStore/eventstoreDBEventStore.ts"],"sourcesContent":["export type EmmettPluginConfig =\n | {\n name: string;\n register: EmmettPluginRegistration[];\n }\n | string;\n\nexport type EmmettPluginType = 'cli';\n\nexport type EmmettCliPluginRegistration = { pluginType: 'cli'; path?: string };\n\nexport type EmmettPluginRegistration = EmmettCliPluginRegistration;\n\nexport type EmmettCliCommand = {\n addCommand<CliCommand>(command: CliCommand): CliCommand;\n};\n\nexport type EmmettCliPlugin = {\n pluginType: 'cli';\n name: string;\n registerCommands: (program: EmmettCliCommand) => Promise<void> | void;\n};\n\nexport type EmmettPlugin = EmmettCliPlugin;\n\nexport const isPluginConfig = (\n plugin: Partial<EmmettPluginConfig> | string | undefined,\n): plugin is EmmettPluginConfig =>\n plugin !== undefined &&\n (typeof plugin === 'string' ||\n ('name' in plugin &&\n plugin.name !== undefined &&\n typeof plugin.name === 'string'));\n","import { ValidationError } from '../errors';\n\nexport const enum ValidationErrors {\n NOT_A_NONEMPTY_STRING = 'NOT_A_NONEMPTY_STRING',\n NOT_A_POSITIVE_NUMBER = 'NOT_A_POSITIVE_NUMBER',\n NOT_AN_UNSIGNED_BIGINT = 'NOT_AN_UNSIGNED_BIGINT',\n}\n\nexport const isNumber = (val: unknown): val is number =>\n typeof val === 'number' && val === val;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const isBigint = (val: any): val is bigint =>\n typeof val === 'bigint' && val === val;\n\nexport const isString = (val: unknown): val is string =>\n typeof val === 'string';\n\nexport const assertNotEmptyString = (value: unknown): string => {\n if (!isString(value) || value.length === 0) {\n throw new ValidationError(ValidationErrors.NOT_A_NONEMPTY_STRING);\n }\n return value;\n};\n\nexport const assertPositiveNumber = (value: unknown): number => {\n if (!isNumber(value) || value <= 0) {\n throw new ValidationError(ValidationErrors.NOT_A_POSITIVE_NUMBER);\n }\n return value;\n};\n\nexport const assertUnsignedBigInt = (value: string): bigint => {\n const number = BigInt(value);\n if (number < 0) {\n throw new ValidationError(ValidationErrors.NOT_AN_UNSIGNED_BIGINT);\n }\n return number;\n};\n\nexport * from './dates';\n","import { isNumber, isString } from '../validation';\n\nexport type ErrorConstructor<ErrorType extends Error> = new (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ...args: any[]\n) => ErrorType;\n\nexport const isErrorConstructor = <ErrorType extends Error>(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n expect: Function,\n): expect is ErrorConstructor<ErrorType> => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return (\n typeof expect === 'function' &&\n expect.prototype &&\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n expect.prototype.constructor === expect\n );\n};\n\nexport class EmmettError extends Error {\n public static readonly Codes = {\n ValidationError: 400,\n IllegalStateError: 403,\n NotFoundError: 404,\n ConcurrencyError: 412,\n InternalServerError: 500,\n };\n\n public errorCode: number;\n\n constructor(\n options?: { errorCode: number; message?: string } | string | number,\n ) {\n const errorCode =\n options && typeof options === 'object' && 'errorCode' in options\n ? options.errorCode\n : isNumber(options)\n ? options\n : EmmettError.Codes.InternalServerError;\n const message =\n options && typeof options === 'object' && 'message' in options\n ? options.message\n : isString(options)\n ? options\n : `Error with status code '${errorCode}' ocurred during Emmett processing`;\n\n super(message);\n this.errorCode = errorCode;\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, EmmettError.prototype);\n }\n\n public static mapFrom(\n error: Error | { message?: string; errorCode?: number },\n ): EmmettError {\n if (EmmettError.isInstanceOf(error)) {\n return error;\n }\n\n return new EmmettError({\n errorCode:\n 'errorCode' in error &&\n error.errorCode !== undefined &&\n error.errorCode !== null\n ? error.errorCode\n : EmmettError.Codes.InternalServerError,\n message: error.message ?? 'An unknown error occurred',\n });\n }\n\n public static isInstanceOf<ErrorType extends EmmettError = EmmettError>(\n error: unknown,\n errorCode?: (typeof EmmettError.Codes)[keyof typeof EmmettError.Codes],\n ): error is ErrorType {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'errorCode' in error &&\n isNumber(error.errorCode) &&\n (errorCode === undefined || error.errorCode === errorCode)\n );\n }\n}\n\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: EmmettError.Codes.ConcurrencyError,\n message:\n message ??\n `Expected version ${expected.toString()} does not match current ${current?.toString()}`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyError.prototype);\n }\n}\n\n// TODO: Make it derive from ConcurrencyError to avoid code duplication\n// Or add additional type to distinguinsh both errors\nexport class ConcurrencyInMemoryDatabaseError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: EmmettError.Codes.ConcurrencyError,\n message: message ?? `Expected document state does not match current one!`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyInMemoryDatabaseError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: EmmettError.Codes.ValidationError,\n message: message ?? `Validation Error ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class IllegalStateError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: EmmettError.Codes.IllegalStateError,\n message: message ?? `Illegal State ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, IllegalStateError.prototype);\n }\n}\n\nexport class NotFoundError extends EmmettError {\n constructor(options?: { id: string; type: string; message?: string }) {\n super({\n errorCode: EmmettError.Codes.NotFoundError,\n message:\n options?.message ??\n (options?.id\n ? options.type\n ? `${options.type} with ${options.id} was not found during Emmett processing`\n : `State with ${options.id} was not found during Emmett processing`\n : options?.type\n ? `${options.type} was not found during Emmett processing`\n : 'State was not found during Emmett processing'),\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n","import { ValidationError } from '../errors';\n\nexport const formatDateToUtcYYYYMMDD = (date: Date) => {\n // Use the 'en-CA' locale which formats as 'yyyy-mm-dd'\n const formatter = new Intl.DateTimeFormat('en-CA', {\n timeZone: 'UTC',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n\n // Format the date\n return formatter.format(date);\n};\n\n// Function to validate 'yyyy-mm-dd' format\nexport const isValidYYYYMMDD = (dateString: string) => {\n const regex = /^\\d{4}-\\d{2}-\\d{2}$/;\n return regex.test(dateString);\n};\n\nexport const parseDateFromUtcYYYYMMDD = (dateString: string) => {\n const date = new Date(dateString + 'T00:00:00Z');\n\n if (!isValidYYYYMMDD(dateString)) {\n throw new ValidationError('Invalid date format, must be yyyy-mm-dd');\n }\n\n if (isNaN(date.getTime())) {\n throw new ValidationError('Invalid date format');\n }\n\n return date;\n};\n","import type {\n BatchRecordedMessageHandlerWithContext,\n BatchRecordedMessageHandlerWithoutContext,\n DefaultRecord,\n Event,\n ReadEvent,\n} from '../../typing';\nimport type { EventStore, EventStoreReadEventMetadata } from '../eventStore';\n\nexport type AfterEventStoreCommitHandler<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = HandlerContext extends undefined\n ? BatchRecordedMessageHandlerWithoutContext<\n Event,\n EventStoreReadEventMetadata<Store>\n >\n : BatchRecordedMessageHandlerWithContext<\n Event,\n EventStoreReadEventMetadata<Store>,\n NonNullable<HandlerContext>\n >;\n\nexport type BeforeEventStoreCommitHandler<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = HandlerContext extends undefined\n ? BatchRecordedMessageHandlerWithoutContext<\n Event,\n EventStoreReadEventMetadata<Store>\n >\n : BatchRecordedMessageHandlerWithContext<\n Event,\n EventStoreReadEventMetadata<Store>,\n NonNullable<HandlerContext>\n >;\n\ntype TryPublishMessagesAfterCommitOptions<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = {\n onAfterCommit?: AfterEventStoreCommitHandler<Store, HandlerContext>;\n};\n\nexport async function tryPublishMessagesAfterCommit<Store extends EventStore>(\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n options: TryPublishMessagesAfterCommitOptions<Store, undefined> | undefined,\n): Promise<boolean>;\nexport async function tryPublishMessagesAfterCommit<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n>(\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n options:\n | TryPublishMessagesAfterCommitOptions<Store, HandlerContext>\n | undefined,\n context: HandlerContext,\n): Promise<boolean>;\nexport async function tryPublishMessagesAfterCommit<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n>(\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n options:\n | TryPublishMessagesAfterCommitOptions<Store, HandlerContext>\n | undefined,\n context?: HandlerContext,\n): Promise<boolean> {\n if (options?.onAfterCommit === undefined) return false;\n\n try {\n await options?.onAfterCommit(messages, context!);\n return true;\n } catch (error) {\n // TODO: enhance with tracing\n console.error(`Error in on after commit hook`, error);\n return false;\n }\n}\n","import type { EventsPublisher } from '../../messageBus';\nimport type { DefaultRecord, Event, ReadEvent } from '../../typing';\nimport type { EventStore, EventStoreReadEventMetadata } from '../eventStore';\nimport type { AfterEventStoreCommitHandler } from './afterEventStoreCommitHandler';\n\nexport const forwardToMessageBus = <\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n>(\n eventPublisher: EventsPublisher,\n): AfterEventStoreCommitHandler<Store, HandlerContext> =>\n (async (\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n ): Promise<void> => {\n for (const message of messages) {\n await eventPublisher.publish(message);\n }\n }) as AfterEventStoreCommitHandler<Store, HandlerContext>;\n","import type { DefaultRecord } from './';\n\nexport type Command<\n CommandType extends string = string,\n CommandData extends DefaultRecord = DefaultRecord,\n CommandMetaData extends DefaultRecord | undefined = undefined,\n> = Readonly<\n CommandMetaData extends undefined\n ? {\n type: CommandType;\n data: Readonly<CommandData>;\n metadata?: DefaultCommandMetadata | undefined;\n }\n : {\n type: CommandType;\n data: CommandData;\n metadata: CommandMetaData;\n }\n> & { readonly kind?: 'Command' };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyCommand = Command<any, any, any>;\n\nexport type CommandTypeOf<T extends Command> = T['type'];\nexport type CommandDataOf<T extends Command> = T['data'];\nexport type CommandMetaDataOf<T extends Command> = T extends {\n metadata: infer M;\n}\n ? M\n : undefined;\n\nexport type CreateCommandType<\n CommandType extends string,\n CommandData extends DefaultRecord,\n CommandMetaData extends DefaultRecord | undefined = undefined,\n> = Readonly<\n CommandMetaData extends undefined\n ? {\n type: CommandType;\n data: CommandData;\n metadata?: DefaultCommandMetadata | undefined;\n }\n : {\n type: CommandType;\n data: CommandData;\n metadata: CommandMetaData;\n }\n> & { readonly kind?: 'Command' };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const command = <CommandType extends Command<string, any, any>>(\n ...args: CommandMetaDataOf<CommandType> extends undefined\n ? [\n type: CommandTypeOf<CommandType>,\n data: CommandDataOf<CommandType>,\n metadata?: DefaultCommandMetadata | undefined,\n ]\n : [\n type: CommandTypeOf<CommandType>,\n data: CommandDataOf<CommandType>,\n metadata: CommandMetaDataOf<CommandType>,\n ]\n): CommandType => {\n const [type, data, metadata] = args;\n\n return metadata !== undefined\n ? ({ type, data, metadata, kind: 'Command' } as CommandType)\n : ({ type, data, kind: 'Command' } as CommandType);\n};\n\nexport type DefaultCommandMetadata = { now: Date };\n","import type { DefaultRecord } from './';\nimport type {\n AnyRecordedMessageMetadata,\n CombinedMessageMetadata,\n CommonRecordedMessageMetadata,\n RecordedMessage,\n RecordedMessageMetadata,\n RecordedMessageMetadataWithGlobalPosition,\n RecordedMessageMetadataWithoutGlobalPosition,\n} from './message';\n\nexport type StreamPosition = bigint;\nexport type GlobalPosition = bigint;\n\nexport type Event<\n EventType extends string = string,\n EventData extends DefaultRecord = DefaultRecord,\n EventMetaData extends DefaultRecord | undefined = undefined,\n> = Readonly<\n EventMetaData extends undefined\n ? {\n type: EventType;\n data: EventData;\n }\n : {\n type: EventType;\n data: EventData;\n metadata: EventMetaData;\n }\n> & { readonly kind?: 'Event' };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyEvent = Event<any, any, any>;\n\nexport type EventTypeOf<T extends Event> = T['type'];\nexport type EventDataOf<T extends Event> = T['data'];\nexport type EventMetaDataOf<T extends Event> = T extends { metadata: infer M }\n ? M\n : undefined;\n\nexport type CreateEventType<\n EventType extends string,\n EventData extends DefaultRecord,\n EventMetaData extends DefaultRecord | undefined = undefined,\n> = Readonly<\n EventMetaData extends undefined\n ? {\n type: EventType;\n data: EventData;\n }\n : {\n type: EventType;\n data: EventData;\n metadata: EventMetaData;\n }\n> & { readonly kind?: 'Event' };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const event = <EventType extends Event<string, any, any>>(\n ...args: EventMetaDataOf<EventType> extends undefined\n ? [type: EventTypeOf<EventType>, data: EventDataOf<EventType>]\n : [\n type: EventTypeOf<EventType>,\n data: EventDataOf<EventType>,\n metadata: EventMetaDataOf<EventType>,\n ]\n): EventType => {\n const [type, data, metadata] = args;\n\n return metadata !== undefined\n ? ({ type, data, metadata, kind: 'Event' } as EventType)\n : ({ type, data, kind: 'Event' } as EventType);\n};\n\nexport type CombinedReadEventMetadata<\n EventType extends Event = Event,\n EventMetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n> = CombinedMessageMetadata<EventType, EventMetaDataType>;\n\nexport type ReadEvent<\n EventType extends Event = Event,\n EventMetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n> = RecordedMessage<EventType, EventMetaDataType>;\n\nexport type AnyReadEvent<\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n> = ReadEvent<AnyEvent, EventMetaDataType>;\n\nexport type CommonReadEventMetadata = CommonRecordedMessageMetadata;\n\nexport type ReadEventMetadata<HasGlobalPosition = undefined> =\n RecordedMessageMetadata<HasGlobalPosition>;\n\nexport type AnyReadEventMetadata = AnyRecordedMessageMetadata;\n\nexport type ReadEventMetadataWithGlobalPosition =\n RecordedMessageMetadataWithGlobalPosition;\n\nexport type ReadEventMetadataWithoutGlobalPosition =\n RecordedMessageMetadataWithoutGlobalPosition;\n","import type {\n AnyCommand,\n AnyEvent,\n Command,\n DefaultRecord,\n Event,\n GlobalPosition,\n StreamPosition,\n} from '.';\nimport type { ProcessorCheckpoint } from '../processors';\n\nexport type Message<\n Type extends string = string,\n Data extends DefaultRecord = DefaultRecord,\n MetaData extends DefaultRecord | undefined = undefined,\n> = Command<Type, Data, MetaData> | Event<Type, Data, MetaData>;\n\nexport type AnyMessage = AnyEvent | AnyCommand;\n\nexport type MessageKindOf<T extends Message> = T['kind'];\nexport type MessageTypeOf<T extends Message> = T['type'];\nexport type MessageDataOf<T extends Message> = T['data'];\nexport type MessageMetaDataOf<T extends Message> = T extends {\n metadata: infer M;\n}\n ? M\n : undefined;\n\nexport type CanHandle<T extends Message> = MessageTypeOf<T>[];\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const message = <MessageType extends Message<string, any, any>>(\n ...args: MessageMetaDataOf<MessageType> extends undefined\n ? [\n kind: MessageKindOf<MessageType>,\n type: MessageTypeOf<MessageType>,\n data: MessageDataOf<MessageType>,\n ]\n : [\n kind: MessageKindOf<MessageType>,\n type: MessageTypeOf<MessageType>,\n data: MessageDataOf<MessageType>,\n metadata: MessageMetaDataOf<MessageType>,\n ]\n): MessageType => {\n const [kind, type, data, metadata] = args;\n\n return metadata !== undefined\n ? ({ type, data, metadata, kind } as MessageType)\n : ({ type, data, kind } as MessageType);\n};\n\nexport type CombinedMessageMetadata<\n MessageType extends Message = Message,\n MessageMetaDataType extends DefaultRecord = DefaultRecord,\n> =\n MessageMetaDataOf<MessageType> extends undefined\n ? MessageMetaDataType\n : MessageMetaDataOf<MessageType> & MessageMetaDataType;\n\nexport type CombineMetadata<\n MessageType extends Message = Message,\n MessageMetaDataType extends DefaultRecord = DefaultRecord,\n> = MessageType & {\n metadata: CombinedMessageMetadata<MessageType, MessageMetaDataType>;\n};\n\nexport type RecordedMessage<\n MessageType extends Message = Message,\n MessageMetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n> = CombineMetadata<MessageType, MessageMetaDataType> & {\n kind: NonNullable<MessageKindOf<Message>>;\n};\n\nexport type CommonRecordedMessageMetadata = Readonly<{\n messageId: string;\n streamPosition: StreamPosition;\n streamName: string;\n checkpoint?: ProcessorCheckpoint | null;\n}>;\n\nexport type WithGlobalPosition = Readonly<{\n globalPosition: GlobalPosition;\n}>;\n\nexport type RecordedMessageMetadata<HasGlobalPosition = undefined> =\n CommonRecordedMessageMetadata &\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n (HasGlobalPosition extends undefined ? {} : WithGlobalPosition);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyRecordedMessage = Message<any, any, any>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyRecordedMessageMetadata = RecordedMessageMetadata<any>;\n\nexport type RecordedMessageMetadataWithGlobalPosition =\n RecordedMessageMetadata<true>;\n\nexport type RecordedMessageMetadataWithoutGlobalPosition =\n RecordedMessageMetadata<undefined>;\n","export * from './deepReadonly';\n\nexport * from './command';\nexport * from './event';\nexport * from './message';\nexport * from './messageHandling';\n\nexport * from './decider';\n\nexport type Brand<K, T> = K & { readonly __brand: T };\nexport type Flavour<K, T> = K & { readonly __brand?: T };\n\nexport type DefaultRecord = Record<string, unknown>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyRecord = Record<string, any>;\n\nexport type NonNullable<T> = T extends null | undefined ? never : T;\n\nexport const emmettPrefix = 'emt';\n\nexport const globalTag = 'global';\nexport const defaultTag = `${emmettPrefix}:default`;\nexport const unknownTag = `${emmettPrefix}:unknown`;\n","import {\n event,\n type Event,\n type EventDataOf,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n} from '../../typing';\n\nexport const GlobalStreamCaughtUpType = '__emt:GlobalStreamCaughtUp';\n\nexport type GlobalStreamCaughtUp = Event<\n '__emt:GlobalStreamCaughtUp',\n { globalPosition: bigint },\n { globalPosition: bigint }\n>;\n\nexport const isGlobalStreamCaughtUp = (\n event: Event,\n): event is GlobalStreamCaughtUp => event.type === GlobalStreamCaughtUpType;\n\nexport const caughtUpEventFrom =\n (position: bigint) =>\n (\n event: ReadEvent<Event, ReadEventMetadataWithGlobalPosition>,\n ): event is ReadEvent<\n GlobalStreamCaughtUp,\n ReadEventMetadataWithGlobalPosition\n > =>\n event.type === GlobalStreamCaughtUpType &&\n event.metadata?.globalPosition >= position;\n\nexport const globalStreamCaughtUp = (\n data: EventDataOf<GlobalStreamCaughtUp>,\n): GlobalStreamCaughtUp =>\n event<GlobalStreamCaughtUp>(GlobalStreamCaughtUpType, data, {\n globalPosition: data.globalPosition,\n });\n\nexport const isSubscriptionEvent = (\n event: Event,\n): event is GlobalSubscriptionEvent => isGlobalStreamCaughtUp(event);\n\nexport const isNotInternalEvent = (event: Event): boolean =>\n !isGlobalStreamCaughtUp(event);\n\nexport type GlobalSubscriptionEvent = GlobalStreamCaughtUp;\n","import type { JSONSerializationOptions } from '../serialization';\nimport type {\n AnyReadEventMetadata,\n CommonReadEventMetadata,\n DefaultRecord,\n Event,\n GlobalPosition,\n ReadEvent,\n ReadEventMetadata,\n StreamPosition,\n WithGlobalPosition,\n} from '../typing';\nimport type { AfterEventStoreCommitHandler } from './afterCommit';\nimport type { ExpectedStreamVersion } from './expectedVersion';\n\n// #region event-store\nexport interface EventStore<\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n> {\n aggregateStream<\n State,\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n ReadEventMetadataType,\n EventPayloadType\n >,\n ): Promise<AggregateStreamResult<State>>;\n\n readStream<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options?: ReadStreamOptions<EventType, EventPayloadType>,\n ): Promise<ReadStreamResult<EventType, ReadEventMetadataType>>;\n\n appendToStream<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResult>;\n\n streamExists(streamName: string): Promise<StreamExistsResult>;\n\n // streamEvents(): ReadableStream<\n // ReadEvent<Event, ReadEventMetadataType> | GlobalSubscriptionEvent\n // >;\n}\n\nexport type EventStoreReadEventMetadata<Store extends EventStore> =\n Store extends EventStore<infer T>\n ? T extends CommonReadEventMetadata\n ? T extends WithGlobalPosition\n ? ReadEventMetadata<true> & T\n : ReadEventMetadata<undefined> & T\n : never\n : never;\n\nexport type EventStoreSession<EventStoreType extends EventStore> = {\n eventStore: EventStoreType;\n close: () => Promise<void>;\n};\n\nexport interface EventStoreSessionFactory<EventStoreType extends EventStore> {\n withSession<T = unknown>(\n callback: (session: EventStoreSession<EventStoreType>) => Promise<T>,\n ): Promise<T>;\n}\n// #endregion event-store\n\nexport const canCreateEventStoreSession = <Store extends EventStore>(\n eventStore: Store | EventStoreSessionFactory<Store>,\n): eventStore is EventStoreSessionFactory<Store> => 'withSession' in eventStore;\n\nexport const nulloSessionFactory = <EventStoreType extends EventStore>(\n eventStore: EventStoreType,\n): EventStoreSessionFactory<EventStoreType> => ({\n withSession: (callback) => {\n const nulloSession: EventStoreSession<EventStoreType> = {\n eventStore,\n close: () => Promise.resolve(),\n };\n\n return callback(nulloSession);\n },\n});\n\n////////////////////////////////////////////////////////////////////\n/// Schema Versioning types\n////////////////////////////////////////////////////////////////////\n\nexport type EventStoreReadSchemaOptions<\n StreamEvent extends Event = Event,\n StoredEvent extends Event = StreamEvent,\n> = {\n versioning?: {\n upcast?: (event: StoredEvent) => StreamEvent;\n };\n};\n\nexport type EventStoreAppendSchemaOptions<\n StreamEvent extends Event = Event,\n StoredEvent extends Event = StreamEvent,\n> = {\n versioning?: {\n downcast?: (event: StreamEvent) => StoredEvent;\n };\n};\n\nexport type EventStoreSchemaOptions<\n StreamEvent extends Event = Event,\n StoredEvent extends Event = StreamEvent,\n> = EventStoreReadSchemaOptions<StreamEvent, StoredEvent> &\n EventStoreAppendSchemaOptions<StreamEvent, StoredEvent>;\n\n////////////////////////////////////////////////////////////////////\n/// ReadStream types\n////////////////////////////////////////////////////////////////////\n\nexport type ReadStreamOptions<\n EventType extends Event = Event,\n EventPayloadType extends Event = EventType,\n> = {\n from?: StreamPosition;\n to?: StreamPosition;\n maxCount?: bigint;\n expectedStreamVersion?: ExpectedStreamVersion;\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n} & JSONSerializationOptions;\n\nexport type ReadStreamResult<\n EventType extends Event,\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n> = {\n currentStreamVersion: StreamPosition;\n events: ReadEvent<EventType, ReadEventMetadataType>[];\n streamExists: boolean;\n};\n\n////////////////////////////////////////////////////////////////////\n/// AggregateStream types\n////////////////////////////////////////////////////////////////////\n\ntype Evolve<\n State,\n EventType extends Event,\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n> =\n | ((currentState: State, event: EventType) => State)\n | ((\n currentState: State,\n event: ReadEvent<EventType, ReadEventMetadataType>,\n ) => State)\n | ((currentState: State, event: ReadEvent<EventType>) => State);\n\nexport type AggregateStreamOptions<\n State,\n EventType extends Event,\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n EventPayloadType extends Event = EventType,\n> = {\n evolve: Evolve<State, EventType, ReadEventMetadataType>;\n initialState: () => State;\n read?: ReadStreamOptions<EventType, EventPayloadType>;\n};\n\nexport type AggregateStreamResult<State> = {\n currentStreamVersion: StreamPosition;\n state: State;\n streamExists: boolean;\n};\n\nexport type AggregateStreamResultWithGlobalPosition<State> =\n | (AggregateStreamResult<State> & {\n streamExists: true;\n lastEventGlobalPosition: GlobalPosition;\n })\n | (AggregateStreamResult<State> & {\n streamExists: false;\n });\n\nexport type AggregateStreamResultOfEventStore<Store extends EventStore> =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Store['aggregateStream'] extends (...args: any[]) => Promise<infer R>\n ? R\n : never;\n\n////////////////////////////////////////////////////////////////////\n/// AppendToStream types\n////////////////////////////////////////////////////////////////////\n\nexport type AppendToStreamOptions<\n EventType extends Event = Event,\n EventPayloadType extends Event = EventType,\n> = {\n expectedStreamVersion?: ExpectedStreamVersion;\n schema?: EventStoreAppendSchemaOptions<EventType, EventPayloadType> &\n JSONSerializationOptions;\n};\n\nexport type AppendToStreamResult = {\n nextExpectedStreamVersion: StreamPosition;\n createdNewStream: boolean;\n};\n\nexport type AppendToStreamResultWithGlobalPosition = AppendToStreamResult & {\n lastEventGlobalPosition: GlobalPosition;\n};\n\nexport type AppendStreamResultOfEventStore<Store extends EventStore> =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Store['appendToStream'] extends (...args: any[]) => Promise<infer R>\n ? R\n : never;\n\n////////////////////////////////////////////////////////////////////\n/// StreamExists types\n////////////////////////////////////////////////////////////////////\n\nexport type StreamExistsResult = boolean;\n\n////////////////////////////////////////////////////////////////////\n/// DefaultEventStoreOptions\n////////////////////////////////////////////////////////////////////\n\nexport type DefaultEventStoreOptions<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = {\n /**\n * Pluggable set of hooks informing about the event store internal behaviour.\n */\n hooks?: {\n /**\n * This hook will be called **AFTER** events were stored in the event store.\n * It's designed to handle scenarios where delivery and ordering guarantees do not matter much.\n *\n * **WARNINGS:**\n *\n * 1. It will be called **EXACTLY ONCE** if append succeded.\n * 2. If the hook fails, its append **will still silently succeed**, and no error will be thrown.\n * 3. Wen process crashes after events were committed, but before the hook was called, delivery won't be retried.\n * That can lead to state inconsistencies.\n * 4. In the case of high concurrent traffic, **race conditions may cause ordering issues**.\n * For instance, where the second hook takes longer to process than the first one, ordering won't be guaranteed.\n *\n * @type {AfterEventStoreCommitHandler<Store, HandlerContext>}\n */\n onAfterCommit?: AfterEventStoreCommitHandler<Store, HandlerContext>;\n };\n};\n","import { ConcurrencyError, EmmettError } from '../errors';\nimport type { Flavour, StreamPosition } from '../typing';\n\nexport type ExpectedStreamVersion =\n | ExpectedStreamVersionWithValue\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue = Flavour<\n StreamPosition,\n 'StreamVersion'\n>;\n\nexport type ExpectedStreamVersionGeneral = Flavour<\n 'STREAM_EXISTS' | 'STREAM_DOES_NOT_EXIST' | 'NO_CONCURRENCY_CHECK',\n 'StreamVersion'\n>;\n\nexport const STREAM_EXISTS = 'STREAM_EXISTS' as ExpectedStreamVersionGeneral;\nexport const STREAM_DOES_NOT_EXIST =\n 'STREAM_DOES_NOT_EXIST' as ExpectedStreamVersionGeneral;\nexport const NO_CONCURRENCY_CHECK =\n 'NO_CONCURRENCY_CHECK' as ExpectedStreamVersionGeneral;\n\nexport const matchesExpectedVersion = (\n current: StreamPosition | undefined,\n expected: ExpectedStreamVersion,\n defaultVersion: StreamPosition,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === defaultVersion;\n\n if (expected == STREAM_EXISTS) return current !== defaultVersion;\n\n return current === expected;\n};\n\nexport const assertExpectedVersionMatchesCurrent = (\n current: StreamPosition,\n expected: ExpectedStreamVersion | undefined,\n defaultVersion: StreamPosition,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected, defaultVersion))\n throw new ExpectedVersionConflictError(current, expected);\n};\n\nexport class ExpectedVersionConflictError extends ConcurrencyError {\n constructor(current: StreamPosition, expected: ExpectedStreamVersion) {\n super(current?.toString(), expected?.toString());\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);\n }\n}\n\nexport const isExpectedVersionConflictError = (\n error: unknown,\n): error is ExpectedVersionConflictError =>\n error instanceof ExpectedVersionConflictError ||\n EmmettError.isInstanceOf<ConcurrencyError>(\n error,\n ExpectedVersionConflictError.Codes.ConcurrencyError,\n );\n","import { v4 as uuid } from 'uuid';\nimport {\n getInMemoryDatabase,\n type InMemoryDatabase,\n} from '../database/inMemoryDatabase';\nimport { bigIntProcessorCheckpoint } from '../processors';\nimport type { ProjectionRegistration } from '../projections';\nimport type {\n CombinedReadEventMetadata,\n Event,\n ReadEvent,\n ReadEventMetadataWithGlobalPosition,\n} from '../typing';\nimport { tryPublishMessagesAfterCommit } from './afterCommit';\nimport type {\n AggregateStreamOptions,\n AggregateStreamResult,\n AppendToStreamOptions,\n AppendToStreamResult,\n DefaultEventStoreOptions,\n EventStore,\n ReadStreamOptions,\n ReadStreamResult,\n StreamExistsResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\nimport { handleInMemoryProjections } from './projections/inMemory';\nimport { downcastRecordedMessages, upcastRecordedMessages } from './versioning';\n\nexport const InMemoryEventStoreDefaultStreamVersion = 0n;\n\nexport type InMemoryEventStore =\n EventStore<ReadEventMetadataWithGlobalPosition> & {\n database: InMemoryDatabase;\n };\n\nexport type InMemoryReadEventMetadata = ReadEventMetadataWithGlobalPosition;\n\nexport type InMemoryProjectionHandlerContext = {\n eventStore?: InMemoryEventStore;\n database?: InMemoryDatabase;\n};\n\nexport type InMemoryEventStoreOptions =\n DefaultEventStoreOptions<InMemoryEventStore> & {\n projections?: ProjectionRegistration<\n 'inline',\n InMemoryReadEventMetadata,\n InMemoryProjectionHandlerContext\n >[];\n database?: InMemoryDatabase;\n };\n\nexport type InMemoryReadEvent<EventType extends Event = Event> = ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n>;\n\nexport const getInMemoryEventStore = (\n eventStoreOptions?: InMemoryEventStoreOptions,\n): InMemoryEventStore => {\n const streams = new Map<\n string,\n ReadEvent<Event, ReadEventMetadataWithGlobalPosition>[]\n >();\n\n const getAllEventsCount = () => {\n return Array.from<ReadEvent[]>(streams.values())\n .map((s) => s.length)\n .reduce((p, c) => p + c, 0);\n };\n\n // Get the database instance to be used for projections\n const database = eventStoreOptions?.database || getInMemoryDatabase();\n\n // Extract inline projections from options\n const inlineProjections = (eventStoreOptions?.projections ?? [])\n .filter(({ type }) => type === 'inline')\n .map(({ projection }) => projection);\n\n // Create the event store object\n const eventStore: InMemoryEventStore = {\n database,\n async aggregateStream<\n State,\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n ReadEventMetadataWithGlobalPosition,\n EventPayloadType\n >,\n ): Promise<AggregateStreamResult<State>> {\n const { evolve, initialState, read } = options;\n\n const result = await this.readStream<EventType, EventPayloadType>(\n streamName,\n read,\n );\n\n const events = result?.events ?? [];\n\n const state = events.reduce((s, e) => evolve(s, e), initialState());\n\n return {\n currentStreamVersion: BigInt(events.length),\n state,\n streamExists: result.streamExists,\n };\n },\n\n readStream: <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n readOptions?: ReadStreamOptions<EventType, EventPayloadType>,\n ): Promise<\n ReadStreamResult<EventType, ReadEventMetadataWithGlobalPosition>\n > => {\n const events = streams.get(streamName);\n const currentStreamVersion = events\n ? BigInt(events.length)\n : InMemoryEventStoreDefaultStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n readOptions?.expectedStreamVersion,\n InMemoryEventStoreDefaultStreamVersion,\n );\n\n const from = Number(readOptions?.from ?? 0);\n const to = Number(\n readOptions?.to ??\n (readOptions?.maxCount\n ? (readOptions.from ?? 0n) + readOptions.maxCount\n : (events?.length ?? 1)),\n );\n\n const resultEvents =\n events !== undefined && events.length > 0\n ? upcastRecordedMessages<\n EventType,\n EventPayloadType,\n ReadEventMetadataWithGlobalPosition\n >(\n events.slice(from, to) as ReadEvent<\n EventPayloadType,\n ReadEventMetadataWithGlobalPosition\n >[],\n readOptions?.schema?.versioning,\n )\n : [];\n\n const result: ReadStreamResult<\n EventType,\n ReadEventMetadataWithGlobalPosition\n > = {\n currentStreamVersion,\n events: resultEvents,\n streamExists: events !== undefined && events.length > 0,\n };\n\n return Promise.resolve(result);\n },\n\n appendToStream: async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResult> => {\n const currentEvents = streams.get(streamName) ?? [];\n const currentStreamVersion =\n currentEvents.length > 0\n ? BigInt(currentEvents.length)\n : InMemoryEventStoreDefaultStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n InMemoryEventStoreDefaultStreamVersion,\n );\n\n const newEvents: ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >[] = events.map((event, index) => {\n const globalPosition = BigInt(getAllEventsCount() + index + 1);\n const metadata: ReadEventMetadataWithGlobalPosition = {\n streamName,\n messageId: uuid(),\n streamPosition: BigInt(currentEvents.length + index + 1),\n globalPosition,\n checkpoint: bigIntProcessorCheckpoint(globalPosition),\n };\n return {\n ...event,\n kind: event.kind ?? 'Event',\n metadata: {\n ...('metadata' in event ? (event.metadata ?? {}) : {}),\n ...metadata,\n } as CombinedReadEventMetadata<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >,\n };\n });\n\n const positionOfLastEventInTheStream = BigInt(\n newEvents.slice(-1)[0]!.metadata.streamPosition,\n );\n\n streams.set(streamName, [\n ...currentEvents,\n ...downcastRecordedMessages(newEvents, options?.schema?.versioning),\n ]);\n\n // Process projections if there are any registered\n if (inlineProjections.length > 0) {\n await handleInMemoryProjections({\n projections: inlineProjections,\n events: newEvents,\n database: eventStore.database,\n eventStore,\n });\n }\n\n const result: AppendToStreamResult = {\n nextExpectedStreamVersion: positionOfLastEventInTheStream,\n createdNewStream:\n currentStreamVersion === InMemoryEventStoreDefaultStreamVersion,\n };\n\n await tryPublishMessagesAfterCommit<InMemoryEventStore>(\n newEvents,\n eventStoreOptions?.hooks,\n );\n\n return result;\n },\n\n streamExists: (streamName): Promise<StreamExistsResult> => {\n const events = streams.get(streamName);\n\n return Promise.resolve(events !== undefined && events.length > 0);\n },\n };\n\n return eventStore;\n};\n","import { v7 as uuid } from 'uuid';\nimport { deepEquals } from '../utils';\nimport type {\n DatabaseHandleOptionErrors,\n DatabaseHandleOptions,\n DatabaseHandleResult,\n DeleteResult,\n Document,\n DocumentHandler,\n InsertOneResult,\n OptionalUnlessRequiredIdAndVersion,\n ReplaceOneOptions,\n UpdateResult,\n WithIdAndVersion,\n WithoutId,\n} from './types';\nimport { expectedVersionValue, operationResult } from './utils';\n\nexport interface InMemoryDocumentsCollection<T extends Document> {\n handle: (\n id: string,\n handle: DocumentHandler<T>,\n options?: DatabaseHandleOptions,\n ) => Promise<DatabaseHandleResult<T>>;\n findOne: (predicate?: Predicate<T>) => Promise<T | null>;\n find: (predicate?: Predicate<T>) => Promise<T[]>;\n insertOne: (\n document: OptionalUnlessRequiredIdAndVersion<T>,\n ) => Promise<InsertOneResult>;\n deleteOne: (predicate?: Predicate<T>) => Promise<DeleteResult>;\n replaceOne: (\n predicate: Predicate<T>,\n document: WithoutId<T>,\n options?: ReplaceOneOptions,\n ) => Promise<UpdateResult>;\n}\n\nexport interface InMemoryDatabase {\n collection: <T extends Document>(\n name: string,\n ) => InMemoryDocumentsCollection<T>;\n}\n\ntype Predicate<T> = (item: T) => boolean;\ntype CollectionName = string;\n\nexport const getInMemoryDatabase = (): InMemoryDatabase => {\n const storage = new Map<CollectionName, WithIdAndVersion<Document>[]>();\n\n return {\n collection: <T extends Document, CollectionName extends string>(\n collectionName: CollectionName,\n collectionOptions: {\n errors?: DatabaseHandleOptionErrors;\n } = {},\n ): InMemoryDocumentsCollection<T> => {\n const ensureCollectionCreated = () => {\n if (!storage.has(collectionName)) storage.set(collectionName, []);\n };\n\n const errors = collectionOptions.errors;\n\n const collection = {\n collectionName,\n insertOne: async (\n document: OptionalUnlessRequiredIdAndVersion<T>,\n ): Promise<InsertOneResult> => {\n ensureCollectionCreated();\n\n const _id = (document._id as string | undefined | null) ?? uuid();\n const _version = document._version ?? 1n;\n\n const existing = await collection.findOne((c) => c._id === _id);\n\n if (existing) {\n return operationResult<InsertOneResult>(\n {\n successful: false,\n insertedId: null,\n nextExpectedVersion: _version,\n },\n { operationName: 'insertOne', collectionName, errors },\n );\n }\n\n const documentsInCollection = storage.get(collectionName)!;\n const newDocument = { ...document, _id, _version };\n const newCollection = [...documentsInCollection, newDocument];\n storage.set(collectionName, newCollection);\n\n return operationResult<InsertOneResult>(\n {\n successful: true,\n insertedId: _id,\n nextExpectedVersion: _version,\n },\n { operationName: 'insertOne', collectionName, errors },\n );\n },\n findOne: (predicate?: Predicate<T>): Promise<T | null> => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName);\n const filteredDocuments = predicate\n ? documentsInCollection?.filter((doc) => predicate(doc as T))\n : documentsInCollection;\n\n const firstOne = filteredDocuments?.[0] ?? null;\n\n return Promise.resolve(firstOne as T | null);\n },\n find: (predicate?: Predicate<T>): Promise<T[]> => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName);\n const filteredDocuments = predicate\n ? documentsInCollection?.filter((doc) => predicate(doc as T))\n : documentsInCollection;\n\n return Promise.resolve(filteredDocuments as T[]);\n },\n deleteOne: (predicate?: Predicate<T>): Promise<DeleteResult> => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName)!;\n\n if (predicate) {\n const foundIndex = documentsInCollection.findIndex((doc) =>\n predicate(doc as T),\n );\n\n if (foundIndex === -1) {\n return Promise.resolve(\n operationResult<DeleteResult>(\n {\n successful: false,\n matchedCount: 0,\n deletedCount: 0,\n },\n { operationName: 'deleteOne', collectionName, errors },\n ),\n );\n } else {\n const newCollection = documentsInCollection.toSpliced(\n foundIndex,\n 1,\n );\n\n storage.set(collectionName, newCollection);\n\n return Promise.resolve(\n operationResult<DeleteResult>(\n {\n successful: true,\n matchedCount: 1,\n deletedCount: 1,\n },\n { operationName: 'deleteOne', collectionName, errors },\n ),\n );\n }\n }\n\n const newCollection = documentsInCollection.slice(1);\n\n storage.set(collectionName, newCollection);\n\n return Promise.resolve(\n operationResult<DeleteResult>(\n {\n successful: true,\n matchedCount: 1,\n deletedCount: 1,\n },\n { operationName: 'deleteOne', collectionName, errors },\n ),\n );\n },\n replaceOne: (\n predicate: Predicate<T>,\n document: WithoutId<T>,\n options?: ReplaceOneOptions,\n ): Promise<UpdateResult> => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName)!;\n\n const firstIndex = documentsInCollection.findIndex((doc) =>\n predicate(doc as T),\n );\n\n if (firstIndex === undefined || firstIndex === -1) {\n return Promise.resolve(\n operationResult<UpdateResult>(\n {\n successful: false,\n matchedCount: 0,\n modifiedCount: 0,\n nextExpectedVersion: 0n,\n },\n { operationName: 'replaceOne', collectionName, errors },\n ),\n );\n }\n\n const existing = documentsInCollection[firstIndex]!;\n\n if (\n typeof options?.expectedVersion === 'bigint' &&\n existing._version !== options.expectedVersion\n ) {\n return Promise.resolve(\n operationResult<UpdateResult>(\n {\n successful: false,\n matchedCount: 1,\n modifiedCount: 0,\n nextExpectedVersion: existing._version,\n },\n { operationName: 'replaceOne', collectionName, errors },\n ),\n );\n }\n\n const newVersion = existing._version + 1n;\n\n const newCollection = documentsInCollection.with(firstIndex, {\n _id: existing._id,\n ...document,\n _version: newVersion,\n });\n\n storage.set(collectionName, newCollection);\n\n return Promise.resolve(\n operationResult<UpdateResult>(\n {\n successful: true,\n modifiedCount: 1,\n matchedCount: firstIndex,\n nextExpectedVersion: newVersion,\n },\n { operationName: 'replaceOne', collectionName, errors },\n ),\n );\n },\n handle: async (\n id: string,\n handle: DocumentHandler<T>,\n options?: DatabaseHandleOptions,\n ): Promise<DatabaseHandleResult<T>> => {\n const { expectedVersion: version, ...operationOptions } =\n options ?? {};\n ensureCollectionCreated();\n const existing = await collection.findOne(({ _id }) => _id === id);\n\n const expectedVersion = expectedVersionValue(version);\n\n if (\n (existing == null && version === 'DOCUMENT_EXISTS') ||\n (existing == null && expectedVersion != null) ||\n (existing != null && version === 'DOCUMENT_DOES_NOT_EXIST') ||\n (existing != null &&\n expectedVersion !== null &&\n existing._version !== expectedVersion)\n ) {\n return operationResult<DatabaseHandleResult<T>>(\n {\n successful: false,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n }\n\n const result = handle(existing !== null ? { ...existing } : null);\n\n if (deepEquals(existing, result))\n return operationResult<DatabaseHandleResult<T>>(\n {\n successful: true,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n\n if (!existing && result) {\n const newDoc = { ...result, _id: id };\n const insertResult = await collection.insertOne({\n ...newDoc,\n _id: id,\n } as OptionalUnlessRequiredIdAndVersion<T>);\n return {\n ...insertResult,\n document: {\n ...newDoc,\n _version: insertResult.nextExpectedVersion,\n } as unknown as WithIdAndVersion<T>,\n };\n }\n\n if (existing && !result) {\n const deleteResult = await collection.deleteOne(\n ({ _id }) => id === _id,\n );\n return { ...deleteResult, document: null };\n }\n\n if (existing && result) {\n const replaceResult = await collection.replaceOne(\n ({ _id }) => id === _id,\n result,\n {\n ...operationOptions,\n expectedVersion: expectedVersion ?? 'DOCUMENT_EXISTS',\n },\n );\n return {\n ...replaceResult,\n document: {\n ...result,\n _version: replaceResult.nextExpectedVersion,\n } as unknown as WithIdAndVersion<T>,\n };\n }\n\n return operationResult<DatabaseHandleResult<T>>(\n {\n successful: true,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n },\n };\n\n return collection;\n },\n };\n};\n","export const hasDuplicates = <ArrayItem, Mapped>(\n array: ArrayItem[],\n predicate: (value: ArrayItem, index: number, array: ArrayItem[]) => Mapped,\n) => {\n const mapped = array.map(predicate);\n const uniqueValues = new Set(mapped);\n\n return uniqueValues.size < mapped.length;\n};\n\nexport const getDuplicates = <ArrayItem, Mapped>(\n array: ArrayItem[],\n predicate: (value: ArrayItem, index: number, array: ArrayItem[]) => Mapped,\n): ArrayItem[] => {\n const map = new Map<Mapped, ArrayItem[]>();\n\n for (let i = 0; i < array.length; i++) {\n const item = array[i]!;\n const key = predicate(item, i, array);\n if (!map.has(key)) {\n map.set(key, []);\n }\n map.get(key)!.push(item);\n }\n\n return Array.from(map.values())\n .filter((group) => group.length > 1)\n .flat();\n};\n","export const merge = <T>(\n array: T[],\n item: T,\n where: (current: T) => boolean,\n onExisting: (current: T) => T,\n onNotFound: () => T | undefined = () => undefined,\n) => {\n let wasFound = false;\n\n const result = array\n // merge the existing item if matches condition\n .map((p: T) => {\n if (!where(p)) return p;\n\n wasFound = true;\n return onExisting(p);\n })\n // filter out item if undefined was returned\n // for cases of removal\n .filter((p) => p !== undefined)\n // make TypeScript happy\n .map((p) => {\n if (!p) throw Error('That should not happen');\n\n return p;\n });\n\n // if item was not found and onNotFound action is defined\n // try to generate new item\n if (!wasFound) {\n const result = onNotFound();\n\n if (result !== undefined) return [...array, item];\n }\n\n return result;\n};\n","import { getDuplicates, hasDuplicates } from './duplicates';\nimport { merge } from './merge';\n\nexport * from './merge';\n\nexport const arrayUtils = {\n merge,\n hasDuplicates,\n getDuplicates,\n};\n","const isPrimitive = (value: unknown): boolean => {\n const type = typeof value;\n return (\n value === null ||\n value === undefined ||\n type === 'boolean' ||\n type === 'number' ||\n type === 'string' ||\n type === 'symbol' ||\n type === 'bigint'\n );\n};\n\nconst compareArrays = <T>(left: T[], right: T[]): boolean => {\n if (left.length !== right.length) {\n return false;\n }\n for (let i = 0; i < left.length; i++) {\n const leftHas = i in left;\n const rightHas = i in right;\n if (leftHas !== rightHas) return false;\n if (leftHas && !deepEquals(left[i], right[i])) return false;\n }\n return true;\n};\n\nconst compareDates = (left: Date, right: Date): boolean => {\n return left.getTime() === right.getTime();\n};\n\nconst compareRegExps = (left: RegExp, right: RegExp): boolean => {\n return left.toString() === right.toString();\n};\n\nconst compareErrors = (left: Error, right: Error): boolean => {\n if (left.message !== right.message || left.name !== right.name) {\n return false;\n }\n const leftKeys = Object.keys(left);\n const rightKeys = Object.keys(right);\n if (leftKeys.length !== rightKeys.length) return false;\n const rightKeySet = new Set(rightKeys);\n for (const key of leftKeys) {\n if (!rightKeySet.has(key)) return false;\n // @ts-expect-error - accessing dynamic keys\n if (!deepEquals(left[key], right[key])) return false;\n }\n return true;\n};\n\nconst compareMaps = (\n left: Map<unknown, unknown>,\n right: Map<unknown, unknown>,\n): boolean => {\n if (left.size !== right.size) return false;\n\n for (const [key, value] of left) {\n if (isPrimitive(key)) {\n if (!right.has(key) || !deepEquals(value, right.get(key))) {\n return false;\n }\n } else {\n let found = false;\n for (const [rightKey, rightValue] of right) {\n if (deepEquals(key, rightKey) && deepEquals(value, rightValue)) {\n found = true;\n break;\n }\n }\n if (!found) return false;\n }\n }\n return true;\n};\n\nconst compareSets = (left: Set<unknown>, right: Set<unknown>): boolean => {\n if (left.size !== right.size) return false;\n\n for (const leftItem of left) {\n if (isPrimitive(leftItem)) {\n if (!right.has(leftItem)) return false;\n } else {\n let found = false;\n for (const rightItem of right) {\n if (deepEquals(leftItem, rightItem)) {\n found = true;\n break;\n }\n }\n if (!found) return false;\n }\n }\n return true;\n};\n\nconst compareArrayBuffers = (\n left: ArrayBuffer,\n right: ArrayBuffer,\n): boolean => {\n if (left.byteLength !== right.byteLength) return false;\n const leftView = new Uint8Array(left);\n const rightView = new Uint8Array(right);\n for (let i = 0; i < leftView.length; i++) {\n if (leftView[i] !== rightView[i]) return false;\n }\n return true;\n};\n\nconst compareTypedArrays = (\n left: ArrayBufferView,\n right: ArrayBufferView,\n): boolean => {\n if (left.constructor !== right.constructor) return false;\n if (left.byteLength !== right.byteLength) return false;\n\n const leftArray = new Uint8Array(\n left.buffer,\n left.byteOffset,\n left.byteLength,\n );\n const rightArray = new Uint8Array(\n right.buffer,\n right.byteOffset,\n right.byteLength,\n );\n\n for (let i = 0; i < leftArray.length; i++) {\n if (leftArray[i] !== rightArray[i]) return false;\n }\n return true;\n};\n\nconst compareObjects = (\n left: Record<string, unknown>,\n right: Record<string, unknown>,\n): boolean => {\n const keys1 = Object.keys(left);\n const keys2 = Object.keys(right);\n\n if (keys1.length !== keys2.length) {\n return false;\n }\n\n for (const key of keys1) {\n if (left[key] instanceof Function && right[key] instanceof Function) {\n continue;\n }\n\n const isEqual = deepEquals(left[key], right[key]);\n if (!isEqual) {\n return false;\n }\n }\n\n return true;\n};\n\nconst getType = (value: unknown): string => {\n if (value === null) return 'null';\n if (value === undefined) return 'undefined';\n\n const primitiveType = typeof value;\n if (primitiveType !== 'object') return primitiveType;\n\n if (Array.isArray(value)) return 'array';\n if (value instanceof Boolean) return 'boxed-boolean';\n if (value instanceof Number) return 'boxed-number';\n if (value instanceof String) return 'boxed-string';\n if (value instanceof Date) return 'date';\n if (value instanceof RegExp) return 'regexp';\n if (value instanceof Error) return 'error';\n if (value instanceof Map) return 'map';\n if (value instanceof Set) return 'set';\n if (value instanceof ArrayBuffer) return 'arraybuffer';\n if (value instanceof DataView) return 'dataview';\n if (value instanceof WeakMap) return 'weakmap';\n if (value instanceof WeakSet) return 'weakset';\n\n if (ArrayBuffer.isView(value)) return 'typedarray';\n\n return 'object';\n};\n\nexport const deepEquals = <T>(left: T, right: T): boolean => {\n if (left === right) return true;\n\n if (isEquatable(left)) {\n return left.equals(right);\n }\n\n const leftType = getType(left);\n const rightType = getType(right);\n\n if (leftType !== rightType) return false;\n\n switch (leftType) {\n case 'null':\n case 'undefined':\n case 'boolean':\n case 'number':\n case 'bigint':\n case 'string':\n case 'symbol':\n case 'function':\n return left === right;\n\n case 'array':\n return compareArrays(left as unknown[], right as unknown[]);\n\n case 'date':\n return compareDates(left as Date, right as Date);\n\n case 'regexp':\n return compareRegExps(left as RegExp, right as RegExp);\n\n case 'error':\n return compareErrors(left as Error, right as Error);\n\n case 'map':\n return compareMaps(\n left as Map<unknown, unknown>,\n right as Map<unknown, unknown>,\n );\n\n case 'set':\n return compareSets(left as Set<unknown>, right as Set<unknown>);\n\n case 'arraybuffer':\n return compareArrayBuffers(left as ArrayBuffer, right as ArrayBuffer);\n\n case 'dataview':\n case 'weakmap':\n case 'weakset':\n return false;\n\n case 'typedarray':\n return compareTypedArrays(\n left as ArrayBufferView,\n right as ArrayBufferView,\n );\n\n case 'boxed-boolean':\n return (left as boolean).valueOf() === (right as boolean).valueOf();\n\n case 'boxed-number':\n return (left as number).valueOf() === (right as number).valueOf();\n\n case 'boxed-string':\n return (left as string).valueOf() === (right as string).valueOf();\n\n case 'object':\n return compareObjects(\n left as Record<string, unknown>,\n right as Record<string, unknown>,\n );\n\n default:\n return false;\n }\n};\n\nexport type Equatable<T> = { equals: (right: T) => boolean } & T;\n\nexport const isEquatable = <T>(left: T): left is Equatable<T> => {\n return (\n left !== null &&\n left !== undefined &&\n typeof left === 'object' &&\n 'equals' in left &&\n typeof left['equals'] === 'function'\n );\n};\n","export const sum = (\n iterator: Iterator<number, number, number> | Iterator<number>,\n) => {\n let value,\n done: boolean | undefined,\n sum = 0;\n do {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n ({ value, done } = iterator.next());\n sum += value || 0;\n } while (!done);\n return sum;\n};\n","import { v7 as uuid } from 'uuid';\nimport { TaskProcessor } from './taskProcessor';\n\nexport type ExclusiveAccessGuard = {\n execute: <Result>(operation: () => Promise<Result>) => Promise<Result>;\n waitForIdle: () => Promise<void>;\n stop: (options?: { force?: boolean }) => Promise<void>;\n};\n\nexport const guardExclusiveAccess = (options?: {\n maxQueueSize?: number;\n}): ExclusiveAccessGuard => {\n const taskProcessor = new TaskProcessor({\n maxActiveTasks: 1,\n maxQueueSize: options?.maxQueueSize ?? 1000,\n });\n\n return {\n execute: <Result>(operation: () => Promise<Result>): Promise<Result> =>\n taskProcessor.enqueue(async ({ ack }) => {\n try {\n return await operation();\n } finally {\n ack();\n }\n }),\n waitForIdle: () => taskProcessor.waitForEndOfProcessing(),\n stop: (options) => taskProcessor.stop(options),\n };\n};\n\nexport type BoundedAccessGuard<Resource> = {\n acquire: () => Promise<Resource>;\n release: (resource: Resource) => void;\n execute: <Result>(\n operation: (resource: Resource) => Promise<Result>,\n ) => Promise<Result>;\n waitForIdle: () => Promise<void>;\n stop: (options?: { force?: boolean }) => Promise<void>;\n};\n\nexport const guardBoundedAccess = <Resource>(\n getResource: () => Resource | Promise<Resource>,\n options: {\n maxResources: number;\n maxQueueSize?: number;\n reuseResources?: boolean;\n closeResource?: (resource: Resource) => void | Promise<void>;\n },\n): BoundedAccessGuard<Resource> => {\n let isStopped = false;\n const taskProcessor = new TaskProcessor({\n maxActiveTasks: options.maxResources,\n maxQueueSize: options.maxQueueSize ?? 1000,\n });\n\n const resourcePool: Resource[] = [];\n const allResources = new Set<Resource>();\n const ackCallbacks = new Map<Resource, () => void>();\n\n const acquire = async (): Promise<Resource> =>\n taskProcessor.enqueue(async ({ ack }) => {\n try {\n let resource: Resource | undefined;\n\n if (options.reuseResources) {\n resource = resourcePool.pop();\n }\n\n if (!resource) {\n resource = await getResource();\n allResources.add(resource);\n }\n\n ackCallbacks.set(resource, ack);\n return resource;\n } catch (e) {\n ack();\n throw e;\n }\n });\n\n const release = (resource: Resource) => {\n const ack = ackCallbacks.get(resource);\n if (ack) {\n ackCallbacks.delete(resource);\n if (options.reuseResources) {\n resourcePool.push(resource);\n }\n ack();\n }\n };\n\n const execute = async <Result>(\n operation: (resource: Resource) => Promise<Result>,\n ): Promise<Result> => {\n const resource = await acquire();\n try {\n return await operation(resource);\n } finally {\n release(resource);\n }\n };\n\n return {\n acquire,\n release,\n execute,\n waitForIdle: () => taskProcessor.waitForEndOfProcessing(),\n stop: async (stopOptions) => {\n if (isStopped) return;\n isStopped = true;\n if (options?.closeResource) {\n const resources = [...allResources];\n allResources.clear();\n resourcePool.length = 0;\n await Promise.all(\n resources.map(\n async (resource) => await options.closeResource!(resource),\n ),\n );\n }\n\n await taskProcessor.stop(stopOptions);\n },\n };\n};\n\nexport type InitializedOnceGuard<T> = {\n ensureInitialized: () => Promise<T>;\n reset: () => void;\n stop: (options?: { force?: boolean }) => Promise<void>;\n};\n\nexport const guardInitializedOnce = <T>(\n initialize: () => Promise<T>,\n options?: {\n maxQueueSize?: number;\n maxRetries?: number;\n },\n): InitializedOnceGuard<T> => {\n let initPromise: Promise<T> | null = null;\n\n const taskProcessor = new TaskProcessor({\n maxActiveTasks: 1,\n maxQueueSize: options?.maxQueueSize ?? 1000,\n });\n\n const ensureInitialized = async (retryCount = 0): Promise<T> => {\n if (initPromise !== null) {\n return initPromise;\n }\n\n return taskProcessor.enqueue(\n async ({ ack }) => {\n if (initPromise !== null) {\n ack();\n return initPromise;\n }\n\n try {\n const promise = initialize();\n initPromise = promise;\n const result = await promise;\n ack();\n return result;\n } catch (error) {\n initPromise = null;\n ack();\n const maxRetries = options?.maxRetries ?? 3;\n if (retryCount < maxRetries) {\n return ensureInitialized(retryCount + 1);\n }\n throw error;\n }\n },\n { taskGroupId: uuid() },\n );\n };\n\n return {\n ensureInitialized,\n reset: () => {\n initPromise = null;\n },\n stop: (options) => taskProcessor.stop(options),\n };\n};\n","import { EmmettError } from '../errors';\n\nexport type TaskQueue = TaskQueueItem[];\n\nexport type TaskQueueItem = {\n task: () => Promise<void>;\n options?: EnqueueTaskOptions | undefined;\n};\n\nexport type TaskProcessorOptions = {\n maxActiveTasks: number;\n maxQueueSize: number;\n maxTaskIdleTime?: number;\n};\n\nexport type Task<T> = (context: TaskContext) => Promise<T>;\n\nexport type TaskContext = {\n ack: () => void;\n};\n\nexport type EnqueueTaskOptions = { taskGroupId?: string };\n\nexport class TaskProcessor {\n private queue: TaskQueue = [];\n private isProcessing = false;\n private activeTasks = 0;\n private activeGroups: Set<string> = new Set();\n private options: TaskProcessorOptions;\n private stopped = false;\n\n constructor(options: TaskProcessorOptions) {\n this.options = options;\n }\n\n enqueue<T>(task: Task<T>, options?: EnqueueTaskOptions): Promise<T> {\n if (this.stopped) {\n return Promise.reject(new EmmettError('TaskProcessor has been stopped'));\n }\n\n if (this.queue.length >= this.options.maxQueueSize) {\n return Promise.reject(\n new EmmettError('Too many pending tasks. Please try again later.'),\n );\n }\n\n return this.schedule(task, options);\n }\n\n waitForEndOfProcessing(): Promise<void> {\n return this.schedule(({ ack }) => Promise.resolve(ack()));\n }\n\n async stop(options?: { force?: boolean }): Promise<void> {\n if (this.stopped) return;\n this.stopped = true;\n this.queue.length = 0;\n this.activeGroups.clear();\n\n if (!options?.force) {\n await this.waitForEndOfProcessing();\n }\n }\n\n private schedule<T>(task: Task<T>, options?: EnqueueTaskOptions): Promise<T> {\n return promiseWithDeadline(\n (resolve, reject) => {\n const taskWithContext = () => {\n return new Promise<void>((resolveTask, failTask) => {\n const taskPromise = task({\n ack: resolveTask,\n });\n\n taskPromise.then(resolve).catch((err) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n failTask(err);\n reject(err);\n });\n });\n };\n\n this.queue.push({ task: taskWithContext, options });\n if (!this.isProcessing) {\n this.ensureProcessing();\n }\n },\n { deadline: this.options.maxTaskIdleTime },\n );\n }\n\n private ensureProcessing(): void {\n if (this.isProcessing) return;\n this.isProcessing = true;\n this.processQueue();\n }\n\n private processQueue(): void {\n try {\n while (\n this.activeTasks < this.options.maxActiveTasks &&\n this.queue.length > 0\n ) {\n const item = this.takeFirstAvailableItem();\n\n if (item === null) return;\n\n const groupId = item.options?.taskGroupId;\n\n if (groupId) {\n // Mark the group as active\n this.activeGroups.add(groupId);\n }\n\n this.activeTasks++;\n void this.executeItem(item);\n }\n } catch (error) {\n console.error(error);\n throw error;\n } finally {\n this.isProcessing = false;\n if (\n this.hasItemsToProcess() &&\n this.activeTasks < this.options.maxActiveTasks\n ) {\n this.ensureProcessing();\n }\n }\n }\n\n private async executeItem({ task, options }: TaskQueueItem): Promise<void> {\n try {\n await task();\n } finally {\n this.activeTasks--;\n\n // Mark the group as inactive after task completion\n if (options && options.taskGroupId) {\n this.activeGroups.delete(options.taskGroupId);\n }\n\n this.ensureProcessing();\n }\n }\n\n private takeFirstAvailableItem = (): TaskQueueItem | null => {\n const taskIndex = this.queue.findIndex(\n (item) =>\n !item.options?.taskGroupId ||\n !this.activeGroups.has(item.options.taskGroupId),\n );\n\n if (taskIndex === -1) {\n // All remaining tasks are blocked by active groups\n return null;\n }\n\n // Remove the task from the queue\n const [item] = this.queue.splice(taskIndex, 1);\n\n return item ?? null;\n };\n\n private hasItemsToProcess = (): boolean =>\n this.queue.findIndex(\n (item) =>\n !item.options?.taskGroupId ||\n !this.activeGroups.has(item.options.taskGroupId),\n ) !== -1;\n}\n\nconst DEFAULT_PROMISE_DEADLINE = 2147483647;\n\nconst promiseWithDeadline = <T>(\n executor: (\n resolve: (value: T | PromiseLike<T>) => void,\n reject: (reason?: unknown) => void,\n ) => void,\n options: { deadline?: number | undefined },\n) => {\n return new Promise<T>((resolve, reject) => {\n let taskStarted = false;\n let timeoutId: NodeJS.Timeout | null = null;\n\n const deadline = options.deadline ?? DEFAULT_PROMISE_DEADLINE;\n\n timeoutId = setTimeout(() => {\n if (!taskStarted) {\n reject(\n new Error('Task was not started within the maximum waiting time'),\n );\n }\n }, deadline);\n timeoutId.unref();\n\n executor(\n (value) => {\n taskStarted = true;\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n timeoutId = null;\n resolve(value);\n },\n (reason) => {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n timeoutId = null;\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n reject(reason);\n },\n );\n });\n};\n","import { TaskProcessor } from '../../taskProcessing';\n\nexport type LockOptions = { lockId: number };\n\nexport type AcquireLockOptions = { lockId: string };\nexport type ReleaseLockOptions = { lockId: string };\n\nexport type Lock = {\n acquire(options: AcquireLockOptions): Promise<void>;\n tryAcquire(options: AcquireLockOptions): Promise<boolean>;\n release(options: ReleaseLockOptions): Promise<boolean>;\n withAcquire: <Result = unknown>(\n handle: () => Promise<Result>,\n options: AcquireLockOptions,\n ) => Promise<Result>;\n};\n\nexport const InProcessLock = (): Lock => {\n const taskProcessor = new TaskProcessor({\n maxActiveTasks: Number.MAX_VALUE,\n maxQueueSize: Number.MAX_VALUE,\n });\n\n // Map to store ack functions of currently held locks: lockId -> ack()\n const locks = new Map<string, () => void>();\n\n return {\n async acquire({ lockId }: AcquireLockOptions): Promise<void> {\n // If the lock is already held, we just queue up another task in the same group.\n // TaskProcessor ensures tasks in the same group run one at a time.\n await new Promise<void>((resolve, reject) => {\n taskProcessor\n .enqueue(\n ({ ack }) => {\n // When this task starts, it means the previous lock (if any) was released\n // and now we have exclusive access.\n locks.set(lockId, ack);\n // We do NOT call ack() here. We hold onto the lock.\n resolve();\n return Promise.resolve();\n },\n { taskGroupId: lockId },\n )\n .catch(reject);\n });\n },\n\n async tryAcquire({ lockId }: AcquireLockOptions): Promise<boolean> {\n // If lock is already held, fail immediately\n if (locks.has(lockId)) {\n return false;\n }\n\n // TODO: Check pending queue\n await this.acquire({ lockId });\n\n return true;\n },\n\n release({ lockId }: ReleaseLockOptions): Promise<boolean> {\n const ack = locks.get(lockId);\n if (ack === undefined) {\n return Promise.resolve(true);\n }\n locks.delete(lockId);\n ack();\n return Promise.resolve(true);\n },\n\n async withAcquire<Result = unknown>(\n handle: () => Promise<Result>,\n { lockId }: AcquireLockOptions,\n ): Promise<Result> {\n return taskProcessor.enqueue(\n async ({ ack }) => {\n // When this task starts, it means the previous lock (if any) was released\n // and now we have exclusive access.\n locks.set(lockId, ack);\n\n // We do NOT call ack() here. We hold onto the lock.\n try {\n return await handle();\n } finally {\n locks.delete(lockId);\n ack();\n }\n },\n { taskGroupId: lockId },\n );\n },\n };\n};\n","export const toNormalizedString = (value: bigint): string =>\n value.toString().padStart(19, '0');\n\nexport const bigInt = {\n toNormalizedString,\n};\n","export const delay = (ms: number): Promise<void> => {\n return new Promise((resolve) => setTimeout(resolve, ms));\n};\n\nexport type AsyncAwaiter<T = void> = {\n wait: Promise<T>;\n resolve: (value: T | PromiseLike<T>) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n reject: (reason?: any) => void;\n reset: () => void;\n};\n\n// TODO: Remove this after migrating to Node 22\nexport const asyncAwaiter = <T = void>(): AsyncAwaiter<T> => {\n const result: AsyncAwaiter<T> = {} as AsyncAwaiter<T>;\n\n (result.reset = () => {\n result.wait = new Promise<T>((res, rej) => {\n result.resolve = res;\n result.reject = rej;\n });\n })();\n\n return result;\n};\n","import retry from 'async-retry';\nimport { EmmettError } from '../errors';\nimport { JSONSerializer } from '../serialization';\n\nexport type AsyncRetryOptions<T = unknown> = retry.Options & {\n shouldRetryResult?: (result: T) => boolean;\n shouldRetryError?: (error?: unknown) => boolean;\n};\n\nexport const NoRetries: AsyncRetryOptions = { retries: 0 };\n\nexport const asyncRetry = async <T>(\n fn: () => Promise<T>,\n opts?: AsyncRetryOptions<T>,\n): Promise<T> => {\n if (opts === undefined || opts.retries === 0) return fn();\n\n return retry(\n async (bail) => {\n try {\n const result = await fn();\n\n if (opts?.shouldRetryResult && opts.shouldRetryResult(result)) {\n throw new EmmettError(\n `Retrying because of result: ${JSONSerializer.serialize(result)}`,\n );\n }\n return result;\n } catch (error) {\n if (opts?.shouldRetryError && !opts.shouldRetryError(error)) {\n bail(error as Error);\n return undefined as unknown as T;\n }\n throw error;\n }\n },\n opts ?? { retries: 0 },\n );\n};\n","import type { SerializationCodec, Serializer } from './serializer';\n\ninterface JSONSerializer<\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n> extends Serializer<string, SerializeOptions, DeserializeOptions> {\n serialize<T>(object: T, options?: SerializeOptions): string;\n deserialize<T>(payload: string, options?: DeserializeOptions): T;\n}\n\ntype JSONSerializerOptions = {\n parseDates?: boolean;\n parseBigInts?: boolean;\n failOnBigIntSerialization?: boolean;\n useDefaultDateSerialization?: boolean;\n};\n\ntype JSONSerializeOptions = {\n replacer?: JSONReplacer;\n} & JSONSerializerOptions;\n\ntype JSONDeserializeOptions = {\n reviver?: JSONReviver;\n} & JSONSerializerOptions;\n\ninterface JSONCodec<\n T,\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n> extends SerializationCodec<T, string, SerializeOptions, DeserializeOptions> {\n encode(object: T, options?: SerializeOptions): string;\n decode(payload: string, options?: DeserializeOptions): T;\n}\n\ntype JSONCodecSerializationOptions<\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n> =\n | {\n serializer?: JSONSerializer<SerializeOptions, DeserializeOptions>;\n serializerOptions?: never;\n }\n | {\n serializer?: never;\n serializerOptions?: JSONSerializerOptions;\n };\n\ntype JSONSerializationOptions<\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n> = {\n serialization?:\n | {\n serializer?: JSONSerializer<SerializeOptions, DeserializeOptions>;\n options?: JSONSerializeOptions | JSONDeserializeOptions;\n }\n | undefined;\n};\n\ntype JSONCodecOptions<\n T,\n Payload = T,\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n> = JSONCodecSerializationOptions<SerializeOptions, DeserializeOptions> & {\n upcast?: (document: Payload) => T;\n downcast?: (document: T) => Payload;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype JSONReplacer = (this: any, key: string, value: any) => any;\n\ntype JSONReviver = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this: any,\n key: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: any,\n context: JSONReviverContext,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n) => any;\n\n// See more in: https://tc39.es/proposal-json-parse-with-source/\nexport type JSONReviverContext = {\n source: string;\n};\n\nconst bigIntReplacer: JSONReplacer = (_key, value) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return typeof value === 'bigint' ? value.toString() : value;\n};\n\nconst dateReplacer: JSONReplacer = (_key, value) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value instanceof Date ? value.toISOString() : value;\n};\n\nconst isFirstLetterNumeric = (str: string): boolean => {\n const c = str.charCodeAt(0);\n return c >= 48 && c <= 57;\n};\n\nconst isFirstLetterNumericOrMinus = (str: string): boolean => {\n const c = str.charCodeAt(0);\n return (c >= 48 && c <= 57) || c === 45;\n};\n\nconst bigIntReviver: JSONReviver = (_key, value, context) => {\n if (\n typeof value === 'number' &&\n Number.isInteger(value) &&\n !Number.isSafeInteger(value)\n ) {\n try {\n return BigInt(context?.source ?? value.toString());\n } catch {\n return value;\n }\n }\n if (typeof value === 'string' && value.length > 15) {\n if (isFirstLetterNumericOrMinus(value)) {\n const num = Number(value);\n if (Number.isFinite(num) && !Number.isSafeInteger(num)) {\n try {\n return BigInt(value);\n } catch {\n // not a valid bigint string\n }\n }\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n};\n\nconst dateReviver: JSONReviver = (_key, value) => {\n if (\n typeof value === 'string' &&\n value.length === 24 &&\n isFirstLetterNumeric(value) &&\n value[10] === 'T' &&\n value[23] === 'Z'\n ) {\n const date = new Date(value);\n if (!isNaN(date.getTime())) {\n return date;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n};\n\nconst composeJSONReplacers = (\n ...replacers: (JSONReplacer | undefined)[]\n): JSONReplacer | undefined => {\n const filteredReplacers = replacers.filter((r) => r !== undefined);\n\n if (filteredReplacers.length === 0) return undefined;\n\n return (key, value) =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n filteredReplacers.reduce(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n (accValue, replacer) => replacer(key, accValue),\n value,\n );\n};\n\nconst composeJSONRevivers = (\n ...revivers: (JSONReviver | undefined)[]\n): JSONReviver | undefined => {\n const filteredRevivers = revivers.filter((r) => r !== undefined);\n\n if (filteredRevivers.length === 0) return undefined;\n\n return (key, value, context) =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n filteredRevivers.reduce(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n (accValue, reviver) => reviver(key, accValue, context),\n value,\n );\n};\n\nconst JSONReplacer = (opts?: JSONSerializeOptions) =>\n composeJSONReplacers(\n opts?.replacer,\n opts?.failOnBigIntSerialization !== true ? JSONReplacers.bigInt : undefined,\n opts?.useDefaultDateSerialization !== true ? JSONReplacers.date : undefined,\n );\n\nconst JSONReviver = (opts?: JSONDeserializeOptions) =>\n composeJSONRevivers(\n opts?.reviver,\n opts?.parseBigInts === true ? JSONRevivers.bigInt : undefined,\n opts?.parseDates === true ? JSONRevivers.date : undefined,\n );\n\nconst JSONReplacers = {\n bigInt: bigIntReplacer,\n date: dateReplacer,\n};\n\nconst JSONRevivers = {\n bigInt: bigIntReviver,\n date: dateReviver,\n};\n\ntype ClassicJsonReviver =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this: any, key: string, value: any) => any;\n\nconst jsonSerializer = (\n options?: JSONSerializerOptions &\n JSONDeserializeOptions &\n JSONSerializeOptions,\n): JSONSerializer => {\n const defaultReplacer = JSONReplacer(options);\n const defaultReviver = JSONReviver(options);\n\n return {\n serialize: <T>(\n object: T,\n serializerOptions?: JSONSerializeOptions,\n ): string =>\n JSON.stringify(\n object,\n serializerOptions ? JSONReplacer(serializerOptions) : defaultReplacer,\n ),\n deserialize: <T>(\n payload: string,\n deserializerOptions?: JSONDeserializeOptions,\n ): T =>\n JSON.parse(\n payload,\n (deserializerOptions\n ? JSONReviver(deserializerOptions)\n : defaultReviver) as ClassicJsonReviver,\n ) as T,\n };\n};\n\nconst JSONSerializer: JSONSerializer & {\n from: <\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n >(\n options?: JSONSerializationOptions<SerializeOptions, DeserializeOptions>,\n ) => JSONSerializer<SerializeOptions, DeserializeOptions>;\n} = Object.assign(jsonSerializer(), {\n from: <\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n >(\n options?: JSONSerializationOptions<SerializeOptions, DeserializeOptions>,\n ) =>\n options?.serialization?.serializer ??\n (options?.serialization?.options\n ? jsonSerializer(options?.serialization?.options)\n : JSONSerializer),\n});\n\nconst JSONCodec = <\n T,\n Payload = T,\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n>(\n options: JSONCodecOptions<T, Payload, SerializeOptions, DeserializeOptions>,\n): JSONCodec<T, SerializeOptions, DeserializeOptions> => {\n const serializer =\n 'serializer' in options && options.serializer\n ? options.serializer\n : jsonSerializer(\n 'serializerOptions' in options\n ? options.serializerOptions\n : undefined,\n );\n\n const upcast = options.upcast ?? ((doc: Payload) => doc as unknown as T);\n const downcast = options.downcast ?? ((doc: T) => doc as unknown as Payload);\n\n return {\n decode: (payload: string, decodeOptions?: DeserializeOptions) => {\n const deserialized = decodeOptions\n ? serializer.deserialize<Payload>(payload, decodeOptions)\n : serializer.deserialize<Payload>(payload);\n return upcast(deserialized);\n },\n encode: (object: T, encodeOptions?: SerializeOptions) => {\n const downcasted = downcast(object);\n return encodeOptions\n ? serializer.serialize(downcasted, encodeOptions)\n : serializer.serialize(downcasted);\n },\n };\n};\n\nexport {\n composeJSONReplacers,\n composeJSONRevivers,\n JSONCodec,\n JSONReplacer,\n JSONReplacers,\n JSONReviver,\n JSONRevivers,\n JSONSerializer,\n jsonSerializer,\n type JSONCodecOptions,\n type JSONDeserializeOptions,\n type JSONSerializationOptions,\n type JSONSerializeOptions,\n type JSONSerializerOptions,\n};\n","export type ShutdownHandler = () => void | Promise<void>;\n\n/**\n * Registers handlers for OS signals to enable graceful shutdown.\n * Handles SIGTERM and SIGINT by default.\n * Works in Node.js, Bun, and Deno. Safely no-ops in Browser/Cloudflare Workers.\n *\n * @param handler - Function to call when shutdown signal is received\n * @returns Cleanup function to unregister the handlers\n */\nexport const onShutdown = (handler: ShutdownHandler): (() => void) => {\n const signals = ['SIGTERM', 'SIGINT'] as const;\n\n // Node.js/Bun\n if (typeof process !== 'undefined' && typeof process.on === 'function') {\n for (const signal of signals) {\n process.on(signal, handler);\n }\n return () => {\n for (const signal of signals) {\n process.off(signal, handler);\n }\n };\n }\n\n // Deno\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access\n const deno = (globalThis as any).Deno;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (deno && typeof deno.addSignalListener === 'function') {\n for (const signal of signals) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n deno.addSignalListener(signal, handler);\n }\n return () => {\n for (const signal of signals) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n deno.removeSignalListener(signal, handler);\n }\n };\n }\n\n // Browser/Cloudflare Workers: no-op\n return () => {};\n};\n","const textEncoder = new TextEncoder();\n\nexport const hashText = async (text: string): Promise<bigint> => {\n const hashBuffer = await crypto.subtle.digest(\n 'SHA-256',\n textEncoder.encode(text),\n );\n // Create an array with a single element that is a 64-bit signed integer\n // We take the first 8 bytes (so 64 bits) of the SHA-256 hash\n const view = new BigInt64Array(hashBuffer, 0, 1);\n return view[0]!;\n};\n","import { ConcurrencyInMemoryDatabaseError } from '../errors';\nimport { JSONSerializer } from '../serialization';\nimport type {\n DatabaseHandleOptionErrors,\n ExpectedDocumentVersion,\n ExpectedDocumentVersionGeneral,\n ExpectedDocumentVersionValue,\n OperationResult,\n} from './types';\n\nexport const isGeneralExpectedDocumentVersion = (\n version: ExpectedDocumentVersion | undefined,\n): version is ExpectedDocumentVersionGeneral => {\n return (\n version === 'DOCUMENT_DOES_NOT_EXIST' ||\n version === 'DOCUMENT_EXISTS' ||\n version === 'NO_CONCURRENCY_CHECK'\n );\n};\n\nexport const expectedVersionValue = (\n version: ExpectedDocumentVersion | undefined,\n): ExpectedDocumentVersionValue | null =>\n version === undefined || isGeneralExpectedDocumentVersion(version)\n ? null\n : version;\n\nexport const operationResult = <T extends OperationResult>(\n result: Omit<T, 'assertSuccess' | 'acknowledged' | 'assertSuccessful'>,\n options: {\n operationName: string;\n collectionName: string;\n errors?: DatabaseHandleOptionErrors;\n },\n): T => {\n const operationResult: T = {\n ...result,\n acknowledged: true,\n successful: result.successful,\n assertSuccessful: (errorMessage?: string) => {\n const { successful } = result;\n const { operationName, collectionName } = options;\n\n if (!successful)\n throw new ConcurrencyInMemoryDatabaseError(\n errorMessage ??\n `${operationName} on ${collectionName} failed. Expected document state does not match current one! Result: ${JSONSerializer.serialize(result)}!`,\n );\n },\n } as T;\n\n if (options.errors?.throwOnOperationFailures)\n operationResult.assertSuccessful();\n\n return operationResult;\n};\n","import { v7 as uuid } from 'uuid';\nimport type { EmmettError } from '../errors';\nimport { upcastRecordedMessage } from '../eventStore';\nimport type { ProjectionDefinition } from '../projections';\nimport type { JSONSerializationOptions } from '../serialization';\nimport {\n defaultTag,\n type AnyEvent,\n type AnyMessage,\n type AnyReadEventMetadata,\n type AnyRecordedMessageMetadata,\n type BatchRecordedMessageHandlerWithContext,\n type Brand,\n type CanHandle,\n type DefaultRecord,\n type Event,\n type Message,\n type MessageHandlerResult,\n type RecordedMessage,\n type SingleMessageHandlerWithContext,\n type SingleRecordedMessageHandlerWithContext,\n} from '../typing';\nimport { bigInt } from '../utils';\nimport { onShutdown } from '../utils/shutdown';\n\nexport type CurrentMessageProcessorPosition =\n | { lastCheckpoint: ProcessorCheckpoint }\n | 'BEGINNING'\n | 'END';\n\nexport type GetCheckpoint<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n> = (\n message: RecordedMessage<MessageType, MessageMetadataType>,\n) => ProcessorCheckpoint | null;\n\nexport const getCheckpoint = <\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n>(\n message: RecordedMessage<MessageType, MessageMetadataType>,\n): ProcessorCheckpoint | null => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access\n return message.metadata.checkpoint;\n};\n\nexport const wasMessageHandled = <\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n>(\n message: RecordedMessage<MessageType, MessageMetadataType>,\n checkpoint: ProcessorCheckpoint | null,\n): boolean => {\n //TODO Make it smarter\n const messageCheckpoint = getCheckpoint(message);\n\n return (\n messageCheckpoint !== null &&\n messageCheckpoint !== undefined &&\n checkpoint !== null &&\n checkpoint !== undefined &&\n messageCheckpoint <= checkpoint\n );\n};\n\nexport type MessageProcessorStartFrom =\n | CurrentMessageProcessorPosition\n | 'CURRENT';\n\nexport type MessageProcessorType = 'projector' | 'reactor';\nexport const MessageProcessorType = {\n PROJECTOR: 'projector' as MessageProcessorType,\n REACTOR: 'reactor' as MessageProcessorType,\n};\n\nexport type MessageProcessor<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = {\n id: string;\n instanceId: string;\n type: string;\n canHandle?: string[];\n init: (options: Partial<HandlerContext>) => Promise<void>;\n start: (\n options: Partial<HandlerContext>,\n ) => Promise<CurrentMessageProcessorPosition | undefined>;\n close: (closeOptions: Partial<HandlerContext>) => Promise<void>;\n isActive: boolean;\n handle: BatchRecordedMessageHandlerWithContext<\n MessageType,\n MessageMetadataType,\n Partial<HandlerContext>\n >;\n};\n\nexport const MessageProcessor = {\n result: {\n skip: (options?: { reason?: string }): MessageHandlerResult => ({\n type: 'SKIP',\n ...(options ?? {}),\n }),\n stop: (options?: {\n reason?: string;\n error?: EmmettError;\n }): MessageHandlerResult => ({\n type: 'STOP',\n ...(options ?? {}),\n }),\n },\n};\n\nexport type MessageProcessingScope<\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = <Result = MessageHandlerResult>(\n handler: (context: HandlerContext) => Result | Promise<Result>,\n partialContext: Partial<HandlerContext>,\n) => Result | Promise<Result>;\n\nexport type Checkpointer<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n read: ReadProcessorCheckpoint<HandlerContext>;\n store: StoreProcessorCheckpoint<\n MessageType,\n MessageMetadataType,\n HandlerContext\n >;\n};\n\nexport type ProcessorHooks<\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n onInit?: OnReactorInitHook<HandlerContext>;\n onStart?: OnReactorStartHook<HandlerContext>;\n onClose?: OnReactorCloseHook<HandlerContext>;\n};\n\nexport type BaseMessageProcessorOptions<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n type?: string;\n processorId: string;\n processorInstanceId?: string;\n version?: number;\n partition?: string;\n startFrom?: MessageProcessorStartFrom;\n stopAfter?: (\n message: RecordedMessage<MessageType, MessageMetadataType>,\n ) => boolean;\n processingScope?: MessageProcessingScope<HandlerContext>;\n checkpoints?: Checkpointer<MessageType, MessageMetadataType, HandlerContext>;\n canHandle?: CanHandle<MessageType>;\n hooks?: ProcessorHooks<HandlerContext>;\n} & JSONSerializationOptions;\n\nexport type HandlerOptions<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n> =\n | {\n eachMessage: SingleRecordedMessageHandlerWithContext<\n MessageType,\n MessageMetadataType,\n HandlerContext\n >;\n eachBatch?: never;\n }\n | {\n eachMessage?: never;\n eachBatch: BatchRecordedMessageHandlerWithContext<\n MessageType,\n MessageMetadataType,\n HandlerContext\n >;\n };\n\nexport type OnReactorInitHook<\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = (context: HandlerContext) => Promise<void>;\n\nexport type OnReactorStartHook<\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = (context: HandlerContext) => Promise<void>;\n\nexport type OnReactorCloseHook<\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = (context: HandlerContext) => Promise<void>;\n\nexport type ReactorOptions<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n MessagePayloadType extends AnyMessage = MessageType,\n> = BaseMessageProcessorOptions<\n MessageType,\n MessageMetadataType,\n HandlerContext\n> &\n HandlerOptions<MessageType, MessageMetadataType, HandlerContext> & {\n messageOptions?: {\n schema?: {\n versioning?: { upcast?: (event: MessagePayloadType) => MessageType };\n };\n };\n };\n\nexport type ProjectorOptions<\n EventType extends AnyEvent = AnyEvent,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n EventPayloadType extends Event = EventType,\n> = Omit<\n BaseMessageProcessorOptions<EventType, MessageMetadataType, HandlerContext>,\n 'type' | 'processorId'\n> & { processorId?: string } & {\n truncateOnStart?: boolean;\n projection: ProjectionDefinition<\n EventType,\n MessageMetadataType,\n HandlerContext,\n EventPayloadType\n >;\n};\n\nexport const defaultProcessingMessageProcessingScope = <\n HandlerContext = never,\n Result = MessageHandlerResult,\n>(\n handler: (context: HandlerContext) => Result | Promise<Result>,\n partialContext: Partial<HandlerContext>,\n) => handler(partialContext as HandlerContext);\n\nexport type ProcessorCheckpoint = Brand<string, 'ProcessorCheckpoint'>;\n\nexport const bigIntProcessorCheckpoint = (value: bigint): ProcessorCheckpoint =>\n bigInt.toNormalizedString(value) as ProcessorCheckpoint;\n\nexport const parseBigIntProcessorCheckpoint = (\n value: ProcessorCheckpoint,\n): bigint => BigInt(value);\n\nexport type ReadProcessorCheckpointResult = {\n lastCheckpoint: ProcessorCheckpoint | null;\n};\n\nexport type ReadProcessorCheckpoint<\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = (\n options: { processorId: string; partition?: string },\n context: HandlerContext,\n) => Promise<ReadProcessorCheckpointResult>;\n\nexport type StoreProcessorCheckpointResult =\n | {\n success: true;\n newCheckpoint: ProcessorCheckpoint | null;\n }\n | { success: false; reason: 'IGNORED' | 'MISMATCH' | 'CURRENT_AHEAD' };\n\nexport type StoreProcessorCheckpoint<\n MessageType extends Message = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = (\n options: {\n message: RecordedMessage<MessageType, MessageMetadataType>;\n processorId: string;\n version: number | undefined;\n lastCheckpoint: ProcessorCheckpoint | null;\n partition?: string;\n },\n context: HandlerContext,\n) => Promise<StoreProcessorCheckpointResult>;\n\nexport const defaultProcessorVersion = 1;\nexport const defaultProcessorPartition = defaultTag;\n\nexport const getProcessorInstanceId = (processorId: string): string =>\n `${processorId}:${uuid()}`;\n\nexport const getProjectorId = (options: { projectionName: string }): string =>\n `emt:processor:projector:${options.projectionName}`;\n\nexport const reactor = <\n MessageType extends Message = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n MessagePayloadType extends Message = MessageType,\n>(\n options: ReactorOptions<\n MessageType,\n MessageMetadataType,\n HandlerContext,\n MessagePayloadType\n >,\n): MessageProcessor<MessageType, MessageMetadataType, HandlerContext> => {\n const {\n checkpoints,\n processorId,\n processorInstanceId: instanceId = getProcessorInstanceId(processorId),\n type = MessageProcessorType.REACTOR,\n version = defaultProcessorVersion,\n partition = defaultProcessorPartition,\n hooks = {},\n processingScope = defaultProcessingMessageProcessingScope,\n startFrom,\n canHandle,\n stopAfter,\n } = options;\n\n const eachMessage: SingleMessageHandlerWithContext<\n MessageType,\n MessageMetadataType,\n HandlerContext\n > =\n 'eachMessage' in options && options.eachMessage\n ? options.eachMessage\n : () => Promise.resolve();\n\n let isInitiated = false;\n let isActive = false;\n\n let lastCheckpoint: ProcessorCheckpoint | null = null;\n let closeSignal: (() => void) | null = null;\n\n const init = async (initOptions: Partial<HandlerContext>): Promise<void> => {\n if (isInitiated) return;\n\n if (hooks.onInit === undefined) {\n isInitiated = true;\n return;\n }\n\n return await processingScope(async (context) => {\n await hooks.onInit!(context);\n isInitiated = true;\n }, initOptions);\n };\n\n const close = async (\n closeOptions: Partial<HandlerContext>,\n ): Promise<void> => {\n // TODO: Align when active is set to false\n // if (!isActive) return;\n\n isActive = false;\n\n if (closeSignal) {\n closeSignal();\n closeSignal = null;\n }\n\n if (hooks.onClose) {\n await processingScope(hooks.onClose, closeOptions);\n }\n };\n\n return {\n // TODO: Consider whether not make it optional or add URN prefix\n id: processorId,\n instanceId,\n type,\n canHandle,\n init,\n start: async (\n startOptions: Partial<HandlerContext>,\n ): Promise<CurrentMessageProcessorPosition | undefined> => {\n if (isActive) return;\n\n await init(startOptions);\n\n isActive = true;\n\n closeSignal = onShutdown(() => close(startOptions));\n\n if (lastCheckpoint !== null)\n return {\n lastCheckpoint,\n };\n\n return await processingScope(async (context) => {\n if (hooks.onStart) {\n await hooks.onStart(context);\n }\n\n if (startFrom && startFrom !== 'CURRENT') return startFrom;\n\n if (checkpoints) {\n const readResult = await checkpoints?.read(\n {\n processorId: processorId,\n partition,\n },\n { ...startOptions, ...context },\n );\n lastCheckpoint = readResult.lastCheckpoint;\n }\n\n if (lastCheckpoint === null) return 'BEGINNING';\n\n return {\n lastCheckpoint,\n };\n }, startOptions);\n },\n close,\n get isActive() {\n return isActive;\n },\n handle: async (\n messages: RecordedMessage<MessageType, MessageMetadataType>[],\n partialContext: Partial<HandlerContext>,\n ): Promise<MessageHandlerResult> => {\n if (!isActive) return Promise.resolve();\n\n return await processingScope(async (context) => {\n let result: MessageHandlerResult = undefined;\n\n for (const message of messages) {\n if (wasMessageHandled(message, lastCheckpoint)) continue;\n\n const upcasted = upcastRecordedMessage(\n // TODO: Make it smarter\n message as unknown as RecordedMessage<\n MessagePayloadType,\n MessageMetadataType\n >,\n options.messageOptions?.schema?.versioning,\n );\n\n if (canHandle !== undefined && !canHandle.includes(upcasted.type))\n continue;\n\n const messageProcessingResult = await eachMessage(upcasted, context);\n\n if (checkpoints) {\n const storeCheckpointResult: StoreProcessorCheckpointResult =\n await checkpoints.store(\n {\n processorId,\n version,\n message: upcasted,\n lastCheckpoint,\n partition,\n },\n context,\n );\n\n if (storeCheckpointResult.success) {\n // TODO: Add correct handling of the storing checkpoint\n lastCheckpoint = storeCheckpointResult.newCheckpoint;\n }\n }\n\n if (\n messageProcessingResult &&\n messageProcessingResult.type === 'STOP'\n ) {\n isActive = false;\n result = messageProcessingResult;\n break;\n }\n\n if (stopAfter && stopAfter(upcasted)) {\n isActive = false;\n result = { type: 'STOP', reason: 'Stop condition reached' };\n break;\n }\n\n if (\n messageProcessingResult &&\n messageProcessingResult.type === 'SKIP'\n )\n continue;\n }\n\n return result;\n }, partialContext);\n },\n };\n};\n\nexport const projector = <\n EventType extends Event = Event,\n EventMetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n EventPayloadType extends Event = EventType,\n>(\n options: ProjectorOptions<\n EventType,\n EventMetaDataType,\n HandlerContext,\n EventPayloadType\n >,\n): MessageProcessor<EventType, EventMetaDataType, HandlerContext> => {\n const {\n projection,\n processorId = getProjectorId({\n projectionName: projection.name ?? 'unknown',\n }),\n ...rest\n } = options;\n\n return reactor<\n EventType,\n EventMetaDataType,\n HandlerContext,\n EventPayloadType\n >({\n ...rest,\n type: MessageProcessorType.PROJECTOR,\n canHandle: projection.canHandle,\n processorId,\n messageOptions: options.projection.eventsOptions,\n hooks: {\n onInit: options.hooks?.onInit,\n onStart:\n (options.truncateOnStart && options.projection.truncate) ||\n options.hooks?.onStart\n ? async (context: HandlerContext) => {\n if (options.truncateOnStart && options.projection.truncate)\n await options.projection.truncate(context);\n\n if (options.hooks?.onStart) await options.hooks?.onStart(context);\n }\n : undefined,\n onClose: options.hooks?.onClose,\n },\n eachMessage: async (\n event: RecordedMessage<EventType, EventMetaDataType>,\n context: HandlerContext,\n ) => projection.handle([event], context),\n });\n};\n","import { getInMemoryDatabase, type InMemoryDatabase } from '../database';\nimport { EmmettError } from '../errors';\nimport type {\n AnyEvent,\n AnyMessage,\n BatchRecordedMessageHandlerWithContext,\n MessageHandlerResult,\n ReadEventMetadataWithGlobalPosition,\n SingleRecordedMessageHandlerWithContext,\n} from '../typing';\nimport type { MessageProcessor, ProcessorCheckpoint } from './processors';\nimport {\n getCheckpoint,\n projector,\n reactor,\n type Checkpointer,\n type MessageProcessingScope,\n type ProjectorOptions,\n type ReactorOptions,\n} from './processors';\n\nexport type InMemoryProcessorHandlerContext = {\n database: InMemoryDatabase;\n};\n\nexport type InMemoryProcessor<MessageType extends AnyMessage = AnyMessage> =\n MessageProcessor<\n MessageType,\n // TODO: generalize this to support other metadata types\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n > & { database: InMemoryDatabase };\n\nexport type InMemoryProcessorEachMessageHandler<\n MessageType extends AnyMessage = AnyMessage,\n> = SingleRecordedMessageHandlerWithContext<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n>;\n\nexport type InMemoryProcessorEachBatchHandler<\n MessageType extends AnyMessage = AnyMessage,\n> = BatchRecordedMessageHandlerWithContext<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n>;\n\nexport type InMemoryProcessorConnectionOptions = {\n database?: InMemoryDatabase;\n};\n\ntype CheckpointDocument = {\n _id: string;\n lastCheckpoint: ProcessorCheckpoint | null;\n};\n\nexport type InMemoryCheckpointer<MessageType extends AnyMessage = AnyMessage> =\n Checkpointer<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n >;\n\nexport const inMemoryCheckpointer = <\n MessageType extends AnyMessage = AnyMessage,\n>(): InMemoryCheckpointer<MessageType> => {\n return {\n read: async ({ processorId }, { database }) => {\n const checkpoint = await database\n .collection<CheckpointDocument>('emt_processor_checkpoints')\n .findOne((d) => d._id === processorId);\n\n return Promise.resolve({\n lastCheckpoint: checkpoint?.lastCheckpoint ?? null,\n });\n },\n store: async (context, { database }) => {\n const { message, processorId, lastCheckpoint } = context;\n const checkpoints = database.collection<CheckpointDocument>(\n 'emt_processor_checkpoints',\n );\n\n const checkpoint = await checkpoints.findOne(\n (d) => d._id === processorId,\n );\n\n const currentPosition = checkpoint?.lastCheckpoint ?? null;\n\n const newCheckpoint: ProcessorCheckpoint | null = getCheckpoint(message);\n\n if (\n currentPosition &&\n (currentPosition === newCheckpoint ||\n currentPosition !== lastCheckpoint)\n ) {\n return {\n success: false,\n reason:\n currentPosition === newCheckpoint\n ? 'IGNORED'\n : newCheckpoint !== null && currentPosition > newCheckpoint\n ? 'CURRENT_AHEAD'\n : 'MISMATCH',\n };\n }\n\n await checkpoints.handle(processorId, (existing) => ({\n ...(existing ?? {}),\n _id: processorId,\n lastCheckpoint: newCheckpoint,\n }));\n\n return { success: true, newCheckpoint };\n },\n };\n};\n\ntype InMemoryConnectionOptions = {\n connectionOptions?: InMemoryProcessorConnectionOptions;\n};\n\nexport type InMemoryReactorOptions<\n MessageType extends AnyMessage = AnyMessage,\n> = ReactorOptions<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n> &\n InMemoryConnectionOptions;\n\nexport type InMemoryProjectorOptions<EventType extends AnyEvent = AnyEvent> =\n ProjectorOptions<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n > &\n InMemoryConnectionOptions;\n\nexport type InMemoryProcessorOptions<\n MessageType extends AnyMessage = AnyMessage,\n> =\n | InMemoryReactorOptions<MessageType>\n | InMemoryProjectorOptions<MessageType & AnyEvent>;\n\nconst inMemoryProcessingScope = (options: {\n database: InMemoryDatabase | null;\n processorId: string;\n}): MessageProcessingScope<InMemoryProcessorHandlerContext> => {\n const processorDatabase = options.database;\n\n const processingScope: MessageProcessingScope<\n InMemoryProcessorHandlerContext\n > = <Result = MessageHandlerResult>(\n handler: (\n context: InMemoryProcessorHandlerContext,\n ) => Result | Promise<Result>,\n partialContext: Partial<InMemoryProcessorHandlerContext>,\n ) => {\n const database = processorDatabase ?? partialContext?.database;\n\n if (!database)\n throw new EmmettError(\n `InMemory processor '${options.processorId}' is missing database. Ensure that you passed it through options`,\n );\n\n return handler({ ...partialContext, database });\n };\n\n return processingScope;\n};\n\nexport const inMemoryProjector = <EventType extends AnyEvent = AnyEvent>(\n options: InMemoryProjectorOptions<EventType>,\n): InMemoryProcessor<EventType> => {\n const database = options.connectionOptions?.database ?? getInMemoryDatabase();\n\n const hooks = {\n onInit: options.hooks?.onInit,\n onStart: options.hooks?.onStart,\n onClose: options.hooks?.onClose\n ? async (context: InMemoryProcessorHandlerContext) => {\n if (options.hooks?.onClose) await options.hooks?.onClose(context);\n }\n : undefined,\n };\n\n const processor = projector<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n >({\n ...options,\n hooks,\n processingScope: inMemoryProcessingScope({\n database,\n processorId:\n options.processorId ?? `projection:${options.projection.name}`,\n }),\n checkpoints: inMemoryCheckpointer<EventType>(),\n });\n\n return Object.assign(processor, { database });\n};\n\nexport const inMemoryReactor = <MessageType extends AnyMessage = AnyMessage>(\n options: InMemoryReactorOptions<MessageType>,\n): InMemoryProcessor<MessageType> => {\n const database = options.connectionOptions?.database ?? getInMemoryDatabase();\n\n const hooks = {\n onInit: options.hooks?.onInit,\n onStart: options.hooks?.onStart,\n onClose: options.hooks?.onClose,\n };\n\n const processor = reactor({\n ...options,\n hooks,\n processingScope: inMemoryProcessingScope({\n database,\n processorId: options.processorId,\n }),\n checkpoints: inMemoryCheckpointer<MessageType>(),\n });\n\n return Object.assign(processor, { database });\n};\n","import type { InMemoryDatabase } from '../../../database/inMemoryDatabase';\nimport type {\n ProjectionDefinition,\n TruncateProjection,\n} from '../../../projections';\nimport type { CanHandle, Event, ReadEvent } from '../../../typing';\nimport type {\n InMemoryProjectionHandlerContext,\n InMemoryReadEventMetadata,\n} from '../../inMemoryEventStore';\n\nexport const DATABASE_REQUIRED_ERROR_MESSAGE =\n 'Database is required in context for InMemory projections';\n\nexport type InMemoryProjectionDefinition<EventType extends Event> =\n ProjectionDefinition<\n EventType,\n InMemoryReadEventMetadata,\n InMemoryProjectionHandlerContext\n >;\n\nexport type InMemoryProjectionHandlerOptions<EventType extends Event = Event> =\n {\n projections: InMemoryProjectionDefinition<EventType>[];\n events: ReadEvent<EventType, InMemoryReadEventMetadata>[];\n database: InMemoryDatabase;\n eventStore?: InMemoryProjectionHandlerContext['eventStore'];\n };\n\n/**\n * Handles projections for the InMemoryEventStore\n * Similar to the PostgreSQL implementation, this processes events through projections\n */\nexport const handleInMemoryProjections = async <\n EventType extends Event = Event,\n>(\n options: InMemoryProjectionHandlerOptions<EventType>,\n): Promise<void> => {\n const { projections, events, database, eventStore } = options;\n\n // Get all event types from the events batch to filter projections\n const eventTypes = events.map((e) => e.type);\n\n // Filter projections that can handle these event types\n const relevantProjections = projections.filter((p) =>\n p.canHandle.some((type) => eventTypes.includes(type)),\n );\n\n // Process each projection\n for (const projection of relevantProjections) {\n await projection.handle(events, {\n eventStore,\n database,\n });\n }\n};\n\nexport type InMemoryWithNotNullDocumentEvolve<\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n> = (\n document: DocumentType,\n event: ReadEvent<EventType, InMemoryReadEventMetadata>,\n) => DocumentType | null;\n\nexport type InMemoryWithNullableDocumentEvolve<\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n> = (\n document: DocumentType | null,\n event: ReadEvent<EventType, InMemoryReadEventMetadata>,\n) => DocumentType | null;\n\nexport type InMemoryDocumentEvolve<\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n> =\n | InMemoryWithNotNullDocumentEvolve<DocumentType, EventType>\n | InMemoryWithNullableDocumentEvolve<DocumentType, EventType>;\n\nexport type InMemoryProjectionOptions<EventType extends Event> = {\n handle: (\n events: ReadEvent<EventType, InMemoryReadEventMetadata>[],\n context: InMemoryProjectionHandlerContext & { database: InMemoryDatabase },\n ) => Promise<void>;\n canHandle: CanHandle<EventType>;\n truncate?: TruncateProjection<\n InMemoryProjectionHandlerContext & { database: InMemoryDatabase }\n >;\n};\n\n/**\n * Creates an InMemory projection\n */\nexport const inMemoryProjection = <EventType extends Event>({\n truncate,\n handle,\n canHandle,\n}: InMemoryProjectionOptions<EventType>): InMemoryProjectionDefinition<EventType> => ({\n canHandle,\n handle: async (events, context) => {\n if (!context.database) {\n throw new Error(DATABASE_REQUIRED_ERROR_MESSAGE);\n }\n await handle(events, {\n ...context,\n database: context.database,\n });\n },\n truncate: truncate\n ? (context) => {\n if (!context.database) {\n throw new Error(DATABASE_REQUIRED_ERROR_MESSAGE);\n }\n return truncate({\n ...context,\n database: context.database,\n });\n }\n : undefined,\n});\n\n/**\n * Creates a multi-stream projection for InMemoryDatabase\n */\nexport type InMemoryMultiStreamProjectionOptions<\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n> = {\n canHandle: CanHandle<EventType>;\n collectionName: string;\n getDocumentId: (event: ReadEvent<EventType>) => string;\n} & (\n | {\n evolve: InMemoryWithNullableDocumentEvolve<DocumentType, EventType>;\n }\n | {\n evolve: InMemoryWithNotNullDocumentEvolve<DocumentType, EventType>;\n initialState: () => DocumentType;\n }\n);\n\n/**\n * Creates a projection that handles events across multiple streams\n */\nexport const inMemoryMultiStreamProjection = <\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n>(\n options: InMemoryMultiStreamProjectionOptions<DocumentType, EventType>,\n): InMemoryProjectionDefinition<EventType> => {\n const { collectionName, getDocumentId, canHandle } = options;\n\n return inMemoryProjection({\n handle: async (\n events: ReadEvent<EventType, InMemoryReadEventMetadata>[],\n { database },\n ) => {\n const collection = database.collection<DocumentType>(collectionName);\n\n for (const event of events) {\n await collection.handle(getDocumentId(event), (document) => {\n if ('initialState' in options) {\n return options.evolve(document ?? options.initialState(), event);\n } else {\n return options.evolve(document, event);\n }\n });\n }\n },\n canHandle,\n truncate: async ({\n database,\n }: InMemoryProjectionHandlerContext & { database: InMemoryDatabase }) => {\n // For InMemory database, we can't directly truncate a collection\n // So we'll delete all documents from the collection\n const collection = database.collection<DocumentType>(collectionName);\n const documents = await collection.find();\n\n for (const doc of documents) {\n if (doc && '_id' in doc) {\n const id = doc._id;\n await collection.deleteOne((d) => d._id === id);\n }\n }\n },\n });\n};\n\n/**\n * Creates a single-stream projection for InMemoryDatabase\n */\nexport type InMemorySingleStreamProjectionOptions<\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n> = {\n canHandle: CanHandle<EventType>;\n getDocumentId?: (event: ReadEvent<EventType>) => string;\n collectionName: string;\n} & (\n | {\n evolve: InMemoryWithNullableDocumentEvolve<DocumentType, EventType>;\n }\n | {\n evolve: InMemoryWithNotNullDocumentEvolve<DocumentType, EventType>;\n initialState: () => DocumentType;\n }\n);\n\n/**\n * Creates a projection that handles events from a single stream\n */\nexport const inMemorySingleStreamProjection = <\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n>(\n options: InMemorySingleStreamProjectionOptions<DocumentType, EventType>,\n): InMemoryProjectionDefinition<EventType> => {\n return inMemoryMultiStreamProjection<DocumentType, EventType>({\n ...options,\n getDocumentId:\n options.getDocumentId ?? ((event) => event.metadata.streamName),\n });\n};\n","import { v4 as uuid } from 'uuid';\nimport {\n handleInMemoryProjections,\n type InMemoryProjectionDefinition,\n} from '.';\nimport { bigIntProcessorCheckpoint } from '../../..';\nimport {\n getInMemoryDatabase,\n type Document,\n type InMemoryDatabase,\n} from '../../../database';\nimport { isErrorConstructor } from '../../../errors';\nimport { JSONSerializer } from '../../../serialization';\nimport {\n assertFails,\n AssertionError,\n assertTrue,\n type ThenThrows,\n} from '../../../testing';\nimport type {\n CombinedReadEventMetadata,\n Event,\n ReadEvent,\n} from '../../../typing';\nimport type {\n InMemoryEventStore,\n InMemoryReadEventMetadata,\n} from '../../inMemoryEventStore';\n\n// Define a more specific type for T that extends Document\ntype DocumentWithId = Document & { _id?: string | number };\n\nexport type InMemoryProjectionSpecEvent<\n EventType extends Event,\n EventMetaDataType extends InMemoryReadEventMetadata =\n InMemoryReadEventMetadata,\n> = EventType & {\n metadata?: Partial<EventMetaDataType>;\n};\n\nexport type InMemoryProjectionSpecWhenOptions = { numberOfTimes: number };\n\nexport type InMemoryProjectionSpec<EventType extends Event> = (\n givenEvents: InMemoryProjectionSpecEvent<EventType>[],\n) => {\n when: (\n events: InMemoryProjectionSpecEvent<EventType>[],\n options?: InMemoryProjectionSpecWhenOptions,\n ) => {\n then: (assert: InMemoryProjectionAssert, message?: string) => Promise<void>;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => Promise<void>;\n };\n};\n\nexport type InMemoryProjectionAssert = (options: {\n database: InMemoryDatabase;\n}) => Promise<void | boolean>;\n\nexport type InMemoryProjectionSpecOptions<EventType extends Event> = {\n projection: InMemoryProjectionDefinition<EventType>;\n};\n\nexport const InMemoryProjectionSpec = {\n for: <EventType extends Event>(\n options: InMemoryProjectionSpecOptions<EventType>,\n ): InMemoryProjectionSpec<EventType> => {\n const { projection } = options;\n\n return (givenEvents: InMemoryProjectionSpecEvent<EventType>[]) => {\n return {\n when: (\n events: InMemoryProjectionSpecEvent<EventType>[],\n options?: InMemoryProjectionSpecWhenOptions,\n ) => {\n const allEvents: ReadEvent<EventType, InMemoryReadEventMetadata>[] =\n [];\n\n const run = async (database: InMemoryDatabase) => {\n let globalPosition = 0n;\n const numberOfTimes = options?.numberOfTimes ?? 1;\n\n for (const event of [\n ...givenEvents,\n ...Array.from({ length: numberOfTimes }).flatMap(() => events),\n ]) {\n const metadata: InMemoryReadEventMetadata = {\n checkpoint: bigIntProcessorCheckpoint(++globalPosition),\n globalPosition,\n streamPosition: globalPosition,\n streamName: event.metadata?.streamName ?? `test-${uuid()}`,\n messageId: uuid(),\n };\n\n allEvents.push({\n ...event,\n kind: 'Event',\n metadata: {\n ...metadata,\n ...('metadata' in event ? (event.metadata ?? {}) : {}),\n } as CombinedReadEventMetadata<\n EventType,\n InMemoryReadEventMetadata\n >,\n });\n }\n\n // Create a minimal mock EventStore implementation\n const mockEventStore = {\n database,\n aggregateStream: async () => {\n return Promise.resolve({\n state: {},\n currentStreamVersion: 0n,\n streamExists: false,\n });\n },\n readStream: async () => {\n return Promise.resolve({\n events: [],\n currentStreamVersion: 0n,\n streamExists: false,\n });\n },\n appendToStream: async () => {\n return Promise.resolve({\n nextExpectedStreamVersion: 0n,\n createdNewStream: false,\n });\n },\n streamExists: async () => {\n return Promise.resolve(false);\n },\n } as InMemoryEventStore;\n\n await handleInMemoryProjections({\n events: allEvents,\n projections: [projection],\n database,\n eventStore: mockEventStore,\n });\n };\n\n return {\n then: async (\n assertFn: InMemoryProjectionAssert,\n message?: string,\n ): Promise<void> => {\n const database = getInMemoryDatabase();\n await run(database);\n\n const succeeded = await assertFn({ database });\n\n if (succeeded !== undefined && succeeded === false) {\n assertFails(\n message ??\n \"Projection specification didn't match the criteria\",\n );\n }\n },\n thenThrows: async <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): Promise<void> => {\n const database = getInMemoryDatabase();\n try {\n await run(database);\n throw new AssertionError('Handler did not fail as expected');\n } catch (error) {\n if (error instanceof AssertionError) throw error;\n\n if (args.length === 0) return;\n\n if (!isErrorConstructor(args[0])) {\n assertTrue(\n args[0](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n return;\n }\n\n assertTrue(\n error instanceof args[0],\n `Caught error is not an instance of the expected type: ${error?.toString()}`,\n );\n\n if (args[1]) {\n assertTrue(\n args[1](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n }\n }\n },\n };\n },\n };\n };\n },\n};\n\n// Helper functions for creating events in stream\nexport const eventInStream = <\n EventType extends Event = Event,\n EventMetaDataType extends InMemoryReadEventMetadata =\n InMemoryReadEventMetadata,\n>(\n streamName: string,\n event: InMemoryProjectionSpecEvent<EventType, EventMetaDataType>,\n): InMemoryProjectionSpecEvent<EventType, EventMetaDataType> => {\n return {\n ...event,\n metadata: {\n ...(event.metadata ?? {}),\n streamName: event.metadata?.streamName ?? streamName,\n } as Partial<EventMetaDataType>,\n };\n};\n\nexport const eventsInStream = <\n EventType extends Event = Event,\n EventMetaDataType extends InMemoryReadEventMetadata =\n InMemoryReadEventMetadata,\n>(\n streamName: string,\n events: InMemoryProjectionSpecEvent<EventType, EventMetaDataType>[],\n): InMemoryProjectionSpecEvent<EventType, EventMetaDataType>[] => {\n return events.map((e) => eventInStream(streamName, e));\n};\n\nexport const newEventsInStream = eventsInStream;\n\n// Assertion helpers for checking documents\nexport function documentExists<T extends DocumentWithId>(\n expected: Partial<T>,\n options: { inCollection: string; withId: string | number },\n): InMemoryProjectionAssert {\n return async ({ database }) => {\n const collection = database.collection<T>(options.inCollection);\n\n const document = await collection.findOne((doc) => {\n // Handle both string IDs and numeric IDs in a type-safe way\n const docId = '_id' in doc ? doc._id : undefined;\n return docId === options.withId;\n });\n\n if (!document) {\n assertFails(\n `Document with ID ${options.withId} does not exist in collection ${options.inCollection}`,\n );\n return Promise.resolve(false);\n }\n\n // Check that all expected properties exist with expected values\n for (const [key, value] of Object.entries(expected)) {\n const propKey = key as keyof typeof document;\n if (\n !(key in document) ||\n JSONSerializer.serialize(document[propKey]) !==\n JSONSerializer.serialize(value)\n ) {\n assertFails(`Property ${key} doesn't match the expected value`);\n return Promise.resolve(false);\n }\n }\n\n return Promise.resolve(true);\n };\n}\n\n// Helper for checking document contents\nexport const expectInMemoryDocuments = {\n fromCollection: <T extends DocumentWithId>(collectionName: string) => ({\n withId: (id: string | number) => ({\n toBeEqual: (expected: Partial<T>): InMemoryProjectionAssert =>\n documentExists<T>(expected, {\n inCollection: collectionName,\n withId: id,\n }),\n }),\n }),\n};\n","import { JSONSerializer } from '../serialization';\nimport type { DefaultRecord } from '../typing';\nimport { deepEquals } from '../utils';\n\nexport class AssertionError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n\nexport const isSubset = (superObj: unknown, subObj: unknown): boolean => {\n const sup = superObj as DefaultRecord;\n const sub = subObj as DefaultRecord;\n\n assertOk(sup);\n assertOk(sub);\n\n return Object.keys(sub).every((ele: string) => {\n if (sub[ele] !== null && typeof sub[ele] == 'object') {\n return isSubset(sup[ele], sub[ele]);\n }\n return sub[ele] === sup[ele];\n });\n};\n\nexport const assertFails = (message?: string) => {\n throw new AssertionError(message ?? 'That should not ever happened, right?');\n};\n\nexport const assertThrowsAsync = async <TError extends Error>(\n fun: () => Promise<unknown>,\n errorCheck?: (error: Error) => boolean,\n): Promise<TError> => {\n try {\n await fun();\n } catch (error) {\n const typedError = error as TError;\n if (typedError instanceof AssertionError || !errorCheck) {\n assertFalse(\n typedError instanceof AssertionError,\n \"Function didn't throw expected error\",\n );\n return typedError;\n }\n\n assertTrue(\n errorCheck(typedError),\n `Error doesn't match the expected condition: ${JSONSerializer.serialize(error)}`,\n );\n\n return typedError;\n }\n throw new AssertionError(\"Function didn't throw expected error\");\n};\n\nexport const assertThrows = <TError extends Error>(\n fun: () => void,\n errorCheck?: (error: Error) => boolean,\n): TError => {\n try {\n fun();\n } catch (error) {\n const typedError = error as TError;\n\n if (errorCheck) {\n assertTrue(\n errorCheck(typedError),\n `Error doesn't match the expected condition: ${JSONSerializer.serialize(error)}`,\n );\n } else if (typedError instanceof AssertionError) {\n assertFalse(\n typedError instanceof AssertionError,\n \"Function didn't throw expected error\",\n );\n }\n\n return typedError;\n }\n throw new AssertionError(\"Function didn't throw expected error\");\n};\n\nexport const assertDoesNotThrow = <TError extends Error>(\n fun: () => void,\n errorCheck?: (error: Error) => boolean,\n): TError | null => {\n try {\n fun();\n return null;\n } catch (error) {\n const typedError = error as TError;\n\n if (errorCheck) {\n assertFalse(\n errorCheck(typedError),\n `Error matching the expected condition was thrown!: ${JSONSerializer.serialize(error)}`,\n );\n } else {\n assertFails(\n `Function threw an error: ${JSONSerializer.serialize(error)}`,\n );\n }\n\n return typedError;\n }\n};\n\nexport const assertRejects = async <T, TError extends Error = Error>(\n promise: Promise<T>,\n errorCheck?: ((error: TError) => boolean) | TError,\n) => {\n try {\n await promise;\n throw new AssertionError(\"Function didn't throw expected error\");\n } catch (error) {\n if (!errorCheck) return;\n\n if (errorCheck instanceof Error) assertDeepEqual(error, errorCheck);\n else assertTrue(errorCheck(error as TError));\n }\n};\n\nexport const assertMatches = (\n actual: unknown,\n expected: unknown,\n message?: string,\n) => {\n if (!isSubset(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONSerializer.serialize(expected)}\\nis not subset of\\n${JSONSerializer.serialize(actual)}`,\n );\n};\n\nexport const assertDeepEqual = <T = unknown>(\n actual: T,\n expected: T,\n message?: string,\n) => {\n if (!deepEquals(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONSerializer.serialize(expected)}\\nis not equal to\\n${JSONSerializer.serialize(actual)}`,\n );\n};\n\nexport const assertNotDeepEqual = <T = unknown>(\n actual: T,\n expected: T,\n message?: string,\n) => {\n if (deepEquals(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONSerializer.serialize(expected)}\\nis equals to\\n${JSONSerializer.serialize(actual)}`,\n );\n};\n\nexport const assertThat = <T>(item: T) => {\n return {\n isEqualTo: (other: T) => assertTrue(deepEquals(item, other)),\n };\n};\n\nexport const assertDefined = (\n value: unknown,\n message?: string | Error,\n): asserts value => {\n assertOk(value, message instanceof Error ? message.message : message);\n};\n\nexport function assertFalse(\n condition: boolean,\n message?: string,\n): asserts condition is false {\n if (condition !== false)\n throw new AssertionError(message ?? `Condition is true`);\n}\n\nexport function assertTrue(\n condition: boolean,\n message?: string,\n): asserts condition is true {\n if (condition !== true)\n throw new AssertionError(message ?? `Condition is false`);\n}\n\n// TODO: replace with assertDefined\nexport function assertOk<T>(\n obj: T | null | undefined,\n message?: string,\n): asserts obj is T {\n if (!obj) throw new AssertionError(message ?? `Condition is not truthy`);\n}\n\nexport function assertEqual<T>(\n expected: T | null | undefined,\n actual: T | null | undefined,\n message?: string,\n): void {\n if (expected !== actual)\n throw new AssertionError(\n `${message ?? 'Objects are not equal'}:\\nExpected: ${JSONSerializer.serialize(expected)}\\nActual: ${JSONSerializer.serialize(actual)}`,\n );\n}\n\nexport function assertNotEqual<T>(\n obj: T | null | undefined,\n other: T | null | undefined,\n message?: string,\n): void {\n if (obj === other)\n throw new AssertionError(\n message ?? `Objects are equal: ${JSONSerializer.serialize(obj)}`,\n );\n}\n\nexport function assertIsNotNull<T extends object | bigint>(\n result: T | null,\n): asserts result is T {\n assertNotEqual(result, null);\n assertOk(result);\n}\n\nexport function assertIsNull<T extends object>(\n result: T | null,\n): asserts result is null {\n assertEqual(result, null);\n}\n\ntype Call = {\n arguments: unknown[];\n result: unknown;\n target: unknown;\n this: unknown;\n};\n\nexport type ArgumentMatcher = (arg: unknown) => boolean;\n\nexport const argValue =\n <T>(value: T): ArgumentMatcher =>\n (arg) =>\n deepEquals(arg, value);\n\nexport const argMatches =\n <T>(matches: (arg: T) => boolean): ArgumentMatcher =>\n (arg) =>\n matches(arg as T);\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport type MockedFunction = Function & { mock?: { calls: Call[] } };\n\nexport function verifyThat(fn: MockedFunction) {\n return {\n calledTimes: (times: number) => {\n assertEqual(fn.mock?.calls?.length, times);\n },\n notCalled: () => {\n assertEqual(fn?.mock?.calls?.length, 0);\n },\n called: () => {\n assertTrue(\n fn.mock?.calls.length !== undefined && fn.mock.calls.length > 0,\n );\n },\n calledWith: (...args: unknown[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls.some((call) => deepEquals(call.arguments, args)),\n );\n },\n calledOnceWith: (...args: unknown[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length === 1 &&\n fn.mock.calls.some((call) => deepEquals(call.arguments, args)),\n );\n },\n calledWithArgumentMatching: (...matches: ArgumentMatcher[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined && fn.mock.calls.length >= 1,\n );\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls.some(\n (call) =>\n call.arguments &&\n call.arguments.length >= matches.length &&\n matches.every((match, index) => match(call.arguments[index])),\n ),\n );\n },\n notCalledWithArgumentMatching: (...matches: ArgumentMatcher[]) => {\n assertFalse(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls[0]!.arguments &&\n fn.mock.calls[0]!.arguments.length >= matches.length &&\n matches.every((match, index) =>\n match(fn.mock!.calls[0]!.arguments[index]),\n ),\n );\n },\n };\n}\n\nexport const assertThatArray = <T>(array: T[]) => {\n return {\n isEmpty: () =>\n assertEqual(\n array.length,\n 0,\n `Array is not empty ${JSONSerializer.serialize(array)}`,\n ),\n isNotEmpty: () => assertNotEqual(array.length, 0, `Array is empty`),\n hasSize: (length: number) => assertEqual(array.length, length),\n containsElements: (other: T[]) => {\n assertTrue(other.every((ts) => array.some((o) => deepEquals(ts, o))));\n },\n containsElementsMatching: (other: T[]) => {\n assertTrue(other.every((ts) => array.some((o) => isSubset(o, ts))));\n },\n containsOnlyElementsMatching: (other: T[]) => {\n assertEqual(array.length, other.length, `Arrays lengths don't match`);\n assertTrue(other.every((ts) => array.some((o) => isSubset(o, ts))));\n },\n containsExactlyInAnyOrder: (other: T[]) => {\n assertEqual(array.length, other.length);\n assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyInAnyOrderElementsOf: (other: T[]) => {\n assertEqual(array.length, other.length);\n assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyElementsOf: (other: T[]) => {\n assertEqual(array.length, other.length);\n for (let i = 0; i < array.length; i++) {\n assertTrue(deepEquals(array[i], other[i]));\n }\n },\n containsExactly: (elem: T) => {\n assertEqual(array.length, 1);\n assertTrue(deepEquals(array[0], elem));\n },\n contains: (elem: T) => {\n assertTrue(array.some((a) => deepEquals(a, elem)));\n },\n containsOnlyOnceElementsOf: (other: T[]) => {\n assertTrue(\n other\n .map((o) => array.filter((a) => deepEquals(a, o)).length)\n .filter((a) => a === 1).length === other.length,\n );\n },\n containsAnyOf: (other: T[]) => {\n assertTrue(array.some((a) => other.some((o) => deepEquals(a, o))));\n },\n allMatch: (matches: (item: T) => boolean) => {\n assertTrue(array.every(matches));\n },\n anyMatches: (matches: (item: T) => boolean) => {\n assertTrue(array.some(matches));\n },\n allMatchAsync: async (\n matches: (item: T) => Promise<boolean>,\n ): Promise<void> => {\n for (const item of array) {\n assertTrue(await matches(item));\n }\n },\n };\n};\n","import { isErrorConstructor, type ErrorConstructor } from '../errors';\nimport { AssertionError, assertThatArray, assertTrue } from './assertions';\n\ntype ErrorCheck<ErrorType> = (error: ErrorType) => boolean;\n\nexport type ThenThrows<ErrorType extends Error> =\n | (() => void)\n | ((errorConstructor: ErrorConstructor<ErrorType>) => void)\n | ((errorCheck: ErrorCheck<ErrorType>) => void)\n | ((\n errorConstructor: ErrorConstructor<ErrorType>,\n errorCheck?: ErrorCheck<ErrorType>,\n ) => void);\n\nexport type DeciderSpecification<Command, Event> = (\n givenEvents: Event | Event[],\n) => {\n when: (command: Command) => {\n then: (expectedEvents: Event | Event[]) => void;\n thenNothingHappened: () => void;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => void;\n };\n};\nexport type AsyncDeciderSpecification<Command, Event> = (\n givenEvents: Event | Event[],\n) => {\n when: (command: Command) => {\n then: (expectedEvents: Event | Event[]) => Promise<void>;\n thenNothingHappened: () => Promise<void>;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => Promise<void>;\n };\n};\n\nexport const DeciderSpecification = {\n for: deciderSpecificationFor,\n};\n\nfunction deciderSpecificationFor<Command, Event, State>(decider: {\n decide: (command: Command, state: State) => Event | Event[];\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n}): DeciderSpecification<Command, Event>;\nfunction deciderSpecificationFor<Command, Event, State>(decider: {\n decide: (command: Command, state: State) => Promise<Event | Event[]>;\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n}): AsyncDeciderSpecification<Command, Event>;\nfunction deciderSpecificationFor<Command, Event, State>(decider: {\n decide: (\n command: Command,\n state: State,\n ) => Event | Event[] | Promise<Event | Event[]>;\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n}):\n | DeciderSpecification<Command, Event>\n | AsyncDeciderSpecification<Command, Event> {\n {\n return (givenEvents: Event | Event[]) => {\n return {\n when: (command: Command) => {\n const handle = () => {\n const existingEvents = Array.isArray(givenEvents)\n ? givenEvents\n : [givenEvents];\n\n const currentState = existingEvents.reduce<State>(\n decider.evolve,\n decider.initialState(),\n );\n\n return decider.decide(command, currentState);\n };\n\n return {\n then: (expectedEvents: Event | Event[]): void | Promise<void> => {\n const resultEvents = handle();\n\n if (resultEvents instanceof Promise) {\n return resultEvents.then((events) => {\n thenHandler(events, expectedEvents);\n });\n }\n\n thenHandler(resultEvents, expectedEvents);\n },\n thenNothingHappened: (): void | Promise<void> => {\n const resultEvents = handle();\n\n if (resultEvents instanceof Promise) {\n return resultEvents.then((events) => {\n thenNothingHappensHandler(events);\n });\n }\n\n thenNothingHappensHandler(resultEvents);\n },\n thenThrows: <ErrorType extends Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): void | Promise<void> => {\n try {\n const result = handle();\n if (result instanceof Promise) {\n return result\n .then(() => {\n throw new AssertionError(\n 'Handler did not fail as expected',\n );\n })\n .catch((error) => {\n thenThrowsErrorHandler(error, args);\n });\n }\n throw new AssertionError('Handler did not fail as expected');\n } catch (error) {\n thenThrowsErrorHandler(error, args);\n }\n },\n };\n },\n };\n };\n }\n}\n\nfunction thenHandler<Event>(\n events: Event | Event[],\n expectedEvents: Event | Event[],\n): void {\n const resultEventsArray = Array.isArray(events) ? events : [events];\n\n const expectedEventsArray = Array.isArray(expectedEvents)\n ? expectedEvents\n : [expectedEvents];\n\n assertThatArray(resultEventsArray).containsOnlyElementsMatching(\n expectedEventsArray,\n );\n}\n\nfunction thenNothingHappensHandler<Event>(events: Event | Event[]): void {\n const resultEventsArray = Array.isArray(events) ? events : [events];\n assertThatArray(resultEventsArray).isEmpty();\n}\n\nfunction thenThrowsErrorHandler<ErrorType extends Error>(\n error: unknown,\n args: Parameters<ThenThrows<ErrorType>>,\n): void {\n if (error instanceof AssertionError) throw error;\n\n if (args.length === 0) return;\n\n if (!isErrorConstructor(args[0])) {\n assertTrue(\n args[0](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n return;\n }\n\n assertTrue(\n error instanceof args[0],\n `Caught error is not an instance of the expected type: ${error?.toString()}`,\n );\n\n if (args[1]) {\n assertTrue(\n args[1](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n }\n}\n","import { isErrorConstructor } from '../errors';\nimport type { AnyCommand } from '../typing/command';\nimport type { AnyEvent } from '../typing/event';\nimport type { Workflow, WorkflowEvent } from '../workflows/workflow';\nimport { AssertionError, assertThatArray, assertTrue } from './assertions';\nimport type { ThenThrows } from './deciderSpecification';\n\nexport type WorkflowSpecification<\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n> = (\n givenEvents: WorkflowEvent<Input | Output> | WorkflowEvent<Input | Output>[],\n) => {\n when: (input: Input) => {\n then: (expectedOutput: Output | Output[]) => void;\n thenNothingHappened: () => void;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => void;\n };\n};\n\nexport const WorkflowSpecification = {\n for: workflowSpecificationFor,\n};\n\nfunction workflowSpecificationFor<\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n>(\n workflow: Workflow<Input, State, Output>,\n): WorkflowSpecification<Input, Output> {\n return (\n givenEvents:\n | WorkflowEvent<Input | Output>\n | WorkflowEvent<Input | Output>[],\n ) => {\n return {\n when: (input: Input) => {\n const handle = () => {\n const existingEvents = Array.isArray(givenEvents)\n ? givenEvents\n : [givenEvents];\n\n const currentState = existingEvents.reduce<State>(\n workflow.evolve,\n workflow.initialState(),\n );\n\n return workflow.decide(input, currentState);\n };\n\n return {\n then: (expectedOutput: Output | Output[]): void => {\n const result = handle();\n thenHandler(result, expectedOutput);\n },\n thenNothingHappened: (): void => {\n const result = handle();\n thenNothingHappensHandler(result);\n },\n thenThrows: <ErrorType extends Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): void => {\n try {\n handle();\n throw new AssertionError('Handler did not fail as expected');\n } catch (error) {\n thenThrowsErrorHandler(error, args);\n }\n },\n };\n },\n };\n };\n}\n\nfunction thenHandler<Output>(\n result: Output | Output[],\n expectedOutput: Output | Output[],\n): void {\n const resultArray = Array.isArray(result) ? result : [result];\n const expectedArray = Array.isArray(expectedOutput)\n ? expectedOutput\n : [expectedOutput];\n\n assertThatArray(resultArray).containsOnlyElementsMatching(expectedArray);\n}\n\nfunction thenNothingHappensHandler<Output>(result: Output | Output[]): void {\n const resultArray = Array.isArray(result) ? result : [result];\n assertThatArray(resultArray).isEmpty();\n}\n\nfunction thenThrowsErrorHandler<ErrorType extends Error>(\n error: unknown,\n args: Parameters<ThenThrows<ErrorType>>,\n): void {\n if (error instanceof AssertionError) throw error;\n\n if (args.length === 0) return;\n\n if (!isErrorConstructor(args[0])) {\n assertTrue(\n args[0](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n return;\n }\n\n assertTrue(\n error instanceof args[0],\n `Caught error is not an instance of the expected type: ${error?.toString()}`,\n );\n\n if (args[1]) {\n assertTrue(\n args[1](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n }\n}\n","import type {\n AggregateStreamOptions,\n AggregateStreamResult,\n AppendToStreamOptions,\n AppendToStreamResult,\n EventStore,\n EventStoreReadEventMetadata,\n ReadStreamOptions,\n ReadStreamResult,\n} from '../eventStore';\nimport type { Event, EventMetaDataOf } from '../typing';\n\nexport type TestEventStream<EventType extends Event = Event> = [\n string,\n EventType[],\n];\n\nexport type EventStoreWrapper<Store extends EventStore> = Store & {\n appendedEvents: Map<string, TestEventStream>;\n setup<EventType extends Event>(\n streamName: string,\n events: EventType[],\n ): Promise<AppendToStreamResult>;\n};\n\nexport const WrapEventStore = <Store extends EventStore>(\n eventStore: Store,\n): EventStoreWrapper<Store> => {\n const appendedEvents = new Map<string, TestEventStream>();\n\n const wrapped = {\n ...eventStore,\n aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State>> {\n return eventStore.aggregateStream(streamName, options);\n },\n\n async readStream<EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions<EventType>,\n ): Promise<\n ReadStreamResult<\n EventType,\n EventStoreReadEventMetadata<Store> & EventMetaDataOf<EventType>\n >\n > {\n return (await eventStore.readStream(\n streamName,\n options,\n )) as ReadStreamResult<\n EventType,\n EventStoreReadEventMetadata<Store> & EventMetaDataOf<EventType>\n >;\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType>,\n ): Promise<AppendToStreamResult> => {\n const result = await eventStore.appendToStream(\n streamName,\n events,\n options,\n );\n\n const currentStream = appendedEvents.get(streamName) ?? [streamName, []];\n\n appendedEvents.set(streamName, [\n streamName,\n [...currentStream[1], ...events],\n ]);\n\n return result;\n },\n\n appendedEvents,\n\n setup: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n ): Promise<AppendToStreamResult> => {\n return eventStore.appendToStream(streamName, events);\n },\n\n // streamEvents: (): ReadableStream<\n // // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\n // ReadEvent<Event, ReadEventMetadataType> | GlobalSubscriptionEvent\n // > => {\n // return eventStore.streamEvents();\n // },\n };\n\n return wrapped as EventStoreWrapper<Store>;\n};\n","import type {\n AnyMessage,\n AnyRecordedMessageMetadata,\n RecordedMessage,\n} from '../../typing';\n\nexport type MessageDowncast<\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n> =\n | ((\n message: RecordedMessage<MessageType, RecordedMessageMetadataType>,\n ) => RecordedMessage<MessagePayloadType, RecordedMessageMetadataType>)\n | ((message: MessageType) => MessagePayloadType);\n\nexport const downcastRecordedMessage = <\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n>(\n recordedMessage:\n | RecordedMessage<MessageType, RecordedMessageMetadataType>\n | MessageType,\n options?: {\n downcast?: MessageDowncast<\n MessageType,\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n },\n): RecordedMessage<MessagePayloadType, RecordedMessageMetadataType> => {\n if (!options?.downcast)\n return recordedMessage as unknown as RecordedMessage<\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n\n const downcasted = options.downcast(\n recordedMessage as RecordedMessage<\n MessageType,\n RecordedMessageMetadataType\n >,\n );\n\n return {\n ...recordedMessage,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n data: downcasted.data,\n ...('metadata' in recordedMessage || 'metadata' in downcasted\n ? {\n metadata: {\n ...('metadata' in recordedMessage\n ? (recordedMessage.metadata as object)\n : {}),\n ...('metadata' in downcasted\n ? (downcasted.metadata as object)\n : {}),\n },\n }\n : {}),\n } as unknown as RecordedMessage<\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n};\n\nexport const downcastRecordedMessages = <\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n>(\n recordedMessages:\n | RecordedMessage<MessageType, RecordedMessageMetadataType>[]\n | MessageType[],\n options?: {\n downcast?: MessageDowncast<\n MessageType,\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n },\n): RecordedMessage<MessagePayloadType, RecordedMessageMetadataType>[] => {\n if (!options?.downcast)\n return recordedMessages as unknown as RecordedMessage<\n MessagePayloadType,\n RecordedMessageMetadataType\n >[];\n\n return recordedMessages.map((recordedMessage) =>\n downcastRecordedMessage(recordedMessage, options),\n );\n};\n","import type {\n AnyMessage,\n AnyRecordedMessageMetadata,\n RecordedMessage,\n} from '../../typing';\n\nexport type MessageUpcast<\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n> =\n | ((message: MessagePayloadType) => MessageType)\n | ((\n message: RecordedMessage<MessagePayloadType, RecordedMessageMetadataType>,\n ) => RecordedMessage<MessageType, RecordedMessageMetadataType>);\n\nexport const upcastRecordedMessage = <\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n>(\n recordedMessage:\n | RecordedMessage<MessagePayloadType, RecordedMessageMetadataType>\n | MessagePayloadType,\n options?: {\n upcast?: MessageUpcast<\n MessageType,\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n },\n): RecordedMessage<MessageType, RecordedMessageMetadataType> => {\n if (!options?.upcast)\n return recordedMessage as unknown as RecordedMessage<\n MessageType,\n RecordedMessageMetadataType\n >;\n\n const upcasted = options.upcast(\n recordedMessage as RecordedMessage<\n MessagePayloadType,\n RecordedMessageMetadataType\n >,\n );\n\n return {\n ...recordedMessage,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n data: upcasted.data,\n ...('metadata' in recordedMessage || 'metadata' in upcasted\n ? {\n metadata: {\n ...('metadata' in recordedMessage\n ? (recordedMessage.metadata as object)\n : {}),\n ...('metadata' in upcasted ? (upcasted.metadata as object) : {}),\n },\n }\n : {}),\n } as unknown as RecordedMessage<MessageType, RecordedMessageMetadataType>;\n};\n\nexport const upcastRecordedMessages = <\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n>(\n recordedMessages:\n | RecordedMessage<MessagePayloadType, RecordedMessageMetadataType>[]\n | MessagePayloadType[],\n options?: {\n upcast?: MessageUpcast<\n MessageType,\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n },\n): RecordedMessage<MessageType, RecordedMessageMetadataType>[] => {\n if (!options?.upcast)\n return recordedMessages as unknown as RecordedMessage<\n MessageType,\n RecordedMessageMetadataType\n >[];\n\n return recordedMessages.map((recordedMessage) =>\n upcastRecordedMessage(recordedMessage, options),\n );\n};\n","import {\n canCreateEventStoreSession,\n isExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n nulloSessionFactory,\n STREAM_DOES_NOT_EXIST,\n type AppendStreamResultOfEventStore,\n type AppendToStreamOptions,\n type EventStore,\n type EventStoreSession,\n type ExpectedStreamVersion,\n type ReadStreamOptions,\n} from '../eventStore';\nimport type { JSONSerializationOptions } from '../serialization';\nimport type { Event } from '../typing';\nimport { asyncRetry, NoRetries, type AsyncRetryOptions } from '../utils';\n\nexport const CommandHandlerStreamVersionConflictRetryOptions: AsyncRetryOptions =\n {\n retries: 3,\n minTimeout: 100,\n factor: 1.5,\n shouldRetryError: isExpectedVersionConflictError,\n };\n\nexport type CommandHandlerRetryOptions =\n | AsyncRetryOptions\n | { onVersionConflict: true | number | AsyncRetryOptions };\n\nconst fromCommandHandlerRetryOptions = (\n retryOptions: CommandHandlerRetryOptions | undefined,\n): AsyncRetryOptions => {\n if (retryOptions === undefined) return NoRetries;\n\n if ('onVersionConflict' in retryOptions) {\n if (typeof retryOptions.onVersionConflict === 'boolean')\n return CommandHandlerStreamVersionConflictRetryOptions;\n else if (typeof retryOptions.onVersionConflict === 'number')\n return {\n ...CommandHandlerStreamVersionConflictRetryOptions,\n retries: retryOptions.onVersionConflict,\n };\n else return retryOptions.onVersionConflict;\n }\n\n return retryOptions;\n};\n\n// #region command-handler\nexport type CommandHandlerResult<\n State,\n StreamEvent extends Event,\n Store extends EventStore,\n> = AppendStreamResultOfEventStore<Store> & {\n newState: State;\n newEvents: StreamEvent[];\n};\n\nexport type CommandHandlerOptions<\n State,\n StreamEvent extends Event,\n StoredEvent extends Event = StreamEvent,\n> = {\n evolve: (state: State, event: StreamEvent) => State;\n initialState: () => State;\n mapToStreamId?: (id: string) => string;\n retry?: CommandHandlerRetryOptions;\n schema?: {\n versioning?: {\n upcast?: (event: StoredEvent) => StreamEvent;\n downcast?: (event: StreamEvent) => StoredEvent;\n };\n };\n} & JSONSerializationOptions;\n\nexport type HandleOptions<Store extends EventStore> = Parameters<\n Store['appendToStream']\n>[2] &\n (\n | {\n expectedStreamVersion?: ExpectedStreamVersion;\n }\n | {\n retry?: CommandHandlerRetryOptions;\n }\n );\n\ntype CommandHandlerFunction<State, StreamEvent extends Event> = (\n state: State,\n) => StreamEvent | StreamEvent[] | Promise<StreamEvent | StreamEvent[]>;\n\nexport const CommandHandler =\n <\n State,\n StreamEvent extends Event,\n EventPayloadType extends Event = StreamEvent,\n >(\n options: CommandHandlerOptions<State, StreamEvent, EventPayloadType>,\n ) =>\n async <Store extends EventStore>(\n store: Store,\n id: string,\n handle:\n | CommandHandlerFunction<State, StreamEvent>\n | CommandHandlerFunction<State, StreamEvent>[],\n handleOptions?: HandleOptions<Store>,\n ): Promise<CommandHandlerResult<State, StreamEvent, Store>> =>\n asyncRetry(\n async () => {\n const result = await withSession<\n Store,\n CommandHandlerResult<State, StreamEvent, Store>\n >(store, async ({ eventStore }) => {\n const { evolve, initialState } = options;\n const mapToStreamId = options.mapToStreamId ?? ((id) => id);\n\n const streamName = mapToStreamId(id);\n\n // 1. Aggregate the stream\n const aggregationResult = await eventStore.aggregateStream<\n State,\n StreamEvent,\n EventPayloadType\n >(streamName, {\n evolve,\n initialState,\n read: {\n schema: options.schema,\n ...(handleOptions as ReadStreamOptions<\n StreamEvent,\n EventPayloadType\n >),\n serialization: options.serialization,\n // expected stream version is passed to fail fast\n // if stream is in the wrong state\n expectedStreamVersion:\n handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n },\n });\n\n // 2. Use the aggregate state\n\n const {\n currentStreamVersion,\n streamExists: _streamExists,\n ...restOfAggregationResult\n } = aggregationResult;\n\n let state = aggregationResult.state;\n\n const handlers = Array.isArray(handle) ? handle : [handle];\n let eventsToAppend: StreamEvent[] = [];\n\n // 3. Run business logic\n for (const handler of handlers) {\n const result = await handler(state);\n\n const newEvents = Array.isArray(result) ? result : [result];\n\n if (newEvents.length > 0) {\n state = newEvents.reduce(evolve, state);\n }\n\n eventsToAppend = [...eventsToAppend, ...newEvents];\n }\n\n //const newEvents = Array.isArray(result) ? result : [result];\n\n if (eventsToAppend.length === 0) {\n return {\n ...restOfAggregationResult,\n newEvents: [],\n newState: state,\n\n nextExpectedStreamVersion: currentStreamVersion,\n createdNewStream: false,\n } as unknown as CommandHandlerResult<State, StreamEvent, Store>;\n }\n\n // Either use:\n // - provided expected stream version,\n // - current stream version got from stream aggregation,\n // - or expect stream not to exists otherwise.\n\n const expectedStreamVersion: ExpectedStreamVersion =\n handleOptions?.expectedStreamVersion ??\n (aggregationResult.streamExists\n ? currentStreamVersion\n : STREAM_DOES_NOT_EXIST);\n\n // 4. Append result to the stream\n const appendResult = await eventStore.appendToStream(\n streamName,\n eventsToAppend,\n {\n ...(handleOptions as AppendToStreamOptions<\n StreamEvent,\n EventPayloadType\n >),\n expectedStreamVersion,\n },\n );\n\n // 5. Return result with updated state\n return {\n ...appendResult,\n newEvents: eventsToAppend,\n newState: state,\n } as unknown as CommandHandlerResult<State, StreamEvent, Store>;\n });\n\n return result;\n },\n fromCommandHandlerRetryOptions(\n handleOptions && 'retry' in handleOptions\n ? handleOptions.retry\n : options.retry,\n ),\n );\n// #endregion command-handler\n\nconst withSession = <EventStoreType extends EventStore, T = unknown>(\n eventStore: EventStoreType,\n callback: (session: EventStoreSession<EventStoreType>) => Promise<T>,\n) => {\n const sessionFactory = canCreateEventStoreSession<EventStoreType>(eventStore)\n ? eventStore\n : nulloSessionFactory<EventStoreType>(eventStore);\n\n return sessionFactory.withSession(callback);\n};\n","import type { EventStore } from '../eventStore';\nimport type { Command, Event } from '../typing';\nimport type { Decider } from '../typing/decider';\nimport {\n CommandHandler,\n type CommandHandlerOptions,\n type HandleOptions,\n} from './handleCommand';\n\n// #region command-handler\n\nexport type DeciderCommandHandlerOptions<\n State,\n CommandType extends Command,\n StreamEvent extends Event,\n> = CommandHandlerOptions<State, StreamEvent> &\n Decider<State, CommandType, StreamEvent>;\n\nexport const DeciderCommandHandler =\n <State, CommandType extends Command, StreamEvent extends Event>(\n options: DeciderCommandHandlerOptions<State, CommandType, StreamEvent>,\n ) =>\n async <Store extends EventStore>(\n eventStore: Store,\n id: string,\n commands: CommandType | CommandType[],\n handleOptions?: HandleOptions<Store>,\n ) => {\n const { decide, ...rest } = options;\n\n const deciders = (Array.isArray(commands) ? commands : [commands]).map(\n (command) => (state: State) => decide(command, state),\n );\n\n return CommandHandler<State, StreamEvent>(rest)(\n eventStore,\n id,\n deciders,\n handleOptions,\n );\n };\n// #endregion command-handler\n","import { EmmettError } from '../errors';\nimport type {\n AnyCommand,\n AnyMessage,\n Command,\n CommandTypeOf,\n Event,\n EventTypeOf,\n Message,\n SingleMessageHandler,\n SingleRawMessageHandlerWithoutContext,\n} from '../typing';\n\nexport interface CommandSender {\n send<CommandType extends Command = Command>(\n command: CommandType,\n ): Promise<void>;\n}\n\nexport interface EventsPublisher {\n publish<EventType extends Event = Event>(event: EventType): Promise<void>;\n}\n\nexport type ScheduleOptions = { afterInMs: number } | { at: Date };\n\nexport interface MessageScheduler<CommandOrEvent extends Command | Event> {\n schedule<MessageType extends CommandOrEvent>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void;\n}\n\nexport interface CommandBus extends CommandSender, MessageScheduler<Command> {}\n\nexport interface EventBus extends EventsPublisher, MessageScheduler<Event> {}\n\nexport interface MessageBus extends CommandBus, EventBus {\n schedule<MessageType extends Command | Event>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void;\n}\n\nexport interface CommandProcessor {\n handle<CommandType extends Command>(\n commandHandler: SingleMessageHandler<CommandType>,\n ...commandTypes: CommandTypeOf<CommandType>[]\n ): void;\n}\nexport interface EventSubscription {\n subscribe<EventType extends Event>(\n eventHandler: SingleMessageHandler<EventType>,\n ...eventTypes: EventTypeOf<EventType>[]\n ): void;\n}\n\nexport type ScheduledMessage = {\n message: Message;\n options?: ScheduleOptions;\n};\n\nexport interface ScheduledMessageProcessor {\n dequeue(): ScheduledMessage[];\n}\n\nexport type MessageSubscription = EventSubscription | CommandProcessor;\n\nexport const getInMemoryMessageBus = (): MessageBus &\n EventSubscription &\n CommandProcessor &\n ScheduledMessageProcessor => {\n const allHandlers = new Map<\n string,\n SingleRawMessageHandlerWithoutContext<AnyMessage>[]\n >();\n let pendingMessages: ScheduledMessage[] = [];\n\n return {\n send: async <CommandType extends Command = AnyCommand>(\n command: CommandType,\n ): Promise<void> => {\n const handlers = allHandlers.get(command.type);\n\n if (handlers === undefined || handlers.length === 0)\n throw new EmmettError(\n `No handler registered for command ${command.type}!`,\n );\n\n const commandHandler = handlers[0]!;\n\n await commandHandler(command);\n },\n\n publish: async <EventType extends Event = Event>(\n event: EventType,\n ): Promise<void> => {\n const handlers = allHandlers.get(event.type) ?? [];\n\n for (const handler of handlers) {\n const eventHandler = handler;\n\n await eventHandler(event);\n }\n },\n\n schedule: <MessageType extends Message>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void => {\n pendingMessages = [...pendingMessages, { message, options: when }];\n },\n\n handle: <CommandType extends Command>(\n commandHandler: SingleMessageHandler<CommandType>,\n ...commandTypes: CommandTypeOf<CommandType>[]\n ): void => {\n const alreadyRegistered = [...allHandlers.keys()].filter((registered) =>\n commandTypes.includes(registered),\n );\n\n if (alreadyRegistered.length > 0)\n throw new EmmettError(\n `Cannot register handler for commands ${alreadyRegistered.join(', ')} as they're already registered!`,\n );\n for (const commandType of commandTypes) {\n allHandlers.set(commandType, [\n commandHandler as SingleRawMessageHandlerWithoutContext<AnyMessage>,\n ]);\n }\n },\n\n subscribe<EventType extends Event>(\n eventHandler: SingleMessageHandler<EventType>,\n ...eventTypes: EventTypeOf<EventType>[]\n ): void {\n for (const eventType of eventTypes) {\n if (!allHandlers.has(eventType)) allHandlers.set(eventType, []);\n\n allHandlers.set(eventType, [\n ...(allHandlers.get(eventType) ?? []),\n eventHandler as SingleRawMessageHandlerWithoutContext<AnyMessage>,\n ]);\n }\n },\n\n dequeue: (): ScheduledMessage[] => {\n const pending = pendingMessages;\n pendingMessages = [];\n return pending;\n },\n };\n};\n","import { EmmettError } from '../errors';\nimport type { EventStoreReadSchemaOptions } from '../eventStore';\nimport {\n JSONSerializer,\n type JSONSerializationOptions,\n} from '../serialization';\nimport type {\n AnyEvent,\n AnyReadEventMetadata,\n BatchRecordedMessageHandlerWithContext,\n CanHandle,\n DefaultRecord,\n Event,\n} from '../typing';\nimport { arrayUtils } from '../utils';\n\nexport type ProjectionHandlingType = 'inline' | 'async';\n\nexport type ProjectionHandler<\n EventType extends Event = AnyEvent,\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = BatchRecordedMessageHandlerWithContext<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n>;\n\nexport type TruncateProjection<\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = (context: ProjectionHandlerContext) => Promise<void>;\n\nexport type ProjectionInitOptions<\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n version: number;\n status?: 'active' | 'inactive';\n registrationType: ProjectionHandlingType;\n context: ProjectionHandlerContext;\n};\n\nexport type ProjectionDefinition<\n EventType extends Event = AnyEvent,\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n EventPayloadType extends Event = EventType,\n> = {\n name?: string;\n version?: number;\n kind?: string;\n canHandle: CanHandle<EventType>;\n handle: ProjectionHandler<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n >;\n truncate?: TruncateProjection<ProjectionHandlerContext>;\n init?: (\n options: ProjectionInitOptions<ProjectionHandlerContext>,\n ) => void | Promise<void>;\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\n} & JSONSerializationOptions;\n\nexport type ProjectionRegistration<\n HandlingType extends ProjectionHandlingType,\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n type: HandlingType;\n projection: ProjectionDefinition<\n AnyEvent,\n ReadEventMetadataType,\n ProjectionHandlerContext,\n AnyEvent\n >;\n};\n\nexport const filterProjections = <\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n>(\n type: ProjectionHandlingType,\n projections: ProjectionRegistration<\n ProjectionHandlingType,\n ReadEventMetadataType,\n ProjectionHandlerContext\n >[],\n) => {\n const inlineProjections = projections\n .filter((projection) => projection.type === type)\n .map(({ projection }) => projection);\n\n const duplicateRegistrations = arrayUtils.getDuplicates(\n inlineProjections,\n (proj) => proj.name,\n );\n\n if (duplicateRegistrations.length > 0) {\n throw new EmmettError(`You cannot register multiple projections with the same name (or without the name).\n Ensure that:\n ${JSONSerializer.serialize(duplicateRegistrations)}\n have different names`);\n }\n\n return inlineProjections;\n};\n\nexport const projection = <\n EventType extends Event = Event,\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n EventPayloadType extends Event = EventType,\n>(\n definition: ProjectionDefinition<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext,\n EventPayloadType\n >,\n): ProjectionDefinition<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext,\n EventPayloadType\n> => definition;\n\nexport const inlineProjections = <\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n>(\n definitions: ProjectionDefinition<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n ReadEventMetadataType,\n ProjectionHandlerContext\n >[],\n): ProjectionRegistration<\n 'inline',\n ReadEventMetadataType,\n ProjectionHandlerContext\n>[] =>\n definitions.map((definition) => ({\n type: 'inline',\n projection: definition,\n }));\n\nexport const asyncProjections = <\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n>(\n definitions: ProjectionDefinition<\n AnyEvent,\n ReadEventMetadataType,\n ProjectionHandlerContext\n >[],\n): ProjectionRegistration<\n 'inline',\n ReadEventMetadataType,\n ProjectionHandlerContext\n>[] =>\n definitions.map((definition) => ({\n type: 'inline',\n projection: definition,\n }));\n\nexport const projections = {\n inline: inlineProjections,\n async: asyncProjections,\n};\n","import { v7 as uuid } from 'uuid';\nimport {\n canCreateEventStoreSession,\n isExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n nulloSessionFactory,\n STREAM_DOES_NOT_EXIST,\n type AppendStreamResultOfEventStore,\n type AppendToStreamOptions,\n type EventStore,\n type EventStoreSession,\n type ExpectedStreamVersion,\n type ReadStreamOptions,\n} from '../eventStore';\nimport type {\n AnyCommand,\n AnyEvent,\n AnyReadEventMetadata,\n Event,\n RecordedMessage,\n} from '../typing';\nimport { asyncRetry, NoRetries, type AsyncRetryOptions } from '../utils';\nimport type {\n WorkflowEvent,\n WorkflowInputMessageMetadata,\n WorkflowMessageAction,\n} from './workflow';\nimport type { WorkflowOptions } from './workflowProcessor';\n\nexport const WorkflowHandlerStreamVersionConflictRetryOptions: AsyncRetryOptions =\n {\n retries: 3,\n minTimeout: 100,\n factor: 1.5,\n shouldRetryError: isExpectedVersionConflictError,\n };\n\nexport type WorkflowHandlerRetryOptions =\n | AsyncRetryOptions\n | { onVersionConflict: true | number | AsyncRetryOptions };\n\nconst fromWorkflowHandlerRetryOptions = (\n retryOptions: WorkflowHandlerRetryOptions | undefined,\n): AsyncRetryOptions => {\n if (retryOptions === undefined) return NoRetries;\n\n if ('onVersionConflict' in retryOptions) {\n if (typeof retryOptions.onVersionConflict === 'boolean')\n return WorkflowHandlerStreamVersionConflictRetryOptions;\n else if (typeof retryOptions.onVersionConflict === 'number')\n return {\n ...WorkflowHandlerStreamVersionConflictRetryOptions,\n retries: retryOptions.onVersionConflict,\n };\n else return retryOptions.onVersionConflict;\n }\n\n return retryOptions;\n};\n\n// #region workflow-handler\nexport type WorkflowHandlerResult<\n Output extends AnyEvent | AnyCommand,\n Store extends EventStore,\n> = AppendStreamResultOfEventStore<Store> & {\n newMessages: Output[];\n};\n\nexport type WorkflowHandleOptions<Store extends EventStore> = Parameters<\n Store['appendToStream']\n>[2] & {\n expectedStreamVersion?: ExpectedStreamVersion;\n retry?: WorkflowHandlerRetryOptions;\n};\n\ntype WorkflowInternalState<State> = {\n userState: State;\n processedInputIds: Set<string>;\n};\n\nconst emptyHandlerResult = <\n Output extends AnyEvent | AnyCommand,\n Store extends EventStore,\n>(\n nextExpectedStreamVersion: bigint = 0n,\n): WorkflowHandlerResult<Output, Store> =>\n ({\n newMessages: [] as Output[],\n createdNewStream: false,\n nextExpectedStreamVersion,\n }) as unknown as WorkflowHandlerResult<Output, Store>;\n\nconst createInputMetadata = (\n originalMessageId: string,\n action: Extract<WorkflowMessageAction, 'InitiatedBy' | 'Received'>,\n): WorkflowInputMessageMetadata => ({\n originalMessageId,\n input: true,\n action,\n});\n\nconst tagOutputMessage = <Output extends AnyEvent | AnyCommand>(\n msg: Output,\n action: Extract<WorkflowMessageAction, 'Sent' | 'Published' | 'Scheduled'>,\n): Output => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const existingMetadata =\n 'metadata' in msg && msg.metadata ? msg.metadata : {};\n return {\n ...msg,\n metadata: {\n ...existingMetadata,\n action,\n },\n } as Output;\n};\n\nconst createWrappedInitialState = <State>(initialState: () => State) => {\n return (): WorkflowInternalState<State> => ({\n userState: initialState(),\n processedInputIds: new Set(),\n });\n};\n\nconst createWrappedEvolve = <\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n State,\n>(\n evolve: (state: State, event: WorkflowEvent<Input | Output>) => State,\n workflowName: string,\n separateInputInboxFromProcessing: boolean,\n) => {\n return (\n state: WorkflowInternalState<State>,\n event: WorkflowEvent<Input | Output>,\n ): WorkflowInternalState<State> => {\n const metadata = (event as Record<string, unknown>).metadata as\n | Record<string, unknown>\n | undefined;\n\n // Track processed inputs for idempotency\n let processedInputIds = state.processedInputIds;\n if (\n metadata?.input === true &&\n typeof metadata?.originalMessageId === 'string'\n ) {\n processedInputIds = new Set(state.processedInputIds);\n processedInputIds.add(metadata.originalMessageId);\n }\n\n // In separated inbox mode, don't apply inputs to state - they're just sitting in inbox\n // Only outputs (from processing) should update state\n if (separateInputInboxFromProcessing && metadata?.input === true) {\n return {\n userState: state.userState,\n processedInputIds,\n };\n }\n\n // Strip workflow prefix from input event types\n const eventType = event.type as string;\n const eventForEvolve = eventType.startsWith(`${workflowName}:`)\n ? ({\n ...event,\n type: eventType.replace(`${workflowName}:`, ''),\n } as WorkflowEvent<Input | Output>)\n : event;\n\n return {\n userState: evolve(state.userState, eventForEvolve),\n processedInputIds,\n };\n };\n};\n\nexport const workflowStreamName = ({\n workflowName,\n workflowId,\n}: {\n workflowName: string;\n workflowId: string;\n}) => `emt:workflow:${workflowName}:${workflowId}`;\n\nexport const WorkflowHandler =\n <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n >(\n options: WorkflowOptions<\n Input,\n State,\n Output,\n MessageMetadataType,\n StoredMessage\n > & {\n retry?: WorkflowHandlerRetryOptions;\n },\n ) =>\n async <Store extends EventStore>(\n store: Store,\n message: Input | RecordedMessage<Input, MessageMetadataType>,\n handleOptions?: WorkflowHandleOptions<Store>,\n ): Promise<WorkflowHandlerResult<Output, Store>> =>\n asyncRetry(\n async () => {\n const result = await withSession<\n Store,\n WorkflowHandlerResult<Output, Store>\n >(store, async ({ eventStore }) => {\n const {\n workflow: { evolve, initialState, decide, name: workflowName },\n getWorkflowId,\n } = options;\n\n const inputMessageId =\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n ('metadata' in message && message.metadata?.messageId\n ? // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n (message.metadata.messageId as string | undefined)\n : undefined) ?? uuid();\n\n const messageWithMetadata: RecordedMessage<\n Input,\n MessageMetadataType\n > = {\n ...message,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n metadata: {\n messageId: inputMessageId,\n ...(message as RecordedMessage<Input, MessageMetadataType>)\n .metadata,\n },\n } as RecordedMessage<Input, MessageMetadataType>;\n\n const workflowId = getWorkflowId(messageWithMetadata);\n\n if (!workflowId) {\n return emptyHandlerResult<Output, Store>();\n }\n\n const streamName = options.mapWorkflowId\n ? options.mapWorkflowId(workflowId)\n : workflowStreamName({ workflowName, workflowId });\n\n const messageType = messageWithMetadata.type as string;\n const hasWorkflowPrefix = messageType.startsWith(`${workflowName}:`);\n\n // Separated inbox mode: store-only path (no prefix = external input)\n if (options.separateInputInboxFromProcessing && !hasWorkflowPrefix) {\n const inputMetadata = createInputMetadata(\n inputMessageId,\n 'InitiatedBy',\n );\n\n const inputToStore = {\n type: `${workflowName}:${messageWithMetadata.type}`,\n data: messageWithMetadata.data,\n kind: messageWithMetadata.kind,\n metadata: inputMetadata,\n } as StoredMessage;\n\n const appendResult = await eventStore.appendToStream(\n streamName,\n [inputToStore] as unknown as Event[],\n {\n ...(handleOptions as AppendToStreamOptions<\n Event,\n StoredMessage & Event\n >),\n expectedStreamVersion:\n handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n },\n );\n\n return {\n ...appendResult,\n newMessages: [] as Output[],\n } as unknown as WorkflowHandlerResult<Output, Store>;\n }\n\n // Wrap the evolve and initialState for idempotency tracking\n const wrappedInitialState = createWrappedInitialState(initialState);\n const wrappedEvolve = createWrappedEvolve(\n evolve,\n workflowName,\n options.separateInputInboxFromProcessing ?? false,\n ) as (\n state: WorkflowInternalState<State>,\n event: WorkflowEvent<Input | Output>,\n ) => WorkflowInternalState<State>;\n\n // 1. Aggregate the stream\n const aggregationResult = await eventStore.aggregateStream<\n WorkflowInternalState<State>,\n WorkflowEvent<Input | Output>,\n StoredMessage & Event\n >(streamName, {\n evolve: wrappedEvolve,\n initialState: wrappedInitialState,\n read: {\n ...(handleOptions as ReadStreamOptions<\n WorkflowEvent<Input | Output>,\n StoredMessage & Event\n >),\n // expected stream version is passed to fail fast\n // if stream is in the wrong state\n\n expectedStreamVersion:\n handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n },\n });\n\n // 2. Use the aggregate state\n\n const { currentStreamVersion } = aggregationResult;\n\n const { userState: state, processedInputIds } =\n aggregationResult.state;\n\n // Idempotency: skip if this input was already processed\n\n if (processedInputIds.has(inputMessageId)) {\n return emptyHandlerResult<Output, Store>(currentStreamVersion);\n }\n\n // 3. Run business logic\n // Strip workflow prefix from message type if present (for separated inbox processing)\n const messageForDecide = hasWorkflowPrefix\n ? ({\n ...messageWithMetadata,\n type: messageType.replace(`${workflowName}:`, ''),\n } as Input)\n : (messageWithMetadata as Input);\n\n const result = decide(messageForDecide, state);\n\n const inputMetadata = createInputMetadata(\n inputMessageId,\n aggregationResult.streamExists ? 'Received' : 'InitiatedBy',\n );\n\n const inputToStore = {\n type: `${workflowName}:${messageWithMetadata.type}`,\n data: messageWithMetadata.data,\n kind: messageWithMetadata.kind,\n metadata: inputMetadata,\n } as StoredMessage;\n\n const outputMessages = (\n Array.isArray(result) ? result : [result]\n ).filter((msg): msg is Output => msg !== undefined && msg !== null);\n\n const outputCommandTypes = options.outputs?.commands ?? [];\n const taggedOutputMessages = outputMessages.map((msg) => {\n const action: WorkflowMessageAction = outputCommandTypes.includes(\n msg.type as string,\n )\n ? 'Sent'\n : 'Published';\n return tagOutputMessage(msg, action);\n });\n\n const messagesToAppend =\n options.separateInputInboxFromProcessing && hasWorkflowPrefix\n ? [...taggedOutputMessages] // input already in stream\n : [inputToStore, ...taggedOutputMessages]; // normal: store input + outputs\n\n // If there are no messages to append, return early with current state\n if (messagesToAppend.length === 0) {\n return emptyHandlerResult<Output, Store>(currentStreamVersion);\n }\n\n // Either use:\n // - provided expected stream version,\n // - current stream version got from stream aggregation,\n // - or expect stream not to exists otherwise.\n\n const expectedStreamVersion: ExpectedStreamVersion =\n handleOptions?.expectedStreamVersion ??\n (aggregationResult.streamExists\n ? currentStreamVersion\n : STREAM_DOES_NOT_EXIST);\n\n // 4. Append result to the stream\n const appendResult = await eventStore.appendToStream(\n streamName,\n // TODO: Fix this cast\n messagesToAppend as unknown as Event[],\n {\n ...(handleOptions as AppendToStreamOptions<\n Event,\n StoredMessage & Event\n >),\n expectedStreamVersion,\n },\n );\n\n // 5. Return result with output messages only\n return {\n ...appendResult,\n newMessages: outputMessages,\n } as unknown as WorkflowHandlerResult<Output, Store>;\n });\n\n return result;\n },\n fromWorkflowHandlerRetryOptions(\n handleOptions && 'retry' in handleOptions\n ? handleOptions.retry\n : options.retry,\n ),\n );\n// #endregion stream-handler\n\nconst withSession = <EventStoreType extends EventStore, T = unknown>(\n eventStore: EventStoreType,\n callback: (session: EventStoreSession<EventStoreType>) => Promise<T>,\n) => {\n const sessionFactory = canCreateEventStoreSession<EventStoreType>(eventStore)\n ? eventStore\n : nulloSessionFactory<EventStoreType>(eventStore);\n\n return sessionFactory.withSession(callback);\n};\n","import type { EmmettError } from '../errors';\nimport type { AnyCommand } from '../typing/command';\nimport type { AnyEvent } from '../typing/event';\n\n/// Inspired by https://blog.bittacklr.be/the-workflow-pattern.html\n\nexport type Workflow<\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n Name extends string = string,\n> = {\n name: Name;\n decide: (command: Input, state: State) => WorkflowOutput<Output>;\n evolve: (currentState: State, event: WorkflowEvent<Input | Output>) => State;\n initialState: () => State;\n};\n\nexport type WorkflowEvent<Output extends AnyEvent | AnyCommand> = Extract<\n Output,\n { kind?: 'Event' }\n>;\n\nexport type WorkflowCommand<Output extends AnyEvent | AnyCommand> = Extract<\n Output,\n { kind?: 'Command' }\n>;\n\nexport type WorkflowMessageAction =\n | 'InitiatedBy'\n | 'Received'\n | 'Sent'\n | 'Published'\n | 'Scheduled';\n\nexport type WorkflowInputMessageMetadata = Readonly<{\n originalMessageId: string | undefined;\n input: true;\n action?: Extract<WorkflowMessageAction, 'InitiatedBy' | 'Received'>;\n}>;\n\nexport type WorkflowOutputMessageMetadata = Readonly<{\n action?: Extract<WorkflowMessageAction, 'Sent' | 'Published' | 'Scheduled'>;\n}>;\n\nexport type WorkflowOutput<Output extends AnyEvent | AnyCommand | EmmettError> =\n | Output\n | Output[];\n\nexport const Workflow = <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n>(\n workflow: Workflow<Input, State, Output>,\n): Workflow<Input, State, Output> => {\n return workflow;\n};\n","import { EmmettError } from '../errors';\nimport type { EventStore } from '../eventStore';\nimport type { MessageProcessor } from '../processors';\nimport {\n MessageProcessorType,\n reactor,\n type BaseMessageProcessorOptions,\n} from '../processors';\nimport type {\n AnyCommand,\n AnyEvent,\n AnyReadEventMetadata,\n AnyRecordedMessageMetadata,\n CanHandle,\n Event,\n MessageTypeOf,\n RecordedMessage,\n} from '../typing';\nimport {\n WorkflowHandler,\n workflowStreamName,\n type WorkflowHandlerRetryOptions,\n} from './handleWorkflow';\nimport type { Workflow, WorkflowCommand, WorkflowEvent } from './workflow';\n\nexport type WorkflowOptions<\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n> = {\n workflow: Workflow<Input, State, Output>;\n getWorkflowId: (\n input: Input | RecordedMessage<Input, MessageMetadataType>,\n ) => string | null;\n mapWorkflowId?: (workflowId: string) => string;\n separateInputInboxFromProcessing?: boolean;\n inputs: {\n commands: CanHandle<WorkflowCommand<Input>>;\n events: CanHandle<WorkflowEvent<Input>>;\n };\n outputs: {\n commands: MessageTypeOf<WorkflowCommand<Output>>[];\n events: MessageTypeOf<WorkflowEvent<Output>>[];\n };\n schema?: {\n versioning?: {\n upcast?: (event: StoredMessage) => Input;\n downcast?: (event: Output) => StoredMessage;\n };\n };\n};\n\nexport type WorkflowProcessorContext = {\n connection: {\n messageStore: EventStore;\n };\n};\n\nexport type WorkflowOutputHandler<\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n MessageMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n> = (\n messages:\n | RecordedMessage<Output, MessageMetaDataType>\n | RecordedMessage<Output, MessageMetaDataType>[],\n context: HandlerContext,\n) =>\n | Promise<Input | Input[] | EmmettError | []>\n | Input\n | Input[]\n | EmmettError\n | [];\n\nexport type WorkflowOutputHandlerOptions<\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n HandledOutput extends Output = Output,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n> = {\n canHandle: CanHandle<HandledOutput>;\n handle: WorkflowOutputHandler<\n Input,\n HandledOutput,\n MessageMetadataType,\n HandlerContext\n >;\n};\n\nexport const workflowOutputHandler = <\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n HandledOutput extends Output = Output,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n>(\n handler: WorkflowOutputHandlerOptions<\n Input,\n Output,\n HandledOutput,\n MessageMetadataType,\n HandlerContext\n >,\n): WorkflowOutputHandlerOptions<\n Input,\n Output,\n HandledOutput,\n MessageMetadataType,\n HandlerContext\n> => handler;\n\nexport type WorkflowProcessorOptions<\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n HandledOutput extends Output = Output,\n> = Omit<\n BaseMessageProcessorOptions<\n Input | Output,\n MessageMetadataType,\n HandlerContext\n >,\n 'type' | 'canHandle' | 'processorId'\n> & { processorId?: string } & WorkflowOptions<\n Input,\n State,\n Output,\n MessageMetadataType,\n StoredMessage\n > & {\n retry?: WorkflowHandlerRetryOptions;\n outputHandler?: WorkflowOutputHandlerOptions<\n Input,\n Output,\n HandledOutput,\n MessageMetadataType,\n HandlerContext\n >;\n };\n\nexport const getWorkflowId = (options: { workflowName: string }): string =>\n `emt:processor:workflow:${options.workflowName}`;\n\nexport const workflowProcessor = <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MetaDataType extends AnyRecordedMessageMetadata = AnyRecordedMessageMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n HandledOutput extends Output = Output,\n>(\n options: WorkflowProcessorOptions<\n Input,\n State,\n Output,\n MetaDataType,\n HandlerContext,\n StoredMessage,\n HandledOutput\n >,\n): MessageProcessor<Input, MetaDataType, HandlerContext> => {\n const { workflow, ...rest } = options;\n\n const inputs = [...options.inputs.commands, ...options.inputs.events];\n let canHandle = inputs;\n\n if (options.separateInputInboxFromProcessing)\n canHandle = [\n ...canHandle,\n ...options.inputs.commands.map((t) => `${workflow.name}:${t}`),\n ...options.inputs.events.map((t) => `${workflow.name}:${t}`),\n ];\n\n if (options.outputHandler)\n canHandle = [...canHandle, ...options.outputHandler.canHandle];\n\n const handle = WorkflowHandler(options);\n\n return reactor<Input | Output, MetaDataType, HandlerContext>({\n ...rest,\n processorId:\n options.processorId ?? getWorkflowId({ workflowName: workflow.name }),\n canHandle,\n type: MessageProcessorType.PROJECTOR,\n eachMessage: async (\n message: RecordedMessage<Input | Output, MetaDataType>,\n context: HandlerContext,\n ) => {\n const messageType = message.type as string;\n const metadata = message.metadata as Record<string, unknown> | undefined;\n const isInput = metadata?.input === true;\n\n if (isInput || inputs.includes(messageType)) {\n const result = await handle(\n context.connection.messageStore,\n message as RecordedMessage<Input, MetaDataType>,\n context,\n );\n\n // Check stopAfter on output messages\n if (options.stopAfter && result.newMessages.length > 0) {\n for (const outputMessage of result.newMessages) {\n if (\n options.stopAfter(\n outputMessage as RecordedMessage<Output, MetaDataType>,\n )\n ) {\n return { type: 'STOP', reason: 'Stop condition reached' };\n }\n }\n }\n\n return;\n }\n\n if (options.outputHandler?.canHandle.includes(messageType) === true) {\n const handledOutputMessages = await options.outputHandler.handle(\n message as RecordedMessage<HandledOutput, MetaDataType>,\n context,\n );\n\n if (handledOutputMessages instanceof EmmettError) {\n return {\n type: 'STOP',\n reason: 'Routing error',\n error: handledOutputMessages,\n };\n }\n\n const messagesToAppend = Array.isArray(handledOutputMessages)\n ? handledOutputMessages\n : handledOutputMessages\n ? [handledOutputMessages]\n : [];\n\n if (messagesToAppend.length === 0) {\n return;\n }\n\n const workflowId = options.getWorkflowId(\n message as RecordedMessage<Input, MetaDataType>,\n );\n\n if (!workflowId) return;\n\n const streamName = options.mapWorkflowId\n ? options.mapWorkflowId(workflowId)\n : workflowStreamName({\n workflowName: workflow.name,\n workflowId,\n });\n\n await context.connection.messageStore.appendToStream(\n streamName,\n messagesToAppend as unknown as Event[],\n );\n\n return;\n }\n\n return;\n },\n });\n};\n","import type { MessageProcessor } from '@event-driven-io/emmett';\nimport {\n EmmettError,\n inMemoryProjector,\n inMemoryReactor,\n type AnyEvent,\n type AnyMessage,\n type AnyRecordedMessageMetadata,\n type AsyncRetryOptions,\n type BatchRecordedMessageHandlerWithoutContext,\n type DefaultRecord,\n type InMemoryProcessor,\n type InMemoryProjectorOptions,\n type InMemoryReactorOptions,\n type Message,\n type MessageConsumer,\n type MessageConsumerOptions,\n} from '@event-driven-io/emmett';\nimport {\n EventStoreDBClient,\n type SubscribeToAllOptions,\n type SubscribeToStreamOptions,\n} from '@eventstore/db-client';\nimport { v7 as uuid } from 'uuid';\nimport type { EventStoreDBReadEventMetadata } from '../eventstoreDBEventStore';\nimport {\n DefaultEventStoreDBEventStoreProcessorBatchSize,\n eventStoreDBSubscription,\n zipEventStoreDBEventStoreMessageBatchPullerStartFrom,\n type EventStoreDBSubscription,\n} from './subscriptions';\n\nexport type EventStoreDBEventStoreConsumerConfig<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ConsumerMessageType extends Message = any,\n> = MessageConsumerOptions<ConsumerMessageType> & {\n from?: EventStoreDBEventStoreConsumerType;\n pulling?: {\n batchSize?: number;\n };\n resilience?: {\n resubscribeOptions?: AsyncRetryOptions;\n };\n};\n\nexport type EventStoreDBEventStoreConsumerOptions<\n ConsumerEventType extends Message = Message,\n> = EventStoreDBEventStoreConsumerConfig<ConsumerEventType> &\n (\n | {\n connectionString: string;\n client?: never;\n }\n | { client: EventStoreDBClient; connectionString?: never }\n );\n\nexport type $all = '$all';\nexport const $all = '$all';\n\nexport type EventStoreDBEventStoreConsumerType =\n | {\n stream: $all;\n options?: Exclude<SubscribeToAllOptions, 'fromPosition'>;\n }\n | {\n stream: string;\n options?: Exclude<SubscribeToStreamOptions, 'fromRevision'>;\n };\n\nexport type EventStoreDBEventStoreConsumer<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ConsumerMessageType extends AnyMessage = any,\n> = MessageConsumer<ConsumerMessageType> &\n Readonly<{\n reactor: <MessageType extends AnyMessage = ConsumerMessageType>(\n options: InMemoryReactorOptions<MessageType>,\n ) => InMemoryProcessor<MessageType>;\n }> &\n (AnyEvent extends ConsumerMessageType\n ? Readonly<{\n projector: <\n EventType extends AnyEvent = ConsumerMessageType & AnyEvent,\n >(\n options: InMemoryProjectorOptions<EventType>,\n ) => InMemoryProcessor<EventType>;\n }>\n : object);\n\nexport const eventStoreDBEventStoreConsumer = <\n ConsumerMessageType extends Message = AnyMessage,\n>(\n options: EventStoreDBEventStoreConsumerOptions<ConsumerMessageType>,\n): EventStoreDBEventStoreConsumer<ConsumerMessageType> => {\n let isRunning = false;\n const { pulling } = options;\n const processors = options.processors ?? [];\n\n let start: Promise<void>;\n\n let currentSubscription: EventStoreDBSubscription | undefined;\n\n const client =\n 'client' in options && options.client\n ? options.client\n : EventStoreDBClient.connectionString(options.connectionString);\n\n const eachBatch: BatchRecordedMessageHandlerWithoutContext<\n ConsumerMessageType,\n EventStoreDBReadEventMetadata\n > = async (messagesBatch) => {\n const activeProcessors = processors.filter((s) => s.isActive);\n\n if (activeProcessors.length === 0)\n return {\n type: 'STOP',\n reason: 'No active processors',\n };\n\n const result = await Promise.allSettled(\n activeProcessors.map(async (s) => {\n // TODO: Add here filtering to only pass messages that can be handled by\n return await s.handle(messagesBatch, { client });\n }),\n );\n\n const error = result.find((r) => r.status === 'rejected')?.reason as\n | Error\n | undefined;\n\n return result.some(\n (r) => r.status === 'fulfilled' && r.value?.type !== 'STOP',\n )\n ? undefined\n : {\n type: 'STOP',\n error: error ? EmmettError.mapFrom(error) : undefined,\n };\n };\n\n const subscription = (currentSubscription = eventStoreDBSubscription({\n client,\n from: options.from,\n eachBatch,\n batchSize:\n pulling?.batchSize ?? DefaultEventStoreDBEventStoreProcessorBatchSize,\n resilience: options.resilience,\n }));\n\n const stop = async () => {\n if (!isRunning) return;\n isRunning = false;\n if (currentSubscription) {\n await currentSubscription.stop();\n currentSubscription = undefined;\n }\n await start;\n };\n\n return {\n consumerId: options.consumerId ?? uuid(),\n get isRunning() {\n return isRunning;\n },\n processors,\n reactor: <MessageType extends AnyMessage = ConsumerMessageType>(\n options: InMemoryReactorOptions<MessageType>,\n ): InMemoryProcessor<MessageType> => {\n const processor = inMemoryReactor(options);\n\n processors.push(\n // TODO: change that\n processor as unknown as MessageProcessor<\n ConsumerMessageType,\n AnyRecordedMessageMetadata,\n DefaultRecord\n >,\n );\n\n return processor;\n },\n projector: <EventType extends AnyEvent = ConsumerMessageType & AnyEvent>(\n options: InMemoryProjectorOptions<EventType>,\n ): InMemoryProcessor<EventType> => {\n const processor = inMemoryProjector(options);\n\n processors.push(\n // TODO: change that\n processor as unknown as MessageProcessor<\n ConsumerMessageType,\n AnyRecordedMessageMetadata,\n DefaultRecord\n >,\n );\n\n return processor;\n },\n start: () => {\n if (isRunning) return start;\n\n start = (async () => {\n if (processors.length === 0)\n return Promise.reject(\n new EmmettError(\n 'Cannot start consumer without at least a single processor',\n ),\n );\n\n isRunning = true;\n\n const startFrom = zipEventStoreDBEventStoreMessageBatchPullerStartFrom(\n await Promise.all(processors.map((o) => o.start(client))),\n );\n\n return subscription.start({ startFrom });\n })();\n\n return start;\n },\n stop,\n close: stop,\n };\n};\n","import {\n asyncRetry,\n getCheckpoint,\n isString,\n JSONSerializer,\n parseBigIntProcessorCheckpoint,\n type AnyMessage,\n type AsyncRetryOptions,\n type BatchRecordedMessageHandlerWithoutContext,\n type EmmettError,\n type Message,\n type MessageHandlerResult,\n type ProcessorCheckpoint,\n} from '@event-driven-io/emmett';\nimport type { EventStoreDBClient } from '@eventstore/db-client';\nimport {\n END,\n excludeSystemEvents,\n START,\n type ResolvedEvent,\n type StreamSubscription,\n} from '@eventstore/db-client';\nimport { pipeline, Transform, Writable, type WritableOptions } from 'stream';\nimport {\n mapFromESDBEvent,\n type EventStoreDBReadEventMetadata,\n} from '../../eventstoreDBEventStore';\nimport {\n $all,\n type EventStoreDBEventStoreConsumerType,\n} from '../eventStoreDBEventStoreConsumer';\n\nexport const DefaultEventStoreDBEventStoreProcessorBatchSize = 100;\nexport const DefaultEventStoreDBEventStoreProcessorPullingFrequencyInMs = 50;\n\nexport type EventStoreDBEventStoreMessagesBatchHandlerResult = void | {\n type: 'STOP';\n reason?: string;\n error?: EmmettError;\n};\n\nexport type EventStoreDBSubscriptionOptions<\n MessageType extends Message = Message,\n> = {\n from?: EventStoreDBEventStoreConsumerType;\n client: EventStoreDBClient;\n batchSize: number;\n eachBatch: BatchRecordedMessageHandlerWithoutContext<\n MessageType,\n EventStoreDBReadEventMetadata\n >;\n resilience?: {\n resubscribeOptions?: AsyncRetryOptions;\n };\n};\n\nexport type EventStoreDBSubscriptionStartFrom =\n | { lastCheckpoint: ProcessorCheckpoint }\n | 'BEGINNING'\n | 'END';\n\nexport type EventStoreDBSubscriptionStartOptions = {\n startFrom: EventStoreDBSubscriptionStartFrom;\n};\n\nexport type EventStoreDBSubscription = {\n isRunning: boolean;\n start(options: EventStoreDBSubscriptionStartOptions): Promise<void>;\n stop(): Promise<void>;\n};\n\nconst toGlobalPosition = (startFrom: EventStoreDBSubscriptionStartFrom) =>\n startFrom === 'BEGINNING'\n ? START\n : startFrom === 'END'\n ? END\n : {\n prepare: parseBigIntProcessorCheckpoint(startFrom.lastCheckpoint),\n commit: parseBigIntProcessorCheckpoint(startFrom.lastCheckpoint),\n };\n\nconst toStreamPosition = (startFrom: EventStoreDBSubscriptionStartFrom) =>\n startFrom === 'BEGINNING'\n ? START\n : startFrom === 'END'\n ? END\n : parseBigIntProcessorCheckpoint(startFrom.lastCheckpoint);\n\nconst subscribe = (\n client: EventStoreDBClient,\n from: EventStoreDBEventStoreConsumerType | undefined,\n options: EventStoreDBSubscriptionStartOptions,\n) =>\n from == undefined || from.stream == $all\n ? client.subscribeToAll({\n ...(from?.options ?? {}),\n fromPosition: toGlobalPosition(options.startFrom),\n filter: excludeSystemEvents(),\n })\n : client.subscribeToStream(from.stream, {\n ...(from.options ?? {}),\n fromRevision: toStreamPosition(options.startFrom),\n });\n\nexport const isDatabaseUnavailableError = (error: unknown) =>\n error instanceof Error &&\n 'type' in error &&\n error.type === 'unavailable' &&\n 'code' in error &&\n error.code === 14;\n\nexport const EventStoreDBResubscribeDefaultOptions: AsyncRetryOptions = {\n forever: true,\n minTimeout: 100,\n factor: 1.5,\n shouldRetryError: (error) => !isDatabaseUnavailableError(error),\n};\n\ntype SubscriptionSequentialHandlerOptions<\n MessageType extends AnyMessage = AnyMessage,\n> = EventStoreDBSubscriptionOptions<MessageType> & WritableOptions;\n\nclass SubscriptionSequentialHandler<\n MessageType extends AnyMessage = AnyMessage,\n> extends Transform {\n private options: SubscriptionSequentialHandlerOptions<MessageType>;\n private from: EventStoreDBEventStoreConsumerType | undefined;\n public isRunning: boolean;\n\n constructor(options: SubscriptionSequentialHandlerOptions<MessageType>) {\n super({ objectMode: true, ...options });\n this.options = options;\n this.from = options.from;\n this.isRunning = true;\n }\n\n async _transform(\n resolvedEvent: ResolvedEvent<MessageType>,\n _encoding: BufferEncoding,\n callback: (error?: Error | null) => void,\n ): Promise<void> {\n try {\n if (!this.isRunning || !resolvedEvent.event) {\n callback();\n return;\n }\n\n const message = mapFromESDBEvent(resolvedEvent, this.from);\n const messageCheckpoint = getCheckpoint(message);\n\n const result = await this.options.eachBatch([message]);\n\n if (result && result.type === 'STOP') {\n this.isRunning = false;\n if (!result.error) this.push(messageCheckpoint);\n\n this.push(result);\n this.push(null);\n callback();\n return;\n }\n\n this.push(messageCheckpoint);\n callback();\n } catch (error) {\n callback(error as Error);\n }\n }\n}\n\nexport const eventStoreDBSubscription = <\n MessageType extends AnyMessage = AnyMessage,\n>({\n client,\n from,\n batchSize,\n eachBatch,\n resilience,\n}: EventStoreDBSubscriptionOptions<MessageType>): EventStoreDBSubscription => {\n let isRunning = false;\n\n let start: Promise<void>;\n let processor: SubscriptionSequentialHandler<MessageType>;\n\n let subscription: StreamSubscription<MessageType>;\n\n const resubscribeOptions: AsyncRetryOptions =\n resilience?.resubscribeOptions ?? {\n ...EventStoreDBResubscribeDefaultOptions,\n shouldRetryResult: () => isRunning,\n shouldRetryError: (error) =>\n isRunning &&\n EventStoreDBResubscribeDefaultOptions.shouldRetryError!(error),\n };\n\n const stopSubscription = (callback?: () => void): Promise<void> => {\n isRunning = false;\n if (processor) processor.isRunning = false;\n return subscription\n .unsubscribe()\n .then(() => {\n subscription.destroy();\n })\n .catch((err) => console.error('Error during unsubscribe.%s', err))\n .finally(callback ?? (() => {}));\n };\n\n const pipeMessages = (options: EventStoreDBSubscriptionStartOptions) => {\n let retry = 0;\n return asyncRetry(\n () =>\n new Promise<void>((resolve, reject) => {\n if (!isRunning) {\n resolve();\n return;\n }\n console.info(\n `Starting subscription. ${retry++} retries. From: ${JSONSerializer.serialize(from ?? '$all')}, Start from: ${JSONSerializer.serialize(\n options.startFrom,\n )}`,\n );\n subscription = subscribe(client, from, options);\n\n processor = new SubscriptionSequentialHandler({\n client,\n from,\n batchSize,\n eachBatch,\n resilience,\n });\n\n const handler = new (class extends Writable {\n async _write(\n result: ProcessorCheckpoint | MessageHandlerResult,\n _encoding: string,\n done: () => void,\n ) {\n if (!isRunning) return;\n\n if (isString(result)) {\n options.startFrom = {\n lastCheckpoint: result,\n };\n done();\n return;\n }\n\n if (result && result.type === 'STOP' && result.error) {\n console.error(\n `Subscription stopped with error code: ${result.error.errorCode}, message: ${\n result.error.message\n }.`,\n );\n }\n\n await stopSubscription();\n done();\n }\n })({ objectMode: true });\n\n pipeline(\n subscription,\n processor,\n handler,\n async (error: Error | null) => {\n console.info(`Stopping subscription.`);\n await stopSubscription(() => {\n if (!error) {\n console.info('Subscription ended successfully.');\n resolve();\n return;\n }\n console.error(\n `Received error: ${JSONSerializer.serialize(error)}.`,\n );\n reject(error);\n });\n },\n );\n }),\n resubscribeOptions,\n );\n };\n\n return {\n get isRunning() {\n return isRunning;\n },\n start: (options) => {\n if (isRunning) return start;\n\n start = (async () => {\n isRunning = true;\n\n return pipeMessages(options);\n })();\n\n return start;\n },\n stop: async () => {\n if (!isRunning) return start ? await start : Promise.resolve();\n await stopSubscription();\n await start;\n },\n };\n};\n\nexport const zipEventStoreDBEventStoreMessageBatchPullerStartFrom = (\n options: (EventStoreDBSubscriptionStartFrom | undefined)[],\n): EventStoreDBSubscriptionStartFrom => {\n if (\n options.length === 0 ||\n options.some((o) => o === undefined || o === 'BEGINNING')\n )\n return 'BEGINNING';\n\n if (options.every((o) => o === 'END')) return 'END';\n\n return options\n .filter((o) => o !== undefined && o !== 'BEGINNING' && o !== 'END')\n .sort((a, b) => (a > b ? 1 : -1))[0]!;\n};\n","import {\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n assertExpectedVersionMatchesCurrent,\n bigIntProcessorCheckpoint,\n downcastRecordedMessages,\n upcastRecordedMessage,\n type AggregateStreamOptions,\n type AggregateStreamResultWithGlobalPosition,\n type AnyMessage,\n type AppendToStreamOptions,\n type AppendToStreamResultWithGlobalPosition,\n type Event,\n type EventStore,\n type ExpectedStreamVersion,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n type RecordedMessage,\n type StreamExistsResult,\n} from '@event-driven-io/emmett';\nimport type { EventStoreDBClient } from '@eventstore/db-client';\nimport {\n ANY,\n STREAM_EXISTS as ESDB_STREAM_EXISTS,\n NO_STREAM,\n StreamNotFoundError,\n WrongExpectedVersionError,\n jsonEvent,\n type AppendExpectedRevision,\n type ReadStreamOptions as ESDBReadStreamOptions,\n type ResolvedEvent,\n} from '@eventstore/db-client';\nimport {\n $all,\n eventStoreDBEventStoreConsumer,\n type EventStoreDBEventStoreConsumer,\n type EventStoreDBEventStoreConsumerConfig,\n type EventStoreDBEventStoreConsumerType,\n} from './consumers';\n\nconst toEventStoreDBReadOptions = <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>(\n options: ReadStreamOptions<EventType, EventPayloadType> | undefined,\n): ESDBReadStreamOptions | undefined => {\n return options\n ? {\n fromRevision: 'from' in options ? options.from : undefined,\n maxCount:\n 'maxCount' in options\n ? options.maxCount\n : 'to' in options\n ? options.to\n : undefined,\n }\n : undefined;\n};\n\nexport const EventStoreDBEventStoreDefaultStreamVersion = -1n;\n\nexport type EventStoreDBReadEventMetadata = ReadEventMetadataWithGlobalPosition;\n\nexport type EventStoreDBReadEvent<EventType extends Event = Event> = ReadEvent<\n EventType,\n EventStoreDBReadEventMetadata\n>;\n\nexport interface EventStoreDBEventStore extends EventStore<EventStoreDBReadEventMetadata> {\n appendToStream<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResultWithGlobalPosition>;\n consumer<ConsumerEventType extends Event = Event>(\n options?: EventStoreDBEventStoreConsumerConfig<ConsumerEventType>,\n ): EventStoreDBEventStoreConsumer<ConsumerEventType>;\n}\n\nexport const getEventStoreDBEventStore = (\n eventStore: EventStoreDBClient,\n): EventStoreDBEventStore => {\n return {\n async aggregateStream<\n State,\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n EventStoreDBReadEventMetadata,\n EventPayloadType\n >,\n ): Promise<AggregateStreamResultWithGlobalPosition<State>> {\n const { evolve, initialState, read } = options;\n\n const expectedStreamVersion = read?.expectedStreamVersion;\n\n let state = initialState();\n let currentStreamVersion: bigint =\n EventStoreDBEventStoreDefaultStreamVersion;\n let lastEventGlobalPosition: bigint | undefined = undefined;\n\n try {\n for await (const resolvedEvent of eventStore.readStream<EventPayloadType>(\n streamName,\n toEventStoreDBReadOptions(options.read),\n )) {\n const { event } = resolvedEvent;\n if (!event) continue;\n\n state = evolve(\n state,\n upcastRecordedMessage(\n mapFromESDBEvent<EventPayloadType>(resolvedEvent),\n options?.read?.schema?.versioning,\n ),\n );\n currentStreamVersion = event.revision;\n lastEventGlobalPosition = event.position?.commit;\n }\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n EventStoreDBEventStoreDefaultStreamVersion,\n );\n\n return lastEventGlobalPosition\n ? {\n currentStreamVersion,\n lastEventGlobalPosition,\n state,\n streamExists: true,\n }\n : {\n currentStreamVersion,\n state,\n streamExists: false,\n };\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return {\n currentStreamVersion,\n state,\n streamExists: false,\n };\n }\n\n throw error;\n }\n },\n\n readStream: async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options?: ReadStreamOptions<EventType, EventPayloadType>,\n ): Promise<ReadStreamResult<EventType, EventStoreDBReadEventMetadata>> => {\n const events: ReadEvent<EventType, EventStoreDBReadEventMetadata>[] = [];\n\n let currentStreamVersion: bigint =\n EventStoreDBEventStoreDefaultStreamVersion;\n\n try {\n for await (const resolvedEvent of eventStore.readStream<EventPayloadType>(\n streamName,\n toEventStoreDBReadOptions(options),\n )) {\n const { event } = resolvedEvent;\n if (!event) continue;\n events.push(\n upcastRecordedMessage(\n mapFromESDBEvent<EventPayloadType>(resolvedEvent),\n options?.schema?.versioning,\n ),\n );\n\n currentStreamVersion = event.revision;\n }\n return {\n currentStreamVersion,\n events,\n streamExists: true,\n };\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return {\n currentStreamVersion,\n events: [],\n streamExists: false,\n };\n }\n\n throw error;\n }\n },\n\n appendToStream: async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResultWithGlobalPosition> => {\n try {\n const eventsToStore = downcastRecordedMessages(\n events,\n options?.schema?.versioning,\n );\n const serializedEvents = eventsToStore.map(jsonEvent);\n\n const expectedRevision = toExpectedRevision(\n options?.expectedStreamVersion,\n );\n\n const appendResult = await eventStore.appendToStream(\n streamName,\n serializedEvents,\n {\n expectedRevision,\n },\n );\n\n return {\n nextExpectedStreamVersion: appendResult.nextExpectedRevision,\n lastEventGlobalPosition: appendResult.position!.commit,\n createdNewStream:\n appendResult.nextExpectedRevision >=\n BigInt(serializedEvents.length),\n };\n } catch (error) {\n if (error instanceof WrongExpectedVersionError) {\n throw new ExpectedVersionConflictError(\n BigInt(error.actualVersion),\n toExpectedVersion(error.expectedVersion),\n );\n }\n\n throw error;\n }\n },\n\n consumer: <ConsumerEventType extends Event = Event>(\n options?: EventStoreDBEventStoreConsumerConfig<ConsumerEventType>,\n ): EventStoreDBEventStoreConsumer<ConsumerEventType> =>\n eventStoreDBEventStoreConsumer<ConsumerEventType>({\n ...(options ?? {}),\n client: eventStore,\n }),\n\n streamExists: async (streamName: string): Promise<StreamExistsResult> => {\n try {\n for await (const resolvedEvent of eventStore.readStream(streamName)) {\n const { event } = resolvedEvent;\n\n if (!event) continue;\n\n return true;\n }\n\n return false;\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return false;\n }\n\n throw error;\n }\n },\n\n //streamEvents: streamEvents(eventStore),\n };\n};\n\nconst getESDBCheckpoint = <MessageType extends AnyMessage = AnyMessage>(\n resolvedEvent: ResolvedEvent<MessageType>,\n from?: EventStoreDBEventStoreConsumerType,\n): bigint => {\n return !from || from?.stream === $all\n ? (resolvedEvent.link?.position?.commit ??\n resolvedEvent.event?.position?.commit)!\n : (resolvedEvent.link?.revision ?? resolvedEvent.event!.revision);\n};\n\nexport const mapFromESDBEvent = <MessageType extends AnyMessage = AnyMessage>(\n resolvedEvent: ResolvedEvent<MessageType>,\n from?: EventStoreDBEventStoreConsumerType,\n): RecordedMessage<MessageType, EventStoreDBReadEventMetadata> => {\n const event = resolvedEvent.event!;\n return <RecordedMessage<MessageType, EventStoreDBReadEventMetadata>>{\n type: event.type,\n data: event.data,\n metadata: {\n ...((event.metadata as EventStoreDBReadEventMetadata) ??\n ({} as EventStoreDBReadEventMetadata)),\n eventId: event.id,\n streamName: event.streamId,\n streamPosition: event.revision,\n globalPosition: event.position!.commit,\n checkpoint: bigIntProcessorCheckpoint(\n getESDBCheckpoint(resolvedEvent, from),\n ),\n },\n };\n};\n\nconst toExpectedRevision = (\n expected: ExpectedStreamVersion | undefined,\n): AppendExpectedRevision => {\n if (expected === undefined) return ANY;\n\n if (expected === NO_CONCURRENCY_CHECK) return ANY;\n\n if (expected == STREAM_DOES_NOT_EXIST) return NO_STREAM;\n\n if (expected == STREAM_EXISTS) return ESDB_STREAM_EXISTS;\n\n return expected as bigint;\n};\n\nconst toExpectedVersion = (\n expected: AppendExpectedRevision | undefined,\n): ExpectedStreamVersion => {\n if (expected === undefined) return NO_CONCURRENCY_CHECK;\n\n if (expected === ANY) return NO_CONCURRENCY_CHECK;\n\n if (expected == NO_STREAM) return STREAM_DOES_NOT_EXIST;\n\n if (expected == ESDB_STREAM_EXISTS) return STREAM_EXISTS;\n\n return expected;\n};\n\n// const { map } = streamTransformations;\n//\n// // eslint-disable-next-line @typescript-eslint/no-unused-vars\n// const convertToWebReadableStream = (\n// allStreamSubscription: AllStreamSubscription,\n// ): ReadableStream<AllStreamResolvedEvent | GlobalStreamCaughtUp> => {\n// // Validate the input type\n// if (!(allStreamSubscription instanceof Readable)) {\n// throw new Error('Provided stream is not a Node.js Readable stream.');\n// }\n\n// let globalPosition = 0n;\n\n// const stream = Readable.toWeb(\n// allStreamSubscription,\n// ) as ReadableStream<AllStreamResolvedEvent>;\n\n// const writable = new WritableStream<\n// AllStreamResolvedEvent | GlobalStreamCaughtUp\n// >();\n\n// allStreamSubscription.on('caughtUp', async () => {\n// console.log(globalPosition);\n// await writable.getWriter().write(globalStreamCaughtUp({ globalPosition }));\n// });\n\n// const transform = map<\n// AllStreamResolvedEvent,\n// AllStreamResolvedEvent | GlobalStreamCaughtUp\n// >((event) => {\n// if (event?.event?.position.commit)\n// globalPosition = event.event?.position.commit;\n\n// return event;\n// });\n\n// return stream.pipeThrough<AllStreamResolvedEvent | GlobalStreamCaughtUp>(\n// transform,\n// );\n// };\n\n// const streamEvents = (eventStore: EventStoreDBClient) => () => {\n// return restream<\n// AllStreamResolvedEvent | GlobalSubscriptionEvent,\n// | ReadEvent<Event, EventStoreDBReadEventMetadata>\n// | GlobalSubscriptionEvent\n// >(\n// (): ReadableStream<AllStreamResolvedEvent | GlobalSubscriptionEvent> =>\n// convertToWebReadableStream(\n// eventStore.subscribeToAll({\n// fromPosition: START,\n// filter: excludeSystemEvents(),\n// }),\n// ),\n// (\n// resolvedEvent: AllStreamResolvedEvent | GlobalSubscriptionEvent,\n// ): ReadEvent<Event, EventStoreDBReadEventMetadata> =>\n// mapFromESDBEvent(resolvedEvent.event as JSONRecordedEvent<Event>),\n// );\n// };\n"],"mappings":"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","names":["uuid","operationResult","uuid","newCollection","message","uuid","message","projection","event","uuid","retry","uuid","options"]}
1
+ {"version":3,"sources":["../../emmett/src/config/plugins/index.ts","../../emmett/src/validation/index.ts","../../emmett/src/errors/index.ts","../../emmett/src/validation/dates.ts","../../emmett/src/eventStore/afterCommit/afterEventStoreCommitHandler.ts","../../emmett/src/eventStore/afterCommit/forwardToMessageBus.ts","../../emmett/src/typing/command.ts","../../emmett/src/typing/event.ts","../../emmett/src/typing/message.ts","../../emmett/src/typing/index.ts","../../emmett/src/eventStore/events/index.ts","../../emmett/src/eventStore/eventStore.ts","../../emmett/src/eventStore/expectedVersion.ts","../../emmett/src/eventStore/inMemoryEventStore.ts","../../emmett/src/database/inMemoryDatabase.ts","../../emmett/src/utils/collections/duplicates.ts","../../emmett/src/utils/collections/merge.ts","../../emmett/src/utils/collections/index.ts","../../emmett/src/utils/deepEquals.ts","../../emmett/src/utils/iterators.ts","../../emmett/src/taskProcessing/executionGuards.ts","../../emmett/src/taskProcessing/taskProcessor.ts","../../emmett/src/utils/locking/index.ts","../../emmett/src/utils/numbers/bigint.ts","../../emmett/src/utils/promises.ts","../../emmett/src/utils/retry.ts","../../emmett/src/serialization/json/jsonSerializer.ts","../../emmett/src/utils/shutdown/gracefulShutdown.ts","../../emmett/src/utils/strings/hashText.ts","../../emmett/src/database/utils.ts","../../emmett/src/processors/processors.ts","../../emmett/src/processors/inMemoryProcessors.ts","../../emmett/src/eventStore/projections/inMemory/inMemoryProjection.ts","../../emmett/src/eventStore/projections/inMemory/inMemoryProjectionSpec.ts","../../emmett/src/testing/assertions.ts","../../emmett/src/testing/deciderSpecification.ts","../../emmett/src/testing/workflowSpecification.ts","../../emmett/src/testing/wrapEventStore.ts","../../emmett/src/eventStore/versioning/downcasting.ts","../../emmett/src/eventStore/versioning/upcasting.ts","../../emmett/src/commandHandling/handleCommand.ts","../../emmett/src/commandHandling/handleCommandWithDecider.ts","../../emmett/src/messageBus/index.ts","../../emmett/src/projections/index.ts","../../emmett/src/workflows/handleWorkflow.ts","../../emmett/src/workflows/workflow.ts","../../emmett/src/workflows/workflowProcessor.ts","../src/eventStore/consumers/eventStoreDBEventStoreConsumer.ts","../src/eventStore/consumers/subscriptions/index.ts","../src/eventStore/eventstoreDBEventStore.ts"],"sourcesContent":["export type EmmettPluginConfig =\n | {\n name: string;\n register: EmmettPluginRegistration[];\n }\n | string;\n\nexport type EmmettPluginType = 'cli';\n\nexport type EmmettCliPluginRegistration = { pluginType: 'cli'; path?: string };\n\nexport type EmmettPluginRegistration = EmmettCliPluginRegistration;\n\nexport type EmmettCliCommand = {\n addCommand<CliCommand>(command: CliCommand): CliCommand;\n};\n\nexport type EmmettCliPlugin = {\n pluginType: 'cli';\n name: string;\n registerCommands: (program: EmmettCliCommand) => Promise<void> | void;\n};\n\nexport type EmmettPlugin = EmmettCliPlugin;\n\nexport const isPluginConfig = (\n plugin: Partial<EmmettPluginConfig> | string | undefined,\n): plugin is EmmettPluginConfig =>\n plugin !== undefined &&\n (typeof plugin === 'string' ||\n ('name' in plugin &&\n plugin.name !== undefined &&\n typeof plugin.name === 'string'));\n","import { ValidationError } from '../errors';\n\nexport const enum ValidationErrors {\n NOT_A_NONEMPTY_STRING = 'NOT_A_NONEMPTY_STRING',\n NOT_A_POSITIVE_NUMBER = 'NOT_A_POSITIVE_NUMBER',\n NOT_AN_UNSIGNED_BIGINT = 'NOT_AN_UNSIGNED_BIGINT',\n}\n\nexport const isNumber = (val: unknown): val is number =>\n typeof val === 'number' && val === val;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const isBigint = (val: any): val is bigint =>\n typeof val === 'bigint' && val === val;\n\nexport const isString = (val: unknown): val is string =>\n typeof val === 'string';\n\nexport const assertNotEmptyString = (value: unknown): string => {\n if (!isString(value) || value.length === 0) {\n throw new ValidationError(ValidationErrors.NOT_A_NONEMPTY_STRING);\n }\n return value;\n};\n\nexport const assertPositiveNumber = (value: unknown): number => {\n if (!isNumber(value) || value <= 0) {\n throw new ValidationError(ValidationErrors.NOT_A_POSITIVE_NUMBER);\n }\n return value;\n};\n\nexport const assertUnsignedBigInt = (value: string): bigint => {\n const number = BigInt(value);\n if (number < 0) {\n throw new ValidationError(ValidationErrors.NOT_AN_UNSIGNED_BIGINT);\n }\n return number;\n};\n\nexport * from './dates';\n","import { isNumber, isString } from '../validation';\n\nexport type ErrorConstructor<ErrorType extends Error> = new (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ...args: any[]\n) => ErrorType;\n\nexport const isErrorConstructor = <ErrorType extends Error>(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n expect: Function,\n): expect is ErrorConstructor<ErrorType> => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return (\n typeof expect === 'function' &&\n expect.prototype &&\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n expect.prototype.constructor === expect\n );\n};\n\nexport class EmmettError extends Error {\n public static readonly Codes = {\n ValidationError: 400,\n IllegalStateError: 403,\n NotFoundError: 404,\n ConcurrencyError: 412,\n InternalServerError: 500,\n };\n\n public errorCode: number;\n\n constructor(\n options?: { errorCode: number; message?: string } | string | number,\n ) {\n const errorCode =\n options && typeof options === 'object' && 'errorCode' in options\n ? options.errorCode\n : isNumber(options)\n ? options\n : EmmettError.Codes.InternalServerError;\n const message =\n options && typeof options === 'object' && 'message' in options\n ? options.message\n : isString(options)\n ? options\n : `Error with status code '${errorCode}' ocurred during Emmett processing`;\n\n super(message);\n this.errorCode = errorCode;\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, EmmettError.prototype);\n }\n\n public static mapFrom(\n error: Error | { message?: string; errorCode?: number },\n ): EmmettError {\n if (EmmettError.isInstanceOf(error)) {\n return error;\n }\n\n return new EmmettError({\n errorCode:\n 'errorCode' in error &&\n error.errorCode !== undefined &&\n error.errorCode !== null\n ? error.errorCode\n : EmmettError.Codes.InternalServerError,\n message: error.message ?? 'An unknown error occurred',\n });\n }\n\n public static isInstanceOf<ErrorType extends EmmettError = EmmettError>(\n error: unknown,\n errorCode?: (typeof EmmettError.Codes)[keyof typeof EmmettError.Codes],\n ): error is ErrorType {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'errorCode' in error &&\n isNumber(error.errorCode) &&\n (errorCode === undefined || error.errorCode === errorCode)\n );\n }\n}\n\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: EmmettError.Codes.ConcurrencyError,\n message:\n message ??\n `Expected version ${expected.toString()} does not match current ${current?.toString()}`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyError.prototype);\n }\n}\n\n// TODO: Make it derive from ConcurrencyError to avoid code duplication\n// Or add additional type to distinguinsh both errors\nexport class ConcurrencyInMemoryDatabaseError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: EmmettError.Codes.ConcurrencyError,\n message: message ?? `Expected document state does not match current one!`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyInMemoryDatabaseError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: EmmettError.Codes.ValidationError,\n message: message ?? `Validation Error ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class IllegalStateError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: EmmettError.Codes.IllegalStateError,\n message: message ?? `Illegal State ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, IllegalStateError.prototype);\n }\n}\n\nexport class NotFoundError extends EmmettError {\n constructor(options?: { id: string; type: string; message?: string }) {\n super({\n errorCode: EmmettError.Codes.NotFoundError,\n message:\n options?.message ??\n (options?.id\n ? options.type\n ? `${options.type} with ${options.id} was not found during Emmett processing`\n : `State with ${options.id} was not found during Emmett processing`\n : options?.type\n ? `${options.type} was not found during Emmett processing`\n : 'State was not found during Emmett processing'),\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n","import { ValidationError } from '../errors';\n\nexport const formatDateToUtcYYYYMMDD = (date: Date) => {\n // Use the 'en-CA' locale which formats as 'yyyy-mm-dd'\n const formatter = new Intl.DateTimeFormat('en-CA', {\n timeZone: 'UTC',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n\n // Format the date\n return formatter.format(date);\n};\n\n// Function to validate 'yyyy-mm-dd' format\nexport const isValidYYYYMMDD = (dateString: string) => {\n const regex = /^\\d{4}-\\d{2}-\\d{2}$/;\n return regex.test(dateString);\n};\n\nexport const parseDateFromUtcYYYYMMDD = (dateString: string) => {\n const date = new Date(dateString + 'T00:00:00Z');\n\n if (!isValidYYYYMMDD(dateString)) {\n throw new ValidationError('Invalid date format, must be yyyy-mm-dd');\n }\n\n if (isNaN(date.getTime())) {\n throw new ValidationError('Invalid date format');\n }\n\n return date;\n};\n","import type {\n BatchRecordedMessageHandlerWithContext,\n BatchRecordedMessageHandlerWithoutContext,\n DefaultRecord,\n Event,\n ReadEvent,\n} from '../../typing';\nimport type { EventStore, EventStoreReadEventMetadata } from '../eventStore';\n\nexport type AfterEventStoreCommitHandler<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = HandlerContext extends undefined\n ? BatchRecordedMessageHandlerWithoutContext<\n Event,\n EventStoreReadEventMetadata<Store>\n >\n : BatchRecordedMessageHandlerWithContext<\n Event,\n EventStoreReadEventMetadata<Store>,\n NonNullable<HandlerContext>\n >;\n\nexport type BeforeEventStoreCommitHandler<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = HandlerContext extends undefined\n ? BatchRecordedMessageHandlerWithoutContext<\n Event,\n EventStoreReadEventMetadata<Store>\n >\n : BatchRecordedMessageHandlerWithContext<\n Event,\n EventStoreReadEventMetadata<Store>,\n NonNullable<HandlerContext>\n >;\n\ntype TryPublishMessagesAfterCommitOptions<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = {\n onAfterCommit?: AfterEventStoreCommitHandler<Store, HandlerContext>;\n};\n\nexport async function tryPublishMessagesAfterCommit<Store extends EventStore>(\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n options: TryPublishMessagesAfterCommitOptions<Store, undefined> | undefined,\n): Promise<boolean>;\nexport async function tryPublishMessagesAfterCommit<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n>(\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n options:\n | TryPublishMessagesAfterCommitOptions<Store, HandlerContext>\n | undefined,\n context: HandlerContext,\n): Promise<boolean>;\nexport async function tryPublishMessagesAfterCommit<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n>(\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n options:\n | TryPublishMessagesAfterCommitOptions<Store, HandlerContext>\n | undefined,\n context?: HandlerContext,\n): Promise<boolean> {\n if (options?.onAfterCommit === undefined) return false;\n\n try {\n await options?.onAfterCommit(messages, context!);\n return true;\n } catch (error) {\n // TODO: enhance with tracing\n console.error(`Error in on after commit hook`, error);\n return false;\n }\n}\n","import type { EventsPublisher } from '../../messageBus';\nimport type { DefaultRecord, Event, ReadEvent } from '../../typing';\nimport type { EventStore, EventStoreReadEventMetadata } from '../eventStore';\nimport type { AfterEventStoreCommitHandler } from './afterEventStoreCommitHandler';\n\nexport const forwardToMessageBus = <\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n>(\n eventPublisher: EventsPublisher,\n): AfterEventStoreCommitHandler<Store, HandlerContext> =>\n (async (\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n ): Promise<void> => {\n for (const message of messages) {\n await eventPublisher.publish(message);\n }\n }) as AfterEventStoreCommitHandler<Store, HandlerContext>;\n","import type { DefaultRecord } from './';\n\nexport type Command<\n CommandType extends string = string,\n CommandData extends DefaultRecord = DefaultRecord,\n CommandMetaData extends DefaultRecord | undefined = undefined,\n> = Readonly<\n CommandMetaData extends undefined\n ? {\n type: CommandType;\n data: Readonly<CommandData>;\n metadata?: DefaultCommandMetadata | undefined;\n }\n : {\n type: CommandType;\n data: CommandData;\n metadata: CommandMetaData;\n }\n> & { readonly kind?: 'Command' };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyCommand = Command<any, any, any>;\n\nexport type CommandTypeOf<T extends Command> = T['type'];\nexport type CommandDataOf<T extends Command> = T['data'];\nexport type CommandMetaDataOf<T extends Command> = T extends {\n metadata: infer M;\n}\n ? M\n : undefined;\n\nexport type CreateCommandType<\n CommandType extends string,\n CommandData extends DefaultRecord,\n CommandMetaData extends DefaultRecord | undefined = undefined,\n> = Readonly<\n CommandMetaData extends undefined\n ? {\n type: CommandType;\n data: CommandData;\n metadata?: DefaultCommandMetadata | undefined;\n }\n : {\n type: CommandType;\n data: CommandData;\n metadata: CommandMetaData;\n }\n> & { readonly kind?: 'Command' };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const command = <CommandType extends Command<string, any, any>>(\n ...args: CommandMetaDataOf<CommandType> extends undefined\n ? [\n type: CommandTypeOf<CommandType>,\n data: CommandDataOf<CommandType>,\n metadata?: DefaultCommandMetadata | undefined,\n ]\n : [\n type: CommandTypeOf<CommandType>,\n data: CommandDataOf<CommandType>,\n metadata: CommandMetaDataOf<CommandType>,\n ]\n): CommandType => {\n const [type, data, metadata] = args;\n\n return metadata !== undefined\n ? ({ type, data, metadata, kind: 'Command' } as CommandType)\n : ({ type, data, kind: 'Command' } as CommandType);\n};\n\nexport type DefaultCommandMetadata = { now: Date };\n","import type { DefaultRecord } from './';\nimport type {\n AnyRecordedMessageMetadata,\n CombinedMessageMetadata,\n CommonRecordedMessageMetadata,\n RecordedMessage,\n RecordedMessageMetadata,\n RecordedMessageMetadataWithGlobalPosition,\n RecordedMessageMetadataWithoutGlobalPosition,\n} from './message';\n\nexport type StreamPosition = bigint;\nexport type GlobalPosition = bigint;\n\nexport type Event<\n EventType extends string = string,\n EventData extends DefaultRecord = DefaultRecord,\n EventMetaData extends DefaultRecord | undefined = undefined,\n> = Readonly<\n EventMetaData extends undefined\n ? {\n type: EventType;\n data: EventData;\n }\n : {\n type: EventType;\n data: EventData;\n metadata: EventMetaData;\n }\n> & { readonly kind?: 'Event' };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyEvent = Event<any, any, any>;\n\nexport type EventTypeOf<T extends Event> = T['type'];\nexport type EventDataOf<T extends Event> = T['data'];\nexport type EventMetaDataOf<T extends Event> = T extends { metadata: infer M }\n ? M\n : undefined;\n\nexport type CreateEventType<\n EventType extends string,\n EventData extends DefaultRecord,\n EventMetaData extends DefaultRecord | undefined = undefined,\n> = Readonly<\n EventMetaData extends undefined\n ? {\n type: EventType;\n data: EventData;\n }\n : {\n type: EventType;\n data: EventData;\n metadata: EventMetaData;\n }\n> & { readonly kind?: 'Event' };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const event = <EventType extends Event<string, any, any>>(\n ...args: EventMetaDataOf<EventType> extends undefined\n ? [type: EventTypeOf<EventType>, data: EventDataOf<EventType>]\n : [\n type: EventTypeOf<EventType>,\n data: EventDataOf<EventType>,\n metadata: EventMetaDataOf<EventType>,\n ]\n): EventType => {\n const [type, data, metadata] = args;\n\n return metadata !== undefined\n ? ({ type, data, metadata, kind: 'Event' } as EventType)\n : ({ type, data, kind: 'Event' } as EventType);\n};\n\nexport type CombinedReadEventMetadata<\n EventType extends Event = Event,\n EventMetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n> = CombinedMessageMetadata<EventType, EventMetaDataType>;\n\nexport type ReadEvent<\n EventType extends Event = Event,\n EventMetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n> = RecordedMessage<EventType, EventMetaDataType>;\n\nexport type AnyReadEvent<\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n> = ReadEvent<AnyEvent, EventMetaDataType>;\n\nexport type CommonReadEventMetadata = CommonRecordedMessageMetadata;\n\nexport type ReadEventMetadata<HasGlobalPosition = undefined> =\n RecordedMessageMetadata<HasGlobalPosition>;\n\nexport type AnyReadEventMetadata = AnyRecordedMessageMetadata;\n\nexport type ReadEventMetadataWithGlobalPosition =\n RecordedMessageMetadataWithGlobalPosition;\n\nexport type ReadEventMetadataWithoutGlobalPosition =\n RecordedMessageMetadataWithoutGlobalPosition;\n","import type {\n AnyCommand,\n AnyEvent,\n Command,\n DefaultRecord,\n Event,\n GlobalPosition,\n StreamPosition,\n} from '.';\nimport type { ProcessorCheckpoint } from '../processors';\n\nexport type Message<\n Type extends string = string,\n Data extends DefaultRecord = DefaultRecord,\n MetaData extends DefaultRecord | undefined = undefined,\n> = Command<Type, Data, MetaData> | Event<Type, Data, MetaData>;\n\nexport type AnyMessage = AnyEvent | AnyCommand;\n\nexport type MessageKindOf<T extends Message> = T['kind'];\nexport type MessageTypeOf<T extends Message> = T['type'];\nexport type MessageDataOf<T extends Message> = T['data'];\nexport type MessageMetaDataOf<T extends Message> = T extends {\n metadata: infer M;\n}\n ? M\n : undefined;\n\nexport type CanHandle<T extends Message> = MessageTypeOf<T>[];\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const message = <MessageType extends Message<string, any, any>>(\n ...args: MessageMetaDataOf<MessageType> extends undefined\n ? [\n kind: MessageKindOf<MessageType>,\n type: MessageTypeOf<MessageType>,\n data: MessageDataOf<MessageType>,\n ]\n : [\n kind: MessageKindOf<MessageType>,\n type: MessageTypeOf<MessageType>,\n data: MessageDataOf<MessageType>,\n metadata: MessageMetaDataOf<MessageType>,\n ]\n): MessageType => {\n const [kind, type, data, metadata] = args;\n\n return metadata !== undefined\n ? ({ type, data, metadata, kind } as MessageType)\n : ({ type, data, kind } as MessageType);\n};\n\nexport type CombinedMessageMetadata<\n MessageType extends Message = Message,\n MessageMetaDataType extends DefaultRecord = DefaultRecord,\n> =\n MessageMetaDataOf<MessageType> extends undefined\n ? MessageMetaDataType\n : MessageMetaDataOf<MessageType> & MessageMetaDataType;\n\nexport type CombineMetadata<\n MessageType extends Message = Message,\n MessageMetaDataType extends DefaultRecord = DefaultRecord,\n> = MessageType & {\n metadata: CombinedMessageMetadata<MessageType, MessageMetaDataType>;\n};\n\nexport type RecordedMessage<\n MessageType extends Message = Message,\n MessageMetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n> = CombineMetadata<MessageType, MessageMetaDataType> & {\n kind: NonNullable<MessageKindOf<Message>>;\n};\n\nexport type CommonRecordedMessageMetadata = Readonly<{\n messageId: string;\n streamPosition: StreamPosition;\n streamName: string;\n checkpoint?: ProcessorCheckpoint | null;\n}>;\n\nexport type WithGlobalPosition = Readonly<{\n globalPosition: GlobalPosition;\n}>;\n\nexport type RecordedMessageMetadata<HasGlobalPosition = undefined> =\n CommonRecordedMessageMetadata &\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n (HasGlobalPosition extends undefined ? {} : WithGlobalPosition);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyRecordedMessage = Message<any, any, any>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyRecordedMessageMetadata = RecordedMessageMetadata<any>;\n\nexport type RecordedMessageMetadataWithGlobalPosition =\n RecordedMessageMetadata<true>;\n\nexport type RecordedMessageMetadataWithoutGlobalPosition =\n RecordedMessageMetadata<undefined>;\n","export * from './deepReadonly';\n\nexport * from './command';\nexport * from './event';\nexport * from './message';\nexport * from './messageHandling';\n\nexport * from './decider';\n\nexport type Brand<K, T> = K & { readonly __brand: T };\nexport type Flavour<K, T> = K & { readonly __brand?: T };\n\nexport type DefaultRecord = Record<string, unknown>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyRecord = Record<string, any>;\n\nexport type NonNullable<T> = T extends null | undefined ? never : T;\n\nexport const emmettPrefix = 'emt';\n\nexport const globalTag = 'global';\nexport const defaultTag = `${emmettPrefix}:default`;\nexport const unknownTag = `${emmettPrefix}:unknown`;\n","import {\n event,\n type Event,\n type EventDataOf,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n} from '../../typing';\n\nexport const GlobalStreamCaughtUpType = '__emt:GlobalStreamCaughtUp';\n\nexport type GlobalStreamCaughtUp = Event<\n '__emt:GlobalStreamCaughtUp',\n { globalPosition: bigint },\n { globalPosition: bigint }\n>;\n\nexport const isGlobalStreamCaughtUp = (\n event: Event,\n): event is GlobalStreamCaughtUp => event.type === GlobalStreamCaughtUpType;\n\nexport const caughtUpEventFrom =\n (position: bigint) =>\n (\n event: ReadEvent<Event, ReadEventMetadataWithGlobalPosition>,\n ): event is ReadEvent<\n GlobalStreamCaughtUp,\n ReadEventMetadataWithGlobalPosition\n > =>\n event.type === GlobalStreamCaughtUpType &&\n event.metadata?.globalPosition >= position;\n\nexport const globalStreamCaughtUp = (\n data: EventDataOf<GlobalStreamCaughtUp>,\n): GlobalStreamCaughtUp =>\n event<GlobalStreamCaughtUp>(GlobalStreamCaughtUpType, data, {\n globalPosition: data.globalPosition,\n });\n\nexport const isSubscriptionEvent = (\n event: Event,\n): event is GlobalSubscriptionEvent => isGlobalStreamCaughtUp(event);\n\nexport const isNotInternalEvent = (event: Event): boolean =>\n !isGlobalStreamCaughtUp(event);\n\nexport type GlobalSubscriptionEvent = GlobalStreamCaughtUp;\n","import type { JSONSerializationOptions } from '../serialization';\nimport type {\n AnyReadEventMetadata,\n CommonReadEventMetadata,\n DefaultRecord,\n Event,\n GlobalPosition,\n ReadEvent,\n ReadEventMetadata,\n StreamPosition,\n WithGlobalPosition,\n} from '../typing';\nimport type { AfterEventStoreCommitHandler } from './afterCommit';\nimport type { ExpectedStreamVersion } from './expectedVersion';\n\n// #region event-store\nexport interface EventStore<\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n> {\n aggregateStream<\n State,\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n ReadEventMetadataType,\n EventPayloadType\n >,\n ): Promise<AggregateStreamResult<State>>;\n\n readStream<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options?: ReadStreamOptions<EventType, EventPayloadType>,\n ): Promise<ReadStreamResult<EventType, ReadEventMetadataType>>;\n\n appendToStream<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResult>;\n\n streamExists(streamName: string): Promise<StreamExistsResult>;\n\n // streamEvents(): ReadableStream<\n // ReadEvent<Event, ReadEventMetadataType> | GlobalSubscriptionEvent\n // >;\n}\n\nexport type EventStoreReadEventMetadata<Store extends EventStore> =\n Store extends EventStore<infer T>\n ? T extends CommonReadEventMetadata\n ? T extends WithGlobalPosition\n ? ReadEventMetadata<true> & T\n : ReadEventMetadata<undefined> & T\n : never\n : never;\n\nexport type EventStoreSession<EventStoreType extends EventStore> = {\n eventStore: EventStoreType;\n close: () => Promise<void>;\n};\n\nexport interface EventStoreSessionFactory<EventStoreType extends EventStore> {\n withSession<T = unknown>(\n callback: (session: EventStoreSession<EventStoreType>) => Promise<T>,\n ): Promise<T>;\n}\n// #endregion event-store\n\nexport const canCreateEventStoreSession = <Store extends EventStore>(\n eventStore: Store | EventStoreSessionFactory<Store>,\n): eventStore is EventStoreSessionFactory<Store> => 'withSession' in eventStore;\n\nexport const nulloSessionFactory = <EventStoreType extends EventStore>(\n eventStore: EventStoreType,\n): EventStoreSessionFactory<EventStoreType> => ({\n withSession: (callback) => {\n const nulloSession: EventStoreSession<EventStoreType> = {\n eventStore,\n close: () => Promise.resolve(),\n };\n\n return callback(nulloSession);\n },\n});\n\n////////////////////////////////////////////////////////////////////\n/// Schema Versioning types\n////////////////////////////////////////////////////////////////////\n\nexport type EventStoreReadSchemaOptions<\n StreamEvent extends Event = Event,\n StoredEvent extends Event = StreamEvent,\n> = {\n versioning?: {\n upcast?: (event: StoredEvent) => StreamEvent;\n };\n};\n\nexport type EventStoreAppendSchemaOptions<\n StreamEvent extends Event = Event,\n StoredEvent extends Event = StreamEvent,\n> = {\n versioning?: {\n downcast?: (event: StreamEvent) => StoredEvent;\n };\n};\n\nexport type EventStoreSchemaOptions<\n StreamEvent extends Event = Event,\n StoredEvent extends Event = StreamEvent,\n> = EventStoreReadSchemaOptions<StreamEvent, StoredEvent> &\n EventStoreAppendSchemaOptions<StreamEvent, StoredEvent>;\n\n////////////////////////////////////////////////////////////////////\n/// ReadStream types\n////////////////////////////////////////////////////////////////////\n\nexport type ReadStreamOptions<\n EventType extends Event = Event,\n EventPayloadType extends Event = EventType,\n> = {\n from?: StreamPosition;\n to?: StreamPosition;\n maxCount?: bigint;\n expectedStreamVersion?: ExpectedStreamVersion;\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n} & JSONSerializationOptions;\n\nexport type ReadStreamResult<\n EventType extends Event,\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n> = {\n currentStreamVersion: StreamPosition;\n events: ReadEvent<EventType, ReadEventMetadataType>[];\n streamExists: boolean;\n};\n\n////////////////////////////////////////////////////////////////////\n/// AggregateStream types\n////////////////////////////////////////////////////////////////////\n\ntype Evolve<\n State,\n EventType extends Event,\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n> =\n | ((currentState: State, event: EventType) => State)\n | ((\n currentState: State,\n event: ReadEvent<EventType, ReadEventMetadataType>,\n ) => State)\n | ((currentState: State, event: ReadEvent<EventType>) => State);\n\nexport type AggregateStreamOptions<\n State,\n EventType extends Event,\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n EventPayloadType extends Event = EventType,\n> = {\n evolve: Evolve<State, EventType, ReadEventMetadataType>;\n initialState: () => State;\n read?: ReadStreamOptions<EventType, EventPayloadType>;\n};\n\nexport type AggregateStreamResult<State> = {\n currentStreamVersion: StreamPosition;\n state: State;\n streamExists: boolean;\n};\n\nexport type AggregateStreamResultWithGlobalPosition<State> =\n | (AggregateStreamResult<State> & {\n streamExists: true;\n lastEventGlobalPosition: GlobalPosition;\n })\n | (AggregateStreamResult<State> & {\n streamExists: false;\n });\n\nexport type AggregateStreamResultOfEventStore<Store extends EventStore> =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Store['aggregateStream'] extends (...args: any[]) => Promise<infer R>\n ? R\n : never;\n\n////////////////////////////////////////////////////////////////////\n/// AppendToStream types\n////////////////////////////////////////////////////////////////////\n\nexport type AppendToStreamOptions<\n EventType extends Event = Event,\n EventPayloadType extends Event = EventType,\n> = {\n expectedStreamVersion?: ExpectedStreamVersion;\n schema?: EventStoreAppendSchemaOptions<EventType, EventPayloadType> &\n JSONSerializationOptions;\n};\n\nexport type AppendToStreamResult = {\n nextExpectedStreamVersion: StreamPosition;\n createdNewStream: boolean;\n};\n\nexport type AppendToStreamResultWithGlobalPosition = AppendToStreamResult & {\n lastEventGlobalPosition: GlobalPosition;\n};\n\nexport type AppendStreamResultOfEventStore<Store extends EventStore> =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Store['appendToStream'] extends (...args: any[]) => Promise<infer R>\n ? R\n : never;\n\n////////////////////////////////////////////////////////////////////\n/// StreamExists types\n////////////////////////////////////////////////////////////////////\n\nexport type StreamExistsResult = boolean;\n\n////////////////////////////////////////////////////////////////////\n/// DefaultEventStoreOptions\n////////////////////////////////////////////////////////////////////\n\nexport type DefaultEventStoreOptions<\n Store extends EventStore,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = {\n /**\n * Pluggable set of hooks informing about the event store internal behaviour.\n */\n hooks?: {\n /**\n * This hook will be called **AFTER** events were stored in the event store.\n * It's designed to handle scenarios where delivery and ordering guarantees do not matter much.\n *\n * **WARNINGS:**\n *\n * 1. It will be called **EXACTLY ONCE** if append succeded.\n * 2. If the hook fails, its append **will still silently succeed**, and no error will be thrown.\n * 3. Wen process crashes after events were committed, but before the hook was called, delivery won't be retried.\n * That can lead to state inconsistencies.\n * 4. In the case of high concurrent traffic, **race conditions may cause ordering issues**.\n * For instance, where the second hook takes longer to process than the first one, ordering won't be guaranteed.\n *\n * @type {AfterEventStoreCommitHandler<Store, HandlerContext>}\n */\n onAfterCommit?: AfterEventStoreCommitHandler<Store, HandlerContext>;\n };\n};\n","import { ConcurrencyError, EmmettError } from '../errors';\nimport type { Flavour, StreamPosition } from '../typing';\n\nexport type ExpectedStreamVersion =\n | ExpectedStreamVersionWithValue\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue = Flavour<\n StreamPosition,\n 'StreamVersion'\n>;\n\nexport type ExpectedStreamVersionGeneral = Flavour<\n 'STREAM_EXISTS' | 'STREAM_DOES_NOT_EXIST' | 'NO_CONCURRENCY_CHECK',\n 'StreamVersion'\n>;\n\nexport const STREAM_EXISTS = 'STREAM_EXISTS' as ExpectedStreamVersionGeneral;\nexport const STREAM_DOES_NOT_EXIST =\n 'STREAM_DOES_NOT_EXIST' as ExpectedStreamVersionGeneral;\nexport const NO_CONCURRENCY_CHECK =\n 'NO_CONCURRENCY_CHECK' as ExpectedStreamVersionGeneral;\n\nexport const matchesExpectedVersion = (\n current: StreamPosition | undefined,\n expected: ExpectedStreamVersion,\n defaultVersion: StreamPosition,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === defaultVersion;\n\n if (expected == STREAM_EXISTS) return current !== defaultVersion;\n\n return current === expected;\n};\n\nexport const assertExpectedVersionMatchesCurrent = (\n current: StreamPosition,\n expected: ExpectedStreamVersion | undefined,\n defaultVersion: StreamPosition,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected, defaultVersion))\n throw new ExpectedVersionConflictError(current, expected);\n};\n\nexport class ExpectedVersionConflictError extends ConcurrencyError {\n constructor(current: StreamPosition, expected: ExpectedStreamVersion) {\n super(current?.toString(), expected?.toString());\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);\n }\n}\n\nexport const isExpectedVersionConflictError = (\n error: unknown,\n): error is ExpectedVersionConflictError =>\n error instanceof ExpectedVersionConflictError ||\n EmmettError.isInstanceOf<ConcurrencyError>(\n error,\n ExpectedVersionConflictError.Codes.ConcurrencyError,\n );\n","import { v4 as uuid } from 'uuid';\nimport {\n getInMemoryDatabase,\n type InMemoryDatabase,\n} from '../database/inMemoryDatabase';\nimport { bigIntProcessorCheckpoint } from '../processors';\nimport type { ProjectionRegistration } from '../projections';\nimport type {\n CombinedReadEventMetadata,\n Event,\n ReadEvent,\n ReadEventMetadataWithGlobalPosition,\n} from '../typing';\nimport { tryPublishMessagesAfterCommit } from './afterCommit';\nimport type {\n AggregateStreamOptions,\n AggregateStreamResult,\n AppendToStreamOptions,\n AppendToStreamResult,\n DefaultEventStoreOptions,\n EventStore,\n ReadStreamOptions,\n ReadStreamResult,\n StreamExistsResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\nimport { handleInMemoryProjections } from './projections/inMemory';\nimport { downcastRecordedMessages, upcastRecordedMessages } from './versioning';\n\nexport const InMemoryEventStoreDefaultStreamVersion = 0n;\n\nexport type InMemoryEventStore =\n EventStore<ReadEventMetadataWithGlobalPosition> & {\n database: InMemoryDatabase;\n };\n\nexport type InMemoryReadEventMetadata = ReadEventMetadataWithGlobalPosition;\n\nexport type InMemoryProjectionHandlerContext = {\n eventStore?: InMemoryEventStore;\n database?: InMemoryDatabase;\n};\n\nexport type InMemoryEventStoreOptions =\n DefaultEventStoreOptions<InMemoryEventStore> & {\n projections?: ProjectionRegistration<\n 'inline',\n InMemoryReadEventMetadata,\n InMemoryProjectionHandlerContext\n >[];\n database?: InMemoryDatabase;\n };\n\nexport type InMemoryReadEvent<EventType extends Event = Event> = ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n>;\n\nexport const getInMemoryEventStore = (\n eventStoreOptions?: InMemoryEventStoreOptions,\n): InMemoryEventStore => {\n const streams = new Map<\n string,\n ReadEvent<Event, ReadEventMetadataWithGlobalPosition>[]\n >();\n\n const getAllEventsCount = () => {\n return Array.from<ReadEvent[]>(streams.values())\n .map((s) => s.length)\n .reduce((p, c) => p + c, 0);\n };\n\n // Get the database instance to be used for projections\n const database = eventStoreOptions?.database || getInMemoryDatabase();\n\n // Extract inline projections from options\n const inlineProjections = (eventStoreOptions?.projections ?? [])\n .filter(({ type }) => type === 'inline')\n .map(({ projection }) => projection);\n\n // Create the event store object\n const eventStore: InMemoryEventStore = {\n database,\n async aggregateStream<\n State,\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n ReadEventMetadataWithGlobalPosition,\n EventPayloadType\n >,\n ): Promise<AggregateStreamResult<State>> {\n const { evolve, initialState, read } = options;\n\n const result = await this.readStream<EventType, EventPayloadType>(\n streamName,\n read,\n );\n\n const events = result?.events ?? [];\n\n const state = events.reduce((s, e) => evolve(s, e), initialState());\n\n return {\n currentStreamVersion: BigInt(events.length),\n state,\n streamExists: result.streamExists,\n };\n },\n\n readStream: <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n readOptions?: ReadStreamOptions<EventType, EventPayloadType>,\n ): Promise<\n ReadStreamResult<EventType, ReadEventMetadataWithGlobalPosition>\n > => {\n const events = streams.get(streamName);\n const currentStreamVersion = events\n ? BigInt(events.length)\n : InMemoryEventStoreDefaultStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n readOptions?.expectedStreamVersion,\n InMemoryEventStoreDefaultStreamVersion,\n );\n\n const from = Number(readOptions?.from ?? 0);\n const to = Number(\n readOptions?.to ??\n (readOptions?.maxCount\n ? (readOptions.from ?? 0n) + readOptions.maxCount\n : (events?.length ?? 1)),\n );\n\n const resultEvents =\n events !== undefined && events.length > 0\n ? upcastRecordedMessages<\n EventType,\n EventPayloadType,\n ReadEventMetadataWithGlobalPosition\n >(\n events.slice(from, to) as ReadEvent<\n EventPayloadType,\n ReadEventMetadataWithGlobalPosition\n >[],\n readOptions?.schema?.versioning,\n )\n : [];\n\n const result: ReadStreamResult<\n EventType,\n ReadEventMetadataWithGlobalPosition\n > = {\n currentStreamVersion,\n events: resultEvents,\n streamExists: events !== undefined && events.length > 0,\n };\n\n return Promise.resolve(result);\n },\n\n appendToStream: async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResult> => {\n const currentEvents = streams.get(streamName) ?? [];\n const currentStreamVersion =\n currentEvents.length > 0\n ? BigInt(currentEvents.length)\n : InMemoryEventStoreDefaultStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n InMemoryEventStoreDefaultStreamVersion,\n );\n\n const newEvents: ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >[] = events.map((event, index) => {\n const globalPosition = BigInt(getAllEventsCount() + index + 1);\n const metadata: ReadEventMetadataWithGlobalPosition = {\n streamName,\n messageId: uuid(),\n streamPosition: BigInt(currentEvents.length + index + 1),\n globalPosition,\n checkpoint: bigIntProcessorCheckpoint(globalPosition),\n };\n return {\n ...event,\n kind: event.kind ?? 'Event',\n metadata: {\n ...('metadata' in event ? (event.metadata ?? {}) : {}),\n ...metadata,\n } as CombinedReadEventMetadata<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >,\n };\n });\n\n const positionOfLastEventInTheStream = BigInt(\n newEvents.slice(-1)[0]!.metadata.streamPosition,\n );\n\n streams.set(streamName, [\n ...currentEvents,\n ...downcastRecordedMessages(newEvents, options?.schema?.versioning),\n ]);\n\n // Process projections if there are any registered\n if (inlineProjections.length > 0) {\n await handleInMemoryProjections({\n projections: inlineProjections,\n events: newEvents,\n database: eventStore.database,\n eventStore,\n });\n }\n\n const result: AppendToStreamResult = {\n nextExpectedStreamVersion: positionOfLastEventInTheStream,\n createdNewStream:\n currentStreamVersion === InMemoryEventStoreDefaultStreamVersion,\n };\n\n await tryPublishMessagesAfterCommit<InMemoryEventStore>(\n newEvents,\n eventStoreOptions?.hooks,\n );\n\n return result;\n },\n\n streamExists: (streamName): Promise<StreamExistsResult> => {\n const events = streams.get(streamName);\n\n return Promise.resolve(events !== undefined && events.length > 0);\n },\n };\n\n return eventStore;\n};\n","import { v7 as uuid } from 'uuid';\nimport { deepEquals } from '../utils';\nimport type {\n DatabaseHandleOptionErrors,\n DatabaseHandleOptions,\n DatabaseHandleResult,\n DeleteResult,\n Document,\n DocumentHandler,\n InsertOneResult,\n OptionalUnlessRequiredIdAndVersion,\n ReplaceOneOptions,\n UpdateResult,\n WithIdAndVersion,\n WithoutId,\n} from './types';\nimport { expectedVersionValue, operationResult } from './utils';\n\nexport interface InMemoryDocumentsCollection<T extends Document> {\n handle: (\n id: string,\n handle: DocumentHandler<T>,\n options?: DatabaseHandleOptions,\n ) => Promise<DatabaseHandleResult<T>>;\n findOne: (predicate?: Predicate<T>) => Promise<T | null>;\n find: (predicate?: Predicate<T>) => Promise<T[]>;\n insertOne: (\n document: OptionalUnlessRequiredIdAndVersion<T>,\n ) => Promise<InsertOneResult>;\n deleteOne: (predicate?: Predicate<T>) => Promise<DeleteResult>;\n replaceOne: (\n predicate: Predicate<T>,\n document: WithoutId<T>,\n options?: ReplaceOneOptions,\n ) => Promise<UpdateResult>;\n}\n\nexport interface InMemoryDatabase {\n collection: <T extends Document>(\n name: string,\n ) => InMemoryDocumentsCollection<T>;\n}\n\ntype Predicate<T> = (item: T) => boolean;\ntype CollectionName = string;\n\nexport const getInMemoryDatabase = (): InMemoryDatabase => {\n const storage = new Map<CollectionName, WithIdAndVersion<Document>[]>();\n\n return {\n collection: <T extends Document, CollectionName extends string>(\n collectionName: CollectionName,\n collectionOptions: {\n errors?: DatabaseHandleOptionErrors;\n } = {},\n ): InMemoryDocumentsCollection<T> => {\n const ensureCollectionCreated = () => {\n if (!storage.has(collectionName)) storage.set(collectionName, []);\n };\n\n const errors = collectionOptions.errors;\n\n const collection = {\n collectionName,\n insertOne: async (\n document: OptionalUnlessRequiredIdAndVersion<T>,\n ): Promise<InsertOneResult> => {\n ensureCollectionCreated();\n\n const _id = (document._id as string | undefined | null) ?? uuid();\n const _version = document._version ?? 1n;\n\n const existing = await collection.findOne((c) => c._id === _id);\n\n if (existing) {\n return operationResult<InsertOneResult>(\n {\n successful: false,\n insertedId: null,\n nextExpectedVersion: _version,\n },\n { operationName: 'insertOne', collectionName, errors },\n );\n }\n\n const documentsInCollection = storage.get(collectionName)!;\n const newDocument = { ...document, _id, _version };\n const newCollection = [...documentsInCollection, newDocument];\n storage.set(collectionName, newCollection);\n\n return operationResult<InsertOneResult>(\n {\n successful: true,\n insertedId: _id,\n nextExpectedVersion: _version,\n },\n { operationName: 'insertOne', collectionName, errors },\n );\n },\n findOne: (predicate?: Predicate<T>): Promise<T | null> => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName);\n const filteredDocuments = predicate\n ? documentsInCollection?.filter((doc) => predicate(doc as T))\n : documentsInCollection;\n\n const firstOne = filteredDocuments?.[0] ?? null;\n\n return Promise.resolve(firstOne as T | null);\n },\n find: (predicate?: Predicate<T>): Promise<T[]> => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName);\n const filteredDocuments = predicate\n ? documentsInCollection?.filter((doc) => predicate(doc as T))\n : documentsInCollection;\n\n return Promise.resolve(filteredDocuments as T[]);\n },\n deleteOne: (predicate?: Predicate<T>): Promise<DeleteResult> => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName)!;\n\n if (predicate) {\n const foundIndex = documentsInCollection.findIndex((doc) =>\n predicate(doc as T),\n );\n\n if (foundIndex === -1) {\n return Promise.resolve(\n operationResult<DeleteResult>(\n {\n successful: false,\n matchedCount: 0,\n deletedCount: 0,\n },\n { operationName: 'deleteOne', collectionName, errors },\n ),\n );\n } else {\n const newCollection = documentsInCollection.toSpliced(\n foundIndex,\n 1,\n );\n\n storage.set(collectionName, newCollection);\n\n return Promise.resolve(\n operationResult<DeleteResult>(\n {\n successful: true,\n matchedCount: 1,\n deletedCount: 1,\n },\n { operationName: 'deleteOne', collectionName, errors },\n ),\n );\n }\n }\n\n const newCollection = documentsInCollection.slice(1);\n\n storage.set(collectionName, newCollection);\n\n return Promise.resolve(\n operationResult<DeleteResult>(\n {\n successful: true,\n matchedCount: 1,\n deletedCount: 1,\n },\n { operationName: 'deleteOne', collectionName, errors },\n ),\n );\n },\n replaceOne: (\n predicate: Predicate<T>,\n document: WithoutId<T>,\n options?: ReplaceOneOptions,\n ): Promise<UpdateResult> => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName)!;\n\n const firstIndex = documentsInCollection.findIndex((doc) =>\n predicate(doc as T),\n );\n\n if (firstIndex === undefined || firstIndex === -1) {\n return Promise.resolve(\n operationResult<UpdateResult>(\n {\n successful: false,\n matchedCount: 0,\n modifiedCount: 0,\n nextExpectedVersion: 0n,\n },\n { operationName: 'replaceOne', collectionName, errors },\n ),\n );\n }\n\n const existing = documentsInCollection[firstIndex]!;\n\n if (\n typeof options?.expectedVersion === 'bigint' &&\n existing._version !== options.expectedVersion\n ) {\n return Promise.resolve(\n operationResult<UpdateResult>(\n {\n successful: false,\n matchedCount: 1,\n modifiedCount: 0,\n nextExpectedVersion: existing._version,\n },\n { operationName: 'replaceOne', collectionName, errors },\n ),\n );\n }\n\n const newVersion = existing._version + 1n;\n\n const newCollection = documentsInCollection.with(firstIndex, {\n _id: existing._id,\n ...document,\n _version: newVersion,\n });\n\n storage.set(collectionName, newCollection);\n\n return Promise.resolve(\n operationResult<UpdateResult>(\n {\n successful: true,\n modifiedCount: 1,\n matchedCount: firstIndex,\n nextExpectedVersion: newVersion,\n },\n { operationName: 'replaceOne', collectionName, errors },\n ),\n );\n },\n handle: async (\n id: string,\n handle: DocumentHandler<T>,\n options?: DatabaseHandleOptions,\n ): Promise<DatabaseHandleResult<T>> => {\n const { expectedVersion: version, ...operationOptions } =\n options ?? {};\n ensureCollectionCreated();\n const existing = await collection.findOne(({ _id }) => _id === id);\n\n const expectedVersion = expectedVersionValue(version);\n\n if (\n (existing == null && version === 'DOCUMENT_EXISTS') ||\n (existing == null && expectedVersion != null) ||\n (existing != null && version === 'DOCUMENT_DOES_NOT_EXIST') ||\n (existing != null &&\n expectedVersion !== null &&\n existing._version !== expectedVersion)\n ) {\n return operationResult<DatabaseHandleResult<T>>(\n {\n successful: false,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n }\n\n const result = handle(existing !== null ? { ...existing } : null);\n\n if (deepEquals(existing, result))\n return operationResult<DatabaseHandleResult<T>>(\n {\n successful: true,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n\n if (!existing && result) {\n const newDoc = { ...result, _id: id };\n const insertResult = await collection.insertOne({\n ...newDoc,\n _id: id,\n } as OptionalUnlessRequiredIdAndVersion<T>);\n return {\n ...insertResult,\n document: {\n ...newDoc,\n _version: insertResult.nextExpectedVersion,\n } as unknown as WithIdAndVersion<T>,\n };\n }\n\n if (existing && !result) {\n const deleteResult = await collection.deleteOne(\n ({ _id }) => id === _id,\n );\n return { ...deleteResult, document: null };\n }\n\n if (existing && result) {\n const replaceResult = await collection.replaceOne(\n ({ _id }) => id === _id,\n result,\n {\n ...operationOptions,\n expectedVersion: expectedVersion ?? 'DOCUMENT_EXISTS',\n },\n );\n return {\n ...replaceResult,\n document: {\n ...result,\n _version: replaceResult.nextExpectedVersion,\n } as unknown as WithIdAndVersion<T>,\n };\n }\n\n return operationResult<DatabaseHandleResult<T>>(\n {\n successful: true,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n },\n };\n\n return collection;\n },\n };\n};\n","export const hasDuplicates = <ArrayItem, Mapped>(\n array: ArrayItem[],\n predicate: (value: ArrayItem, index: number, array: ArrayItem[]) => Mapped,\n) => {\n const mapped = array.map(predicate);\n const uniqueValues = new Set(mapped);\n\n return uniqueValues.size < mapped.length;\n};\n\nexport const getDuplicates = <ArrayItem, Mapped>(\n array: ArrayItem[],\n predicate: (value: ArrayItem, index: number, array: ArrayItem[]) => Mapped,\n): ArrayItem[] => {\n const map = new Map<Mapped, ArrayItem[]>();\n\n for (let i = 0; i < array.length; i++) {\n const item = array[i]!;\n const key = predicate(item, i, array);\n if (!map.has(key)) {\n map.set(key, []);\n }\n map.get(key)!.push(item);\n }\n\n return Array.from(map.values())\n .filter((group) => group.length > 1)\n .flat();\n};\n","export const merge = <T>(\n array: T[],\n item: T,\n where: (current: T) => boolean,\n onExisting: (current: T) => T,\n onNotFound: () => T | undefined = () => undefined,\n) => {\n let wasFound = false;\n\n const result = array\n // merge the existing item if matches condition\n .map((p: T) => {\n if (!where(p)) return p;\n\n wasFound = true;\n return onExisting(p);\n })\n // filter out item if undefined was returned\n // for cases of removal\n .filter((p) => p !== undefined)\n // make TypeScript happy\n .map((p) => {\n if (!p) throw Error('That should not happen');\n\n return p;\n });\n\n // if item was not found and onNotFound action is defined\n // try to generate new item\n if (!wasFound) {\n const result = onNotFound();\n\n if (result !== undefined) return [...array, item];\n }\n\n return result;\n};\n","import { getDuplicates, hasDuplicates } from './duplicates';\nimport { merge } from './merge';\n\nexport * from './merge';\n\nexport const arrayUtils = {\n merge,\n hasDuplicates,\n getDuplicates,\n};\n","const isPrimitive = (value: unknown): boolean => {\n const type = typeof value;\n return (\n value === null ||\n value === undefined ||\n type === 'boolean' ||\n type === 'number' ||\n type === 'string' ||\n type === 'symbol' ||\n type === 'bigint'\n );\n};\n\nconst compareArrays = <T>(left: T[], right: T[]): boolean => {\n if (left.length !== right.length) {\n return false;\n }\n for (let i = 0; i < left.length; i++) {\n const leftHas = i in left;\n const rightHas = i in right;\n if (leftHas !== rightHas) return false;\n if (leftHas && !deepEquals(left[i], right[i])) return false;\n }\n return true;\n};\n\nconst compareDates = (left: Date, right: Date): boolean => {\n return left.getTime() === right.getTime();\n};\n\nconst compareRegExps = (left: RegExp, right: RegExp): boolean => {\n return left.toString() === right.toString();\n};\n\nconst compareErrors = (left: Error, right: Error): boolean => {\n if (left.message !== right.message || left.name !== right.name) {\n return false;\n }\n const leftKeys = Object.keys(left);\n const rightKeys = Object.keys(right);\n if (leftKeys.length !== rightKeys.length) return false;\n const rightKeySet = new Set(rightKeys);\n for (const key of leftKeys) {\n if (!rightKeySet.has(key)) return false;\n // @ts-expect-error - accessing dynamic keys\n if (!deepEquals(left[key], right[key])) return false;\n }\n return true;\n};\n\nconst compareMaps = (\n left: Map<unknown, unknown>,\n right: Map<unknown, unknown>,\n): boolean => {\n if (left.size !== right.size) return false;\n\n for (const [key, value] of left) {\n if (isPrimitive(key)) {\n if (!right.has(key) || !deepEquals(value, right.get(key))) {\n return false;\n }\n } else {\n let found = false;\n for (const [rightKey, rightValue] of right) {\n if (deepEquals(key, rightKey) && deepEquals(value, rightValue)) {\n found = true;\n break;\n }\n }\n if (!found) return false;\n }\n }\n return true;\n};\n\nconst compareSets = (left: Set<unknown>, right: Set<unknown>): boolean => {\n if (left.size !== right.size) return false;\n\n for (const leftItem of left) {\n if (isPrimitive(leftItem)) {\n if (!right.has(leftItem)) return false;\n } else {\n let found = false;\n for (const rightItem of right) {\n if (deepEquals(leftItem, rightItem)) {\n found = true;\n break;\n }\n }\n if (!found) return false;\n }\n }\n return true;\n};\n\nconst compareArrayBuffers = (\n left: ArrayBuffer,\n right: ArrayBuffer,\n): boolean => {\n if (left.byteLength !== right.byteLength) return false;\n const leftView = new Uint8Array(left);\n const rightView = new Uint8Array(right);\n for (let i = 0; i < leftView.length; i++) {\n if (leftView[i] !== rightView[i]) return false;\n }\n return true;\n};\n\nconst compareTypedArrays = (\n left: ArrayBufferView,\n right: ArrayBufferView,\n): boolean => {\n if (left.constructor !== right.constructor) return false;\n if (left.byteLength !== right.byteLength) return false;\n\n const leftArray = new Uint8Array(\n left.buffer,\n left.byteOffset,\n left.byteLength,\n );\n const rightArray = new Uint8Array(\n right.buffer,\n right.byteOffset,\n right.byteLength,\n );\n\n for (let i = 0; i < leftArray.length; i++) {\n if (leftArray[i] !== rightArray[i]) return false;\n }\n return true;\n};\n\nconst compareObjects = (\n left: Record<string, unknown>,\n right: Record<string, unknown>,\n): boolean => {\n const keys1 = Object.keys(left);\n const keys2 = Object.keys(right);\n\n if (keys1.length !== keys2.length) {\n return false;\n }\n\n for (const key of keys1) {\n if (left[key] instanceof Function && right[key] instanceof Function) {\n continue;\n }\n\n const isEqual = deepEquals(left[key], right[key]);\n if (!isEqual) {\n return false;\n }\n }\n\n return true;\n};\n\nconst getType = (value: unknown): string => {\n if (value === null) return 'null';\n if (value === undefined) return 'undefined';\n\n const primitiveType = typeof value;\n if (primitiveType !== 'object') return primitiveType;\n\n if (Array.isArray(value)) return 'array';\n if (value instanceof Boolean) return 'boxed-boolean';\n if (value instanceof Number) return 'boxed-number';\n if (value instanceof String) return 'boxed-string';\n if (value instanceof Date) return 'date';\n if (value instanceof RegExp) return 'regexp';\n if (value instanceof Error) return 'error';\n if (value instanceof Map) return 'map';\n if (value instanceof Set) return 'set';\n if (value instanceof ArrayBuffer) return 'arraybuffer';\n if (value instanceof DataView) return 'dataview';\n if (value instanceof WeakMap) return 'weakmap';\n if (value instanceof WeakSet) return 'weakset';\n\n if (ArrayBuffer.isView(value)) return 'typedarray';\n\n return 'object';\n};\n\nexport const deepEquals = <T>(left: T, right: T): boolean => {\n if (left === right) return true;\n\n if (isEquatable(left)) {\n return left.equals(right);\n }\n\n const leftType = getType(left);\n const rightType = getType(right);\n\n if (leftType !== rightType) return false;\n\n switch (leftType) {\n case 'null':\n case 'undefined':\n case 'boolean':\n case 'number':\n case 'bigint':\n case 'string':\n case 'symbol':\n case 'function':\n return left === right;\n\n case 'array':\n return compareArrays(left as unknown[], right as unknown[]);\n\n case 'date':\n return compareDates(left as Date, right as Date);\n\n case 'regexp':\n return compareRegExps(left as RegExp, right as RegExp);\n\n case 'error':\n return compareErrors(left as Error, right as Error);\n\n case 'map':\n return compareMaps(\n left as Map<unknown, unknown>,\n right as Map<unknown, unknown>,\n );\n\n case 'set':\n return compareSets(left as Set<unknown>, right as Set<unknown>);\n\n case 'arraybuffer':\n return compareArrayBuffers(left as ArrayBuffer, right as ArrayBuffer);\n\n case 'dataview':\n case 'weakmap':\n case 'weakset':\n return false;\n\n case 'typedarray':\n return compareTypedArrays(\n left as ArrayBufferView,\n right as ArrayBufferView,\n );\n\n case 'boxed-boolean':\n return (left as boolean).valueOf() === (right as boolean).valueOf();\n\n case 'boxed-number':\n return (left as number).valueOf() === (right as number).valueOf();\n\n case 'boxed-string':\n return (left as string).valueOf() === (right as string).valueOf();\n\n case 'object':\n return compareObjects(\n left as Record<string, unknown>,\n right as Record<string, unknown>,\n );\n\n default:\n return false;\n }\n};\n\nexport type Equatable<T> = { equals: (right: T) => boolean } & T;\n\nexport const isEquatable = <T>(left: T): left is Equatable<T> => {\n return (\n left !== null &&\n left !== undefined &&\n typeof left === 'object' &&\n 'equals' in left &&\n typeof left['equals'] === 'function'\n );\n};\n","export const sum = (\n iterator: Iterator<number, number, number> | Iterator<number>,\n) => {\n let value,\n done: boolean | undefined,\n sum = 0;\n do {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n ({ value, done } = iterator.next());\n sum += value || 0;\n } while (!done);\n return sum;\n};\n","import { v7 as uuid } from 'uuid';\nimport { TaskProcessor } from './taskProcessor';\n\nexport type ExclusiveAccessGuard = {\n execute: <Result>(operation: () => Promise<Result>) => Promise<Result>;\n waitForIdle: () => Promise<void>;\n stop: (options?: { force?: boolean }) => Promise<void>;\n};\n\nexport const guardExclusiveAccess = (options?: {\n maxQueueSize?: number;\n}): ExclusiveAccessGuard => {\n const taskProcessor = new TaskProcessor({\n maxActiveTasks: 1,\n maxQueueSize: options?.maxQueueSize ?? 1000,\n });\n\n return {\n execute: <Result>(operation: () => Promise<Result>): Promise<Result> =>\n taskProcessor.enqueue(async ({ ack }) => {\n try {\n return await operation();\n } finally {\n ack();\n }\n }),\n waitForIdle: () => taskProcessor.waitForEndOfProcessing(),\n stop: (options) => taskProcessor.stop(options),\n };\n};\n\nexport type BoundedAccessGuard<Resource> = {\n acquire: () => Promise<Resource>;\n release: (resource: Resource) => void;\n execute: <Result>(\n operation: (resource: Resource) => Promise<Result>,\n ) => Promise<Result>;\n waitForIdle: () => Promise<void>;\n stop: (options?: { force?: boolean }) => Promise<void>;\n};\n\nexport const guardBoundedAccess = <Resource>(\n getResource: () => Resource | Promise<Resource>,\n options: {\n maxResources: number;\n maxQueueSize?: number;\n reuseResources?: boolean;\n closeResource?: (resource: Resource) => void | Promise<void>;\n },\n): BoundedAccessGuard<Resource> => {\n let isStopped = false;\n const taskProcessor = new TaskProcessor({\n maxActiveTasks: options.maxResources,\n maxQueueSize: options.maxQueueSize ?? 1000,\n });\n\n const resourcePool: Resource[] = [];\n const allResources = new Set<Resource>();\n const ackCallbacks = new Map<Resource, () => void>();\n\n const acquire = async (): Promise<Resource> =>\n taskProcessor.enqueue(async ({ ack }) => {\n try {\n let resource: Resource | undefined;\n\n if (options.reuseResources) {\n resource = resourcePool.pop();\n }\n\n if (!resource) {\n resource = await getResource();\n allResources.add(resource);\n }\n\n ackCallbacks.set(resource, ack);\n return resource;\n } catch (e) {\n ack();\n throw e;\n }\n });\n\n const release = (resource: Resource) => {\n const ack = ackCallbacks.get(resource);\n if (ack) {\n ackCallbacks.delete(resource);\n if (options.reuseResources) {\n resourcePool.push(resource);\n }\n ack();\n }\n };\n\n const execute = async <Result>(\n operation: (resource: Resource) => Promise<Result>,\n ): Promise<Result> => {\n const resource = await acquire();\n try {\n return await operation(resource);\n } finally {\n release(resource);\n }\n };\n\n return {\n acquire,\n release,\n execute,\n waitForIdle: () => taskProcessor.waitForEndOfProcessing(),\n stop: async (stopOptions) => {\n if (isStopped) return;\n isStopped = true;\n if (options?.closeResource) {\n const resources = [...allResources];\n allResources.clear();\n resourcePool.length = 0;\n await Promise.all(\n resources.map(\n async (resource) => await options.closeResource!(resource),\n ),\n );\n }\n\n await taskProcessor.stop(stopOptions);\n },\n };\n};\n\nexport type InitializedOnceGuard<T> = {\n ensureInitialized: () => Promise<T>;\n reset: () => void;\n stop: (options?: { force?: boolean }) => Promise<void>;\n};\n\nexport const guardInitializedOnce = <T>(\n initialize: () => Promise<T>,\n options?: {\n maxQueueSize?: number;\n maxRetries?: number;\n },\n): InitializedOnceGuard<T> => {\n let initPromise: Promise<T> | null = null;\n\n const taskProcessor = new TaskProcessor({\n maxActiveTasks: 1,\n maxQueueSize: options?.maxQueueSize ?? 1000,\n });\n\n const ensureInitialized = async (retryCount = 0): Promise<T> => {\n if (initPromise !== null) {\n return initPromise;\n }\n\n return taskProcessor.enqueue(\n async ({ ack }) => {\n if (initPromise !== null) {\n ack();\n return initPromise;\n }\n\n try {\n const promise = initialize();\n initPromise = promise;\n const result = await promise;\n ack();\n return result;\n } catch (error) {\n initPromise = null;\n ack();\n const maxRetries = options?.maxRetries ?? 3;\n if (retryCount < maxRetries) {\n return ensureInitialized(retryCount + 1);\n }\n throw error;\n }\n },\n { taskGroupId: uuid() },\n );\n };\n\n return {\n ensureInitialized,\n reset: () => {\n initPromise = null;\n },\n stop: (options) => taskProcessor.stop(options),\n };\n};\n","import { EmmettError } from '../errors';\n\nexport type TaskQueue = TaskQueueItem[];\n\nexport type TaskQueueItem = {\n task: () => Promise<void>;\n options?: EnqueueTaskOptions | undefined;\n};\n\nexport type TaskProcessorOptions = {\n maxActiveTasks: number;\n maxQueueSize: number;\n maxTaskIdleTime?: number;\n};\n\nexport type Task<T> = (context: TaskContext) => Promise<T>;\n\nexport type TaskContext = {\n ack: () => void;\n};\n\nexport type EnqueueTaskOptions = { taskGroupId?: string };\n\nexport class TaskProcessor {\n private queue: TaskQueue = [];\n private isProcessing = false;\n private activeTasks = 0;\n private activeGroups: Set<string> = new Set();\n private options: TaskProcessorOptions;\n private stopped = false;\n\n constructor(options: TaskProcessorOptions) {\n this.options = options;\n }\n\n enqueue<T>(task: Task<T>, options?: EnqueueTaskOptions): Promise<T> {\n if (this.stopped) {\n return Promise.reject(new EmmettError('TaskProcessor has been stopped'));\n }\n\n if (this.queue.length >= this.options.maxQueueSize) {\n return Promise.reject(\n new EmmettError('Too many pending tasks. Please try again later.'),\n );\n }\n\n return this.schedule(task, options);\n }\n\n waitForEndOfProcessing(): Promise<void> {\n return this.schedule(({ ack }) => Promise.resolve(ack()));\n }\n\n async stop(options?: { force?: boolean }): Promise<void> {\n if (this.stopped) return;\n this.stopped = true;\n this.queue.length = 0;\n this.activeGroups.clear();\n\n if (!options?.force) {\n await this.waitForEndOfProcessing();\n }\n }\n\n private schedule<T>(task: Task<T>, options?: EnqueueTaskOptions): Promise<T> {\n return promiseWithDeadline(\n (resolve, reject) => {\n const taskWithContext = () => {\n return new Promise<void>((resolveTask, failTask) => {\n const taskPromise = task({\n ack: resolveTask,\n });\n\n taskPromise.then(resolve).catch((err) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n failTask(err);\n reject(err);\n });\n });\n };\n\n this.queue.push({ task: taskWithContext, options });\n if (!this.isProcessing) {\n this.ensureProcessing();\n }\n },\n { deadline: this.options.maxTaskIdleTime },\n );\n }\n\n private ensureProcessing(): void {\n if (this.isProcessing) return;\n this.isProcessing = true;\n this.processQueue();\n }\n\n private processQueue(): void {\n try {\n while (\n this.activeTasks < this.options.maxActiveTasks &&\n this.queue.length > 0\n ) {\n const item = this.takeFirstAvailableItem();\n\n if (item === null) return;\n\n const groupId = item.options?.taskGroupId;\n\n if (groupId) {\n // Mark the group as active\n this.activeGroups.add(groupId);\n }\n\n this.activeTasks++;\n void this.executeItem(item);\n }\n } catch (error) {\n console.error(error);\n throw error;\n } finally {\n this.isProcessing = false;\n if (\n this.hasItemsToProcess() &&\n this.activeTasks < this.options.maxActiveTasks\n ) {\n this.ensureProcessing();\n }\n }\n }\n\n private async executeItem({ task, options }: TaskQueueItem): Promise<void> {\n try {\n await task();\n } finally {\n this.activeTasks--;\n\n // Mark the group as inactive after task completion\n if (options && options.taskGroupId) {\n this.activeGroups.delete(options.taskGroupId);\n }\n\n this.ensureProcessing();\n }\n }\n\n private takeFirstAvailableItem = (): TaskQueueItem | null => {\n const taskIndex = this.queue.findIndex(\n (item) =>\n !item.options?.taskGroupId ||\n !this.activeGroups.has(item.options.taskGroupId),\n );\n\n if (taskIndex === -1) {\n // All remaining tasks are blocked by active groups\n return null;\n }\n\n // Remove the task from the queue\n const [item] = this.queue.splice(taskIndex, 1);\n\n return item ?? null;\n };\n\n private hasItemsToProcess = (): boolean =>\n this.queue.findIndex(\n (item) =>\n !item.options?.taskGroupId ||\n !this.activeGroups.has(item.options.taskGroupId),\n ) !== -1;\n}\n\nconst DEFAULT_PROMISE_DEADLINE = 2147483647;\n\nconst promiseWithDeadline = <T>(\n executor: (\n resolve: (value: T | PromiseLike<T>) => void,\n reject: (reason?: unknown) => void,\n ) => void,\n options: { deadline?: number | undefined },\n) => {\n return new Promise<T>((resolve, reject) => {\n let taskStarted = false;\n let timeoutId: NodeJS.Timeout | null = null;\n\n const deadline = options.deadline ?? DEFAULT_PROMISE_DEADLINE;\n\n timeoutId = setTimeout(() => {\n if (!taskStarted) {\n reject(\n new Error('Task was not started within the maximum waiting time'),\n );\n }\n }, deadline);\n timeoutId.unref();\n\n executor(\n (value) => {\n taskStarted = true;\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n timeoutId = null;\n resolve(value);\n },\n (reason) => {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n timeoutId = null;\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n reject(reason);\n },\n );\n });\n};\n","import { TaskProcessor } from '../../taskProcessing';\n\nexport type LockOptions = { lockId: number };\n\nexport type AcquireLockOptions = { lockId: string };\nexport type ReleaseLockOptions = { lockId: string };\n\nexport type Lock = {\n acquire(options: AcquireLockOptions): Promise<void>;\n tryAcquire(options: AcquireLockOptions): Promise<boolean>;\n release(options: ReleaseLockOptions): Promise<boolean>;\n withAcquire: <Result = unknown>(\n handle: () => Promise<Result>,\n options: AcquireLockOptions,\n ) => Promise<Result>;\n};\n\nexport const InProcessLock = (): Lock => {\n const taskProcessor = new TaskProcessor({\n maxActiveTasks: Number.MAX_VALUE,\n maxQueueSize: Number.MAX_VALUE,\n });\n\n // Map to store ack functions of currently held locks: lockId -> ack()\n const locks = new Map<string, () => void>();\n\n return {\n async acquire({ lockId }: AcquireLockOptions): Promise<void> {\n // If the lock is already held, we just queue up another task in the same group.\n // TaskProcessor ensures tasks in the same group run one at a time.\n await new Promise<void>((resolve, reject) => {\n taskProcessor\n .enqueue(\n ({ ack }) => {\n // When this task starts, it means the previous lock (if any) was released\n // and now we have exclusive access.\n locks.set(lockId, ack);\n // We do NOT call ack() here. We hold onto the lock.\n resolve();\n return Promise.resolve();\n },\n { taskGroupId: lockId },\n )\n .catch(reject);\n });\n },\n\n async tryAcquire({ lockId }: AcquireLockOptions): Promise<boolean> {\n // If lock is already held, fail immediately\n if (locks.has(lockId)) {\n return false;\n }\n\n // TODO: Check pending queue\n await this.acquire({ lockId });\n\n return true;\n },\n\n release({ lockId }: ReleaseLockOptions): Promise<boolean> {\n const ack = locks.get(lockId);\n if (ack === undefined) {\n return Promise.resolve(true);\n }\n locks.delete(lockId);\n ack();\n return Promise.resolve(true);\n },\n\n async withAcquire<Result = unknown>(\n handle: () => Promise<Result>,\n { lockId }: AcquireLockOptions,\n ): Promise<Result> {\n return taskProcessor.enqueue(\n async ({ ack }) => {\n // When this task starts, it means the previous lock (if any) was released\n // and now we have exclusive access.\n locks.set(lockId, ack);\n\n // We do NOT call ack() here. We hold onto the lock.\n try {\n return await handle();\n } finally {\n locks.delete(lockId);\n ack();\n }\n },\n { taskGroupId: lockId },\n );\n },\n };\n};\n","export const toNormalizedString = (value: bigint): string =>\n value.toString().padStart(19, '0');\n\nexport const bigInt = {\n toNormalizedString,\n};\n","export const delay = (ms: number): Promise<void> => {\n return new Promise((resolve) => setTimeout(resolve, ms));\n};\n\nexport type AsyncAwaiter<T = void> = {\n wait: Promise<T>;\n resolve: (value: T | PromiseLike<T>) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n reject: (reason?: any) => void;\n reset: () => void;\n};\n\n// TODO: Remove this after migrating to Node 22\nexport const asyncAwaiter = <T = void>(): AsyncAwaiter<T> => {\n const result: AsyncAwaiter<T> = {} as AsyncAwaiter<T>;\n\n (result.reset = () => {\n result.wait = new Promise<T>((res, rej) => {\n result.resolve = res;\n result.reject = rej;\n });\n })();\n\n return result;\n};\n","import retry from 'async-retry';\nimport { EmmettError } from '../errors';\nimport { JSONSerializer } from '../serialization';\n\nexport type AsyncRetryOptions<T = unknown> = retry.Options & {\n shouldRetryResult?: (result: T) => boolean;\n shouldRetryError?: (error?: unknown) => boolean;\n};\n\nexport const NoRetries: AsyncRetryOptions = { retries: 0 };\n\nexport const asyncRetry = async <T>(\n fn: () => Promise<T>,\n opts?: AsyncRetryOptions<T>,\n): Promise<T> => {\n if (opts === undefined || opts.retries === 0) return fn();\n\n return retry(\n async (bail) => {\n try {\n const result = await fn();\n\n if (opts?.shouldRetryResult && opts.shouldRetryResult(result)) {\n throw new EmmettError(\n `Retrying because of result: ${JSONSerializer.serialize(result)}`,\n );\n }\n return result;\n } catch (error) {\n if (opts?.shouldRetryError && !opts.shouldRetryError(error)) {\n bail(error as Error);\n return undefined as unknown as T;\n }\n throw error;\n }\n },\n opts ?? { retries: 0 },\n );\n};\n","import type { SerializationCodec, Serializer } from './serializer';\n\ninterface JSONSerializer<\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n> extends Serializer<string, SerializeOptions, DeserializeOptions> {\n serialize<T>(object: T, options?: SerializeOptions): string;\n deserialize<T>(payload: string, options?: DeserializeOptions): T;\n}\n\ntype JSONSerializerOptions = {\n parseDates?: boolean;\n parseBigInts?: boolean;\n failOnBigIntSerialization?: boolean;\n useDefaultDateSerialization?: boolean;\n};\n\ntype JSONSerializeOptions = {\n replacer?: JSONReplacer;\n} & JSONSerializerOptions;\n\ntype JSONDeserializeOptions = {\n reviver?: JSONReviver;\n} & JSONSerializerOptions;\n\ninterface JSONCodec<\n T,\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n> extends SerializationCodec<T, string, SerializeOptions, DeserializeOptions> {\n encode(object: T, options?: SerializeOptions): string;\n decode(payload: string, options?: DeserializeOptions): T;\n}\n\ntype JSONCodecSerializationOptions<\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n> =\n | {\n serializer?: JSONSerializer<SerializeOptions, DeserializeOptions>;\n serializerOptions?: never;\n }\n | {\n serializer?: never;\n serializerOptions?: JSONSerializerOptions;\n };\n\ntype JSONSerializationOptions<\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n> = {\n serialization?:\n | {\n serializer?: JSONSerializer<SerializeOptions, DeserializeOptions>;\n options?: JSONSerializeOptions | JSONDeserializeOptions;\n }\n | undefined;\n};\n\ntype JSONCodecOptions<\n T,\n Payload = T,\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n> = JSONCodecSerializationOptions<SerializeOptions, DeserializeOptions> & {\n upcast?: (document: Payload) => T;\n downcast?: (document: T) => Payload;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype JSONReplacer = (this: any, key: string, value: any) => any;\n\ntype JSONReviver = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this: any,\n key: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: any,\n context: JSONReviverContext,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n) => any;\n\n// See more in: https://tc39.es/proposal-json-parse-with-source/\nexport type JSONReviverContext = {\n source: string;\n};\n\nconst bigIntReplacer: JSONReplacer = (_key, value) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return typeof value === 'bigint' ? value.toString() : value;\n};\n\nconst dateReplacer: JSONReplacer = (_key, value) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value instanceof Date ? value.toISOString() : value;\n};\n\nconst isFirstLetterNumeric = (str: string): boolean => {\n const c = str.charCodeAt(0);\n return c >= 48 && c <= 57;\n};\n\nconst isFirstLetterNumericOrMinus = (str: string): boolean => {\n const c = str.charCodeAt(0);\n return (c >= 48 && c <= 57) || c === 45;\n};\n\nconst bigIntReviver: JSONReviver = (_key, value, context) => {\n if (\n typeof value === 'number' &&\n Number.isInteger(value) &&\n !Number.isSafeInteger(value)\n ) {\n try {\n return BigInt(context?.source ?? value.toString());\n } catch {\n return value;\n }\n }\n if (typeof value === 'string' && value.length > 15) {\n if (isFirstLetterNumericOrMinus(value)) {\n const num = Number(value);\n if (Number.isFinite(num) && !Number.isSafeInteger(num)) {\n try {\n return BigInt(value);\n } catch {\n // not a valid bigint string\n }\n }\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n};\n\nconst dateReviver: JSONReviver = (_key, value) => {\n if (\n typeof value === 'string' &&\n value.length === 24 &&\n isFirstLetterNumeric(value) &&\n value[10] === 'T' &&\n value[23] === 'Z'\n ) {\n const date = new Date(value);\n if (!isNaN(date.getTime())) {\n return date;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n};\n\nconst composeJSONReplacers = (\n ...replacers: (JSONReplacer | undefined)[]\n): JSONReplacer | undefined => {\n const filteredReplacers = replacers.filter((r) => r !== undefined);\n\n if (filteredReplacers.length === 0) return undefined;\n\n return (key, value) =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n filteredReplacers.reduce(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n (accValue, replacer) => replacer(key, accValue),\n value,\n );\n};\n\nconst composeJSONRevivers = (\n ...revivers: (JSONReviver | undefined)[]\n): JSONReviver | undefined => {\n const filteredRevivers = revivers.filter((r) => r !== undefined);\n\n if (filteredRevivers.length === 0) return undefined;\n\n return (key, value, context) =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n filteredRevivers.reduce(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n (accValue, reviver) => reviver(key, accValue, context),\n value,\n );\n};\n\nconst JSONReplacer = (opts?: JSONSerializeOptions) =>\n composeJSONReplacers(\n opts?.replacer,\n opts?.failOnBigIntSerialization !== true ? JSONReplacers.bigInt : undefined,\n opts?.useDefaultDateSerialization !== true ? JSONReplacers.date : undefined,\n );\n\nconst JSONReviver = (opts?: JSONDeserializeOptions) =>\n composeJSONRevivers(\n opts?.reviver,\n opts?.parseBigInts === true ? JSONRevivers.bigInt : undefined,\n opts?.parseDates === true ? JSONRevivers.date : undefined,\n );\n\nconst JSONReplacers = {\n bigInt: bigIntReplacer,\n date: dateReplacer,\n};\n\nconst JSONRevivers = {\n bigInt: bigIntReviver,\n date: dateReviver,\n};\n\ntype ClassicJsonReviver =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this: any, key: string, value: any) => any;\n\nconst jsonSerializer = (\n options?: JSONSerializerOptions &\n JSONDeserializeOptions &\n JSONSerializeOptions,\n): JSONSerializer => {\n const defaultReplacer = JSONReplacer(options);\n const defaultReviver = JSONReviver(options);\n\n return {\n serialize: <T>(\n object: T,\n serializerOptions?: JSONSerializeOptions,\n ): string =>\n JSON.stringify(\n object,\n serializerOptions ? JSONReplacer(serializerOptions) : defaultReplacer,\n ),\n deserialize: <T>(\n payload: string,\n deserializerOptions?: JSONDeserializeOptions,\n ): T =>\n JSON.parse(\n payload,\n (deserializerOptions\n ? JSONReviver(deserializerOptions)\n : defaultReviver) as ClassicJsonReviver,\n ) as T,\n };\n};\n\nconst JSONSerializer: JSONSerializer & {\n from: <\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n >(\n options?: JSONSerializationOptions<SerializeOptions, DeserializeOptions>,\n ) => JSONSerializer<SerializeOptions, DeserializeOptions>;\n} = Object.assign(jsonSerializer(), {\n from: <\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n >(\n options?: JSONSerializationOptions<SerializeOptions, DeserializeOptions>,\n ) =>\n options?.serialization?.serializer ??\n (options?.serialization?.options\n ? jsonSerializer(options?.serialization?.options)\n : JSONSerializer),\n});\n\nconst JSONCodec = <\n T,\n Payload = T,\n SerializeOptions extends JSONSerializeOptions = JSONSerializeOptions,\n DeserializeOptions extends JSONDeserializeOptions = JSONDeserializeOptions,\n>(\n options: JSONCodecOptions<T, Payload, SerializeOptions, DeserializeOptions>,\n): JSONCodec<T, SerializeOptions, DeserializeOptions> => {\n const serializer =\n 'serializer' in options && options.serializer\n ? options.serializer\n : jsonSerializer(\n 'serializerOptions' in options\n ? options.serializerOptions\n : undefined,\n );\n\n const upcast = options.upcast ?? ((doc: Payload) => doc as unknown as T);\n const downcast = options.downcast ?? ((doc: T) => doc as unknown as Payload);\n\n return {\n decode: (payload: string, decodeOptions?: DeserializeOptions) => {\n const deserialized = decodeOptions\n ? serializer.deserialize<Payload>(payload, decodeOptions)\n : serializer.deserialize<Payload>(payload);\n return upcast(deserialized);\n },\n encode: (object: T, encodeOptions?: SerializeOptions) => {\n const downcasted = downcast(object);\n return encodeOptions\n ? serializer.serialize(downcasted, encodeOptions)\n : serializer.serialize(downcasted);\n },\n };\n};\n\nexport {\n composeJSONReplacers,\n composeJSONRevivers,\n JSONCodec,\n JSONReplacer,\n JSONReplacers,\n JSONReviver,\n JSONRevivers,\n JSONSerializer,\n jsonSerializer,\n type JSONCodecOptions,\n type JSONDeserializeOptions,\n type JSONSerializationOptions,\n type JSONSerializeOptions,\n type JSONSerializerOptions,\n};\n","export type ShutdownHandler = () => void | Promise<void>;\n\n/**\n * Registers handlers for OS signals to enable graceful shutdown.\n * Handles SIGTERM and SIGINT by default.\n * Works in Node.js, Bun, and Deno. Safely no-ops in Browser/Cloudflare Workers.\n *\n * @param handler - Function to call when shutdown signal is received\n * @returns Cleanup function to unregister the handlers\n */\nexport const onShutdown = (handler: ShutdownHandler): (() => void) => {\n const signals = ['SIGTERM', 'SIGINT'] as const;\n\n // Node.js/Bun\n if (typeof process !== 'undefined' && typeof process.on === 'function') {\n for (const signal of signals) {\n process.on(signal, handler);\n }\n return () => {\n for (const signal of signals) {\n process.off(signal, handler);\n }\n };\n }\n\n // Deno\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access\n const deno = (globalThis as any).Deno;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (deno && typeof deno.addSignalListener === 'function') {\n for (const signal of signals) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n deno.addSignalListener(signal, handler);\n }\n return () => {\n for (const signal of signals) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n deno.removeSignalListener(signal, handler);\n }\n };\n }\n\n // Browser/Cloudflare Workers: no-op\n return () => {};\n};\n","const textEncoder = new TextEncoder();\n\nexport const hashText = async (text: string): Promise<bigint> => {\n const hashBuffer = await crypto.subtle.digest(\n 'SHA-256',\n textEncoder.encode(text),\n );\n // Create an array with a single element that is a 64-bit signed integer\n // We take the first 8 bytes (so 64 bits) of the SHA-256 hash\n const view = new BigInt64Array(hashBuffer, 0, 1);\n return view[0]!;\n};\n","import { ConcurrencyInMemoryDatabaseError } from '../errors';\nimport { JSONSerializer } from '../serialization';\nimport type {\n DatabaseHandleOptionErrors,\n ExpectedDocumentVersion,\n ExpectedDocumentVersionGeneral,\n ExpectedDocumentVersionValue,\n OperationResult,\n} from './types';\n\nexport const isGeneralExpectedDocumentVersion = (\n version: ExpectedDocumentVersion | undefined,\n): version is ExpectedDocumentVersionGeneral => {\n return (\n version === 'DOCUMENT_DOES_NOT_EXIST' ||\n version === 'DOCUMENT_EXISTS' ||\n version === 'NO_CONCURRENCY_CHECK'\n );\n};\n\nexport const expectedVersionValue = (\n version: ExpectedDocumentVersion | undefined,\n): ExpectedDocumentVersionValue | null =>\n version === undefined || isGeneralExpectedDocumentVersion(version)\n ? null\n : version;\n\nexport const operationResult = <T extends OperationResult>(\n result: Omit<T, 'assertSuccess' | 'acknowledged' | 'assertSuccessful'>,\n options: {\n operationName: string;\n collectionName: string;\n errors?: DatabaseHandleOptionErrors;\n },\n): T => {\n const operationResult: T = {\n ...result,\n acknowledged: true,\n successful: result.successful,\n assertSuccessful: (errorMessage?: string) => {\n const { successful } = result;\n const { operationName, collectionName } = options;\n\n if (!successful)\n throw new ConcurrencyInMemoryDatabaseError(\n errorMessage ??\n `${operationName} on ${collectionName} failed. Expected document state does not match current one! Result: ${JSONSerializer.serialize(result)}!`,\n );\n },\n } as T;\n\n if (options.errors?.throwOnOperationFailures)\n operationResult.assertSuccessful();\n\n return operationResult;\n};\n","import { v7 as uuid } from 'uuid';\nimport type { EmmettError } from '../errors';\nimport { upcastRecordedMessage } from '../eventStore';\nimport type { ProjectionDefinition } from '../projections';\nimport type { JSONSerializationOptions } from '../serialization';\nimport {\n defaultTag,\n type AnyEvent,\n type AnyMessage,\n type AnyReadEventMetadata,\n type AnyRecordedMessageMetadata,\n type BatchRecordedMessageHandlerWithContext,\n type Brand,\n type CanHandle,\n type DefaultRecord,\n type Event,\n type Message,\n type MessageHandlerResult,\n type RecordedMessage,\n type SingleMessageHandlerWithContext,\n type SingleRecordedMessageHandlerWithContext,\n} from '../typing';\nimport { bigInt } from '../utils';\nimport { onShutdown } from '../utils/shutdown';\n\nexport type CurrentMessageProcessorPosition =\n | { lastCheckpoint: ProcessorCheckpoint }\n | 'BEGINNING'\n | 'END';\n\nexport type GetCheckpoint<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n> = (\n message: RecordedMessage<MessageType, MessageMetadataType>,\n) => ProcessorCheckpoint | null;\n\nexport const getCheckpoint = <\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n>(\n message: RecordedMessage<MessageType, MessageMetadataType>,\n): ProcessorCheckpoint | null => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access\n return message.metadata.checkpoint;\n};\n\nexport const wasMessageHandled = <\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n>(\n message: RecordedMessage<MessageType, MessageMetadataType>,\n checkpoint: ProcessorCheckpoint | null,\n): boolean => {\n //TODO Make it smarter\n const messageCheckpoint = getCheckpoint(message);\n\n return (\n messageCheckpoint !== null &&\n messageCheckpoint !== undefined &&\n checkpoint !== null &&\n checkpoint !== undefined &&\n messageCheckpoint <= checkpoint\n );\n};\n\nexport type MessageProcessorStartFrom =\n | CurrentMessageProcessorPosition\n | 'CURRENT';\n\nexport type MessageProcessorType = 'projector' | 'reactor';\nexport const MessageProcessorType = {\n PROJECTOR: 'projector' as MessageProcessorType,\n REACTOR: 'reactor' as MessageProcessorType,\n};\n\nexport type MessageProcessor<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = {\n id: string;\n instanceId: string;\n type: string;\n canHandle?: string[];\n init: (options: Partial<HandlerContext>) => Promise<void>;\n start: (\n options: Partial<HandlerContext>,\n ) => Promise<CurrentMessageProcessorPosition | undefined>;\n close: (closeOptions: Partial<HandlerContext>) => Promise<void>;\n isActive: boolean;\n handle: BatchRecordedMessageHandlerWithContext<\n MessageType,\n MessageMetadataType,\n Partial<HandlerContext>\n >;\n};\n\nexport const MessageProcessor = {\n result: {\n skip: (options?: { reason?: string }): MessageHandlerResult => ({\n type: 'SKIP',\n ...(options ?? {}),\n }),\n stop: (options?: {\n reason?: string;\n error?: EmmettError;\n }): MessageHandlerResult => ({\n type: 'STOP',\n ...(options ?? {}),\n }),\n },\n};\n\nexport type MessageProcessingScope<\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = <Result = MessageHandlerResult>(\n handler: (context: HandlerContext) => Result | Promise<Result>,\n partialContext: Partial<HandlerContext>,\n) => Result | Promise<Result>;\n\nexport type Checkpointer<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n read: ReadProcessorCheckpoint<HandlerContext>;\n store: StoreProcessorCheckpoint<\n MessageType,\n MessageMetadataType,\n HandlerContext\n >;\n};\n\nexport type ProcessorHooks<\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n onInit?: OnReactorInitHook<HandlerContext>;\n onStart?: OnReactorStartHook<HandlerContext>;\n onClose?: OnReactorCloseHook<HandlerContext>;\n};\n\nexport type BaseMessageProcessorOptions<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n type?: string;\n processorId: string;\n processorInstanceId?: string;\n version?: number;\n partition?: string;\n startFrom?: MessageProcessorStartFrom;\n stopAfter?: (\n message: RecordedMessage<MessageType, MessageMetadataType>,\n ) => boolean;\n processingScope?: MessageProcessingScope<HandlerContext>;\n checkpoints?: Checkpointer<MessageType, MessageMetadataType, HandlerContext>;\n canHandle?: CanHandle<MessageType>;\n hooks?: ProcessorHooks<HandlerContext>;\n} & JSONSerializationOptions;\n\nexport type HandlerOptions<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n> =\n | {\n eachMessage: SingleRecordedMessageHandlerWithContext<\n MessageType,\n MessageMetadataType,\n HandlerContext\n >;\n eachBatch?: never;\n }\n | {\n eachMessage?: never;\n eachBatch: BatchRecordedMessageHandlerWithContext<\n MessageType,\n MessageMetadataType,\n HandlerContext\n >;\n };\n\nexport type OnReactorInitHook<\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = (context: HandlerContext) => Promise<void>;\n\nexport type OnReactorStartHook<\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = (context: HandlerContext) => Promise<void>;\n\nexport type OnReactorCloseHook<\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = (context: HandlerContext) => Promise<void>;\n\nexport type ReactorOptions<\n MessageType extends AnyMessage = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n MessagePayloadType extends AnyMessage = MessageType,\n> = BaseMessageProcessorOptions<\n MessageType,\n MessageMetadataType,\n HandlerContext\n> &\n HandlerOptions<MessageType, MessageMetadataType, HandlerContext> & {\n messageOptions?: {\n schema?: {\n versioning?: { upcast?: (event: MessagePayloadType) => MessageType };\n };\n };\n };\n\nexport type ProjectorOptions<\n EventType extends AnyEvent = AnyEvent,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n EventPayloadType extends Event = EventType,\n> = Omit<\n BaseMessageProcessorOptions<EventType, MessageMetadataType, HandlerContext>,\n 'type' | 'processorId'\n> & { processorId?: string } & {\n truncateOnStart?: boolean;\n projection: ProjectionDefinition<\n EventType,\n MessageMetadataType,\n HandlerContext,\n EventPayloadType\n >;\n};\n\nexport const defaultProcessingMessageProcessingScope = <\n HandlerContext = never,\n Result = MessageHandlerResult,\n>(\n handler: (context: HandlerContext) => Result | Promise<Result>,\n partialContext: Partial<HandlerContext>,\n) => handler(partialContext as HandlerContext);\n\nexport type ProcessorCheckpoint = Brand<string, 'ProcessorCheckpoint'>;\n\nexport const bigIntProcessorCheckpoint = (value: bigint): ProcessorCheckpoint =>\n bigInt.toNormalizedString(value) as ProcessorCheckpoint;\n\nexport const parseBigIntProcessorCheckpoint = (\n value: ProcessorCheckpoint,\n): bigint => BigInt(value);\n\nexport type ReadProcessorCheckpointResult = {\n lastCheckpoint: ProcessorCheckpoint | null;\n};\n\nexport type ReadProcessorCheckpoint<\n HandlerContext extends DefaultRecord = DefaultRecord,\n> = (\n options: { processorId: string; partition?: string },\n context: HandlerContext,\n) => Promise<ReadProcessorCheckpointResult>;\n\nexport type StoreProcessorCheckpointResult =\n | {\n success: true;\n newCheckpoint: ProcessorCheckpoint | null;\n }\n | { success: false; reason: 'IGNORED' | 'MISMATCH' | 'CURRENT_AHEAD' };\n\nexport type StoreProcessorCheckpoint<\n MessageType extends Message = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord | undefined = undefined,\n> = (\n options: {\n message: RecordedMessage<MessageType, MessageMetadataType>;\n processorId: string;\n version: number | undefined;\n lastCheckpoint: ProcessorCheckpoint | null;\n partition?: string;\n },\n context: HandlerContext,\n) => Promise<StoreProcessorCheckpointResult>;\n\nexport const defaultProcessorVersion = 1;\nexport const defaultProcessorPartition = defaultTag;\n\nexport const getProcessorInstanceId = (processorId: string): string =>\n `${processorId}:${uuid()}`;\n\nexport const getProjectorId = (options: { projectionName: string }): string =>\n `emt:processor:projector:${options.projectionName}`;\n\nexport const reactor = <\n MessageType extends Message = AnyMessage,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n MessagePayloadType extends Message = MessageType,\n>(\n options: ReactorOptions<\n MessageType,\n MessageMetadataType,\n HandlerContext,\n MessagePayloadType\n >,\n): MessageProcessor<MessageType, MessageMetadataType, HandlerContext> => {\n const {\n checkpoints,\n processorId,\n processorInstanceId: instanceId = getProcessorInstanceId(processorId),\n type = MessageProcessorType.REACTOR,\n version = defaultProcessorVersion,\n partition = defaultProcessorPartition,\n hooks = {},\n processingScope = defaultProcessingMessageProcessingScope,\n startFrom,\n canHandle,\n stopAfter,\n } = options;\n\n const eachMessage: SingleMessageHandlerWithContext<\n MessageType,\n MessageMetadataType,\n HandlerContext\n > =\n 'eachMessage' in options && options.eachMessage\n ? options.eachMessage\n : () => Promise.resolve();\n\n let isInitiated = false;\n let isActive = false;\n\n let lastCheckpoint: ProcessorCheckpoint | null = null;\n let closeSignal: (() => void) | null = null;\n\n const init = async (initOptions: Partial<HandlerContext>): Promise<void> => {\n if (isInitiated) return;\n\n if (hooks.onInit === undefined) {\n isInitiated = true;\n return;\n }\n\n return await processingScope(async (context) => {\n await hooks.onInit!(context);\n isInitiated = true;\n }, initOptions);\n };\n\n const close = async (\n closeOptions: Partial<HandlerContext>,\n ): Promise<void> => {\n // TODO: Align when active is set to false\n // if (!isActive) return;\n\n isActive = false;\n\n if (closeSignal) {\n closeSignal();\n closeSignal = null;\n }\n\n if (hooks.onClose) {\n await processingScope(hooks.onClose, closeOptions);\n }\n };\n\n return {\n // TODO: Consider whether not make it optional or add URN prefix\n id: processorId,\n instanceId,\n type,\n canHandle,\n init,\n start: async (\n startOptions: Partial<HandlerContext>,\n ): Promise<CurrentMessageProcessorPosition | undefined> => {\n if (isActive) return;\n\n await init(startOptions);\n\n isActive = true;\n\n closeSignal = onShutdown(() => close(startOptions));\n\n if (lastCheckpoint !== null)\n return {\n lastCheckpoint,\n };\n\n return await processingScope(async (context) => {\n if (hooks.onStart) {\n await hooks.onStart(context);\n }\n\n if (startFrom && startFrom !== 'CURRENT') return startFrom;\n\n if (checkpoints) {\n const readResult = await checkpoints?.read(\n {\n processorId: processorId,\n partition,\n },\n { ...startOptions, ...context },\n );\n lastCheckpoint = readResult.lastCheckpoint;\n }\n\n if (lastCheckpoint === null) return 'BEGINNING';\n\n return {\n lastCheckpoint,\n };\n }, startOptions);\n },\n close,\n get isActive() {\n return isActive;\n },\n handle: async (\n messages: RecordedMessage<MessageType, MessageMetadataType>[],\n partialContext: Partial<HandlerContext>,\n ): Promise<MessageHandlerResult> => {\n if (!isActive) return Promise.resolve();\n\n return await processingScope(async (context) => {\n let result: MessageHandlerResult = undefined;\n\n for (const message of messages) {\n if (wasMessageHandled(message, lastCheckpoint)) continue;\n\n const upcasted = upcastRecordedMessage(\n // TODO: Make it smarter\n message as unknown as RecordedMessage<\n MessagePayloadType,\n MessageMetadataType\n >,\n options.messageOptions?.schema?.versioning,\n );\n\n if (canHandle !== undefined && !canHandle.includes(upcasted.type))\n continue;\n\n const messageProcessingResult = await eachMessage(upcasted, context);\n\n if (checkpoints) {\n const storeCheckpointResult: StoreProcessorCheckpointResult =\n await checkpoints.store(\n {\n processorId,\n version,\n message: upcasted,\n lastCheckpoint,\n partition,\n },\n context,\n );\n\n if (storeCheckpointResult.success) {\n // TODO: Add correct handling of the storing checkpoint\n lastCheckpoint = storeCheckpointResult.newCheckpoint;\n }\n }\n\n if (\n messageProcessingResult &&\n messageProcessingResult.type === 'STOP'\n ) {\n isActive = false;\n result = messageProcessingResult;\n break;\n }\n\n if (stopAfter && stopAfter(upcasted)) {\n isActive = false;\n result = { type: 'STOP', reason: 'Stop condition reached' };\n break;\n }\n\n if (\n messageProcessingResult &&\n messageProcessingResult.type === 'SKIP'\n )\n continue;\n }\n\n return result;\n }, partialContext);\n },\n };\n};\n\nexport const projector = <\n EventType extends Event = Event,\n EventMetaDataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n HandlerContext extends DefaultRecord = DefaultRecord,\n EventPayloadType extends Event = EventType,\n>(\n options: ProjectorOptions<\n EventType,\n EventMetaDataType,\n HandlerContext,\n EventPayloadType\n >,\n): MessageProcessor<EventType, EventMetaDataType, HandlerContext> => {\n const {\n projection,\n processorId = getProjectorId({\n projectionName: projection.name ?? 'unknown',\n }),\n ...rest\n } = options;\n\n return reactor<\n EventType,\n EventMetaDataType,\n HandlerContext,\n EventPayloadType\n >({\n ...rest,\n type: MessageProcessorType.PROJECTOR,\n canHandle: projection.canHandle,\n processorId,\n messageOptions: options.projection.eventsOptions,\n hooks: {\n onInit: options.hooks?.onInit,\n onStart:\n (options.truncateOnStart && options.projection.truncate) ||\n options.hooks?.onStart\n ? async (context: HandlerContext) => {\n if (options.truncateOnStart && options.projection.truncate)\n await options.projection.truncate(context);\n\n if (options.hooks?.onStart) await options.hooks?.onStart(context);\n }\n : undefined,\n onClose: options.hooks?.onClose,\n },\n eachMessage: async (\n event: RecordedMessage<EventType, EventMetaDataType>,\n context: HandlerContext,\n ) => projection.handle([event], context),\n });\n};\n","import { getInMemoryDatabase, type InMemoryDatabase } from '../database';\nimport { EmmettError } from '../errors';\nimport type {\n AnyEvent,\n AnyMessage,\n BatchRecordedMessageHandlerWithContext,\n MessageHandlerResult,\n ReadEventMetadataWithGlobalPosition,\n SingleRecordedMessageHandlerWithContext,\n} from '../typing';\nimport type { MessageProcessor, ProcessorCheckpoint } from './processors';\nimport {\n getCheckpoint,\n projector,\n reactor,\n type Checkpointer,\n type MessageProcessingScope,\n type ProjectorOptions,\n type ReactorOptions,\n} from './processors';\n\nexport type InMemoryProcessorHandlerContext = {\n database: InMemoryDatabase;\n};\n\nexport type InMemoryProcessor<MessageType extends AnyMessage = AnyMessage> =\n MessageProcessor<\n MessageType,\n // TODO: generalize this to support other metadata types\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n > & { database: InMemoryDatabase };\n\nexport type InMemoryProcessorEachMessageHandler<\n MessageType extends AnyMessage = AnyMessage,\n> = SingleRecordedMessageHandlerWithContext<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n>;\n\nexport type InMemoryProcessorEachBatchHandler<\n MessageType extends AnyMessage = AnyMessage,\n> = BatchRecordedMessageHandlerWithContext<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n>;\n\nexport type InMemoryProcessorConnectionOptions = {\n database?: InMemoryDatabase;\n};\n\ntype CheckpointDocument = {\n _id: string;\n lastCheckpoint: ProcessorCheckpoint | null;\n};\n\nexport type InMemoryCheckpointer<MessageType extends AnyMessage = AnyMessage> =\n Checkpointer<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n >;\n\nexport const inMemoryCheckpointer = <\n MessageType extends AnyMessage = AnyMessage,\n>(): InMemoryCheckpointer<MessageType> => {\n return {\n read: async ({ processorId }, { database }) => {\n const checkpoint = await database\n .collection<CheckpointDocument>('emt_processor_checkpoints')\n .findOne((d) => d._id === processorId);\n\n return Promise.resolve({\n lastCheckpoint: checkpoint?.lastCheckpoint ?? null,\n });\n },\n store: async (context, { database }) => {\n const { message, processorId, lastCheckpoint } = context;\n const checkpoints = database.collection<CheckpointDocument>(\n 'emt_processor_checkpoints',\n );\n\n const checkpoint = await checkpoints.findOne(\n (d) => d._id === processorId,\n );\n\n const currentPosition = checkpoint?.lastCheckpoint ?? null;\n\n const newCheckpoint: ProcessorCheckpoint | null = getCheckpoint(message);\n\n if (\n currentPosition &&\n (currentPosition === newCheckpoint ||\n currentPosition !== lastCheckpoint)\n ) {\n return {\n success: false,\n reason:\n currentPosition === newCheckpoint\n ? 'IGNORED'\n : newCheckpoint !== null && currentPosition > newCheckpoint\n ? 'CURRENT_AHEAD'\n : 'MISMATCH',\n };\n }\n\n await checkpoints.handle(processorId, (existing) => ({\n ...(existing ?? {}),\n _id: processorId,\n lastCheckpoint: newCheckpoint,\n }));\n\n return { success: true, newCheckpoint };\n },\n };\n};\n\ntype InMemoryConnectionOptions = {\n connectionOptions?: InMemoryProcessorConnectionOptions;\n};\n\nexport type InMemoryReactorOptions<\n MessageType extends AnyMessage = AnyMessage,\n> = ReactorOptions<\n MessageType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n> &\n InMemoryConnectionOptions;\n\nexport type InMemoryProjectorOptions<EventType extends AnyEvent = AnyEvent> =\n ProjectorOptions<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n > &\n InMemoryConnectionOptions;\n\nexport type InMemoryProcessorOptions<\n MessageType extends AnyMessage = AnyMessage,\n> =\n | InMemoryReactorOptions<MessageType>\n | InMemoryProjectorOptions<MessageType & AnyEvent>;\n\nconst inMemoryProcessingScope = (options: {\n database: InMemoryDatabase | null;\n processorId: string;\n}): MessageProcessingScope<InMemoryProcessorHandlerContext> => {\n const processorDatabase = options.database;\n\n const processingScope: MessageProcessingScope<\n InMemoryProcessorHandlerContext\n > = <Result = MessageHandlerResult>(\n handler: (\n context: InMemoryProcessorHandlerContext,\n ) => Result | Promise<Result>,\n partialContext: Partial<InMemoryProcessorHandlerContext>,\n ) => {\n const database = processorDatabase ?? partialContext?.database;\n\n if (!database)\n throw new EmmettError(\n `InMemory processor '${options.processorId}' is missing database. Ensure that you passed it through options`,\n );\n\n return handler({ ...partialContext, database });\n };\n\n return processingScope;\n};\n\nexport const inMemoryProjector = <EventType extends AnyEvent = AnyEvent>(\n options: InMemoryProjectorOptions<EventType>,\n): InMemoryProcessor<EventType> => {\n const database = options.connectionOptions?.database ?? getInMemoryDatabase();\n\n const hooks = {\n onInit: options.hooks?.onInit,\n onStart: options.hooks?.onStart,\n onClose: options.hooks?.onClose\n ? async (context: InMemoryProcessorHandlerContext) => {\n if (options.hooks?.onClose) await options.hooks?.onClose(context);\n }\n : undefined,\n };\n\n const processor = projector<\n EventType,\n ReadEventMetadataWithGlobalPosition,\n InMemoryProcessorHandlerContext\n >({\n ...options,\n hooks,\n processingScope: inMemoryProcessingScope({\n database,\n processorId:\n options.processorId ?? `projection:${options.projection.name}`,\n }),\n checkpoints: inMemoryCheckpointer<EventType>(),\n });\n\n return Object.assign(processor, { database });\n};\n\nexport const inMemoryReactor = <MessageType extends AnyMessage = AnyMessage>(\n options: InMemoryReactorOptions<MessageType>,\n): InMemoryProcessor<MessageType> => {\n const database = options.connectionOptions?.database ?? getInMemoryDatabase();\n\n const hooks = {\n onInit: options.hooks?.onInit,\n onStart: options.hooks?.onStart,\n onClose: options.hooks?.onClose,\n };\n\n const processor = reactor({\n ...options,\n hooks,\n processingScope: inMemoryProcessingScope({\n database,\n processorId: options.processorId,\n }),\n checkpoints: inMemoryCheckpointer<MessageType>(),\n });\n\n return Object.assign(processor, { database });\n};\n","import type { InMemoryDatabase } from '../../../database/inMemoryDatabase';\nimport type {\n ProjectionDefinition,\n TruncateProjection,\n} from '../../../projections';\nimport type { CanHandle, Event, ReadEvent } from '../../../typing';\nimport type {\n InMemoryProjectionHandlerContext,\n InMemoryReadEventMetadata,\n} from '../../inMemoryEventStore';\n\nexport const DATABASE_REQUIRED_ERROR_MESSAGE =\n 'Database is required in context for InMemory projections';\n\nexport type InMemoryProjectionDefinition<EventType extends Event> =\n ProjectionDefinition<\n EventType,\n InMemoryReadEventMetadata,\n InMemoryProjectionHandlerContext\n >;\n\nexport type InMemoryProjectionHandlerOptions<EventType extends Event = Event> =\n {\n projections: InMemoryProjectionDefinition<EventType>[];\n events: ReadEvent<EventType, InMemoryReadEventMetadata>[];\n database: InMemoryDatabase;\n eventStore?: InMemoryProjectionHandlerContext['eventStore'];\n };\n\n/**\n * Handles projections for the InMemoryEventStore\n * Similar to the PostgreSQL implementation, this processes events through projections\n */\nexport const handleInMemoryProjections = async <\n EventType extends Event = Event,\n>(\n options: InMemoryProjectionHandlerOptions<EventType>,\n): Promise<void> => {\n const { projections, events, database, eventStore } = options;\n\n // Get all event types from the events batch to filter projections\n const eventTypes = events.map((e) => e.type);\n\n // Filter projections that can handle these event types\n const relevantProjections = projections.filter((p) =>\n p.canHandle.some((type) => eventTypes.includes(type)),\n );\n\n // Process each projection\n for (const projection of relevantProjections) {\n await projection.handle(events, {\n eventStore,\n database,\n });\n }\n};\n\nexport type InMemoryWithNotNullDocumentEvolve<\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n> = (\n document: DocumentType,\n event: ReadEvent<EventType, InMemoryReadEventMetadata>,\n) => DocumentType | null;\n\nexport type InMemoryWithNullableDocumentEvolve<\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n> = (\n document: DocumentType | null,\n event: ReadEvent<EventType, InMemoryReadEventMetadata>,\n) => DocumentType | null;\n\nexport type InMemoryDocumentEvolve<\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n> =\n | InMemoryWithNotNullDocumentEvolve<DocumentType, EventType>\n | InMemoryWithNullableDocumentEvolve<DocumentType, EventType>;\n\nexport type InMemoryProjectionOptions<EventType extends Event> = {\n handle: (\n events: ReadEvent<EventType, InMemoryReadEventMetadata>[],\n context: InMemoryProjectionHandlerContext & { database: InMemoryDatabase },\n ) => Promise<void>;\n canHandle: CanHandle<EventType>;\n truncate?: TruncateProjection<\n InMemoryProjectionHandlerContext & { database: InMemoryDatabase }\n >;\n};\n\n/**\n * Creates an InMemory projection\n */\nexport const inMemoryProjection = <EventType extends Event>({\n truncate,\n handle,\n canHandle,\n}: InMemoryProjectionOptions<EventType>): InMemoryProjectionDefinition<EventType> => ({\n canHandle,\n handle: async (events, context) => {\n if (!context.database) {\n throw new Error(DATABASE_REQUIRED_ERROR_MESSAGE);\n }\n await handle(events, {\n ...context,\n database: context.database,\n });\n },\n truncate: truncate\n ? (context) => {\n if (!context.database) {\n throw new Error(DATABASE_REQUIRED_ERROR_MESSAGE);\n }\n return truncate({\n ...context,\n database: context.database,\n });\n }\n : undefined,\n});\n\n/**\n * Creates a multi-stream projection for InMemoryDatabase\n */\nexport type InMemoryMultiStreamProjectionOptions<\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n> = {\n canHandle: CanHandle<EventType>;\n collectionName: string;\n getDocumentId: (event: ReadEvent<EventType>) => string;\n} & (\n | {\n evolve: InMemoryWithNullableDocumentEvolve<DocumentType, EventType>;\n }\n | {\n evolve: InMemoryWithNotNullDocumentEvolve<DocumentType, EventType>;\n initialState: () => DocumentType;\n }\n);\n\n/**\n * Creates a projection that handles events across multiple streams\n */\nexport const inMemoryMultiStreamProjection = <\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n>(\n options: InMemoryMultiStreamProjectionOptions<DocumentType, EventType>,\n): InMemoryProjectionDefinition<EventType> => {\n const { collectionName, getDocumentId, canHandle } = options;\n\n return inMemoryProjection({\n handle: async (\n events: ReadEvent<EventType, InMemoryReadEventMetadata>[],\n { database },\n ) => {\n const collection = database.collection<DocumentType>(collectionName);\n\n for (const event of events) {\n await collection.handle(getDocumentId(event), (document) => {\n if ('initialState' in options) {\n return options.evolve(document ?? options.initialState(), event);\n } else {\n return options.evolve(document, event);\n }\n });\n }\n },\n canHandle,\n truncate: async ({\n database,\n }: InMemoryProjectionHandlerContext & { database: InMemoryDatabase }) => {\n // For InMemory database, we can't directly truncate a collection\n // So we'll delete all documents from the collection\n const collection = database.collection<DocumentType>(collectionName);\n const documents = await collection.find();\n\n for (const doc of documents) {\n if (doc && '_id' in doc) {\n const id = doc._id;\n await collection.deleteOne((d) => d._id === id);\n }\n }\n },\n });\n};\n\n/**\n * Creates a single-stream projection for InMemoryDatabase\n */\nexport type InMemorySingleStreamProjectionOptions<\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n> = {\n canHandle: CanHandle<EventType>;\n getDocumentId?: (event: ReadEvent<EventType>) => string;\n collectionName: string;\n} & (\n | {\n evolve: InMemoryWithNullableDocumentEvolve<DocumentType, EventType>;\n }\n | {\n evolve: InMemoryWithNotNullDocumentEvolve<DocumentType, EventType>;\n initialState: () => DocumentType;\n }\n);\n\n/**\n * Creates a projection that handles events from a single stream\n */\nexport const inMemorySingleStreamProjection = <\n DocumentType extends Record<string, unknown>,\n EventType extends Event,\n>(\n options: InMemorySingleStreamProjectionOptions<DocumentType, EventType>,\n): InMemoryProjectionDefinition<EventType> => {\n return inMemoryMultiStreamProjection<DocumentType, EventType>({\n ...options,\n getDocumentId:\n options.getDocumentId ?? ((event) => event.metadata.streamName),\n });\n};\n","import { v4 as uuid } from 'uuid';\nimport {\n handleInMemoryProjections,\n type InMemoryProjectionDefinition,\n} from '.';\nimport { bigIntProcessorCheckpoint } from '../../..';\nimport {\n getInMemoryDatabase,\n type Document,\n type InMemoryDatabase,\n} from '../../../database';\nimport { isErrorConstructor } from '../../../errors';\nimport { JSONSerializer } from '../../../serialization';\nimport {\n assertFails,\n AssertionError,\n assertTrue,\n type ThenThrows,\n} from '../../../testing';\nimport type {\n CombinedReadEventMetadata,\n Event,\n ReadEvent,\n} from '../../../typing';\nimport type {\n InMemoryEventStore,\n InMemoryReadEventMetadata,\n} from '../../inMemoryEventStore';\n\n// Define a more specific type for T that extends Document\ntype DocumentWithId = Document & { _id?: string | number };\n\nexport type InMemoryProjectionSpecEvent<\n EventType extends Event,\n EventMetaDataType extends InMemoryReadEventMetadata =\n InMemoryReadEventMetadata,\n> = EventType & {\n metadata?: Partial<EventMetaDataType>;\n};\n\nexport type InMemoryProjectionSpecWhenOptions = { numberOfTimes: number };\n\nexport type InMemoryProjectionSpec<EventType extends Event> = (\n givenEvents: InMemoryProjectionSpecEvent<EventType>[],\n) => {\n when: (\n events: InMemoryProjectionSpecEvent<EventType>[],\n options?: InMemoryProjectionSpecWhenOptions,\n ) => {\n then: (assert: InMemoryProjectionAssert, message?: string) => Promise<void>;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => Promise<void>;\n };\n};\n\nexport type InMemoryProjectionAssert = (options: {\n database: InMemoryDatabase;\n}) => Promise<void | boolean>;\n\nexport type InMemoryProjectionSpecOptions<EventType extends Event> = {\n projection: InMemoryProjectionDefinition<EventType>;\n};\n\nexport const InMemoryProjectionSpec = {\n for: <EventType extends Event>(\n options: InMemoryProjectionSpecOptions<EventType>,\n ): InMemoryProjectionSpec<EventType> => {\n const { projection } = options;\n\n return (givenEvents: InMemoryProjectionSpecEvent<EventType>[]) => {\n return {\n when: (\n events: InMemoryProjectionSpecEvent<EventType>[],\n options?: InMemoryProjectionSpecWhenOptions,\n ) => {\n const allEvents: ReadEvent<EventType, InMemoryReadEventMetadata>[] =\n [];\n\n const run = async (database: InMemoryDatabase) => {\n let globalPosition = 0n;\n const numberOfTimes = options?.numberOfTimes ?? 1;\n\n for (const event of [\n ...givenEvents,\n ...Array.from({ length: numberOfTimes }).flatMap(() => events),\n ]) {\n const metadata: InMemoryReadEventMetadata = {\n checkpoint: bigIntProcessorCheckpoint(++globalPosition),\n globalPosition,\n streamPosition: globalPosition,\n streamName: event.metadata?.streamName ?? `test-${uuid()}`,\n messageId: uuid(),\n };\n\n allEvents.push({\n ...event,\n kind: 'Event',\n metadata: {\n ...metadata,\n ...('metadata' in event ? (event.metadata ?? {}) : {}),\n } as CombinedReadEventMetadata<\n EventType,\n InMemoryReadEventMetadata\n >,\n });\n }\n\n // Create a minimal mock EventStore implementation\n const mockEventStore = {\n database,\n aggregateStream: async () => {\n return Promise.resolve({\n state: {},\n currentStreamVersion: 0n,\n streamExists: false,\n });\n },\n readStream: async () => {\n return Promise.resolve({\n events: [],\n currentStreamVersion: 0n,\n streamExists: false,\n });\n },\n appendToStream: async () => {\n return Promise.resolve({\n nextExpectedStreamVersion: 0n,\n createdNewStream: false,\n });\n },\n streamExists: async () => {\n return Promise.resolve(false);\n },\n } as InMemoryEventStore;\n\n await handleInMemoryProjections({\n events: allEvents,\n projections: [projection],\n database,\n eventStore: mockEventStore,\n });\n };\n\n return {\n then: async (\n assertFn: InMemoryProjectionAssert,\n message?: string,\n ): Promise<void> => {\n const database = getInMemoryDatabase();\n await run(database);\n\n const succeeded = await assertFn({ database });\n\n if (succeeded !== undefined && succeeded === false) {\n assertFails(\n message ??\n \"Projection specification didn't match the criteria\",\n );\n }\n },\n thenThrows: async <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): Promise<void> => {\n const database = getInMemoryDatabase();\n try {\n await run(database);\n throw new AssertionError('Handler did not fail as expected');\n } catch (error) {\n if (error instanceof AssertionError) throw error;\n\n if (args.length === 0) return;\n\n if (!isErrorConstructor(args[0])) {\n assertTrue(\n args[0](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n return;\n }\n\n assertTrue(\n error instanceof args[0],\n `Caught error is not an instance of the expected type: ${error?.toString()}`,\n );\n\n if (args[1]) {\n assertTrue(\n args[1](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n }\n }\n },\n };\n },\n };\n };\n },\n};\n\n// Helper functions for creating events in stream\nexport const eventInStream = <\n EventType extends Event = Event,\n EventMetaDataType extends InMemoryReadEventMetadata =\n InMemoryReadEventMetadata,\n>(\n streamName: string,\n event: InMemoryProjectionSpecEvent<EventType, EventMetaDataType>,\n): InMemoryProjectionSpecEvent<EventType, EventMetaDataType> => {\n return {\n ...event,\n metadata: {\n ...(event.metadata ?? {}),\n streamName: event.metadata?.streamName ?? streamName,\n } as Partial<EventMetaDataType>,\n };\n};\n\nexport const eventsInStream = <\n EventType extends Event = Event,\n EventMetaDataType extends InMemoryReadEventMetadata =\n InMemoryReadEventMetadata,\n>(\n streamName: string,\n events: InMemoryProjectionSpecEvent<EventType, EventMetaDataType>[],\n): InMemoryProjectionSpecEvent<EventType, EventMetaDataType>[] => {\n return events.map((e) => eventInStream(streamName, e));\n};\n\nexport const newEventsInStream = eventsInStream;\n\n// Assertion helpers for checking documents\nexport function documentExists<T extends DocumentWithId>(\n expected: Partial<T>,\n options: { inCollection: string; withId: string | number },\n): InMemoryProjectionAssert {\n return async ({ database }) => {\n const collection = database.collection<T>(options.inCollection);\n\n const document = await collection.findOne((doc) => {\n // Handle both string IDs and numeric IDs in a type-safe way\n const docId = '_id' in doc ? doc._id : undefined;\n return docId === options.withId;\n });\n\n if (!document) {\n assertFails(\n `Document with ID ${options.withId} does not exist in collection ${options.inCollection}`,\n );\n return Promise.resolve(false);\n }\n\n // Check that all expected properties exist with expected values\n for (const [key, value] of Object.entries(expected)) {\n const propKey = key as keyof typeof document;\n if (\n !(key in document) ||\n JSONSerializer.serialize(document[propKey]) !==\n JSONSerializer.serialize(value)\n ) {\n assertFails(`Property ${key} doesn't match the expected value`);\n return Promise.resolve(false);\n }\n }\n\n return Promise.resolve(true);\n };\n}\n\n// Helper for checking document contents\nexport const expectInMemoryDocuments = {\n fromCollection: <T extends DocumentWithId>(collectionName: string) => ({\n withId: (id: string | number) => ({\n toBeEqual: (expected: Partial<T>): InMemoryProjectionAssert =>\n documentExists<T>(expected, {\n inCollection: collectionName,\n withId: id,\n }),\n }),\n }),\n};\n","import { JSONSerializer } from '../serialization';\nimport type { DefaultRecord } from '../typing';\nimport { deepEquals } from '../utils';\n\nexport class AssertionError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n\nexport const isSubset = (superObj: unknown, subObj: unknown): boolean => {\n const sup = superObj as DefaultRecord;\n const sub = subObj as DefaultRecord;\n\n assertOk(sup);\n assertOk(sub);\n\n return Object.keys(sub).every((ele: string) => {\n if (sub[ele] !== null && typeof sub[ele] == 'object') {\n return isSubset(sup[ele], sub[ele]);\n }\n return sub[ele] === sup[ele];\n });\n};\n\nexport const assertFails = (message?: string) => {\n throw new AssertionError(message ?? 'That should not ever happened, right?');\n};\n\nexport const assertThrowsAsync = async <TError extends Error>(\n fun: () => Promise<unknown>,\n errorCheck?: (error: Error) => boolean,\n): Promise<TError> => {\n try {\n await fun();\n } catch (error) {\n const typedError = error as TError;\n if (typedError instanceof AssertionError || !errorCheck) {\n assertFalse(\n typedError instanceof AssertionError,\n \"Function didn't throw expected error\",\n );\n return typedError;\n }\n\n assertTrue(\n errorCheck(typedError),\n `Error doesn't match the expected condition: ${JSONSerializer.serialize(error)}`,\n );\n\n return typedError;\n }\n throw new AssertionError(\"Function didn't throw expected error\");\n};\n\nexport const assertThrows = <TError extends Error>(\n fun: () => void,\n errorCheck?: (error: Error) => boolean,\n): TError => {\n try {\n fun();\n } catch (error) {\n const typedError = error as TError;\n\n if (errorCheck) {\n assertTrue(\n errorCheck(typedError),\n `Error doesn't match the expected condition: ${JSONSerializer.serialize(error)}`,\n );\n } else if (typedError instanceof AssertionError) {\n assertFalse(\n typedError instanceof AssertionError,\n \"Function didn't throw expected error\",\n );\n }\n\n return typedError;\n }\n throw new AssertionError(\"Function didn't throw expected error\");\n};\n\nexport const assertDoesNotThrow = <TError extends Error>(\n fun: () => void,\n errorCheck?: (error: Error) => boolean,\n): TError | null => {\n try {\n fun();\n return null;\n } catch (error) {\n const typedError = error as TError;\n\n if (errorCheck) {\n assertFalse(\n errorCheck(typedError),\n `Error matching the expected condition was thrown!: ${JSONSerializer.serialize(error)}`,\n );\n } else {\n assertFails(\n `Function threw an error: ${JSONSerializer.serialize(error)}`,\n );\n }\n\n return typedError;\n }\n};\n\nexport const assertRejects = async <T, TError extends Error = Error>(\n promise: Promise<T>,\n errorCheck?: ((error: TError) => boolean) | TError,\n) => {\n try {\n await promise;\n throw new AssertionError(\"Function didn't throw expected error\");\n } catch (error) {\n if (!errorCheck) return;\n\n if (errorCheck instanceof Error) assertDeepEqual(error, errorCheck);\n else assertTrue(errorCheck(error as TError));\n }\n};\n\nexport const assertMatches = (\n actual: unknown,\n expected: unknown,\n message?: string,\n) => {\n if (!isSubset(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONSerializer.serialize(expected)}\\nis not subset of\\n${JSONSerializer.serialize(actual)}`,\n );\n};\n\nexport const assertDeepEqual = <T = unknown>(\n actual: T,\n expected: T,\n message?: string,\n) => {\n if (!deepEquals(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONSerializer.serialize(expected)}\\nis not equal to\\n${JSONSerializer.serialize(actual)}`,\n );\n};\n\nexport const assertNotDeepEqual = <T = unknown>(\n actual: T,\n expected: T,\n message?: string,\n) => {\n if (deepEquals(actual, expected))\n throw new AssertionError(\n message ??\n `subObj:\\n${JSONSerializer.serialize(expected)}\\nis equals to\\n${JSONSerializer.serialize(actual)}`,\n );\n};\n\nexport const assertThat = <T>(item: T) => {\n return {\n isEqualTo: (other: T) => assertTrue(deepEquals(item, other)),\n };\n};\n\nexport const assertDefined = (\n value: unknown,\n message?: string | Error,\n): asserts value => {\n assertOk(value, message instanceof Error ? message.message : message);\n};\n\nexport function assertFalse(\n condition: boolean,\n message?: string,\n): asserts condition is false {\n if (condition !== false)\n throw new AssertionError(message ?? `Condition is true`);\n}\n\nexport function assertTrue(\n condition: boolean,\n message?: string,\n): asserts condition is true {\n if (condition !== true)\n throw new AssertionError(message ?? `Condition is false`);\n}\n\n// TODO: replace with assertDefined\nexport function assertOk<T>(\n obj: T | null | undefined,\n message?: string,\n): asserts obj is T {\n if (!obj) throw new AssertionError(message ?? `Condition is not truthy`);\n}\n\nexport function assertEqual<T>(\n expected: T | null | undefined,\n actual: T | null | undefined,\n message?: string,\n): void {\n if (expected !== actual)\n throw new AssertionError(\n `${message ?? 'Objects are not equal'}:\\nExpected: ${JSONSerializer.serialize(expected)}\\nActual: ${JSONSerializer.serialize(actual)}`,\n );\n}\n\nexport function assertNotEqual<T>(\n obj: T | null | undefined,\n other: T | null | undefined,\n message?: string,\n): void {\n if (obj === other)\n throw new AssertionError(\n message ?? `Objects are equal: ${JSONSerializer.serialize(obj)}`,\n );\n}\n\nexport function assertIsNotNull<T extends object | bigint>(\n result: T | null,\n): asserts result is T {\n assertNotEqual(result, null);\n assertOk(result);\n}\n\nexport function assertIsNull<T extends object>(\n result: T | null,\n): asserts result is null {\n assertEqual(result, null);\n}\n\ntype Call = {\n arguments: unknown[];\n result: unknown;\n target: unknown;\n this: unknown;\n};\n\nexport type ArgumentMatcher = (arg: unknown) => boolean;\n\nexport const argValue =\n <T>(value: T): ArgumentMatcher =>\n (arg) =>\n deepEquals(arg, value);\n\nexport const argMatches =\n <T>(matches: (arg: T) => boolean): ArgumentMatcher =>\n (arg) =>\n matches(arg as T);\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport type MockedFunction = Function & { mock?: { calls: Call[] } };\n\nexport function verifyThat(fn: MockedFunction) {\n return {\n calledTimes: (times: number) => {\n assertEqual(fn.mock?.calls?.length, times);\n },\n notCalled: () => {\n assertEqual(fn?.mock?.calls?.length, 0);\n },\n called: () => {\n assertTrue(\n fn.mock?.calls.length !== undefined && fn.mock.calls.length > 0,\n );\n },\n calledWith: (...args: unknown[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls.some((call) => deepEquals(call.arguments, args)),\n );\n },\n calledOnceWith: (...args: unknown[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length === 1 &&\n fn.mock.calls.some((call) => deepEquals(call.arguments, args)),\n );\n },\n calledWithArgumentMatching: (...matches: ArgumentMatcher[]) => {\n assertTrue(\n fn.mock?.calls.length !== undefined && fn.mock.calls.length >= 1,\n );\n assertTrue(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls.some(\n (call) =>\n call.arguments &&\n call.arguments.length >= matches.length &&\n matches.every((match, index) => match(call.arguments[index])),\n ),\n );\n },\n notCalledWithArgumentMatching: (...matches: ArgumentMatcher[]) => {\n assertFalse(\n fn.mock?.calls.length !== undefined &&\n fn.mock.calls.length >= 1 &&\n fn.mock.calls[0]!.arguments &&\n fn.mock.calls[0]!.arguments.length >= matches.length &&\n matches.every((match, index) =>\n match(fn.mock!.calls[0]!.arguments[index]),\n ),\n );\n },\n };\n}\n\nexport const assertThatArray = <T>(array: T[]) => {\n return {\n isEmpty: () =>\n assertEqual(\n array.length,\n 0,\n `Array is not empty ${JSONSerializer.serialize(array)}`,\n ),\n isNotEmpty: () => assertNotEqual(array.length, 0, `Array is empty`),\n hasSize: (length: number) => assertEqual(array.length, length),\n containsElements: (other: T[]) => {\n assertTrue(other.every((ts) => array.some((o) => deepEquals(ts, o))));\n },\n containsElementsMatching: (other: T[]) => {\n assertTrue(other.every((ts) => array.some((o) => isSubset(o, ts))));\n },\n containsOnlyElementsMatching: (other: T[]) => {\n assertEqual(array.length, other.length, `Arrays lengths don't match`);\n assertTrue(other.every((ts) => array.some((o) => isSubset(o, ts))));\n },\n containsExactlyInAnyOrder: (other: T[]) => {\n assertEqual(array.length, other.length);\n assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyInAnyOrderElementsOf: (other: T[]) => {\n assertEqual(array.length, other.length);\n assertTrue(array.every((ts) => other.some((o) => deepEquals(ts, o))));\n },\n containsExactlyElementsOf: (other: T[]) => {\n assertEqual(array.length, other.length);\n for (let i = 0; i < array.length; i++) {\n assertTrue(deepEquals(array[i], other[i]));\n }\n },\n containsExactly: (elem: T) => {\n assertEqual(array.length, 1);\n assertTrue(deepEquals(array[0], elem));\n },\n contains: (elem: T) => {\n assertTrue(array.some((a) => deepEquals(a, elem)));\n },\n containsOnlyOnceElementsOf: (other: T[]) => {\n assertTrue(\n other\n .map((o) => array.filter((a) => deepEquals(a, o)).length)\n .filter((a) => a === 1).length === other.length,\n );\n },\n containsAnyOf: (other: T[]) => {\n assertTrue(array.some((a) => other.some((o) => deepEquals(a, o))));\n },\n allMatch: (matches: (item: T) => boolean) => {\n assertTrue(array.every(matches));\n },\n anyMatches: (matches: (item: T) => boolean) => {\n assertTrue(array.some(matches));\n },\n allMatchAsync: async (\n matches: (item: T) => Promise<boolean>,\n ): Promise<void> => {\n for (const item of array) {\n assertTrue(await matches(item));\n }\n },\n };\n};\n","import { isErrorConstructor, type ErrorConstructor } from '../errors';\nimport { AssertionError, assertThatArray, assertTrue } from './assertions';\n\ntype ErrorCheck<ErrorType> = (error: ErrorType) => boolean;\n\nexport type ThenThrows<ErrorType extends Error> =\n | (() => void)\n | ((errorConstructor: ErrorConstructor<ErrorType>) => void)\n | ((errorCheck: ErrorCheck<ErrorType>) => void)\n | ((\n errorConstructor: ErrorConstructor<ErrorType>,\n errorCheck?: ErrorCheck<ErrorType>,\n ) => void);\n\nexport type DeciderSpecification<Command, Event> = (\n givenEvents: Event | Event[],\n) => {\n when: (command: Command) => {\n then: (expectedEvents: Event | Event[]) => void;\n thenNothingHappened: () => void;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => void;\n };\n};\nexport type AsyncDeciderSpecification<Command, Event> = (\n givenEvents: Event | Event[],\n) => {\n when: (command: Command) => {\n then: (expectedEvents: Event | Event[]) => Promise<void>;\n thenNothingHappened: () => Promise<void>;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => Promise<void>;\n };\n};\n\nexport const DeciderSpecification = {\n for: deciderSpecificationFor,\n};\n\nfunction deciderSpecificationFor<Command, Event, State>(decider: {\n decide: (command: Command, state: State) => Event | Event[];\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n}): DeciderSpecification<Command, Event>;\nfunction deciderSpecificationFor<Command, Event, State>(decider: {\n decide: (command: Command, state: State) => Promise<Event | Event[]>;\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n}): AsyncDeciderSpecification<Command, Event>;\nfunction deciderSpecificationFor<Command, Event, State>(decider: {\n decide: (\n command: Command,\n state: State,\n ) => Event | Event[] | Promise<Event | Event[]>;\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n}):\n | DeciderSpecification<Command, Event>\n | AsyncDeciderSpecification<Command, Event> {\n {\n return (givenEvents: Event | Event[]) => {\n return {\n when: (command: Command) => {\n const handle = () => {\n const existingEvents = Array.isArray(givenEvents)\n ? givenEvents\n : [givenEvents];\n\n const currentState = existingEvents.reduce<State>(\n decider.evolve,\n decider.initialState(),\n );\n\n return decider.decide(command, currentState);\n };\n\n return {\n then: (expectedEvents: Event | Event[]): void | Promise<void> => {\n const resultEvents = handle();\n\n if (resultEvents instanceof Promise) {\n return resultEvents.then((events) => {\n thenHandler(events, expectedEvents);\n });\n }\n\n thenHandler(resultEvents, expectedEvents);\n },\n thenNothingHappened: (): void | Promise<void> => {\n const resultEvents = handle();\n\n if (resultEvents instanceof Promise) {\n return resultEvents.then((events) => {\n thenNothingHappensHandler(events);\n });\n }\n\n thenNothingHappensHandler(resultEvents);\n },\n thenThrows: <ErrorType extends Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): void | Promise<void> => {\n try {\n const result = handle();\n if (result instanceof Promise) {\n return result\n .then(() => {\n throw new AssertionError(\n 'Handler did not fail as expected',\n );\n })\n .catch((error) => {\n thenThrowsErrorHandler(error, args);\n });\n }\n throw new AssertionError('Handler did not fail as expected');\n } catch (error) {\n thenThrowsErrorHandler(error, args);\n }\n },\n };\n },\n };\n };\n }\n}\n\nfunction thenHandler<Event>(\n events: Event | Event[],\n expectedEvents: Event | Event[],\n): void {\n const resultEventsArray = Array.isArray(events) ? events : [events];\n\n const expectedEventsArray = Array.isArray(expectedEvents)\n ? expectedEvents\n : [expectedEvents];\n\n assertThatArray(resultEventsArray).containsOnlyElementsMatching(\n expectedEventsArray,\n );\n}\n\nfunction thenNothingHappensHandler<Event>(events: Event | Event[]): void {\n const resultEventsArray = Array.isArray(events) ? events : [events];\n assertThatArray(resultEventsArray).isEmpty();\n}\n\nfunction thenThrowsErrorHandler<ErrorType extends Error>(\n error: unknown,\n args: Parameters<ThenThrows<ErrorType>>,\n): void {\n if (error instanceof AssertionError) throw error;\n\n if (args.length === 0) return;\n\n if (!isErrorConstructor(args[0])) {\n assertTrue(\n args[0](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n return;\n }\n\n assertTrue(\n error instanceof args[0],\n `Caught error is not an instance of the expected type: ${error?.toString()}`,\n );\n\n if (args[1]) {\n assertTrue(\n args[1](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n }\n}\n","import { isErrorConstructor } from '../errors';\nimport type { AnyCommand } from '../typing/command';\nimport type { AnyEvent } from '../typing/event';\nimport type { Workflow, WorkflowEvent } from '../workflows/workflow';\nimport { AssertionError, assertThatArray, assertTrue } from './assertions';\nimport type { ThenThrows } from './deciderSpecification';\n\nexport type WorkflowSpecification<\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n> = (\n givenEvents: WorkflowEvent<Input | Output> | WorkflowEvent<Input | Output>[],\n) => {\n when: (input: Input) => {\n then: (expectedOutput: Output | Output[]) => void;\n thenNothingHappened: () => void;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => void;\n };\n};\n\nexport const WorkflowSpecification = {\n for: workflowSpecificationFor,\n};\n\nfunction workflowSpecificationFor<\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n>(\n workflow: Workflow<Input, State, Output>,\n): WorkflowSpecification<Input, Output> {\n return (\n givenEvents:\n | WorkflowEvent<Input | Output>\n | WorkflowEvent<Input | Output>[],\n ) => {\n return {\n when: (input: Input) => {\n const handle = () => {\n const existingEvents = Array.isArray(givenEvents)\n ? givenEvents\n : [givenEvents];\n\n const currentState = existingEvents.reduce<State>(\n workflow.evolve,\n workflow.initialState(),\n );\n\n return workflow.decide(input, currentState);\n };\n\n return {\n then: (expectedOutput: Output | Output[]): void => {\n const result = handle();\n thenHandler(result, expectedOutput);\n },\n thenNothingHappened: (): void => {\n const result = handle();\n thenNothingHappensHandler(result);\n },\n thenThrows: <ErrorType extends Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): void => {\n try {\n handle();\n throw new AssertionError('Handler did not fail as expected');\n } catch (error) {\n thenThrowsErrorHandler(error, args);\n }\n },\n };\n },\n };\n };\n}\n\nfunction thenHandler<Output>(\n result: Output | Output[],\n expectedOutput: Output | Output[],\n): void {\n const resultArray = Array.isArray(result) ? result : [result];\n const expectedArray = Array.isArray(expectedOutput)\n ? expectedOutput\n : [expectedOutput];\n\n assertThatArray(resultArray).containsOnlyElementsMatching(expectedArray);\n}\n\nfunction thenNothingHappensHandler<Output>(result: Output | Output[]): void {\n const resultArray = Array.isArray(result) ? result : [result];\n assertThatArray(resultArray).isEmpty();\n}\n\nfunction thenThrowsErrorHandler<ErrorType extends Error>(\n error: unknown,\n args: Parameters<ThenThrows<ErrorType>>,\n): void {\n if (error instanceof AssertionError) throw error;\n\n if (args.length === 0) return;\n\n if (!isErrorConstructor(args[0])) {\n assertTrue(\n args[0](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n return;\n }\n\n assertTrue(\n error instanceof args[0],\n `Caught error is not an instance of the expected type: ${error?.toString()}`,\n );\n\n if (args[1]) {\n assertTrue(\n args[1](error as ErrorType),\n `Error didn't match the error condition: ${error?.toString()}`,\n );\n }\n}\n","import type {\n AggregateStreamOptions,\n AggregateStreamResult,\n AppendToStreamOptions,\n AppendToStreamResult,\n EventStore,\n EventStoreReadEventMetadata,\n ReadStreamOptions,\n ReadStreamResult,\n} from '../eventStore';\nimport type { Event, EventMetaDataOf } from '../typing';\n\nexport type TestEventStream<EventType extends Event = Event> = [\n string,\n EventType[],\n];\n\nexport type EventStoreWrapper<Store extends EventStore> = Store & {\n appendedEvents: Map<string, TestEventStream>;\n setup<EventType extends Event>(\n streamName: string,\n events: EventType[],\n ): Promise<AppendToStreamResult>;\n};\n\nexport const WrapEventStore = <Store extends EventStore>(\n eventStore: Store,\n): EventStoreWrapper<Store> => {\n const appendedEvents = new Map<string, TestEventStream>();\n\n const wrapped = {\n ...eventStore,\n aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State>> {\n return eventStore.aggregateStream(streamName, options);\n },\n\n async readStream<EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions<EventType>,\n ): Promise<\n ReadStreamResult<\n EventType,\n EventStoreReadEventMetadata<Store> & EventMetaDataOf<EventType>\n >\n > {\n return (await eventStore.readStream(\n streamName,\n options,\n )) as ReadStreamResult<\n EventType,\n EventStoreReadEventMetadata<Store> & EventMetaDataOf<EventType>\n >;\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType>,\n ): Promise<AppendToStreamResult> => {\n const result = await eventStore.appendToStream(\n streamName,\n events,\n options,\n );\n\n const currentStream = appendedEvents.get(streamName) ?? [streamName, []];\n\n appendedEvents.set(streamName, [\n streamName,\n [...currentStream[1], ...events],\n ]);\n\n return result;\n },\n\n appendedEvents,\n\n setup: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n ): Promise<AppendToStreamResult> => {\n return eventStore.appendToStream(streamName, events);\n },\n\n // streamEvents: (): ReadableStream<\n // // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\n // ReadEvent<Event, ReadEventMetadataType> | GlobalSubscriptionEvent\n // > => {\n // return eventStore.streamEvents();\n // },\n };\n\n return wrapped as EventStoreWrapper<Store>;\n};\n","import type {\n AnyMessage,\n AnyRecordedMessageMetadata,\n RecordedMessage,\n} from '../../typing';\n\nexport type MessageDowncast<\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n> =\n | ((\n message: RecordedMessage<MessageType, RecordedMessageMetadataType>,\n ) => RecordedMessage<MessagePayloadType, RecordedMessageMetadataType>)\n | ((message: MessageType) => MessagePayloadType);\n\nexport const downcastRecordedMessage = <\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n>(\n recordedMessage:\n | RecordedMessage<MessageType, RecordedMessageMetadataType>\n | MessageType,\n options?: {\n downcast?: MessageDowncast<\n MessageType,\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n },\n): RecordedMessage<MessagePayloadType, RecordedMessageMetadataType> => {\n if (!options?.downcast)\n return recordedMessage as unknown as RecordedMessage<\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n\n const downcasted = options.downcast(\n recordedMessage as RecordedMessage<\n MessageType,\n RecordedMessageMetadataType\n >,\n );\n\n return {\n ...recordedMessage,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n data: downcasted.data,\n ...('metadata' in recordedMessage || 'metadata' in downcasted\n ? {\n metadata: {\n ...('metadata' in recordedMessage\n ? (recordedMessage.metadata as object)\n : {}),\n ...('metadata' in downcasted\n ? (downcasted.metadata as object)\n : {}),\n },\n }\n : {}),\n } as unknown as RecordedMessage<\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n};\n\nexport const downcastRecordedMessages = <\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n>(\n recordedMessages:\n | RecordedMessage<MessageType, RecordedMessageMetadataType>[]\n | MessageType[],\n options?: {\n downcast?: MessageDowncast<\n MessageType,\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n },\n): RecordedMessage<MessagePayloadType, RecordedMessageMetadataType>[] => {\n if (!options?.downcast)\n return recordedMessages as unknown as RecordedMessage<\n MessagePayloadType,\n RecordedMessageMetadataType\n >[];\n\n return recordedMessages.map((recordedMessage) =>\n downcastRecordedMessage(recordedMessage, options),\n );\n};\n","import type {\n AnyMessage,\n AnyRecordedMessageMetadata,\n RecordedMessage,\n} from '../../typing';\n\nexport type MessageUpcast<\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n> =\n | ((message: MessagePayloadType) => MessageType)\n | ((\n message: RecordedMessage<MessagePayloadType, RecordedMessageMetadataType>,\n ) => RecordedMessage<MessageType, RecordedMessageMetadataType>);\n\nexport const upcastRecordedMessage = <\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n>(\n recordedMessage:\n | RecordedMessage<MessagePayloadType, RecordedMessageMetadataType>\n | MessagePayloadType,\n options?: {\n upcast?: MessageUpcast<\n MessageType,\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n },\n): RecordedMessage<MessageType, RecordedMessageMetadataType> => {\n if (!options?.upcast)\n return recordedMessage as unknown as RecordedMessage<\n MessageType,\n RecordedMessageMetadataType\n >;\n\n const upcasted = options.upcast(\n recordedMessage as RecordedMessage<\n MessagePayloadType,\n RecordedMessageMetadataType\n >,\n );\n\n return {\n ...recordedMessage,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n data: upcasted.data,\n ...('metadata' in recordedMessage || 'metadata' in upcasted\n ? {\n metadata: {\n ...('metadata' in recordedMessage\n ? (recordedMessage.metadata as object)\n : {}),\n ...('metadata' in upcasted ? (upcasted.metadata as object) : {}),\n },\n }\n : {}),\n } as unknown as RecordedMessage<MessageType, RecordedMessageMetadataType>;\n};\n\nexport const upcastRecordedMessages = <\n MessageType extends AnyMessage,\n MessagePayloadType extends AnyMessage = MessageType,\n RecordedMessageMetadataType extends AnyRecordedMessageMetadata =\n AnyRecordedMessageMetadata,\n>(\n recordedMessages:\n | RecordedMessage<MessagePayloadType, RecordedMessageMetadataType>[]\n | MessagePayloadType[],\n options?: {\n upcast?: MessageUpcast<\n MessageType,\n MessagePayloadType,\n RecordedMessageMetadataType\n >;\n },\n): RecordedMessage<MessageType, RecordedMessageMetadataType>[] => {\n if (!options?.upcast)\n return recordedMessages as unknown as RecordedMessage<\n MessageType,\n RecordedMessageMetadataType\n >[];\n\n return recordedMessages.map((recordedMessage) =>\n upcastRecordedMessage(recordedMessage, options),\n );\n};\n","import {\n canCreateEventStoreSession,\n isExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n nulloSessionFactory,\n STREAM_DOES_NOT_EXIST,\n type AppendStreamResultOfEventStore,\n type AppendToStreamOptions,\n type EventStore,\n type EventStoreSession,\n type ExpectedStreamVersion,\n type ReadStreamOptions,\n} from '../eventStore';\nimport type { JSONSerializationOptions } from '../serialization';\nimport type { Event } from '../typing';\nimport { asyncRetry, NoRetries, type AsyncRetryOptions } from '../utils';\n\nexport const CommandHandlerStreamVersionConflictRetryOptions: AsyncRetryOptions =\n {\n retries: 3,\n minTimeout: 100,\n factor: 1.5,\n shouldRetryError: isExpectedVersionConflictError,\n };\n\nexport type CommandHandlerRetryOptions =\n | AsyncRetryOptions\n | { onVersionConflict: true | number | AsyncRetryOptions };\n\nconst fromCommandHandlerRetryOptions = (\n retryOptions: CommandHandlerRetryOptions | undefined,\n): AsyncRetryOptions => {\n if (retryOptions === undefined) return NoRetries;\n\n if ('onVersionConflict' in retryOptions) {\n if (typeof retryOptions.onVersionConflict === 'boolean')\n return CommandHandlerStreamVersionConflictRetryOptions;\n else if (typeof retryOptions.onVersionConflict === 'number')\n return {\n ...CommandHandlerStreamVersionConflictRetryOptions,\n retries: retryOptions.onVersionConflict,\n };\n else return retryOptions.onVersionConflict;\n }\n\n return retryOptions;\n};\n\n// #region command-handler\nexport type CommandHandlerResult<\n State,\n StreamEvent extends Event,\n Store extends EventStore,\n> = AppendStreamResultOfEventStore<Store> & {\n newState: State;\n newEvents: StreamEvent[];\n};\n\nexport type CommandHandlerOptions<\n State,\n StreamEvent extends Event,\n StoredEvent extends Event = StreamEvent,\n> = {\n evolve: (state: State, event: StreamEvent) => State;\n initialState: () => State;\n mapToStreamId?: (id: string) => string;\n retry?: CommandHandlerRetryOptions;\n schema?: {\n versioning?: {\n upcast?: (event: StoredEvent) => StreamEvent;\n downcast?: (event: StreamEvent) => StoredEvent;\n };\n };\n} & JSONSerializationOptions;\n\nexport type HandleOptions<Store extends EventStore> = Parameters<\n Store['appendToStream']\n>[2] &\n (\n | {\n expectedStreamVersion?: ExpectedStreamVersion;\n }\n | {\n retry?: CommandHandlerRetryOptions;\n }\n );\n\ntype CommandHandlerFunction<State, StreamEvent extends Event> = (\n state: State,\n) => StreamEvent | StreamEvent[] | Promise<StreamEvent | StreamEvent[]>;\n\nexport const CommandHandler =\n <\n State,\n StreamEvent extends Event,\n EventPayloadType extends Event = StreamEvent,\n >(\n options: CommandHandlerOptions<State, StreamEvent, EventPayloadType>,\n ) =>\n async <Store extends EventStore>(\n store: Store,\n id: string,\n handle:\n | CommandHandlerFunction<State, StreamEvent>\n | CommandHandlerFunction<State, StreamEvent>[],\n handleOptions?: HandleOptions<Store>,\n ): Promise<CommandHandlerResult<State, StreamEvent, Store>> =>\n asyncRetry(\n async () => {\n const result = await withSession<\n Store,\n CommandHandlerResult<State, StreamEvent, Store>\n >(store, async ({ eventStore }) => {\n const { evolve, initialState } = options;\n const mapToStreamId = options.mapToStreamId ?? ((id) => id);\n\n const streamName = mapToStreamId(id);\n\n // 1. Aggregate the stream\n const aggregationResult = await eventStore.aggregateStream<\n State,\n StreamEvent,\n EventPayloadType\n >(streamName, {\n evolve,\n initialState,\n read: {\n schema: options.schema,\n ...(handleOptions as ReadStreamOptions<\n StreamEvent,\n EventPayloadType\n >),\n serialization: options.serialization,\n // expected stream version is passed to fail fast\n // if stream is in the wrong state\n expectedStreamVersion:\n handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n },\n });\n\n // 2. Use the aggregate state\n\n const {\n currentStreamVersion,\n streamExists: _streamExists,\n ...restOfAggregationResult\n } = aggregationResult;\n\n let state = aggregationResult.state;\n\n const handlers = Array.isArray(handle) ? handle : [handle];\n let eventsToAppend: StreamEvent[] = [];\n\n // 3. Run business logic\n for (const handler of handlers) {\n const result = await handler(state);\n\n const newEvents = Array.isArray(result) ? result : [result];\n\n if (newEvents.length > 0) {\n state = newEvents.reduce(evolve, state);\n }\n\n eventsToAppend = [...eventsToAppend, ...newEvents];\n }\n\n //const newEvents = Array.isArray(result) ? result : [result];\n\n if (eventsToAppend.length === 0) {\n return {\n ...restOfAggregationResult,\n newEvents: [],\n newState: state,\n\n nextExpectedStreamVersion: currentStreamVersion,\n createdNewStream: false,\n } as unknown as CommandHandlerResult<State, StreamEvent, Store>;\n }\n\n // Either use:\n // - provided expected stream version,\n // - current stream version got from stream aggregation,\n // - or expect stream not to exists otherwise.\n\n const expectedStreamVersion: ExpectedStreamVersion =\n handleOptions?.expectedStreamVersion ??\n (aggregationResult.streamExists\n ? currentStreamVersion\n : STREAM_DOES_NOT_EXIST);\n\n // 4. Append result to the stream\n const appendResult = await eventStore.appendToStream(\n streamName,\n eventsToAppend,\n {\n ...(handleOptions as AppendToStreamOptions<\n StreamEvent,\n EventPayloadType\n >),\n expectedStreamVersion,\n },\n );\n\n // 5. Return result with updated state\n return {\n ...appendResult,\n newEvents: eventsToAppend,\n newState: state,\n } as unknown as CommandHandlerResult<State, StreamEvent, Store>;\n });\n\n return result;\n },\n fromCommandHandlerRetryOptions(\n handleOptions && 'retry' in handleOptions\n ? handleOptions.retry\n : options.retry,\n ),\n );\n// #endregion command-handler\n\nconst withSession = <EventStoreType extends EventStore, T = unknown>(\n eventStore: EventStoreType,\n callback: (session: EventStoreSession<EventStoreType>) => Promise<T>,\n) => {\n const sessionFactory = canCreateEventStoreSession<EventStoreType>(eventStore)\n ? eventStore\n : nulloSessionFactory<EventStoreType>(eventStore);\n\n return sessionFactory.withSession(callback);\n};\n","import type { EventStore } from '../eventStore';\nimport type { Command, Event } from '../typing';\nimport type { Decider } from '../typing/decider';\nimport {\n CommandHandler,\n type CommandHandlerOptions,\n type HandleOptions,\n} from './handleCommand';\n\n// #region command-handler\n\nexport type DeciderCommandHandlerOptions<\n State,\n CommandType extends Command,\n StreamEvent extends Event,\n> = CommandHandlerOptions<State, StreamEvent> &\n Decider<State, CommandType, StreamEvent>;\n\nexport const DeciderCommandHandler =\n <State, CommandType extends Command, StreamEvent extends Event>(\n options: DeciderCommandHandlerOptions<State, CommandType, StreamEvent>,\n ) =>\n async <Store extends EventStore>(\n eventStore: Store,\n id: string,\n commands: CommandType | CommandType[],\n handleOptions?: HandleOptions<Store>,\n ) => {\n const { decide, ...rest } = options;\n\n const deciders = (Array.isArray(commands) ? commands : [commands]).map(\n (command) => (state: State) => decide(command, state),\n );\n\n return CommandHandler<State, StreamEvent>(rest)(\n eventStore,\n id,\n deciders,\n handleOptions,\n );\n };\n// #endregion command-handler\n","import { EmmettError } from '../errors';\nimport type {\n AnyCommand,\n AnyMessage,\n Command,\n CommandTypeOf,\n Event,\n EventTypeOf,\n Message,\n SingleMessageHandler,\n SingleRawMessageHandlerWithoutContext,\n} from '../typing';\n\nexport interface CommandSender {\n send<CommandType extends Command = Command>(\n command: CommandType,\n ): Promise<void>;\n}\n\nexport interface EventsPublisher {\n publish<EventType extends Event = Event>(event: EventType): Promise<void>;\n}\n\nexport type ScheduleOptions = { afterInMs: number } | { at: Date };\n\nexport interface MessageScheduler<CommandOrEvent extends Command | Event> {\n schedule<MessageType extends CommandOrEvent>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void;\n}\n\nexport interface CommandBus extends CommandSender, MessageScheduler<Command> {}\n\nexport interface EventBus extends EventsPublisher, MessageScheduler<Event> {}\n\nexport interface MessageBus extends CommandBus, EventBus {\n schedule<MessageType extends Command | Event>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void;\n}\n\nexport interface CommandProcessor {\n handle<CommandType extends Command>(\n commandHandler: SingleMessageHandler<CommandType>,\n ...commandTypes: CommandTypeOf<CommandType>[]\n ): void;\n}\nexport interface EventSubscription {\n subscribe<EventType extends Event>(\n eventHandler: SingleMessageHandler<EventType>,\n ...eventTypes: EventTypeOf<EventType>[]\n ): void;\n}\n\nexport type ScheduledMessage = {\n message: Message;\n options?: ScheduleOptions;\n};\n\nexport interface ScheduledMessageProcessor {\n dequeue(): ScheduledMessage[];\n}\n\nexport type MessageSubscription = EventSubscription | CommandProcessor;\n\nexport const getInMemoryMessageBus = (): MessageBus &\n EventSubscription &\n CommandProcessor &\n ScheduledMessageProcessor => {\n const allHandlers = new Map<\n string,\n SingleRawMessageHandlerWithoutContext<AnyMessage>[]\n >();\n let pendingMessages: ScheduledMessage[] = [];\n\n return {\n send: async <CommandType extends Command = AnyCommand>(\n command: CommandType,\n ): Promise<void> => {\n const handlers = allHandlers.get(command.type);\n\n if (handlers === undefined || handlers.length === 0)\n throw new EmmettError(\n `No handler registered for command ${command.type}!`,\n );\n\n const commandHandler = handlers[0]!;\n\n await commandHandler(command);\n },\n\n publish: async <EventType extends Event = Event>(\n event: EventType,\n ): Promise<void> => {\n const handlers = allHandlers.get(event.type) ?? [];\n\n for (const handler of handlers) {\n const eventHandler = handler;\n\n await eventHandler(event);\n }\n },\n\n schedule: <MessageType extends Message>(\n message: MessageType,\n when?: ScheduleOptions,\n ): void => {\n pendingMessages = [...pendingMessages, { message, options: when }];\n },\n\n handle: <CommandType extends Command>(\n commandHandler: SingleMessageHandler<CommandType>,\n ...commandTypes: CommandTypeOf<CommandType>[]\n ): void => {\n const alreadyRegistered = [...allHandlers.keys()].filter((registered) =>\n commandTypes.includes(registered),\n );\n\n if (alreadyRegistered.length > 0)\n throw new EmmettError(\n `Cannot register handler for commands ${alreadyRegistered.join(', ')} as they're already registered!`,\n );\n for (const commandType of commandTypes) {\n allHandlers.set(commandType, [\n commandHandler as SingleRawMessageHandlerWithoutContext<AnyMessage>,\n ]);\n }\n },\n\n subscribe<EventType extends Event>(\n eventHandler: SingleMessageHandler<EventType>,\n ...eventTypes: EventTypeOf<EventType>[]\n ): void {\n for (const eventType of eventTypes) {\n if (!allHandlers.has(eventType)) allHandlers.set(eventType, []);\n\n allHandlers.set(eventType, [\n ...(allHandlers.get(eventType) ?? []),\n eventHandler as SingleRawMessageHandlerWithoutContext<AnyMessage>,\n ]);\n }\n },\n\n dequeue: (): ScheduledMessage[] => {\n const pending = pendingMessages;\n pendingMessages = [];\n return pending;\n },\n };\n};\n","import { EmmettError } from '../errors';\nimport type { EventStoreReadSchemaOptions } from '../eventStore';\nimport {\n JSONSerializer,\n type JSONSerializationOptions,\n} from '../serialization';\nimport type {\n AnyEvent,\n AnyReadEventMetadata,\n BatchRecordedMessageHandlerWithContext,\n CanHandle,\n DefaultRecord,\n Event,\n} from '../typing';\nimport { arrayUtils } from '../utils';\n\nexport type ProjectionHandlingType = 'inline' | 'async';\n\nexport type ProjectionHandler<\n EventType extends Event = AnyEvent,\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = BatchRecordedMessageHandlerWithContext<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n>;\n\nexport type TruncateProjection<\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = (context: ProjectionHandlerContext) => Promise<void>;\n\nexport type ProjectionInitOptions<\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n version: number;\n status?: 'active' | 'inactive';\n registrationType: ProjectionHandlingType;\n context: ProjectionHandlerContext;\n};\n\nexport type ProjectionDefinition<\n EventType extends Event = AnyEvent,\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n EventPayloadType extends Event = EventType,\n> = {\n name?: string;\n version?: number;\n kind?: string;\n canHandle: CanHandle<EventType>;\n handle: ProjectionHandler<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n >;\n truncate?: TruncateProjection<ProjectionHandlerContext>;\n init?: (\n options: ProjectionInitOptions<ProjectionHandlerContext>,\n ) => void | Promise<void>;\n eventsOptions?: {\n schema?: EventStoreReadSchemaOptions<EventType, EventPayloadType>;\n };\n} & JSONSerializationOptions;\n\nexport type ProjectionRegistration<\n HandlingType extends ProjectionHandlingType,\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = {\n type: HandlingType;\n projection: ProjectionDefinition<\n AnyEvent,\n ReadEventMetadataType,\n ProjectionHandlerContext,\n AnyEvent\n >;\n};\n\nexport const filterProjections = <\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n>(\n type: ProjectionHandlingType,\n projections: ProjectionRegistration<\n ProjectionHandlingType,\n ReadEventMetadataType,\n ProjectionHandlerContext\n >[],\n) => {\n const inlineProjections = projections\n .filter((projection) => projection.type === type)\n .map(({ projection }) => projection);\n\n const duplicateRegistrations = arrayUtils.getDuplicates(\n inlineProjections,\n (proj) => proj.name,\n );\n\n if (duplicateRegistrations.length > 0) {\n throw new EmmettError(`You cannot register multiple projections with the same name (or without the name).\n Ensure that:\n ${JSONSerializer.serialize(duplicateRegistrations)}\n have different names`);\n }\n\n return inlineProjections;\n};\n\nexport const projection = <\n EventType extends Event = Event,\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n EventPayloadType extends Event = EventType,\n>(\n definition: ProjectionDefinition<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext,\n EventPayloadType\n >,\n): ProjectionDefinition<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext,\n EventPayloadType\n> => definition;\n\nexport const inlineProjections = <\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n>(\n definitions: ProjectionDefinition<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n any,\n ReadEventMetadataType,\n ProjectionHandlerContext\n >[],\n): ProjectionRegistration<\n 'inline',\n ReadEventMetadataType,\n ProjectionHandlerContext\n>[] =>\n definitions.map((definition) => ({\n type: 'inline',\n projection: definition,\n }));\n\nexport const asyncProjections = <\n ReadEventMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n>(\n definitions: ProjectionDefinition<\n AnyEvent,\n ReadEventMetadataType,\n ProjectionHandlerContext\n >[],\n): ProjectionRegistration<\n 'inline',\n ReadEventMetadataType,\n ProjectionHandlerContext\n>[] =>\n definitions.map((definition) => ({\n type: 'inline',\n projection: definition,\n }));\n\nexport const projections = {\n inline: inlineProjections,\n async: asyncProjections,\n};\n","import { v7 as uuid } from 'uuid';\nimport {\n canCreateEventStoreSession,\n isExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n nulloSessionFactory,\n STREAM_DOES_NOT_EXIST,\n type AppendStreamResultOfEventStore,\n type AppendToStreamOptions,\n type EventStore,\n type EventStoreSession,\n type ExpectedStreamVersion,\n type ReadStreamOptions,\n} from '../eventStore';\nimport type {\n AnyCommand,\n AnyEvent,\n AnyReadEventMetadata,\n Event,\n RecordedMessage,\n} from '../typing';\nimport { asyncRetry, NoRetries, type AsyncRetryOptions } from '../utils';\nimport type {\n WorkflowEvent,\n WorkflowInputMessageMetadata,\n WorkflowMessageAction,\n} from './workflow';\nimport type { WorkflowOptions } from './workflowProcessor';\n\nexport const WorkflowHandlerStreamVersionConflictRetryOptions: AsyncRetryOptions =\n {\n retries: 3,\n minTimeout: 100,\n factor: 1.5,\n shouldRetryError: isExpectedVersionConflictError,\n };\n\nexport type WorkflowHandlerRetryOptions =\n | AsyncRetryOptions\n | { onVersionConflict: true | number | AsyncRetryOptions };\n\nconst fromWorkflowHandlerRetryOptions = (\n retryOptions: WorkflowHandlerRetryOptions | undefined,\n): AsyncRetryOptions => {\n if (retryOptions === undefined) return NoRetries;\n\n if ('onVersionConflict' in retryOptions) {\n if (typeof retryOptions.onVersionConflict === 'boolean')\n return WorkflowHandlerStreamVersionConflictRetryOptions;\n else if (typeof retryOptions.onVersionConflict === 'number')\n return {\n ...WorkflowHandlerStreamVersionConflictRetryOptions,\n retries: retryOptions.onVersionConflict,\n };\n else return retryOptions.onVersionConflict;\n }\n\n return retryOptions;\n};\n\n// #region workflow-handler\nexport type WorkflowHandlerResult<\n Output extends AnyEvent | AnyCommand,\n Store extends EventStore,\n> = AppendStreamResultOfEventStore<Store> & {\n newMessages: Output[];\n};\n\nexport type WorkflowHandleOptions<Store extends EventStore> = Parameters<\n Store['appendToStream']\n>[2] & {\n expectedStreamVersion?: ExpectedStreamVersion;\n retry?: WorkflowHandlerRetryOptions;\n};\n\ntype WorkflowInternalState<State> = {\n userState: State;\n processedInputIds: Set<string>;\n};\n\nconst emptyHandlerResult = <\n Output extends AnyEvent | AnyCommand,\n Store extends EventStore,\n>(\n nextExpectedStreamVersion: bigint = 0n,\n): WorkflowHandlerResult<Output, Store> =>\n ({\n newMessages: [] as Output[],\n createdNewStream: false,\n nextExpectedStreamVersion,\n }) as unknown as WorkflowHandlerResult<Output, Store>;\n\nconst createInputMetadata = (\n originalMessageId: string,\n action: Extract<WorkflowMessageAction, 'InitiatedBy' | 'Received'>,\n): WorkflowInputMessageMetadata => ({\n originalMessageId,\n input: true,\n action,\n});\n\nconst tagOutputMessage = <Output extends AnyEvent | AnyCommand>(\n msg: Output,\n action: Extract<WorkflowMessageAction, 'Sent' | 'Published' | 'Scheduled'>,\n): Output => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const existingMetadata =\n 'metadata' in msg && msg.metadata ? msg.metadata : {};\n return {\n ...msg,\n metadata: {\n ...existingMetadata,\n action,\n },\n } as Output;\n};\n\nconst createWrappedInitialState = <State>(initialState: () => State) => {\n return (): WorkflowInternalState<State> => ({\n userState: initialState(),\n processedInputIds: new Set(),\n });\n};\n\nconst createWrappedEvolve = <\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n State,\n>(\n evolve: (state: State, event: WorkflowEvent<Input | Output>) => State,\n workflowName: string,\n separateInputInboxFromProcessing: boolean,\n) => {\n return (\n state: WorkflowInternalState<State>,\n event: WorkflowEvent<Input | Output>,\n ): WorkflowInternalState<State> => {\n const metadata = (event as Record<string, unknown>).metadata as\n | Record<string, unknown>\n | undefined;\n\n // Track processed inputs for idempotency\n let processedInputIds = state.processedInputIds;\n if (\n metadata?.input === true &&\n typeof metadata?.originalMessageId === 'string'\n ) {\n processedInputIds = new Set(state.processedInputIds);\n processedInputIds.add(metadata.originalMessageId);\n }\n\n // In separated inbox mode, don't apply inputs to state - they're just sitting in inbox\n // Only outputs (from processing) should update state\n if (separateInputInboxFromProcessing && metadata?.input === true) {\n return {\n userState: state.userState,\n processedInputIds,\n };\n }\n\n // Strip workflow prefix from input event types\n const eventType = event.type as string;\n const eventForEvolve = eventType.startsWith(`${workflowName}:`)\n ? ({\n ...event,\n type: eventType.replace(`${workflowName}:`, ''),\n } as WorkflowEvent<Input | Output>)\n : event;\n\n return {\n userState: evolve(state.userState, eventForEvolve),\n processedInputIds,\n };\n };\n};\n\nexport const workflowStreamName = ({\n workflowName,\n workflowId,\n}: {\n workflowName: string;\n workflowId: string;\n}) => `emt:workflow:${workflowName}:${workflowId}`;\n\nexport const WorkflowHandler =\n <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n >(\n options: WorkflowOptions<\n Input,\n State,\n Output,\n MessageMetadataType,\n StoredMessage\n > & {\n retry?: WorkflowHandlerRetryOptions;\n },\n ) =>\n async <Store extends EventStore>(\n store: Store,\n message: Input | RecordedMessage<Input, MessageMetadataType>,\n handleOptions?: WorkflowHandleOptions<Store>,\n ): Promise<WorkflowHandlerResult<Output, Store>> =>\n asyncRetry(\n async () => {\n const result = await withSession<\n Store,\n WorkflowHandlerResult<Output, Store>\n >(store, async ({ eventStore }) => {\n const {\n workflow: { evolve, initialState, decide, name: workflowName },\n getWorkflowId,\n } = options;\n\n const inputMessageId =\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n ('metadata' in message && message.metadata?.messageId\n ? // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n (message.metadata.messageId as string | undefined)\n : undefined) ?? uuid();\n\n const messageWithMetadata: RecordedMessage<\n Input,\n MessageMetadataType\n > = {\n ...message,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n metadata: {\n messageId: inputMessageId,\n ...(message as RecordedMessage<Input, MessageMetadataType>)\n .metadata,\n },\n } as RecordedMessage<Input, MessageMetadataType>;\n\n const workflowId = getWorkflowId(messageWithMetadata);\n\n if (!workflowId) {\n return emptyHandlerResult<Output, Store>();\n }\n\n const streamName = options.mapWorkflowId\n ? options.mapWorkflowId(workflowId)\n : workflowStreamName({ workflowName, workflowId });\n\n const messageType = messageWithMetadata.type as string;\n const hasWorkflowPrefix = messageType.startsWith(`${workflowName}:`);\n\n // Separated inbox mode: store-only path (no prefix = external input)\n if (options.separateInputInboxFromProcessing && !hasWorkflowPrefix) {\n const inputMetadata = createInputMetadata(\n inputMessageId,\n 'InitiatedBy',\n );\n\n const inputToStore = {\n type: `${workflowName}:${messageWithMetadata.type}`,\n data: messageWithMetadata.data,\n kind: messageWithMetadata.kind,\n metadata: inputMetadata,\n } as StoredMessage;\n\n const appendResult = await eventStore.appendToStream(\n streamName,\n [inputToStore] as unknown as Event[],\n {\n ...(handleOptions as AppendToStreamOptions<\n Event,\n StoredMessage & Event\n >),\n expectedStreamVersion:\n handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n },\n );\n\n return {\n ...appendResult,\n newMessages: [] as Output[],\n } as unknown as WorkflowHandlerResult<Output, Store>;\n }\n\n // Wrap the evolve and initialState for idempotency tracking\n const wrappedInitialState = createWrappedInitialState(initialState);\n const wrappedEvolve = createWrappedEvolve(\n evolve,\n workflowName,\n options.separateInputInboxFromProcessing ?? false,\n ) as (\n state: WorkflowInternalState<State>,\n event: WorkflowEvent<Input | Output>,\n ) => WorkflowInternalState<State>;\n\n // 1. Aggregate the stream\n const aggregationResult = await eventStore.aggregateStream<\n WorkflowInternalState<State>,\n WorkflowEvent<Input | Output>,\n StoredMessage & Event\n >(streamName, {\n evolve: wrappedEvolve,\n initialState: wrappedInitialState,\n read: {\n ...(handleOptions as ReadStreamOptions<\n WorkflowEvent<Input | Output>,\n StoredMessage & Event\n >),\n // expected stream version is passed to fail fast\n // if stream is in the wrong state\n\n expectedStreamVersion:\n handleOptions?.expectedStreamVersion ?? NO_CONCURRENCY_CHECK,\n },\n });\n\n // 2. Use the aggregate state\n\n const { currentStreamVersion } = aggregationResult;\n\n const { userState: state, processedInputIds } =\n aggregationResult.state;\n\n // Idempotency: skip if this input was already processed\n\n if (processedInputIds.has(inputMessageId)) {\n return emptyHandlerResult<Output, Store>(currentStreamVersion);\n }\n\n // 3. Run business logic\n // Strip workflow prefix from message type if present (for separated inbox processing)\n const messageForDecide = hasWorkflowPrefix\n ? ({\n ...messageWithMetadata,\n type: messageType.replace(`${workflowName}:`, ''),\n } as Input)\n : (messageWithMetadata as Input);\n\n const result = decide(messageForDecide, state);\n\n const inputMetadata = createInputMetadata(\n inputMessageId,\n aggregationResult.streamExists ? 'Received' : 'InitiatedBy',\n );\n\n const inputToStore = {\n type: `${workflowName}:${messageWithMetadata.type}`,\n data: messageWithMetadata.data,\n kind: messageWithMetadata.kind,\n metadata: inputMetadata,\n } as StoredMessage;\n\n const outputMessages = (\n Array.isArray(result) ? result : [result]\n ).filter((msg): msg is Output => msg !== undefined && msg !== null);\n\n const outputCommandTypes = options.outputs?.commands ?? [];\n const taggedOutputMessages = outputMessages.map((msg) => {\n const action: WorkflowMessageAction = outputCommandTypes.includes(\n msg.type as string,\n )\n ? 'Sent'\n : 'Published';\n return tagOutputMessage(msg, action);\n });\n\n const messagesToAppend =\n options.separateInputInboxFromProcessing && hasWorkflowPrefix\n ? [...taggedOutputMessages] // input already in stream\n : [inputToStore, ...taggedOutputMessages]; // normal: store input + outputs\n\n // If there are no messages to append, return early with current state\n if (messagesToAppend.length === 0) {\n return emptyHandlerResult<Output, Store>(currentStreamVersion);\n }\n\n // Either use:\n // - provided expected stream version,\n // - current stream version got from stream aggregation,\n // - or expect stream not to exists otherwise.\n\n const expectedStreamVersion: ExpectedStreamVersion =\n handleOptions?.expectedStreamVersion ??\n (aggregationResult.streamExists\n ? currentStreamVersion\n : STREAM_DOES_NOT_EXIST);\n\n // 4. Append result to the stream\n const appendResult = await eventStore.appendToStream(\n streamName,\n // TODO: Fix this cast\n messagesToAppend as unknown as Event[],\n {\n ...(handleOptions as AppendToStreamOptions<\n Event,\n StoredMessage & Event\n >),\n expectedStreamVersion,\n },\n );\n\n // 5. Return result with output messages only\n return {\n ...appendResult,\n newMessages: outputMessages,\n } as unknown as WorkflowHandlerResult<Output, Store>;\n });\n\n return result;\n },\n fromWorkflowHandlerRetryOptions(\n handleOptions && 'retry' in handleOptions\n ? handleOptions.retry\n : options.retry,\n ),\n );\n// #endregion stream-handler\n\nconst withSession = <EventStoreType extends EventStore, T = unknown>(\n eventStore: EventStoreType,\n callback: (session: EventStoreSession<EventStoreType>) => Promise<T>,\n) => {\n const sessionFactory = canCreateEventStoreSession<EventStoreType>(eventStore)\n ? eventStore\n : nulloSessionFactory<EventStoreType>(eventStore);\n\n return sessionFactory.withSession(callback);\n};\n","import type { EmmettError } from '../errors';\nimport type { AnyCommand } from '../typing/command';\nimport type { AnyEvent } from '../typing/event';\n\n/// Inspired by https://blog.bittacklr.be/the-workflow-pattern.html\n\nexport type Workflow<\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n Name extends string = string,\n> = {\n name: Name;\n decide: (command: Input, state: State) => WorkflowOutput<Output>;\n evolve: (currentState: State, event: WorkflowEvent<Input | Output>) => State;\n initialState: () => State;\n};\n\nexport type WorkflowEvent<Output extends AnyEvent | AnyCommand> = Extract<\n Output,\n { kind?: 'Event' }\n>;\n\nexport type WorkflowCommand<Output extends AnyEvent | AnyCommand> = Extract<\n Output,\n { kind?: 'Command' }\n>;\n\nexport type WorkflowMessageAction =\n | 'InitiatedBy'\n | 'Received'\n | 'Sent'\n | 'Published'\n | 'Scheduled';\n\nexport type WorkflowInputMessageMetadata = Readonly<{\n originalMessageId: string | undefined;\n input: true;\n action?: Extract<WorkflowMessageAction, 'InitiatedBy' | 'Received'>;\n}>;\n\nexport type WorkflowOutputMessageMetadata = Readonly<{\n action?: Extract<WorkflowMessageAction, 'Sent' | 'Published' | 'Scheduled'>;\n}>;\n\nexport type WorkflowOutput<Output extends AnyEvent | AnyCommand | EmmettError> =\n | Output\n | Output[];\n\nexport const Workflow = <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n>(\n workflow: Workflow<Input, State, Output>,\n): Workflow<Input, State, Output> => {\n return workflow;\n};\n","import { EmmettError } from '../errors';\nimport type { EventStore } from '../eventStore';\nimport type { MessageProcessor } from '../processors';\nimport {\n MessageProcessorType,\n reactor,\n type BaseMessageProcessorOptions,\n} from '../processors';\nimport type {\n AnyCommand,\n AnyEvent,\n AnyReadEventMetadata,\n AnyRecordedMessageMetadata,\n CanHandle,\n Event,\n MessageTypeOf,\n RecordedMessage,\n} from '../typing';\nimport {\n WorkflowHandler,\n workflowStreamName,\n type WorkflowHandlerRetryOptions,\n} from './handleWorkflow';\nimport type { Workflow, WorkflowCommand, WorkflowEvent } from './workflow';\n\nexport type WorkflowOptions<\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n> = {\n workflow: Workflow<Input, State, Output>;\n getWorkflowId: (\n input: Input | RecordedMessage<Input, MessageMetadataType>,\n ) => string | null;\n mapWorkflowId?: (workflowId: string) => string;\n separateInputInboxFromProcessing?: boolean;\n inputs: {\n commands: CanHandle<WorkflowCommand<Input>>;\n events: CanHandle<WorkflowEvent<Input>>;\n };\n outputs: {\n commands: MessageTypeOf<WorkflowCommand<Output>>[];\n events: MessageTypeOf<WorkflowEvent<Output>>[];\n };\n schema?: {\n versioning?: {\n upcast?: (event: StoredMessage) => Input;\n downcast?: (event: Output) => StoredMessage;\n };\n };\n};\n\nexport type WorkflowProcessorContext = {\n connection: {\n messageStore: EventStore;\n };\n};\n\nexport type WorkflowOutputHandlerResult<Input extends AnyEvent | AnyCommand> =\n | Promise<Input | Input[] | EmmettError | [] | void>\n | Input\n | Input[]\n | EmmettError\n | []\n | void;\n\nexport type SingleWorkflowOutputHandler<\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n MessageMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n> = (\n message: Output | RecordedMessage<Output, MessageMetaDataType>,\n context: HandlerContext,\n) => WorkflowOutputHandlerResult<Input>;\n\nexport type BatchWorkflowOutputHandler<\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n MessageMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n> = (\n messages: RecordedMessage<Output, MessageMetaDataType>[],\n context: HandlerContext,\n) => WorkflowOutputHandlerResult<Input>;\n\nexport type WorkflowOutputHandlerOptions<\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n MessageMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n> =\n | {\n eachMessage: SingleWorkflowOutputHandler<\n Input,\n Output,\n MessageMetaDataType,\n HandlerContext\n >;\n eachBatch?: never;\n }\n | {\n eachMessage?: never;\n eachBatch: BatchWorkflowOutputHandler<\n Input,\n Output,\n MessageMetaDataType,\n HandlerContext\n >;\n };\n\nexport type WorkflowOutputHandlerDefinition<\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n HandledOutput extends Output = Output,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n> = {\n canHandle: CanHandle<HandledOutput>;\n} & WorkflowOutputHandlerOptions<\n Input,\n HandledOutput,\n MessageMetadataType,\n HandlerContext\n>;\n\nexport const workflowOutputHandler = <\n Input extends AnyEvent | AnyCommand,\n Output extends AnyEvent | AnyCommand,\n HandledOutput extends Output = Output,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n>(\n handler: WorkflowOutputHandlerDefinition<\n Input,\n Output,\n HandledOutput,\n MessageMetadataType,\n HandlerContext\n >,\n): WorkflowOutputHandlerDefinition<\n Input,\n Output,\n HandledOutput,\n MessageMetadataType,\n HandlerContext\n> => handler;\n\nexport type WorkflowProcessorOptions<\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MessageMetadataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n HandledOutput extends Output = Output,\n> = Omit<\n BaseMessageProcessorOptions<\n Input | Output,\n MessageMetadataType,\n HandlerContext\n >,\n 'type' | 'canHandle' | 'processorId'\n> & { processorId?: string } & WorkflowOptions<\n Input,\n State,\n Output,\n MessageMetadataType,\n StoredMessage\n > & {\n retry?: WorkflowHandlerRetryOptions;\n outputHandler?: WorkflowOutputHandlerDefinition<\n Input,\n Output,\n HandledOutput,\n MessageMetadataType,\n HandlerContext\n >;\n };\n\nexport const getWorkflowId = (options: { workflowName: string }): string =>\n `emt:processor:workflow:${options.workflowName}`;\n\nexport const workflowProcessor = <\n Input extends AnyEvent | AnyCommand,\n State,\n Output extends AnyEvent | AnyCommand,\n MetaDataType extends AnyRecordedMessageMetadata = AnyRecordedMessageMetadata,\n HandlerContext extends WorkflowProcessorContext = WorkflowProcessorContext,\n StoredMessage extends AnyEvent | AnyCommand = Output,\n HandledOutput extends Output = Output,\n>(\n options: WorkflowProcessorOptions<\n Input,\n State,\n Output,\n MetaDataType,\n HandlerContext,\n StoredMessage,\n HandledOutput\n >,\n): MessageProcessor<Input, MetaDataType, HandlerContext> => {\n const { workflow, ...rest } = options;\n\n const inputs = [...options.inputs.commands, ...options.inputs.events];\n let canHandle = inputs;\n\n if (options.separateInputInboxFromProcessing)\n canHandle = [\n ...canHandle,\n ...options.inputs.commands.map((t) => `${workflow.name}:${t}`),\n ...options.inputs.events.map((t) => `${workflow.name}:${t}`),\n ];\n\n if (options.outputHandler)\n canHandle = [...canHandle, ...options.outputHandler.canHandle];\n\n const handle = WorkflowHandler(options);\n\n return reactor<Input | Output, MetaDataType, HandlerContext>({\n ...rest,\n processorId:\n options.processorId ?? getWorkflowId({ workflowName: workflow.name }),\n canHandle,\n type: MessageProcessorType.PROJECTOR,\n eachMessage: async (\n message: RecordedMessage<Input | Output, MetaDataType>,\n context: HandlerContext,\n ) => {\n const messageType = message.type as string;\n const metadata = message.metadata as Record<string, unknown> | undefined;\n const isInput = metadata?.input === true;\n\n if (isInput || inputs.includes(messageType)) {\n const result = await handle(\n context.connection.messageStore,\n message as RecordedMessage<Input, MetaDataType>,\n context,\n );\n\n // Check stopAfter on output messages\n if (options.stopAfter && result.newMessages.length > 0) {\n for (const outputMessage of result.newMessages) {\n if (\n options.stopAfter(\n outputMessage as RecordedMessage<Output, MetaDataType>,\n )\n ) {\n return { type: 'STOP', reason: 'Stop condition reached' };\n }\n }\n }\n\n return;\n }\n\n if (options.outputHandler?.canHandle.includes(messageType) === true) {\n const recordedMessage = message as RecordedMessage<\n HandledOutput,\n MetaDataType\n >;\n const handledOutputMessages = options.outputHandler.eachBatch\n ? await options.outputHandler.eachBatch([recordedMessage], context)\n : await options.outputHandler.eachMessage(recordedMessage, context);\n\n if (handledOutputMessages instanceof EmmettError) {\n return {\n type: 'STOP',\n reason: 'Routing error',\n error: handledOutputMessages,\n };\n }\n\n const messagesToAppend = Array.isArray(handledOutputMessages)\n ? handledOutputMessages\n : handledOutputMessages\n ? [handledOutputMessages]\n : [];\n\n if (messagesToAppend.length === 0) {\n return;\n }\n\n const workflowId = options.getWorkflowId(\n message as RecordedMessage<Input, MetaDataType>,\n );\n\n if (!workflowId) return;\n\n const streamName = options.mapWorkflowId\n ? options.mapWorkflowId(workflowId)\n : workflowStreamName({\n workflowName: workflow.name,\n workflowId,\n });\n\n await context.connection.messageStore.appendToStream(\n streamName,\n messagesToAppend as unknown as Event[],\n );\n\n return;\n }\n\n return;\n },\n });\n};\n","import type { MessageProcessor } from '@event-driven-io/emmett';\nimport {\n EmmettError,\n inMemoryProjector,\n inMemoryReactor,\n type AnyEvent,\n type AnyMessage,\n type AnyRecordedMessageMetadata,\n type AsyncRetryOptions,\n type BatchRecordedMessageHandlerWithoutContext,\n type DefaultRecord,\n type InMemoryProcessor,\n type InMemoryProjectorOptions,\n type InMemoryReactorOptions,\n type Message,\n type MessageConsumer,\n type MessageConsumerOptions,\n} from '@event-driven-io/emmett';\nimport {\n EventStoreDBClient,\n type SubscribeToAllOptions,\n type SubscribeToStreamOptions,\n} from '@eventstore/db-client';\nimport { v7 as uuid } from 'uuid';\nimport type { EventStoreDBReadEventMetadata } from '../eventstoreDBEventStore';\nimport {\n DefaultEventStoreDBEventStoreProcessorBatchSize,\n eventStoreDBSubscription,\n zipEventStoreDBEventStoreMessageBatchPullerStartFrom,\n type EventStoreDBSubscription,\n} from './subscriptions';\n\nexport type EventStoreDBEventStoreConsumerConfig<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ConsumerMessageType extends Message = any,\n> = MessageConsumerOptions<ConsumerMessageType> & {\n from?: EventStoreDBEventStoreConsumerType;\n pulling?: {\n batchSize?: number;\n };\n resilience?: {\n resubscribeOptions?: AsyncRetryOptions;\n };\n};\n\nexport type EventStoreDBEventStoreConsumerOptions<\n ConsumerEventType extends Message = Message,\n> = EventStoreDBEventStoreConsumerConfig<ConsumerEventType> &\n (\n | {\n connectionString: string;\n client?: never;\n }\n | { client: EventStoreDBClient; connectionString?: never }\n );\n\nexport type $all = '$all';\nexport const $all = '$all';\n\nexport type EventStoreDBEventStoreConsumerType =\n | {\n stream: $all;\n options?: Exclude<SubscribeToAllOptions, 'fromPosition'>;\n }\n | {\n stream: string;\n options?: Exclude<SubscribeToStreamOptions, 'fromRevision'>;\n };\n\nexport type EventStoreDBEventStoreConsumer<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ConsumerMessageType extends AnyMessage = any,\n> = MessageConsumer<ConsumerMessageType> &\n Readonly<{\n reactor: <MessageType extends AnyMessage = ConsumerMessageType>(\n options: InMemoryReactorOptions<MessageType>,\n ) => InMemoryProcessor<MessageType>;\n }> &\n (AnyEvent extends ConsumerMessageType\n ? Readonly<{\n projector: <\n EventType extends AnyEvent = ConsumerMessageType & AnyEvent,\n >(\n options: InMemoryProjectorOptions<EventType>,\n ) => InMemoryProcessor<EventType>;\n }>\n : object);\n\nexport const eventStoreDBEventStoreConsumer = <\n ConsumerMessageType extends Message = AnyMessage,\n>(\n options: EventStoreDBEventStoreConsumerOptions<ConsumerMessageType>,\n): EventStoreDBEventStoreConsumer<ConsumerMessageType> => {\n let isRunning = false;\n const { pulling } = options;\n const processors = options.processors ?? [];\n\n let start: Promise<void>;\n\n let currentSubscription: EventStoreDBSubscription | undefined;\n\n const client =\n 'client' in options && options.client\n ? options.client\n : EventStoreDBClient.connectionString(options.connectionString);\n\n const eachBatch: BatchRecordedMessageHandlerWithoutContext<\n ConsumerMessageType,\n EventStoreDBReadEventMetadata\n > = async (messagesBatch) => {\n const activeProcessors = processors.filter((s) => s.isActive);\n\n if (activeProcessors.length === 0)\n return {\n type: 'STOP',\n reason: 'No active processors',\n };\n\n const result = await Promise.allSettled(\n activeProcessors.map(async (s) => {\n // TODO: Add here filtering to only pass messages that can be handled by\n return await s.handle(messagesBatch, { client });\n }),\n );\n\n const error = result.find((r) => r.status === 'rejected')?.reason as\n | Error\n | undefined;\n\n return result.some(\n (r) => r.status === 'fulfilled' && r.value?.type !== 'STOP',\n )\n ? undefined\n : {\n type: 'STOP',\n error: error ? EmmettError.mapFrom(error) : undefined,\n };\n };\n\n const subscription = (currentSubscription = eventStoreDBSubscription({\n client,\n from: options.from,\n eachBatch,\n batchSize:\n pulling?.batchSize ?? DefaultEventStoreDBEventStoreProcessorBatchSize,\n resilience: options.resilience,\n }));\n\n const stop = async () => {\n if (!isRunning) return;\n isRunning = false;\n if (currentSubscription) {\n await currentSubscription.stop();\n currentSubscription = undefined;\n }\n await start;\n };\n\n return {\n consumerId: options.consumerId ?? uuid(),\n get isRunning() {\n return isRunning;\n },\n processors,\n reactor: <MessageType extends AnyMessage = ConsumerMessageType>(\n options: InMemoryReactorOptions<MessageType>,\n ): InMemoryProcessor<MessageType> => {\n const processor = inMemoryReactor(options);\n\n processors.push(\n // TODO: change that\n processor as unknown as MessageProcessor<\n ConsumerMessageType,\n AnyRecordedMessageMetadata,\n DefaultRecord\n >,\n );\n\n return processor;\n },\n projector: <EventType extends AnyEvent = ConsumerMessageType & AnyEvent>(\n options: InMemoryProjectorOptions<EventType>,\n ): InMemoryProcessor<EventType> => {\n const processor = inMemoryProjector(options);\n\n processors.push(\n // TODO: change that\n processor as unknown as MessageProcessor<\n ConsumerMessageType,\n AnyRecordedMessageMetadata,\n DefaultRecord\n >,\n );\n\n return processor;\n },\n start: () => {\n if (isRunning) return start;\n\n start = (async () => {\n if (processors.length === 0)\n return Promise.reject(\n new EmmettError(\n 'Cannot start consumer without at least a single processor',\n ),\n );\n\n isRunning = true;\n\n const startFrom = zipEventStoreDBEventStoreMessageBatchPullerStartFrom(\n await Promise.all(processors.map((o) => o.start(client))),\n );\n\n return subscription.start({ startFrom });\n })();\n\n return start;\n },\n stop,\n close: stop,\n };\n};\n","import {\n asyncRetry,\n getCheckpoint,\n isString,\n JSONSerializer,\n parseBigIntProcessorCheckpoint,\n type AnyMessage,\n type AsyncRetryOptions,\n type BatchRecordedMessageHandlerWithoutContext,\n type EmmettError,\n type Message,\n type MessageHandlerResult,\n type ProcessorCheckpoint,\n} from '@event-driven-io/emmett';\nimport type { EventStoreDBClient } from '@eventstore/db-client';\nimport {\n END,\n excludeSystemEvents,\n START,\n type ResolvedEvent,\n type StreamSubscription,\n} from '@eventstore/db-client';\nimport { pipeline, Transform, Writable, type WritableOptions } from 'stream';\nimport {\n mapFromESDBEvent,\n type EventStoreDBReadEventMetadata,\n} from '../../eventstoreDBEventStore';\nimport {\n $all,\n type EventStoreDBEventStoreConsumerType,\n} from '../eventStoreDBEventStoreConsumer';\n\nexport const DefaultEventStoreDBEventStoreProcessorBatchSize = 100;\nexport const DefaultEventStoreDBEventStoreProcessorPullingFrequencyInMs = 50;\n\nexport type EventStoreDBEventStoreMessagesBatchHandlerResult = void | {\n type: 'STOP';\n reason?: string;\n error?: EmmettError;\n};\n\nexport type EventStoreDBSubscriptionOptions<\n MessageType extends Message = Message,\n> = {\n from?: EventStoreDBEventStoreConsumerType;\n client: EventStoreDBClient;\n batchSize: number;\n eachBatch: BatchRecordedMessageHandlerWithoutContext<\n MessageType,\n EventStoreDBReadEventMetadata\n >;\n resilience?: {\n resubscribeOptions?: AsyncRetryOptions;\n };\n};\n\nexport type EventStoreDBSubscriptionStartFrom =\n | { lastCheckpoint: ProcessorCheckpoint }\n | 'BEGINNING'\n | 'END';\n\nexport type EventStoreDBSubscriptionStartOptions = {\n startFrom: EventStoreDBSubscriptionStartFrom;\n};\n\nexport type EventStoreDBSubscription = {\n isRunning: boolean;\n start(options: EventStoreDBSubscriptionStartOptions): Promise<void>;\n stop(): Promise<void>;\n};\n\nconst toGlobalPosition = (startFrom: EventStoreDBSubscriptionStartFrom) =>\n startFrom === 'BEGINNING'\n ? START\n : startFrom === 'END'\n ? END\n : {\n prepare: parseBigIntProcessorCheckpoint(startFrom.lastCheckpoint),\n commit: parseBigIntProcessorCheckpoint(startFrom.lastCheckpoint),\n };\n\nconst toStreamPosition = (startFrom: EventStoreDBSubscriptionStartFrom) =>\n startFrom === 'BEGINNING'\n ? START\n : startFrom === 'END'\n ? END\n : parseBigIntProcessorCheckpoint(startFrom.lastCheckpoint);\n\nconst subscribe = (\n client: EventStoreDBClient,\n from: EventStoreDBEventStoreConsumerType | undefined,\n options: EventStoreDBSubscriptionStartOptions,\n) =>\n from == undefined || from.stream == $all\n ? client.subscribeToAll({\n ...(from?.options ?? {}),\n fromPosition: toGlobalPosition(options.startFrom),\n filter: excludeSystemEvents(),\n })\n : client.subscribeToStream(from.stream, {\n ...(from.options ?? {}),\n fromRevision: toStreamPosition(options.startFrom),\n });\n\nexport const isDatabaseUnavailableError = (error: unknown) =>\n error instanceof Error &&\n 'type' in error &&\n error.type === 'unavailable' &&\n 'code' in error &&\n error.code === 14;\n\nexport const EventStoreDBResubscribeDefaultOptions: AsyncRetryOptions = {\n forever: true,\n minTimeout: 100,\n factor: 1.5,\n shouldRetryError: (error) => !isDatabaseUnavailableError(error),\n};\n\ntype SubscriptionSequentialHandlerOptions<\n MessageType extends AnyMessage = AnyMessage,\n> = EventStoreDBSubscriptionOptions<MessageType> & WritableOptions;\n\nclass SubscriptionSequentialHandler<\n MessageType extends AnyMessage = AnyMessage,\n> extends Transform {\n private options: SubscriptionSequentialHandlerOptions<MessageType>;\n private from: EventStoreDBEventStoreConsumerType | undefined;\n public isRunning: boolean;\n\n constructor(options: SubscriptionSequentialHandlerOptions<MessageType>) {\n super({ objectMode: true, ...options });\n this.options = options;\n this.from = options.from;\n this.isRunning = true;\n }\n\n async _transform(\n resolvedEvent: ResolvedEvent<MessageType>,\n _encoding: BufferEncoding,\n callback: (error?: Error | null) => void,\n ): Promise<void> {\n try {\n if (!this.isRunning || !resolvedEvent.event) {\n callback();\n return;\n }\n\n const message = mapFromESDBEvent(resolvedEvent, this.from);\n const messageCheckpoint = getCheckpoint(message);\n\n const result = await this.options.eachBatch([message]);\n\n if (result && result.type === 'STOP') {\n this.isRunning = false;\n if (!result.error) this.push(messageCheckpoint);\n\n this.push(result);\n this.push(null);\n callback();\n return;\n }\n\n this.push(messageCheckpoint);\n callback();\n } catch (error) {\n callback(error as Error);\n }\n }\n}\n\nexport const eventStoreDBSubscription = <\n MessageType extends AnyMessage = AnyMessage,\n>({\n client,\n from,\n batchSize,\n eachBatch,\n resilience,\n}: EventStoreDBSubscriptionOptions<MessageType>): EventStoreDBSubscription => {\n let isRunning = false;\n\n let start: Promise<void>;\n let processor: SubscriptionSequentialHandler<MessageType>;\n\n let subscription: StreamSubscription<MessageType>;\n\n const resubscribeOptions: AsyncRetryOptions =\n resilience?.resubscribeOptions ?? {\n ...EventStoreDBResubscribeDefaultOptions,\n shouldRetryResult: () => isRunning,\n shouldRetryError: (error) =>\n isRunning &&\n EventStoreDBResubscribeDefaultOptions.shouldRetryError!(error),\n };\n\n const stopSubscription = (callback?: () => void): Promise<void> => {\n isRunning = false;\n if (processor) processor.isRunning = false;\n return subscription\n .unsubscribe()\n .then(() => {\n subscription.destroy();\n })\n .catch((err) => console.error('Error during unsubscribe.%s', err))\n .finally(callback ?? (() => {}));\n };\n\n const pipeMessages = (options: EventStoreDBSubscriptionStartOptions) => {\n let retry = 0;\n return asyncRetry(\n () =>\n new Promise<void>((resolve, reject) => {\n if (!isRunning) {\n resolve();\n return;\n }\n console.info(\n `Starting subscription. ${retry++} retries. From: ${JSONSerializer.serialize(from ?? '$all')}, Start from: ${JSONSerializer.serialize(\n options.startFrom,\n )}`,\n );\n subscription = subscribe(client, from, options);\n\n processor = new SubscriptionSequentialHandler({\n client,\n from,\n batchSize,\n eachBatch,\n resilience,\n });\n\n const handler = new (class extends Writable {\n async _write(\n result: ProcessorCheckpoint | MessageHandlerResult,\n _encoding: string,\n done: () => void,\n ) {\n if (!isRunning) return;\n\n if (isString(result)) {\n options.startFrom = {\n lastCheckpoint: result,\n };\n done();\n return;\n }\n\n if (result && result.type === 'STOP' && result.error) {\n console.error(\n `Subscription stopped with error code: ${result.error.errorCode}, message: ${\n result.error.message\n }.`,\n );\n }\n\n await stopSubscription();\n done();\n }\n })({ objectMode: true });\n\n pipeline(\n subscription,\n processor,\n handler,\n async (error: Error | null) => {\n console.info(`Stopping subscription.`);\n await stopSubscription(() => {\n if (!error) {\n console.info('Subscription ended successfully.');\n resolve();\n return;\n }\n console.error(\n `Received error: ${JSONSerializer.serialize(error)}.`,\n );\n reject(error);\n });\n },\n );\n }),\n resubscribeOptions,\n );\n };\n\n return {\n get isRunning() {\n return isRunning;\n },\n start: (options) => {\n if (isRunning) return start;\n\n start = (async () => {\n isRunning = true;\n\n return pipeMessages(options);\n })();\n\n return start;\n },\n stop: async () => {\n if (!isRunning) return start ? await start : Promise.resolve();\n await stopSubscription();\n await start;\n },\n };\n};\n\nexport const zipEventStoreDBEventStoreMessageBatchPullerStartFrom = (\n options: (EventStoreDBSubscriptionStartFrom | undefined)[],\n): EventStoreDBSubscriptionStartFrom => {\n if (\n options.length === 0 ||\n options.some((o) => o === undefined || o === 'BEGINNING')\n )\n return 'BEGINNING';\n\n if (options.every((o) => o === 'END')) return 'END';\n\n return options\n .filter((o) => o !== undefined && o !== 'BEGINNING' && o !== 'END')\n .sort((a, b) => (a > b ? 1 : -1))[0]!;\n};\n","import {\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n assertExpectedVersionMatchesCurrent,\n bigIntProcessorCheckpoint,\n downcastRecordedMessages,\n upcastRecordedMessage,\n type AggregateStreamOptions,\n type AggregateStreamResultWithGlobalPosition,\n type AnyMessage,\n type AppendToStreamOptions,\n type AppendToStreamResultWithGlobalPosition,\n type Event,\n type EventStore,\n type ExpectedStreamVersion,\n type ReadEvent,\n type ReadEventMetadataWithGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n type RecordedMessage,\n type StreamExistsResult,\n} from '@event-driven-io/emmett';\nimport type { EventStoreDBClient } from '@eventstore/db-client';\nimport {\n ANY,\n STREAM_EXISTS as ESDB_STREAM_EXISTS,\n NO_STREAM,\n StreamNotFoundError,\n WrongExpectedVersionError,\n jsonEvent,\n type AppendExpectedRevision,\n type ReadStreamOptions as ESDBReadStreamOptions,\n type ResolvedEvent,\n} from '@eventstore/db-client';\nimport {\n $all,\n eventStoreDBEventStoreConsumer,\n type EventStoreDBEventStoreConsumer,\n type EventStoreDBEventStoreConsumerConfig,\n type EventStoreDBEventStoreConsumerType,\n} from './consumers';\n\nconst toEventStoreDBReadOptions = <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n>(\n options: ReadStreamOptions<EventType, EventPayloadType> | undefined,\n): ESDBReadStreamOptions | undefined => {\n return options\n ? {\n fromRevision: 'from' in options ? options.from : undefined,\n maxCount:\n 'maxCount' in options\n ? options.maxCount\n : 'to' in options\n ? options.to\n : undefined,\n }\n : undefined;\n};\n\nexport const EventStoreDBEventStoreDefaultStreamVersion = -1n;\n\nexport type EventStoreDBReadEventMetadata = ReadEventMetadataWithGlobalPosition;\n\nexport type EventStoreDBReadEvent<EventType extends Event = Event> = ReadEvent<\n EventType,\n EventStoreDBReadEventMetadata\n>;\n\nexport interface EventStoreDBEventStore extends EventStore<EventStoreDBReadEventMetadata> {\n appendToStream<\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResultWithGlobalPosition>;\n consumer<ConsumerEventType extends Event = Event>(\n options?: EventStoreDBEventStoreConsumerConfig<ConsumerEventType>,\n ): EventStoreDBEventStoreConsumer<ConsumerEventType>;\n}\n\nexport const getEventStoreDBEventStore = (\n eventStore: EventStoreDBClient,\n): EventStoreDBEventStore => {\n return {\n async aggregateStream<\n State,\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n EventStoreDBReadEventMetadata,\n EventPayloadType\n >,\n ): Promise<AggregateStreamResultWithGlobalPosition<State>> {\n const { evolve, initialState, read } = options;\n\n const expectedStreamVersion = read?.expectedStreamVersion;\n\n let state = initialState();\n let currentStreamVersion: bigint =\n EventStoreDBEventStoreDefaultStreamVersion;\n let lastEventGlobalPosition: bigint | undefined = undefined;\n\n try {\n for await (const resolvedEvent of eventStore.readStream<EventPayloadType>(\n streamName,\n toEventStoreDBReadOptions(options.read),\n )) {\n const { event } = resolvedEvent;\n if (!event) continue;\n\n state = evolve(\n state,\n upcastRecordedMessage(\n mapFromESDBEvent<EventPayloadType>(resolvedEvent),\n options?.read?.schema?.versioning,\n ),\n );\n currentStreamVersion = event.revision;\n lastEventGlobalPosition = event.position?.commit;\n }\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n EventStoreDBEventStoreDefaultStreamVersion,\n );\n\n return lastEventGlobalPosition\n ? {\n currentStreamVersion,\n lastEventGlobalPosition,\n state,\n streamExists: true,\n }\n : {\n currentStreamVersion,\n state,\n streamExists: false,\n };\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return {\n currentStreamVersion,\n state,\n streamExists: false,\n };\n }\n\n throw error;\n }\n },\n\n readStream: async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n options?: ReadStreamOptions<EventType, EventPayloadType>,\n ): Promise<ReadStreamResult<EventType, EventStoreDBReadEventMetadata>> => {\n const events: ReadEvent<EventType, EventStoreDBReadEventMetadata>[] = [];\n\n let currentStreamVersion: bigint =\n EventStoreDBEventStoreDefaultStreamVersion;\n\n try {\n for await (const resolvedEvent of eventStore.readStream<EventPayloadType>(\n streamName,\n toEventStoreDBReadOptions(options),\n )) {\n const { event } = resolvedEvent;\n if (!event) continue;\n events.push(\n upcastRecordedMessage(\n mapFromESDBEvent<EventPayloadType>(resolvedEvent),\n options?.schema?.versioning,\n ),\n );\n\n currentStreamVersion = event.revision;\n }\n return {\n currentStreamVersion,\n events,\n streamExists: true,\n };\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return {\n currentStreamVersion,\n events: [],\n streamExists: false,\n };\n }\n\n throw error;\n }\n },\n\n appendToStream: async <\n EventType extends Event,\n EventPayloadType extends Event = EventType,\n >(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions<EventType, EventPayloadType>,\n ): Promise<AppendToStreamResultWithGlobalPosition> => {\n try {\n const eventsToStore = downcastRecordedMessages(\n events,\n options?.schema?.versioning,\n );\n const serializedEvents = eventsToStore.map(jsonEvent);\n\n const expectedRevision = toExpectedRevision(\n options?.expectedStreamVersion,\n );\n\n const appendResult = await eventStore.appendToStream(\n streamName,\n serializedEvents,\n {\n expectedRevision,\n },\n );\n\n return {\n nextExpectedStreamVersion: appendResult.nextExpectedRevision,\n lastEventGlobalPosition: appendResult.position!.commit,\n createdNewStream:\n appendResult.nextExpectedRevision >=\n BigInt(serializedEvents.length),\n };\n } catch (error) {\n if (error instanceof WrongExpectedVersionError) {\n throw new ExpectedVersionConflictError(\n BigInt(error.actualVersion),\n toExpectedVersion(error.expectedVersion),\n );\n }\n\n throw error;\n }\n },\n\n consumer: <ConsumerEventType extends Event = Event>(\n options?: EventStoreDBEventStoreConsumerConfig<ConsumerEventType>,\n ): EventStoreDBEventStoreConsumer<ConsumerEventType> =>\n eventStoreDBEventStoreConsumer<ConsumerEventType>({\n ...(options ?? {}),\n client: eventStore,\n }),\n\n streamExists: async (streamName: string): Promise<StreamExistsResult> => {\n try {\n for await (const resolvedEvent of eventStore.readStream(streamName)) {\n const { event } = resolvedEvent;\n\n if (!event) continue;\n\n return true;\n }\n\n return false;\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return false;\n }\n\n throw error;\n }\n },\n\n //streamEvents: streamEvents(eventStore),\n };\n};\n\nconst getESDBCheckpoint = <MessageType extends AnyMessage = AnyMessage>(\n resolvedEvent: ResolvedEvent<MessageType>,\n from?: EventStoreDBEventStoreConsumerType,\n): bigint => {\n return !from || from?.stream === $all\n ? (resolvedEvent.link?.position?.commit ??\n resolvedEvent.event?.position?.commit)!\n : (resolvedEvent.link?.revision ?? resolvedEvent.event!.revision);\n};\n\nexport const mapFromESDBEvent = <MessageType extends AnyMessage = AnyMessage>(\n resolvedEvent: ResolvedEvent<MessageType>,\n from?: EventStoreDBEventStoreConsumerType,\n): RecordedMessage<MessageType, EventStoreDBReadEventMetadata> => {\n const event = resolvedEvent.event!;\n return <RecordedMessage<MessageType, EventStoreDBReadEventMetadata>>{\n type: event.type,\n data: event.data,\n metadata: {\n ...((event.metadata as EventStoreDBReadEventMetadata) ??\n ({} as EventStoreDBReadEventMetadata)),\n eventId: event.id,\n streamName: event.streamId,\n streamPosition: event.revision,\n globalPosition: event.position!.commit,\n checkpoint: bigIntProcessorCheckpoint(\n getESDBCheckpoint(resolvedEvent, from),\n ),\n },\n };\n};\n\nconst toExpectedRevision = (\n expected: ExpectedStreamVersion | undefined,\n): AppendExpectedRevision => {\n if (expected === undefined) return ANY;\n\n if (expected === NO_CONCURRENCY_CHECK) return ANY;\n\n if (expected == STREAM_DOES_NOT_EXIST) return NO_STREAM;\n\n if (expected == STREAM_EXISTS) return ESDB_STREAM_EXISTS;\n\n return expected as bigint;\n};\n\nconst toExpectedVersion = (\n expected: AppendExpectedRevision | undefined,\n): ExpectedStreamVersion => {\n if (expected === undefined) return NO_CONCURRENCY_CHECK;\n\n if (expected === ANY) return NO_CONCURRENCY_CHECK;\n\n if (expected == NO_STREAM) return STREAM_DOES_NOT_EXIST;\n\n if (expected == ESDB_STREAM_EXISTS) return STREAM_EXISTS;\n\n return expected;\n};\n\n// const { map } = streamTransformations;\n//\n// // eslint-disable-next-line @typescript-eslint/no-unused-vars\n// const convertToWebReadableStream = (\n// allStreamSubscription: AllStreamSubscription,\n// ): ReadableStream<AllStreamResolvedEvent | GlobalStreamCaughtUp> => {\n// // Validate the input type\n// if (!(allStreamSubscription instanceof Readable)) {\n// throw new Error('Provided stream is not a Node.js Readable stream.');\n// }\n\n// let globalPosition = 0n;\n\n// const stream = Readable.toWeb(\n// allStreamSubscription,\n// ) as ReadableStream<AllStreamResolvedEvent>;\n\n// const writable = new WritableStream<\n// AllStreamResolvedEvent | GlobalStreamCaughtUp\n// >();\n\n// allStreamSubscription.on('caughtUp', async () => {\n// console.log(globalPosition);\n// await writable.getWriter().write(globalStreamCaughtUp({ globalPosition }));\n// });\n\n// const transform = map<\n// AllStreamResolvedEvent,\n// AllStreamResolvedEvent | GlobalStreamCaughtUp\n// >((event) => {\n// if (event?.event?.position.commit)\n// globalPosition = event.event?.position.commit;\n\n// return event;\n// });\n\n// return stream.pipeThrough<AllStreamResolvedEvent | GlobalStreamCaughtUp>(\n// transform,\n// );\n// };\n\n// const streamEvents = (eventStore: EventStoreDBClient) => () => {\n// return restream<\n// AllStreamResolvedEvent | GlobalSubscriptionEvent,\n// | ReadEvent<Event, EventStoreDBReadEventMetadata>\n// | GlobalSubscriptionEvent\n// >(\n// (): ReadableStream<AllStreamResolvedEvent | GlobalSubscriptionEvent> =>\n// convertToWebReadableStream(\n// eventStore.subscribeToAll({\n// fromPosition: START,\n// filter: excludeSystemEvents(),\n// }),\n// ),\n// (\n// resolvedEvent: AllStreamResolvedEvent | GlobalSubscriptionEvent,\n// ): ReadEvent<Event, EventStoreDBReadEventMetadata> =>\n// mapFromESDBEvent(resolvedEvent.event as JSONRecordedEvent<Event>),\n// );\n// };\n"],"mappings":"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","names":["uuid","operationResult","uuid","newCollection","message","uuid","message","projection","event","uuid","retry","uuid","options"]}