@event-driven-io/emmett-esdb 0.7.0 → 0.8.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.
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _assert = require('assert'); var _assert2 = _interopRequireDefault(_assert);var f=class g extends Error{constructor(t){let r=t&&typeof t=="object"&&"errorCode"in t?t.errorCode:h(t)?t:500,a=t&&typeof t=="object"&&"message"in t?t.message:T(t)?t:`Error with status code '${r}' ocurred during Emmett processing`;super(a),this.errorCode=r,Object.setPrototypeOf(this,g.prototype)}},S=class v extends f{constructor(t,r,a){super({errorCode:412,message:_nullishCoalesce(a, () => (`Expected version ${r.toString()} does not match current ${_optionalChain([t, 'optionalAccess', _ => _.toString, 'call', _2 => _2()])}`))}),this.current=t,this.expected=r,Object.setPrototypeOf(this,v.prototype)}};var y=(e=>(e.NOT_A_NONEMPTY_STRING="NOT_A_NONEMPTY_STRING",e.NOT_A_POSITIVE_NUMBER="NOT_A_POSITIVE_NUMBER",e.NOT_AN_UNSIGNED_BIGINT="NOT_AN_UNSIGNED_BIGINT",e))(y||{}),h=e=>typeof e=="number"&&e===e,T=e=>typeof e=="string";var p="STREAM_EXISTS",i="STREAM_DOES_NOT_EXIST",o="NO_CONCURRENCY_CHECK";var m=class x extends S{constructor(t,r){super(_optionalChain([t, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]),_optionalChain([r, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()])),Object.setPrototypeOf(this,x.prototype)}};var _crypto = require('crypto');var _dbclient = require('@eventstore/db-client');var O=e=>e?{fromRevision:"from"in e?e.from:void 0,maxCount:"maxCount"in e?e.maxCount:"to"in e?e.to:void 0}:void 0,We= exports.a =e=>({async aggregateStream(t,r){try{let{evolve:a,getInitialState:s,read:n}=r,E=_optionalChain([n, 'optionalAccess', _7 => _7.expectedStreamVersion]),u=s(),c;for await(let{event:d}of e.readStream(t,O(r.read)))d&&(u=a(u,{type:d.type,data:d.data}),c=d.revision);return B(c,E),{currentStreamVersion:_nullishCoalesce(c, () => (0n)),state:u}}catch(a){if(a instanceof _dbclient.StreamNotFoundError)return null;throw a}},readStream:async(t,r)=>{let a=[],s;try{for await(let{event:n}of e.readStream(t,O(r)))n&&(a.push({type:n.type,data:n.data}),s=n.revision);return s?{currentStreamVersion:s,events:a}:null}catch(n){if(n instanceof _dbclient.StreamNotFoundError)return null;throw n}},appendToStream:async(t,r,a)=>{try{let s=r.map(_dbclient.jsonEvent),n=w(_optionalChain([a, 'optionalAccess', _8 => _8.expectedStreamVersion]));return{nextExpectedStreamVersion:(await e.appendToStream(t,s,{expectedRevision:n})).nextExpectedRevision}}catch(s){throw s instanceof _dbclient.WrongExpectedVersionError?new m(s.actualVersion,V(s.expectedVersion)):s}}}),w=e=>e===void 0?_dbclient.ANY:e===o?_dbclient.ANY:e==i?_dbclient.NO_STREAM:e==p?_dbclient.STREAM_EXISTS:e,V=e=>e===void 0?o:e===_dbclient.ANY?o:e==_dbclient.NO_STREAM?i:e==_dbclient.STREAM_EXISTS?p:e,P=(e,t)=>t===o?!0:t==i?e===void 0:t==p?e!==void 0:e===t,B=(e,t)=>{if(t??=o,!P(e,t))throw new m(e,t)};exports.a = We;
2
+ //# sourceMappingURL=chunk-F2TAKPNE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../emmett/src/testing/deciderSpecification.ts","../../emmett/src/errors/index.ts","../../emmett/src/validation/index.ts","../../emmett/src/eventStore/expectedVersion.ts","../../emmett/src/eventStore/inMemoryEventStore.ts","../src/eventStore/eventstoreDBEventStore.ts"],"names":["assert","EmmettError","_EmmettError","options","errorCode","isNumber","message","isString","ConcurrencyError","_ConcurrencyError","current","expected","ValidationErrors","val","STREAM_EXISTS","STREAM_DOES_NOT_EXIST","NO_CONCURRENCY_CHECK","ExpectedVersionConflictError","_ExpectedVersionConflictError","randomUUID","ANY","ESDB_STREAM_EXISTS","NO_STREAM","StreamNotFoundError","WrongExpectedVersionError","jsonEvent","toEventStoreDBReadOptions","getEventStoreDBEventStore","eventStore","streamName","evolve","getInitialState","read","expectedStreamVersion","state","currentStreamVersion","event","assertExpectedVersionMatchesCurrent","error","events","serializedEvents","expectedRevision","toExpectedRevision","t","toExpectedVersion","n","a","s","matchesExpectedVersion"],"mappings":"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","sourcesContent":["import assert from 'assert';\n\nexport type DeciderSpecfication<Command, Event> = (\n givenEvents: Event | Event[],\n) => {\n when: (command: Command) => {\n then: (expectedEvents: Event | Event[]) => void;\n thenThrows: <Error>(assert: (error: Error) => boolean) => void;\n };\n};\n\nexport const DeciderSpecification = {\n for: <Command, Event, State>(decider: {\n decide: (command: Command, state: State) => Event | Event[];\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n }): DeciderSpecfication<Command, Event> => {\n {\n return (givenEvents: Event | Event[]) => {\n return {\n when: (command: Command) => {\n const handle = () => {\n const existingEvents = Array.isArray(givenEvents)\n ? givenEvents\n : [givenEvents];\n\n const currentState = existingEvents.reduce<State>(\n decider.evolve,\n decider.initialState(),\n );\n\n return decider.decide(command, currentState);\n };\n\n return {\n then: (expectedEvents: Event | Event[]): void => {\n const resultEvents = handle();\n\n const resultEventsArray = Array.isArray(resultEvents)\n ? resultEvents\n : [resultEvents];\n\n const expectedEventsArray = Array.isArray(expectedEvents)\n ? expectedEvents\n : [expectedEvents];\n\n assert.deepEqual(resultEventsArray, expectedEventsArray);\n },\n thenThrows: <Error>(check?: (error: Error) => boolean): void => {\n try {\n handle();\n assert.fail('Handler did not fail as expected');\n } catch (error) {\n if (check) assert.ok(check(error as Error));\n }\n },\n };\n },\n };\n };\n }\n },\n};\n","import { isNumber, isString } from '../validation';\n\nexport class EmmettError extends Error {\n public errorCode: number;\n\n constructor(\n options?: { errorCode: number; message?: string } | string | number,\n ) {\n const errorCode =\n options && typeof options === 'object' && 'errorCode' in options\n ? options.errorCode\n : isNumber(options)\n ? options\n : 500;\n const message =\n options && typeof options === 'object' && 'message' in options\n ? options.message\n : isString(options)\n ? options\n : `Error with status code '${errorCode}' ocurred during Emmett processing`;\n\n super(message);\n this.errorCode = errorCode;\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, EmmettError.prototype);\n }\n}\n\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: 412,\n message:\n message ??\n `Expected version ${expected.toString()} does not match current ${current?.toString()}`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 400,\n message: message ?? `Validation Error ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class IllegalStateError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 403,\n message: message ?? `Illegal State ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, IllegalStateError.prototype);\n }\n}\n\nexport class NotFoundError extends EmmettError {\n constructor(options?: { id: string; type: string; message?: string }) {\n super({\n errorCode: 404,\n message:\n options?.message ??\n (options?.id\n ? options.type\n ? `${options.type} with ${options.id} was not found during Emmett processing`\n : `State with ${options.id} was not found during Emmett processing`\n : options?.type\n ? `${options.type} was not found during Emmett processing`\n : 'State was not found during Emmett processing'),\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n","import { 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","import { ConcurrencyError } from '../errors';\nimport type { Flavour } from '../typing';\nimport type { DefaultStreamVersionType } from './eventStore';\n\nexport type ExpectedStreamVersion<VersionType = DefaultStreamVersionType> =\n | ExpectedStreamVersionWithValue<VersionType>\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue<\n VersionType = DefaultStreamVersionType,\n> = Flavour<VersionType, 'StreamVersion'>;\n\nexport type ExpectedStreamVersionGeneral = Flavour<\n 'STREAM_EXISTS' | 'STREAM_DOES_NOT_EXIST' | 'NO_CONCURRENCY_CHECK',\n 'StreamVersion'\n>;\n\nexport const STREAM_EXISTS = 'STREAM_EXISTS' as ExpectedStreamVersionGeneral;\nexport const STREAM_DOES_NOT_EXIST =\n 'STREAM_DOES_NOT_EXIST' as ExpectedStreamVersionGeneral;\nexport const NO_CONCURRENCY_CHECK =\n 'NO_CONCURRENCY_CHECK' as ExpectedStreamVersionGeneral;\n\nexport const matchesExpectedVersion = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion>,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nexport const assertExpectedVersionMatchesCurrent = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion> | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n\nexport class ExpectedVersionConflictError<\n VersionType = DefaultStreamVersionType,\n> extends ConcurrencyError {\n constructor(\n current: VersionType | undefined,\n expected: ExpectedStreamVersion<VersionType>,\n ) {\n super(current?.toString(), expected?.toString());\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);\n }\n}\n","import { randomUUID } from 'crypto';\nimport type { Event } from '../typing';\nimport {\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type EventStore,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\n\nexport type EventMetadata = Readonly<{\n eventId: string;\n streamPosition: number;\n logPosition: bigint;\n}>;\n\nexport type EventEnvelope<E extends Event = Event> = {\n event: E;\n metadata: EventMetadata;\n};\n\nexport type EventHandler<E extends Event = Event> = (\n eventEnvelope: EventEnvelope<E>,\n) => void;\n\nexport const getInMemoryEventStore = (): EventStore => {\n const streams = new Map<string, EventEnvelope[]>();\n\n const getAllEventsCount = () => {\n return Array.from<EventEnvelope[]>(streams.values())\n .map((s) => s.length)\n .reduce((p, c) => p + c, 0);\n };\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, getInitialState, read } = options;\n\n const result = await this.readStream<EventType>(streamName, read);\n\n if (!result) return null;\n\n const events = result?.events ?? [];\n\n return {\n currentStreamVersion: BigInt(events.length),\n state: events.reduce(evolve, getInitialState()),\n };\n },\n\n readStream: <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<ReadStreamResult<EventType>> => {\n const events = streams.get(streamName);\n const currentStreamVersion = events ? BigInt(events.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\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 && events.length > 0\n ? events.map((e) => e.event as EventType).slice(from, to)\n : [];\n\n const result: ReadStreamResult<EventType> =\n events && events.length > 0\n ? {\n currentStreamVersion: currentStreamVersion!,\n events: resultEvents,\n }\n : null;\n\n return Promise.resolve(result);\n },\n\n appendToStream: <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 ? BigInt(currentEvents.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const eventEnvelopes: EventEnvelope[] = events.map((event, index) => {\n return {\n event,\n metadata: {\n eventId: randomUUID(),\n streamPosition: currentEvents.length + index + 1,\n logPosition: BigInt(getAllEventsCount() + index + 1),\n },\n };\n });\n\n const positionOfLastEventInTheStream = BigInt(\n eventEnvelopes.slice(-1)[0]!.metadata.streamPosition,\n );\n\n streams.set(streamName, [...currentEvents, ...eventEnvelopes]);\n\n const result: AppendToStreamResult = {\n nextExpectedStreamVersion: positionOfLastEventInTheStream,\n };\n\n return Promise.resolve(result);\n },\n };\n};\n","import {\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type Event,\n type EventStore,\n type ExpectedStreamVersion,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport {\n ANY,\n STREAM_EXISTS as ESDB_STREAM_EXISTS,\n EventStoreDBClient,\n NO_STREAM,\n StreamNotFoundError,\n WrongExpectedVersionError,\n jsonEvent,\n type AppendExpectedRevision,\n type ReadStreamOptions as ESDBReadStreamOptions,\n} from '@eventstore/db-client';\n\nconst toEventStoreDBReadOptions = (\n options: ReadStreamOptions | undefined,\n): ESDBReadStreamOptions | undefined => {\n return options\n ? {\n fromRevision: 'from' in options ? options.from : undefined,\n maxCount:\n 'maxCount' in options\n ? options.maxCount\n : 'to' in options\n ? options.to\n : undefined,\n }\n : undefined;\n};\n\nexport const getEventStoreDBEventStore = (\n eventStore: EventStoreDBClient,\n): EventStore => {\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n try {\n const { evolve, getInitialState, read } = options;\n\n const expectedStreamVersion = read?.expectedStreamVersion;\n\n let state = getInitialState();\n let currentStreamVersion: bigint | undefined = undefined;\n\n for await (const { event } of eventStore.readStream(\n streamName,\n toEventStoreDBReadOptions(options.read),\n )) {\n if (!event) continue;\n\n state = evolve(state, <EventType>{\n type: event.type,\n data: event.data,\n });\n currentStreamVersion = event.revision;\n }\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n );\n\n return {\n currentStreamVersion: currentStreamVersion ?? 0n,\n state,\n };\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return null;\n }\n\n throw error;\n }\n },\n\n readStream: async <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<ReadStreamResult<EventType>> => {\n const events: EventType[] = [];\n\n let currentStreamVersion: bigint | undefined = undefined;\n\n try {\n for await (const { event } of eventStore.readStream(\n streamName,\n toEventStoreDBReadOptions(options),\n )) {\n if (!event) continue;\n events.push(<EventType>{\n type: event.type,\n data: event.data,\n });\n currentStreamVersion = event.revision;\n }\n return currentStreamVersion\n ? {\n currentStreamVersion,\n events,\n }\n : null;\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return null;\n }\n\n throw error;\n }\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> => {\n try {\n const serializedEvents = events.map(jsonEvent);\n\n const expectedRevision = toExpectedRevision(\n options?.expectedStreamVersion,\n );\n\n const appendResult = await eventStore.appendToStream(\n streamName,\n serializedEvents,\n {\n expectedRevision,\n },\n );\n\n return { nextExpectedStreamVersion: appendResult.nextExpectedRevision };\n } catch (error) {\n if (error instanceof WrongExpectedVersionError) {\n throw new ExpectedVersionConflictError(\n error.actualVersion,\n toExpectedVersion(error.expectedVersion),\n );\n }\n\n throw error;\n }\n },\n };\n};\n\nconst toExpectedRevision = (\n expected: ExpectedStreamVersion | undefined,\n): AppendExpectedRevision => {\n if (expected === undefined) return ANY;\n\n if (expected === NO_CONCURRENCY_CHECK) return ANY;\n\n if (expected == STREAM_DOES_NOT_EXIST) return NO_STREAM;\n\n if (expected == STREAM_EXISTS) return ESDB_STREAM_EXISTS;\n\n return expected as bigint;\n};\n\nconst toExpectedVersion = (\n expected: AppendExpectedRevision | undefined,\n): ExpectedStreamVersion => {\n if (expected === undefined) return NO_CONCURRENCY_CHECK;\n\n if (expected === ANY) return NO_CONCURRENCY_CHECK;\n\n if (expected == NO_STREAM) return STREAM_DOES_NOT_EXIST;\n\n if (expected == ESDB_STREAM_EXISTS) return STREAM_EXISTS;\n\n return expected;\n};\n\nconst matchesExpectedVersion = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nconst assertExpectedVersionMatchesCurrent = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n"]}
@@ -0,0 +1,2 @@
1
+ import $ from"assert";var f=class g extends Error{errorCode;constructor(t){let r=t&&typeof t=="object"&&"errorCode"in t?t.errorCode:h(t)?t:500,a=t&&typeof t=="object"&&"message"in t?t.message:T(t)?t:`Error with status code '${r}' ocurred during Emmett processing`;super(a),this.errorCode=r,Object.setPrototypeOf(this,g.prototype)}},S=class v extends f{constructor(t,r,a){super({errorCode:412,message:a??`Expected version ${r.toString()} does not match current ${t?.toString()}`}),this.current=t,this.expected=r,Object.setPrototypeOf(this,v.prototype)}};var y=(e=>(e.NOT_A_NONEMPTY_STRING="NOT_A_NONEMPTY_STRING",e.NOT_A_POSITIVE_NUMBER="NOT_A_POSITIVE_NUMBER",e.NOT_AN_UNSIGNED_BIGINT="NOT_AN_UNSIGNED_BIGINT",e))(y||{}),h=e=>typeof e=="number"&&e===e,T=e=>typeof e=="string";var p="STREAM_EXISTS",i="STREAM_DOES_NOT_EXIST",o="NO_CONCURRENCY_CHECK";var m=class x extends S{constructor(t,r){super(t?.toString(),r?.toString()),Object.setPrototypeOf(this,x.prototype)}};import{randomUUID as re}from"crypto";import{ANY as l,STREAM_EXISTS as I,NO_STREAM as A,StreamNotFoundError as N,WrongExpectedVersionError as C,jsonEvent as b}from"@eventstore/db-client";var O=e=>e?{fromRevision:"from"in e?e.from:void 0,maxCount:"maxCount"in e?e.maxCount:"to"in e?e.to:void 0}:void 0,We=e=>({async aggregateStream(t,r){try{let{evolve:a,getInitialState:s,read:n}=r,E=n?.expectedStreamVersion,u=s(),c;for await(let{event:d}of e.readStream(t,O(r.read)))d&&(u=a(u,{type:d.type,data:d.data}),c=d.revision);return B(c,E),{currentStreamVersion:c??0n,state:u}}catch(a){if(a instanceof N)return null;throw a}},readStream:async(t,r)=>{let a=[],s;try{for await(let{event:n}of e.readStream(t,O(r)))n&&(a.push({type:n.type,data:n.data}),s=n.revision);return s?{currentStreamVersion:s,events:a}:null}catch(n){if(n instanceof N)return null;throw n}},appendToStream:async(t,r,a)=>{try{let s=r.map(b),n=w(a?.expectedStreamVersion);return{nextExpectedStreamVersion:(await e.appendToStream(t,s,{expectedRevision:n})).nextExpectedRevision}}catch(s){throw s instanceof C?new m(s.actualVersion,V(s.expectedVersion)):s}}}),w=e=>e===void 0?l:e===o?l:e==i?A:e==p?I:e,V=e=>e===void 0?o:e===l?o:e==A?i:e==I?p:e,P=(e,t)=>t===o?!0:t==i?e===void 0:t==p?e!==void 0:e===t,B=(e,t)=>{if(t??=o,!P(e,t))throw new m(e,t)};export{We as a};
2
+ //# sourceMappingURL=chunk-GL57PH3D.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../emmett/src/testing/deciderSpecification.ts","../../emmett/src/errors/index.ts","../../emmett/src/validation/index.ts","../../emmett/src/eventStore/expectedVersion.ts","../../emmett/src/eventStore/inMemoryEventStore.ts","../src/eventStore/eventstoreDBEventStore.ts"],"sourcesContent":["import assert from 'assert';\n\nexport type DeciderSpecfication<Command, Event> = (\n givenEvents: Event | Event[],\n) => {\n when: (command: Command) => {\n then: (expectedEvents: Event | Event[]) => void;\n thenThrows: <Error>(assert: (error: Error) => boolean) => void;\n };\n};\n\nexport const DeciderSpecification = {\n for: <Command, Event, State>(decider: {\n decide: (command: Command, state: State) => Event | Event[];\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n }): DeciderSpecfication<Command, Event> => {\n {\n return (givenEvents: Event | Event[]) => {\n return {\n when: (command: Command) => {\n const handle = () => {\n const existingEvents = Array.isArray(givenEvents)\n ? givenEvents\n : [givenEvents];\n\n const currentState = existingEvents.reduce<State>(\n decider.evolve,\n decider.initialState(),\n );\n\n return decider.decide(command, currentState);\n };\n\n return {\n then: (expectedEvents: Event | Event[]): void => {\n const resultEvents = handle();\n\n const resultEventsArray = Array.isArray(resultEvents)\n ? resultEvents\n : [resultEvents];\n\n const expectedEventsArray = Array.isArray(expectedEvents)\n ? expectedEvents\n : [expectedEvents];\n\n assert.deepEqual(resultEventsArray, expectedEventsArray);\n },\n thenThrows: <Error>(check?: (error: Error) => boolean): void => {\n try {\n handle();\n assert.fail('Handler did not fail as expected');\n } catch (error) {\n if (check) assert.ok(check(error as Error));\n }\n },\n };\n },\n };\n };\n }\n },\n};\n","import { isNumber, isString } from '../validation';\n\nexport class EmmettError extends Error {\n public errorCode: number;\n\n constructor(\n options?: { errorCode: number; message?: string } | string | number,\n ) {\n const errorCode =\n options && typeof options === 'object' && 'errorCode' in options\n ? options.errorCode\n : isNumber(options)\n ? options\n : 500;\n const message =\n options && typeof options === 'object' && 'message' in options\n ? options.message\n : isString(options)\n ? options\n : `Error with status code '${errorCode}' ocurred during Emmett processing`;\n\n super(message);\n this.errorCode = errorCode;\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, EmmettError.prototype);\n }\n}\n\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: 412,\n message:\n message ??\n `Expected version ${expected.toString()} does not match current ${current?.toString()}`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 400,\n message: message ?? `Validation Error ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class IllegalStateError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 403,\n message: message ?? `Illegal State ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, IllegalStateError.prototype);\n }\n}\n\nexport class NotFoundError extends EmmettError {\n constructor(options?: { id: string; type: string; message?: string }) {\n super({\n errorCode: 404,\n message:\n options?.message ??\n (options?.id\n ? options.type\n ? `${options.type} with ${options.id} was not found during Emmett processing`\n : `State with ${options.id} was not found during Emmett processing`\n : options?.type\n ? `${options.type} was not found during Emmett processing`\n : 'State was not found during Emmett processing'),\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n","import { 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","import { ConcurrencyError } from '../errors';\nimport type { Flavour } from '../typing';\nimport type { DefaultStreamVersionType } from './eventStore';\n\nexport type ExpectedStreamVersion<VersionType = DefaultStreamVersionType> =\n | ExpectedStreamVersionWithValue<VersionType>\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue<\n VersionType = DefaultStreamVersionType,\n> = Flavour<VersionType, 'StreamVersion'>;\n\nexport type ExpectedStreamVersionGeneral = Flavour<\n 'STREAM_EXISTS' | 'STREAM_DOES_NOT_EXIST' | 'NO_CONCURRENCY_CHECK',\n 'StreamVersion'\n>;\n\nexport const STREAM_EXISTS = 'STREAM_EXISTS' as ExpectedStreamVersionGeneral;\nexport const STREAM_DOES_NOT_EXIST =\n 'STREAM_DOES_NOT_EXIST' as ExpectedStreamVersionGeneral;\nexport const NO_CONCURRENCY_CHECK =\n 'NO_CONCURRENCY_CHECK' as ExpectedStreamVersionGeneral;\n\nexport const matchesExpectedVersion = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion>,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nexport const assertExpectedVersionMatchesCurrent = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion> | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n\nexport class ExpectedVersionConflictError<\n VersionType = DefaultStreamVersionType,\n> extends ConcurrencyError {\n constructor(\n current: VersionType | undefined,\n expected: ExpectedStreamVersion<VersionType>,\n ) {\n super(current?.toString(), expected?.toString());\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);\n }\n}\n","import { randomUUID } from 'crypto';\nimport type { Event } from '../typing';\nimport {\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type EventStore,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\n\nexport type EventMetadata = Readonly<{\n eventId: string;\n streamPosition: number;\n logPosition: bigint;\n}>;\n\nexport type EventEnvelope<E extends Event = Event> = {\n event: E;\n metadata: EventMetadata;\n};\n\nexport type EventHandler<E extends Event = Event> = (\n eventEnvelope: EventEnvelope<E>,\n) => void;\n\nexport const getInMemoryEventStore = (): EventStore => {\n const streams = new Map<string, EventEnvelope[]>();\n\n const getAllEventsCount = () => {\n return Array.from<EventEnvelope[]>(streams.values())\n .map((s) => s.length)\n .reduce((p, c) => p + c, 0);\n };\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, getInitialState, read } = options;\n\n const result = await this.readStream<EventType>(streamName, read);\n\n if (!result) return null;\n\n const events = result?.events ?? [];\n\n return {\n currentStreamVersion: BigInt(events.length),\n state: events.reduce(evolve, getInitialState()),\n };\n },\n\n readStream: <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<ReadStreamResult<EventType>> => {\n const events = streams.get(streamName);\n const currentStreamVersion = events ? BigInt(events.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\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 && events.length > 0\n ? events.map((e) => e.event as EventType).slice(from, to)\n : [];\n\n const result: ReadStreamResult<EventType> =\n events && events.length > 0\n ? {\n currentStreamVersion: currentStreamVersion!,\n events: resultEvents,\n }\n : null;\n\n return Promise.resolve(result);\n },\n\n appendToStream: <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 ? BigInt(currentEvents.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const eventEnvelopes: EventEnvelope[] = events.map((event, index) => {\n return {\n event,\n metadata: {\n eventId: randomUUID(),\n streamPosition: currentEvents.length + index + 1,\n logPosition: BigInt(getAllEventsCount() + index + 1),\n },\n };\n });\n\n const positionOfLastEventInTheStream = BigInt(\n eventEnvelopes.slice(-1)[0]!.metadata.streamPosition,\n );\n\n streams.set(streamName, [...currentEvents, ...eventEnvelopes]);\n\n const result: AppendToStreamResult = {\n nextExpectedStreamVersion: positionOfLastEventInTheStream,\n };\n\n return Promise.resolve(result);\n },\n };\n};\n","import {\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type Event,\n type EventStore,\n type ExpectedStreamVersion,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport {\n ANY,\n STREAM_EXISTS as ESDB_STREAM_EXISTS,\n EventStoreDBClient,\n NO_STREAM,\n StreamNotFoundError,\n WrongExpectedVersionError,\n jsonEvent,\n type AppendExpectedRevision,\n type ReadStreamOptions as ESDBReadStreamOptions,\n} from '@eventstore/db-client';\n\nconst toEventStoreDBReadOptions = (\n options: ReadStreamOptions | undefined,\n): ESDBReadStreamOptions | undefined => {\n return options\n ? {\n fromRevision: 'from' in options ? options.from : undefined,\n maxCount:\n 'maxCount' in options\n ? options.maxCount\n : 'to' in options\n ? options.to\n : undefined,\n }\n : undefined;\n};\n\nexport const getEventStoreDBEventStore = (\n eventStore: EventStoreDBClient,\n): EventStore => {\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n try {\n const { evolve, getInitialState, read } = options;\n\n const expectedStreamVersion = read?.expectedStreamVersion;\n\n let state = getInitialState();\n let currentStreamVersion: bigint | undefined = undefined;\n\n for await (const { event } of eventStore.readStream(\n streamName,\n toEventStoreDBReadOptions(options.read),\n )) {\n if (!event) continue;\n\n state = evolve(state, <EventType>{\n type: event.type,\n data: event.data,\n });\n currentStreamVersion = event.revision;\n }\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n );\n\n return {\n currentStreamVersion: currentStreamVersion ?? 0n,\n state,\n };\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return null;\n }\n\n throw error;\n }\n },\n\n readStream: async <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<ReadStreamResult<EventType>> => {\n const events: EventType[] = [];\n\n let currentStreamVersion: bigint | undefined = undefined;\n\n try {\n for await (const { event } of eventStore.readStream(\n streamName,\n toEventStoreDBReadOptions(options),\n )) {\n if (!event) continue;\n events.push(<EventType>{\n type: event.type,\n data: event.data,\n });\n currentStreamVersion = event.revision;\n }\n return currentStreamVersion\n ? {\n currentStreamVersion,\n events,\n }\n : null;\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return null;\n }\n\n throw error;\n }\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> => {\n try {\n const serializedEvents = events.map(jsonEvent);\n\n const expectedRevision = toExpectedRevision(\n options?.expectedStreamVersion,\n );\n\n const appendResult = await eventStore.appendToStream(\n streamName,\n serializedEvents,\n {\n expectedRevision,\n },\n );\n\n return { nextExpectedStreamVersion: appendResult.nextExpectedRevision };\n } catch (error) {\n if (error instanceof WrongExpectedVersionError) {\n throw new ExpectedVersionConflictError(\n error.actualVersion,\n toExpectedVersion(error.expectedVersion),\n );\n }\n\n throw error;\n }\n },\n };\n};\n\nconst toExpectedRevision = (\n expected: ExpectedStreamVersion | undefined,\n): AppendExpectedRevision => {\n if (expected === undefined) return ANY;\n\n if (expected === NO_CONCURRENCY_CHECK) return ANY;\n\n if (expected == STREAM_DOES_NOT_EXIST) return NO_STREAM;\n\n if (expected == STREAM_EXISTS) return ESDB_STREAM_EXISTS;\n\n return expected as bigint;\n};\n\nconst toExpectedVersion = (\n expected: AppendExpectedRevision | undefined,\n): ExpectedStreamVersion => {\n if (expected === undefined) return NO_CONCURRENCY_CHECK;\n\n if (expected === ANY) return NO_CONCURRENCY_CHECK;\n\n if (expected == NO_STREAM) return STREAM_DOES_NOT_EXIST;\n\n if (expected == ESDB_STREAM_EXISTS) return STREAM_EXISTS;\n\n return expected;\n};\n\nconst matchesExpectedVersion = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nconst assertExpectedVersionMatchesCurrent = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n"],"mappings":"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","names":["assert","EmmettError","_EmmettError","options","errorCode","isNumber","message","isString","ConcurrencyError","_ConcurrencyError","current","expected","ValidationErrors","isNumber","val","isString","STREAM_EXISTS","STREAM_DOES_NOT_EXIST","NO_CONCURRENCY_CHECK","ExpectedVersionConflictError","_ExpectedVersionConflictError","ConcurrencyError","current","expected","randomUUID","ANY","ESDB_STREAM_EXISTS","NO_STREAM","StreamNotFoundError","WrongExpectedVersionError","jsonEvent","toEventStoreDBReadOptions","options","getEventStoreDBEventStore","eventStore","streamName","evolve","getInitialState","read","expectedStreamVersion","state","currentStreamVersion","event","assertExpectedVersionMatchesCurrent","error","events","serializedEvents","expectedRevision","toExpectedRevision","t","toExpectedVersion","expected","n","a","s","matchesExpectedVersion","current"]}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkMDCGSRTIjs = require('../chunk-MDCGSRTI.js');exports.getEventStoreDBEventStore = _chunkMDCGSRTIjs.a;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkF2TAKPNEjs = require('../chunk-F2TAKPNE.js');exports.getEventStoreDBEventStore = _chunkF2TAKPNEjs.a;
2
2
  //# sourceMappingURL=eventstoreDBEventStore.js.map
@@ -1,2 +1,2 @@
1
- import{a}from"../chunk-PF2HTK3Z.mjs";export{a as getEventStoreDBEventStore};
1
+ import{a}from"../chunk-GL57PH3D.mjs";export{a as getEventStoreDBEventStore};
2
2
  //# sourceMappingURL=eventstoreDBEventStore.mjs.map
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});require('../chunk-UXBL2ICC.js');var _chunkMDCGSRTIjs = require('../chunk-MDCGSRTI.js');exports.getEventStoreDBEventStore = _chunkMDCGSRTIjs.a;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});require('../chunk-UXBL2ICC.js');var _chunkF2TAKPNEjs = require('../chunk-F2TAKPNE.js');exports.getEventStoreDBEventStore = _chunkF2TAKPNEjs.a;
2
2
  //# sourceMappingURL=index.js.map
@@ -1,2 +1,2 @@
1
- import"../chunk-K54GVY42.mjs";import{a}from"../chunk-PF2HTK3Z.mjs";export{a as getEventStoreDBEventStore};
1
+ import"../chunk-K54GVY42.mjs";import{a}from"../chunk-GL57PH3D.mjs";export{a as getEventStoreDBEventStore};
2
2
  //# sourceMappingURL=index.mjs.map
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});require('./chunk-UXBL2ICC.js');var _chunkMDCGSRTIjs = require('./chunk-MDCGSRTI.js');exports.getEventStoreDBEventStore = _chunkMDCGSRTIjs.a;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});require('./chunk-UXBL2ICC.js');var _chunkF2TAKPNEjs = require('./chunk-F2TAKPNE.js');exports.getEventStoreDBEventStore = _chunkF2TAKPNEjs.a;
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import"./chunk-K54GVY42.mjs";import{a as o}from"./chunk-PF2HTK3Z.mjs";export{o as getEventStoreDBEventStore};
1
+ import"./chunk-K54GVY42.mjs";import{a as o}from"./chunk-GL57PH3D.mjs";export{o as getEventStoreDBEventStore};
2
2
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@event-driven-io/emmett-esdb",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Emmett - EventStoreDB - Event Sourcing development made simple",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -50,7 +50,7 @@
50
50
  "@event-driven-io/emmett-testcontainers": "^0.5.0"
51
51
  },
52
52
  "peerDependencies": {
53
- "@event-driven-io/emmett": "0.7.0",
53
+ "@event-driven-io/emmett": "0.8.0",
54
54
  "@eventstore/db-client": "^6.1.0"
55
55
  }
56
56
  }
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _assert = require('assert'); var _assert2 = _interopRequireDefault(_assert);var _crypto = require('crypto');var _test = require('test');var f=class E extends Error{constructor(t){let r=t&&typeof t=="object"&&"errorCode"in t?t.errorCode:I(t)?t:500,a=t&&typeof t=="object"&&"message"in t?t.message:h(t)?t:`Error with status code '${r}' ocurred during Emmett processing`;super(a),this.errorCode=r,Object.setPrototypeOf(this,E.prototype)}},l=class v extends f{constructor(t,r,a){super({errorCode:412,message:_nullishCoalesce(a, () => (`Expected version ${r.toString()} does not match current ${_optionalChain([t, 'optionalAccess', _ => _.toString, 'call', _2 => _2()])}`))}),this.current=t,this.expected=r,Object.setPrototypeOf(this,v.prototype)}};var y=(e=>(e.NOT_A_NONEMPTY_STRING="NOT_A_NONEMPTY_STRING",e.NOT_A_POSITIVE_NUMBER="NOT_A_POSITIVE_NUMBER",e.NOT_AN_UNSIGNED_BIGINT="NOT_AN_UNSIGNED_BIGINT",e))(y||{}),I=e=>typeof e=="number"&&e===e,h=e=>typeof e=="string";var d="STREAM_EXISTS",i="STREAM_DOES_NOT_EXIST",o="NO_CONCURRENCY_CHECK";var m=class x extends l{constructor(t,r){super(_optionalChain([t, 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]),_optionalChain([r, 'optionalAccess', _5 => _5.toString, 'call', _6 => _6()])),Object.setPrototypeOf(this,x.prototype)}};var _dbclient = require('@eventstore/db-client');var N=e=>e?{fromRevision:"from"in e?e.from:void 0,maxCount:"maxCount"in e?e.maxCount:"to"in e?e.to:void 0}:void 0,mt= exports.a =e=>({async aggregateStream(t,r){try{let{evolve:a,getInitialState:s,read:n}=r,g=_optionalChain([n, 'optionalAccess', _7 => _7.expectedStreamVersion]),u=s(),c;for await(let{event:p}of e.readStream(t,N(r.read)))p&&(u=a(u,{type:p.type,data:p.data}),c=p.revision);return D(c,g),{currentStreamVersion:_nullishCoalesce(c, () => (0n)),state:u}}catch(a){if(a instanceof _dbclient.StreamNotFoundError)return null;throw a}},readStream:async(t,r)=>{let a=[],s;try{for await(let{event:n}of e.readStream(t,N(r)))n&&(a.push({type:n.type,data:n.data}),s=n.revision);return s?{currentStreamVersion:s,events:a}:null}catch(n){if(n instanceof _dbclient.StreamNotFoundError)return null;throw n}},appendToStream:async(t,r,a)=>{try{let s=r.map(_dbclient.jsonEvent),n=P(_optionalChain([a, 'optionalAccess', _8 => _8.expectedStreamVersion]));return{nextExpectedStreamVersion:(await e.appendToStream(t,s,{expectedRevision:n})).nextExpectedRevision}}catch(s){throw s instanceof _dbclient.WrongExpectedVersionError?new m(s.actualVersion,B(s.expectedVersion)):s}}}),P=e=>e===void 0?_dbclient.ANY:e===o?_dbclient.ANY:e==i?_dbclient.NO_STREAM:e==d?_dbclient.STREAM_EXISTS:e,B=e=>e===void 0?o:e===_dbclient.ANY?o:e==_dbclient.NO_STREAM?i:e==_dbclient.STREAM_EXISTS?d:e,M=(e,t)=>t===o?!0:t==i?e===void 0:t==d?e!==void 0:e===t,D=(e,t)=>{if(t??=o,!M(e,t))throw new m(e,t)};exports.a = mt;
2
- //# sourceMappingURL=chunk-MDCGSRTI.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../emmett/src/testing/deciderSpecification.ts","../../emmett/src/testing/features.ts","../../emmett/src/errors/index.ts","../../emmett/src/validation/index.ts","../../emmett/src/eventStore/expectedVersion.ts","../../emmett/src/eventStore/inMemoryEventStore.ts","../src/eventStore/eventstoreDBEventStore.ts"],"names":["assert","randomUUID","after","before","describe","it","EmmettError","_EmmettError","options","errorCode","isNumber","message","isString","ConcurrencyError","_ConcurrencyError","current","expected","ValidationErrors","val","STREAM_EXISTS","STREAM_DOES_NOT_EXIST","NO_CONCURRENCY_CHECK","ExpectedVersionConflictError","_ExpectedVersionConflictError","ANY","ESDB_STREAM_EXISTS","NO_STREAM","StreamNotFoundError","WrongExpectedVersionError","jsonEvent","toEventStoreDBReadOptions","getEventStoreDBEventStore","eventStore","streamName","evolve","getInitialState","read","expectedStreamVersion","state","currentStreamVersion","event","assertExpectedVersionMatchesCurrent","error","events","serializedEvents","expectedRevision","toExpectedRevision","t","toExpectedVersion","n","a","s","matchesExpectedVersion"],"mappings":"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","sourcesContent":["import assert from 'assert';\n\nexport type DeciderSpecfication<Command, Event> = (\n givenEvents: Event | Event[],\n) => {\n when: (command: Command) => {\n then: (expectedEvents: Event | Event[]) => void;\n thenThrows: <Error>(assert: (error: Error) => boolean) => void;\n };\n};\n\nexport const DeciderSpecification = {\n for: <Command, Event, State>(decider: {\n decide: (command: Command, state: State) => Event | Event[];\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n }): DeciderSpecfication<Command, Event> => {\n {\n return (givenEvents: Event | Event[]) => {\n return {\n when: (command: Command) => {\n const handle = () => {\n const existingEvents = Array.isArray(givenEvents)\n ? givenEvents\n : [givenEvents];\n\n const currentState = existingEvents.reduce<State>(\n decider.evolve,\n decider.initialState(),\n );\n\n return decider.decide(command, currentState);\n };\n\n return {\n then: (expectedEvents: Event | Event[]): void => {\n const resultEvents = handle();\n\n const resultEventsArray = Array.isArray(resultEvents)\n ? resultEvents\n : [resultEvents];\n\n const expectedEventsArray = Array.isArray(expectedEvents)\n ? expectedEvents\n : [expectedEvents];\n\n assert.deepEqual(resultEventsArray, expectedEventsArray);\n },\n thenThrows: <Error>(check?: (error: Error) => boolean): void => {\n try {\n handle();\n assert.fail('Handler did not fail as expected');\n } catch (error) {\n if (check) assert.ok(check(error as Error));\n }\n },\n };\n },\n };\n };\n }\n },\n};\n","/* eslint-disable @typescript-eslint/no-floating-promises */\nimport assert from 'node:assert';\nimport { randomUUID } from 'node:crypto';\nimport { after, before, describe, it } from 'node:test';\nimport type { EventStore } from '../eventStore';\nimport {\n evolve,\n getInitialState,\n type PricedProductItem,\n type ShoppingCartEvent,\n} from './shoppingCart.domain';\n\ntype TestOptions = {\n getInitialIndex: () => bigint;\n teardownHook?: () => Promise<void>;\n};\n\nexport type EventStoreFactory = () => Promise<EventStore<bigint>>;\n\nexport async function testAggregateStream(\n eventStoreFactory: EventStoreFactory,\n options: TestOptions = {\n getInitialIndex: () => 1n,\n },\n) {\n return describe('aggregateStream', () => {\n let eventStore: EventStore<bigint>;\n\n before(async () => {\n eventStore = await eventStoreFactory();\n });\n\n after(async () => {\n const teardownHook = options.teardownHook;\n if (teardownHook) await teardownHook();\n });\n\n it('When called with `to` allows time traveling', async () => {\n // Given\n const productItem: PricedProductItem = {\n productId: '123',\n quantity: 10,\n price: 3,\n };\n const discount = 10;\n const shoppingCartId = randomUUID();\n\n await eventStore.appendToStream<ShoppingCartEvent>(shoppingCartId, [\n { type: 'ProductItemAdded', data: { productItem } },\n ]);\n await eventStore.appendToStream<ShoppingCartEvent>(shoppingCartId, [\n { type: 'ProductItemAdded', data: { productItem } },\n ]);\n await eventStore.appendToStream<ShoppingCartEvent>(shoppingCartId, [\n { type: 'DiscountApplied', data: { percent: discount } },\n ]);\n\n // when\n const resultAt1 = await eventStore.aggregateStream(shoppingCartId, {\n evolve,\n getInitialState,\n read: { to: 1n },\n });\n const resultAt2 = await eventStore.aggregateStream(shoppingCartId, {\n evolve,\n getInitialState,\n read: { to: 2n },\n });\n const resultAt3 = await eventStore.aggregateStream(shoppingCartId, {\n evolve,\n getInitialState,\n read: { to: 3n },\n });\n\n // then\n assert.ok(resultAt1);\n assert.ok(resultAt2);\n assert.ok(resultAt3);\n\n assert.equal(resultAt1.currentStreamVersion, options.getInitialIndex());\n assert.deepEqual(resultAt1.state, {\n productItems: [productItem],\n totalAmount: 30,\n });\n\n assert.equal(\n resultAt2.currentStreamVersion,\n options.getInitialIndex() + 1n,\n );\n assert.deepEqual(resultAt2.state, {\n productItems: [productItem, productItem],\n totalAmount: 60,\n });\n\n assert.equal(\n resultAt3.currentStreamVersion,\n options.getInitialIndex() + 2n,\n );\n assert.deepEqual(resultAt3.state, {\n productItems: [productItem, productItem],\n totalAmount: 54,\n });\n });\n });\n}\n","import { isNumber, isString } from '../validation';\n\nexport class EmmettError extends Error {\n public errorCode: number;\n\n constructor(\n options?: { errorCode: number; message?: string } | string | number,\n ) {\n const errorCode =\n options && typeof options === 'object' && 'errorCode' in options\n ? options.errorCode\n : isNumber(options)\n ? options\n : 500;\n const message =\n options && typeof options === 'object' && 'message' in options\n ? options.message\n : isString(options)\n ? options\n : `Error with status code '${errorCode}' ocurred during Emmett processing`;\n\n super(message);\n this.errorCode = errorCode;\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, EmmettError.prototype);\n }\n}\n\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: 412,\n message:\n message ??\n `Expected version ${expected.toString()} does not match current ${current?.toString()}`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 400,\n message: message ?? `Validation Error ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class IllegalStateError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 403,\n message: message ?? `Illegal State ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, IllegalStateError.prototype);\n }\n}\n\nexport class NotFoundError extends EmmettError {\n constructor(options?: { id: string; type: string; message?: string }) {\n super({\n errorCode: 404,\n message:\n options?.message ??\n (options?.id\n ? options.type\n ? `${options.type} with ${options.id} was not found during Emmett processing`\n : `State with ${options.id} was not found during Emmett processing`\n : options?.type\n ? `${options.type} was not found during Emmett processing`\n : 'State was not found during Emmett processing'),\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n","import { 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","import { ConcurrencyError } from '../errors';\nimport type { Flavour } from '../typing';\nimport type { DefaultStreamVersionType } from './eventStore';\n\nexport type ExpectedStreamVersion<VersionType = DefaultStreamVersionType> =\n | ExpectedStreamVersionWithValue<VersionType>\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue<\n VersionType = DefaultStreamVersionType,\n> = Flavour<VersionType, 'StreamVersion'>;\n\nexport type ExpectedStreamVersionGeneral = Flavour<\n 'STREAM_EXISTS' | 'STREAM_DOES_NOT_EXIST' | 'NO_CONCURRENCY_CHECK',\n 'StreamVersion'\n>;\n\nexport const STREAM_EXISTS = 'STREAM_EXISTS' as ExpectedStreamVersionGeneral;\nexport const STREAM_DOES_NOT_EXIST =\n 'STREAM_DOES_NOT_EXIST' as ExpectedStreamVersionGeneral;\nexport const NO_CONCURRENCY_CHECK =\n 'NO_CONCURRENCY_CHECK' as ExpectedStreamVersionGeneral;\n\nexport const matchesExpectedVersion = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion>,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nexport const assertExpectedVersionMatchesCurrent = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion> | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n\nexport class ExpectedVersionConflictError<\n VersionType = DefaultStreamVersionType,\n> extends ConcurrencyError {\n constructor(\n current: VersionType | undefined,\n expected: ExpectedStreamVersion<VersionType>,\n ) {\n super(current?.toString(), expected?.toString());\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);\n }\n}\n","import { randomUUID } from 'crypto';\nimport type { Event } from '../typing';\nimport {\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type EventStore,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\n\nexport type EventMetadata = Readonly<{\n eventId: string;\n streamPosition: number;\n logPosition: bigint;\n}>;\n\nexport type EventEnvelope<E extends Event = Event> = {\n event: E;\n metadata: EventMetadata;\n};\n\nexport type EventHandler<E extends Event = Event> = (\n eventEnvelope: EventEnvelope<E>,\n) => void;\n\nexport const getInMemoryEventStore = (): EventStore => {\n const streams = new Map<string, EventEnvelope[]>();\n\n const getAllEventsCount = () => {\n return Array.from<EventEnvelope[]>(streams.values())\n .map((s) => s.length)\n .reduce((p, c) => p + c, 0);\n };\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, getInitialState, read } = options;\n\n const result = await this.readStream<EventType>(streamName, read);\n\n if (!result) return null;\n\n const events = result?.events ?? [];\n\n return {\n currentStreamVersion: BigInt(events.length),\n state: events.reduce(evolve, getInitialState()),\n };\n },\n\n readStream: <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<ReadStreamResult<EventType>> => {\n const events = streams.get(streamName);\n const currentStreamVersion = events ? BigInt(events.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\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 && events.length > 0\n ? events.map((e) => e.event as EventType).slice(from, to)\n : [];\n\n const result: ReadStreamResult<EventType> =\n events && events.length > 0\n ? {\n currentStreamVersion: currentStreamVersion!,\n events: resultEvents,\n }\n : null;\n\n return Promise.resolve(result);\n },\n\n appendToStream: <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 ? BigInt(currentEvents.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const eventEnvelopes: EventEnvelope[] = events.map((event, index) => {\n return {\n event,\n metadata: {\n eventId: randomUUID(),\n streamPosition: currentEvents.length + index + 1,\n logPosition: BigInt(getAllEventsCount() + index + 1),\n },\n };\n });\n\n const positionOfLastEventInTheStream = BigInt(\n eventEnvelopes.slice(-1)[0]!.metadata.streamPosition,\n );\n\n streams.set(streamName, [...currentEvents, ...eventEnvelopes]);\n\n const result: AppendToStreamResult = {\n nextExpectedStreamVersion: positionOfLastEventInTheStream,\n };\n\n return Promise.resolve(result);\n },\n };\n};\n","import {\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type Event,\n type EventStore,\n type ExpectedStreamVersion,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport {\n ANY,\n STREAM_EXISTS as ESDB_STREAM_EXISTS,\n EventStoreDBClient,\n NO_STREAM,\n StreamNotFoundError,\n WrongExpectedVersionError,\n jsonEvent,\n type AppendExpectedRevision,\n type ReadStreamOptions as ESDBReadStreamOptions,\n} from '@eventstore/db-client';\n\nconst toEventStoreDBReadOptions = (\n options: ReadStreamOptions | undefined,\n): ESDBReadStreamOptions | undefined => {\n return options\n ? {\n fromRevision: 'from' in options ? options.from : undefined,\n maxCount:\n 'maxCount' in options\n ? options.maxCount\n : 'to' in options\n ? options.to\n : undefined,\n }\n : undefined;\n};\n\nexport const getEventStoreDBEventStore = (\n eventStore: EventStoreDBClient,\n): EventStore => {\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n try {\n const { evolve, getInitialState, read } = options;\n\n const expectedStreamVersion = read?.expectedStreamVersion;\n\n let state = getInitialState();\n let currentStreamVersion: bigint | undefined = undefined;\n\n for await (const { event } of eventStore.readStream(\n streamName,\n toEventStoreDBReadOptions(options.read),\n )) {\n if (!event) continue;\n\n state = evolve(state, <EventType>{\n type: event.type,\n data: event.data,\n });\n currentStreamVersion = event.revision;\n }\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n );\n\n return {\n currentStreamVersion: currentStreamVersion ?? 0n,\n state,\n };\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return null;\n }\n\n throw error;\n }\n },\n\n readStream: async <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<ReadStreamResult<EventType>> => {\n const events: EventType[] = [];\n\n let currentStreamVersion: bigint | undefined = undefined;\n\n try {\n for await (const { event } of eventStore.readStream(\n streamName,\n toEventStoreDBReadOptions(options),\n )) {\n if (!event) continue;\n events.push(<EventType>{\n type: event.type,\n data: event.data,\n });\n currentStreamVersion = event.revision;\n }\n return currentStreamVersion\n ? {\n currentStreamVersion,\n events,\n }\n : null;\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return null;\n }\n\n throw error;\n }\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> => {\n try {\n const serializedEvents = events.map(jsonEvent);\n\n const expectedRevision = toExpectedRevision(\n options?.expectedStreamVersion,\n );\n\n const appendResult = await eventStore.appendToStream(\n streamName,\n serializedEvents,\n {\n expectedRevision,\n },\n );\n\n return { nextExpectedStreamVersion: appendResult.nextExpectedRevision };\n } catch (error) {\n if (error instanceof WrongExpectedVersionError) {\n throw new ExpectedVersionConflictError(\n error.actualVersion,\n toExpectedVersion(error.expectedVersion),\n );\n }\n\n throw error;\n }\n },\n };\n};\n\nconst toExpectedRevision = (\n expected: ExpectedStreamVersion | undefined,\n): AppendExpectedRevision => {\n if (expected === undefined) return ANY;\n\n if (expected === NO_CONCURRENCY_CHECK) return ANY;\n\n if (expected == STREAM_DOES_NOT_EXIST) return NO_STREAM;\n\n if (expected == STREAM_EXISTS) return ESDB_STREAM_EXISTS;\n\n return expected as bigint;\n};\n\nconst toExpectedVersion = (\n expected: AppendExpectedRevision | undefined,\n): ExpectedStreamVersion => {\n if (expected === undefined) return NO_CONCURRENCY_CHECK;\n\n if (expected === ANY) return NO_CONCURRENCY_CHECK;\n\n if (expected == NO_STREAM) return STREAM_DOES_NOT_EXIST;\n\n if (expected == ESDB_STREAM_EXISTS) return STREAM_EXISTS;\n\n return expected;\n};\n\nconst matchesExpectedVersion = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nconst assertExpectedVersionMatchesCurrent = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n"]}
@@ -1,2 +0,0 @@
1
- import H from"assert";import F from"node:assert";import{randomUUID as W}from"node:crypto";import{after as Q,before as Z,describe as ee,it as te}from"node:test";var f=class E extends Error{errorCode;constructor(t){let r=t&&typeof t=="object"&&"errorCode"in t?t.errorCode:I(t)?t:500,a=t&&typeof t=="object"&&"message"in t?t.message:h(t)?t:`Error with status code '${r}' ocurred during Emmett processing`;super(a),this.errorCode=r,Object.setPrototypeOf(this,E.prototype)}},l=class v extends f{constructor(t,r,a){super({errorCode:412,message:a??`Expected version ${r.toString()} does not match current ${t?.toString()}`}),this.current=t,this.expected=r,Object.setPrototypeOf(this,v.prototype)}};var y=(e=>(e.NOT_A_NONEMPTY_STRING="NOT_A_NONEMPTY_STRING",e.NOT_A_POSITIVE_NUMBER="NOT_A_POSITIVE_NUMBER",e.NOT_AN_UNSIGNED_BIGINT="NOT_AN_UNSIGNED_BIGINT",e))(y||{}),I=e=>typeof e=="number"&&e===e,h=e=>typeof e=="string";var d="STREAM_EXISTS",i="STREAM_DOES_NOT_EXIST",o="NO_CONCURRENCY_CHECK";var m=class x extends l{constructor(t,r){super(t?.toString(),r?.toString()),Object.setPrototypeOf(this,x.prototype)}};import{randomUUID as ge}from"crypto";import{ANY as S,STREAM_EXISTS as O,NO_STREAM as A,StreamNotFoundError as T,WrongExpectedVersionError as C,jsonEvent as V}from"@eventstore/db-client";var N=e=>e?{fromRevision:"from"in e?e.from:void 0,maxCount:"maxCount"in e?e.maxCount:"to"in e?e.to:void 0}:void 0,mt=e=>({async aggregateStream(t,r){try{let{evolve:a,getInitialState:s,read:n}=r,g=n?.expectedStreamVersion,u=s(),c;for await(let{event:p}of e.readStream(t,N(r.read)))p&&(u=a(u,{type:p.type,data:p.data}),c=p.revision);return D(c,g),{currentStreamVersion:c??0n,state:u}}catch(a){if(a instanceof T)return null;throw a}},readStream:async(t,r)=>{let a=[],s;try{for await(let{event:n}of e.readStream(t,N(r)))n&&(a.push({type:n.type,data:n.data}),s=n.revision);return s?{currentStreamVersion:s,events:a}:null}catch(n){if(n instanceof T)return null;throw n}},appendToStream:async(t,r,a)=>{try{let s=r.map(V),n=P(a?.expectedStreamVersion);return{nextExpectedStreamVersion:(await e.appendToStream(t,s,{expectedRevision:n})).nextExpectedRevision}}catch(s){throw s instanceof C?new m(s.actualVersion,B(s.expectedVersion)):s}}}),P=e=>e===void 0?S:e===o?S:e==i?A:e==d?O:e,B=e=>e===void 0?o:e===S?o:e==A?i:e==O?d:e,M=(e,t)=>t===o?!0:t==i?e===void 0:t==d?e!==void 0:e===t,D=(e,t)=>{if(t??=o,!M(e,t))throw new m(e,t)};export{mt as a};
2
- //# sourceMappingURL=chunk-PF2HTK3Z.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../emmett/src/testing/deciderSpecification.ts","../../emmett/src/testing/features.ts","../../emmett/src/errors/index.ts","../../emmett/src/validation/index.ts","../../emmett/src/eventStore/expectedVersion.ts","../../emmett/src/eventStore/inMemoryEventStore.ts","../src/eventStore/eventstoreDBEventStore.ts"],"sourcesContent":["import assert from 'assert';\n\nexport type DeciderSpecfication<Command, Event> = (\n givenEvents: Event | Event[],\n) => {\n when: (command: Command) => {\n then: (expectedEvents: Event | Event[]) => void;\n thenThrows: <Error>(assert: (error: Error) => boolean) => void;\n };\n};\n\nexport const DeciderSpecification = {\n for: <Command, Event, State>(decider: {\n decide: (command: Command, state: State) => Event | Event[];\n evolve: (state: State, event: Event) => State;\n initialState: () => State;\n }): DeciderSpecfication<Command, Event> => {\n {\n return (givenEvents: Event | Event[]) => {\n return {\n when: (command: Command) => {\n const handle = () => {\n const existingEvents = Array.isArray(givenEvents)\n ? givenEvents\n : [givenEvents];\n\n const currentState = existingEvents.reduce<State>(\n decider.evolve,\n decider.initialState(),\n );\n\n return decider.decide(command, currentState);\n };\n\n return {\n then: (expectedEvents: Event | Event[]): void => {\n const resultEvents = handle();\n\n const resultEventsArray = Array.isArray(resultEvents)\n ? resultEvents\n : [resultEvents];\n\n const expectedEventsArray = Array.isArray(expectedEvents)\n ? expectedEvents\n : [expectedEvents];\n\n assert.deepEqual(resultEventsArray, expectedEventsArray);\n },\n thenThrows: <Error>(check?: (error: Error) => boolean): void => {\n try {\n handle();\n assert.fail('Handler did not fail as expected');\n } catch (error) {\n if (check) assert.ok(check(error as Error));\n }\n },\n };\n },\n };\n };\n }\n },\n};\n","/* eslint-disable @typescript-eslint/no-floating-promises */\nimport assert from 'node:assert';\nimport { randomUUID } from 'node:crypto';\nimport { after, before, describe, it } from 'node:test';\nimport type { EventStore } from '../eventStore';\nimport {\n evolve,\n getInitialState,\n type PricedProductItem,\n type ShoppingCartEvent,\n} from './shoppingCart.domain';\n\ntype TestOptions = {\n getInitialIndex: () => bigint;\n teardownHook?: () => Promise<void>;\n};\n\nexport type EventStoreFactory = () => Promise<EventStore<bigint>>;\n\nexport async function testAggregateStream(\n eventStoreFactory: EventStoreFactory,\n options: TestOptions = {\n getInitialIndex: () => 1n,\n },\n) {\n return describe('aggregateStream', () => {\n let eventStore: EventStore<bigint>;\n\n before(async () => {\n eventStore = await eventStoreFactory();\n });\n\n after(async () => {\n const teardownHook = options.teardownHook;\n if (teardownHook) await teardownHook();\n });\n\n it('When called with `to` allows time traveling', async () => {\n // Given\n const productItem: PricedProductItem = {\n productId: '123',\n quantity: 10,\n price: 3,\n };\n const discount = 10;\n const shoppingCartId = randomUUID();\n\n await eventStore.appendToStream<ShoppingCartEvent>(shoppingCartId, [\n { type: 'ProductItemAdded', data: { productItem } },\n ]);\n await eventStore.appendToStream<ShoppingCartEvent>(shoppingCartId, [\n { type: 'ProductItemAdded', data: { productItem } },\n ]);\n await eventStore.appendToStream<ShoppingCartEvent>(shoppingCartId, [\n { type: 'DiscountApplied', data: { percent: discount } },\n ]);\n\n // when\n const resultAt1 = await eventStore.aggregateStream(shoppingCartId, {\n evolve,\n getInitialState,\n read: { to: 1n },\n });\n const resultAt2 = await eventStore.aggregateStream(shoppingCartId, {\n evolve,\n getInitialState,\n read: { to: 2n },\n });\n const resultAt3 = await eventStore.aggregateStream(shoppingCartId, {\n evolve,\n getInitialState,\n read: { to: 3n },\n });\n\n // then\n assert.ok(resultAt1);\n assert.ok(resultAt2);\n assert.ok(resultAt3);\n\n assert.equal(resultAt1.currentStreamVersion, options.getInitialIndex());\n assert.deepEqual(resultAt1.state, {\n productItems: [productItem],\n totalAmount: 30,\n });\n\n assert.equal(\n resultAt2.currentStreamVersion,\n options.getInitialIndex() + 1n,\n );\n assert.deepEqual(resultAt2.state, {\n productItems: [productItem, productItem],\n totalAmount: 60,\n });\n\n assert.equal(\n resultAt3.currentStreamVersion,\n options.getInitialIndex() + 2n,\n );\n assert.deepEqual(resultAt3.state, {\n productItems: [productItem, productItem],\n totalAmount: 54,\n });\n });\n });\n}\n","import { isNumber, isString } from '../validation';\n\nexport class EmmettError extends Error {\n public errorCode: number;\n\n constructor(\n options?: { errorCode: number; message?: string } | string | number,\n ) {\n const errorCode =\n options && typeof options === 'object' && 'errorCode' in options\n ? options.errorCode\n : isNumber(options)\n ? options\n : 500;\n const message =\n options && typeof options === 'object' && 'message' in options\n ? options.message\n : isString(options)\n ? options\n : `Error with status code '${errorCode}' ocurred during Emmett processing`;\n\n super(message);\n this.errorCode = errorCode;\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, EmmettError.prototype);\n }\n}\n\nexport class ConcurrencyError extends EmmettError {\n constructor(\n public current: string | undefined,\n public expected: string,\n message?: string,\n ) {\n super({\n errorCode: 412,\n message:\n message ??\n `Expected version ${expected.toString()} does not match current ${current?.toString()}`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ConcurrencyError.prototype);\n }\n}\n\nexport class ValidationError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 400,\n message: message ?? `Validation Error ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class IllegalStateError extends EmmettError {\n constructor(message?: string) {\n super({\n errorCode: 403,\n message: message ?? `Illegal State ocurred during Emmett processing`,\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, IllegalStateError.prototype);\n }\n}\n\nexport class NotFoundError extends EmmettError {\n constructor(options?: { id: string; type: string; message?: string }) {\n super({\n errorCode: 404,\n message:\n options?.message ??\n (options?.id\n ? options.type\n ? `${options.type} with ${options.id} was not found during Emmett processing`\n : `State with ${options.id} was not found during Emmett processing`\n : options?.type\n ? `${options.type} was not found during Emmett processing`\n : 'State was not found during Emmett processing'),\n });\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n","import { 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","import { ConcurrencyError } from '../errors';\nimport type { Flavour } from '../typing';\nimport type { DefaultStreamVersionType } from './eventStore';\n\nexport type ExpectedStreamVersion<VersionType = DefaultStreamVersionType> =\n | ExpectedStreamVersionWithValue<VersionType>\n | ExpectedStreamVersionGeneral;\n\nexport type ExpectedStreamVersionWithValue<\n VersionType = DefaultStreamVersionType,\n> = Flavour<VersionType, 'StreamVersion'>;\n\nexport type ExpectedStreamVersionGeneral = Flavour<\n 'STREAM_EXISTS' | 'STREAM_DOES_NOT_EXIST' | 'NO_CONCURRENCY_CHECK',\n 'StreamVersion'\n>;\n\nexport const STREAM_EXISTS = 'STREAM_EXISTS' as ExpectedStreamVersionGeneral;\nexport const STREAM_DOES_NOT_EXIST =\n 'STREAM_DOES_NOT_EXIST' as ExpectedStreamVersionGeneral;\nexport const NO_CONCURRENCY_CHECK =\n 'NO_CONCURRENCY_CHECK' as ExpectedStreamVersionGeneral;\n\nexport const matchesExpectedVersion = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion>,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nexport const assertExpectedVersionMatchesCurrent = <\n StreamVersion = DefaultStreamVersionType,\n>(\n current: StreamVersion | undefined,\n expected: ExpectedStreamVersion<StreamVersion> | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n\nexport class ExpectedVersionConflictError<\n VersionType = DefaultStreamVersionType,\n> extends ConcurrencyError {\n constructor(\n current: VersionType | undefined,\n expected: ExpectedStreamVersion<VersionType>,\n ) {\n super(current?.toString(), expected?.toString());\n\n // 👇️ because we are extending a built-in class\n Object.setPrototypeOf(this, ExpectedVersionConflictError.prototype);\n }\n}\n","import { randomUUID } from 'crypto';\nimport type { Event } from '../typing';\nimport {\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type EventStore,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from './eventStore';\nimport { assertExpectedVersionMatchesCurrent } from './expectedVersion';\n\nexport type EventMetadata = Readonly<{\n eventId: string;\n streamPosition: number;\n logPosition: bigint;\n}>;\n\nexport type EventEnvelope<E extends Event = Event> = {\n event: E;\n metadata: EventMetadata;\n};\n\nexport type EventHandler<E extends Event = Event> = (\n eventEnvelope: EventEnvelope<E>,\n) => void;\n\nexport const getInMemoryEventStore = (): EventStore => {\n const streams = new Map<string, EventEnvelope[]>();\n\n const getAllEventsCount = () => {\n return Array.from<EventEnvelope[]>(streams.values())\n .map((s) => s.length)\n .reduce((p, c) => p + c, 0);\n };\n\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n const { evolve, getInitialState, read } = options;\n\n const result = await this.readStream<EventType>(streamName, read);\n\n if (!result) return null;\n\n const events = result?.events ?? [];\n\n return {\n currentStreamVersion: BigInt(events.length),\n state: events.reduce(evolve, getInitialState()),\n };\n },\n\n readStream: <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<ReadStreamResult<EventType>> => {\n const events = streams.get(streamName);\n const currentStreamVersion = events ? BigInt(events.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\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 && events.length > 0\n ? events.map((e) => e.event as EventType).slice(from, to)\n : [];\n\n const result: ReadStreamResult<EventType> =\n events && events.length > 0\n ? {\n currentStreamVersion: currentStreamVersion!,\n events: resultEvents,\n }\n : null;\n\n return Promise.resolve(result);\n },\n\n appendToStream: <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 ? BigInt(currentEvents.length) : undefined;\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n options?.expectedStreamVersion,\n );\n\n const eventEnvelopes: EventEnvelope[] = events.map((event, index) => {\n return {\n event,\n metadata: {\n eventId: randomUUID(),\n streamPosition: currentEvents.length + index + 1,\n logPosition: BigInt(getAllEventsCount() + index + 1),\n },\n };\n });\n\n const positionOfLastEventInTheStream = BigInt(\n eventEnvelopes.slice(-1)[0]!.metadata.streamPosition,\n );\n\n streams.set(streamName, [...currentEvents, ...eventEnvelopes]);\n\n const result: AppendToStreamResult = {\n nextExpectedStreamVersion: positionOfLastEventInTheStream,\n };\n\n return Promise.resolve(result);\n },\n };\n};\n","import {\n ExpectedVersionConflictError,\n NO_CONCURRENCY_CHECK,\n STREAM_DOES_NOT_EXIST,\n STREAM_EXISTS,\n type AggregateStreamOptions,\n type AggregateStreamResult,\n type AppendToStreamOptions,\n type AppendToStreamResult,\n type Event,\n type EventStore,\n type ExpectedStreamVersion,\n type ReadStreamOptions,\n type ReadStreamResult,\n} from '@event-driven-io/emmett';\nimport {\n ANY,\n STREAM_EXISTS as ESDB_STREAM_EXISTS,\n EventStoreDBClient,\n NO_STREAM,\n StreamNotFoundError,\n WrongExpectedVersionError,\n jsonEvent,\n type AppendExpectedRevision,\n type ReadStreamOptions as ESDBReadStreamOptions,\n} from '@eventstore/db-client';\n\nconst toEventStoreDBReadOptions = (\n options: ReadStreamOptions | undefined,\n): ESDBReadStreamOptions | undefined => {\n return options\n ? {\n fromRevision: 'from' in options ? options.from : undefined,\n maxCount:\n 'maxCount' in options\n ? options.maxCount\n : 'to' in options\n ? options.to\n : undefined,\n }\n : undefined;\n};\n\nexport const getEventStoreDBEventStore = (\n eventStore: EventStoreDBClient,\n): EventStore => {\n return {\n async aggregateStream<State, EventType extends Event>(\n streamName: string,\n options: AggregateStreamOptions<State, EventType>,\n ): Promise<AggregateStreamResult<State> | null> {\n try {\n const { evolve, getInitialState, read } = options;\n\n const expectedStreamVersion = read?.expectedStreamVersion;\n\n let state = getInitialState();\n let currentStreamVersion: bigint | undefined = undefined;\n\n for await (const { event } of eventStore.readStream(\n streamName,\n toEventStoreDBReadOptions(options.read),\n )) {\n if (!event) continue;\n\n state = evolve(state, <EventType>{\n type: event.type,\n data: event.data,\n });\n currentStreamVersion = event.revision;\n }\n\n assertExpectedVersionMatchesCurrent(\n currentStreamVersion,\n expectedStreamVersion,\n );\n\n return {\n currentStreamVersion: currentStreamVersion ?? 0n,\n state,\n };\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return null;\n }\n\n throw error;\n }\n },\n\n readStream: async <EventType extends Event>(\n streamName: string,\n options?: ReadStreamOptions,\n ): Promise<ReadStreamResult<EventType>> => {\n const events: EventType[] = [];\n\n let currentStreamVersion: bigint | undefined = undefined;\n\n try {\n for await (const { event } of eventStore.readStream(\n streamName,\n toEventStoreDBReadOptions(options),\n )) {\n if (!event) continue;\n events.push(<EventType>{\n type: event.type,\n data: event.data,\n });\n currentStreamVersion = event.revision;\n }\n return currentStreamVersion\n ? {\n currentStreamVersion,\n events,\n }\n : null;\n } catch (error) {\n if (error instanceof StreamNotFoundError) {\n return null;\n }\n\n throw error;\n }\n },\n\n appendToStream: async <EventType extends Event>(\n streamName: string,\n events: EventType[],\n options?: AppendToStreamOptions,\n ): Promise<AppendToStreamResult> => {\n try {\n const serializedEvents = events.map(jsonEvent);\n\n const expectedRevision = toExpectedRevision(\n options?.expectedStreamVersion,\n );\n\n const appendResult = await eventStore.appendToStream(\n streamName,\n serializedEvents,\n {\n expectedRevision,\n },\n );\n\n return { nextExpectedStreamVersion: appendResult.nextExpectedRevision };\n } catch (error) {\n if (error instanceof WrongExpectedVersionError) {\n throw new ExpectedVersionConflictError(\n error.actualVersion,\n toExpectedVersion(error.expectedVersion),\n );\n }\n\n throw error;\n }\n },\n };\n};\n\nconst toExpectedRevision = (\n expected: ExpectedStreamVersion | undefined,\n): AppendExpectedRevision => {\n if (expected === undefined) return ANY;\n\n if (expected === NO_CONCURRENCY_CHECK) return ANY;\n\n if (expected == STREAM_DOES_NOT_EXIST) return NO_STREAM;\n\n if (expected == STREAM_EXISTS) return ESDB_STREAM_EXISTS;\n\n return expected as bigint;\n};\n\nconst toExpectedVersion = (\n expected: AppendExpectedRevision | undefined,\n): ExpectedStreamVersion => {\n if (expected === undefined) return NO_CONCURRENCY_CHECK;\n\n if (expected === ANY) return NO_CONCURRENCY_CHECK;\n\n if (expected == NO_STREAM) return STREAM_DOES_NOT_EXIST;\n\n if (expected == ESDB_STREAM_EXISTS) return STREAM_EXISTS;\n\n return expected;\n};\n\nconst matchesExpectedVersion = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion,\n): boolean => {\n if (expected === NO_CONCURRENCY_CHECK) return true;\n\n if (expected == STREAM_DOES_NOT_EXIST) return current === undefined;\n\n if (expected == STREAM_EXISTS) return current !== undefined;\n\n return current === expected;\n};\n\nconst assertExpectedVersionMatchesCurrent = (\n current: bigint | undefined,\n expected: ExpectedStreamVersion | undefined,\n): void => {\n expected ??= NO_CONCURRENCY_CHECK;\n\n if (!matchesExpectedVersion(current, expected))\n throw new ExpectedVersionConflictError(current, expected);\n};\n"],"mappings":"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","names":["assert","assert","randomUUID","after","before","describe","it","EmmettError","_EmmettError","options","errorCode","isNumber","message","isString","ConcurrencyError","_ConcurrencyError","current","expected","ValidationErrors","isNumber","val","isString","STREAM_EXISTS","STREAM_DOES_NOT_EXIST","NO_CONCURRENCY_CHECK","ExpectedVersionConflictError","_ExpectedVersionConflictError","ConcurrencyError","current","expected","randomUUID","ANY","ESDB_STREAM_EXISTS","NO_STREAM","StreamNotFoundError","WrongExpectedVersionError","jsonEvent","toEventStoreDBReadOptions","options","getEventStoreDBEventStore","eventStore","streamName","evolve","getInitialState","read","expectedStreamVersion","state","currentStreamVersion","event","assertExpectedVersionMatchesCurrent","error","events","serializedEvents","expectedRevision","toExpectedRevision","t","toExpectedVersion","expected","n","a","s","matchesExpectedVersion","current"]}