@defai.digital/memory-domain 13.4.5 → 13.4.8

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.
@@ -17,6 +17,14 @@ export declare class AggregateRepository<T> {
17
17
  /**
18
18
  * Saves an event to the aggregate
19
19
  * INV-MEM-004: Event ordering enforced via version
20
+ *
21
+ * CONCURRENCY NOTE (INV-MEM-008):
22
+ * The optimistic concurrency check and append are NOT atomic. In truly concurrent
23
+ * scenarios (e.g., distributed systems or multi-process), another operation could
24
+ * modify the aggregate between getVersion() and append(). This is acceptable for
25
+ * single-process Node.js where async operations interleave but don't truly run
26
+ * in parallel. For distributed scenarios, implement compare-and-swap at the
27
+ * storage layer or use a mutex/lock around the check-and-write operation.
20
28
  */
21
29
  save(aggregateId: string, event: MemoryEvent, expectedVersion?: number): Promise<void>;
22
30
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,YAAY,EACb,MAAM,YAAY,CAAC;AAIpB;;;GAGG;AACH,qBAAa,mBAAmB,CAAC,CAAC;IAE9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAFZ,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,CAAC,EACrB,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;IAGhD;;;OAGG;IACG,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IA6B3D;;;OAGG;IACG,IAAI,CACR,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,WAAW,EAClB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC;IAgBhB;;OAEG;IACG,aAAa,CACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;CAiC9B;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EACzC,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,CAAC,EACrB,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,GAC5B,mBAAmB,CAAC,CAAC,CAAC,CAExB"}
1
+ {"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,YAAY,EACb,MAAM,YAAY,CAAC;AAIpB;;;GAGG;AACH,qBAAa,mBAAmB,CAAC,CAAC;IAE9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAFZ,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,CAAC,EACrB,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;IAGhD;;;OAGG;IACG,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IA6B3D;;;;;;;;;;;OAWG;IACG,IAAI,CACR,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,WAAW,EAClB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC;IAgBhB;;OAEG;IACG,aAAa,CACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;CAiC9B;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EACzC,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,CAAC,EACrB,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,GAC5B,mBAAmB,CAAC,CAAC,CAAC,CAExB"}
package/dist/aggregate.js CHANGED
@@ -44,9 +44,17 @@ export class AggregateRepository {
44
44
  /**
45
45
  * Saves an event to the aggregate
46
46
  * INV-MEM-004: Event ordering enforced via version
47
+ *
48
+ * CONCURRENCY NOTE (INV-MEM-008):
49
+ * The optimistic concurrency check and append are NOT atomic. In truly concurrent
50
+ * scenarios (e.g., distributed systems or multi-process), another operation could
51
+ * modify the aggregate between getVersion() and append(). This is acceptable for
52
+ * single-process Node.js where async operations interleave but don't truly run
53
+ * in parallel. For distributed scenarios, implement compare-and-swap at the
54
+ * storage layer or use a mutex/lock around the check-and-write operation.
47
55
  */
48
56
  async save(aggregateId, event, expectedVersion) {
49
- // Optimistic concurrency check
57
+ // Optimistic concurrency check (see INV-MEM-008 for concurrency limitations)
50
58
  if (expectedVersion !== undefined) {
51
59
  const currentVersion = await this.eventStore.getVersion(aggregateId);
52
60
  if (currentVersion !== expectedVersion) {
@@ -1 +1 @@
1
- {"version":3,"file":"aggregate.js","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"aggregate.js","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"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"}
@@ -12,11 +12,14 @@ export declare class EventStoreError extends Error {
12
12
  * In-memory event store implementation
13
13
  * INV-MEM-001: Events are immutable - stored as frozen objects
14
14
  * INV-MEM-004: Events are ordered by version within aggregate
15
+ * INV-MEM-006: Memory growth is bounded with LRU eviction
15
16
  */
16
17
  export declare class InMemoryEventStore implements EventStore {
17
18
  private readonly events;
18
19
  private readonly allEvents;
19
20
  private readonly correlationIndex;
21
+ private readonly maxEvents;
22
+ constructor(maxEvents?: number);
20
23
  /**
21
24
  * Appends an event to the store
22
25
  * INV-MEM-001: Events are immutable
@@ -39,8 +42,14 @@ export declare class InMemoryEventStore implements EventStore {
39
42
  getEventsByCorrelation(correlationId: string): Promise<MemoryEvent[]>;
40
43
  /**
41
44
  * Gets the current version for an aggregate
45
+ * INV-MEM-007: Version calculation handles edge cases correctly
42
46
  */
43
47
  getVersion(aggregateId: string): Promise<number>;
48
+ /**
49
+ * Evicts the oldest events to maintain memory bounds
50
+ * INV-MEM-006: LRU eviction when over maxEvents
51
+ */
52
+ private evictOldest;
44
53
  /**
45
54
  * Clears all events (for testing)
46
55
  */
@@ -48,6 +57,7 @@ export declare class InMemoryEventStore implements EventStore {
48
57
  }
49
58
  /**
50
59
  * Creates an in-memory event store
60
+ * @param maxEvents Maximum events to store before eviction (default: 100000)
51
61
  */
52
- export declare function createInMemoryEventStore(): InMemoryEventStore;
62
+ export declare function createInMemoryEventStore(maxEvents?: number): InMemoryEventStore;
53
63
  //# sourceMappingURL=event-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"event-store.d.ts","sourceRoot":"","sources":["../src/event-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;aAEtB,IAAI,EAAE,MAAM;aAEZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAFjC,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAKpD;AAED;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,UAAU;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoC;IAErE;;;;OAIG;IACG,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA2C/C;;;OAGG;IACH,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAMtD;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAI9D;;;OAGG;IACH,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAIrE;;OAEG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAShD;;OAEG;IACH,KAAK,IAAI,IAAI;CAKd;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,kBAAkB,CAE7D"}
1
+ {"version":3,"file":"event-store.d.ts","sourceRoot":"","sources":["../src/event-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;aAEtB,IAAI,EAAE,MAAM;aAEZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAFjC,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAKpD;AAQD;;;;;GAKG;AACH,qBAAa,kBAAmB,YAAW,UAAU;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoC;IACrE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,SAAS,GAAE,MAA2B;IAIlD;;;;OAIG;IACG,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAgD/C;;;OAGG;IACH,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAMtD;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAI9D;;;OAGG;IACH,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAIrE;;;OAGG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBhD;;;OAGG;IACH,OAAO,CAAC,WAAW;IAmCnB;;OAEG;IACH,KAAK,IAAI,IAAI;CAKd;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAE/E"}
@@ -12,15 +12,25 @@ export class EventStoreError extends Error {
12
12
  this.name = 'EventStoreError';
13
13
  }
14
14
  }
15
+ /**
16
+ * Default maximum events to store before eviction
17
+ * INV-MEM-006: Memory growth is bounded
18
+ */
19
+ const DEFAULT_MAX_EVENTS = 100000;
15
20
  /**
16
21
  * In-memory event store implementation
17
22
  * INV-MEM-001: Events are immutable - stored as frozen objects
18
23
  * INV-MEM-004: Events are ordered by version within aggregate
24
+ * INV-MEM-006: Memory growth is bounded with LRU eviction
19
25
  */
20
26
  export class InMemoryEventStore {
21
27
  events = new Map();
22
28
  allEvents = [];
23
29
  correlationIndex = new Map();
30
+ maxEvents;
31
+ constructor(maxEvents = DEFAULT_MAX_EVENTS) {
32
+ this.maxEvents = maxEvents;
33
+ }
24
34
  /**
25
35
  * Appends an event to the store
26
36
  * INV-MEM-001: Events are immutable
@@ -47,6 +57,10 @@ export class InMemoryEventStore {
47
57
  this.events.set(aggregateId, aggregateEvents);
48
58
  // Store in global list
49
59
  this.allEvents.push(frozenEvent);
60
+ // INV-MEM-006: Evict oldest events if over limit to prevent unbounded memory growth
61
+ if (this.allEvents.length > this.maxEvents) {
62
+ this.evictOldest(this.allEvents.length - this.maxEvents);
63
+ }
50
64
  // Index by correlation ID (INV-MEM-005)
51
65
  if (event.metadata?.correlationId !== undefined) {
52
66
  const correlatedEvents = this.correlationIndex.get(event.metadata.correlationId) ?? [];
@@ -78,6 +92,7 @@ export class InMemoryEventStore {
78
92
  }
79
93
  /**
80
94
  * Gets the current version for an aggregate
95
+ * INV-MEM-007: Version calculation handles edge cases correctly
81
96
  */
82
97
  getVersion(aggregateId) {
83
98
  const events = this.events.get(aggregateId) ?? [];
@@ -85,7 +100,50 @@ export class InMemoryEventStore {
85
100
  return Promise.resolve(0);
86
101
  }
87
102
  const lastEvent = events[events.length - 1];
88
- return Promise.resolve(lastEvent?.version ?? events.length);
103
+ // INV-MEM-007: Explicit undefined check - version 0 is valid, undefined means use length
104
+ if (lastEvent === undefined) {
105
+ return Promise.resolve(0);
106
+ }
107
+ if (lastEvent.version === undefined) {
108
+ return Promise.resolve(events.length);
109
+ }
110
+ return Promise.resolve(lastEvent.version);
111
+ }
112
+ /**
113
+ * Evicts the oldest events to maintain memory bounds
114
+ * INV-MEM-006: LRU eviction when over maxEvents
115
+ */
116
+ evictOldest(count) {
117
+ // Remove from global list
118
+ const evicted = this.allEvents.splice(0, count);
119
+ // Remove from aggregate buckets and correlation index
120
+ // INV-MEM-007: Use eventId comparison instead of reference equality for robustness
121
+ for (const event of evicted) {
122
+ const aggregateId = event.aggregateId ?? 'global';
123
+ const aggregateEvents = this.events.get(aggregateId);
124
+ if (aggregateEvents) {
125
+ const index = aggregateEvents.findIndex((e) => e.eventId === event.eventId);
126
+ if (index !== -1) {
127
+ aggregateEvents.splice(index, 1);
128
+ }
129
+ if (aggregateEvents.length === 0) {
130
+ this.events.delete(aggregateId);
131
+ }
132
+ }
133
+ // Remove from correlation index
134
+ if (event.metadata?.correlationId) {
135
+ const correlatedEvents = this.correlationIndex.get(event.metadata.correlationId);
136
+ if (correlatedEvents) {
137
+ const index = correlatedEvents.findIndex((e) => e.eventId === event.eventId);
138
+ if (index !== -1) {
139
+ correlatedEvents.splice(index, 1);
140
+ }
141
+ if (correlatedEvents.length === 0) {
142
+ this.correlationIndex.delete(event.metadata.correlationId);
143
+ }
144
+ }
145
+ }
146
+ }
89
147
  }
90
148
  /**
91
149
  * Clears all events (for testing)
@@ -98,8 +156,9 @@ export class InMemoryEventStore {
98
156
  }
99
157
  /**
100
158
  * Creates an in-memory event store
159
+ * @param maxEvents Maximum events to store before eviction (default: 100000)
101
160
  */
102
- export function createInMemoryEventStore() {
103
- return new InMemoryEventStore();
161
+ export function createInMemoryEventStore(maxEvents) {
162
+ return new InMemoryEventStore(maxEvents);
104
163
  }
105
164
  //# sourceMappingURL=event-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"event-store.js","sourceRoot":"","sources":["../src/event-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"event-store.js","sourceRoot":"","sources":["../src/event-store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defai.digital/memory-domain",
3
- "version": "13.4.5",
3
+ "version": "13.4.8",
4
4
  "type": "module",
5
5
  "description": "Memory domain - event sourcing following contract invariants",
6
6
  "license": "BUSL-1.1",
@@ -32,7 +32,7 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@defai.digital/contracts": "13.4.5"
35
+ "@defai.digital/contracts": "13.4.8"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "tsc --build",