@robinmalfait/event-source 0.0.1 → 0.0.3

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 CHANGED
@@ -15,22 +15,22 @@ import {
15
15
  createEventMapper,
16
16
  createEventSource,
17
17
  createProjector,
18
- createTestEventStore
19
- } from '@robinmalfait/event-source';
18
+ createTestEventStore,
19
+ } from '@robinmalfait/event-source'
20
20
  ```
21
21
 
22
22
  ## Local Development
23
23
 
24
24
  Below is a list of commands you will probably find useful.
25
25
 
26
- ### `npm start` or `yarn start`
26
+ ### `pnpm start`
27
27
 
28
28
  Start the build in watch mode, which makes it easy to make incremental builds.
29
29
 
30
- ### `npm run build` or `yarn build`
30
+ ### `pnpm build`
31
31
 
32
32
  Build the package!
33
33
 
34
- ### `npm test` or `yarn test`
34
+ ### `pnpm test`
35
35
 
36
36
  Runn all the tests!
@@ -0,0 +1,83 @@
1
+ interface EventType<T, N> {
2
+ aggregateId: string;
3
+ eventId: string;
4
+ eventName: N;
5
+ payload: T;
6
+ recordedAt: Date;
7
+ version: number;
8
+ }
9
+ declare function Event<T, N>(eventName: N, aggregateId: string, payload: T): EventType<T, N>;
10
+
11
+ declare class Aggregate {
12
+ private version;
13
+ private recordedEvents;
14
+ replayEvents<T>(events?: EventType<T, any>[]): this;
15
+ private applyAnEvent;
16
+ protected recordThat<T>(event: EventType<T, any>): this;
17
+ releaseEvents(): EventType<unknown, any>[];
18
+ }
19
+
20
+ interface CommandType<T> {
21
+ type: string;
22
+ payload: T;
23
+ }
24
+ declare function Command<T>(type: string, payload: T): CommandType<T>;
25
+
26
+ type PayloadOf<T extends (...args: any) => {
27
+ payload: unknown;
28
+ }> = ReturnType<T>['payload'];
29
+ type TypeOf<T extends (...args: any) => {
30
+ type: unknown;
31
+ }> = ReturnType<T>['type'];
32
+
33
+ declare function abort<T>(message: string, attributes?: T): void;
34
+
35
+ declare function objectToYaml<T extends Object>(object: T): string;
36
+
37
+ type MaybePromise<T> = T | Promise<T>;
38
+ interface EventStore {
39
+ persist<T>(events: EventType<T, unknown>[]): MaybePromise<void>;
40
+ load<T>(aggregateId: string): MaybePromise<EventType<T, string>[]>;
41
+ loadEvents<T>(): MaybePromise<EventType<T, string>[]>;
42
+ }
43
+ interface EventSourceConfig<Handlers = any> {
44
+ store: EventStore | Promise<EventStore>;
45
+ commandHandlers: Record<string, CommandHandler<Handlers>>;
46
+ projectors?: Projector[];
47
+ eventHandlers?: EventHandler[];
48
+ }
49
+ interface EventHandler {
50
+ (event: EventType<unknown, string>, es: EventSource): MaybePromise<unknown>;
51
+ }
52
+ interface Projector<TPayload = any, TEventName = any> {
53
+ name: string;
54
+ init: (es: EventSource) => MaybePromise<void>;
55
+ update: (event: EventType<TPayload, TEventName>) => MaybePromise<unknown>;
56
+ }
57
+ interface CommandHandler<T> {
58
+ (command: CommandType<T>, es: EventSource): MaybePromise<void>;
59
+ }
60
+ type EventSource = ReturnType<typeof createEventSource>;
61
+ declare function createEventSource(config: EventSourceConfig): {
62
+ resetProjections(): Promise<void>;
63
+ dispatch<T>(command: CommandType<T>): Promise<CommandType<T>>;
64
+ loadEvents<T_1>(): Promise<EventType<T_1, string>[]>;
65
+ load<T_2 extends Aggregate>(aggregate: T_2, aggregateId: string): Promise<T_2>;
66
+ persist(aggregate: Aggregate): Promise<void>;
67
+ loadPersist<T_3 extends Aggregate>(aggregate: T_3, aggregateId: string, handle: (aggregate: T_3) => Promise<void> | void): Promise<void>;
68
+ };
69
+
70
+ type EventMapper$1 = Record<string, (event: EventType<any, any>, es: EventSource) => void>;
71
+ declare function createEventMapper(mapper: EventMapper$1): (event: EventType<any, any>, es: EventSource) => void;
72
+
73
+ type EventMapper<Ctx, TPayload, TEventName> = Record<string, (event: EventType<TPayload, TEventName>, ctx?: Ctx) => void>;
74
+ declare function createProjector<Ctx, TPayload, TEventName>(name: string, mapper: EventMapper<Ctx, TPayload, TEventName>, initializer?: (ctx?: Ctx) => Promise<void> | void, createContext?: () => Ctx): Projector;
75
+
76
+ declare function createTestEventStore(commandHandlers: Record<string, CommandHandler<any>>, projectors?: Projector[]): {
77
+ ___: any;
78
+ given(events?: EventType<any, any>[]): Promise<void>;
79
+ when<T>(command: CommandType<T> | (() => CommandType<T>)): Promise<CommandType<T>>;
80
+ then<T_1>(expectation: Error | EventType<T_1, any>[]): Promise<void>;
81
+ };
82
+
83
+ export { Aggregate, Command, type CommandHandler, type CommandType, Event, type EventHandler, type EventSource, type EventSourceConfig, type EventStore, type EventType, type PayloadOf, type Projector, type TypeOf, abort, createEventMapper, createEventSource, createProjector, createTestEventStore, objectToYaml };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,83 @@
1
- export * from './aggregate';
2
- export * from './command';
3
- export * from './event';
4
- export * from './utils/abort';
5
- export * from './create-event-source';
6
- export { createEventMapper } from './create-event-mapper';
7
- export { createProjector } from './create-projector';
8
- export * from './create-test-event-store';
1
+ interface EventType<T, N> {
2
+ aggregateId: string;
3
+ eventId: string;
4
+ eventName: N;
5
+ payload: T;
6
+ recordedAt: Date;
7
+ version: number;
8
+ }
9
+ declare function Event<T, N>(eventName: N, aggregateId: string, payload: T): EventType<T, N>;
10
+
11
+ declare class Aggregate {
12
+ private version;
13
+ private recordedEvents;
14
+ replayEvents<T>(events?: EventType<T, any>[]): this;
15
+ private applyAnEvent;
16
+ protected recordThat<T>(event: EventType<T, any>): this;
17
+ releaseEvents(): EventType<unknown, any>[];
18
+ }
19
+
20
+ interface CommandType<T> {
21
+ type: string;
22
+ payload: T;
23
+ }
24
+ declare function Command<T>(type: string, payload: T): CommandType<T>;
25
+
26
+ type PayloadOf<T extends (...args: any) => {
27
+ payload: unknown;
28
+ }> = ReturnType<T>['payload'];
29
+ type TypeOf<T extends (...args: any) => {
30
+ type: unknown;
31
+ }> = ReturnType<T>['type'];
32
+
33
+ declare function abort<T>(message: string, attributes?: T): void;
34
+
35
+ declare function objectToYaml<T extends Object>(object: T): string;
36
+
37
+ type MaybePromise<T> = T | Promise<T>;
38
+ interface EventStore {
39
+ persist<T>(events: EventType<T, unknown>[]): MaybePromise<void>;
40
+ load<T>(aggregateId: string): MaybePromise<EventType<T, string>[]>;
41
+ loadEvents<T>(): MaybePromise<EventType<T, string>[]>;
42
+ }
43
+ interface EventSourceConfig<Handlers = any> {
44
+ store: EventStore | Promise<EventStore>;
45
+ commandHandlers: Record<string, CommandHandler<Handlers>>;
46
+ projectors?: Projector[];
47
+ eventHandlers?: EventHandler[];
48
+ }
49
+ interface EventHandler {
50
+ (event: EventType<unknown, string>, es: EventSource): MaybePromise<unknown>;
51
+ }
52
+ interface Projector<TPayload = any, TEventName = any> {
53
+ name: string;
54
+ init: (es: EventSource) => MaybePromise<void>;
55
+ update: (event: EventType<TPayload, TEventName>) => MaybePromise<unknown>;
56
+ }
57
+ interface CommandHandler<T> {
58
+ (command: CommandType<T>, es: EventSource): MaybePromise<void>;
59
+ }
60
+ type EventSource = ReturnType<typeof createEventSource>;
61
+ declare function createEventSource(config: EventSourceConfig): {
62
+ resetProjections(): Promise<void>;
63
+ dispatch<T>(command: CommandType<T>): Promise<CommandType<T>>;
64
+ loadEvents<T_1>(): Promise<EventType<T_1, string>[]>;
65
+ load<T_2 extends Aggregate>(aggregate: T_2, aggregateId: string): Promise<T_2>;
66
+ persist(aggregate: Aggregate): Promise<void>;
67
+ loadPersist<T_3 extends Aggregate>(aggregate: T_3, aggregateId: string, handle: (aggregate: T_3) => Promise<void> | void): Promise<void>;
68
+ };
69
+
70
+ type EventMapper$1 = Record<string, (event: EventType<any, any>, es: EventSource) => void>;
71
+ declare function createEventMapper(mapper: EventMapper$1): (event: EventType<any, any>, es: EventSource) => void;
72
+
73
+ type EventMapper<Ctx, TPayload, TEventName> = Record<string, (event: EventType<TPayload, TEventName>, ctx?: Ctx) => void>;
74
+ declare function createProjector<Ctx, TPayload, TEventName>(name: string, mapper: EventMapper<Ctx, TPayload, TEventName>, initializer?: (ctx?: Ctx) => Promise<void> | void, createContext?: () => Ctx): Projector;
75
+
76
+ declare function createTestEventStore(commandHandlers: Record<string, CommandHandler<any>>, projectors?: Projector[]): {
77
+ ___: any;
78
+ given(events?: EventType<any, any>[]): Promise<void>;
79
+ when<T>(command: CommandType<T> | (() => CommandType<T>)): Promise<CommandType<T>>;
80
+ then<T_1>(expectation: Error | EventType<T_1, any>[]): Promise<void>;
81
+ };
82
+
83
+ export { Aggregate, Command, type CommandHandler, type CommandType, Event, type EventHandler, type EventSource, type EventSourceConfig, type EventStore, type EventType, type PayloadOf, type Projector, type TypeOf, abort, createEventMapper, createEventSource, createProjector, createTestEventStore, objectToYaml };
package/dist/index.js CHANGED
@@ -1,8 +1,24 @@
1
+ "use strict";var $=Object.create;var f=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var L=Object.getPrototypeOf,Q=Object.prototype.hasOwnProperty;var q=(t,e)=>{for(var r in e)f(t,r,{get:e[r],enumerable:!0})},A=(t,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of R(e))!Q.call(t,o)&&o!==r&&f(t,o,{get:()=>e[o],enumerable:!(s=O(e,o))||s.enumerable});return t};var F=(t,e,r)=>(r=t!=null?$(L(t)):{},A(e||!t||!t.__esModule?f(r,"default",{value:t,enumerable:!0}):r,t)),V=t=>A(f({},"__esModule",{value:!0}),t);var B={};q(B,{Aggregate:()=>S,Command:()=>Y,Event:()=>J,abort:()=>u,createEventMapper:()=>_,createEventSource:()=>N,createProjector:()=>D,createTestEventStore:()=>Z,objectToYaml:()=>E});module.exports=V(B);function P(t,e){let r=Object.assign(new Error(t),e);return r.stack,Error.captureStackTrace&&Error.captureStackTrace(r,P),r}function u(t,e){let r=P(t,e);throw Error.captureStackTrace&&Error.captureStackTrace(r,u),r}function b(t){Object.freeze(t);for(let e of Object.getOwnPropertyNames(t))t.hasOwnProperty(e)&&t[e]!==null&&(typeof t[e]=="object"||typeof t[e]=="function")&&!Object.isFrozen(t[e])&&b(t[e]);return t}var z={NODE_ENV:process.env.NODE_ENV},S=class{version=0;recordedEvents=[];replayEvents(e=[]){for(let r of e)this.applyAnEvent(r);return this}applyAnEvent(e){z.NODE_ENV==="test"&&b(e),this[e.eventName]===void 0&&(e.eventName.match(/^[$A-Z_][0-9A-Z_$]*$/i)?u(`Aggregate "${this.constructor.name}" has no method:
1
2
 
2
- 'use strict'
3
+ ${e.eventName}(event) {
4
+ // Code goes here...
5
+ }`):u(`Aggregate "${this.constructor.name}" has no method:
3
6
 
4
- if (process.env.NODE_ENV === 'production') {
5
- module.exports = require('./event-source.cjs.production.min.js')
6
- } else {
7
- module.exports = require('./event-source.cjs.development.js')
8
- }
7
+ ['${e.eventName}'](event) {
8
+ // Code goes here...
9
+ }`));try{this[e.eventName](e)}catch(r){r instanceof Error&&console.error(`An error occurred inside your "%s" function:
10
+ `,e.eventName,r.stack?.split(`
11
+ `).map(s=>` ${s}`).join(`
12
+ `))}finally{this.version++}return this}recordThat(e){let r={...e,version:this.version};return this.applyAnEvent(r),this.recordedEvents.push(r),this}releaseEvents(){return this.recordedEvents.splice(0)}};function Y(t,e){return{type:t,payload:e}}var I=require("crypto");function J(t,e,r){return{aggregateId:e,eventId:(0,I.randomUUID)(),eventName:t,payload:r,recordedAt:new Date,version:-1}}var H=F(require("yamlify-object")),U={indent:" ",colors:{date:m,error:m,symbol:m,string:m,number:m,boolean:m,null:m,undefined:m}};function m(t){return t}function E(t){return t instanceof Error?E({...t}):(0,H.default)(t,U).split(`
13
+ `).slice(1).join(`
14
+ `)}function N(t){let{commandHandlers:e,eventHandlers:r=[],projectors:s=[],store:o}=t,l=[],a={async resetProjections(){await Promise.all(l),await Promise.all(s.map(n=>n.init(a)))},async dispatch(n){e[n.type]===void 0&&u(`There is no command handler for the "${n.type}" command`);let i=e[n.type];return await i(n,a),n},async loadEvents(){return await(await o).loadEvents()},async load(n,i){let v=await(await o).load(i);return v.length<=0&&u(`Aggregate(${n.constructor.name}) with ID(${i}) does not exist.`,{aggregate:n.constructor.name,aggregateId:i}),n.replayEvents(v)},async persist(n){await Promise.all(l);let i=await o,p=n.releaseEvents();await i.persist(p);for(let v of p)await Promise.all(s.map(async T=>{try{await T.update(v)}catch(c){throw c instanceof Error&&console.error(`An error occurred in one of your projections: ${T.name}, given an event`,c.stack?.split(`
15
+ `).map(d=>` ${d}`).join(`
16
+ `)),c}})),await Promise.all(r.map(async T=>{try{await T(v,a)}catch(c){throw c instanceof Error&&console.error(`An error occurred in one of your event handlers: ${T.name}, given an event`,c.stack?.split(`
17
+ `).map(d=>` ${d}`).join(`
18
+ `)),c}}))},async loadPersist(n,i,p){return await this.load(n,i),await p(n),this.persist(n)}};for(let n of s)l.push(n.init(a));return a}function _(t){return(e,r)=>t[e.eventName]?.(e,r)}var h=new WeakMap;function g(t,e){if(h.has(t)){let r=h.get(t);for(let s in e)r[s]=e[s]}else h.set(t,e)}function x(t){return h.get(t)}var w=class{constructor(){g(this,{jobs:[],state:0})}get length(){return x(this).jobs.length}async start(){let{state:e,jobs:r}=x(this);if(!(e===1||r.length<=0)){for(g(this,{state:1});r.length>0;){let s=r.shift();await Promise.resolve().then(s.handle).then(s.resolve,s.reject)}g(this,{state:0})}}push(e){return new Promise((r,s)=>{let{jobs:o}=x(this);o.push({handle:e,resolve:r,reject:s}),setImmediate(()=>this.start())})}};function W(){}function D(t,e,r=W,s){let o=new w,l=s?.();return{name:t,async init(a){await o.push(()=>r(l));let n=await a.loadEvents();await Promise.all(n.map(i=>o.push(()=>e[i.eventName]?.(i,l))))},update(a){return o.push(()=>e[a.eventName]?.(a,l))}}}var j=Symbol("__placeholder__"),y={usedTestEventStoreInTest:!1,calledThenHandler:!1};process.env.NODE_ENV==="test"&&(beforeEach(()=>{y.usedTestEventStoreInTest=!1,y.calledThenHandler=!1}),afterEach(()=>{y.usedTestEventStoreInTest&&!y.calledThenHandler&&u("It seems like you used `createTestEventStore()`\nwithout using the `await then([expected, events, go, here, ...])`")}));function M(t,e){try{return t()}catch(r){throw Error.captureStackTrace&&r instanceof Error&&Error.captureStackTrace(r,e),r}}var C=class{constructor(e=[],r=[]){this.db=e;this.producedEvents=r}name="test-recording-projector";init(){this.db.splice(0)}update(e){this.producedEvents.push(e)}};function Z(t,e=[]){y.usedTestEventStoreInTest=!0;let r=new C,s=N({store:{async load(a){return r.db.filter(n=>n.aggregateId===a)},loadEvents(){return r.db},persist(a){r.db.push(...a)}},commandHandlers:t,projectors:[...e,r]}),o,l={___:j,async given(a=[]){r.db.push(...a)},async when(a){try{return await s.dispatch(typeof a=="function"?a():a)}catch(n){return n instanceof Error&&(o=n),n}},async then(a){if(y.calledThenHandler=!0,a instanceof Error){let i=a;M(()=>expect(o).toEqual(i),l.then);return}let n=a;if(o)throw Object.keys(o).length>0&&(o.message=["With properties:",`
19
+ ${E(o)}
20
+
21
+ ---
22
+
23
+ `].join(`
24
+ `)),o;M(()=>{expect(n).toHaveLength(r.producedEvents.length);for(let[i,p]of n.entries()){let{aggregateId:v,eventName:T,payload:c}=r.producedEvents[i];if(p.aggregateId===j)throw new Error("Expected an `aggregateId`, but got `___` instead.");expect(p.aggregateId).toEqual(v),expect(p.eventName).toEqual(T),(p.payload===null||p.payload===void 0)&&expect(p.payload).toEqual(c);for(let d in p.payload){let k=p.payload[d];k===j?(expect(c).toHaveProperty(d),expect(c[d]).toBeDefined()):expect(c[d]).toEqual(k)}}},l.then)}};return l}0&&(module.exports={Aggregate,Command,Event,abort,createEventMapper,createEventSource,createProjector,createTestEventStore,objectToYaml});
package/dist/index.mjs ADDED
@@ -0,0 +1,24 @@
1
+ function x(r,e){let t=Object.assign(new Error(r),e);return t.stack,Error.captureStackTrace&&Error.captureStackTrace(t,x),t}function u(r,e){let t=x(r,e);throw Error.captureStackTrace&&Error.captureStackTrace(t,u),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 A={NODE_ENV:process.env.NODE_ENV},j=class{version=0;recordedEvents=[];replayEvents(e=[]){for(let t of e)this.applyAnEvent(t);return this}applyAnEvent(e){A.NODE_ENV==="test"&&w(e),this[e.eventName]===void 0&&(e.eventName.match(/^[$A-Z_][0-9A-Z_$]*$/i)?u(`Aggregate "${this.constructor.name}" has no method:
2
+
3
+ ${e.eventName}(event) {
4
+ // Code goes here...
5
+ }`):u(`Aggregate "${this.constructor.name}" has no method:
6
+
7
+ ['${e.eventName}'](event) {
8
+ // Code goes here...
9
+ }`));try{this[e.eventName](e)}catch(t){t instanceof Error&&console.error(`An error occurred inside your "%s" function:
10
+ `,e.eventName,t.stack?.split(`
11
+ `).map(a=>` ${a}`).join(`
12
+ `))}finally{this.version++}return this}recordThat(e){let t={...e,version:this.version};return this.applyAnEvent(t),this.recordedEvents.push(t),this}releaseEvents(){return this.recordedEvents.splice(0)}};function z(r,e){return{type:r,payload:e}}import{randomUUID as I}from"crypto";function U(r,e,t){return{aggregateId:e,eventId:I(),eventName:r,payload:t,recordedAt:new Date,version:-1}}import H from"yamlify-object";var _={indent:" ",colors:{date:m,error:m,symbol:m,string:m,number:m,boolean:m,null:m,undefined:m}};function m(r){return r}function P(r){return r instanceof Error?P({...r}):H(r,_).split(`
13
+ `).slice(1).join(`
14
+ `)}function C(r){let{commandHandlers:e,eventHandlers:t=[],projectors:a=[],store:s}=r,l=[],o={async resetProjections(){await Promise.all(l),await Promise.all(a.map(n=>n.init(o)))},async dispatch(n){e[n.type]===void 0&&u(`There is no command handler for the "${n.type}" command`);let i=e[n.type];return await i(n,o),n},async loadEvents(){return await(await s).loadEvents()},async load(n,i){let v=await(await s).load(i);return v.length<=0&&u(`Aggregate(${n.constructor.name}) with ID(${i}) does not exist.`,{aggregate:n.constructor.name,aggregateId:i}),n.replayEvents(v)},async persist(n){await Promise.all(l);let i=await s,p=n.releaseEvents();await i.persist(p);for(let v of p)await Promise.all(a.map(async T=>{try{await T.update(v)}catch(c){throw c instanceof Error&&console.error(`An error occurred in one of your projections: ${T.name}, given an event`,c.stack?.split(`
15
+ `).map(d=>` ${d}`).join(`
16
+ `)),c}})),await Promise.all(t.map(async T=>{try{await T(v,o)}catch(c){throw c instanceof Error&&console.error(`An error occurred in one of your event handlers: ${T.name}, given an event`,c.stack?.split(`
17
+ `).map(d=>` ${d}`).join(`
18
+ `)),c}}))},async loadPersist(n,i,p){return await this.load(n,i),await p(n),this.persist(n)}};for(let n of a)l.push(n.init(o));return o}function D(r){return(e,t)=>r[e.eventName]?.(e,t)}var f=new WeakMap;function E(r,e){if(f.has(r)){let t=f.get(r);for(let a in e)t[a]=e[a]}else f.set(r,e)}function h(r){return f.get(r)}var g=class{constructor(){E(this,{jobs:[],state:0})}get length(){return h(this).jobs.length}async start(){let{state:e,jobs:t}=h(this);if(!(e===1||t.length<=0)){for(E(this,{state:1});t.length>0;){let a=t.shift();await Promise.resolve().then(a.handle).then(a.resolve,a.reject)}E(this,{state:0})}}push(e){return new Promise((t,a)=>{let{jobs:s}=h(this);s.push({handle:e,resolve:t,reject:a}),setImmediate(()=>this.start())})}};function M(){}function $(r,e,t=M,a){let s=new g,l=a?.();return{name:r,async init(o){await s.push(()=>t(l));let n=await o.loadEvents();await Promise.all(n.map(i=>s.push(()=>e[i.eventName]?.(i,l))))},update(o){return s.push(()=>e[o.eventName]?.(o,l))}}}var b=Symbol("__placeholder__"),y={usedTestEventStoreInTest:!1,calledThenHandler:!1};process.env.NODE_ENV==="test"&&(beforeEach(()=>{y.usedTestEventStoreInTest=!1,y.calledThenHandler=!1}),afterEach(()=>{y.usedTestEventStoreInTest&&!y.calledThenHandler&&u("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 S=class{constructor(e=[],t=[]){this.db=e;this.producedEvents=t}name="test-recording-projector";init(){this.db.splice(0)}update(e){this.producedEvents.push(e)}};function le(r,e=[]){y.usedTestEventStoreInTest=!0;let t=new S,a=C({store:{async load(o){return t.db.filter(n=>n.aggregateId===o)},loadEvents(){return t.db},persist(o){t.db.push(...o)}},commandHandlers:r,projectors:[...e,t]}),s,l={___:b,async given(o=[]){t.db.push(...o)},async when(o){try{return await a.dispatch(typeof o=="function"?o():o)}catch(n){return n instanceof Error&&(s=n),n}},async then(o){if(y.calledThenHandler=!0,o instanceof Error){let i=o;k(()=>expect(s).toEqual(i),l.then);return}let n=o;if(s)throw Object.keys(s).length>0&&(s.message=["With properties:",`
19
+ ${P(s)}
20
+
21
+ ---
22
+
23
+ `].join(`
24
+ `)),s;k(()=>{expect(n).toHaveLength(t.producedEvents.length);for(let[i,p]of n.entries()){let{aggregateId:v,eventName:T,payload:c}=t.producedEvents[i];if(p.aggregateId===b)throw new Error("Expected an `aggregateId`, but got `___` instead.");expect(p.aggregateId).toEqual(v),expect(p.eventName).toEqual(T),(p.payload===null||p.payload===void 0)&&expect(p.payload).toEqual(c);for(let d in p.payload){let N=p.payload[d];N===b?(expect(c).toHaveProperty(d),expect(c[d]).toBeDefined()):expect(c[d]).toEqual(N)}}},l.then)}};return l}export{j as Aggregate,z as Command,U as Event,u as abort,D as createEventMapper,C as createEventSource,$ as createProjector,le as createTestEventStore,P as objectToYaml};
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.1",
2
+ "version": "0.0.3",
3
3
  "name": "@robinmalfait/event-source",
4
4
  "publishConfig": {
5
5
  "access": "public"
@@ -9,28 +9,19 @@
9
9
  "name": "Robin Malfait"
10
10
  },
11
11
  "main": "dist/index.js",
12
- "module": "dist/eventsource.esm.js",
12
+ "module": "dist/index.mjs",
13
13
  "typings": "dist/index.d.ts",
14
14
  "files": [
15
15
  "dist"
16
16
  ],
17
17
  "license": "MIT",
18
18
  "scripts": {
19
- "start": "tsdx watch",
20
- "build": "tsdx build",
21
- "test": "tsdx test",
22
- "tdd": "tsdx test --watch",
23
- "lint": "tsdx lint src",
24
- "format": "tsdx lint ./{src,examples}/**/*.ts --fix",
25
- "prepublishOnly": "tsdx build"
26
- },
27
- "husky": {
28
- "hooks": {
29
- "pre-commit": "lint-staged"
30
- }
31
- },
32
- "lint-staged": {
33
- "*.{js,jsx,ts,tsx}": "tsdx lint"
19
+ "start": "pnpm build --watch",
20
+ "build": "tsup ./src/index.ts --format esm,cjs --clean --minify --dts",
21
+ "test": "jest",
22
+ "tdd": "jest --watchAll",
23
+ "format": "prettier --write .",
24
+ "prepublishOnly": "pnpm build"
34
25
  },
35
26
  "prettier": {
36
27
  "printWidth": 80,
@@ -38,16 +29,27 @@
38
29
  "singleQuote": true,
39
30
  "trailingComma": "es5"
40
31
  },
32
+ "jest": {
33
+ "transform": {
34
+ "\\.ts$": "@swc/jest"
35
+ },
36
+ "moduleNameMapper": {
37
+ "^~/(.*)": "<rootDir>/src/$1",
38
+ "^@robinmalfait/event-source": "<rootDir>/src/index.ts"
39
+ }
40
+ },
41
41
  "devDependencies": {
42
- "@types/jest": "^26.0.20",
43
- "@types/node": "^14.14.25",
44
- "husky": "^4.3.8",
45
- "lint-staged": "^10.5.3",
46
- "tsdx": "^0.14.1",
47
- "tslib": "^2.1.0",
48
- "typescript": "^4.1.3"
42
+ "@swc/core": "^1.3.101",
43
+ "@swc/jest": "^0.2.29",
44
+ "@types/jest": "^29.5.11",
45
+ "@types/node": "^20.10.5",
46
+ "jest": "^29.7.0",
47
+ "knex": "^3.1.0",
48
+ "prettier": "^3.1.1",
49
+ "tsup": "^8.0.1",
50
+ "typescript": "^5.3.3"
49
51
  },
50
52
  "dependencies": {
51
- "yamlify-object": "^0.5.1"
53
+ "yamlify-object": "^1.0.0"
52
54
  }
53
55
  }
@@ -1,9 +0,0 @@
1
- import { EventType } from './event';
2
- export declare class Aggregate {
3
- private version;
4
- private recordedEvents;
5
- replayEvents<T>(events?: EventType<T>[]): this;
6
- private applyAnEvent;
7
- protected recordThat<T>(event: EventType<T>): this;
8
- releaseEvents(): EventType<unknown>[];
9
- }
package/dist/command.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export interface CommandType<T> {
2
- type: string;
3
- payload: T;
4
- }
5
- export declare function Command<T>(type: string, payload: T): CommandType<T>;
@@ -1,5 +0,0 @@
1
- import { EventType } from './event';
2
- import { EventSource } from './create-event-source';
3
- declare type EventMapper = Record<string, (event: EventType<any>, es: EventSource) => void>;
4
- export declare function createEventMapper(mapper: EventMapper): (event: EventType<any>, es: EventSource) => void;
5
- export {};
@@ -1,33 +0,0 @@
1
- import { EventType } from './event';
2
- import { CommandType } from './command';
3
- import { Aggregate } from './aggregate';
4
- export interface EventStore {
5
- persist<T>(events: EventType<T>[]): void | Promise<void>;
6
- load<T>(aggregateId: string): EventType<T>[] | Promise<EventType<T>[]>;
7
- loadEvents<T>(): EventType<T>[] | Promise<EventType<T>[]>;
8
- }
9
- export interface EventSourceConfig {
10
- store: EventStore | Promise<EventStore>;
11
- commandHandlers: Record<string, CommandHandler<unknown>>;
12
- projectors?: Projector[];
13
- eventHandlers?: EventHandler[];
14
- }
15
- export interface EventHandler {
16
- (event: EventType<unknown>, es: EventSource): void | Promise<unknown>;
17
- }
18
- export interface Projector {
19
- name: string;
20
- init: (es: EventSource) => Promise<void> | void;
21
- update: (event: EventType<unknown>) => Promise<unknown> | void;
22
- }
23
- export interface CommandHandler<T> {
24
- (command: CommandType<T>, es: EventSource): void | Promise<void>;
25
- }
26
- export declare type EventSource = ReturnType<typeof createEventSource>;
27
- export declare function createEventSource(config: EventSourceConfig): {
28
- dispatch<T>(command: CommandType<T>): Promise<CommandType<T>>;
29
- loadEvents<T_1>(): Promise<EventType<T_1>[]>;
30
- load<T_2 extends Aggregate>(aggregate: T_2, aggregateId: string): Promise<T_2>;
31
- persist(aggregate: Aggregate): Promise<void>;
32
- loadPersist<T_3 extends Aggregate>(aggregate: T_3, aggregateId: string, handle: (aggregate: T_3) => Promise<void> | void): Promise<void>;
33
- };
@@ -1,6 +0,0 @@
1
- import { EventType } from './event';
2
- import { Projector } from './create-event-source';
3
- declare type EventMapper = Record<string, (event: EventType<unknown>) => void>;
4
- declare function noop(): void;
5
- export declare function createProjector(name: string, mapper: EventMapper, initializer?: typeof noop): Projector;
6
- export {};
@@ -1,9 +0,0 @@
1
- import { CommandHandler, Projector } from './create-event-source';
2
- import { EventType } from './event';
3
- import { CommandType } from './command';
4
- export declare function createTestEventStore(commandHandlers: Record<string, CommandHandler<any>>, projectors?: Projector[]): {
5
- ___: any;
6
- given(events?: EventType<any>[]): Promise<void>;
7
- when<T>(command: CommandType<T>): Promise<CommandType<T>>;
8
- then<T_1>(events: Error | EventType<T_1>[]): Promise<void>;
9
- };