@robinmalfait/event-source 0.0.2 → 0.0.4

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 extends string, P> {
2
+ aggregateId: string;
3
+ eventId: string;
4
+ eventName: T;
5
+ payload: P;
6
+ recordedAt: Date;
7
+ version: number;
8
+ }
9
+ declare function Event<const T extends string, P = null>(eventName: T, aggregateId: string, payload?: P): EventType<T, P>;
10
+
11
+ declare class Aggregate {
12
+ private version;
13
+ private recordedEvents;
14
+ replayEvents<T extends string>(events?: EventType<T, any>[]): this;
15
+ private applyAnEvent;
16
+ protected recordThat<const T extends string>(event: EventType<T, any>): this;
17
+ releaseEvents(): EventType<string, any>[];
18
+ }
19
+
20
+ interface CommandType<T> {
21
+ type: string;
22
+ payload: T;
23
+ }
24
+ declare function Command<const T extends string, P>(type: T, payload: P): CommandType<P>;
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<const T extends string>(events: EventType<T, unknown>[]): MaybePromise<void>;
40
+ load<const T extends string>(aggregateId: string): MaybePromise<EventType<T, string>[]>;
41
+ loadEvents<const T extends string>(): 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<string, string>, es: EventSource): MaybePromise<unknown>;
51
+ }
52
+ interface Projector<T extends string = any, P = any> {
53
+ name: string;
54
+ init: (es: EventSource) => MaybePromise<void>;
55
+ update: (event: EventType<T, P>) => 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<const T_1 extends string>(): 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, T extends string, P> = Record<string, (event: EventType<T, P>, ctx?: Ctx) => void>;
74
+ declare function createProjector<Ctx, T extends string, P>(name: string, mapper: EventMapper<Ctx, T, P>, 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<const T_1 extends string>(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 extends string, P> {
2
+ aggregateId: string;
3
+ eventId: string;
4
+ eventName: T;
5
+ payload: P;
6
+ recordedAt: Date;
7
+ version: number;
8
+ }
9
+ declare function Event<const T extends string, P = null>(eventName: T, aggregateId: string, payload?: P): EventType<T, P>;
10
+
11
+ declare class Aggregate {
12
+ private version;
13
+ private recordedEvents;
14
+ replayEvents<T extends string>(events?: EventType<T, any>[]): this;
15
+ private applyAnEvent;
16
+ protected recordThat<const T extends string>(event: EventType<T, any>): this;
17
+ releaseEvents(): EventType<string, any>[];
18
+ }
19
+
20
+ interface CommandType<T> {
21
+ type: string;
22
+ payload: T;
23
+ }
24
+ declare function Command<const T extends string, P>(type: T, payload: P): CommandType<P>;
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<const T extends string>(events: EventType<T, unknown>[]): MaybePromise<void>;
40
+ load<const T extends string>(aggregateId: string): MaybePromise<EventType<T, string>[]>;
41
+ loadEvents<const T extends string>(): 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<string, string>, es: EventSource): MaybePromise<unknown>;
51
+ }
52
+ interface Projector<T extends string = any, P = any> {
53
+ name: string;
54
+ init: (es: EventSource) => MaybePromise<void>;
55
+ update: (event: EventType<T, P>) => 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<const T_1 extends string>(): 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, T extends string, P> = Record<string, (event: EventType<T, P>, ctx?: Ctx) => void>;
74
+ declare function createProjector<Ctx, T extends string, P>(name: string, mapper: EventMapper<Ctx, T, P>, 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<const T_1 extends string>(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:()=>d,createEventMapper:()=>_,createEventSource:()=>j,createProjector:()=>D,createTestEventStore:()=>Z,objectToYaml:()=>E});module.exports=V(B);function w(t,e){let r=Object.assign(new Error(t),e);return r.stack,Error.captureStackTrace&&Error.captureStackTrace(r,w),r}function d(t,e){let r=w(t,e);throw Error.captureStackTrace&&Error.captureStackTrace(r,d),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)?d(`Aggregate "${this.constructor.name}" has no method:
1
2
 
2
- 'use strict'
3
+ ${e.eventName}(event) {
4
+ // Code goes here...
5
+ }`):d(`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=null){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 j(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&&d(`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&&d(`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,c=n.releaseEvents();await i.persist(c);for(let v of c)await Promise.all(s.map(async T=>{try{await T.update(v)}catch(p){throw p instanceof Error&&console.error(`An error occurred in one of your projections: ${T.name}, given an event`,p.stack?.split(`
15
+ `).map(u=>` ${u}`).join(`
16
+ `)),p}})),await Promise.all(r.map(async T=>{try{await T(v,a)}catch(p){throw p instanceof Error&&console.error(`An error occurred in one of your event handlers: ${T.name}, given an event`,p.stack?.split(`
17
+ `).map(u=>` ${u}`).join(`
18
+ `)),p}}))},async loadPersist(n,i,c){return await this.load(n,i),await c(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 P=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 P,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 C=Symbol("__placeholder__"),y={usedTestEventStoreInTest:!1,calledThenHandler:!1};process.env.NODE_ENV==="test"&&(beforeEach(()=>{y.usedTestEventStoreInTest=!1,y.calledThenHandler=!1}),afterEach(()=>{y.usedTestEventStoreInTest&&!y.calledThenHandler&&d("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 k=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 k,s=j({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={___:C,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,c]of n.entries()){let{aggregateId:v,eventName:T,payload:p}=r.producedEvents[i];if(c.aggregateId===C)throw new Error("Expected an `aggregateId`, but got `___` instead.");expect(c.aggregateId).toEqual(v),expect(c.eventName).toEqual(T),(c.payload===null||c.payload===void 0)&&expect(c.payload).toEqual(p);for(let u in c.payload){let N=c.payload[u];N===C?(expect(p).toHaveProperty(u),expect(p[u]).toBeDefined()):expect(p[u]).toEqual(N)}}},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 d(r,e){let t=x(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 A={NODE_ENV:process.env.NODE_ENV},C=class{version=0;recordedEvents=[];replayEvents(e=[]){for(let t of e)this.applyAnEvent(t);return this}applyAnEvent(e){A.NODE_ENV==="test"&&P(e),this[e.eventName]===void 0&&(e.eventName.match(/^[$A-Z_][0-9A-Z_$]*$/i)?d(`Aggregate "${this.constructor.name}" has no method:
2
+
3
+ ${e.eventName}(event) {
4
+ // Code goes here...
5
+ }`):d(`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=null){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 w(r){return r instanceof Error?w({...r}):H(r,_).split(`
13
+ `).slice(1).join(`
14
+ `)}function k(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&&d(`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&&d(`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,c=n.releaseEvents();await i.persist(c);for(let v of c)await Promise.all(a.map(async T=>{try{await T.update(v)}catch(p){throw p instanceof Error&&console.error(`An error occurred in one of your projections: ${T.name}, given an event`,p.stack?.split(`
15
+ `).map(u=>` ${u}`).join(`
16
+ `)),p}})),await Promise.all(t.map(async T=>{try{await T(v,o)}catch(p){throw p instanceof Error&&console.error(`An error occurred in one of your event handlers: ${T.name}, given an event`,p.stack?.split(`
17
+ `).map(u=>` ${u}`).join(`
18
+ `)),p}}))},async loadPersist(n,i,c){return await this.load(n,i),await c(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&&d("It seems like you used `createTestEventStore()`\nwithout using the `await then([expected, events, go, here, ...])`")}));function N(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=k({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;N(()=>expect(s).toEqual(i),l.then);return}let n=o;if(s)throw Object.keys(s).length>0&&(s.message=["With properties:",`
19
+ ${w(s)}
20
+
21
+ ---
22
+
23
+ `].join(`
24
+ `)),s;N(()=>{expect(n).toHaveLength(t.producedEvents.length);for(let[i,c]of n.entries()){let{aggregateId:v,eventName:T,payload:p}=t.producedEvents[i];if(c.aggregateId===b)throw new Error("Expected an `aggregateId`, but got `___` instead.");expect(c.aggregateId).toEqual(v),expect(c.eventName).toEqual(T),(c.payload===null||c.payload===void 0)&&expect(c.payload).toEqual(p);for(let u in c.payload){let j=c.payload[u];j===b?(expect(p).toHaveProperty(u),expect(p[u]).toBeDefined()):expect(p[u]).toEqual(j)}}},l.then)}};return l}export{C as Aggregate,z as Command,U as Event,d as abort,D as createEventMapper,k as createEventSource,$ as createProjector,le as createTestEventStore,w as objectToYaml};
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.2",
2
+ "version": "0.0.4",
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
- };