@event-driven-io/emmett-mongodb 0.31.0 → 0.32.0

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.cjs CHANGED
@@ -386,8 +386,8 @@ var streamTransformations = {
386
386
  };
387
387
  var { retry: retry2 } = streamTransformations;
388
388
  var AssertionError = class extends Error {
389
- constructor(message) {
390
- super(message);
389
+ constructor(message2) {
390
+ super(message2);
391
391
  }
392
392
  };
393
393
  var isSubset = (superObj, subObj) => {
@@ -402,15 +402,15 @@ var isSubset = (superObj, subObj) => {
402
402
  return sub[ele] === sup[ele];
403
403
  });
404
404
  };
405
- var assertFails = (message) => {
406
- throw new AssertionError(_nullishCoalesce(message, () => ( "That should not ever happened, right?")));
405
+ var assertFails = (message2) => {
406
+ throw new AssertionError(_nullishCoalesce(message2, () => ( "That should not ever happened, right?")));
407
407
  };
408
- function assertTrue(condition, message) {
408
+ function assertTrue(condition, message2) {
409
409
  if (condition !== true)
410
- throw new AssertionError(_nullishCoalesce(message, () => ( `Condition is false`)));
410
+ throw new AssertionError(_nullishCoalesce(message2, () => ( `Condition is false`)));
411
411
  }
412
- function assertOk(obj, message) {
413
- if (!obj) throw new AssertionError(_nullishCoalesce(message, () => ( `Condition is not truthy`)));
412
+ function assertOk(obj, message2) {
413
+ if (!obj) throw new AssertionError(_nullishCoalesce(message2, () => ( `Condition is not truthy`)));
414
414
  }
415
415
 
416
416
  // src/eventStore/mongoDBEventStore.ts
@@ -776,7 +776,7 @@ var MongoDBEventStoreImplementation = (_class4 = class {
776
776
  let streamOffset = currentStreamVersion;
777
777
  const eventsToAppend = events.map((event) => {
778
778
  const metadata = {
779
- eventId: _uuid.v4.call(void 0, ),
779
+ messageId: _uuid.v4.call(void 0, ),
780
780
  streamName,
781
781
  streamPosition: ++streamOffset
782
782
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/emmett/emmett/src/packages/emmett-mongodb/dist/index.cjs","../../emmett/src/validation/index.ts","../../emmett/src/errors/index.ts","../../emmett/src/eventStore/inMemoryEventStore.ts","../../emmett/src/eventStore/subscriptions/caughtUpTransformStream.ts","../../emmett/src/eventStore/subscriptions/streamingCoordinator.ts","../../emmett/src/streaming/transformations/notifyAboutNoActiveReaders.ts","../../emmett/src/utils/retry.ts","../../emmett/src/streaming/generators/fromArray.ts","../../emmett/src/streaming/restream.ts","../../emmett/src/streaming/transformations/filter.ts","../../emmett/src/streaming/transformations/map.ts","../../emmett/src/streaming/transformations/reduce.ts","../../emmett/src/streaming/transformations/retry.ts","../../emmett/src/streaming/transformations/skip.ts","../../emmett/src/streaming/transformations/stopAfter.ts","../../emmett/src/streaming/transformations/stopOn.ts","../../emmett/src/streaming/transformations/take.ts","../../emmett/src/streaming/transformations/waitAtMost.ts","../../emmett/src/eventStore/afterCommit/afterEventStoreCommitHandler.ts","../../emmett/src/eventStore/expectedVersion.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/serialization/json/JSONParser.ts","../../emmett/src/projections/index.ts","../../emmett/src/streaming/transformations/index.ts","../../emmett/src/testing/assertions.ts","../src/eventStore/mongoDBEventStore.ts","../src/eventStore/projections/mongoDBInlineProjection.ts","../src/eventStore/projections/mongoDBInlineProjectionSpec.ts","../src/eventStore/storage/mongoDBEventStoreStorage.ts"],"names":["map"],"mappings":"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","file":"/home/runner/work/emmett/emmett/src/packages/emmett-mongodb/dist/index.cjs","sourcesContent":[null,"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\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 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 : 500;\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\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: 412,\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\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 400,\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: 403,\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: 404,\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 { v4 as uuid } from 'uuid';\nimport type {\n BigIntStreamPosition,\n CombinedReadEventMetadata,\n Event,\n ReadEvent,\n ReadEventMetadataWithGlobalPosition,\n} from '../typing';\nimport { tryPublishMessagesAfterCommit } from './afterCommit';\nimport {\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type DefaultEventStoreOptions,\n type EventStore,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\nimport { StreamingCoordinator } from './subscriptions';\nimport type { ProjectionRegistration } from '../projections';\n\nexport const InMemoryEventStoreDefaultStreamVersion = 0n;\n\nexport type InMemoryEventStore =\n EventStore<ReadEventMetadataWithGlobalPosition>;\n\nexport type InMemoryReadEventMetadata = ReadEventMetadataWithGlobalPosition;\n\nexport type InMemoryProjectionHandlerContext = {\n eventStore: InMemoryEventStore;\n};\n\nexport type InMemoryEventStoreOptions =\n DefaultEventStoreOptions<InMemoryEventStore> & {\n projections?: ProjectionRegistration<\n 'inline',\n InMemoryReadEventMetadata,\n InMemoryProjectionHandlerContext\n >[];\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 const streamingCoordinator = StreamingCoordinator();\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 const _inlineProjections = (eventStoreOptions?.projections ?? [])\n .filter(({ type }) => type === 'inline')\n .map(({ projection }) => projection);\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n ReadEventMetadataWithGlobalPosition\n >,\n ): Promise<AggregateStreamResult<State>> {\n const { evolve, initialState, read } = options;\n\n const result = await this.readStream<EventType>(streamName, read);\n\n const events = result?.events ?? [];\n\n return {\n currentStreamVersion: BigInt(events.length),\n state: events.reduce(evolve, initialState()),\n streamExists: result.streamExists,\n };\n },\n\n readStream: <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions<BigIntStreamPosition>,\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 options?.expectedStreamVersion,\n InMemoryEventStoreDefaultStreamVersion,\n );\n\n const from = Number(options && 'from' in options ? options.from : 0);\n const to = Number(\n options && 'to' in options\n ? options.to\n : options && 'maxCount' in options && options.maxCount\n ? options.from + options.maxCount\n : (events?.length ?? 1),\n );\n\n const resultEvents =\n events !== undefined && events.length > 0\n ? events\n .map(\n (e) =>\n e as ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >,\n )\n .slice(from, to)\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 <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\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 metadata: ReadEventMetadataWithGlobalPosition = {\n streamName,\n eventId: uuid(),\n streamPosition: BigInt(currentEvents.length + index + 1),\n globalPosition: BigInt(getAllEventsCount() + index + 1),\n };\n return {\n ...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, [...currentEvents, ...newEvents]);\n await streamingCoordinator.notify(newEvents);\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 //streamEvents: streamingCoordinator.stream,\n };\n};\n","import { TransformStream } from 'web-streams-polyfill';\nimport type {\n Event,\n ReadEvent,\n ReadEventMetadataWithGlobalPosition,\n} from '../../typing';\nimport { globalStreamCaughtUp, type GlobalSubscriptionEvent } from '../events';\n\nexport const streamTrackingGlobalPosition = (\n currentEvents: ReadEvent<Event, ReadEventMetadataWithGlobalPosition>[],\n) => new CaughtUpTransformStream(currentEvents);\n\nexport class CaughtUpTransformStream extends TransformStream<\n ReadEvent<Event, ReadEventMetadataWithGlobalPosition>,\n | ReadEvent<Event, ReadEventMetadataWithGlobalPosition>\n | GlobalSubscriptionEvent\n> {\n private _currentPosition: bigint;\n private _logPosition: bigint;\n\n constructor(events: ReadEvent<Event, ReadEventMetadataWithGlobalPosition>[]) {\n super({\n start: (controller) => {\n let globalPosition = 0n;\n for (const event of events) {\n controller.enqueue(event);\n globalPosition = event.metadata.globalPosition;\n }\n controller.enqueue(globalStreamCaughtUp({ globalPosition }));\n },\n transform: (event, controller) => {\n this._currentPosition = event.metadata.globalPosition;\n controller.enqueue(event);\n\n if (this._currentPosition < this._logPosition) return;\n\n controller.enqueue(\n globalStreamCaughtUp({ globalPosition: this._currentPosition }),\n );\n },\n });\n\n this._currentPosition = this._logPosition =\n events.length > 0\n ? events[events.length - 1]!.metadata.globalPosition\n : 0n;\n }\n\n public set logPosition(value: bigint) {\n this._logPosition = value;\n }\n}\n","import { v4 as uuid } from 'uuid';\nimport { notifyAboutNoActiveReadersStream } from '../../streaming/transformations/notifyAboutNoActiveReaders';\nimport { writeToStream } from '../../streaming/writers';\nimport type {\n Event,\n ReadEvent,\n ReadEventMetadataWithGlobalPosition,\n} from '../../typing';\nimport {\n CaughtUpTransformStream,\n streamTrackingGlobalPosition,\n} from './caughtUpTransformStream';\n\nexport const StreamingCoordinator = () => {\n const allEvents: ReadEvent<Event, ReadEventMetadataWithGlobalPosition>[] = [];\n const listeners = new Map<string, CaughtUpTransformStream>();\n\n return {\n notify: async (\n events: ReadEvent<Event, ReadEventMetadataWithGlobalPosition>[],\n ) => {\n if (events.length === 0) return;\n\n allEvents.push(...events);\n\n for (const listener of listeners.values()) {\n listener.logPosition =\n events[events.length - 1]!.metadata.globalPosition;\n\n await writeToStream(listener, events);\n }\n },\n\n stream: () => {\n const streamId = uuid();\n const transformStream = streamTrackingGlobalPosition(allEvents);\n\n listeners.set(streamId, transformStream);\n return transformStream.readable.pipeThrough(\n notifyAboutNoActiveReadersStream(\n (stream) => {\n if (listeners.has(stream.streamId))\n listeners.delete(stream.streamId);\n },\n { streamId },\n ),\n );\n },\n };\n};\n","import { v4 as uuid } from 'uuid';\nimport { TransformStream } from 'web-streams-polyfill';\n\nexport const notifyAboutNoActiveReadersStream = <Item>(\n onNoActiveReaderCallback: (\n stream: NotifyAboutNoActiveReadersStream<Item>,\n ) => void,\n options: { streamId?: string; intervalCheckInMs?: number } = {},\n) => new NotifyAboutNoActiveReadersStream(onNoActiveReaderCallback, options);\n\nexport class NotifyAboutNoActiveReadersStream<Item> extends TransformStream<\n Item,\n Item\n> {\n private checkInterval: NodeJS.Timeout | null = null;\n public readonly streamId: string;\n private _isStopped: boolean = false;\n public get hasActiveSubscribers() {\n return !this._isStopped;\n }\n\n constructor(\n private onNoActiveReaderCallback: (\n stream: NotifyAboutNoActiveReadersStream<Item>,\n ) => void,\n options: { streamId?: string; intervalCheckInMs?: number } = {},\n ) {\n super({\n cancel: (reason) => {\n console.log('Stream was canceled. Reason:', reason);\n this.stopChecking();\n },\n });\n this.streamId = options?.streamId ?? uuid();\n\n this.onNoActiveReaderCallback = onNoActiveReaderCallback;\n\n this.startChecking(options?.intervalCheckInMs ?? 20);\n }\n\n private startChecking(interval: number) {\n this.checkInterval = setInterval(() => {\n this.checkNoActiveReader();\n }, interval);\n }\n\n private stopChecking() {\n if (!this.checkInterval) return;\n\n clearInterval(this.checkInterval);\n this.checkInterval = null;\n this._isStopped = true;\n this.onNoActiveReaderCallback(this);\n }\n\n private checkNoActiveReader() {\n if (!this.readable.locked && !this._isStopped) {\n this.stopChecking();\n }\n }\n}\n","import retry from 'async-retry';\n\nexport type AsyncRetryOptions = retry.Options & {\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,\n): Promise<T> => {\n if (opts === undefined || opts.retries === 0) return fn();\n\n return retry(\n async (bail) => {\n try {\n return await fn();\n } catch (error) {\n if (opts?.shouldRetryError && !opts.shouldRetryError(error)) {\n bail(error as Error);\n }\n throw error;\n }\n },\n opts ?? { retries: 0 },\n );\n};\n","import { ReadableStream } from 'web-streams-polyfill';\n\nexport const fromArray = <T>(chunks: T[]) =>\n new ReadableStream<T>({\n start(controller) {\n for (const chunk of chunks) controller.enqueue(chunk);\n controller.close();\n },\n });\n","import {\n type ReadableStream,\n type ReadableStreamDefaultReadResult,\n type TransformStreamDefaultController,\n} from 'web-streams-polyfill';\nimport type { AsyncRetryOptions } from '../utils';\nimport type { Decoder } from './decoders';\nimport { DefaultDecoder } from './decoders/composite';\nimport { streamTransformations } from './transformations';\n\nconst { retry } = streamTransformations;\n\nexport const restream = <\n Source = unknown,\n Transformed = Source,\n StreamType = Source,\n>(\n createSourceStream: () => ReadableStream<StreamType>,\n transform: (input: Source) => Transformed = (source) =>\n source as unknown as Transformed,\n retryOptions: AsyncRetryOptions = { forever: true, minTimeout: 25 },\n decoder: Decoder<StreamType, Source> = new DefaultDecoder<Source>(),\n): ReadableStream<Transformed> =>\n retry(createSourceStream, handleChunk(transform, decoder), retryOptions)\n .readable;\n\nconst handleChunk =\n <Source = unknown, Transformed = Source, StreamType = Source>(\n transform: (input: Source) => Transformed = (source) =>\n source as unknown as Transformed,\n decoder: Decoder<StreamType, Source> = new DefaultDecoder<Source>(),\n ) =>\n (\n readResult: ReadableStreamDefaultReadResult<StreamType>,\n controller: TransformStreamDefaultController<Transformed>,\n ): void => {\n const { done: isDone, value } = readResult;\n\n if (value) decoder.addToBuffer(value);\n\n if (!isDone && !decoder.hasCompleteMessage()) return;\n\n decodeAndTransform(decoder, transform, controller);\n };\n\nconst decodeAndTransform = <StreamType, Source, Transformed = Source>(\n decoder: Decoder<StreamType, Source>,\n transform: (input: Source) => Transformed,\n controller: TransformStreamDefaultController<Transformed>,\n) => {\n try {\n const decoded = decoder.decode();\n if (!decoded) return; // TODO: Add a proper handling of decode errors\n\n const transformed = transform(decoded);\n controller.enqueue(transformed);\n } catch (error) {\n controller.error(new Error(`Decoding error: ${error?.toString()}`));\n }\n};\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const filter = <Item>(filter: (item: Item) => boolean) =>\n new TransformStream<Item, Item>({\n transform(chunk, controller) {\n if (filter(chunk)) {\n controller.enqueue(chunk);\n }\n },\n });\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const map = <From, To>(map: (item: From) => To) =>\n new TransformStream<From, To>({\n transform(chunk, controller) {\n controller.enqueue(map(chunk));\n },\n });\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const reduce = <I, O>(\n reducer: (accumulator: O, chunk: I) => O,\n initialValue: O,\n) => new ReduceTransformStream<I, O>(reducer, initialValue);\n\nexport class ReduceTransformStream<I, O> extends TransformStream<I, O> {\n private accumulator: O;\n private reducer: (accumulator: O, chunk: I) => O;\n\n constructor(reducer: (accumulator: O, chunk: I) => O, initialValue: O) {\n super({\n transform: (chunk) => {\n this.accumulator = this.reducer(this.accumulator, chunk);\n },\n flush: (controller) => {\n controller.enqueue(this.accumulator);\n controller.terminate();\n },\n });\n\n this.accumulator = initialValue;\n this.reducer = reducer;\n }\n}\n","import {\n type ReadableStream,\n type ReadableStreamDefaultReadResult,\n TransformStream,\n type TransformStreamDefaultController,\n} from 'web-streams-polyfill';\nimport { type AsyncRetryOptions, asyncRetry } from '../../utils';\n\nexport const retryStream = <\n Source = unknown,\n Transformed = Source,\n StreamType = Source,\n>(\n createSourceStream: () => ReadableStream<StreamType>,\n handleChunk: (\n readResult: ReadableStreamDefaultReadResult<StreamType>,\n controller: TransformStreamDefaultController<Transformed>,\n ) => Promise<void> | void,\n retryOptions: AsyncRetryOptions = { forever: true, minTimeout: 25 },\n): TransformStream<Source, Transformed> =>\n new TransformStream<Source, Transformed>({\n start(controller) {\n asyncRetry(\n () => onRestream(createSourceStream, handleChunk, controller),\n retryOptions,\n ).catch((error) => {\n controller.error(error);\n });\n },\n });\n\nconst onRestream = async <StreamType, Source, Transformed = Source>(\n createSourceStream: () => ReadableStream<StreamType>,\n handleChunk: (\n readResult: ReadableStreamDefaultReadResult<StreamType>,\n controller: TransformStreamDefaultController<Transformed>,\n ) => Promise<void> | void,\n controller: TransformStreamDefaultController<Transformed>,\n): Promise<void> => {\n const sourceStream = createSourceStream();\n const reader = sourceStream.getReader();\n\n try {\n let done: boolean;\n\n do {\n const result = await reader.read();\n done = result.done;\n\n await handleChunk(result, controller);\n\n if (done) {\n controller.terminate();\n }\n } while (!done);\n } finally {\n reader.releaseLock();\n }\n};\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const skip = <T>(limit: number) => new SkipTransformStream<T>(limit);\n\nexport class SkipTransformStream<T> extends TransformStream<T, T> {\n private count = 0;\n private skip: number;\n\n constructor(skip: number) {\n super({\n transform: (chunk, controller) => {\n this.count++;\n if (this.count > this.skip) {\n controller.enqueue(chunk);\n }\n },\n });\n\n this.skip = skip;\n }\n}\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const stopAfter = <Item>(stopCondition: (item: Item) => boolean) =>\n new TransformStream<Item, Item>({\n transform(chunk, controller) {\n controller.enqueue(chunk);\n\n if (stopCondition(chunk)) {\n controller.terminate();\n }\n },\n });\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const stopOn = <Item>(stopCondition: (item: Item) => boolean) =>\n new TransformStream<Item, Item>({\n async transform(chunk, controller) {\n if (!stopCondition(chunk)) {\n controller.enqueue(chunk);\n return;\n }\n await Promise.resolve();\n controller.terminate();\n },\n });\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const take = <T>(limit: number) => new TakeTransformStream<T>(limit);\n\nexport class TakeTransformStream<T> extends TransformStream<T, T> {\n private count = 0;\n private limit: number;\n\n constructor(limit: number) {\n super({\n transform: (chunk, controller) => {\n if (this.count < this.limit) {\n this.count++;\n controller.enqueue(chunk);\n } else {\n controller.terminate();\n }\n },\n });\n\n this.limit = limit;\n }\n}\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const waitAtMost = <Item>(waitTimeInMs: number) =>\n new TransformStream<Item, Item>({\n start(controller) {\n const timeoutId = setTimeout(() => {\n controller.terminate();\n }, waitTimeInMs);\n\n const originalTerminate = controller.terminate.bind(controller);\n\n // Clear the timeout if the stream is terminated early\n controller.terminate = () => {\n clearTimeout(timeoutId);\n originalTerminate();\n };\n },\n transform(chunk, controller) {\n controller.enqueue(chunk);\n },\n });\n","import { type Event, type ReadEvent } from '../../typing';\nimport type { EventStore, EventStoreReadEventMetadata } from '../eventStore';\n\ntype AfterEventStoreCommitHandlerWithoutContext<Store extends EventStore> = (\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n) => Promise<void> | void;\n\nexport type AfterEventStoreCommitHandler<\n Store extends EventStore,\n HandlerContext = never,\n> = [HandlerContext] extends [never]\n ? AfterEventStoreCommitHandlerWithoutContext<Store>\n : (\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n context: HandlerContext,\n ) => Promise<void> | void;\n\ntype TryPublishMessagesAfterCommitOptions<\n Store extends EventStore,\n HandlerContext = never,\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,\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 = never,\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 { ConcurrencyError } from '../errors';\nimport type { BigIntStreamPosition, Flavour } from '../typing';\n\nexport type ExpectedStreamVersion<VersionType = BigIntStreamPosition> =\n | ExpectedStreamVersionWithValue<VersionType>\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue<VersionType = BigIntStreamPosition> =\n Flavour<VersionType, 'StreamVersion'>;\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 = <StreamVersion = BigIntStreamPosition>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion>,\n defaultVersion: StreamVersion,\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 StreamVersion = BigIntStreamPosition,\n>(\n current: StreamVersion,\n expected: ExpectedStreamVersion<StreamVersion> | undefined,\n defaultVersion: StreamVersion,\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<\n VersionType = BigIntStreamPosition,\n> extends ConcurrencyError {\n constructor(\n current: VersionType,\n expected: ExpectedStreamVersion<VersionType>,\n ) {\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","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","export const deepEquals = <T>(left: T, right: T): boolean => {\n if (isEquatable(left)) {\n return left.equals(right);\n }\n\n if (Array.isArray(left)) {\n return (\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((val, index) => deepEquals(val, right[index]))\n );\n }\n\n if (\n typeof left !== 'object' ||\n typeof right !== 'object' ||\n left === null ||\n right === null\n ) {\n return left === right;\n }\n\n if (Array.isArray(right)) return false;\n\n const keys1 = Object.keys(left);\n const keys2 = Object.keys(right);\n\n if (\n keys1.length !== keys2.length ||\n !keys1.every((key) => keys2.includes(key))\n )\n return false;\n\n for (const key in left) {\n if (left[key] instanceof Function && right[key] instanceof Function)\n continue;\n\n const isEqual = deepEquals(left[key], right[key]);\n if (!isEqual) {\n return false;\n }\n }\n\n return true;\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 &&\n typeof left === 'object' &&\n 'equals' in left &&\n typeof left['equals'] === 'function'\n );\n};\n","export class ParseError extends Error {\n constructor(text: string) {\n super(`Cannot parse! ${text}`);\n }\n}\n\nexport type Mapper<From, To = From> =\n | ((value: unknown) => To)\n | ((value: Partial<From>) => To)\n | ((value: From) => To)\n | ((value: Partial<To>) => To)\n | ((value: To) => To)\n | ((value: Partial<To | From>) => To)\n | ((value: To | From) => To);\n\nexport type MapperArgs<From, To = From> = Partial<From> &\n From &\n Partial<To> &\n To;\n\nexport type ParseOptions<From, To = From> = {\n reviver?: (key: string, value: unknown) => unknown;\n map?: Mapper<From, To>;\n typeCheck?: <To>(value: unknown) => value is To;\n};\n\nexport type StringifyOptions<From, To = From> = {\n map?: Mapper<From, To>;\n};\n\nexport const JSONParser = {\n stringify: <From, To = From>(\n value: From,\n options?: StringifyOptions<From, To>,\n ) => {\n return JSON.stringify(\n options?.map ? options.map(value as MapperArgs<From, To>) : value,\n //TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n (_, v) => (typeof v === 'bigint' ? v.toString() : v),\n );\n },\n parse: <From, To = From>(\n text: string,\n options?: ParseOptions<From, To>,\n ): To | undefined => {\n const parsed: unknown = JSON.parse(text, options?.reviver);\n\n if (options?.typeCheck && !options?.typeCheck<To>(parsed))\n throw new ParseError(text);\n\n return options?.map\n ? options.map(parsed as MapperArgs<From, To>)\n : (parsed as To | undefined);\n },\n};\n","import { EmmettError } from '../errors';\nimport { JSONParser } from '../serialization';\nimport type {\n AnyEvent,\n AnyReadEventMetadata,\n CanHandle,\n DefaultRecord,\n Event,\n ReadEvent,\n} from '../typing';\nimport { arrayUtils } from '../utils';\n\nexport type ProjectionHandlingType = 'inline' | 'async';\n\nexport type ProjectionHandler<\n EventType extends Event = Event,\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = (\n events: ReadEvent<EventType, EventMetaDataType>[],\n context: ProjectionHandlerContext,\n) => Promise<void> | void;\n\nexport interface ProjectionDefinition<\n EventType extends Event = Event,\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> {\n name?: string;\n canHandle: CanHandle<EventType>;\n handle: ProjectionHandler<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n >;\n}\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 >;\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 ${JSONParser.stringify(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>(\n definition: ProjectionDefinition<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n >,\n): ProjectionDefinition<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n> => definition;\n\nexport const inlineProjections = <\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 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 { filter } from './filter';\nimport { map } from './map';\nimport {\n notifyAboutNoActiveReadersStream,\n NotifyAboutNoActiveReadersStream,\n} from './notifyAboutNoActiveReaders';\nimport { reduce, ReduceTransformStream } from './reduce';\nimport { retryStream } from './retry';\nimport { skip, SkipTransformStream } from './skip';\nimport { stopAfter } from './stopAfter';\nimport { stopOn } from './stopOn';\nimport { take, TakeTransformStream } from './take';\nimport { waitAtMost } from './waitAtMost';\n\nexport const streamTransformations = {\n filter,\n take,\n TakeTransformStream,\n skip,\n SkipTransformStream,\n map,\n notifyAboutNoActiveReadersStream,\n NotifyAboutNoActiveReadersStream,\n reduce,\n ReduceTransformStream,\n retry: retryStream,\n stopAfter,\n stopOn,\n waitAtMost,\n};\n","import { JSONParser } 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 (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<void>,\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: ${JSONParser.stringify(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: ${JSONParser.stringify(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!: ${JSONParser.stringify(error)}`,\n );\n } else {\n assertFails(`Function threw an error: ${JSONParser.stringify(error)}`);\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${JSONParser.stringify(expected)}\\nis not subset of\\n${JSONParser.stringify(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${JSONParser.stringify(expected)}\\nis not equal to\\n${JSONParser.stringify(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${JSONParser.stringify(expected)}\\nis equals to\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertThat = <T>(item: T) => {\n return {\n isEqualTo: (other: T) => assertTrue(deepEquals(item, other)),\n };\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\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: ${JSONParser.stringify(expected)}\\nActual: ${JSONParser.stringify(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: ${JSONParser.stringify(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 ${JSONParser.stringify(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 {\n assertExpectedVersionMatchesCurrent,\n ExpectedVersionConflictError,\n filterProjections,\n tryPublishMessagesAfterCommit,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type Closeable,\n type DefaultEventStoreOptions,\n type Event,\n type EventStore,\n type ProjectionRegistration,\n type ReadEvent,\n type ReadEventMetadataWithoutGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport {\n MongoClient,\n type Collection,\n type Document,\n type Filter,\n type MongoClientOptions,\n type Sort,\n type UpdateFilter,\n type WithId,\n} from 'mongodb';\nimport { v4 as uuid } from 'uuid';\nimport {\n handleInlineProjections,\n MongoDBDefaultInlineProjectionName,\n type MongoDBInlineProjectionDefinition,\n type MongoDBProjectionInlineHandlerContext,\n} from './projections';\nimport {\n mongoDBEventStoreStorage,\n type MongoDBEventStoreStorage,\n type MongoDBEventStoreStorageOptions,\n} from './storage';\n\nexport const MongoDBEventStoreDefaultStreamVersion = 0n;\n\nexport type StreamType = string;\nexport type StreamName<T extends StreamType = StreamType> = `${T}:${string}`;\n\nexport type StreamNameParts<T extends StreamType = StreamType> = {\n streamType: T;\n streamId: string;\n};\n\nexport type StreamCollectionName<T extends StreamType = StreamType> =\n `emt:${T}`;\n\nexport type StreamCollectionNameParts<T extends StreamType = StreamType> = {\n streamType: T;\n};\n\nexport type MongoDBReadModelMetadata = {\n streamId: string;\n name: string;\n schemaVersion: number;\n streamPosition: bigint;\n};\n\nexport type MongoDBReadModel<Doc extends Document = Document> = Doc & {\n _metadata: MongoDBReadModelMetadata;\n};\n\nexport interface EventStream<\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> {\n streamName: string;\n messages: Array<ReadEvent<EventType, EventMetaDataType>>;\n metadata: {\n streamId: string;\n streamType: StreamType;\n streamPosition: bigint;\n createdAt: Date;\n updatedAt: Date;\n };\n projections: Record<string, MongoDBReadModel>;\n}\n\nexport type MongoDBReadEventMetadata =\n ReadEventMetadataWithoutGlobalPosition<bigint>;\n\nexport type MongoDBReadEvent<EventType extends Event = Event> = ReadEvent<\n EventType,\n MongoDBReadEventMetadata\n>;\n\ntype SingleProjectionQueryStreamFilter<T extends StreamType> = {\n projectionName?: string;\n} & ({ streamName: StreamName<T> } | { streamType: T; streamId?: string });\n\ntype MultiProjectionQueryStreamFilter<T extends StreamType> = {\n projectionName?: string;\n} & (\n | { streamNames: StreamName<T>[] }\n | { streamType: T; streamIds?: string[] }\n);\n\ntype MultiProjectionQueryOptions = {\n skip?: number;\n limit?: number;\n sort?: [string, 1 | -1][] | Record<string, 1 | -1>;\n};\n\n/**\n * Helpers for querying inline projections on event streams.\n */\ntype InlineProjectionQueries<T extends StreamType> = {\n /**\n * Helper for querying for a single projection. Similar to `collection.findOne`.\n * @param streamFilter - A filter object for stream level fields. If `streamType` is required if `streamName` is not provided. If `projectionName` is not provided, the default projection will be used (`MongoDBDefaultInlineProjectionName`).\n * @param projectionQuery - A MongoDB filter query based on the projection schema. Internally, this function will prepend each object key with the necessary projection name.\n */\n findOne: <Doc extends Document>(\n streamFilter: SingleProjectionQueryStreamFilter<T>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n ) => Promise<MongoDBReadModel<Doc> | null>;\n /**\n * Helper for querying for multiple projections. Similar to `collection.find`.\n *\n * ***NOTE***: If `streamFilter.streamNames` is an empty array, this function will return an empty array. If `streamFilter.streamIds` is an empty array, the `streamIds` filter will not be used.\n *\n * @param streamFilter - A filter object for stream level fields. If `streamType` is required if `streamNames` is not provided. If `projectionName` is not provided, the default projection will be used (`MongoDBDefaultInlineProjectionName`).\n * @param projectionQuery - A MongoDB filter query based on the projection schema. Internally, this function will prepend each object key with the necessary projection name.\n * @param queryOptions - Additional query options like `skip`, `limit`, and `sort`. `sort`, similar to `projectionQuery`, will prepend each object key with the necessary projection name.\n */\n find: <Doc extends Document>(\n streamFilter: MultiProjectionQueryStreamFilter<T>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n queryOptions?: MultiProjectionQueryOptions,\n ) => Promise<MongoDBReadModel<Doc>[]>;\n /**\n * Returns the total number of documents matching the provided filter options. Similar to `collection.countDocuments`.\n *\n * ***NOTE***: If `streamFilter.streamNames` is an empty array, this function will return `0`. If `streamFilter.streamIds` is an empty array, the `streamIds` filter will not be used.\n *\n * @param streamFilter - A filter object for stream level fields. If `streamType` is required if `streamNames` is not provided. If `projectionName` is not provided, the default projection will be used (`MongoDBDefaultInlineProjectionName`).\n * @param projectionQuery - A MongoDB filter query based on the projection schema. Internally, this function will prepend each object key with the necessary projection name.\n */\n count: <Doc extends Document>(\n streamFilter: MultiProjectionQueryStreamFilter<T>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n ) => Promise<number>;\n};\n\n/**\n * Helpers for querying projections on event streams.\n */\ntype ProjectionQueries<T extends StreamType> = {\n inline: InlineProjectionQueries<T>;\n};\n\nexport type MongoDBEventStoreClientOptions = {\n client: MongoClient;\n connectionString?: never;\n clientOptions?: never;\n};\n\nexport type MongoDBEventStoreConnectionStringOptions = {\n client?: never;\n connectionString: string;\n clientOptions?: MongoClientOptions;\n};\n\nexport type MongoDBEventStoreConnectionOptions =\n | MongoDBEventStoreClientOptions\n | MongoDBEventStoreConnectionStringOptions;\n\nexport type MongoDBEventStoreOptions = {\n projections?: ProjectionRegistration<\n 'inline',\n MongoDBReadEventMetadata,\n MongoDBProjectionInlineHandlerContext\n >[];\n storage?: MongoDBEventStoreStorageOptions;\n} & MongoDBEventStoreConnectionOptions &\n DefaultEventStoreOptions<MongoDBEventStore>;\n\nexport type MongoDBEventStore = EventStore<MongoDBReadEventMetadata> & {\n projections: ProjectionQueries<StreamType>;\n collectionFor: <EventType extends Event>(\n streamType: StreamType,\n ) => Promise<Collection<EventStream<EventType>>>;\n};\n\nclass MongoDBEventStoreImplementation implements MongoDBEventStore, Closeable {\n private readonly client: MongoClient;\n private readonly inlineProjections: MongoDBInlineProjectionDefinition[];\n private shouldManageClientLifetime: boolean;\n private isClosed: boolean = false;\n private storage: MongoDBEventStoreStorage;\n private options: MongoDBEventStoreOptions;\n public projections: ProjectionQueries<StreamType>;\n\n constructor(options: MongoDBEventStoreOptions) {\n this.options = options;\n this.client =\n 'client' in options && options.client\n ? options.client\n : new MongoClient(options.connectionString, options.clientOptions);\n this.shouldManageClientLifetime = !('client' in options);\n this.storage = mongoDBEventStoreStorage({\n storage: options.storage,\n getConnectedClient: () => this.getConnectedClient(),\n });\n this.inlineProjections = filterProjections(\n 'inline',\n options.projections ?? [],\n ) as MongoDBInlineProjectionDefinition[];\n\n this.projections = {\n inline: {\n findOne: this.findOneInlineProjection.bind(this),\n find: this.findInlineProjection.bind(this),\n count: this.countInlineProjection.bind(this),\n },\n };\n }\n\n async readStream<EventType extends Event>(\n streamName: StreamName,\n options?: ReadStreamOptions,\n ): Promise<\n Exclude<ReadStreamResult<EventType, MongoDBReadEventMetadata>, null>\n > {\n const { streamType } = fromStreamName(streamName);\n const expectedStreamVersion = options?.expectedStreamVersion;\n\n const collection = await this.storage.collectionFor(streamType);\n\n const filter = {\n streamName: { $eq: streamName },\n };\n\n const eventsSliceArr: number[] = [];\n\n if (options && 'from' in options) {\n eventsSliceArr.push(Number(options.from));\n } else {\n eventsSliceArr.push(0);\n }\n\n if (options && 'to' in options) {\n eventsSliceArr.push(Number(options.to));\n }\n\n const eventsSlice =\n eventsSliceArr.length > 1 ? { $slice: eventsSliceArr } : 1;\n\n const stream = await collection.findOne<\n WithId<Pick<EventStream<EventType>, 'metadata' | 'messages'>>\n >(filter, {\n useBigInt64: true,\n projection: {\n metadata: 1,\n messages: eventsSlice,\n },\n });\n\n if (!stream) {\n return {\n events: [],\n currentStreamVersion: MongoDBEventStoreDefaultStreamVersion,\n streamExists: false,\n };\n }\n\n assertExpectedVersionMatchesCurrent(\n stream.metadata.streamPosition,\n expectedStreamVersion,\n MongoDBEventStoreDefaultStreamVersion,\n );\n\n return {\n events: stream.messages,\n currentStreamVersion: stream.metadata.streamPosition,\n streamExists: true,\n };\n }\n\n async aggregateStream<State, EventType extends Event>(\n streamName: StreamName,\n options: AggregateStreamOptions<State, EventType, MongoDBReadEventMetadata>,\n ): Promise<AggregateStreamResult<State>> {\n const stream = await this.readStream<EventType>(streamName, options?.read);\n\n const state = stream.events.reduce(options.evolve, options.initialState());\n return {\n state,\n currentStreamVersion: stream.currentStreamVersion,\n streamExists: stream.streamExists,\n };\n }\n\n async appendToStream<EventType extends Event>(\n streamName: StreamName,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> {\n const { streamId, streamType } = fromStreamName(streamName);\n const expectedStreamVersion = options?.expectedStreamVersion;\n\n const collection = await this.storage.collectionFor(streamType);\n\n const stream = await collection.findOne<\n WithId<Pick<EventStream<EventType>, 'metadata' | 'projections'>>\n >(\n { streamName: { $eq: streamName } },\n {\n useBigInt64: true,\n projection: {\n 'metadata.streamPosition': 1,\n projections: 1,\n },\n },\n );\n\n const currentStreamVersion =\n stream?.metadata.streamPosition ?? MongoDBEventStoreDefaultStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n MongoDBEventStoreDefaultStreamVersion,\n );\n\n let streamOffset = currentStreamVersion;\n\n const eventsToAppend: ReadEvent<EventType, MongoDBReadEventMetadata>[] =\n events.map((event) => {\n const metadata: MongoDBReadEventMetadata = {\n eventId: uuid(),\n streamName,\n streamPosition: ++streamOffset,\n };\n return {\n type: event.type,\n data: event.data,\n metadata: {\n ...metadata,\n ...('metadata' in event ? (event.metadata ?? {}) : {}),\n },\n } as ReadEvent<EventType, MongoDBReadEventMetadata>;\n });\n\n const now = new Date();\n const updates: UpdateFilter<EventStream> = {\n $push: { messages: { $each: eventsToAppend } },\n $set: {\n 'metadata.updatedAt': now,\n 'metadata.streamPosition': currentStreamVersion + BigInt(events.length),\n },\n $setOnInsert: {\n streamName,\n 'metadata.streamId': streamId,\n 'metadata.streamType': streamType,\n 'metadata.createdAt': now,\n },\n };\n\n if (this.inlineProjections) {\n await handleInlineProjections({\n readModels: stream?.projections ?? {},\n streamId,\n events: eventsToAppend,\n projections: this.inlineProjections,\n collection,\n updates,\n client: {},\n });\n }\n\n const updatedStream = await collection.updateOne(\n {\n streamName: { $eq: streamName },\n 'metadata.streamPosition': currentStreamVersion,\n },\n updates,\n { useBigInt64: true, upsert: true },\n );\n\n if (!updatedStream) {\n throw new ExpectedVersionConflictError(\n currentStreamVersion,\n options?.expectedStreamVersion ?? 0n,\n );\n }\n\n await tryPublishMessagesAfterCommit<MongoDBEventStore>(\n eventsToAppend,\n this.options.hooks,\n // {\n // TODO: same context as InlineProjectionHandlerContext for mongodb?\n // },\n );\n\n return {\n nextExpectedStreamVersion:\n currentStreamVersion + BigInt(eventsToAppend.length),\n createdNewStream:\n currentStreamVersion === MongoDBEventStoreDefaultStreamVersion,\n };\n }\n\n collectionFor = async <EventType extends Event>(\n streamType: StreamType,\n ): Promise<Collection<EventStream<EventType>>> => {\n return this.storage.collectionFor(streamType);\n };\n\n /**\n * Gracefully cleans up managed resources by the MongoDBEventStore.\n * It closes MongoDB client created for the provided connection string\n * through event store options.\n *\n * @memberof Closeable\n */\n close = (): Promise<void> => {\n if (this.isClosed) return Promise.resolve();\n\n this.isClosed = true;\n if (!this.shouldManageClientLifetime) return Promise.resolve();\n\n return this.client.close();\n };\n\n private async findOneInlineProjection<Doc extends Document>(\n streamFilter: SingleProjectionQueryStreamFilter<StreamType>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n ) {\n const { projectionName, streamName, streamType } =\n parseSingleProjectionQueryStreamFilter(streamFilter);\n const collection = await this.storage.collectionFor(streamType);\n const query = prependMongoFilterWithProjectionPrefix<\n Filter<MongoDBReadModel<Doc>> | undefined,\n Filter<EventStream> | undefined\n >(projectionQuery, `projections.${projectionName}`);\n\n const filters: Filter<EventStream>[] = [\n { [`projections.${projectionName}`]: { $exists: true } },\n ];\n\n if (query) {\n filters.push(query);\n }\n\n if (streamName) {\n filters.push({ streamName: { $eq: streamName } });\n }\n\n const result = await collection.findOne<{\n projections: Record<typeof projectionName, MongoDBReadModel<Doc>>;\n }>(\n { $and: filters },\n {\n useBigInt64: true,\n projection: { [`projections.${projectionName}`]: 1 },\n },\n );\n\n return result?.projections?.[projectionName] ?? null;\n }\n\n private async findInlineProjection<Doc extends Document>(\n streamFilter: MultiProjectionQueryStreamFilter<StreamType>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n queryOptions?: MultiProjectionQueryOptions,\n ) {\n const parsedStreamFilter =\n parseMultiProjectionQueryStreamFilter(streamFilter);\n if (!parsedStreamFilter) return [];\n const { projectionName, streamNames, streamType } = parsedStreamFilter;\n\n const collection = await this.storage.collectionFor(streamType);\n const prefix = `projections.${projectionName}`;\n const projectionFilter = prependMongoFilterWithProjectionPrefix<\n Filter<MongoDBReadModel<Doc>> | undefined,\n Filter<EventStream> | undefined\n >(projectionQuery, prefix);\n\n const filters: Filter<EventStream>[] = [\n { [`projections.${projectionName}`]: { $exists: true } },\n ];\n\n if (projectionFilter) {\n filters.push(projectionFilter);\n }\n\n if (streamNames) {\n filters.push({ streamName: { $in: streamNames } });\n }\n\n let query = collection.find<\n EventStream & {\n projections: Record<typeof projectionName, MongoDBReadModel<Doc>>;\n }\n >(\n { $and: filters },\n {\n useBigInt64: true,\n projection: { [`projections.${projectionName}`]: 1 },\n },\n );\n\n if (queryOptions?.skip) {\n query = query.skip(queryOptions.skip);\n }\n\n if (queryOptions?.limit) {\n query = query.limit(queryOptions.limit);\n }\n\n if (queryOptions?.sort) {\n const sort = prependMongoFilterWithProjectionPrefix<Sort>(\n queryOptions.sort,\n prefix,\n );\n query = query.sort(sort);\n }\n\n const streams = await query.toArray();\n\n return streams\n .map((s) => s.projections[projectionName])\n .filter((p): p is MongoDBReadModel<Doc> => !!p);\n }\n\n private async countInlineProjection<Doc extends Document>(\n streamFilter: MultiProjectionQueryStreamFilter<StreamType>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n ) {\n const parsedStreamFilter =\n parseMultiProjectionQueryStreamFilter(streamFilter);\n if (!parsedStreamFilter) return 0;\n const { projectionName, streamNames, streamType } = parsedStreamFilter;\n\n const collection = await this.storage.collectionFor(streamType);\n const prefix = `projections.${projectionName}`;\n const projectionFilter = prependMongoFilterWithProjectionPrefix<\n Filter<MongoDBReadModel<Doc>> | undefined,\n Filter<EventStream> | undefined\n >(projectionQuery, prefix);\n\n const filters: Filter<EventStream>[] = [\n { [`projections.${projectionName}`]: { $exists: true } },\n ];\n\n if (projectionFilter) {\n filters.push(projectionFilter);\n }\n\n if (streamNames) {\n filters.push({ streamName: { $in: streamNames } });\n }\n\n const total = await collection.countDocuments({ $and: filters });\n return total;\n }\n\n private getConnectedClient = async (): Promise<MongoClient> => {\n if (!this.isClosed) await this.client.connect();\n return this.client;\n };\n}\n\nfunction parseSingleProjectionQueryStreamFilter<\n T extends StreamType = StreamType,\n>(streamFilter: SingleProjectionQueryStreamFilter<T>) {\n const projectionName =\n streamFilter.projectionName ?? MongoDBDefaultInlineProjectionName;\n\n if ('streamName' in streamFilter) {\n const { streamType } = fromStreamName(streamFilter.streamName);\n return {\n projectionName,\n streamName: streamFilter.streamName,\n streamType,\n };\n }\n\n if (streamFilter.streamId) {\n const streamName = toStreamName(\n streamFilter.streamType,\n streamFilter.streamId,\n );\n return {\n projectionName,\n streamName,\n streamType: streamFilter.streamType,\n };\n }\n\n return {\n projectionName,\n streamType: streamFilter.streamType,\n };\n}\n\nfunction parseMultiProjectionQueryStreamFilter<T extends StreamType>(\n streamFilter: MultiProjectionQueryStreamFilter<T>,\n) {\n const projectionName =\n streamFilter.projectionName ?? MongoDBDefaultInlineProjectionName;\n\n if ('streamNames' in streamFilter) {\n if (streamFilter.streamNames.length == 0) return null;\n const { streamType } = fromStreamName(streamFilter.streamNames[0]!);\n return {\n projectionName,\n streamNames: streamFilter.streamNames,\n streamType,\n };\n }\n\n if (streamFilter.streamIds && streamFilter.streamIds.length > 0) {\n const streamNames = streamFilter.streamIds.map((id) =>\n toStreamName(streamFilter.streamType, id),\n );\n return {\n projectionName,\n streamNames,\n streamType: streamFilter.streamType,\n };\n }\n\n return {\n projectionName,\n streamType: streamFilter.streamType,\n };\n}\n\n/**\n * Prepends `prefix` to all object keys that don't start with a '$'\n */\nexport function prependMongoFilterWithProjectionPrefix<T, Result = T>(\n obj: T,\n prefix: string,\n): Result {\n if (typeof obj !== 'object' || obj === null || obj === undefined) {\n return obj as unknown as Result;\n }\n\n if (Array.isArray(obj)) {\n for (let i = 0; i < obj.length; i++) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n obj[i] = prependMongoFilterWithProjectionPrefix(obj[i], prefix);\n }\n return obj as unknown as Result;\n }\n\n for (const key in obj) {\n // @ts-expect-error we're forcing `k` to be a key of `T`\n const k: keyof typeof obj = addProjectionPrefixToMongoKey(key, prefix);\n if (k !== key) {\n obj[k] = obj[key as keyof typeof obj];\n delete obj[key as keyof typeof obj];\n }\n\n obj[k] = prependMongoFilterWithProjectionPrefix(obj[k], prefix);\n }\n\n return obj as unknown as Result;\n}\n\nfunction addProjectionPrefixToMongoKey(key: string, prefix: string): string {\n // MongoDB operators\n if (key[0] === '$') {\n return key;\n }\n\n return `${prefix}${key.length > 0 ? '.' : ''}${key}`;\n}\n\nexport function getMongoDBEventStore(\n options: MongoDBEventStoreOptions & { client: MongoClient },\n): MongoDBEventStore;\n\nexport function getMongoDBEventStore(\n options: MongoDBEventStoreOptions & { connectionString: string },\n): MongoDBEventStore & Closeable;\n\n// Implementation signature covers both, using a union for `options`\nexport function getMongoDBEventStore(\n options: MongoDBEventStoreOptions,\n): MongoDBEventStore | Closeable {\n const impl = new MongoDBEventStoreImplementation(options);\n\n // If a client is provided externally, we don't want to allow closing it\n if ('client' in options && 'close' in impl) {\n delete (impl as Partial<MongoDBEventStoreImplementation>).close;\n }\n\n return impl;\n}\n\n/**\n * Accepts a `streamType` (the type/category of the event stream) and an `streamId`\n * (the individual entity/object or aggregate ID) and combines them to a singular\n * `streamName` which can be used in `EventStore`.\n */\nexport function toStreamName<T extends StreamType>(\n streamType: T,\n streamId: string,\n): StreamName<T> {\n return `${streamType}:${streamId}`;\n}\n\n/**\n * Accepts a fully formatted `streamName` and returns the broken down\n * `streamType` and `streamId`.\n */\nexport function fromStreamName<T extends StreamType>(\n streamName: StreamName<T>,\n): StreamNameParts<T> {\n const parts = streamName.split(':') as [T, string];\n return {\n streamType: parts[0],\n streamId: parts[1],\n };\n}\n\n/**\n * Accepts a `streamType` (the type/category of the event stream)\n * and combines them to a `collectionName` which can be used in `EventStore`.\n */\nexport function toStreamCollectionName<T extends StreamType>(\n streamType: T,\n): StreamCollectionName<T> {\n return `emt:${streamType}`;\n}\n\n/**\n * Accepts a fully formatted `streamCollectionName` and returns the parsed `streamType`.\n */\nexport function fromStreamCollectionName<T extends StreamType>(\n streamCollectionName: StreamCollectionName<T>,\n): StreamCollectionNameParts<T> {\n const parts = streamCollectionName.split(':') as [string, T];\n return {\n streamType: parts[1],\n };\n}\n","import {\n type CanHandle,\n type Event,\n type ProjectionDefinition,\n type ProjectionHandler,\n type ReadEvent,\n} from '@event-driven-io/emmett';\nimport type { Collection, Document, UpdateFilter } from 'mongodb';\nimport type {\n EventStream,\n MongoDBReadEventMetadata,\n MongoDBReadModel,\n MongoDBReadModelMetadata,\n} from '../mongoDBEventStore';\n\nexport const MongoDBDefaultInlineProjectionName = '_default';\n\nexport type MongoDBProjectionInlineHandlerContext<\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> = {\n document: MongoDBReadModel | null;\n streamId: string;\n updates: UpdateFilter<EventStream<EventType, EventMetaDataType>>;\n collection: Collection<EventStream<EventType, EventMetaDataType>>;\n};\n\nexport type MongoDBInlineProjectionHandler<\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> = ProjectionHandler<\n EventType,\n EventMetaDataType,\n MongoDBProjectionInlineHandlerContext\n>;\n\nexport type MongoDBInlineProjectionDefinition<\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> = ProjectionDefinition<\n EventType,\n EventMetaDataType,\n MongoDBProjectionInlineHandlerContext\n> & { name: string };\n\nexport type InlineProjectionHandlerOptions<\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> = {\n readModels: Record<string, MongoDBReadModel>;\n events: Array<ReadEvent<EventType, EventMetaDataType>>;\n projections: MongoDBInlineProjectionDefinition<\n EventType,\n EventMetaDataType\n >[];\n streamId: string;\n collection: Collection<EventStream>;\n updates: UpdateFilter<EventStream<Event>>;\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n client: {\n //todo: add client here\n };\n};\n\nexport const handleInlineProjections = async <\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n>(\n options: InlineProjectionHandlerOptions<EventType, EventMetaDataType>,\n): Promise<void> => {\n const {\n events,\n projections: allProjections,\n updates: update,\n streamId,\n collection,\n readModels,\n } = options;\n\n const eventTypes = events.map((e) => e.type);\n\n const projections = allProjections.filter((p) =>\n p.canHandle.some((type) => eventTypes.includes(type)),\n );\n\n for (const projection of projections) {\n await projection.handle(events, {\n document: readModels[projection.name] ?? null,\n streamId,\n collection,\n updates: update,\n });\n }\n};\n\nexport type MongoDBWithNotNullDocumentEvolve<\n Doc extends Document,\n EventType extends Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> =\n | ((\n document: Doc,\n event: ReadEvent<EventType, EventMetaDataType>,\n ) => Doc | null)\n | ((document: Doc, event: ReadEvent<EventType>) => Promise<Doc | null>);\n\nexport type MongoDBWithNullableDocumentEvolve<\n Doc extends Document,\n EventType extends Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> =\n | ((\n document: Doc | null,\n event: ReadEvent<EventType, EventMetaDataType>,\n ) => Doc | null)\n | ((\n document: Doc | null,\n event: ReadEvent<EventType>,\n ) => Promise<Doc | null>);\n\nexport type MongoDBInlineProjectionOptions<\n Doc extends Document,\n EventType extends Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> = {\n name?: string;\n schemaVersion?: number;\n canHandle: CanHandle<EventType>;\n} & (\n | {\n evolve: MongoDBWithNullableDocumentEvolve<\n Doc,\n EventType,\n EventMetaDataType\n >;\n }\n | {\n evolve: MongoDBWithNotNullDocumentEvolve<\n Doc,\n EventType,\n EventMetaDataType\n >;\n initialState: () => Doc;\n }\n);\n\nexport const mongoDBInlineProjection = <\n Doc extends Document,\n EventType extends Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n>(\n options: MongoDBInlineProjectionOptions<Doc, EventType, EventMetaDataType>,\n): MongoDBInlineProjectionDefinition => {\n const projectionName = options.name ?? MongoDBDefaultInlineProjectionName;\n const schemaVersion = options.schemaVersion ?? 1;\n\n return {\n name: projectionName,\n canHandle: options.canHandle,\n handle: async (events, { document, updates, streamId }) => {\n if (events.length === 0) return;\n\n let state =\n 'initialState' in options\n ? (document ?? options.initialState())\n : document;\n\n for (const event of events) {\n state = await options.evolve(\n state as Doc,\n event as ReadEvent<EventType, EventMetaDataType>,\n );\n }\n\n const metadata: MongoDBReadModelMetadata = {\n streamId,\n name: projectionName,\n schemaVersion,\n streamPosition: events[events.length - 1]!.metadata.streamPosition,\n };\n\n updates.$set![`projections.${projectionName}`] =\n state !== null\n ? {\n ...state,\n _metadata: metadata,\n }\n : null;\n },\n };\n};\n","import {\n assertFails,\n AssertionError,\n assertTrue,\n deepEquals,\n isErrorConstructor,\n isSubset,\n projections,\n type Event,\n type ThenThrows,\n} from '@event-driven-io/emmett';\nimport { MongoClient, type Document } from 'mongodb';\nimport {\n getMongoDBEventStore,\n type MongoDBEventStore,\n type MongoDBEventStoreConnectionOptions,\n type MongoDBReadModel,\n type StreamName,\n} from '../mongoDBEventStore';\nimport {\n MongoDBDefaultInlineProjectionName,\n type MongoDBInlineProjectionDefinition,\n} from './mongoDBInlineProjection';\n\nexport type MongoDBInlineProjectionSpecGivenEvents<\n StreamNameType extends StreamName,\n EventType extends Event,\n> = {\n streamName: StreamNameType;\n events: EventType[];\n};\n\nexport type MongoDBInlineProjectionSpec<\n StreamNameType extends StreamName,\n EventType extends Event,\n> = (\n givenStream: MongoDBInlineProjectionSpecGivenEvents<\n StreamNameType,\n EventType\n >,\n) => {\n when: (events: EventType[]) => {\n then: (\n assert: MongoDBInlineProjectionAssert,\n message?: string,\n ) => Promise<void>;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => Promise<void>;\n };\n};\n\nexport type MongoDBInlineProjectionAssertOptions<\n StreamNameType extends StreamName = StreamName,\n> = {\n streamName: StreamNameType;\n eventStore: MongoDBEventStore;\n};\n\nexport type MongoDBInlineProjectionAssert<\n StreamNameType extends StreamName = StreamName,\n> = (\n options: MongoDBInlineProjectionAssertOptions<StreamNameType>,\n) => Promise<void | boolean>;\n\nexport type MongoDBInlineProjectionSpecOptions = {\n projection: MongoDBInlineProjectionDefinition;\n} & MongoDBEventStoreConnectionOptions;\n\nexport const MongoDBInlineProjectionSpec = {\n for: <StreamNameType extends StreamName, EventType extends Event>(\n options: MongoDBInlineProjectionSpecOptions,\n ): MongoDBInlineProjectionSpec<StreamNameType, EventType> => {\n {\n const { projection, ...connectionOptions } = options;\n\n return (\n givenStream: MongoDBInlineProjectionSpecGivenEvents<\n StreamNameType,\n EventType\n >,\n ) => {\n const { streamName, events: givenEvents } = givenStream;\n return {\n when: (events: EventType[]) => {\n const allEvents = [...givenEvents, ...events];\n\n const run = (eventStore: MongoDBEventStore) =>\n eventStore.appendToStream(streamName, allEvents);\n\n return {\n then: async (\n assert: MongoDBInlineProjectionAssert,\n message?: string,\n ): Promise<void> => {\n const client =\n 'client' in connectionOptions && connectionOptions.client\n ? connectionOptions.client\n : new MongoClient(\n connectionOptions.connectionString,\n connectionOptions.clientOptions,\n );\n\n const eventStore = getMongoDBEventStore({\n projections: projections.inline([projection]),\n client,\n });\n\n try {\n await run(eventStore);\n\n const succeeded = await assert({ eventStore, streamName });\n\n if (succeeded !== undefined && succeeded === false)\n assertFails(\n message ??\n \"Projection specification didn't match the criteria\",\n );\n } finally {\n await client.close();\n }\n },\n thenThrows: async <ErrorType extends Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): Promise<void> => {\n const client =\n 'client' in connectionOptions && connectionOptions.client\n ? connectionOptions.client\n : new MongoClient(\n connectionOptions.connectionString,\n connectionOptions.clientOptions,\n );\n\n const eventStore = getMongoDBEventStore({\n projections: projections.inline([projection]),\n client,\n });\n\n try {\n await run(eventStore);\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 } finally {\n await client.close();\n }\n },\n };\n },\n };\n };\n }\n },\n};\n\nexport const eventInStream = <\n StreamNameType extends StreamName,\n EventType extends Event,\n>(\n streamName: StreamNameType,\n event: EventType,\n): MongoDBInlineProjectionSpecGivenEvents<StreamNameType, EventType> => ({\n streamName,\n events: [event],\n});\n\nexport const eventsInStream = <\n StreamNameType extends StreamName,\n EventType extends Event,\n>(\n streamName: StreamNameType,\n events: EventType[],\n): MongoDBInlineProjectionSpecGivenEvents<StreamNameType, EventType> => ({\n streamName,\n events,\n});\n\nconst expectReadModelToMatch = async <\n Doc extends Document = Document,\n StreamNameType extends StreamName = StreamName,\n>(\n options: MongoDBInlineProjectionAssertOptions<StreamNameType> & {\n projectionName: string;\n match: (readModel: MongoDBReadModel<Doc> | null) => boolean;\n },\n) => {\n const { streamName, projectionName, eventStore, match } = options;\n const readModel = await eventStore.projections.inline.findOne<Doc>({\n streamName,\n projectionName,\n });\n\n return match(readModel);\n};\n\nconst expectInlineReadModelWithName = (projectionName: string) => ({\n toHave:\n <Doc extends Document, StreamNameType extends StreamName = StreamName>(\n expected: Partial<MongoDBReadModel<Doc>> | null,\n ): MongoDBInlineProjectionAssert<StreamNameType> =>\n ({ eventStore, streamName }) =>\n expectReadModelToMatch<Doc>({\n eventStore,\n streamName,\n projectionName,\n match: (readModel) => isSubset(readModel, expected),\n }),\n toDeepEquals:\n <Doc extends Document, StreamNameType extends StreamName = StreamName>(\n expected: MongoDBReadModel<Doc> | null,\n ): MongoDBInlineProjectionAssert<StreamNameType> =>\n ({ eventStore, streamName }) =>\n expectReadModelToMatch<Doc>({\n eventStore,\n streamName,\n projectionName,\n match: (readModel) => deepEquals(readModel, expected),\n }),\n toMatch:\n <Doc extends Document, StreamNameType extends StreamName = StreamName>(\n match: (readModel: MongoDBReadModel<Doc> | null) => boolean,\n ): MongoDBInlineProjectionAssert<StreamNameType> =>\n ({ eventStore, streamName }) =>\n expectReadModelToMatch<Doc>({\n eventStore,\n streamName,\n projectionName,\n match,\n }),\n notToExist:\n <\n StreamNameType extends StreamName = StreamName,\n >(): MongoDBInlineProjectionAssert<StreamNameType> =>\n ({ eventStore, streamName }) =>\n expectReadModelToMatch({\n eventStore,\n streamName,\n projectionName,\n match: (readModel) => readModel === null,\n }),\n toExist:\n (): MongoDBInlineProjectionAssert =>\n ({ eventStore, streamName }) =>\n expectReadModelToMatch({\n eventStore,\n streamName,\n projectionName,\n match: (readModel) => readModel !== null,\n }),\n});\n\nexport const expectInlineReadModel = {\n withName: (name: string) => expectInlineReadModelWithName(name),\n ...expectInlineReadModelWithName(MongoDBDefaultInlineProjectionName),\n};\n","import { type Event } from '@event-driven-io/emmett';\nimport type { Collection, Db, MongoClient } from 'mongodb';\nimport {\n toStreamCollectionName,\n type EventStream,\n type StreamType,\n} from '../mongoDBEventStore';\n\nexport type MongoDBEventStoreCollectionPerStreamTypeStorageOptions = {\n /**\n * The recommended setting where each stream type will be kept\n * in a separate collection type using the format: `emt_${streamType}`.\n */\n type: 'COLLECTION_PER_STREAM_TYPE';\n databaseName?: string;\n};\n\nexport type MongoDBEventStoreSingleCollectionStorageOptions = {\n /**\n * All streams will be kept withing a single MongDB collection\n * It'll either use default collection name (\"emt_streams\")\n * or provided name through 'collection' param.\n */\n type: 'SINGLE_COLLECTION';\n collectionName?: string;\n databaseName?: string;\n};\n\nexport type MongoDBEventStoreCollectionResolution = {\n databaseName?: string;\n collectionName: string;\n};\n\nexport type MongoDBEventStoreCustomStorageOptions = {\n /**\n * This is advanced option, where you specify your own collection\n * resolution function. You can do that by specifying the `collectionFor` function.\n */\n type: 'CUSTOM';\n databaseName?: string;\n collectionFor: <T extends StreamType>(\n streamType: T,\n ) => string | MongoDBEventStoreCollectionResolution;\n};\n\nexport type MongoDBEventStoreStorageOptions =\n | 'COLLECTION_PER_STREAM_TYPE'\n | 'SINGLE_COLLECTION'\n | MongoDBEventStoreSingleCollectionStorageOptions\n | MongoDBEventStoreCollectionPerStreamTypeStorageOptions\n | MongoDBEventStoreCustomStorageOptions;\n\nexport const DefaultMongoDBEventStoreStorageOptions =\n 'COLLECTION_PER_STREAM_TYPE';\n\nexport type MongoDBEventStoreStorage = {\n collectionFor: <T extends StreamType, EventType extends Event = Event>(\n streamType: T,\n ) => Promise<Collection<EventStream<EventType>>>;\n};\n\nexport const DefaultMongoDBEventStoreCollectionName = 'emt:streams';\n\nconst resolveCollectionAndDatabase = <T extends StreamType>(\n streamType: T,\n options: MongoDBEventStoreStorageOptions,\n): MongoDBEventStoreCollectionResolution => {\n if (\n options === 'SINGLE_COLLECTION' ||\n (typeof options === 'object' && options.type === 'SINGLE_COLLECTION')\n ) {\n return {\n collectionName:\n typeof options === 'object'\n ? (options.collectionName ?? DefaultMongoDBEventStoreCollectionName)\n : DefaultMongoDBEventStoreCollectionName,\n databaseName:\n typeof options === 'object' ? options.databaseName : undefined,\n };\n } else if (\n options === 'COLLECTION_PER_STREAM_TYPE' ||\n (typeof options === 'object' &&\n options.type === 'COLLECTION_PER_STREAM_TYPE')\n ) {\n return {\n collectionName: toStreamCollectionName(streamType),\n databaseName:\n typeof options === 'object' ? options.databaseName : undefined,\n };\n } else {\n const result = options.collectionFor(streamType);\n return {\n collectionName:\n typeof result === 'object' ? result.collectionName : result,\n databaseName:\n typeof result === 'object'\n ? (result.databaseName ?? options.databaseName)\n : options.databaseName,\n };\n }\n};\n\nconst getDB = async (options: {\n databaseName: string | undefined;\n dbsCache: Map<string, Db>;\n getConnectedClient: () => Promise<MongoClient>;\n}): Promise<Db> => {\n const { dbsCache, databaseName, getConnectedClient } = options;\n const safeDbName = databaseName ?? '___default';\n\n let db = dbsCache.get(safeDbName);\n\n if (!db) {\n const connectedClient = await getConnectedClient();\n\n db = connectedClient.db(databaseName);\n\n dbsCache.set(safeDbName, db);\n }\n\n return db;\n};\n\nconst collectionFor = async <EventType extends Event = Event>(options: {\n collectionName: string;\n streamCollections: Map<string, Collection<EventStream>>;\n db: Db;\n}): Promise<Collection<EventStream<EventType>>> => {\n const { collectionName, db, streamCollections } = options;\n\n let collection = streamCollections.get(collectionName) as\n | Collection<EventStream<EventType>>\n | undefined;\n\n if (!collection) {\n collection = db.collection<EventStream<EventType>>(collectionName);\n await collection.createIndex({ streamName: 1 }, { unique: true });\n\n streamCollections.set(\n collectionName,\n collection as Collection<EventStream>,\n );\n }\n\n return collection;\n};\n\nexport const mongoDBEventStoreStorage = (options: {\n storage?: MongoDBEventStoreStorageOptions | undefined;\n getConnectedClient: () => Promise<MongoClient>;\n}): MongoDBEventStoreStorage => {\n const dbsCache: Map<string, Db> = new Map();\n const streamCollections: Map<string, Collection<EventStream>> = new Map();\n const storageOptions =\n options.storage ?? DefaultMongoDBEventStoreStorageOptions;\n\n const { getConnectedClient } = options;\n\n return {\n collectionFor: async <\n T extends StreamType,\n EventType extends Event = Event,\n >(\n streamType: T,\n ): Promise<Collection<EventStream<EventType>>> => {\n const { collectionName, databaseName } = resolveCollectionAndDatabase(\n streamType,\n storageOptions,\n );\n\n let collection = streamCollections.get(collectionName) as\n | Collection<EventStream<EventType>>\n | undefined;\n\n if (!collection) {\n const db = await getDB({ databaseName, dbsCache, getConnectedClient });\n collection = await collectionFor<EventType>({\n collectionName,\n streamCollections,\n db,\n });\n }\n\n return collection;\n },\n };\n};\n"]}
1
+ {"version":3,"sources":["/home/runner/work/emmett/emmett/src/packages/emmett-mongodb/dist/index.cjs","../../emmett/src/validation/index.ts","../../emmett/src/errors/index.ts","../../emmett/src/eventStore/inMemoryEventStore.ts","../../emmett/src/eventStore/subscriptions/caughtUpTransformStream.ts","../../emmett/src/eventStore/subscriptions/streamingCoordinator.ts","../../emmett/src/streaming/transformations/notifyAboutNoActiveReaders.ts","../../emmett/src/utils/retry.ts","../../emmett/src/streaming/generators/fromArray.ts","../../emmett/src/streaming/restream.ts","../../emmett/src/streaming/transformations/filter.ts","../../emmett/src/streaming/transformations/map.ts","../../emmett/src/streaming/transformations/reduce.ts","../../emmett/src/streaming/transformations/retry.ts","../../emmett/src/streaming/transformations/skip.ts","../../emmett/src/streaming/transformations/stopAfter.ts","../../emmett/src/streaming/transformations/stopOn.ts","../../emmett/src/streaming/transformations/take.ts","../../emmett/src/streaming/transformations/waitAtMost.ts","../../emmett/src/eventStore/afterCommit/afterEventStoreCommitHandler.ts","../../emmett/src/eventStore/expectedVersion.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/serialization/json/JSONParser.ts","../../emmett/src/projections/index.ts","../../emmett/src/streaming/transformations/index.ts","../../emmett/src/testing/assertions.ts","../src/eventStore/mongoDBEventStore.ts","../src/eventStore/projections/mongoDBInlineProjection.ts","../src/eventStore/projections/mongoDBInlineProjectionSpec.ts","../src/eventStore/storage/mongoDBEventStoreStorage.ts"],"names":["map"],"mappings":"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","file":"/home/runner/work/emmett/emmett/src/packages/emmett-mongodb/dist/index.cjs","sourcesContent":[null,"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\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 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 : 500;\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\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: 412,\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\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 400,\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: 403,\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: 404,\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 { v4 as uuid } from 'uuid';\nimport type {\n BigIntStreamPosition,\n CombinedReadEventMetadata,\n Event,\n ReadEvent,\n ReadEventMetadataWithGlobalPosition,\n} from '../typing';\nimport { tryPublishMessagesAfterCommit } from './afterCommit';\nimport {\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type DefaultEventStoreOptions,\n type EventStore,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\nimport { StreamingCoordinator } from './subscriptions';\nimport type { ProjectionRegistration } from '../projections';\n\nexport const InMemoryEventStoreDefaultStreamVersion = 0n;\n\nexport type InMemoryEventStore =\n EventStore<ReadEventMetadataWithGlobalPosition>;\n\nexport type InMemoryReadEventMetadata = ReadEventMetadataWithGlobalPosition;\n\nexport type InMemoryProjectionHandlerContext = {\n eventStore: InMemoryEventStore;\n};\n\nexport type InMemoryEventStoreOptions =\n DefaultEventStoreOptions<InMemoryEventStore> & {\n projections?: ProjectionRegistration<\n 'inline',\n InMemoryReadEventMetadata,\n InMemoryProjectionHandlerContext\n >[];\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 const streamingCoordinator = StreamingCoordinator();\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 const _inlineProjections = (eventStoreOptions?.projections ?? [])\n .filter(({ type }) => type === 'inline')\n .map(({ projection }) => projection);\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<\n State,\n EventType,\n ReadEventMetadataWithGlobalPosition\n >,\n ): Promise<AggregateStreamResult<State>> {\n const { evolve, initialState, read } = options;\n\n const result = await this.readStream<EventType>(streamName, read);\n\n const events = result?.events ?? [];\n\n return {\n currentStreamVersion: BigInt(events.length),\n state: events.reduce(evolve, initialState()),\n streamExists: result.streamExists,\n };\n },\n\n readStream: <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions<BigIntStreamPosition>,\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 options?.expectedStreamVersion,\n InMemoryEventStoreDefaultStreamVersion,\n );\n\n const from = Number(options && 'from' in options ? options.from : 0);\n const to = Number(\n options && 'to' in options\n ? options.to\n : options && 'maxCount' in options && options.maxCount\n ? options.from + options.maxCount\n : (events?.length ?? 1),\n );\n\n const resultEvents =\n events !== undefined && events.length > 0\n ? events\n .map(\n (e) =>\n e as ReadEvent<\n EventType,\n ReadEventMetadataWithGlobalPosition\n >,\n )\n .slice(from, to)\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 <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\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 metadata: ReadEventMetadataWithGlobalPosition = {\n streamName,\n messageId: uuid(),\n streamPosition: BigInt(currentEvents.length + index + 1),\n globalPosition: BigInt(getAllEventsCount() + index + 1),\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, [...currentEvents, ...newEvents]);\n await streamingCoordinator.notify(newEvents);\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 //streamEvents: streamingCoordinator.stream,\n };\n};\n","import { TransformStream } from 'web-streams-polyfill';\nimport type {\n Event,\n ReadEvent,\n ReadEventMetadataWithGlobalPosition,\n} from '../../typing';\nimport { globalStreamCaughtUp, type GlobalSubscriptionEvent } from '../events';\n\nexport const streamTrackingGlobalPosition = (\n currentEvents: ReadEvent<Event, ReadEventMetadataWithGlobalPosition>[],\n) => new CaughtUpTransformStream(currentEvents);\n\nexport class CaughtUpTransformStream extends TransformStream<\n ReadEvent<Event, ReadEventMetadataWithGlobalPosition>,\n | ReadEvent<Event, ReadEventMetadataWithGlobalPosition>\n | GlobalSubscriptionEvent\n> {\n private _currentPosition: bigint;\n private _logPosition: bigint;\n\n constructor(events: ReadEvent<Event, ReadEventMetadataWithGlobalPosition>[]) {\n super({\n start: (controller) => {\n let globalPosition = 0n;\n for (const event of events) {\n controller.enqueue(event);\n globalPosition = event.metadata.globalPosition;\n }\n controller.enqueue(globalStreamCaughtUp({ globalPosition }));\n },\n transform: (event, controller) => {\n this._currentPosition = event.metadata.globalPosition;\n controller.enqueue(event);\n\n if (this._currentPosition < this._logPosition) return;\n\n controller.enqueue(\n globalStreamCaughtUp({ globalPosition: this._currentPosition }),\n );\n },\n });\n\n this._currentPosition = this._logPosition =\n events.length > 0\n ? events[events.length - 1]!.metadata.globalPosition\n : 0n;\n }\n\n public set logPosition(value: bigint) {\n this._logPosition = value;\n }\n}\n","import { v4 as uuid } from 'uuid';\nimport { notifyAboutNoActiveReadersStream } from '../../streaming/transformations/notifyAboutNoActiveReaders';\nimport { writeToStream } from '../../streaming/writers';\nimport type {\n Event,\n ReadEvent,\n ReadEventMetadataWithGlobalPosition,\n} from '../../typing';\nimport {\n CaughtUpTransformStream,\n streamTrackingGlobalPosition,\n} from './caughtUpTransformStream';\n\nexport const StreamingCoordinator = () => {\n const allEvents: ReadEvent<Event, ReadEventMetadataWithGlobalPosition>[] = [];\n const listeners = new Map<string, CaughtUpTransformStream>();\n\n return {\n notify: async (\n events: ReadEvent<Event, ReadEventMetadataWithGlobalPosition>[],\n ) => {\n if (events.length === 0) return;\n\n allEvents.push(...events);\n\n for (const listener of listeners.values()) {\n listener.logPosition =\n events[events.length - 1]!.metadata.globalPosition;\n\n await writeToStream(listener, events);\n }\n },\n\n stream: () => {\n const streamId = uuid();\n const transformStream = streamTrackingGlobalPosition(allEvents);\n\n listeners.set(streamId, transformStream);\n return transformStream.readable.pipeThrough(\n notifyAboutNoActiveReadersStream(\n (stream) => {\n if (listeners.has(stream.streamId))\n listeners.delete(stream.streamId);\n },\n { streamId },\n ),\n );\n },\n };\n};\n","import { v4 as uuid } from 'uuid';\nimport { TransformStream } from 'web-streams-polyfill';\n\nexport const notifyAboutNoActiveReadersStream = <Item>(\n onNoActiveReaderCallback: (\n stream: NotifyAboutNoActiveReadersStream<Item>,\n ) => void,\n options: { streamId?: string; intervalCheckInMs?: number } = {},\n) => new NotifyAboutNoActiveReadersStream(onNoActiveReaderCallback, options);\n\nexport class NotifyAboutNoActiveReadersStream<Item> extends TransformStream<\n Item,\n Item\n> {\n private checkInterval: NodeJS.Timeout | null = null;\n public readonly streamId: string;\n private _isStopped: boolean = false;\n public get hasActiveSubscribers() {\n return !this._isStopped;\n }\n\n constructor(\n private onNoActiveReaderCallback: (\n stream: NotifyAboutNoActiveReadersStream<Item>,\n ) => void,\n options: { streamId?: string; intervalCheckInMs?: number } = {},\n ) {\n super({\n cancel: (reason) => {\n console.log('Stream was canceled. Reason:', reason);\n this.stopChecking();\n },\n });\n this.streamId = options?.streamId ?? uuid();\n\n this.onNoActiveReaderCallback = onNoActiveReaderCallback;\n\n this.startChecking(options?.intervalCheckInMs ?? 20);\n }\n\n private startChecking(interval: number) {\n this.checkInterval = setInterval(() => {\n this.checkNoActiveReader();\n }, interval);\n }\n\n private stopChecking() {\n if (!this.checkInterval) return;\n\n clearInterval(this.checkInterval);\n this.checkInterval = null;\n this._isStopped = true;\n this.onNoActiveReaderCallback(this);\n }\n\n private checkNoActiveReader() {\n if (!this.readable.locked && !this._isStopped) {\n this.stopChecking();\n }\n }\n}\n","import retry from 'async-retry';\n\nexport type AsyncRetryOptions = retry.Options & {\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,\n): Promise<T> => {\n if (opts === undefined || opts.retries === 0) return fn();\n\n return retry(\n async (bail) => {\n try {\n return await fn();\n } catch (error) {\n if (opts?.shouldRetryError && !opts.shouldRetryError(error)) {\n bail(error as Error);\n }\n throw error;\n }\n },\n opts ?? { retries: 0 },\n );\n};\n","import { ReadableStream } from 'web-streams-polyfill';\n\nexport const fromArray = <T>(chunks: T[]) =>\n new ReadableStream<T>({\n start(controller) {\n for (const chunk of chunks) controller.enqueue(chunk);\n controller.close();\n },\n });\n","import {\n type ReadableStream,\n type ReadableStreamDefaultReadResult,\n type TransformStreamDefaultController,\n} from 'web-streams-polyfill';\nimport type { AsyncRetryOptions } from '../utils';\nimport type { Decoder } from './decoders';\nimport { DefaultDecoder } from './decoders/composite';\nimport { streamTransformations } from './transformations';\n\nconst { retry } = streamTransformations;\n\nexport const restream = <\n Source = unknown,\n Transformed = Source,\n StreamType = Source,\n>(\n createSourceStream: () => ReadableStream<StreamType>,\n transform: (input: Source) => Transformed = (source) =>\n source as unknown as Transformed,\n retryOptions: AsyncRetryOptions = { forever: true, minTimeout: 25 },\n decoder: Decoder<StreamType, Source> = new DefaultDecoder<Source>(),\n): ReadableStream<Transformed> =>\n retry(createSourceStream, handleChunk(transform, decoder), retryOptions)\n .readable;\n\nconst handleChunk =\n <Source = unknown, Transformed = Source, StreamType = Source>(\n transform: (input: Source) => Transformed = (source) =>\n source as unknown as Transformed,\n decoder: Decoder<StreamType, Source> = new DefaultDecoder<Source>(),\n ) =>\n (\n readResult: ReadableStreamDefaultReadResult<StreamType>,\n controller: TransformStreamDefaultController<Transformed>,\n ): void => {\n const { done: isDone, value } = readResult;\n\n if (value) decoder.addToBuffer(value);\n\n if (!isDone && !decoder.hasCompleteMessage()) return;\n\n decodeAndTransform(decoder, transform, controller);\n };\n\nconst decodeAndTransform = <StreamType, Source, Transformed = Source>(\n decoder: Decoder<StreamType, Source>,\n transform: (input: Source) => Transformed,\n controller: TransformStreamDefaultController<Transformed>,\n) => {\n try {\n const decoded = decoder.decode();\n if (!decoded) return; // TODO: Add a proper handling of decode errors\n\n const transformed = transform(decoded);\n controller.enqueue(transformed);\n } catch (error) {\n controller.error(new Error(`Decoding error: ${error?.toString()}`));\n }\n};\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const filter = <Item>(filter: (item: Item) => boolean) =>\n new TransformStream<Item, Item>({\n transform(chunk, controller) {\n if (filter(chunk)) {\n controller.enqueue(chunk);\n }\n },\n });\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const map = <From, To>(map: (item: From) => To) =>\n new TransformStream<From, To>({\n transform(chunk, controller) {\n controller.enqueue(map(chunk));\n },\n });\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const reduce = <I, O>(\n reducer: (accumulator: O, chunk: I) => O,\n initialValue: O,\n) => new ReduceTransformStream<I, O>(reducer, initialValue);\n\nexport class ReduceTransformStream<I, O> extends TransformStream<I, O> {\n private accumulator: O;\n private reducer: (accumulator: O, chunk: I) => O;\n\n constructor(reducer: (accumulator: O, chunk: I) => O, initialValue: O) {\n super({\n transform: (chunk) => {\n this.accumulator = this.reducer(this.accumulator, chunk);\n },\n flush: (controller) => {\n controller.enqueue(this.accumulator);\n controller.terminate();\n },\n });\n\n this.accumulator = initialValue;\n this.reducer = reducer;\n }\n}\n","import {\n type ReadableStream,\n type ReadableStreamDefaultReadResult,\n TransformStream,\n type TransformStreamDefaultController,\n} from 'web-streams-polyfill';\nimport { type AsyncRetryOptions, asyncRetry } from '../../utils';\n\nexport const retryStream = <\n Source = unknown,\n Transformed = Source,\n StreamType = Source,\n>(\n createSourceStream: () => ReadableStream<StreamType>,\n handleChunk: (\n readResult: ReadableStreamDefaultReadResult<StreamType>,\n controller: TransformStreamDefaultController<Transformed>,\n ) => Promise<void> | void,\n retryOptions: AsyncRetryOptions = { forever: true, minTimeout: 25 },\n): TransformStream<Source, Transformed> =>\n new TransformStream<Source, Transformed>({\n start(controller) {\n asyncRetry(\n () => onRestream(createSourceStream, handleChunk, controller),\n retryOptions,\n ).catch((error) => {\n controller.error(error);\n });\n },\n });\n\nconst onRestream = async <StreamType, Source, Transformed = Source>(\n createSourceStream: () => ReadableStream<StreamType>,\n handleChunk: (\n readResult: ReadableStreamDefaultReadResult<StreamType>,\n controller: TransformStreamDefaultController<Transformed>,\n ) => Promise<void> | void,\n controller: TransformStreamDefaultController<Transformed>,\n): Promise<void> => {\n const sourceStream = createSourceStream();\n const reader = sourceStream.getReader();\n\n try {\n let done: boolean;\n\n do {\n const result = await reader.read();\n done = result.done;\n\n await handleChunk(result, controller);\n\n if (done) {\n controller.terminate();\n }\n } while (!done);\n } finally {\n reader.releaseLock();\n }\n};\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const skip = <T>(limit: number) => new SkipTransformStream<T>(limit);\n\nexport class SkipTransformStream<T> extends TransformStream<T, T> {\n private count = 0;\n private skip: number;\n\n constructor(skip: number) {\n super({\n transform: (chunk, controller) => {\n this.count++;\n if (this.count > this.skip) {\n controller.enqueue(chunk);\n }\n },\n });\n\n this.skip = skip;\n }\n}\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const stopAfter = <Item>(stopCondition: (item: Item) => boolean) =>\n new TransformStream<Item, Item>({\n transform(chunk, controller) {\n controller.enqueue(chunk);\n\n if (stopCondition(chunk)) {\n controller.terminate();\n }\n },\n });\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const stopOn = <Item>(stopCondition: (item: Item) => boolean) =>\n new TransformStream<Item, Item>({\n async transform(chunk, controller) {\n if (!stopCondition(chunk)) {\n controller.enqueue(chunk);\n return;\n }\n await Promise.resolve();\n controller.terminate();\n },\n });\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const take = <T>(limit: number) => new TakeTransformStream<T>(limit);\n\nexport class TakeTransformStream<T> extends TransformStream<T, T> {\n private count = 0;\n private limit: number;\n\n constructor(limit: number) {\n super({\n transform: (chunk, controller) => {\n if (this.count < this.limit) {\n this.count++;\n controller.enqueue(chunk);\n } else {\n controller.terminate();\n }\n },\n });\n\n this.limit = limit;\n }\n}\n","import { TransformStream } from 'web-streams-polyfill';\n\nexport const waitAtMost = <Item>(waitTimeInMs: number) =>\n new TransformStream<Item, Item>({\n start(controller) {\n const timeoutId = setTimeout(() => {\n controller.terminate();\n }, waitTimeInMs);\n\n const originalTerminate = controller.terminate.bind(controller);\n\n // Clear the timeout if the stream is terminated early\n controller.terminate = () => {\n clearTimeout(timeoutId);\n originalTerminate();\n };\n },\n transform(chunk, controller) {\n controller.enqueue(chunk);\n },\n });\n","import { type Event, type ReadEvent } from '../../typing';\nimport type { EventStore, EventStoreReadEventMetadata } from '../eventStore';\n\ntype AfterEventStoreCommitHandlerWithoutContext<Store extends EventStore> = (\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n) => Promise<void> | void;\n\nexport type AfterEventStoreCommitHandler<\n Store extends EventStore,\n HandlerContext = never,\n> = [HandlerContext] extends [never]\n ? AfterEventStoreCommitHandlerWithoutContext<Store>\n : (\n messages: ReadEvent<Event, EventStoreReadEventMetadata<Store>>[],\n context: HandlerContext,\n ) => Promise<void> | void;\n\ntype TryPublishMessagesAfterCommitOptions<\n Store extends EventStore,\n HandlerContext = never,\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,\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 = never,\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 { ConcurrencyError } from '../errors';\nimport type { BigIntStreamPosition, Flavour } from '../typing';\n\nexport type ExpectedStreamVersion<VersionType = BigIntStreamPosition> =\n | ExpectedStreamVersionWithValue<VersionType>\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue<VersionType = BigIntStreamPosition> =\n Flavour<VersionType, 'StreamVersion'>;\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 = <StreamVersion = BigIntStreamPosition>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion>,\n defaultVersion: StreamVersion,\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 StreamVersion = BigIntStreamPosition,\n>(\n current: StreamVersion,\n expected: ExpectedStreamVersion<StreamVersion> | undefined,\n defaultVersion: StreamVersion,\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<\n VersionType = BigIntStreamPosition,\n> extends ConcurrencyError {\n constructor(\n current: VersionType,\n expected: ExpectedStreamVersion<VersionType>,\n ) {\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","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","export const deepEquals = <T>(left: T, right: T): boolean => {\n if (isEquatable(left)) {\n return left.equals(right);\n }\n\n if (Array.isArray(left)) {\n return (\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((val, index) => deepEquals(val, right[index]))\n );\n }\n\n if (\n typeof left !== 'object' ||\n typeof right !== 'object' ||\n left === null ||\n right === null\n ) {\n return left === right;\n }\n\n if (Array.isArray(right)) return false;\n\n const keys1 = Object.keys(left);\n const keys2 = Object.keys(right);\n\n if (\n keys1.length !== keys2.length ||\n !keys1.every((key) => keys2.includes(key))\n )\n return false;\n\n for (const key in left) {\n if (left[key] instanceof Function && right[key] instanceof Function)\n continue;\n\n const isEqual = deepEquals(left[key], right[key]);\n if (!isEqual) {\n return false;\n }\n }\n\n return true;\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 &&\n typeof left === 'object' &&\n 'equals' in left &&\n typeof left['equals'] === 'function'\n );\n};\n","export class ParseError extends Error {\n constructor(text: string) {\n super(`Cannot parse! ${text}`);\n }\n}\n\nexport type Mapper<From, To = From> =\n | ((value: unknown) => To)\n | ((value: Partial<From>) => To)\n | ((value: From) => To)\n | ((value: Partial<To>) => To)\n | ((value: To) => To)\n | ((value: Partial<To | From>) => To)\n | ((value: To | From) => To);\n\nexport type MapperArgs<From, To = From> = Partial<From> &\n From &\n Partial<To> &\n To;\n\nexport type ParseOptions<From, To = From> = {\n reviver?: (key: string, value: unknown) => unknown;\n map?: Mapper<From, To>;\n typeCheck?: <To>(value: unknown) => value is To;\n};\n\nexport type StringifyOptions<From, To = From> = {\n map?: Mapper<From, To>;\n};\n\nexport const JSONParser = {\n stringify: <From, To = From>(\n value: From,\n options?: StringifyOptions<From, To>,\n ) => {\n return JSON.stringify(\n options?.map ? options.map(value as MapperArgs<From, To>) : value,\n //TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n (_, v) => (typeof v === 'bigint' ? v.toString() : v),\n );\n },\n parse: <From, To = From>(\n text: string,\n options?: ParseOptions<From, To>,\n ): To | undefined => {\n const parsed: unknown = JSON.parse(text, options?.reviver);\n\n if (options?.typeCheck && !options?.typeCheck<To>(parsed))\n throw new ParseError(text);\n\n return options?.map\n ? options.map(parsed as MapperArgs<From, To>)\n : (parsed as To | undefined);\n },\n};\n","import { EmmettError } from '../errors';\nimport { JSONParser } from '../serialization';\nimport type {\n AnyEvent,\n AnyReadEventMetadata,\n CanHandle,\n DefaultRecord,\n Event,\n ReadEvent,\n} from '../typing';\nimport { arrayUtils } from '../utils';\n\nexport type ProjectionHandlingType = 'inline' | 'async';\n\nexport type ProjectionHandler<\n EventType extends Event = Event,\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> = (\n events: ReadEvent<EventType, EventMetaDataType>[],\n context: ProjectionHandlerContext,\n) => Promise<void> | void;\n\nexport interface ProjectionDefinition<\n EventType extends Event = Event,\n EventMetaDataType extends AnyReadEventMetadata = AnyReadEventMetadata,\n ProjectionHandlerContext extends DefaultRecord = DefaultRecord,\n> {\n name?: string;\n canHandle: CanHandle<EventType>;\n handle: ProjectionHandler<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n >;\n}\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 >;\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 ${JSONParser.stringify(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>(\n definition: ProjectionDefinition<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n >,\n): ProjectionDefinition<\n EventType,\n EventMetaDataType,\n ProjectionHandlerContext\n> => definition;\n\nexport const inlineProjections = <\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 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 { filter } from './filter';\nimport { map } from './map';\nimport {\n notifyAboutNoActiveReadersStream,\n NotifyAboutNoActiveReadersStream,\n} from './notifyAboutNoActiveReaders';\nimport { reduce, ReduceTransformStream } from './reduce';\nimport { retryStream } from './retry';\nimport { skip, SkipTransformStream } from './skip';\nimport { stopAfter } from './stopAfter';\nimport { stopOn } from './stopOn';\nimport { take, TakeTransformStream } from './take';\nimport { waitAtMost } from './waitAtMost';\n\nexport const streamTransformations = {\n filter,\n take,\n TakeTransformStream,\n skip,\n SkipTransformStream,\n map,\n notifyAboutNoActiveReadersStream,\n NotifyAboutNoActiveReadersStream,\n reduce,\n ReduceTransformStream,\n retry: retryStream,\n stopAfter,\n stopOn,\n waitAtMost,\n};\n","import { JSONParser } 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 (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<void>,\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: ${JSONParser.stringify(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: ${JSONParser.stringify(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!: ${JSONParser.stringify(error)}`,\n );\n } else {\n assertFails(`Function threw an error: ${JSONParser.stringify(error)}`);\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${JSONParser.stringify(expected)}\\nis not subset of\\n${JSONParser.stringify(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${JSONParser.stringify(expected)}\\nis not equal to\\n${JSONParser.stringify(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${JSONParser.stringify(expected)}\\nis equals to\\n${JSONParser.stringify(actual)}`,\n );\n};\n\nexport const assertThat = <T>(item: T) => {\n return {\n isEqualTo: (other: T) => assertTrue(deepEquals(item, other)),\n };\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\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: ${JSONParser.stringify(expected)}\\nActual: ${JSONParser.stringify(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: ${JSONParser.stringify(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 ${JSONParser.stringify(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 {\n assertExpectedVersionMatchesCurrent,\n ExpectedVersionConflictError,\n filterProjections,\n tryPublishMessagesAfterCommit,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type Closeable,\n type DefaultEventStoreOptions,\n type Event,\n type EventStore,\n type ProjectionRegistration,\n type ReadEvent,\n type ReadEventMetadataWithoutGlobalPosition,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport {\n MongoClient,\n type Collection,\n type Document,\n type Filter,\n type MongoClientOptions,\n type Sort,\n type UpdateFilter,\n type WithId,\n} from 'mongodb';\nimport { v4 as uuid } from 'uuid';\nimport {\n handleInlineProjections,\n MongoDBDefaultInlineProjectionName,\n type MongoDBInlineProjectionDefinition,\n type MongoDBProjectionInlineHandlerContext,\n} from './projections';\nimport {\n mongoDBEventStoreStorage,\n type MongoDBEventStoreStorage,\n type MongoDBEventStoreStorageOptions,\n} from './storage';\n\nexport const MongoDBEventStoreDefaultStreamVersion = 0n;\n\nexport type StreamType = string;\nexport type StreamName<T extends StreamType = StreamType> = `${T}:${string}`;\n\nexport type StreamNameParts<T extends StreamType = StreamType> = {\n streamType: T;\n streamId: string;\n};\n\nexport type StreamCollectionName<T extends StreamType = StreamType> =\n `emt:${T}`;\n\nexport type StreamCollectionNameParts<T extends StreamType = StreamType> = {\n streamType: T;\n};\n\nexport type MongoDBReadModelMetadata = {\n streamId: string;\n name: string;\n schemaVersion: number;\n streamPosition: bigint;\n};\n\nexport type MongoDBReadModel<Doc extends Document = Document> = Doc & {\n _metadata: MongoDBReadModelMetadata;\n};\n\nexport interface EventStream<\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> {\n streamName: string;\n messages: Array<ReadEvent<EventType, EventMetaDataType>>;\n metadata: {\n streamId: string;\n streamType: StreamType;\n streamPosition: bigint;\n createdAt: Date;\n updatedAt: Date;\n };\n projections: Record<string, MongoDBReadModel>;\n}\n\nexport type MongoDBReadEventMetadata =\n ReadEventMetadataWithoutGlobalPosition<bigint>;\n\nexport type MongoDBReadEvent<EventType extends Event = Event> = ReadEvent<\n EventType,\n MongoDBReadEventMetadata\n>;\n\ntype SingleProjectionQueryStreamFilter<T extends StreamType> = {\n projectionName?: string;\n} & ({ streamName: StreamName<T> } | { streamType: T; streamId?: string });\n\ntype MultiProjectionQueryStreamFilter<T extends StreamType> = {\n projectionName?: string;\n} & (\n | { streamNames: StreamName<T>[] }\n | { streamType: T; streamIds?: string[] }\n);\n\ntype MultiProjectionQueryOptions = {\n skip?: number;\n limit?: number;\n sort?: [string, 1 | -1][] | Record<string, 1 | -1>;\n};\n\n/**\n * Helpers for querying inline projections on event streams.\n */\ntype InlineProjectionQueries<T extends StreamType> = {\n /**\n * Helper for querying for a single projection. Similar to `collection.findOne`.\n * @param streamFilter - A filter object for stream level fields. If `streamType` is required if `streamName` is not provided. If `projectionName` is not provided, the default projection will be used (`MongoDBDefaultInlineProjectionName`).\n * @param projectionQuery - A MongoDB filter query based on the projection schema. Internally, this function will prepend each object key with the necessary projection name.\n */\n findOne: <Doc extends Document>(\n streamFilter: SingleProjectionQueryStreamFilter<T>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n ) => Promise<MongoDBReadModel<Doc> | null>;\n /**\n * Helper for querying for multiple projections. Similar to `collection.find`.\n *\n * ***NOTE***: If `streamFilter.streamNames` is an empty array, this function will return an empty array. If `streamFilter.streamIds` is an empty array, the `streamIds` filter will not be used.\n *\n * @param streamFilter - A filter object for stream level fields. If `streamType` is required if `streamNames` is not provided. If `projectionName` is not provided, the default projection will be used (`MongoDBDefaultInlineProjectionName`).\n * @param projectionQuery - A MongoDB filter query based on the projection schema. Internally, this function will prepend each object key with the necessary projection name.\n * @param queryOptions - Additional query options like `skip`, `limit`, and `sort`. `sort`, similar to `projectionQuery`, will prepend each object key with the necessary projection name.\n */\n find: <Doc extends Document>(\n streamFilter: MultiProjectionQueryStreamFilter<T>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n queryOptions?: MultiProjectionQueryOptions,\n ) => Promise<MongoDBReadModel<Doc>[]>;\n /**\n * Returns the total number of documents matching the provided filter options. Similar to `collection.countDocuments`.\n *\n * ***NOTE***: If `streamFilter.streamNames` is an empty array, this function will return `0`. If `streamFilter.streamIds` is an empty array, the `streamIds` filter will not be used.\n *\n * @param streamFilter - A filter object for stream level fields. If `streamType` is required if `streamNames` is not provided. If `projectionName` is not provided, the default projection will be used (`MongoDBDefaultInlineProjectionName`).\n * @param projectionQuery - A MongoDB filter query based on the projection schema. Internally, this function will prepend each object key with the necessary projection name.\n */\n count: <Doc extends Document>(\n streamFilter: MultiProjectionQueryStreamFilter<T>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n ) => Promise<number>;\n};\n\n/**\n * Helpers for querying projections on event streams.\n */\ntype ProjectionQueries<T extends StreamType> = {\n inline: InlineProjectionQueries<T>;\n};\n\nexport type MongoDBEventStoreClientOptions = {\n client: MongoClient;\n connectionString?: never;\n clientOptions?: never;\n};\n\nexport type MongoDBEventStoreConnectionStringOptions = {\n client?: never;\n connectionString: string;\n clientOptions?: MongoClientOptions;\n};\n\nexport type MongoDBEventStoreConnectionOptions =\n | MongoDBEventStoreClientOptions\n | MongoDBEventStoreConnectionStringOptions;\n\nexport type MongoDBEventStoreOptions = {\n projections?: ProjectionRegistration<\n 'inline',\n MongoDBReadEventMetadata,\n MongoDBProjectionInlineHandlerContext\n >[];\n storage?: MongoDBEventStoreStorageOptions;\n} & MongoDBEventStoreConnectionOptions &\n DefaultEventStoreOptions<MongoDBEventStore>;\n\nexport type MongoDBEventStore = EventStore<MongoDBReadEventMetadata> & {\n projections: ProjectionQueries<StreamType>;\n collectionFor: <EventType extends Event>(\n streamType: StreamType,\n ) => Promise<Collection<EventStream<EventType>>>;\n};\n\nclass MongoDBEventStoreImplementation implements MongoDBEventStore, Closeable {\n private readonly client: MongoClient;\n private readonly inlineProjections: MongoDBInlineProjectionDefinition[];\n private shouldManageClientLifetime: boolean;\n private isClosed: boolean = false;\n private storage: MongoDBEventStoreStorage;\n private options: MongoDBEventStoreOptions;\n public projections: ProjectionQueries<StreamType>;\n\n constructor(options: MongoDBEventStoreOptions) {\n this.options = options;\n this.client =\n 'client' in options && options.client\n ? options.client\n : new MongoClient(options.connectionString, options.clientOptions);\n this.shouldManageClientLifetime = !('client' in options);\n this.storage = mongoDBEventStoreStorage({\n storage: options.storage,\n getConnectedClient: () => this.getConnectedClient(),\n });\n this.inlineProjections = filterProjections(\n 'inline',\n options.projections ?? [],\n ) as MongoDBInlineProjectionDefinition[];\n\n this.projections = {\n inline: {\n findOne: this.findOneInlineProjection.bind(this),\n find: this.findInlineProjection.bind(this),\n count: this.countInlineProjection.bind(this),\n },\n };\n }\n\n async readStream<EventType extends Event>(\n streamName: StreamName,\n options?: ReadStreamOptions,\n ): Promise<\n Exclude<ReadStreamResult<EventType, MongoDBReadEventMetadata>, null>\n > {\n const { streamType } = fromStreamName(streamName);\n const expectedStreamVersion = options?.expectedStreamVersion;\n\n const collection = await this.storage.collectionFor(streamType);\n\n const filter = {\n streamName: { $eq: streamName },\n };\n\n const eventsSliceArr: number[] = [];\n\n if (options && 'from' in options) {\n eventsSliceArr.push(Number(options.from));\n } else {\n eventsSliceArr.push(0);\n }\n\n if (options && 'to' in options) {\n eventsSliceArr.push(Number(options.to));\n }\n\n const eventsSlice =\n eventsSliceArr.length > 1 ? { $slice: eventsSliceArr } : 1;\n\n const stream = await collection.findOne<\n WithId<Pick<EventStream<EventType>, 'metadata' | 'messages'>>\n >(filter, {\n useBigInt64: true,\n projection: {\n metadata: 1,\n messages: eventsSlice,\n },\n });\n\n if (!stream) {\n return {\n events: [],\n currentStreamVersion: MongoDBEventStoreDefaultStreamVersion,\n streamExists: false,\n };\n }\n\n assertExpectedVersionMatchesCurrent(\n stream.metadata.streamPosition,\n expectedStreamVersion,\n MongoDBEventStoreDefaultStreamVersion,\n );\n\n return {\n events: stream.messages,\n currentStreamVersion: stream.metadata.streamPosition,\n streamExists: true,\n };\n }\n\n async aggregateStream<State, EventType extends Event>(\n streamName: StreamName,\n options: AggregateStreamOptions<State, EventType, MongoDBReadEventMetadata>,\n ): Promise<AggregateStreamResult<State>> {\n const stream = await this.readStream<EventType>(streamName, options?.read);\n\n const state = stream.events.reduce(options.evolve, options.initialState());\n return {\n state,\n currentStreamVersion: stream.currentStreamVersion,\n streamExists: stream.streamExists,\n };\n }\n\n async appendToStream<EventType extends Event>(\n streamName: StreamName,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> {\n const { streamId, streamType } = fromStreamName(streamName);\n const expectedStreamVersion = options?.expectedStreamVersion;\n\n const collection = await this.storage.collectionFor(streamType);\n\n const stream = await collection.findOne<\n WithId<Pick<EventStream<EventType>, 'metadata' | 'projections'>>\n >(\n { streamName: { $eq: streamName } },\n {\n useBigInt64: true,\n projection: {\n 'metadata.streamPosition': 1,\n projections: 1,\n },\n },\n );\n\n const currentStreamVersion =\n stream?.metadata.streamPosition ?? MongoDBEventStoreDefaultStreamVersion;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n MongoDBEventStoreDefaultStreamVersion,\n );\n\n let streamOffset = currentStreamVersion;\n\n const eventsToAppend: ReadEvent<EventType, MongoDBReadEventMetadata>[] =\n events.map((event) => {\n const metadata: MongoDBReadEventMetadata = {\n messageId: uuid(),\n streamName,\n streamPosition: ++streamOffset,\n };\n return {\n type: event.type,\n data: event.data,\n metadata: {\n ...metadata,\n ...('metadata' in event ? (event.metadata ?? {}) : {}),\n },\n } as ReadEvent<EventType, MongoDBReadEventMetadata>;\n });\n\n const now = new Date();\n const updates: UpdateFilter<EventStream> = {\n $push: { messages: { $each: eventsToAppend } },\n $set: {\n 'metadata.updatedAt': now,\n 'metadata.streamPosition': currentStreamVersion + BigInt(events.length),\n },\n $setOnInsert: {\n streamName,\n 'metadata.streamId': streamId,\n 'metadata.streamType': streamType,\n 'metadata.createdAt': now,\n },\n };\n\n if (this.inlineProjections) {\n await handleInlineProjections({\n readModels: stream?.projections ?? {},\n streamId,\n events: eventsToAppend,\n projections: this.inlineProjections,\n collection,\n updates,\n client: {},\n });\n }\n\n const updatedStream = await collection.updateOne(\n {\n streamName: { $eq: streamName },\n 'metadata.streamPosition': currentStreamVersion,\n },\n updates,\n { useBigInt64: true, upsert: true },\n );\n\n if (!updatedStream) {\n throw new ExpectedVersionConflictError(\n currentStreamVersion,\n options?.expectedStreamVersion ?? 0n,\n );\n }\n\n await tryPublishMessagesAfterCommit<MongoDBEventStore>(\n eventsToAppend,\n this.options.hooks,\n // {\n // TODO: same context as InlineProjectionHandlerContext for mongodb?\n // },\n );\n\n return {\n nextExpectedStreamVersion:\n currentStreamVersion + BigInt(eventsToAppend.length),\n createdNewStream:\n currentStreamVersion === MongoDBEventStoreDefaultStreamVersion,\n };\n }\n\n collectionFor = async <EventType extends Event>(\n streamType: StreamType,\n ): Promise<Collection<EventStream<EventType>>> => {\n return this.storage.collectionFor(streamType);\n };\n\n /**\n * Gracefully cleans up managed resources by the MongoDBEventStore.\n * It closes MongoDB client created for the provided connection string\n * through event store options.\n *\n * @memberof Closeable\n */\n close = (): Promise<void> => {\n if (this.isClosed) return Promise.resolve();\n\n this.isClosed = true;\n if (!this.shouldManageClientLifetime) return Promise.resolve();\n\n return this.client.close();\n };\n\n private async findOneInlineProjection<Doc extends Document>(\n streamFilter: SingleProjectionQueryStreamFilter<StreamType>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n ) {\n const { projectionName, streamName, streamType } =\n parseSingleProjectionQueryStreamFilter(streamFilter);\n const collection = await this.storage.collectionFor(streamType);\n const query = prependMongoFilterWithProjectionPrefix<\n Filter<MongoDBReadModel<Doc>> | undefined,\n Filter<EventStream> | undefined\n >(projectionQuery, `projections.${projectionName}`);\n\n const filters: Filter<EventStream>[] = [\n { [`projections.${projectionName}`]: { $exists: true } },\n ];\n\n if (query) {\n filters.push(query);\n }\n\n if (streamName) {\n filters.push({ streamName: { $eq: streamName } });\n }\n\n const result = await collection.findOne<{\n projections: Record<typeof projectionName, MongoDBReadModel<Doc>>;\n }>(\n { $and: filters },\n {\n useBigInt64: true,\n projection: { [`projections.${projectionName}`]: 1 },\n },\n );\n\n return result?.projections?.[projectionName] ?? null;\n }\n\n private async findInlineProjection<Doc extends Document>(\n streamFilter: MultiProjectionQueryStreamFilter<StreamType>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n queryOptions?: MultiProjectionQueryOptions,\n ) {\n const parsedStreamFilter =\n parseMultiProjectionQueryStreamFilter(streamFilter);\n if (!parsedStreamFilter) return [];\n const { projectionName, streamNames, streamType } = parsedStreamFilter;\n\n const collection = await this.storage.collectionFor(streamType);\n const prefix = `projections.${projectionName}`;\n const projectionFilter = prependMongoFilterWithProjectionPrefix<\n Filter<MongoDBReadModel<Doc>> | undefined,\n Filter<EventStream> | undefined\n >(projectionQuery, prefix);\n\n const filters: Filter<EventStream>[] = [\n { [`projections.${projectionName}`]: { $exists: true } },\n ];\n\n if (projectionFilter) {\n filters.push(projectionFilter);\n }\n\n if (streamNames) {\n filters.push({ streamName: { $in: streamNames } });\n }\n\n let query = collection.find<\n EventStream & {\n projections: Record<typeof projectionName, MongoDBReadModel<Doc>>;\n }\n >(\n { $and: filters },\n {\n useBigInt64: true,\n projection: { [`projections.${projectionName}`]: 1 },\n },\n );\n\n if (queryOptions?.skip) {\n query = query.skip(queryOptions.skip);\n }\n\n if (queryOptions?.limit) {\n query = query.limit(queryOptions.limit);\n }\n\n if (queryOptions?.sort) {\n const sort = prependMongoFilterWithProjectionPrefix<Sort>(\n queryOptions.sort,\n prefix,\n );\n query = query.sort(sort);\n }\n\n const streams = await query.toArray();\n\n return streams\n .map((s) => s.projections[projectionName])\n .filter((p): p is MongoDBReadModel<Doc> => !!p);\n }\n\n private async countInlineProjection<Doc extends Document>(\n streamFilter: MultiProjectionQueryStreamFilter<StreamType>,\n projectionQuery?: Filter<MongoDBReadModel<Doc>>,\n ) {\n const parsedStreamFilter =\n parseMultiProjectionQueryStreamFilter(streamFilter);\n if (!parsedStreamFilter) return 0;\n const { projectionName, streamNames, streamType } = parsedStreamFilter;\n\n const collection = await this.storage.collectionFor(streamType);\n const prefix = `projections.${projectionName}`;\n const projectionFilter = prependMongoFilterWithProjectionPrefix<\n Filter<MongoDBReadModel<Doc>> | undefined,\n Filter<EventStream> | undefined\n >(projectionQuery, prefix);\n\n const filters: Filter<EventStream>[] = [\n { [`projections.${projectionName}`]: { $exists: true } },\n ];\n\n if (projectionFilter) {\n filters.push(projectionFilter);\n }\n\n if (streamNames) {\n filters.push({ streamName: { $in: streamNames } });\n }\n\n const total = await collection.countDocuments({ $and: filters });\n return total;\n }\n\n private getConnectedClient = async (): Promise<MongoClient> => {\n if (!this.isClosed) await this.client.connect();\n return this.client;\n };\n}\n\nfunction parseSingleProjectionQueryStreamFilter<\n T extends StreamType = StreamType,\n>(streamFilter: SingleProjectionQueryStreamFilter<T>) {\n const projectionName =\n streamFilter.projectionName ?? MongoDBDefaultInlineProjectionName;\n\n if ('streamName' in streamFilter) {\n const { streamType } = fromStreamName(streamFilter.streamName);\n return {\n projectionName,\n streamName: streamFilter.streamName,\n streamType,\n };\n }\n\n if (streamFilter.streamId) {\n const streamName = toStreamName(\n streamFilter.streamType,\n streamFilter.streamId,\n );\n return {\n projectionName,\n streamName,\n streamType: streamFilter.streamType,\n };\n }\n\n return {\n projectionName,\n streamType: streamFilter.streamType,\n };\n}\n\nfunction parseMultiProjectionQueryStreamFilter<T extends StreamType>(\n streamFilter: MultiProjectionQueryStreamFilter<T>,\n) {\n const projectionName =\n streamFilter.projectionName ?? MongoDBDefaultInlineProjectionName;\n\n if ('streamNames' in streamFilter) {\n if (streamFilter.streamNames.length == 0) return null;\n const { streamType } = fromStreamName(streamFilter.streamNames[0]!);\n return {\n projectionName,\n streamNames: streamFilter.streamNames,\n streamType,\n };\n }\n\n if (streamFilter.streamIds && streamFilter.streamIds.length > 0) {\n const streamNames = streamFilter.streamIds.map((id) =>\n toStreamName(streamFilter.streamType, id),\n );\n return {\n projectionName,\n streamNames,\n streamType: streamFilter.streamType,\n };\n }\n\n return {\n projectionName,\n streamType: streamFilter.streamType,\n };\n}\n\n/**\n * Prepends `prefix` to all object keys that don't start with a '$'\n */\nexport function prependMongoFilterWithProjectionPrefix<T, Result = T>(\n obj: T,\n prefix: string,\n): Result {\n if (typeof obj !== 'object' || obj === null || obj === undefined) {\n return obj as unknown as Result;\n }\n\n if (Array.isArray(obj)) {\n for (let i = 0; i < obj.length; i++) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n obj[i] = prependMongoFilterWithProjectionPrefix(obj[i], prefix);\n }\n return obj as unknown as Result;\n }\n\n for (const key in obj) {\n // @ts-expect-error we're forcing `k` to be a key of `T`\n const k: keyof typeof obj = addProjectionPrefixToMongoKey(key, prefix);\n if (k !== key) {\n obj[k] = obj[key as keyof typeof obj];\n delete obj[key as keyof typeof obj];\n }\n\n obj[k] = prependMongoFilterWithProjectionPrefix(obj[k], prefix);\n }\n\n return obj as unknown as Result;\n}\n\nfunction addProjectionPrefixToMongoKey(key: string, prefix: string): string {\n // MongoDB operators\n if (key[0] === '$') {\n return key;\n }\n\n return `${prefix}${key.length > 0 ? '.' : ''}${key}`;\n}\n\nexport function getMongoDBEventStore(\n options: MongoDBEventStoreOptions & { client: MongoClient },\n): MongoDBEventStore;\n\nexport function getMongoDBEventStore(\n options: MongoDBEventStoreOptions & { connectionString: string },\n): MongoDBEventStore & Closeable;\n\n// Implementation signature covers both, using a union for `options`\nexport function getMongoDBEventStore(\n options: MongoDBEventStoreOptions,\n): MongoDBEventStore | Closeable {\n const impl = new MongoDBEventStoreImplementation(options);\n\n // If a client is provided externally, we don't want to allow closing it\n if ('client' in options && 'close' in impl) {\n delete (impl as Partial<MongoDBEventStoreImplementation>).close;\n }\n\n return impl;\n}\n\n/**\n * Accepts a `streamType` (the type/category of the event stream) and an `streamId`\n * (the individual entity/object or aggregate ID) and combines them to a singular\n * `streamName` which can be used in `EventStore`.\n */\nexport function toStreamName<T extends StreamType>(\n streamType: T,\n streamId: string,\n): StreamName<T> {\n return `${streamType}:${streamId}`;\n}\n\n/**\n * Accepts a fully formatted `streamName` and returns the broken down\n * `streamType` and `streamId`.\n */\nexport function fromStreamName<T extends StreamType>(\n streamName: StreamName<T>,\n): StreamNameParts<T> {\n const parts = streamName.split(':') as [T, string];\n return {\n streamType: parts[0],\n streamId: parts[1],\n };\n}\n\n/**\n * Accepts a `streamType` (the type/category of the event stream)\n * and combines them to a `collectionName` which can be used in `EventStore`.\n */\nexport function toStreamCollectionName<T extends StreamType>(\n streamType: T,\n): StreamCollectionName<T> {\n return `emt:${streamType}`;\n}\n\n/**\n * Accepts a fully formatted `streamCollectionName` and returns the parsed `streamType`.\n */\nexport function fromStreamCollectionName<T extends StreamType>(\n streamCollectionName: StreamCollectionName<T>,\n): StreamCollectionNameParts<T> {\n const parts = streamCollectionName.split(':') as [string, T];\n return {\n streamType: parts[1],\n };\n}\n","import {\n type CanHandle,\n type Event,\n type ProjectionDefinition,\n type ProjectionHandler,\n type ReadEvent,\n} from '@event-driven-io/emmett';\nimport type { Collection, Document, UpdateFilter } from 'mongodb';\nimport type {\n EventStream,\n MongoDBReadEventMetadata,\n MongoDBReadModel,\n MongoDBReadModelMetadata,\n} from '../mongoDBEventStore';\n\nexport const MongoDBDefaultInlineProjectionName = '_default';\n\nexport type MongoDBProjectionInlineHandlerContext<\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> = {\n document: MongoDBReadModel | null;\n streamId: string;\n updates: UpdateFilter<EventStream<EventType, EventMetaDataType>>;\n collection: Collection<EventStream<EventType, EventMetaDataType>>;\n};\n\nexport type MongoDBInlineProjectionHandler<\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> = ProjectionHandler<\n EventType,\n EventMetaDataType,\n MongoDBProjectionInlineHandlerContext\n>;\n\nexport type MongoDBInlineProjectionDefinition<\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> = ProjectionDefinition<\n EventType,\n EventMetaDataType,\n MongoDBProjectionInlineHandlerContext\n> & { name: string };\n\nexport type InlineProjectionHandlerOptions<\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> = {\n readModels: Record<string, MongoDBReadModel>;\n events: Array<ReadEvent<EventType, EventMetaDataType>>;\n projections: MongoDBInlineProjectionDefinition<\n EventType,\n EventMetaDataType\n >[];\n streamId: string;\n collection: Collection<EventStream>;\n updates: UpdateFilter<EventStream<Event>>;\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n client: {\n //todo: add client here\n };\n};\n\nexport const handleInlineProjections = async <\n EventType extends Event = Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n>(\n options: InlineProjectionHandlerOptions<EventType, EventMetaDataType>,\n): Promise<void> => {\n const {\n events,\n projections: allProjections,\n updates: update,\n streamId,\n collection,\n readModels,\n } = options;\n\n const eventTypes = events.map((e) => e.type);\n\n const projections = allProjections.filter((p) =>\n p.canHandle.some((type) => eventTypes.includes(type)),\n );\n\n for (const projection of projections) {\n await projection.handle(events, {\n document: readModels[projection.name] ?? null,\n streamId,\n collection,\n updates: update,\n });\n }\n};\n\nexport type MongoDBWithNotNullDocumentEvolve<\n Doc extends Document,\n EventType extends Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> =\n | ((\n document: Doc,\n event: ReadEvent<EventType, EventMetaDataType>,\n ) => Doc | null)\n | ((document: Doc, event: ReadEvent<EventType>) => Promise<Doc | null>);\n\nexport type MongoDBWithNullableDocumentEvolve<\n Doc extends Document,\n EventType extends Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> =\n | ((\n document: Doc | null,\n event: ReadEvent<EventType, EventMetaDataType>,\n ) => Doc | null)\n | ((\n document: Doc | null,\n event: ReadEvent<EventType>,\n ) => Promise<Doc | null>);\n\nexport type MongoDBInlineProjectionOptions<\n Doc extends Document,\n EventType extends Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n> = {\n name?: string;\n schemaVersion?: number;\n canHandle: CanHandle<EventType>;\n} & (\n | {\n evolve: MongoDBWithNullableDocumentEvolve<\n Doc,\n EventType,\n EventMetaDataType\n >;\n }\n | {\n evolve: MongoDBWithNotNullDocumentEvolve<\n Doc,\n EventType,\n EventMetaDataType\n >;\n initialState: () => Doc;\n }\n);\n\nexport const mongoDBInlineProjection = <\n Doc extends Document,\n EventType extends Event,\n EventMetaDataType extends MongoDBReadEventMetadata = MongoDBReadEventMetadata,\n>(\n options: MongoDBInlineProjectionOptions<Doc, EventType, EventMetaDataType>,\n): MongoDBInlineProjectionDefinition => {\n const projectionName = options.name ?? MongoDBDefaultInlineProjectionName;\n const schemaVersion = options.schemaVersion ?? 1;\n\n return {\n name: projectionName,\n canHandle: options.canHandle,\n handle: async (events, { document, updates, streamId }) => {\n if (events.length === 0) return;\n\n let state =\n 'initialState' in options\n ? (document ?? options.initialState())\n : document;\n\n for (const event of events) {\n state = await options.evolve(\n state as Doc,\n event as ReadEvent<EventType, EventMetaDataType>,\n );\n }\n\n const metadata: MongoDBReadModelMetadata = {\n streamId,\n name: projectionName,\n schemaVersion,\n streamPosition: events[events.length - 1]!.metadata.streamPosition,\n };\n\n updates.$set![`projections.${projectionName}`] =\n state !== null\n ? {\n ...state,\n _metadata: metadata,\n }\n : null;\n },\n };\n};\n","import {\n assertFails,\n AssertionError,\n assertTrue,\n deepEquals,\n isErrorConstructor,\n isSubset,\n projections,\n type Event,\n type ThenThrows,\n} from '@event-driven-io/emmett';\nimport { MongoClient, type Document } from 'mongodb';\nimport {\n getMongoDBEventStore,\n type MongoDBEventStore,\n type MongoDBEventStoreConnectionOptions,\n type MongoDBReadModel,\n type StreamName,\n} from '../mongoDBEventStore';\nimport {\n MongoDBDefaultInlineProjectionName,\n type MongoDBInlineProjectionDefinition,\n} from './mongoDBInlineProjection';\n\nexport type MongoDBInlineProjectionSpecGivenEvents<\n StreamNameType extends StreamName,\n EventType extends Event,\n> = {\n streamName: StreamNameType;\n events: EventType[];\n};\n\nexport type MongoDBInlineProjectionSpec<\n StreamNameType extends StreamName,\n EventType extends Event,\n> = (\n givenStream: MongoDBInlineProjectionSpecGivenEvents<\n StreamNameType,\n EventType\n >,\n) => {\n when: (events: EventType[]) => {\n then: (\n assert: MongoDBInlineProjectionAssert,\n message?: string,\n ) => Promise<void>;\n thenThrows: <ErrorType extends Error = Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ) => Promise<void>;\n };\n};\n\nexport type MongoDBInlineProjectionAssertOptions<\n StreamNameType extends StreamName = StreamName,\n> = {\n streamName: StreamNameType;\n eventStore: MongoDBEventStore;\n};\n\nexport type MongoDBInlineProjectionAssert<\n StreamNameType extends StreamName = StreamName,\n> = (\n options: MongoDBInlineProjectionAssertOptions<StreamNameType>,\n) => Promise<void | boolean>;\n\nexport type MongoDBInlineProjectionSpecOptions = {\n projection: MongoDBInlineProjectionDefinition;\n} & MongoDBEventStoreConnectionOptions;\n\nexport const MongoDBInlineProjectionSpec = {\n for: <StreamNameType extends StreamName, EventType extends Event>(\n options: MongoDBInlineProjectionSpecOptions,\n ): MongoDBInlineProjectionSpec<StreamNameType, EventType> => {\n {\n const { projection, ...connectionOptions } = options;\n\n return (\n givenStream: MongoDBInlineProjectionSpecGivenEvents<\n StreamNameType,\n EventType\n >,\n ) => {\n const { streamName, events: givenEvents } = givenStream;\n return {\n when: (events: EventType[]) => {\n const allEvents = [...givenEvents, ...events];\n\n const run = (eventStore: MongoDBEventStore) =>\n eventStore.appendToStream(streamName, allEvents);\n\n return {\n then: async (\n assert: MongoDBInlineProjectionAssert,\n message?: string,\n ): Promise<void> => {\n const client =\n 'client' in connectionOptions && connectionOptions.client\n ? connectionOptions.client\n : new MongoClient(\n connectionOptions.connectionString,\n connectionOptions.clientOptions,\n );\n\n const eventStore = getMongoDBEventStore({\n projections: projections.inline([projection]),\n client,\n });\n\n try {\n await run(eventStore);\n\n const succeeded = await assert({ eventStore, streamName });\n\n if (succeeded !== undefined && succeeded === false)\n assertFails(\n message ??\n \"Projection specification didn't match the criteria\",\n );\n } finally {\n await client.close();\n }\n },\n thenThrows: async <ErrorType extends Error>(\n ...args: Parameters<ThenThrows<ErrorType>>\n ): Promise<void> => {\n const client =\n 'client' in connectionOptions && connectionOptions.client\n ? connectionOptions.client\n : new MongoClient(\n connectionOptions.connectionString,\n connectionOptions.clientOptions,\n );\n\n const eventStore = getMongoDBEventStore({\n projections: projections.inline([projection]),\n client,\n });\n\n try {\n await run(eventStore);\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 } finally {\n await client.close();\n }\n },\n };\n },\n };\n };\n }\n },\n};\n\nexport const eventInStream = <\n StreamNameType extends StreamName,\n EventType extends Event,\n>(\n streamName: StreamNameType,\n event: EventType,\n): MongoDBInlineProjectionSpecGivenEvents<StreamNameType, EventType> => ({\n streamName,\n events: [event],\n});\n\nexport const eventsInStream = <\n StreamNameType extends StreamName,\n EventType extends Event,\n>(\n streamName: StreamNameType,\n events: EventType[],\n): MongoDBInlineProjectionSpecGivenEvents<StreamNameType, EventType> => ({\n streamName,\n events,\n});\n\nconst expectReadModelToMatch = async <\n Doc extends Document = Document,\n StreamNameType extends StreamName = StreamName,\n>(\n options: MongoDBInlineProjectionAssertOptions<StreamNameType> & {\n projectionName: string;\n match: (readModel: MongoDBReadModel<Doc> | null) => boolean;\n },\n) => {\n const { streamName, projectionName, eventStore, match } = options;\n const readModel = await eventStore.projections.inline.findOne<Doc>({\n streamName,\n projectionName,\n });\n\n return match(readModel);\n};\n\nconst expectInlineReadModelWithName = (projectionName: string) => ({\n toHave:\n <Doc extends Document, StreamNameType extends StreamName = StreamName>(\n expected: Partial<MongoDBReadModel<Doc>> | null,\n ): MongoDBInlineProjectionAssert<StreamNameType> =>\n ({ eventStore, streamName }) =>\n expectReadModelToMatch<Doc>({\n eventStore,\n streamName,\n projectionName,\n match: (readModel) => isSubset(readModel, expected),\n }),\n toDeepEquals:\n <Doc extends Document, StreamNameType extends StreamName = StreamName>(\n expected: MongoDBReadModel<Doc> | null,\n ): MongoDBInlineProjectionAssert<StreamNameType> =>\n ({ eventStore, streamName }) =>\n expectReadModelToMatch<Doc>({\n eventStore,\n streamName,\n projectionName,\n match: (readModel) => deepEquals(readModel, expected),\n }),\n toMatch:\n <Doc extends Document, StreamNameType extends StreamName = StreamName>(\n match: (readModel: MongoDBReadModel<Doc> | null) => boolean,\n ): MongoDBInlineProjectionAssert<StreamNameType> =>\n ({ eventStore, streamName }) =>\n expectReadModelToMatch<Doc>({\n eventStore,\n streamName,\n projectionName,\n match,\n }),\n notToExist:\n <\n StreamNameType extends StreamName = StreamName,\n >(): MongoDBInlineProjectionAssert<StreamNameType> =>\n ({ eventStore, streamName }) =>\n expectReadModelToMatch({\n eventStore,\n streamName,\n projectionName,\n match: (readModel) => readModel === null,\n }),\n toExist:\n (): MongoDBInlineProjectionAssert =>\n ({ eventStore, streamName }) =>\n expectReadModelToMatch({\n eventStore,\n streamName,\n projectionName,\n match: (readModel) => readModel !== null,\n }),\n});\n\nexport const expectInlineReadModel = {\n withName: (name: string) => expectInlineReadModelWithName(name),\n ...expectInlineReadModelWithName(MongoDBDefaultInlineProjectionName),\n};\n","import { type Event } from '@event-driven-io/emmett';\nimport type { Collection, Db, MongoClient } from 'mongodb';\nimport {\n toStreamCollectionName,\n type EventStream,\n type StreamType,\n} from '../mongoDBEventStore';\n\nexport type MongoDBEventStoreCollectionPerStreamTypeStorageOptions = {\n /**\n * The recommended setting where each stream type will be kept\n * in a separate collection type using the format: `emt_${streamType}`.\n */\n type: 'COLLECTION_PER_STREAM_TYPE';\n databaseName?: string;\n};\n\nexport type MongoDBEventStoreSingleCollectionStorageOptions = {\n /**\n * All streams will be kept withing a single MongDB collection\n * It'll either use default collection name (\"emt_streams\")\n * or provided name through 'collection' param.\n */\n type: 'SINGLE_COLLECTION';\n collectionName?: string;\n databaseName?: string;\n};\n\nexport type MongoDBEventStoreCollectionResolution = {\n databaseName?: string;\n collectionName: string;\n};\n\nexport type MongoDBEventStoreCustomStorageOptions = {\n /**\n * This is advanced option, where you specify your own collection\n * resolution function. You can do that by specifying the `collectionFor` function.\n */\n type: 'CUSTOM';\n databaseName?: string;\n collectionFor: <T extends StreamType>(\n streamType: T,\n ) => string | MongoDBEventStoreCollectionResolution;\n};\n\nexport type MongoDBEventStoreStorageOptions =\n | 'COLLECTION_PER_STREAM_TYPE'\n | 'SINGLE_COLLECTION'\n | MongoDBEventStoreSingleCollectionStorageOptions\n | MongoDBEventStoreCollectionPerStreamTypeStorageOptions\n | MongoDBEventStoreCustomStorageOptions;\n\nexport const DefaultMongoDBEventStoreStorageOptions =\n 'COLLECTION_PER_STREAM_TYPE';\n\nexport type MongoDBEventStoreStorage = {\n collectionFor: <T extends StreamType, EventType extends Event = Event>(\n streamType: T,\n ) => Promise<Collection<EventStream<EventType>>>;\n};\n\nexport const DefaultMongoDBEventStoreCollectionName = 'emt:streams';\n\nconst resolveCollectionAndDatabase = <T extends StreamType>(\n streamType: T,\n options: MongoDBEventStoreStorageOptions,\n): MongoDBEventStoreCollectionResolution => {\n if (\n options === 'SINGLE_COLLECTION' ||\n (typeof options === 'object' && options.type === 'SINGLE_COLLECTION')\n ) {\n return {\n collectionName:\n typeof options === 'object'\n ? (options.collectionName ?? DefaultMongoDBEventStoreCollectionName)\n : DefaultMongoDBEventStoreCollectionName,\n databaseName:\n typeof options === 'object' ? options.databaseName : undefined,\n };\n } else if (\n options === 'COLLECTION_PER_STREAM_TYPE' ||\n (typeof options === 'object' &&\n options.type === 'COLLECTION_PER_STREAM_TYPE')\n ) {\n return {\n collectionName: toStreamCollectionName(streamType),\n databaseName:\n typeof options === 'object' ? options.databaseName : undefined,\n };\n } else {\n const result = options.collectionFor(streamType);\n return {\n collectionName:\n typeof result === 'object' ? result.collectionName : result,\n databaseName:\n typeof result === 'object'\n ? (result.databaseName ?? options.databaseName)\n : options.databaseName,\n };\n }\n};\n\nconst getDB = async (options: {\n databaseName: string | undefined;\n dbsCache: Map<string, Db>;\n getConnectedClient: () => Promise<MongoClient>;\n}): Promise<Db> => {\n const { dbsCache, databaseName, getConnectedClient } = options;\n const safeDbName = databaseName ?? '___default';\n\n let db = dbsCache.get(safeDbName);\n\n if (!db) {\n const connectedClient = await getConnectedClient();\n\n db = connectedClient.db(databaseName);\n\n dbsCache.set(safeDbName, db);\n }\n\n return db;\n};\n\nconst collectionFor = async <EventType extends Event = Event>(options: {\n collectionName: string;\n streamCollections: Map<string, Collection<EventStream>>;\n db: Db;\n}): Promise<Collection<EventStream<EventType>>> => {\n const { collectionName, db, streamCollections } = options;\n\n let collection = streamCollections.get(collectionName) as\n | Collection<EventStream<EventType>>\n | undefined;\n\n if (!collection) {\n collection = db.collection<EventStream<EventType>>(collectionName);\n await collection.createIndex({ streamName: 1 }, { unique: true });\n\n streamCollections.set(\n collectionName,\n collection as Collection<EventStream>,\n );\n }\n\n return collection;\n};\n\nexport const mongoDBEventStoreStorage = (options: {\n storage?: MongoDBEventStoreStorageOptions | undefined;\n getConnectedClient: () => Promise<MongoClient>;\n}): MongoDBEventStoreStorage => {\n const dbsCache: Map<string, Db> = new Map();\n const streamCollections: Map<string, Collection<EventStream>> = new Map();\n const storageOptions =\n options.storage ?? DefaultMongoDBEventStoreStorageOptions;\n\n const { getConnectedClient } = options;\n\n return {\n collectionFor: async <\n T extends StreamType,\n EventType extends Event = Event,\n >(\n streamType: T,\n ): Promise<Collection<EventStream<EventType>>> => {\n const { collectionName, databaseName } = resolveCollectionAndDatabase(\n streamType,\n storageOptions,\n );\n\n let collection = streamCollections.get(collectionName) as\n | Collection<EventStream<EventType>>\n | undefined;\n\n if (!collection) {\n const db = await getDB({ databaseName, dbsCache, getConnectedClient });\n collection = await collectionFor<EventType>({\n collectionName,\n streamCollections,\n db,\n });\n }\n\n return collection;\n },\n };\n};\n"]}
package/dist/index.d.cts CHANGED
@@ -22,7 +22,7 @@ type InlineProjectionHandlerOptions<EventType extends Event = Event, EventMetaDa
22
22
  client: {};
23
23
  };
24
24
  declare const handleInlineProjections: <EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = Readonly<{
25
- eventId: string;
25
+ messageId: string;
26
26
  streamPosition: bigint;
27
27
  streamName: string;
28
28
  }>>(options: InlineProjectionHandlerOptions<EventType, EventMetaDataType>) => Promise<void>;
@@ -39,7 +39,7 @@ type MongoDBInlineProjectionOptions<Doc extends Document, EventType extends Even
39
39
  initialState: () => Doc;
40
40
  });
41
41
  declare const mongoDBInlineProjection: <Doc extends Document, EventType extends Event, EventMetaDataType extends MongoDBReadEventMetadata = Readonly<{
42
- eventId: string;
42
+ messageId: string;
43
43
  streamPosition: bigint;
44
44
  streamName: string;
45
45
  }>>(options: MongoDBInlineProjectionOptions<Doc, EventType, EventMetaDataType>) => MongoDBInlineProjectionDefinition;
package/dist/index.d.ts CHANGED
@@ -22,7 +22,7 @@ type InlineProjectionHandlerOptions<EventType extends Event = Event, EventMetaDa
22
22
  client: {};
23
23
  };
24
24
  declare const handleInlineProjections: <EventType extends Event = Event, EventMetaDataType extends MongoDBReadEventMetadata = Readonly<{
25
- eventId: string;
25
+ messageId: string;
26
26
  streamPosition: bigint;
27
27
  streamName: string;
28
28
  }>>(options: InlineProjectionHandlerOptions<EventType, EventMetaDataType>) => Promise<void>;
@@ -39,7 +39,7 @@ type MongoDBInlineProjectionOptions<Doc extends Document, EventType extends Even
39
39
  initialState: () => Doc;
40
40
  });
41
41
  declare const mongoDBInlineProjection: <Doc extends Document, EventType extends Event, EventMetaDataType extends MongoDBReadEventMetadata = Readonly<{
42
- eventId: string;
42
+ messageId: string;
43
43
  streamPosition: bigint;
44
44
  streamName: string;
45
45
  }>>(options: MongoDBInlineProjectionOptions<Doc, EventType, EventMetaDataType>) => MongoDBInlineProjectionDefinition;