@robinmalfait/event-source 0.0.14 → 0.0.16
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/README.md +1 -3
- package/dist/index.cjs +11 -14
- package/dist/index.d.cts +15 -4
- package/dist/index.d.ts +15 -4
- package/dist/index.js +9 -12
- package/package.json +19 -3
package/README.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Event Source
|
|
2
2
|
|
|
3
|
-

|
|
4
|
-
|
|
5
3
|
A node library for writing event sourced applications.
|
|
6
4
|
|
|
7
5
|
## Usage
|
|
@@ -33,4 +31,4 @@ Build the package!
|
|
|
33
31
|
|
|
34
32
|
### `pnpm test`
|
|
35
33
|
|
|
36
|
-
|
|
34
|
+
Run all the tests!
|
package/dist/index.cjs
CHANGED
|
@@ -1,36 +1,33 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var k=Object.create;var h=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var Q=(r,e)=>{for(var t in e)h(r,t,{get:e[t],enumerable:!0})},O=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of I(e))!J.call(r,a)&&a!==t&&h(r,a,{get:()=>e[a],enumerable:!(n=D(e,a))||n.enumerable});return r};var R=(r,e,t)=>(t=r!=null?k(_(r)):{},O(e||!r||!r.__esModule?h(t,"default",{value:r,enumerable:!0}):t,r)),F=r=>O(h({},"__esModule",{value:!0}),r);var Z={};Q(Z,{Aggregate:()=>S,Command:()=>Y,Event:()=>q,EventSource:()=>E,Projector:()=>m,abort:()=>d,createEventMapper:()=>z,createTestEventStore:()=>W,objectToYaml:()=>f});module.exports=F(Z);function P(r,e){let t=Object.assign(new Error(r),e);return t.stack,Error.captureStackTrace&&Error.captureStackTrace(t,P),t}function d(r,e){let t=P(r,e);throw Error.captureStackTrace&&Error.captureStackTrace(t,d),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 V={NODE_ENV:typeof process<"u"?process.env?.NODE_ENV:void 0},S=class{#e=0;#t=[];replayEvents(e=[]){for(let t of e)this.applyAnEvent(t);return this}applyAnEvent(e){V.NODE_ENV==="test"&&j(e);let t=this.apply[e.eventName];return 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
|
-
}`):
|
|
8
|
+
}`):d(`Aggregate "${this.constructor.name}" has no method:
|
|
9
9
|
|
|
10
10
|
apply = {
|
|
11
11
|
['${e.eventName}'](event) {
|
|
12
12
|
// Code goes here...
|
|
13
13
|
}
|
|
14
14
|
// ...
|
|
15
|
-
}`));
|
|
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(`
|
|
15
|
+
}`)),t(e),this.#e++,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}}function q(r,e,t=null,n=null){return{aggregateId:e,eventId:globalThis.crypto.randomUUID(),eventName:r,payload:t,metadata:n,recordedAt:new Date,version:-1}}var C=R(require("yamlify-object"),1),U={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,C.default)(r,U).split(`
|
|
19
16
|
`).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
|
|
21
|
-
`).map(
|
|
22
|
-
`)),
|
|
23
|
-
`).map(
|
|
24
|
-
`)),
|
|
17
|
+
`)}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 b(r){return T.get(r)}var x=class{constructor(){g(this,{jobs:[],state:0})}get length(){return b(this).jobs.length}async start(){let{state:e,jobs:t}=b(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:a}=b(this);a.push({handle:e,resolve:t,reject:n}),queueMicrotask(()=>this.start())})}};var m=class{apply;initializer(){}#e=new x;async init(e){this.initializer&&await this.#e.push(()=>this.initializer?.());for(let t of e)await this.applyEvent(t)}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,a,o){this.store=e;this.commandHandlers=t;this.projectors=n;this.eventHandlers=a;this.eventMetadataEnhancers=o}static builder(e){return new M(e)}static new(e,t,n,a,o){return new r(e,t,n,a,o)}async resetProjections(){let e=await this.store.loadEvents();await Promise.all(this.projectors.map(t=>t.init(e)))}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();if(this.eventMetadataEnhancers.length>0){let n={};for(let a of this.eventMetadataEnhancers)Object.assign(n,await a());for(let a of t){let o=a.metadata??{};a.metadata=Object.assign({},n,o)}}await this.store.persist(t);for(let n of t)await Promise.all(this.projectors.map(async a=>{try{await a.applyEvent(n)}catch(o){throw o instanceof Error&&console.error(`An error occurred in one of your projections: ${a.name}, given an event`,o.stack?.split(`
|
|
18
|
+
`).map(y=>` ${y}`).join(`
|
|
19
|
+
`)),o}})),await Promise.all(this.eventHandlers.map(async a=>{try{await a(n,this)}catch(o){throw o instanceof Error&&console.error(`An error occurred in one of your event handlers: ${a.name}, given an event`,o.stack?.split(`
|
|
20
|
+
`).map(y=>` ${y}`).join(`
|
|
21
|
+
`)),o}}))}async loadPersist(e,t,n){return await this.load(e,t),await n(e),this.persist(e)}},M=class{constructor(e){this.store=e}commandHandlers=new Map;projectors=[];eventHandlers=[];eventMetadataEnhancers=[];build(){return E.new(this.store,this.commandHandlers,this.projectors,this.eventHandlers,this.eventMetadataEnhancers)}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}metadata(e){return this.eventMetadataEnhancers.push(e),this}};function z(r){return(e,t)=>r[e.eventName]?.(e,t)}var A=Symbol("__placeholder__");function L(r,e){try{return r()}catch(t){throw Error.captureStackTrace&&t instanceof Error&&Error.captureStackTrace(t,e),t}}var N=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 W(r,e=[]){let t=new N,n=E.builder({load(s){return t.db.filter(i=>i.aggregateId===s)},loadEvents(){return t.db},persist(s){t.db.push(...s)}});for(let s of e)n.addProjector(s);n.addProjector(t);for(let[s,i]of Object.entries(r))n.addCommandHandler(s,i);let a=n.build(),o,y={___:A,async given(s=[]){t.db.push(...s)},async when(s){try{return await a.dispatch(typeof s=="function"?s():s)}catch(i){return i instanceof Error&&(o=i),i}},async then(s){if(s instanceof Error){let u=s;L(()=>{if(o?.message!==u?.message)throw new Error(`Expected error message to be:
|
|
25
22
|
|
|
26
23
|
${u.message}
|
|
27
24
|
|
|
28
25
|
But got:
|
|
29
26
|
|
|
30
|
-
${
|
|
31
|
-
${f(
|
|
27
|
+
${o?.message}`)},y.then);return}let i=s;if(o)throw Object.keys(o).length>0&&(o.message=["With properties:",`
|
|
28
|
+
${f(o)}
|
|
32
29
|
|
|
33
30
|
---
|
|
34
31
|
|
|
35
32
|
`].join(`
|
|
36
|
-
`)),
|
|
33
|
+
`)),o;L(()=>{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:$,eventName:H,payload:c}=t.producedEvents[u];if(p.aggregateId===A)throw new Error("Expected an `aggregateId`, but got `___` instead.");if(p.aggregateId!==$)throw new Error(`Expected aggregateId to be ${p.aggregateId}, but got ${$}.`);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 w=p.payload[l];if(w===A){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]!==w)throw new Error(`Expected payload.${l} to be ${w}, but got ${c[l]}.`)}}},y.then)}};return y}0&&(module.exports={Aggregate,Command,Event,EventSource,Projector,abort,createEventMapper,createTestEventStore,objectToYaml});
|
package/dist/index.d.cts
CHANGED
|
@@ -7,7 +7,7 @@ interface EventType<T extends string = any, P = any, M = any> {
|
|
|
7
7
|
recordedAt: Date;
|
|
8
8
|
version: number;
|
|
9
9
|
}
|
|
10
|
-
declare function Event<const T extends string, P = null, M = null>(eventName: T, aggregateId: string, payload?: P, metadata?: M): 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, M>;
|
|
11
11
|
|
|
12
12
|
type ApplyConcreteEvents<Events extends EventType> = Events extends EventType<infer EventName, any> ? {
|
|
13
13
|
[T in EventName]: (event: Extract<Events, {
|
|
@@ -44,6 +44,11 @@ declare function abort<T>(message: string, attributes?: T): void;
|
|
|
44
44
|
|
|
45
45
|
declare function objectToYaml<T extends Object>(object: T): string;
|
|
46
46
|
|
|
47
|
+
interface JSON {
|
|
48
|
+
[x: string]: string | number | boolean | Date | JSON | JSONArray;
|
|
49
|
+
}
|
|
50
|
+
interface JSONArray extends Array<string | number | boolean | Date | JSON | JSONArray> {
|
|
51
|
+
}
|
|
47
52
|
type MaybePromise<T> = T | Promise<T>;
|
|
48
53
|
interface EventStore {
|
|
49
54
|
persist(events: EventType[]): MaybePromise<void>;
|
|
@@ -53,6 +58,9 @@ interface EventStore {
|
|
|
53
58
|
interface EventHandler {
|
|
54
59
|
(event: EventType, es: EventSource): MaybePromise<unknown>;
|
|
55
60
|
}
|
|
61
|
+
interface MetadataEnhancer {
|
|
62
|
+
(): MaybePromise<JSON>;
|
|
63
|
+
}
|
|
56
64
|
type ApplyConcreteProjectorEvents<Events extends EventType> = Events extends EventType<infer EventName, any> ? {
|
|
57
65
|
[T in EventName]: (event: Extract<Events, {
|
|
58
66
|
eventName: T;
|
|
@@ -79,7 +87,7 @@ declare abstract class Projector<T extends ApplyProjectorEvents<any> = any> {
|
|
|
79
87
|
* date.
|
|
80
88
|
*/
|
|
81
89
|
initializer?(): void | Promise<void>;
|
|
82
|
-
init(
|
|
90
|
+
init(events: EventType[]): Promise<void>;
|
|
83
91
|
applyEvent(event: EventType): Promise<void>;
|
|
84
92
|
project(event: EventType): void | Promise<void>;
|
|
85
93
|
}
|
|
@@ -91,9 +99,10 @@ declare class EventSource {
|
|
|
91
99
|
private commandHandlers;
|
|
92
100
|
private projectors;
|
|
93
101
|
private eventHandlers;
|
|
102
|
+
private eventMetadataEnhancers;
|
|
94
103
|
private constructor();
|
|
95
104
|
static builder(store: EventStore): EventSourceBuilder;
|
|
96
|
-
static new(store: EventStore, commandHandlers: Map<string, CommandHandler>, projectors: Projector[], eventHandlers: EventHandler[]): EventSource;
|
|
105
|
+
static new(store: EventStore, commandHandlers: Map<string, CommandHandler>, projectors: Projector[], eventHandlers: EventHandler[], eventMetadataEnhancers: MetadataEnhancer[]): EventSource;
|
|
97
106
|
resetProjections(): Promise<void>;
|
|
98
107
|
dispatch<T extends CommandType>(command: T): Promise<T>;
|
|
99
108
|
loadEvents(): Promise<EventType<any, any, any>[]>;
|
|
@@ -106,11 +115,13 @@ declare class EventSourceBuilder {
|
|
|
106
115
|
private commandHandlers;
|
|
107
116
|
private projectors;
|
|
108
117
|
private eventHandlers;
|
|
118
|
+
private eventMetadataEnhancers;
|
|
109
119
|
constructor(store: EventStore);
|
|
110
120
|
build(): EventSource;
|
|
111
121
|
addCommandHandler(commandType: string, handler: CommandHandler): this;
|
|
112
122
|
addProjector(projector: Projector): this;
|
|
113
123
|
addEventHandler(eventHandler: EventHandler): this;
|
|
124
|
+
metadata(metadataEnhancer: MetadataEnhancer): this;
|
|
114
125
|
}
|
|
115
126
|
|
|
116
127
|
type EventMapper = Record<string, (event: EventType, es: EventSource) => void>;
|
|
@@ -123,4 +134,4 @@ declare function createTestEventStore(commandHandlers: Record<string, CommandHan
|
|
|
123
134
|
then(expectation: EventType[] | Error): Promise<void>;
|
|
124
135
|
};
|
|
125
136
|
|
|
126
|
-
export { Aggregate, type ApplyEvents, Command, type CommandHandler, type CommandType, Event, type EventHandler, EventSource, type EventStore, type EventType, type PayloadOf, Projector, type TypeOf, abort, createEventMapper, createTestEventStore, objectToYaml };
|
|
137
|
+
export { Aggregate, type ApplyEvents, Command, type CommandHandler, type CommandType, Event, type EventHandler, EventSource, type EventStore, type EventType, type MetadataEnhancer, type PayloadOf, Projector, type TypeOf, abort, createEventMapper, createTestEventStore, objectToYaml };
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ interface EventType<T extends string = any, P = any, M = any> {
|
|
|
7
7
|
recordedAt: Date;
|
|
8
8
|
version: number;
|
|
9
9
|
}
|
|
10
|
-
declare function Event<const T extends string, P = null, M = null>(eventName: T, aggregateId: string, payload?: P, metadata?: M): 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, M>;
|
|
11
11
|
|
|
12
12
|
type ApplyConcreteEvents<Events extends EventType> = Events extends EventType<infer EventName, any> ? {
|
|
13
13
|
[T in EventName]: (event: Extract<Events, {
|
|
@@ -44,6 +44,11 @@ declare function abort<T>(message: string, attributes?: T): void;
|
|
|
44
44
|
|
|
45
45
|
declare function objectToYaml<T extends Object>(object: T): string;
|
|
46
46
|
|
|
47
|
+
interface JSON {
|
|
48
|
+
[x: string]: string | number | boolean | Date | JSON | JSONArray;
|
|
49
|
+
}
|
|
50
|
+
interface JSONArray extends Array<string | number | boolean | Date | JSON | JSONArray> {
|
|
51
|
+
}
|
|
47
52
|
type MaybePromise<T> = T | Promise<T>;
|
|
48
53
|
interface EventStore {
|
|
49
54
|
persist(events: EventType[]): MaybePromise<void>;
|
|
@@ -53,6 +58,9 @@ interface EventStore {
|
|
|
53
58
|
interface EventHandler {
|
|
54
59
|
(event: EventType, es: EventSource): MaybePromise<unknown>;
|
|
55
60
|
}
|
|
61
|
+
interface MetadataEnhancer {
|
|
62
|
+
(): MaybePromise<JSON>;
|
|
63
|
+
}
|
|
56
64
|
type ApplyConcreteProjectorEvents<Events extends EventType> = Events extends EventType<infer EventName, any> ? {
|
|
57
65
|
[T in EventName]: (event: Extract<Events, {
|
|
58
66
|
eventName: T;
|
|
@@ -79,7 +87,7 @@ declare abstract class Projector<T extends ApplyProjectorEvents<any> = any> {
|
|
|
79
87
|
* date.
|
|
80
88
|
*/
|
|
81
89
|
initializer?(): void | Promise<void>;
|
|
82
|
-
init(
|
|
90
|
+
init(events: EventType[]): Promise<void>;
|
|
83
91
|
applyEvent(event: EventType): Promise<void>;
|
|
84
92
|
project(event: EventType): void | Promise<void>;
|
|
85
93
|
}
|
|
@@ -91,9 +99,10 @@ declare class EventSource {
|
|
|
91
99
|
private commandHandlers;
|
|
92
100
|
private projectors;
|
|
93
101
|
private eventHandlers;
|
|
102
|
+
private eventMetadataEnhancers;
|
|
94
103
|
private constructor();
|
|
95
104
|
static builder(store: EventStore): EventSourceBuilder;
|
|
96
|
-
static new(store: EventStore, commandHandlers: Map<string, CommandHandler>, projectors: Projector[], eventHandlers: EventHandler[]): EventSource;
|
|
105
|
+
static new(store: EventStore, commandHandlers: Map<string, CommandHandler>, projectors: Projector[], eventHandlers: EventHandler[], eventMetadataEnhancers: MetadataEnhancer[]): EventSource;
|
|
97
106
|
resetProjections(): Promise<void>;
|
|
98
107
|
dispatch<T extends CommandType>(command: T): Promise<T>;
|
|
99
108
|
loadEvents(): Promise<EventType<any, any, any>[]>;
|
|
@@ -106,11 +115,13 @@ declare class EventSourceBuilder {
|
|
|
106
115
|
private commandHandlers;
|
|
107
116
|
private projectors;
|
|
108
117
|
private eventHandlers;
|
|
118
|
+
private eventMetadataEnhancers;
|
|
109
119
|
constructor(store: EventStore);
|
|
110
120
|
build(): EventSource;
|
|
111
121
|
addCommandHandler(commandType: string, handler: CommandHandler): this;
|
|
112
122
|
addProjector(projector: Projector): this;
|
|
113
123
|
addEventHandler(eventHandler: EventHandler): this;
|
|
124
|
+
metadata(metadataEnhancer: MetadataEnhancer): this;
|
|
114
125
|
}
|
|
115
126
|
|
|
116
127
|
type EventMapper = Record<string, (event: EventType, es: EventSource) => void>;
|
|
@@ -123,4 +134,4 @@ declare function createTestEventStore(commandHandlers: Record<string, CommandHan
|
|
|
123
134
|
then(expectation: EventType[] | Error): Promise<void>;
|
|
124
135
|
};
|
|
125
136
|
|
|
126
|
-
export { Aggregate, type ApplyEvents, Command, type CommandHandler, type CommandType, Event, type EventHandler, EventSource, type EventStore, type EventType, type PayloadOf, Projector, type TypeOf, abort, createEventMapper, createTestEventStore, objectToYaml };
|
|
137
|
+
export { Aggregate, type ApplyEvents, Command, type CommandHandler, type CommandType, Event, type EventHandler, EventSource, type EventStore, type EventType, type MetadataEnhancer, type PayloadOf, Projector, type TypeOf, abort, createEventMapper, createTestEventStore, objectToYaml };
|
package/dist/index.js
CHANGED
|
@@ -1,36 +1,33 @@
|
|
|
1
|
-
function
|
|
1
|
+
function x(r,e){let t=Object.assign(new Error(r),e);return t.stack,Error.captureStackTrace&&Error.captureStackTrace(t,x),t}function c(r,e){let t=x(r,e);throw Error.captureStackTrace&&Error.captureStackTrace(t,c),t}function w(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])&&w(r[e]);return r}var O={NODE_ENV:typeof process<"u"?process.env?.NODE_ENV:void 0},$=class{#e=0;#t=[];replayEvents(e=[]){for(let t of e)this.applyAnEvent(t);return this}applyAnEvent(e){O.NODE_ENV==="test"&&w(e);let t=this.apply[e.eventName];return t==null&&(e.eventName.match(/^[$A-Z_][0-9A-Z_$]*$/i)?c(`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
|
-
}`):
|
|
8
|
+
}`):c(`Aggregate "${this.constructor.name}" has no method:
|
|
9
9
|
|
|
10
10
|
apply = {
|
|
11
11
|
['${e.eventName}'](event) {
|
|
12
12
|
// Code goes here...
|
|
13
13
|
}
|
|
14
14
|
// ...
|
|
15
|
-
}`));
|
|
16
|
-
`,e.eventName,n.stack?.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(`
|
|
15
|
+
}`)),t(e),this.#e++,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 F(r,e=null){return{type:r,payload:e}}function Y(r,e,t=null,n=null){return{aggregateId:e,eventId:globalThis.crypto.randomUUID(),eventName:r,payload:t,metadata:n,recordedAt:new Date,version:-1}}import C from"yamlify-object";var z={indent:" ",colors:{date:v,error:v,symbol:v,string:v,number:v,boolean:v,null:v,undefined:v}};function v(r){return r}function P(r){return r instanceof Error?P({...r}):C(r,z).split(`
|
|
19
16
|
`).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 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:
|
|
17
|
+
`)}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:o}=f(this);o.push({handle:e,resolve:t,reject:n}),queueMicrotask(()=>this.start())})}};var g=class{apply;initializer(){}#e=new T;async init(e){this.initializer&&await this.#e.push(()=>this.initializer?.());for(let t of e)await this.applyEvent(t)}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,o,a){this.store=e;this.commandHandlers=t;this.projectors=n;this.eventHandlers=o;this.eventMetadataEnhancers=a}static builder(e){return new j(e)}static new(e,t,n,o,a){return new r(e,t,n,o,a)}async resetProjections(){let e=await this.store.loadEvents();await Promise.all(this.projectors.map(t=>t.init(e)))}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();if(this.eventMetadataEnhancers.length>0){let n={};for(let o of this.eventMetadataEnhancers)Object.assign(n,await o());for(let o of t){let a=o.metadata??{};o.metadata=Object.assign({},n,a)}}await this.store.persist(t);for(let n of t)await Promise.all(this.projectors.map(async o=>{try{await o.applyEvent(n)}catch(a){throw a instanceof Error&&console.error(`An error occurred in one of your projections: ${o.name}, given an event`,a.stack?.split(`
|
|
21
18
|
`).map(y=>` ${y}`).join(`
|
|
22
|
-
`)),a}})),await Promise.all(this.eventHandlers.map(async
|
|
19
|
+
`)),a}})),await Promise.all(this.eventHandlers.map(async o=>{try{await o(n,this)}catch(a){throw a instanceof Error&&console.error(`An error occurred in one of your event handlers: ${o.name}, given an event`,a.stack?.split(`
|
|
23
20
|
`).map(y=>` ${y}`).join(`
|
|
24
|
-
`)),a}}))}async loadPersist(e,t,n){return await this.load(e,t),await n(e),this.persist(e)}},
|
|
21
|
+
`)),a}}))}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=[];eventMetadataEnhancers=[];build(){return E.new(this.store,this.commandHandlers,this.projectors,this.eventHandlers,this.eventMetadataEnhancers)}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}metadata(e){return this.eventMetadataEnhancers.push(e),this}};function L(r){return(e,t)=>r[e.eventName]?.(e,t)}var S=Symbol("__placeholder__");function H(r,e){try{return r()}catch(t){throw Error.captureStackTrace&&t instanceof Error&&Error.captureStackTrace(t,e),t}}var M=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 oe(r,e=[]){let t=new M,n=E.builder({load(s){return t.db.filter(i=>i.aggregateId===s)},loadEvents(){return t.db},persist(s){t.db.push(...s)}});for(let s of e)n.addProjector(s);n.addProjector(t);for(let[s,i]of Object.entries(r))n.addCommandHandler(s,i);let o=n.build(),a,y={___:S,async given(s=[]){t.db.push(...s)},async when(s){try{return await o.dispatch(typeof s=="function"?s():s)}catch(i){return i instanceof Error&&(a=i),i}},async then(s){if(s instanceof Error){let m=s;H(()=>{if(a?.message!==m?.message)throw new Error(`Expected error message to be:
|
|
25
22
|
|
|
26
23
|
${m.message}
|
|
27
24
|
|
|
28
25
|
But got:
|
|
29
26
|
|
|
30
|
-
${a?.message}`)},
|
|
31
|
-
${
|
|
27
|
+
${a?.message}`)},y.then);return}let i=s;if(a)throw Object.keys(a).length>0&&(a.message=["With properties:",`
|
|
28
|
+
${P(a)}
|
|
32
29
|
|
|
33
30
|
---
|
|
34
31
|
|
|
35
32
|
`].join(`
|
|
36
|
-
`)),a;
|
|
33
|
+
`)),a;H(()=>{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:A,eventName:N,payload:d}=t.producedEvents[m];if(p.aggregateId===S)throw new Error("Expected an `aggregateId`, but got `___` instead.");if(p.aggregateId!==A)throw new Error(`Expected aggregateId to be ${p.aggregateId}, but got ${A}.`);if(p.eventName!==N)throw new Error(`Expected eventName to be ${p.eventName}, but got ${N}.`);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 b=p.payload[l];if(b===S){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]!==b)throw new Error(`Expected payload.${l} to be ${b}, but got ${d[l]}.`)}}},y.then)}};return y}export{$ as Aggregate,F as Command,Y as Event,E as EventSource,g as Projector,c as abort,L as createEventMapper,oe as createTestEventStore,P as objectToYaml};
|
package/package.json
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.0.
|
|
2
|
+
"version": "0.0.16",
|
|
3
3
|
"name": "@robinmalfait/event-source",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/RobinMalfait/event-source.git"
|
|
7
|
+
},
|
|
4
8
|
"publishConfig": {
|
|
5
9
|
"access": "public"
|
|
6
10
|
},
|
|
@@ -9,9 +13,21 @@
|
|
|
9
13
|
"name": "Robin Malfait"
|
|
10
14
|
},
|
|
11
15
|
"type": "module",
|
|
12
|
-
"main": "dist/index.
|
|
13
|
-
"module": "dist/index.
|
|
16
|
+
"main": "dist/index.cjs",
|
|
17
|
+
"module": "dist/index.js",
|
|
14
18
|
"typings": "dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/index.d.cts",
|
|
27
|
+
"default": "./dist/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
15
31
|
"files": [
|
|
16
32
|
"dist"
|
|
17
33
|
],
|