@event-driven-io/emmett-testcontainers 0.35.0 → 0.37.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
@@ -46,9 +46,9 @@ var NotifyAboutNoActiveReadersStream = (_class = class extends _webstreamspolyfi
46
46
  }
47
47
  });_class.prototype.__init.call(this);_class.prototype.__init2.call(this);;
48
48
  this.onNoActiveReaderCallback = onNoActiveReaderCallback;
49
- this.streamId = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _ => _.streamId]), () => ( _uuid.v4.call(void 0, )));
49
+ this.streamId = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _2 => _2.streamId]), () => ( _uuid.v4.call(void 0, )));
50
50
  this.onNoActiveReaderCallback = onNoActiveReaderCallback;
51
- this.startChecking(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _2 => _2.intervalCheckInMs]), () => ( 20)));
51
+ this.startChecking(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _3 => _3.intervalCheckInMs]), () => ( 20)));
52
52
  }
53
53
  __init() {this.checkInterval = null}
54
54
 
@@ -127,7 +127,7 @@ var TaskProcessor = (_class2 = class {
127
127
  while (this.activeTasks < this.options.maxActiveTasks && this.queue.length > 0) {
128
128
  const item = this.takeFirstAvailableItem();
129
129
  if (item === null) return;
130
- const groupId = _optionalChain([item, 'access', _7 => _7.options, 'optionalAccess', _8 => _8.taskGroupId]);
130
+ const groupId = _optionalChain([item, 'access', _8 => _8.options, 'optionalAccess', _9 => _9.taskGroupId]);
131
131
  if (groupId) {
132
132
  this.activeGroups.add(groupId);
133
133
  }
@@ -157,7 +157,7 @@ var TaskProcessor = (_class2 = class {
157
157
  }
158
158
  __init7() {this.takeFirstAvailableItem = () => {
159
159
  const taskIndex = this.queue.findIndex(
160
- (item2) => !_optionalChain([item2, 'access', _9 => _9.options, 'optionalAccess', _10 => _10.taskGroupId]) || !this.activeGroups.has(item2.options.taskGroupId)
160
+ (item2) => !_optionalChain([item2, 'access', _10 => _10.options, 'optionalAccess', _11 => _11.taskGroupId]) || !this.activeGroups.has(item2.options.taskGroupId)
161
161
  );
162
162
  if (taskIndex === -1) {
163
163
  return null;
@@ -166,7 +166,7 @@ var TaskProcessor = (_class2 = class {
166
166
  return _nullishCoalesce(item, () => ( null));
167
167
  }}
168
168
  __init8() {this.hasItemsToProcess = () => this.queue.findIndex(
169
- (item) => !_optionalChain([item, 'access', _11 => _11.options, 'optionalAccess', _12 => _12.taskGroupId]) || !this.activeGroups.has(item.options.taskGroupId)
169
+ (item) => !_optionalChain([item, 'access', _12 => _12.options, 'optionalAccess', _13 => _13.taskGroupId]) || !this.activeGroups.has(item.options.taskGroupId)
170
170
  ) !== -1}
171
171
  }, _class2);
172
172
  var DEFAULT_PROMISE_DEADLINE = 2147483647;
@@ -242,14 +242,41 @@ var InProcessLock = () => {
242
242
  }
243
243
  };
244
244
  };
245
+ var ParseError = class extends Error {
246
+ constructor(text) {
247
+ super(`Cannot parse! ${text}`);
248
+ }
249
+ };
250
+ var JSONParser = {
251
+ stringify: (value, options) => {
252
+ return JSON.stringify(
253
+ _optionalChain([options, 'optionalAccess', _14 => _14.map]) ? options.map(value) : value,
254
+ //TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint
255
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
256
+ (_, v) => typeof v === "bigint" ? v.toString() : v
257
+ );
258
+ },
259
+ parse: (text, options) => {
260
+ const parsed = JSON.parse(text, _optionalChain([options, 'optionalAccess', _15 => _15.reviver]));
261
+ if (_optionalChain([options, 'optionalAccess', _16 => _16.typeCheck]) && !_optionalChain([options, 'optionalAccess', _17 => _17.typeCheck, 'call', _18 => _18(parsed)]))
262
+ throw new ParseError(text);
263
+ return _optionalChain([options, 'optionalAccess', _19 => _19.map]) ? options.map(parsed) : parsed;
264
+ }
265
+ };
245
266
  var asyncRetry = async (fn, opts) => {
246
267
  if (opts === void 0 || opts.retries === 0) return fn();
247
268
  return _asyncretry2.default.call(void 0,
248
269
  async (bail) => {
249
270
  try {
250
- return await fn();
271
+ const result = await fn();
272
+ if (_optionalChain([opts, 'optionalAccess', _20 => _20.shouldRetryResult]) && opts.shouldRetryResult(result)) {
273
+ throw new EmmettError(
274
+ `Retrying because of result: ${JSONParser.stringify(result)}`
275
+ );
276
+ }
277
+ return result;
251
278
  } catch (error2) {
252
- if (_optionalChain([opts, 'optionalAccess', _13 => _13.shouldRetryError]) && !opts.shouldRetryError(error2)) {
279
+ if (_optionalChain([opts, 'optionalAccess', _21 => _21.shouldRetryError]) && !opts.shouldRetryError(error2)) {
253
280
  bail(error2);
254
281
  }
255
282
  throw error2;
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/emmett/emmett/src/packages/emmett-testcontainers/dist/index.cjs","../src/eventStore/index.ts","../../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/database/inMemoryDatabase.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/taskProcessing/taskProcessor.ts","../../emmett/src/utils/locking/index.ts","../../emmett/src/streaming/transformations/index.ts","../src/eventStore/eventStoreDBContainer.ts"],"names":["TransformStream","error","item","filter","map","handleChunk","skip","retry"],"mappings":"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","file":"/home/runner/work/emmett/emmett/src/packages/emmett-testcontainers/dist/index.cjs","sourcesContent":[null,"import { EventStoreDBClient } from '@eventstore/db-client';\nimport {\n EventStoreDBContainer,\n StartedEventStoreDBContainer,\n} from './eventStoreDBContainer';\n\nexport * from './eventStoreDBContainer';\n\nlet esdbContainer: StartedEventStoreDBContainer;\n\nexport const getEventStoreDBTestClient = async (\n useTestContainers = false,\n): Promise<EventStoreDBClient> => {\n let connectionString;\n\n if (useTestContainers) {\n if (!esdbContainer)\n esdbContainer = await new EventStoreDBContainer().start();\n\n connectionString = esdbContainer.getConnectionString();\n } else {\n // await compose.upAll();\n connectionString = 'esdb://localhost:2113?tls=false';\n }\n\n // That's how EventStoreDB client is setup\n // We're taking the connection string from container\n return EventStoreDBClient.connectionString(connectionString);\n};\n","import { ValidationError } from '../errors';\n\nexport const enum ValidationErrors {\n NOT_A_NONEMPTY_STRING = 'NOT_A_NONEMPTY_STRING',\n NOT_A_POSITIVE_NUMBER = 'NOT_A_POSITIVE_NUMBER',\n NOT_AN_UNSIGNED_BIGINT = 'NOT_AN_UNSIGNED_BIGINT',\n}\n\nexport const isNumber = (val: unknown): val is number =>\n typeof val === 'number' && val === val;\n\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 ConcurrencyInMemoryDatabaseError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 412,\n message: message ?? `Expected document state does not match current one!`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyInMemoryDatabaseError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 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 { v7 as uuid } from 'uuid';\nimport { deepEquals } from '../utils';\nimport {\n type DeleteResult,\n type Document,\n type DocumentHandler,\n type HandleOptionErrors,\n type HandleOptions,\n type HandleResult,\n type InsertOneResult,\n type OptionalUnlessRequiredIdAndVersion,\n type ReplaceOneOptions,\n type UpdateResult,\n type WithoutId,\n type WithIdAndVersion,\n} from './types';\nimport { expectedVersionValue, operationResult } from './utils';\n\nexport interface DocumentsCollection<T extends Document> {\n handle: (\n id: string,\n handle: DocumentHandler<T>,\n options?: HandleOptions,\n ) => HandleResult<T>;\n findOne: (predicate?: Predicate<T>) => T | null;\n insertOne: (\n document: OptionalUnlessRequiredIdAndVersion<T>,\n ) => InsertOneResult;\n deleteOne: (predicate?: Predicate<T>) => DeleteResult;\n replaceOne: (\n predicate: Predicate<T>,\n document: WithoutId<T>,\n options?: ReplaceOneOptions,\n ) => UpdateResult;\n}\n\nexport interface Database {\n collection: <T extends Document>(name: string) => DocumentsCollection<T>;\n}\n\ntype Predicate<T> = (item: T) => boolean;\n\nexport const getInMemoryDatabase = (): Database => {\n const storage = new Map<string, WithIdAndVersion<Document>[]>();\n\n return {\n collection: <T extends Document>(\n collectionName: string,\n collectionOptions: {\n errors?: HandleOptionErrors;\n } = {},\n ): DocumentsCollection<T> => {\n const ensureCollectionCreated = () => {\n if (!storage.has(collectionName)) storage.set(collectionName, []);\n };\n\n const errors = collectionOptions.errors;\n\n const collection = {\n collectionName,\n insertOne: (\n document: OptionalUnlessRequiredIdAndVersion<T>,\n ): InsertOneResult => {\n ensureCollectionCreated();\n\n const _id = (document._id as string | undefined | null) ?? uuid();\n const _version = document._version ?? 1n;\n\n const existing = collection.findOne((c) => c._id === _id);\n\n if (existing) {\n return operationResult<InsertOneResult>(\n {\n successful: false,\n insertedId: null,\n nextExpectedVersion: _version,\n },\n { operationName: 'insertOne', collectionName, errors },\n );\n }\n\n const documentsInCollection = storage.get(collectionName)!;\n const newDocument = { ...document, _id, _version };\n const newCollection = [...documentsInCollection, newDocument];\n storage.set(collectionName, newCollection);\n\n return operationResult<InsertOneResult>(\n {\n successful: true,\n insertedId: _id,\n nextExpectedVersion: _version,\n },\n { operationName: 'insertOne', collectionName, errors },\n );\n },\n findOne: (predicate?: Predicate<T>): T | null => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName);\n const filteredDocuments = predicate\n ? documentsInCollection?.filter((doc) => predicate(doc as T))\n : documentsInCollection;\n\n const firstOne = filteredDocuments?.[0] ?? null;\n\n return firstOne as T | null;\n },\n deleteOne: (predicate?: Predicate<T>): DeleteResult => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName)!;\n\n if (predicate) {\n const foundIndex = documentsInCollection.findIndex((doc) =>\n predicate(doc as T),\n );\n\n if (foundIndex === -1) {\n return operationResult<DeleteResult>(\n {\n successful: false,\n matchedCount: 0,\n deletedCount: 0,\n },\n { operationName: 'deleteOne', collectionName, errors },\n );\n } else {\n const newCollection = documentsInCollection.toSpliced(\n foundIndex,\n 1,\n );\n\n storage.set(collectionName, newCollection);\n\n return operationResult<DeleteResult>(\n {\n successful: true,\n matchedCount: 1,\n deletedCount: 1,\n },\n { operationName: 'deleteOne', collectionName, errors },\n );\n }\n } else {\n const newCollection = documentsInCollection.slice(1);\n\n storage.set(collectionName, newCollection);\n\n return operationResult<DeleteResult>(\n {\n successful: true,\n matchedCount: 1,\n deletedCount: 1,\n },\n { operationName: 'deleteOne', collectionName, errors },\n );\n }\n },\n replaceOne: (\n predicate: Predicate<T>,\n document: WithoutId<T>,\n options?: ReplaceOneOptions,\n ): UpdateResult => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName)!;\n\n const foundIndexes = documentsInCollection\n .filter((doc) => predicate(doc as T))\n .map((_, index) => index);\n\n const firstIndex = foundIndexes[0];\n\n if (!firstIndex || firstIndex === -1) {\n return operationResult<UpdateResult>(\n {\n successful: false,\n matchedCount: 0,\n modifiedCount: 0,\n nextExpectedVersion: 0n,\n },\n { operationName: 'replaceOne', collectionName, errors },\n );\n }\n\n const existing = documentsInCollection[firstIndex]!;\n\n if (\n typeof options?.expectedVersion === 'bigint' &&\n existing._version !== options.expectedVersion\n ) {\n return operationResult<UpdateResult>(\n {\n successful: false,\n matchedCount: 1,\n modifiedCount: 0,\n nextExpectedVersion: existing._version,\n },\n { operationName: 'replaceOne', collectionName, errors },\n );\n }\n\n const newVersion = existing._version + 1n;\n\n const newCollection = documentsInCollection.with(firstIndex, {\n _id: existing._id,\n ...document,\n _version: newVersion,\n });\n\n storage.set(collectionName, newCollection);\n\n return operationResult<UpdateResult>(\n {\n successful: true,\n modifiedCount: 1,\n matchedCount: foundIndexes.length,\n nextExpectedVersion: newVersion,\n },\n { operationName: 'replaceOne', collectionName, errors },\n );\n },\n handle: (\n id: string,\n handle: DocumentHandler<T>,\n options?: HandleOptions,\n ): HandleResult<T> => {\n const { expectedVersion: version, ...operationOptions } =\n options ?? {};\n ensureCollectionCreated();\n const existing = collection.findOne((c) => c.id === id);\n\n const expectedVersion = expectedVersionValue(version);\n\n if (\n (existing == null && version === 'DOCUMENT_EXISTS') ||\n (existing == null && expectedVersion != null) ||\n (existing != null && version === 'DOCUMENT_DOES_NOT_EXIST') ||\n (existing != null &&\n expectedVersion !== null &&\n existing._version !== expectedVersion)\n ) {\n return operationResult<HandleResult<T>>(\n {\n successful: false,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n }\n\n const result = handle(existing !== null ? { ...existing } : null);\n\n if (deepEquals(existing, result))\n return operationResult<HandleResult<T>>(\n {\n successful: true,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n\n if (!existing && result) {\n const newDoc = { ...result, _id: id };\n const insertResult = collection.insertOne({\n ...newDoc,\n _id: id,\n } as OptionalUnlessRequiredIdAndVersion<T>);\n return {\n ...insertResult,\n document: {\n ...newDoc,\n _version: insertResult.nextExpectedVersion,\n } as unknown as WithIdAndVersion<T>,\n };\n }\n\n if (existing && !result) {\n const deleteResult = collection.deleteOne(({ _id }) => id === _id);\n return { ...deleteResult, document: null };\n }\n\n if (existing && result) {\n const replaceResult = collection.replaceOne(\n ({ _id }) => id === _id,\n result,\n {\n ...operationOptions,\n expectedVersion: expectedVersion ?? 'DOCUMENT_EXISTS',\n },\n );\n return {\n ...replaceResult,\n document: {\n ...result,\n _version: replaceResult.nextExpectedVersion,\n } as unknown as WithIdAndVersion<T>,\n };\n }\n\n return operationResult<HandleResult<T>>(\n {\n successful: true,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n },\n };\n\n return collection;\n },\n };\n};\n","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 { EmmettError } from '../errors';\n\nexport type TaskQueue = TaskQueueItem[];\n\nexport type TaskQueueItem = {\n task: () => Promise<void>;\n options?: EnqueueTaskOptions;\n};\n\nexport type TaskProcessorOptions = {\n maxActiveTasks: number;\n maxQueueSize: number;\n maxTaskIdleTime?: number;\n};\n\nexport type Task<T> = (context: TaskContext) => Promise<T>;\n\nexport type TaskContext = {\n ack: () => void;\n};\n\nexport type EnqueueTaskOptions = { taskGroupId?: string };\n\nexport class TaskProcessor {\n private queue: TaskQueue = [];\n private isProcessing = false;\n private activeTasks = 0;\n private activeGroups: Set<string> = new Set();\n\n constructor(private options: TaskProcessorOptions) {}\n\n enqueue<T>(task: Task<T>, options?: EnqueueTaskOptions): Promise<T> {\n if (this.queue.length >= this.options.maxQueueSize) {\n return Promise.reject(\n new EmmettError(\n 'Too many pending connections. Please try again later.',\n ),\n );\n }\n\n return this.schedule(task, options);\n }\n\n waitForEndOfProcessing(): Promise<void> {\n return this.schedule(({ ack }) => Promise.resolve(ack()));\n }\n\n private schedule<T>(task: Task<T>, options?: EnqueueTaskOptions): Promise<T> {\n return promiseWithDeadline(\n (resolve, reject) => {\n const taskWithContext = () => {\n return new Promise<void>((resolveTask, failTask) => {\n const taskPromise = task({\n ack: resolveTask,\n });\n\n taskPromise.then(resolve).catch((err) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n failTask(err);\n reject(err);\n });\n });\n };\n\n this.queue.push({ task: taskWithContext, options });\n if (!this.isProcessing) {\n this.ensureProcessing();\n }\n },\n { deadline: this.options.maxTaskIdleTime },\n );\n }\n\n private ensureProcessing(): void {\n if (this.isProcessing) return;\n this.isProcessing = true;\n this.processQueue();\n }\n\n private processQueue(): void {\n try {\n while (\n this.activeTasks < this.options.maxActiveTasks &&\n this.queue.length > 0\n ) {\n const item = this.takeFirstAvailableItem();\n\n if (item === null) return;\n\n const groupId = item.options?.taskGroupId;\n\n if (groupId) {\n // Mark the group as active\n this.activeGroups.add(groupId);\n }\n\n this.activeTasks++;\n void this.executeItem(item);\n }\n } catch (error) {\n console.error(error);\n throw error;\n } finally {\n this.isProcessing = false;\n if (\n this.hasItemsToProcess() &&\n this.activeTasks < this.options.maxActiveTasks\n ) {\n this.ensureProcessing();\n }\n }\n }\n\n private async executeItem({ task, options }: TaskQueueItem): Promise<void> {\n try {\n await task();\n } finally {\n this.activeTasks--;\n\n // Mark the group as inactive after task completion\n if (options && options.taskGroupId) {\n this.activeGroups.delete(options.taskGroupId);\n }\n\n this.ensureProcessing();\n }\n }\n\n private takeFirstAvailableItem = (): TaskQueueItem | null => {\n const taskIndex = this.queue.findIndex(\n (item) =>\n !item.options?.taskGroupId ||\n !this.activeGroups.has(item.options.taskGroupId),\n );\n\n if (taskIndex === -1) {\n // All remaining tasks are blocked by active groups\n return null;\n }\n\n // Remove the task from the queue\n const [item] = this.queue.splice(taskIndex, 1);\n\n return item ?? null;\n };\n\n private hasItemsToProcess = (): boolean =>\n this.queue.findIndex(\n (item) =>\n !item.options?.taskGroupId ||\n !this.activeGroups.has(item.options.taskGroupId),\n ) !== -1;\n}\n\nconst DEFAULT_PROMISE_DEADLINE = 2147483647;\n\nconst promiseWithDeadline = <T>(\n executor: (\n resolve: (value: T | PromiseLike<T>) => void,\n reject: (reason?: unknown) => void,\n ) => void,\n options: { deadline?: number },\n) => {\n return new Promise<T>((resolve, reject) => {\n let taskStarted = false;\n\n const maxWaitingTime = options.deadline || DEFAULT_PROMISE_DEADLINE;\n\n let timeoutId: NodeJS.Timeout | null = setTimeout(() => {\n if (!taskStarted) {\n reject(\n new Error('Task was not started within the maximum waiting time'),\n );\n }\n }, maxWaitingTime);\n\n executor((value) => {\n taskStarted = true;\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n timeoutId = null;\n resolve(value);\n }, reject);\n });\n};\n","import { TaskProcessor } from '../../taskProcessing';\n\nexport type LockOptions = { lockId: number };\n\nexport type AcquireLockOptions = { lockId: string };\nexport type ReleaseLockOptions = { lockId: string };\n\nexport type Lock = {\n acquire(options: AcquireLockOptions): Promise<void>;\n tryAcquire(options: AcquireLockOptions): Promise<boolean>;\n release(options: ReleaseLockOptions): Promise<boolean>;\n withAcquire: <Result = unknown>(\n handle: () => Promise<Result>,\n options: AcquireLockOptions,\n ) => Promise<Result>;\n};\n\nexport const InProcessLock = (): Lock => {\n const taskProcessor = new TaskProcessor({\n maxActiveTasks: Number.MAX_VALUE,\n maxQueueSize: Number.MAX_VALUE,\n });\n\n // Map to store ack functions of currently held locks: lockId -> ack()\n const locks = new Map<string, () => void>();\n\n return {\n async acquire({ lockId }: AcquireLockOptions): Promise<void> {\n // If the lock is already held, we just queue up another task in the same group.\n // TaskProcessor ensures tasks in the same group run one at a time.\n await new Promise<void>((resolve, reject) => {\n taskProcessor\n .enqueue(\n ({ ack }) => {\n // When this task starts, it means the previous lock (if any) was released\n // and now we have exclusive access.\n locks.set(lockId, ack);\n // We do NOT call ack() here. We hold onto the lock.\n resolve();\n return Promise.resolve();\n },\n { taskGroupId: lockId },\n )\n .catch(reject);\n });\n },\n\n async tryAcquire({ lockId }: AcquireLockOptions): Promise<boolean> {\n // If lock is already held, fail immediately\n if (locks.has(lockId)) {\n return false;\n }\n\n // TODO: Check pending queue\n await this.acquire({ lockId });\n\n return true;\n },\n\n release({ lockId }: ReleaseLockOptions): Promise<boolean> {\n const ack = locks.get(lockId);\n if (ack === undefined) {\n return Promise.resolve(true);\n }\n locks.delete(lockId);\n ack();\n return Promise.resolve(true);\n },\n\n async withAcquire<Result = unknown>(\n handle: () => Promise<Result>,\n { lockId }: AcquireLockOptions,\n ): Promise<Result> {\n return taskProcessor.enqueue(\n async ({ ack }) => {\n // When this task starts, it means the previous lock (if any) was released\n // and now we have exclusive access.\n locks.set(lockId, ack);\n\n // We do NOT call ack() here. We hold onto the lock.\n try {\n return await handle();\n } finally {\n locks.delete(lockId);\n ack();\n }\n },\n { taskGroupId: lockId },\n );\n },\n };\n};\n","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 { InProcessLock } from '@event-driven-io/emmett';\nimport { EventStoreDBClient } from '@eventstore/db-client';\nimport {\n AbstractStartedContainer,\n GenericContainer,\n Wait,\n type StartedTestContainer,\n} from 'testcontainers';\nimport type { Environment } from 'testcontainers/build/types';\n\nexport const EVENTSTOREDB_PORT = 2113;\nexport const EVENTSTOREDB_IMAGE_NAME = 'eventstore/eventstore';\nexport const EVENTSTOREDB_IMAGE_TAG = '24.10.0-bookworm-slim';\nexport const EVENTSTOREDB_ARM64_IMAGE_TAG = '24.10.0-alpha-arm64v8';\n\nexport const EVENTSTOREDB_DEFAULT_IMAGE = `${EVENTSTOREDB_IMAGE_NAME}:${process.arch !== 'arm64' ? EVENTSTOREDB_IMAGE_TAG : EVENTSTOREDB_ARM64_IMAGE_TAG}`;\n\nexport type EventStoreDBContainerOptions = {\n disableProjections?: boolean;\n isSecure?: boolean;\n useFileStorage?: boolean;\n withReuse?: boolean;\n};\n\nexport const defaultEventStoreDBContainerOptions: EventStoreDBContainerOptions =\n {\n disableProjections: false,\n isSecure: false,\n useFileStorage: false,\n withReuse: false,\n };\n\nexport class EventStoreDBContainer extends GenericContainer {\n constructor(\n image = EVENTSTOREDB_DEFAULT_IMAGE,\n options: EventStoreDBContainerOptions = defaultEventStoreDBContainerOptions,\n ) {\n super(image);\n\n const environment: Environment = {\n ...(!options.disableProjections\n ? {\n EVENTSTORE_RUN_PROJECTIONS: 'ALL',\n }\n : {}),\n ...(!options.isSecure\n ? {\n EVENTSTORE_INSECURE: 'true',\n }\n : {}),\n ...(options.useFileStorage\n ? {\n EVENTSTORE_MEM_DB: 'false',\n EVENTSTORE_DB: '/data/integration-tests',\n }\n : {}),\n EVENTSTORE_CLUSTER_SIZE: '1',\n EVENTSTORE_START_STANDARD_PROJECTIONS: 'true',\n EVENTSTORE_NODE_PORT: `${EVENTSTOREDB_PORT}`,\n EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP: 'true',\n };\n\n this.withEnvironment(environment).withExposedPorts(EVENTSTOREDB_PORT);\n\n if (options.withReuse) this.withReuse();\n\n this.withWaitStrategy(\n Wait.forAll([Wait.forHealthCheck(), Wait.forListeningPorts()]),\n );\n }\n\n async start(): Promise<StartedEventStoreDBContainer> {\n return new StartedEventStoreDBContainer(await super.start());\n }\n}\n\nexport class StartedEventStoreDBContainer extends AbstractStartedContainer {\n constructor(container: StartedTestContainer) {\n super(container);\n }\n\n getConnectionString(): string {\n return `esdb://${this.getHost()}:${this.getMappedPort(2113)}?tls=false`;\n }\n\n getClient(): EventStoreDBClient {\n return EventStoreDBClient.connectionString(this.getConnectionString());\n }\n}\n\nlet container: EventStoreDBContainer | null = null;\nlet startedContainer: StartedEventStoreDBContainer | null = null;\nlet startedCount = 0;\nconst lock = InProcessLock();\n\nexport const getSharedEventStoreDBTestContainer = () =>\n lock.withAcquire(\n async () => {\n if (startedContainer) return startedContainer;\n\n if (!container)\n container = new EventStoreDBContainer(EVENTSTOREDB_DEFAULT_IMAGE);\n\n startedContainer = await container.start();\n startedCount++;\n\n container.withLogConsumer((stream) =>\n stream\n .on('data', (line) => console.log(line))\n .on('err', (line) => console.error(line))\n .on('end', () => console.log('Stream closed')),\n );\n\n return startedContainer;\n },\n { lockId: 'SharedEventStoreDBTestContainer' },\n );\n\nexport const getSharedTestEventStoreDBClient = async () => {\n return (await getSharedEventStoreDBTestContainer()).getClient();\n};\n\nexport const releaseSharedEventStoreDBTestContainer = () =>\n lock.withAcquire(\n async () => {\n const containerToStop = startedContainer;\n if (containerToStop && --startedCount === 0) {\n try {\n startedContainer = null;\n container = null;\n await containerToStop.stop();\n } catch {\n /* do nothing */\n }\n }\n },\n { lockId: 'SharedEventStoreDBTestContainer' },\n );\n"]}
1
+ {"version":3,"sources":["/home/runner/work/emmett/emmett/src/packages/emmett-testcontainers/dist/index.cjs","../src/eventStore/index.ts","../../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/database/inMemoryDatabase.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/taskProcessing/taskProcessor.ts","../../emmett/src/utils/locking/index.ts","../../emmett/src/serialization/json/JSONParser.ts","../../emmett/src/streaming/transformations/index.ts","../src/eventStore/eventStoreDBContainer.ts"],"names":["TransformStream","error","item","skip"],"mappings":"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","file":"/home/runner/work/emmett/emmett/src/packages/emmett-testcontainers/dist/index.cjs","sourcesContent":[null,"import { EventStoreDBClient } from '@eventstore/db-client';\nimport {\n EventStoreDBContainer,\n StartedEventStoreDBContainer,\n} from './eventStoreDBContainer';\n\nexport * from './eventStoreDBContainer';\n\nlet esdbContainer: StartedEventStoreDBContainer;\n\nexport const getEventStoreDBTestClient = async (\n useTestContainers = false,\n): Promise<EventStoreDBClient> => {\n let connectionString;\n\n if (useTestContainers) {\n if (!esdbContainer)\n esdbContainer = await new EventStoreDBContainer().start();\n\n connectionString = esdbContainer.getConnectionString();\n } else {\n // await compose.upAll();\n connectionString = 'esdb://localhost:2113?tls=false';\n }\n\n // That's how EventStoreDB client is setup\n // We're taking the connection string from container\n return EventStoreDBClient.connectionString(connectionString);\n};\n","import { ValidationError } from '../errors';\n\nexport const enum ValidationErrors {\n NOT_A_NONEMPTY_STRING = 'NOT_A_NONEMPTY_STRING',\n NOT_A_POSITIVE_NUMBER = 'NOT_A_POSITIVE_NUMBER',\n NOT_AN_UNSIGNED_BIGINT = 'NOT_AN_UNSIGNED_BIGINT',\n}\n\nexport const isNumber = (val: unknown): val is number =>\n typeof val === 'number' && val === val;\n\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 ConcurrencyInMemoryDatabaseError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 412,\n message: message ?? `Expected document state does not match current one!`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyInMemoryDatabaseError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 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';\nimport { EmmettError } from '../errors';\nimport { JSONParser } from '../serialization';\n\nexport type AsyncRetryOptions<T = unknown> = retry.Options & {\n shouldRetryResult?: (result: T) => boolean;\n shouldRetryError?: (error?: unknown) => boolean;\n};\n\nexport const NoRetries: AsyncRetryOptions = { retries: 0 };\n\nexport const asyncRetry = async <T>(\n fn: () => Promise<T>,\n opts?: AsyncRetryOptions<T>,\n): Promise<T> => {\n if (opts === undefined || opts.retries === 0) return fn();\n\n return retry(\n async (bail) => {\n try {\n const result = await fn();\n\n if (opts?.shouldRetryResult && opts.shouldRetryResult(result)) {\n throw new EmmettError(\n `Retrying because of result: ${JSONParser.stringify(result)}`,\n );\n }\n return result;\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 { v7 as uuid } from 'uuid';\nimport { deepEquals } from '../utils';\nimport {\n type DeleteResult,\n type Document,\n type DocumentHandler,\n type HandleOptionErrors,\n type HandleOptions,\n type HandleResult,\n type InsertOneResult,\n type OptionalUnlessRequiredIdAndVersion,\n type ReplaceOneOptions,\n type UpdateResult,\n type WithoutId,\n type WithIdAndVersion,\n} from './types';\nimport { expectedVersionValue, operationResult } from './utils';\n\nexport interface DocumentsCollection<T extends Document> {\n handle: (\n id: string,\n handle: DocumentHandler<T>,\n options?: HandleOptions,\n ) => HandleResult<T>;\n findOne: (predicate?: Predicate<T>) => T | null;\n find: (predicate?: Predicate<T>) => T[];\n insertOne: (\n document: OptionalUnlessRequiredIdAndVersion<T>,\n ) => InsertOneResult;\n deleteOne: (predicate?: Predicate<T>) => DeleteResult;\n replaceOne: (\n predicate: Predicate<T>,\n document: WithoutId<T>,\n options?: ReplaceOneOptions,\n ) => UpdateResult;\n}\n\nexport interface Database {\n collection: <T extends Document>(name: string) => DocumentsCollection<T>;\n}\n\ntype Predicate<T> = (item: T) => boolean;\ntype CollectionName = string;\n\nexport const getInMemoryDatabase = (): Database => {\n const storage = new Map<CollectionName, WithIdAndVersion<Document>[]>();\n\n return {\n collection: <T extends Document, CollectionName extends string>(\n collectionName: CollectionName,\n collectionOptions: {\n errors?: HandleOptionErrors;\n } = {},\n ): DocumentsCollection<T> => {\n const ensureCollectionCreated = () => {\n if (!storage.has(collectionName)) storage.set(collectionName, []);\n };\n\n const errors = collectionOptions.errors;\n\n const collection = {\n collectionName,\n insertOne: (\n document: OptionalUnlessRequiredIdAndVersion<T>,\n ): InsertOneResult => {\n ensureCollectionCreated();\n\n const _id = (document._id as string | undefined | null) ?? uuid();\n const _version = document._version ?? 1n;\n\n const existing = collection.findOne((c) => c._id === _id);\n\n if (existing) {\n return operationResult<InsertOneResult>(\n {\n successful: false,\n insertedId: null,\n nextExpectedVersion: _version,\n },\n { operationName: 'insertOne', collectionName, errors },\n );\n }\n\n const documentsInCollection = storage.get(collectionName)!;\n const newDocument = { ...document, _id, _version };\n const newCollection = [...documentsInCollection, newDocument];\n storage.set(collectionName, newCollection);\n\n return operationResult<InsertOneResult>(\n {\n successful: true,\n insertedId: _id,\n nextExpectedVersion: _version,\n },\n { operationName: 'insertOne', collectionName, errors },\n );\n },\n findOne: (predicate?: Predicate<T>): T | null => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName);\n const filteredDocuments = predicate\n ? documentsInCollection?.filter((doc) => predicate(doc as T))\n : documentsInCollection;\n\n const firstOne = filteredDocuments?.[0] ?? null;\n\n return firstOne as T | null;\n },\n find: (predicate?: Predicate<T>): T[] => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName);\n const filteredDocuments = predicate\n ? documentsInCollection?.filter((doc) => predicate(doc as T))\n : documentsInCollection;\n\n return filteredDocuments as T[];\n },\n deleteOne: (predicate?: Predicate<T>): DeleteResult => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName)!;\n\n if (predicate) {\n const foundIndex = documentsInCollection.findIndex((doc) =>\n predicate(doc as T),\n );\n\n if (foundIndex === -1) {\n return operationResult<DeleteResult>(\n {\n successful: false,\n matchedCount: 0,\n deletedCount: 0,\n },\n { operationName: 'deleteOne', collectionName, errors },\n );\n } else {\n const newCollection = documentsInCollection.toSpliced(\n foundIndex,\n 1,\n );\n\n storage.set(collectionName, newCollection);\n\n return operationResult<DeleteResult>(\n {\n successful: true,\n matchedCount: 1,\n deletedCount: 1,\n },\n { operationName: 'deleteOne', collectionName, errors },\n );\n }\n }\n\n const newCollection = documentsInCollection.slice(1);\n\n storage.set(collectionName, newCollection);\n\n return operationResult<DeleteResult>(\n {\n successful: true,\n matchedCount: 1,\n deletedCount: 1,\n },\n { operationName: 'deleteOne', collectionName, errors },\n );\n },\n replaceOne: (\n predicate: Predicate<T>,\n document: WithoutId<T>,\n options?: ReplaceOneOptions,\n ): UpdateResult => {\n ensureCollectionCreated();\n\n const documentsInCollection = storage.get(collectionName)!;\n\n const foundIndexes = documentsInCollection\n .filter((doc) => predicate(doc as T))\n .map((_, index) => index);\n\n const firstIndex = foundIndexes[0];\n\n if (firstIndex === undefined || firstIndex === -1) {\n return operationResult<UpdateResult>(\n {\n successful: false,\n matchedCount: 0,\n modifiedCount: 0,\n nextExpectedVersion: 0n,\n },\n { operationName: 'replaceOne', collectionName, errors },\n );\n }\n\n const existing = documentsInCollection[firstIndex]!;\n\n if (\n typeof options?.expectedVersion === 'bigint' &&\n existing._version !== options.expectedVersion\n ) {\n return operationResult<UpdateResult>(\n {\n successful: false,\n matchedCount: 1,\n modifiedCount: 0,\n nextExpectedVersion: existing._version,\n },\n { operationName: 'replaceOne', collectionName, errors },\n );\n }\n\n const newVersion = existing._version + 1n;\n\n const newCollection = documentsInCollection.with(firstIndex, {\n _id: existing._id,\n ...document,\n _version: newVersion,\n });\n\n storage.set(collectionName, newCollection);\n\n return operationResult<UpdateResult>(\n {\n successful: true,\n modifiedCount: 1,\n matchedCount: foundIndexes.length,\n nextExpectedVersion: newVersion,\n },\n { operationName: 'replaceOne', collectionName, errors },\n );\n },\n handle: (\n id: string,\n handle: DocumentHandler<T>,\n options?: HandleOptions,\n ): HandleResult<T> => {\n const { expectedVersion: version, ...operationOptions } =\n options ?? {};\n ensureCollectionCreated();\n const existing = collection.findOne(({ _id }) => _id === id);\n\n const expectedVersion = expectedVersionValue(version);\n\n if (\n (existing == null && version === 'DOCUMENT_EXISTS') ||\n (existing == null && expectedVersion != null) ||\n (existing != null && version === 'DOCUMENT_DOES_NOT_EXIST') ||\n (existing != null &&\n expectedVersion !== null &&\n existing._version !== expectedVersion)\n ) {\n return operationResult<HandleResult<T>>(\n {\n successful: false,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n }\n\n const result = handle(existing !== null ? { ...existing } : null);\n\n if (deepEquals(existing, result))\n return operationResult<HandleResult<T>>(\n {\n successful: true,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n\n if (!existing && result) {\n const newDoc = { ...result, _id: id };\n const insertResult = collection.insertOne({\n ...newDoc,\n _id: id,\n } as OptionalUnlessRequiredIdAndVersion<T>);\n return {\n ...insertResult,\n document: {\n ...newDoc,\n _version: insertResult.nextExpectedVersion,\n } as unknown as WithIdAndVersion<T>,\n };\n }\n\n if (existing && !result) {\n const deleteResult = collection.deleteOne(({ _id }) => id === _id);\n return { ...deleteResult, document: null };\n }\n\n if (existing && result) {\n const replaceResult = collection.replaceOne(\n ({ _id }) => id === _id,\n result,\n {\n ...operationOptions,\n expectedVersion: expectedVersion ?? 'DOCUMENT_EXISTS',\n },\n );\n return {\n ...replaceResult,\n document: {\n ...result,\n _version: replaceResult.nextExpectedVersion,\n } as unknown as WithIdAndVersion<T>,\n };\n }\n\n return operationResult<HandleResult<T>>(\n {\n successful: true,\n document: existing as WithIdAndVersion<T>,\n },\n { operationName: 'handle', collectionName, errors },\n );\n },\n };\n\n return collection;\n },\n };\n};\n","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 { EmmettError } from '../errors';\n\nexport type TaskQueue = TaskQueueItem[];\n\nexport type TaskQueueItem = {\n task: () => Promise<void>;\n options?: EnqueueTaskOptions;\n};\n\nexport type TaskProcessorOptions = {\n maxActiveTasks: number;\n maxQueueSize: number;\n maxTaskIdleTime?: number;\n};\n\nexport type Task<T> = (context: TaskContext) => Promise<T>;\n\nexport type TaskContext = {\n ack: () => void;\n};\n\nexport type EnqueueTaskOptions = { taskGroupId?: string };\n\nexport class TaskProcessor {\n private queue: TaskQueue = [];\n private isProcessing = false;\n private activeTasks = 0;\n private activeGroups: Set<string> = new Set();\n\n constructor(private options: TaskProcessorOptions) {}\n\n enqueue<T>(task: Task<T>, options?: EnqueueTaskOptions): Promise<T> {\n if (this.queue.length >= this.options.maxQueueSize) {\n return Promise.reject(\n new EmmettError(\n 'Too many pending connections. Please try again later.',\n ),\n );\n }\n\n return this.schedule(task, options);\n }\n\n waitForEndOfProcessing(): Promise<void> {\n return this.schedule(({ ack }) => Promise.resolve(ack()));\n }\n\n private schedule<T>(task: Task<T>, options?: EnqueueTaskOptions): Promise<T> {\n return promiseWithDeadline(\n (resolve, reject) => {\n const taskWithContext = () => {\n return new Promise<void>((resolveTask, failTask) => {\n const taskPromise = task({\n ack: resolveTask,\n });\n\n taskPromise.then(resolve).catch((err) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\n failTask(err);\n reject(err);\n });\n });\n };\n\n this.queue.push({ task: taskWithContext, options });\n if (!this.isProcessing) {\n this.ensureProcessing();\n }\n },\n { deadline: this.options.maxTaskIdleTime },\n );\n }\n\n private ensureProcessing(): void {\n if (this.isProcessing) return;\n this.isProcessing = true;\n this.processQueue();\n }\n\n private processQueue(): void {\n try {\n while (\n this.activeTasks < this.options.maxActiveTasks &&\n this.queue.length > 0\n ) {\n const item = this.takeFirstAvailableItem();\n\n if (item === null) return;\n\n const groupId = item.options?.taskGroupId;\n\n if (groupId) {\n // Mark the group as active\n this.activeGroups.add(groupId);\n }\n\n this.activeTasks++;\n void this.executeItem(item);\n }\n } catch (error) {\n console.error(error);\n throw error;\n } finally {\n this.isProcessing = false;\n if (\n this.hasItemsToProcess() &&\n this.activeTasks < this.options.maxActiveTasks\n ) {\n this.ensureProcessing();\n }\n }\n }\n\n private async executeItem({ task, options }: TaskQueueItem): Promise<void> {\n try {\n await task();\n } finally {\n this.activeTasks--;\n\n // Mark the group as inactive after task completion\n if (options && options.taskGroupId) {\n this.activeGroups.delete(options.taskGroupId);\n }\n\n this.ensureProcessing();\n }\n }\n\n private takeFirstAvailableItem = (): TaskQueueItem | null => {\n const taskIndex = this.queue.findIndex(\n (item) =>\n !item.options?.taskGroupId ||\n !this.activeGroups.has(item.options.taskGroupId),\n );\n\n if (taskIndex === -1) {\n // All remaining tasks are blocked by active groups\n return null;\n }\n\n // Remove the task from the queue\n const [item] = this.queue.splice(taskIndex, 1);\n\n return item ?? null;\n };\n\n private hasItemsToProcess = (): boolean =>\n this.queue.findIndex(\n (item) =>\n !item.options?.taskGroupId ||\n !this.activeGroups.has(item.options.taskGroupId),\n ) !== -1;\n}\n\nconst DEFAULT_PROMISE_DEADLINE = 2147483647;\n\nconst promiseWithDeadline = <T>(\n executor: (\n resolve: (value: T | PromiseLike<T>) => void,\n reject: (reason?: unknown) => void,\n ) => void,\n options: { deadline?: number },\n) => {\n return new Promise<T>((resolve, reject) => {\n let taskStarted = false;\n\n const maxWaitingTime = options.deadline || DEFAULT_PROMISE_DEADLINE;\n\n let timeoutId: NodeJS.Timeout | null = setTimeout(() => {\n if (!taskStarted) {\n reject(\n new Error('Task was not started within the maximum waiting time'),\n );\n }\n }, maxWaitingTime);\n\n executor((value) => {\n taskStarted = true;\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n timeoutId = null;\n resolve(value);\n }, reject);\n });\n};\n","import { TaskProcessor } from '../../taskProcessing';\n\nexport type LockOptions = { lockId: number };\n\nexport type AcquireLockOptions = { lockId: string };\nexport type ReleaseLockOptions = { lockId: string };\n\nexport type Lock = {\n acquire(options: AcquireLockOptions): Promise<void>;\n tryAcquire(options: AcquireLockOptions): Promise<boolean>;\n release(options: ReleaseLockOptions): Promise<boolean>;\n withAcquire: <Result = unknown>(\n handle: () => Promise<Result>,\n options: AcquireLockOptions,\n ) => Promise<Result>;\n};\n\nexport const InProcessLock = (): Lock => {\n const taskProcessor = new TaskProcessor({\n maxActiveTasks: Number.MAX_VALUE,\n maxQueueSize: Number.MAX_VALUE,\n });\n\n // Map to store ack functions of currently held locks: lockId -> ack()\n const locks = new Map<string, () => void>();\n\n return {\n async acquire({ lockId }: AcquireLockOptions): Promise<void> {\n // If the lock is already held, we just queue up another task in the same group.\n // TaskProcessor ensures tasks in the same group run one at a time.\n await new Promise<void>((resolve, reject) => {\n taskProcessor\n .enqueue(\n ({ ack }) => {\n // When this task starts, it means the previous lock (if any) was released\n // and now we have exclusive access.\n locks.set(lockId, ack);\n // We do NOT call ack() here. We hold onto the lock.\n resolve();\n return Promise.resolve();\n },\n { taskGroupId: lockId },\n )\n .catch(reject);\n });\n },\n\n async tryAcquire({ lockId }: AcquireLockOptions): Promise<boolean> {\n // If lock is already held, fail immediately\n if (locks.has(lockId)) {\n return false;\n }\n\n // TODO: Check pending queue\n await this.acquire({ lockId });\n\n return true;\n },\n\n release({ lockId }: ReleaseLockOptions): Promise<boolean> {\n const ack = locks.get(lockId);\n if (ack === undefined) {\n return Promise.resolve(true);\n }\n locks.delete(lockId);\n ack();\n return Promise.resolve(true);\n },\n\n async withAcquire<Result = unknown>(\n handle: () => Promise<Result>,\n { lockId }: AcquireLockOptions,\n ): Promise<Result> {\n return taskProcessor.enqueue(\n async ({ ack }) => {\n // When this task starts, it means the previous lock (if any) was released\n // and now we have exclusive access.\n locks.set(lockId, ack);\n\n // We do NOT call ack() here. We hold onto the lock.\n try {\n return await handle();\n } finally {\n locks.delete(lockId);\n ack();\n }\n },\n { taskGroupId: lockId },\n );\n },\n };\n};\n","export 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 { 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 { InProcessLock } from '@event-driven-io/emmett';\nimport { EventStoreDBClient } from '@eventstore/db-client';\nimport {\n AbstractStartedContainer,\n GenericContainer,\n Wait,\n type StartedTestContainer,\n} from 'testcontainers';\nimport type { Environment } from 'testcontainers/build/types';\n\nexport const EVENTSTOREDB_PORT = 2113;\nexport const EVENTSTOREDB_IMAGE_NAME = 'eventstore/eventstore';\nexport const EVENTSTOREDB_IMAGE_TAG = '24.10.0-bookworm-slim';\nexport const EVENTSTOREDB_ARM64_IMAGE_TAG = '24.10.0-alpha-arm64v8';\n\nexport const EVENTSTOREDB_DEFAULT_IMAGE = `${EVENTSTOREDB_IMAGE_NAME}:${process.arch !== 'arm64' ? EVENTSTOREDB_IMAGE_TAG : EVENTSTOREDB_ARM64_IMAGE_TAG}`;\n\nexport type EventStoreDBContainerOptions = {\n disableProjections?: boolean;\n isSecure?: boolean;\n useFileStorage?: boolean;\n withReuse?: boolean;\n};\n\nexport const defaultEventStoreDBContainerOptions: EventStoreDBContainerOptions =\n {\n disableProjections: false,\n isSecure: false,\n useFileStorage: false,\n withReuse: false,\n };\n\nexport class EventStoreDBContainer extends GenericContainer {\n constructor(\n image = EVENTSTOREDB_DEFAULT_IMAGE,\n options: EventStoreDBContainerOptions = defaultEventStoreDBContainerOptions,\n ) {\n super(image);\n\n const environment: Environment = {\n ...(!options.disableProjections\n ? {\n EVENTSTORE_RUN_PROJECTIONS: 'ALL',\n }\n : {}),\n ...(!options.isSecure\n ? {\n EVENTSTORE_INSECURE: 'true',\n }\n : {}),\n ...(options.useFileStorage\n ? {\n EVENTSTORE_MEM_DB: 'false',\n EVENTSTORE_DB: '/data/integration-tests',\n }\n : {}),\n EVENTSTORE_CLUSTER_SIZE: '1',\n EVENTSTORE_START_STANDARD_PROJECTIONS: 'true',\n EVENTSTORE_NODE_PORT: `${EVENTSTOREDB_PORT}`,\n EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP: 'true',\n };\n\n this.withEnvironment(environment).withExposedPorts(EVENTSTOREDB_PORT);\n\n if (options.withReuse) this.withReuse();\n\n this.withWaitStrategy(\n Wait.forAll([Wait.forHealthCheck(), Wait.forListeningPorts()]),\n );\n }\n\n async start(): Promise<StartedEventStoreDBContainer> {\n return new StartedEventStoreDBContainer(await super.start());\n }\n}\n\nexport class StartedEventStoreDBContainer extends AbstractStartedContainer {\n constructor(container: StartedTestContainer) {\n super(container);\n }\n\n getConnectionString(): string {\n return `esdb://${this.getHost()}:${this.getMappedPort(2113)}?tls=false`;\n }\n\n getClient(): EventStoreDBClient {\n return EventStoreDBClient.connectionString(this.getConnectionString());\n }\n}\n\nlet container: EventStoreDBContainer | null = null;\nlet startedContainer: StartedEventStoreDBContainer | null = null;\nlet startedCount = 0;\nconst lock = InProcessLock();\n\nexport const getSharedEventStoreDBTestContainer = () =>\n lock.withAcquire(\n async () => {\n if (startedContainer) return startedContainer;\n\n if (!container)\n container = new EventStoreDBContainer(EVENTSTOREDB_DEFAULT_IMAGE);\n\n startedContainer = await container.start();\n startedCount++;\n\n container.withLogConsumer((stream) =>\n stream\n .on('data', (line) => console.log(line))\n .on('err', (line) => console.error(line))\n .on('end', () => console.log('Stream closed')),\n );\n\n return startedContainer;\n },\n { lockId: 'SharedEventStoreDBTestContainer' },\n );\n\nexport const getSharedTestEventStoreDBClient = async () => {\n return (await getSharedEventStoreDBTestContainer()).getClient();\n};\n\nexport const releaseSharedEventStoreDBTestContainer = () =>\n lock.withAcquire(\n async () => {\n const containerToStop = startedContainer;\n if (containerToStop && --startedCount === 0) {\n try {\n startedContainer = null;\n container = null;\n await containerToStop.stop();\n } catch {\n /* do nothing */\n }\n }\n },\n { lockId: 'SharedEventStoreDBTestContainer' },\n );\n"]}
package/dist/index.js CHANGED
@@ -242,12 +242,39 @@ var InProcessLock = () => {
242
242
  }
243
243
  };
244
244
  };
245
+ var ParseError = class extends Error {
246
+ constructor(text) {
247
+ super(`Cannot parse! ${text}`);
248
+ }
249
+ };
250
+ var JSONParser = {
251
+ stringify: (value, options) => {
252
+ return JSON.stringify(
253
+ options?.map ? options.map(value) : value,
254
+ //TODO: Consider adding support to DateTime and adding specific format to mark that's a bigint
255
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
256
+ (_, v) => typeof v === "bigint" ? v.toString() : v
257
+ );
258
+ },
259
+ parse: (text, options) => {
260
+ const parsed = JSON.parse(text, options?.reviver);
261
+ if (options?.typeCheck && !options?.typeCheck(parsed))
262
+ throw new ParseError(text);
263
+ return options?.map ? options.map(parsed) : parsed;
264
+ }
265
+ };
245
266
  var asyncRetry = async (fn, opts) => {
246
267
  if (opts === void 0 || opts.retries === 0) return fn();
247
268
  return retry(
248
269
  async (bail) => {
249
270
  try {
250
- return await fn();
271
+ const result = await fn();
272
+ if (opts?.shouldRetryResult && opts.shouldRetryResult(result)) {
273
+ throw new EmmettError(
274
+ `Retrying because of result: ${JSONParser.stringify(result)}`
275
+ );
276
+ }
277
+ return result;
251
278
  } catch (error2) {
252
279
  if (opts?.shouldRetryError && !opts.shouldRetryError(error2)) {
253
280
  bail(error2);