@robinmalfait/event-source 0.0.12 → 0.0.14

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 ADDED
@@ -0,0 +1,36 @@
1
+ "use strict";var _=Object.create;var h=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var Q=Object.getPrototypeOf,R=Object.prototype.hasOwnProperty;var F=(r,e)=>{for(var t in e)h(r,t,{get:e[t],enumerable:!0})},z=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of J(e))!R.call(r,o)&&o!==t&&h(r,o,{get:()=>e[o],enumerable:!(n=D(e,o))||n.enumerable});return r};var V=(r,e,t)=>(t=r!=null?_(Q(r)):{},z(e||!r||!r.__esModule?h(t,"default",{value:r,enumerable:!0}):t,r)),Y=r=>z(h({},"__esModule",{value:!0}),r);var G={};F(G,{Aggregate:()=>S,Command:()=>W,Event:()=>Z,EventSource:()=>y,Projector:()=>m,abort:()=>c,createEventMapper:()=>k,createTestEventStore:()=>B,objectToYaml:()=>f});module.exports=Y(G);function j(r,e){let t=Object.assign(new Error(r),e);return t.stack,Error.captureStackTrace&&Error.captureStackTrace(t,j),t}function c(r,e){let t=j(r,e);throw Error.captureStackTrace&&Error.captureStackTrace(t,c),t}function A(r){Object.freeze(r);for(let e of Object.getOwnPropertyNames(r))r.hasOwnProperty(e)&&r[e]!==null&&(typeof r[e]=="object"||typeof r[e]=="function")&&!Object.isFrozen(r[e])&&A(r[e]);return r}var U={NODE_ENV:process.env.NODE_ENV},S=class{#e=0;#t=[];replayEvents(e=[]){for(let t of e)this.applyAnEvent(t);return this}applyAnEvent(e){U.NODE_ENV==="test"&&A(e);let t=this.apply[e.eventName];t==null&&(e.eventName.match(/^[$A-Z_][0-9A-Z_$]*$/i)?c(`Aggregate "${this.constructor.name}" has no method:
2
+
3
+ apply = {
4
+ ${e.eventName}(event) {
5
+ // Code goes here...
6
+ }
7
+ // ...
8
+ }`):c(`Aggregate "${this.constructor.name}" has no method:
9
+
10
+ apply = {
11
+ ['${e.eventName}'](event) {
12
+ // Code goes here...
13
+ }
14
+ // ...
15
+ }`));try{t(e)}catch(n){n instanceof Error&&console.error(`An error occurred inside your "%s" function:
16
+ `,e.eventName,n.stack?.split(`
17
+ `).map(o=>` ${o}`).join(`
18
+ `))}finally{this.#e++}return this}recordThat(e){let t={...e,version:this.#e};return this.applyAnEvent(t),this.#t.push(t),this}releaseEvents(){return this.#t.splice(0)}};function W(r,e=null){return{type:r,payload:e}}var L=require("crypto");function Z(r,e,t=null,n=null){return{aggregateId:e,eventId:(0,L.randomUUID)(),eventName:r,payload:t,metadata:n,recordedAt:new Date,version:-1}}var O=V(require("yamlify-object"),1),q={indent:" ",colors:{date:v,error:v,symbol:v,string:v,number:v,boolean:v,null:v,undefined:v}};function v(r){return r}function f(r){return r instanceof Error?f({...r}):(0,O.default)(r,q).split(`
19
+ `).slice(1).join(`
20
+ `)}var T=new WeakMap;function g(r,e){if(T.has(r)){let t=T.get(r);for(let n in e)t[n]=e[n]}else T.set(r,e)}function x(r){return T.get(r)}var b=class{constructor(){g(this,{jobs:[],state:0})}get length(){return x(this).jobs.length}async start(){let{state:e,jobs:t}=x(this);if(!(e===1||t.length<=0)){for(g(this,{state:1});t.length>0;){let n=t.shift();await Promise.resolve().then(n.handle).then(n.resolve,n.reject)}g(this,{state:0})}}push(e){return new Promise((t,n)=>{let{jobs:o}=x(this);o.push({handle:e,resolve:t,reject:n}),setImmediate(()=>this.start())})}};var m=class{apply;initializer(){}#e=new b;async init(e){this.initializer&&await this.#e.push(()=>this.initializer?.());let t=await e.loadEvents();await Promise.all(t.map(n=>this.applyEvent(n)))}async applyEvent(e){await this.#e.push(()=>this.apply?.[e.eventName]?.(e)),await this.#e.push(()=>this.project(e))}project(e){}},y=class r{constructor(e,t,n,o){this.store=e;this.commandHandlers=t;this.projectors=n;this.eventHandlers=o}static builder(e){return new $(e)}static new(e,t,n,o){return new r(e,t,n,o)}async resetProjections(){await Promise.all(this.projectors.map(e=>e.init(this)))}async dispatch(e){return this.commandHandlers.has(e.type)||c(`There is no command handler for the "${e.type}" command`),await this.commandHandlers.get(e.type)(e,this),e}async loadEvents(){return this.store.loadEvents()}async load(e,t){let n=await this.store.load(t);return n.length<=0&&c(`Aggregate(${e.constructor.name}) with ID(${t}) does not exist.`,{aggregate:e.constructor.name,aggregateId:t}),e.replayEvents(n)}async persist(e){let t=e.releaseEvents();await this.store.persist(t);for(let n of t)await Promise.all(this.projectors.map(async o=>{try{await o.applyEvent(n)}catch(s){throw s instanceof Error&&console.error(`An error occurred in one of your projections: ${o.name}, given an event`,s.stack?.split(`
21
+ `).map(E=>` ${E}`).join(`
22
+ `)),s}})),await Promise.all(this.eventHandlers.map(async o=>{try{await o(n,this)}catch(s){throw s instanceof Error&&console.error(`An error occurred in one of your event handlers: ${o.name}, given an event`,s.stack?.split(`
23
+ `).map(E=>` ${E}`).join(`
24
+ `)),s}}))}async loadPersist(e,t,n){return await this.load(e,t),await n(e),this.persist(e)}},$=class{constructor(e){this.store=e}commandHandlers=new Map;projectors=[];eventHandlers=[];build(){return y.new(this.store,this.commandHandlers,this.projectors,this.eventHandlers)}addCommandHandler(e,t){return this.commandHandlers.has(e)&&c(`A command handler for the "${e}" command already exists`),this.commandHandlers.set(e,t),this}addProjector(e){return this.projectors.push(e),this}addEventHandler(e){return this.eventHandlers.push(e),this}};function k(r){return(e,t)=>r[e.eventName]?.(e,t)}var N=Symbol("__placeholder__");function I(r,e){try{return r()}catch(t){throw Error.captureStackTrace&&t instanceof Error&&Error.captureStackTrace(t,e),t}}var H=class extends m{constructor(t=[],n=[]){super();this.db=t;this.producedEvents=n}apply={};name="test-recording-projector";initializer(){this.db.splice(0)}project(t){this.producedEvents.push(t)}};function B(r,e=[]){let t=new H,n=y.builder({load(a){return t.db.filter(i=>i.aggregateId===a)},loadEvents(){return t.db},persist(a){t.db.push(...a)}});for(let a of e)n.addProjector(a);n.addProjector(t);for(let[a,i]of Object.entries(r))n.addCommandHandler(a,i);let o=n.build(),s,E=!1,w={___:N,async given(a=[]){t.db.push(...a)},async when(a){try{return await o.dispatch(typeof a=="function"?a():a)}catch(i){return i instanceof Error&&(s=i),i}},async then(a){if(E=!0,a instanceof Error){let u=a;I(()=>{if(s?.message!==u?.message)throw new Error(`Expected error message to be:
25
+
26
+ ${u.message}
27
+
28
+ But got:
29
+
30
+ ${s?.message}`)},w.then);return}let i=a;if(s)throw Object.keys(s).length>0&&(s.message=["With properties:",`
31
+ ${f(s)}
32
+
33
+ ---
34
+
35
+ `].join(`
36
+ `)),s;I(()=>{if(i.length!==t.producedEvents.length)throw new Error(`Expected ${i.length} events, but got ${t.producedEvents.length} events.`);for(let[u,p]of i.entries()){let{aggregateId:C,eventName:M,payload:d}=t.producedEvents[u];if(p.aggregateId===N)throw new Error("Expected an `aggregateId`, but got `___` instead.");if(p.aggregateId!==C)throw new Error(`Expected aggregateId to be ${p.aggregateId}, but got ${C}.`);if(p.eventName!==M)throw new Error(`Expected eventName to be ${p.eventName}, but got ${M}.`);if((p.payload===null||p.payload===void 0)&&JSON.stringify(p.payload)!==JSON.stringify(d))throw new Error(`Expected payload to be ${JSON.stringify(p.payload)}, but got ${JSON.stringify(d)}.`);for(let l in p.payload){let P=p.payload[l];if(P===N){if(!(l in d))throw new Error(`Expected payload to have property ${l}, but it does not.`);if(d[l]===null||d[l]===void 0)throw new Error(`Expected payload to have property ${l}, but it is ${d[l]}.`)}else if(d[l]!==P)throw new Error(`Expected payload.${l} to be ${P}, but got ${d[l]}.`)}}},w.then)}};return w}0&&(module.exports={Aggregate,Command,Event,EventSource,Projector,abort,createEventMapper,createTestEventStore,objectToYaml});
@@ -1,12 +1,13 @@
1
- interface EventType<T extends string = any, P = any> {
1
+ interface EventType<T extends string = any, P = any, M = any> {
2
2
  aggregateId: string;
3
3
  eventId: string;
4
4
  eventName: T;
5
5
  payload: P;
6
+ metadata: M;
6
7
  recordedAt: Date;
7
8
  version: number;
8
9
  }
9
- declare function Event<const T extends string, P = null>(eventName: T, aggregateId: string, payload?: P): EventType<T, P>;
10
+ declare function Event<const T extends string, P = null, M = null>(eventName: T, aggregateId: string, payload?: P, metadata?: M): EventType<T, P>;
10
11
 
11
12
  type ApplyConcreteEvents<Events extends EventType> = Events extends EventType<infer EventName, any> ? {
12
13
  [T in EventName]: (event: Extract<Events, {
@@ -23,7 +24,7 @@ declare abstract class Aggregate {
23
24
  replayEvents(events?: EventType[]): this;
24
25
  private applyAnEvent;
25
26
  protected recordThat<T extends EventType>(event: T): this;
26
- releaseEvents(): EventType<any, any>[];
27
+ releaseEvents(): EventType<any, any, any>[];
27
28
  }
28
29
 
29
30
  interface CommandType<T extends string = any, P = any> {
@@ -95,7 +96,7 @@ declare class EventSource {
95
96
  static new(store: EventStore, commandHandlers: Map<string, CommandHandler>, projectors: Projector[], eventHandlers: EventHandler[]): EventSource;
96
97
  resetProjections(): Promise<void>;
97
98
  dispatch<T extends CommandType>(command: T): Promise<T>;
98
- loadEvents(): Promise<EventType<any, any>[]>;
99
+ loadEvents(): Promise<EventType<any, any, any>[]>;
99
100
  load<T extends Aggregate>(aggregate: T, aggregateId: string): Promise<T>;
100
101
  persist(aggregate: Aggregate): Promise<void>;
101
102
  loadPersist<T extends Aggregate>(aggregate: T, aggregateId: string, handle: (aggregate: T) => Promise<void> | void): Promise<void>;
@@ -118,7 +119,7 @@ declare function createEventMapper(mapper: EventMapper): (event: EventType, es:
118
119
  declare function createTestEventStore(commandHandlers: Record<string, CommandHandler>, projectors?: Projector[]): {
119
120
  ___: any;
120
121
  given(events?: EventType[]): Promise<void>;
121
- when<T extends CommandType<any, any>>(command: T | (() => T)): Promise<T>;
122
+ when<T extends CommandType>(command: T | (() => T)): Promise<T> | never;
122
123
  then(expectation: EventType[] | Error): Promise<void>;
123
124
  };
124
125
 
package/dist/index.d.ts CHANGED
@@ -1,12 +1,13 @@
1
- interface EventType<T extends string = any, P = any> {
1
+ interface EventType<T extends string = any, P = any, M = any> {
2
2
  aggregateId: string;
3
3
  eventId: string;
4
4
  eventName: T;
5
5
  payload: P;
6
+ metadata: M;
6
7
  recordedAt: Date;
7
8
  version: number;
8
9
  }
9
- declare function Event<const T extends string, P = null>(eventName: T, aggregateId: string, payload?: P): EventType<T, P>;
10
+ declare function Event<const T extends string, P = null, M = null>(eventName: T, aggregateId: string, payload?: P, metadata?: M): EventType<T, P>;
10
11
 
11
12
  type ApplyConcreteEvents<Events extends EventType> = Events extends EventType<infer EventName, any> ? {
12
13
  [T in EventName]: (event: Extract<Events, {
@@ -23,7 +24,7 @@ declare abstract class Aggregate {
23
24
  replayEvents(events?: EventType[]): this;
24
25
  private applyAnEvent;
25
26
  protected recordThat<T extends EventType>(event: T): this;
26
- releaseEvents(): EventType<any, any>[];
27
+ releaseEvents(): EventType<any, any, any>[];
27
28
  }
28
29
 
29
30
  interface CommandType<T extends string = any, P = any> {
@@ -95,7 +96,7 @@ declare class EventSource {
95
96
  static new(store: EventStore, commandHandlers: Map<string, CommandHandler>, projectors: Projector[], eventHandlers: EventHandler[]): EventSource;
96
97
  resetProjections(): Promise<void>;
97
98
  dispatch<T extends CommandType>(command: T): Promise<T>;
98
- loadEvents(): Promise<EventType<any, any>[]>;
99
+ loadEvents(): Promise<EventType<any, any, any>[]>;
99
100
  load<T extends Aggregate>(aggregate: T, aggregateId: string): Promise<T>;
100
101
  persist(aggregate: Aggregate): Promise<void>;
101
102
  loadPersist<T extends Aggregate>(aggregate: T, aggregateId: string, handle: (aggregate: T) => Promise<void> | void): Promise<void>;
@@ -118,7 +119,7 @@ declare function createEventMapper(mapper: EventMapper): (event: EventType, es:
118
119
  declare function createTestEventStore(commandHandlers: Record<string, CommandHandler>, projectors?: Projector[]): {
119
120
  ___: any;
120
121
  given(events?: EventType[]): Promise<void>;
121
- when<T extends CommandType<any, any>>(command: T | (() => T)): Promise<T>;
122
+ when<T extends CommandType>(command: T | (() => T)): Promise<T> | never;
122
123
  then(expectation: EventType[] | Error): Promise<void>;
123
124
  };
124
125
 
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- "use strict";var O=Object.create;var h=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var R=Object.getPrototypeOf,q=Object.prototype.hasOwnProperty;var F=(r,e)=>{for(var t in e)h(r,t,{get:e[t],enumerable:!0})},z=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Q(e))!q.call(r,o)&&o!==t&&h(r,o,{get:()=>e[o],enumerable:!(n=_(e,o))||n.enumerable});return r};var V=(r,e,t)=>(t=r!=null?O(R(r)):{},z(e||!r||!r.__esModule?h(t,"default",{value:r,enumerable:!0}):t,r)),Y=r=>z(h({},"__esModule",{value:!0}),r);var G={};F(G,{Aggregate:()=>A,Command:()=>U,Event:()=>W,EventSource:()=>v,Projector:()=>E,abort:()=>i,createEventMapper:()=>M,createTestEventStore:()=>B,objectToYaml:()=>T});module.exports=Y(G);function w(r,e){let t=Object.assign(new Error(r),e);return t.stack,Error.captureStackTrace&&Error.captureStackTrace(t,w),t}function i(r,e){let t=w(r,e);throw Error.captureStackTrace&&Error.captureStackTrace(t,i),t}function j(r){Object.freeze(r);for(let e of Object.getOwnPropertyNames(r))r.hasOwnProperty(e)&&r[e]!==null&&(typeof r[e]=="object"||typeof r[e]=="function")&&!Object.isFrozen(r[e])&&j(r[e]);return r}var J={NODE_ENV:process.env.NODE_ENV},A=class{#e=0;#t=[];replayEvents(e=[]){for(let t of e)this.applyAnEvent(t);return this}applyAnEvent(e){J.NODE_ENV==="test"&&j(e);let t=this.apply[e.eventName];t==null&&(e.eventName.match(/^[$A-Z_][0-9A-Z_$]*$/i)?i(`Aggregate "${this.constructor.name}" has no method:
1
+ function w(r,e){let t=Object.assign(new Error(r),e);return t.stack,Error.captureStackTrace&&Error.captureStackTrace(t,w),t}function d(r,e){let t=w(r,e);throw Error.captureStackTrace&&Error.captureStackTrace(t,d),t}function P(r){Object.freeze(r);for(let e of Object.getOwnPropertyNames(r))r.hasOwnProperty(e)&&r[e]!==null&&(typeof r[e]=="object"||typeof r[e]=="function")&&!Object.isFrozen(r[e])&&P(r[e]);return r}var z={NODE_ENV:process.env.NODE_ENV},C=class{#e=0;#t=[];replayEvents(e=[]){for(let t of e)this.applyAnEvent(t);return this}applyAnEvent(e){z.NODE_ENV==="test"&&P(e);let t=this.apply[e.eventName];t==null&&(e.eventName.match(/^[$A-Z_][0-9A-Z_$]*$/i)?d(`Aggregate "${this.constructor.name}" has no method:
2
2
 
3
3
  apply = {
4
4
  ${e.eventName}(event) {
5
5
  // Code goes here...
6
6
  }
7
7
  // ...
8
- }`):i(`Aggregate "${this.constructor.name}" has no method:
8
+ }`):d(`Aggregate "${this.constructor.name}" has no method:
9
9
 
10
10
  apply = {
11
11
  ['${e.eventName}'](event) {
@@ -14,17 +14,23 @@ apply = {
14
14
  // ...
15
15
  }`));try{t(e)}catch(n){n instanceof Error&&console.error(`An error occurred inside your "%s" function:
16
16
  `,e.eventName,n.stack?.split(`
17
- `).map(o=>` ${o}`).join(`
18
- `))}finally{this.#e++}return this}recordThat(e){let t={...e,version:this.#e};return this.applyAnEvent(t),this.#t.push(t),this}releaseEvents(){return this.#t.splice(0)}};function U(r,e=null){return{type:r,payload:e}}var L=require("crypto");function W(r,e,t=null){return{aggregateId:e,eventId:(0,L.randomUUID)(),eventName:r,payload:t,recordedAt:new Date,version:-1}}var I=V(require("yamlify-object")),Z={indent:" ",colors:{date:c,error:c,symbol:c,string:c,number:c,boolean:c,null:c,undefined:c}};function c(r){return r}function T(r){return r instanceof Error?T({...r}):(0,I.default)(r,Z).split(`
17
+ `).map(s=>` ${s}`).join(`
18
+ `))}finally{this.#e++}return this}recordThat(e){let t={...e,version:this.#e};return this.applyAnEvent(t),this.#t.push(t),this}releaseEvents(){return this.#t.splice(0)}};function Y(r,e=null){return{type:r,payload:e}}import{randomUUID as L}from"node:crypto";function Z(r,e,t=null,n=null){return{aggregateId:e,eventId:L(),eventName:r,payload:t,metadata:n,recordedAt:new Date,version:-1}}import O from"yamlify-object";var k={indent:" ",colors:{date:v,error:v,symbol:v,string:v,number:v,boolean:v,null:v,undefined:v}};function v(r){return r}function j(r){return r instanceof Error?j({...r}):O(r,k).split(`
19
19
  `).slice(1).join(`
20
- `)}var f=new WeakMap;function g(r,e){if(f.has(r)){let t=f.get(r);for(let n in e)t[n]=e[n]}else f.set(r,e)}function x(r){return f.get(r)}var b=class{constructor(){g(this,{jobs:[],state:0})}get length(){return x(this).jobs.length}async start(){let{state:e,jobs:t}=x(this);if(!(e===1||t.length<=0)){for(g(this,{state:1});t.length>0;){let n=t.shift();await Promise.resolve().then(n.handle).then(n.resolve,n.reject)}g(this,{state:0})}}push(e){return new Promise((t,n)=>{let{jobs:o}=x(this);o.push({handle:e,resolve:t,reject:n}),setImmediate(()=>this.start())})}};var E=class{apply;initializer(){}#e=new b;async init(e){this.initializer&&await this.#e.push(()=>this.initializer?.());let t=await e.loadEvents();await Promise.all(t.map(n=>this.applyEvent(n)))}async applyEvent(e){await this.#e.push(()=>this.apply?.[e.eventName]?.(e)),await this.#e.push(()=>this.project(e))}project(e){}},v=class r{constructor(e,t,n,o){this.store=e;this.commandHandlers=t;this.projectors=n;this.eventHandlers=o}static builder(e){return new S(e)}static new(e,t,n,o){return new r(e,t,n,o)}async resetProjections(){await Promise.all(this.projectors.map(e=>e.init(this)))}async dispatch(e){return this.commandHandlers.has(e.type)||i(`There is no command handler for the "${e.type}" command`),await this.commandHandlers.get(e.type)(e,this),e}async loadEvents(){return this.store.loadEvents()}async load(e,t){let n=await this.store.load(t);return n.length<=0&&i(`Aggregate(${e.constructor.name}) with ID(${t}) does not exist.`,{aggregate:e.constructor.name,aggregateId:t}),e.replayEvents(n)}async persist(e){let t=e.releaseEvents();await this.store.persist(t);for(let n of t)await Promise.all(this.projectors.map(async o=>{try{await o.applyEvent(n)}catch(s){throw s instanceof Error&&console.error(`An error occurred in one of your projections: ${o.name}, given an event`,s.stack?.split(`
21
- `).map(d=>` ${d}`).join(`
22
- `)),s}})),await Promise.all(this.eventHandlers.map(async o=>{try{await o(n,this)}catch(s){throw s instanceof Error&&console.error(`An error occurred in one of your event handlers: ${o.name}, given an event`,s.stack?.split(`
23
- `).map(d=>` ${d}`).join(`
24
- `)),s}}))}async loadPersist(e,t,n){return await this.load(e,t),await n(e),this.persist(e)}},S=class{constructor(e){this.store=e}commandHandlers=new Map;projectors=[];eventHandlers=[];build(){return v.new(this.store,this.commandHandlers,this.projectors,this.eventHandlers)}addCommandHandler(e,t){return this.commandHandlers.has(e)&&i(`A command handler for the "${e}" command already exists`),this.commandHandlers.set(e,t),this}addProjector(e){return this.projectors.push(e),this}addEventHandler(e){return this.eventHandlers.push(e),this}};function M(r){return(e,t)=>r[e.eventName]?.(e,t)}var H=Symbol("__placeholder__"),y={usedTestEventStoreInTest:!1,calledThenHandler:!1};process.env.NODE_ENV==="test"&&(beforeEach(()=>{y.usedTestEventStoreInTest=!1,y.calledThenHandler=!1}),afterEach(()=>{y.usedTestEventStoreInTest&&!y.calledThenHandler&&i("It seems like you used `createTestEventStore()`\nwithout using the `await then([expected, events, go, here, ...])`")}));function k(r,e){try{return r()}catch(t){throw Error.captureStackTrace&&t instanceof Error&&Error.captureStackTrace(t,e),t}}var N=class extends E{constructor(t=[],n=[]){super();this.db=t;this.producedEvents=n}apply={};name="test-recording-projector";initializer(){this.db.splice(0)}project(t){this.producedEvents.push(t)}};function B(r,e=[]){y.usedTestEventStoreInTest=!0;let t=new N,n=v.builder({load(a){return t.db.filter(p=>p.aggregateId===a)},loadEvents(){return t.db},persist(a){t.db.push(...a)}});for(let a of e)n.addProjector(a);n.addProjector(t);for(let[a,p]of Object.entries(r))n.addCommandHandler(a,p);let o=n.build(),s,d={___:H,async given(a=[]){t.db.push(...a)},async when(a){try{return await o.dispatch(typeof a=="function"?a():a)}catch(p){return p instanceof Error&&(s=p),p}},async then(a){if(y.calledThenHandler=!0,a instanceof Error){let P=a;k(()=>expect(s).toEqual(P),d.then);return}let p=a;if(s)throw Object.keys(s).length>0&&(s.message=["With properties:",`
25
- ${T(s)}
20
+ `)}var u=new WeakMap;function h(r,e){if(u.has(r)){let t=u.get(r);for(let n in e)t[n]=e[n]}else u.set(r,e)}function f(r){return u.get(r)}var T=class{constructor(){h(this,{jobs:[],state:0})}get length(){return f(this).jobs.length}async start(){let{state:e,jobs:t}=f(this);if(!(e===1||t.length<=0)){for(h(this,{state:1});t.length>0;){let n=t.shift();await Promise.resolve().then(n.handle).then(n.resolve,n.reject)}h(this,{state:0})}}push(e){return new Promise((t,n)=>{let{jobs:s}=f(this);s.push({handle:e,resolve:t,reject:n}),setImmediate(()=>this.start())})}};var g=class{apply;initializer(){}#e=new T;async init(e){this.initializer&&await this.#e.push(()=>this.initializer?.());let t=await e.loadEvents();await Promise.all(t.map(n=>this.applyEvent(n)))}async applyEvent(e){await this.#e.push(()=>this.apply?.[e.eventName]?.(e)),await this.#e.push(()=>this.project(e))}project(e){}},E=class r{constructor(e,t,n,s){this.store=e;this.commandHandlers=t;this.projectors=n;this.eventHandlers=s}static builder(e){return new A(e)}static new(e,t,n,s){return new r(e,t,n,s)}async resetProjections(){await Promise.all(this.projectors.map(e=>e.init(this)))}async dispatch(e){return this.commandHandlers.has(e.type)||d(`There is no command handler for the "${e.type}" command`),await this.commandHandlers.get(e.type)(e,this),e}async loadEvents(){return this.store.loadEvents()}async load(e,t){let n=await this.store.load(t);return n.length<=0&&d(`Aggregate(${e.constructor.name}) with ID(${t}) does not exist.`,{aggregate:e.constructor.name,aggregateId:t}),e.replayEvents(n)}async persist(e){let t=e.releaseEvents();await this.store.persist(t);for(let n of t)await Promise.all(this.projectors.map(async s=>{try{await s.applyEvent(n)}catch(a){throw a instanceof Error&&console.error(`An error occurred in one of your projections: ${s.name}, given an event`,a.stack?.split(`
21
+ `).map(y=>` ${y}`).join(`
22
+ `)),a}})),await Promise.all(this.eventHandlers.map(async s=>{try{await s(n,this)}catch(a){throw a instanceof Error&&console.error(`An error occurred in one of your event handlers: ${s.name}, given an event`,a.stack?.split(`
23
+ `).map(y=>` ${y}`).join(`
24
+ `)),a}}))}async loadPersist(e,t,n){return await this.load(e,t),await n(e),this.persist(e)}},A=class{constructor(e){this.store=e}commandHandlers=new Map;projectors=[];eventHandlers=[];build(){return E.new(this.store,this.commandHandlers,this.projectors,this.eventHandlers)}addCommandHandler(e,t){return this.commandHandlers.has(e)&&d(`A command handler for the "${e}" command already exists`),this.commandHandlers.set(e,t),this}addProjector(e){return this.projectors.push(e),this}addEventHandler(e){return this.eventHandlers.push(e),this}};function I(r){return(e,t)=>r[e.eventName]?.(e,t)}var S=Symbol("__placeholder__");function M(r,e){try{return r()}catch(t){throw Error.captureStackTrace&&t instanceof Error&&Error.captureStackTrace(t,e),t}}var $=class extends g{constructor(t=[],n=[]){super();this.db=t;this.producedEvents=n}apply={};name="test-recording-projector";initializer(){this.db.splice(0)}project(t){this.producedEvents.push(t)}};function pe(r,e=[]){let t=new $,n=E.builder({load(o){return t.db.filter(i=>i.aggregateId===o)},loadEvents(){return t.db},persist(o){t.db.push(...o)}});for(let o of e)n.addProjector(o);n.addProjector(t);for(let[o,i]of Object.entries(r))n.addCommandHandler(o,i);let s=n.build(),a,y=!1,x={___:S,async given(o=[]){t.db.push(...o)},async when(o){try{return await s.dispatch(typeof o=="function"?o():o)}catch(i){return i instanceof Error&&(a=i),i}},async then(o){if(y=!0,o instanceof Error){let m=o;M(()=>{if(a?.message!==m?.message)throw new Error(`Expected error message to be:
25
+
26
+ ${m.message}
27
+
28
+ But got:
29
+
30
+ ${a?.message}`)},x.then);return}let i=o;if(a)throw Object.keys(a).length>0&&(a.message=["With properties:",`
31
+ ${j(a)}
26
32
 
27
33
  ---
28
34
 
29
35
  `].join(`
30
- `)),s;k(()=>{expect(p).toHaveLength(t.producedEvents.length);for(let[P,l]of p.entries()){let{aggregateId:$,eventName:D,payload:m}=t.producedEvents[P];if(l.aggregateId===H)throw new Error("Expected an `aggregateId`, but got `___` instead.");expect(l.aggregateId).toEqual($),expect(l.eventName).toEqual(D),(l.payload===null||l.payload===void 0)&&expect(l.payload).toEqual(m);for(let u in l.payload){let C=l.payload[u];C===H?(expect(m).toHaveProperty(u),expect(m[u]).toBeDefined()):expect(m[u]).toEqual(C)}}},d.then)}};return d}0&&(module.exports={Aggregate,Command,Event,EventSource,Projector,abort,createEventMapper,createTestEventStore,objectToYaml});
36
+ `)),a;M(()=>{if(i.length!==t.producedEvents.length)throw new Error(`Expected ${i.length} events, but got ${t.producedEvents.length} events.`);for(let[m,p]of i.entries()){let{aggregateId:N,eventName:H,payload:c}=t.producedEvents[m];if(p.aggregateId===S)throw new Error("Expected an `aggregateId`, but got `___` instead.");if(p.aggregateId!==N)throw new Error(`Expected aggregateId to be ${p.aggregateId}, but got ${N}.`);if(p.eventName!==H)throw new Error(`Expected eventName to be ${p.eventName}, but got ${H}.`);if((p.payload===null||p.payload===void 0)&&JSON.stringify(p.payload)!==JSON.stringify(c))throw new Error(`Expected payload to be ${JSON.stringify(p.payload)}, but got ${JSON.stringify(c)}.`);for(let l in p.payload){let b=p.payload[l];if(b===S){if(!(l in c))throw new Error(`Expected payload to have property ${l}, but it does not.`);if(c[l]===null||c[l]===void 0)throw new Error(`Expected payload to have property ${l}, but it is ${c[l]}.`)}else if(c[l]!==b)throw new Error(`Expected payload.${l} to be ${b}, but got ${c[l]}.`)}}},x.then)}};return x}export{C as Aggregate,Y as Command,Z as Event,E as EventSource,g as Projector,d as abort,I as createEventMapper,pe as createTestEventStore,j as objectToYaml};
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.12",
2
+ "version": "0.0.14",
3
3
  "name": "@robinmalfait/event-source",
4
4
  "publishConfig": {
5
5
  "access": "public"
@@ -8,6 +8,7 @@
8
8
  "email": "malfait.robin@gmail.com",
9
9
  "name": "Robin Malfait"
10
10
  },
11
+ "type": "module",
11
12
  "main": "dist/index.js",
12
13
  "module": "dist/index.mjs",
13
14
  "typings": "dist/index.d.ts",
@@ -21,34 +22,23 @@
21
22
  "singleQuote": true,
22
23
  "trailingComma": "es5"
23
24
  },
24
- "jest": {
25
- "transform": {
26
- "\\.ts$": "@swc/jest"
27
- },
28
- "moduleNameMapper": {
29
- "^~/(.*)": "<rootDir>/src/$1",
30
- "^@robinmalfait/event-source": "<rootDir>/src/index.ts"
31
- }
32
- },
33
25
  "devDependencies": {
34
- "@swc/core": "^1.3.101",
35
- "@swc/jest": "^0.2.29",
36
- "@types/jest": "^29.5.11",
37
- "@types/node": "^20.10.5",
38
- "jest": "^29.7.0",
26
+ "@types/node": "^22.10.2",
39
27
  "knex": "^3.1.0",
40
- "prettier": "^3.1.1",
41
- "tsup": "^8.0.1",
42
- "typescript": "^5.3.3"
28
+ "prettier": "^3.4.2",
29
+ "tsup": "^8.3.5",
30
+ "typescript": "^5.7.2",
31
+ "vite-tsconfig-paths": "^5.1.4",
32
+ "vitest": "^2.1.8"
43
33
  },
44
34
  "dependencies": {
45
- "yamlify-object": "^1.0.0"
35
+ "yamlify-object": "^2.0.0"
46
36
  },
47
37
  "scripts": {
48
38
  "start": "pnpm build --watch",
49
39
  "build": "tsup ./src/index.ts --format esm,cjs --clean --minify --dts",
50
- "test": "jest",
51
- "tdd": "jest --watchAll",
40
+ "test": "vitest run",
41
+ "tdd": "vitest",
52
42
  "format": "prettier --write ."
53
43
  }
54
44
  }
package/dist/index.mjs DELETED
@@ -1,30 +0,0 @@
1
- function b(r,e){let t=Object.assign(new Error(r),e);return t.stack,Error.captureStackTrace&&Error.captureStackTrace(t,b),t}function p(r,e){let t=b(r,e);throw Error.captureStackTrace&&Error.captureStackTrace(t,p),t}function P(r){Object.freeze(r);for(let e of Object.getOwnPropertyNames(r))r.hasOwnProperty(e)&&r[e]!==null&&(typeof r[e]=="object"||typeof r[e]=="function")&&!Object.isFrozen(r[e])&&P(r[e]);return r}var I={NODE_ENV:process.env.NODE_ENV},N=class{#e=0;#t=[];replayEvents(e=[]){for(let t of e)this.applyAnEvent(t);return this}applyAnEvent(e){I.NODE_ENV==="test"&&P(e);let t=this.apply[e.eventName];t==null&&(e.eventName.match(/^[$A-Z_][0-9A-Z_$]*$/i)?p(`Aggregate "${this.constructor.name}" has no method:
2
-
3
- apply = {
4
- ${e.eventName}(event) {
5
- // Code goes here...
6
- }
7
- // ...
8
- }`):p(`Aggregate "${this.constructor.name}" has no method:
9
-
10
- apply = {
11
- ['${e.eventName}'](event) {
12
- // Code goes here...
13
- }
14
- // ...
15
- }`));try{t(e)}catch(n){n instanceof Error&&console.error(`An error occurred inside your "%s" function:
16
- `,e.eventName,n.stack?.split(`
17
- `).map(a=>` ${a}`).join(`
18
- `))}finally{this.#e++}return this}recordThat(e){let t={...e,version:this.#e};return this.applyAnEvent(t),this.#t.push(t),this}releaseEvents(){return this.#t.splice(0)}};function Y(r,e=null){return{type:r,payload:e}}import{randomUUID as M}from"crypto";function W(r,e,t=null){return{aggregateId:e,eventId:M(),eventName:r,payload:t,recordedAt:new Date,version:-1}}import k from"yamlify-object";var $={indent:" ",colors:{date:c,error:c,symbol:c,string:c,number:c,boolean:c,null:c,undefined:c}};function c(r){return r}function w(r){return r instanceof Error?w({...r}):k(r,$).split(`
19
- `).slice(1).join(`
20
- `)}var u=new WeakMap;function h(r,e){if(u.has(r)){let t=u.get(r);for(let n in e)t[n]=e[n]}else u.set(r,e)}function T(r){return u.get(r)}var f=class{constructor(){h(this,{jobs:[],state:0})}get length(){return T(this).jobs.length}async start(){let{state:e,jobs:t}=T(this);if(!(e===1||t.length<=0)){for(h(this,{state:1});t.length>0;){let n=t.shift();await Promise.resolve().then(n.handle).then(n.resolve,n.reject)}h(this,{state:0})}}push(e){return new Promise((t,n)=>{let{jobs:a}=T(this);a.push({handle:e,resolve:t,reject:n}),setImmediate(()=>this.start())})}};var g=class{apply;initializer(){}#e=new f;async init(e){this.initializer&&await this.#e.push(()=>this.initializer?.());let t=await e.loadEvents();await Promise.all(t.map(n=>this.applyEvent(n)))}async applyEvent(e){await this.#e.push(()=>this.apply?.[e.eventName]?.(e)),await this.#e.push(()=>this.project(e))}project(e){}},y=class r{constructor(e,t,n,a){this.store=e;this.commandHandlers=t;this.projectors=n;this.eventHandlers=a}static builder(e){return new j(e)}static new(e,t,n,a){return new r(e,t,n,a)}async resetProjections(){await Promise.all(this.projectors.map(e=>e.init(this)))}async dispatch(e){return this.commandHandlers.has(e.type)||p(`There is no command handler for the "${e.type}" command`),await this.commandHandlers.get(e.type)(e,this),e}async loadEvents(){return this.store.loadEvents()}async load(e,t){let n=await this.store.load(t);return n.length<=0&&p(`Aggregate(${e.constructor.name}) with ID(${t}) does not exist.`,{aggregate:e.constructor.name,aggregateId:t}),e.replayEvents(n)}async persist(e){let t=e.releaseEvents();await this.store.persist(t);for(let n of t)await Promise.all(this.projectors.map(async a=>{try{await a.applyEvent(n)}catch(s){throw s instanceof Error&&console.error(`An error occurred in one of your projections: ${a.name}, given an event`,s.stack?.split(`
21
- `).map(d=>` ${d}`).join(`
22
- `)),s}})),await Promise.all(this.eventHandlers.map(async a=>{try{await a(n,this)}catch(s){throw s instanceof Error&&console.error(`An error occurred in one of your event handlers: ${a.name}, given an event`,s.stack?.split(`
23
- `).map(d=>` ${d}`).join(`
24
- `)),s}}))}async loadPersist(e,t,n){return await this.load(e,t),await n(e),this.persist(e)}},j=class{constructor(e){this.store=e}commandHandlers=new Map;projectors=[];eventHandlers=[];build(){return y.new(this.store,this.commandHandlers,this.projectors,this.eventHandlers)}addCommandHandler(e,t){return this.commandHandlers.has(e)&&p(`A command handler for the "${e}" command already exists`),this.commandHandlers.set(e,t),this}addProjector(e){return this.projectors.push(e),this}addEventHandler(e){return this.eventHandlers.push(e),this}};function D(r){return(e,t)=>r[e.eventName]?.(e,t)}var A=Symbol("__placeholder__"),v={usedTestEventStoreInTest:!1,calledThenHandler:!1};process.env.NODE_ENV==="test"&&(beforeEach(()=>{v.usedTestEventStoreInTest=!1,v.calledThenHandler=!1}),afterEach(()=>{v.usedTestEventStoreInTest&&!v.calledThenHandler&&p("It seems like you used `createTestEventStore()`\nwithout using the `await then([expected, events, go, here, ...])`")}));function C(r,e){try{return r()}catch(t){throw Error.captureStackTrace&&t instanceof Error&&Error.captureStackTrace(t,e),t}}var S=class extends g{constructor(t=[],n=[]){super();this.db=t;this.producedEvents=n}apply={};name="test-recording-projector";initializer(){this.db.splice(0)}project(t){this.producedEvents.push(t)}};function le(r,e=[]){v.usedTestEventStoreInTest=!0;let t=new S,n=y.builder({load(o){return t.db.filter(i=>i.aggregateId===o)},loadEvents(){return t.db},persist(o){t.db.push(...o)}});for(let o of e)n.addProjector(o);n.addProjector(t);for(let[o,i]of Object.entries(r))n.addCommandHandler(o,i);let a=n.build(),s,d={___:A,async given(o=[]){t.db.push(...o)},async when(o){try{return await a.dispatch(typeof o=="function"?o():o)}catch(i){return i instanceof Error&&(s=i),i}},async then(o){if(v.calledThenHandler=!0,o instanceof Error){let x=o;C(()=>expect(s).toEqual(x),d.then);return}let i=o;if(s)throw Object.keys(s).length>0&&(s.message=["With properties:",`
25
- ${w(s)}
26
-
27
- ---
28
-
29
- `].join(`
30
- `)),s;C(()=>{expect(i).toHaveLength(t.producedEvents.length);for(let[x,l]of i.entries()){let{aggregateId:z,eventName:L,payload:E}=t.producedEvents[x];if(l.aggregateId===A)throw new Error("Expected an `aggregateId`, but got `___` instead.");expect(l.aggregateId).toEqual(z),expect(l.eventName).toEqual(L),(l.payload===null||l.payload===void 0)&&expect(l.payload).toEqual(E);for(let m in l.payload){let H=l.payload[m];H===A?(expect(E).toHaveProperty(m),expect(E[m]).toBeDefined()):expect(E[m]).toEqual(H)}}},d.then)}};return d}export{N as Aggregate,Y as Command,W as Event,y as EventSource,g as Projector,p as abort,D as createEventMapper,le as createTestEventStore,w as objectToYaml};