@magek/adapter-event-store-memory 0.0.10

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.
@@ -0,0 +1,4 @@
1
+ import { EventStoreAdapter, EventEnvelope } from '@magek/common';
2
+ export declare function rawEventsToEnvelopes(rawEvents: Array<unknown>): Array<EventEnvelope>;
3
+ export declare const eventStore: EventStoreAdapter;
4
+ export { MemoryEventRegistry } from './memory-event-registry';
package/dist/index.js ADDED
@@ -0,0 +1,306 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemoryEventRegistry = exports.eventStore = void 0;
4
+ exports.rawEventsToEnvelopes = rawEventsToEnvelopes;
5
+ const common_1 = require("@magek/common");
6
+ const memory_event_registry_1 = require("./memory-event-registry");
7
+ // Pre-built Memory Event Store Adapter instance
8
+ const eventRegistry = new memory_event_registry_1.MemoryEventRegistry();
9
+ const originOfTime = new Date(0).toISOString();
10
+ // In-memory cursor for async event processing
11
+ let processingCursor = originOfTime;
12
+ function notImplemented() {
13
+ throw new Error('Not implemented for Memory adapter');
14
+ }
15
+ function rawEventsToEnvelopes(rawEvents) {
16
+ return rawEvents.map((event) => event);
17
+ }
18
+ async function readEntityEventsSince(registry, config, entityTypeName, entityID, since) {
19
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#readEntityEventsSince');
20
+ const fromTime = since ? since : originOfTime;
21
+ const query = {
22
+ entityID: entityID,
23
+ entityTypeName: entityTypeName,
24
+ kind: 'event',
25
+ createdAt: {
26
+ $gt: fromTime,
27
+ },
28
+ deletedAt: { $exists: false },
29
+ };
30
+ const result = await registry.query(query);
31
+ logger.debug(`Loaded events for entity ${entityTypeName} with ID ${entityID} with result:`, result);
32
+ return result;
33
+ }
34
+ async function readEntityLatestSnapshot(registry, config, entityTypeName, entityID) {
35
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#readEntityLatestSnapshot');
36
+ const query = {
37
+ entityID: entityID,
38
+ entityTypeName: entityTypeName,
39
+ kind: 'snapshot',
40
+ };
41
+ const snapshot = await registry.queryLatestSnapshot(query);
42
+ if (snapshot) {
43
+ logger.debug(`Snapshot found for entity ${entityTypeName} with ID ${entityID}:`, snapshot);
44
+ return snapshot;
45
+ }
46
+ else {
47
+ logger.debug(`No snapshot found for entity ${entityTypeName} with ID ${entityID}.`);
48
+ return undefined;
49
+ }
50
+ }
51
+ async function storeEvents(registry, nonPersistedEventEnvelopes, config) {
52
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#storeEvents');
53
+ logger.debug('Storing the following event envelopes:', nonPersistedEventEnvelopes);
54
+ const persistedEventEnvelopes = [];
55
+ for (const nonPersistedEventEnvelope of nonPersistedEventEnvelopes) {
56
+ const persistableEventEnvelope = {
57
+ ...nonPersistedEventEnvelope,
58
+ createdAt: new Date().toISOString(),
59
+ };
60
+ await (0, common_1.retryIfError)(async () => await registry.store(persistableEventEnvelope), common_1.OptimisticConcurrencyUnexpectedVersionError);
61
+ persistedEventEnvelopes.push(persistableEventEnvelope);
62
+ }
63
+ logger.debug('EventEnvelopes stored: ', persistedEventEnvelopes);
64
+ return persistedEventEnvelopes;
65
+ }
66
+ async function storeSnapshot(registry, snapshotEnvelope, config) {
67
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#storeSnapshot');
68
+ logger.debug('Storing the following snapshot envelope:', snapshotEnvelope);
69
+ const persistableEntitySnapshot = {
70
+ ...snapshotEnvelope,
71
+ createdAt: snapshotEnvelope.snapshottedEventCreatedAt,
72
+ persistedAt: new Date().toISOString(),
73
+ };
74
+ await (0, common_1.retryIfError)(() => registry.store(persistableEntitySnapshot), common_1.OptimisticConcurrencyUnexpectedVersionError);
75
+ logger.debug('Snapshot stored');
76
+ return persistableEntitySnapshot;
77
+ }
78
+ async function storeDispatchedEvent(registry, eventEnvelope) {
79
+ const eventId = eventEnvelope.id || `${eventEnvelope.entityTypeName}:${eventEnvelope.entityID}:${eventEnvelope.createdAt}`;
80
+ return registry.storeDispatched(eventId);
81
+ }
82
+ async function fetchUnprocessedEvents(registry, config) {
83
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#fetchUnprocessedEvents');
84
+ const batchSize = config.eventProcessingBatchSize;
85
+ const query = {
86
+ kind: 'event',
87
+ deletedAt: { $exists: false },
88
+ processedAt: { $exists: false },
89
+ createdAt: { $gt: processingCursor },
90
+ };
91
+ logger.debug(`Fetching events after cursor ${processingCursor} (batch size: ${batchSize})`);
92
+ const result = await registry.query(query, 'asc', batchSize);
93
+ logger.debug(`Fetched ${result.length} unprocessed events`);
94
+ return result;
95
+ }
96
+ async function markEventProcessed(registry, config, eventId) {
97
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#markEventProcessed');
98
+ const processedAt = new Date().toISOString();
99
+ const events = await registry.query({ _id: eventId.toString(), kind: 'event' });
100
+ if (events.length === 0) {
101
+ logger.warn(`Event ${eventId} not found, cannot mark as processed`);
102
+ return;
103
+ }
104
+ const event = events[0];
105
+ logger.debug(`Marking event ${eventId} as processed at ${processedAt}`);
106
+ await registry.markProcessed(eventId.toString(), processedAt);
107
+ processingCursor = event.createdAt;
108
+ logger.debug(`Cursor advanced to ${processingCursor}`);
109
+ }
110
+ function buildFiltersForByTime(fromValue, toValue) {
111
+ if (fromValue && toValue) {
112
+ return {
113
+ createdAt: { $gte: fromValue, $lte: toValue },
114
+ };
115
+ }
116
+ else if (fromValue) {
117
+ return {
118
+ createdAt: { $gte: fromValue },
119
+ };
120
+ }
121
+ else if (toValue) {
122
+ return {
123
+ createdAt: { $lte: toValue },
124
+ };
125
+ }
126
+ return {};
127
+ }
128
+ function buildFiltersForByFilters(filters) {
129
+ if ('entity' in filters) {
130
+ if (filters.entityID) {
131
+ return {
132
+ entityTypeName: filters.entity,
133
+ entityID: filters.entityID,
134
+ };
135
+ }
136
+ return {
137
+ entityTypeName: filters.entity,
138
+ };
139
+ }
140
+ else if ('type' in filters) {
141
+ return {
142
+ typeName: filters.type,
143
+ };
144
+ }
145
+ else {
146
+ throw new Error('Invalid search event query. It is neither an search by "entity" nor a search by "type"');
147
+ }
148
+ }
149
+ function resultToEventSearchResponse(result) {
150
+ if (!result || result.length === 0)
151
+ return [];
152
+ const eventSearchResult = result.map((item) => {
153
+ return {
154
+ type: item.typeName,
155
+ entity: item.entityTypeName,
156
+ entityID: item.entityID,
157
+ requestID: item.requestID,
158
+ user: item.currentUser,
159
+ createdAt: item.createdAt,
160
+ value: item.value,
161
+ deletedAt: item.deletedAt,
162
+ };
163
+ });
164
+ return eventSearchResult ?? [];
165
+ }
166
+ async function searchEvents(registry, config, parameters) {
167
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#searchEvents');
168
+ logger.debug('Initiating an events search. Filters: ', parameters);
169
+ const timeFilterQuery = buildFiltersForByTime(parameters.from, parameters.to);
170
+ const eventFilterQuery = buildFiltersForByFilters(parameters);
171
+ const filterQuery = { ...eventFilterQuery, ...timeFilterQuery, kind: 'event' };
172
+ const result = (await registry.query(filterQuery, 'desc', parameters.limit));
173
+ const eventsSearchResponses = resultToEventSearchResponse(result);
174
+ logger.debug('Events search result: ', eventsSearchResponses);
175
+ return eventsSearchResponses;
176
+ }
177
+ async function searchEntitiesIds(registry, config, limit, afterCursor, entityTypeName) {
178
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#searchEntitiesIds');
179
+ logger.debug(`Initiating a paginated events search. limit: ${limit}, afterCursor: ${JSON.stringify(afterCursor)}, entityTypeName: ${entityTypeName}`);
180
+ const filterQuery = {
181
+ kind: 'event',
182
+ entityTypeName: entityTypeName,
183
+ deletedAt: { $exists: false },
184
+ };
185
+ const result = (await registry.query(filterQuery, 'desc'));
186
+ const entitiesIds = result ? result?.map((v) => v.entityID) : [];
187
+ const uniqueResult = (0, common_1.unique)(entitiesIds);
188
+ const skipId = afterCursor?.id ? parseInt(afterCursor?.id) : 0;
189
+ const paginated = uniqueResult.slice(skipId, skipId + limit);
190
+ const paginatedResult = paginated.map((v) => ({ entityID: v }));
191
+ logger.debug('Unique events search result', paginatedResult);
192
+ return {
193
+ items: paginatedResult,
194
+ count: paginatedResult?.length ?? 0,
195
+ cursor: { id: ((limit ? limit : 1) + skipId).toString() },
196
+ };
197
+ }
198
+ async function findDeletableEvent(registry, config, parameters) {
199
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#findDeletableEvent');
200
+ const stringifyParameters = JSON.stringify(parameters);
201
+ logger.debug(`Initiating a deletable event search for ${stringifyParameters}`);
202
+ const filter = {
203
+ entityTypeName: parameters.entityTypeName,
204
+ entityID: parameters.entityID,
205
+ createdAt: parameters.createdAt,
206
+ kind: 'event',
207
+ deletedAt: { $exists: false },
208
+ };
209
+ const events = (await registry.query(filter));
210
+ const result = events.map((event) => {
211
+ return {
212
+ ...event,
213
+ id: event.id,
214
+ };
215
+ });
216
+ logger.debug(`Finished deletable event search for ${stringifyParameters}`);
217
+ return result;
218
+ }
219
+ async function findDeletableSnapshot(registry, config, parameters) {
220
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#findDeletableSnapshot');
221
+ const stringifyParameters = JSON.stringify(parameters);
222
+ logger.debug(`Initiating a deletable snapshot search for ${stringifyParameters}`);
223
+ const filter = {
224
+ entityTypeName: parameters.entityTypeName,
225
+ entityID: parameters.entityID,
226
+ createdAt: parameters.createdAt,
227
+ kind: 'snapshot',
228
+ deletedAt: { $exists: false },
229
+ };
230
+ const snapshots = (await registry.query(filter));
231
+ const result = snapshots.map((snapshot) => {
232
+ return {
233
+ ...snapshot,
234
+ id: snapshot.id,
235
+ };
236
+ });
237
+ logger.debug(`Finished deletable snapshot search for ${stringifyParameters}`);
238
+ return result;
239
+ }
240
+ function buildNewEvent(existingEvent) {
241
+ return {
242
+ ...existingEvent,
243
+ deletedAt: new Date().toISOString(),
244
+ value: {},
245
+ };
246
+ }
247
+ async function deleteEvent(registry, config, events) {
248
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#deleteEvent');
249
+ const stringifyParameters = JSON.stringify(events);
250
+ logger.debug(`Initiating an event delete for ${stringifyParameters}`);
251
+ if (!events || events.length === 0) {
252
+ logger.warn('Could not find events to delete');
253
+ return;
254
+ }
255
+ for (const event of events) {
256
+ const newEvent = buildNewEvent(event);
257
+ await registry.replaceOrDeleteItem(event.id, newEvent);
258
+ }
259
+ logger.debug(`Finished event delete for ${stringifyParameters}`);
260
+ }
261
+ async function deleteSnapshot(registry, config, snapshots) {
262
+ const logger = (0, common_1.getLogger)(config, 'memory-events-adapter#deleteSnapshot');
263
+ const stringifyParameters = JSON.stringify(snapshots);
264
+ logger.debug(`Initiating a snapshot delete for ${stringifyParameters}`);
265
+ if (!snapshots || snapshots.length === 0) {
266
+ logger.warn('Could not find snapshot to delete');
267
+ return;
268
+ }
269
+ for (const snapshot of snapshots) {
270
+ await registry.replaceOrDeleteItem(snapshot.id);
271
+ }
272
+ logger.debug(`Finished snapshot delete for ${stringifyParameters}`);
273
+ }
274
+ exports.eventStore = {
275
+ rawToEnvelopes: rawEventsToEnvelopes,
276
+ rawStreamToEnvelopes: notImplemented,
277
+ dedupEventStream: notImplemented,
278
+ produce: notImplemented,
279
+ forEntitySince: (config, entityTypeName, entityID, since) => readEntityEventsSince(eventRegistry, config, entityTypeName, entityID, since),
280
+ latestEntitySnapshot: (config, entityTypeName, entityID) => readEntityLatestSnapshot(eventRegistry, config, entityTypeName, entityID),
281
+ store: (eventEnvelopes, config) => storeEvents(eventRegistry, eventEnvelopes, config),
282
+ storeSnapshot: (snapshotEnvelope, config) => storeSnapshot(eventRegistry, snapshotEnvelope, config),
283
+ search: (config, parameters) => searchEvents(eventRegistry, config, parameters),
284
+ searchEntitiesIDs: (config, limit, afterCursor, entityTypeName) => searchEntitiesIds(eventRegistry, config, limit, afterCursor, entityTypeName),
285
+ storeDispatched: (eventEnvelope, config) => storeDispatchedEvent(eventRegistry, eventEnvelope),
286
+ findDeletableEvent: (config, parameters) => findDeletableEvent(eventRegistry, config, parameters),
287
+ findDeletableSnapshot: (config, parameters) => findDeletableSnapshot(eventRegistry, config, parameters),
288
+ deleteEvent: (config, events) => deleteEvent(eventRegistry, config, events),
289
+ deleteSnapshot: (config, snapshots) => deleteSnapshot(eventRegistry, config, snapshots),
290
+ healthCheck: {
291
+ isUp: async () => true,
292
+ details: async () => {
293
+ return {
294
+ type: 'memory',
295
+ eventsCount: eventRegistry.getEventsCount(),
296
+ snapshotsCount: eventRegistry.getSnapshotsCount(),
297
+ };
298
+ },
299
+ urls: async () => ['memory://in-memory-event-store'],
300
+ },
301
+ fetchUnprocessedEvents: (config) => fetchUnprocessedEvents(eventRegistry, config),
302
+ markEventProcessed: (config, eventId) => markEventProcessed(eventRegistry, config, eventId),
303
+ };
304
+ // Export components for testing
305
+ var memory_event_registry_2 = require("./memory-event-registry");
306
+ Object.defineProperty(exports, "MemoryEventRegistry", { enumerable: true, get: function () { return memory_event_registry_2.MemoryEventRegistry; } });
@@ -0,0 +1,45 @@
1
+ import { EntitySnapshotEnvelope, EventEnvelope, UUID } from '@magek/common';
2
+ export declare class MemoryEventRegistry {
3
+ private events;
4
+ private snapshots;
5
+ private dispatched;
6
+ private eventsByEntity;
7
+ private snapshotsByEntity;
8
+ private eventIdCounter;
9
+ private snapshotIdCounter;
10
+ private generateEventId;
11
+ private generateSnapshotId;
12
+ private getEntityKey;
13
+ query(query: QueryFilter, sortOrder?: 'asc' | 'desc', limit?: number): Promise<Array<EventEnvelope | EntitySnapshotEnvelope>>;
14
+ queryLatestSnapshot(query: QueryFilter): Promise<EntitySnapshotEnvelope | undefined>;
15
+ store(envelope: EventEnvelope | EntitySnapshotEnvelope): Promise<string>;
16
+ storeDispatched(eventId: string): Promise<boolean>;
17
+ replaceOrDeleteItem(id: string, newValue?: EventEnvelope | EntitySnapshotEnvelope): Promise<void>;
18
+ deleteAll(): Promise<number>;
19
+ count(query?: QueryFilter): Promise<number>;
20
+ getEventsCount(): number;
21
+ getSnapshotsCount(): number;
22
+ private matchesFilter;
23
+ markProcessed(id: string, processedAt: string): Promise<void>;
24
+ }
25
+ interface CreatedAtConditions {
26
+ $gt?: string;
27
+ $gte?: string;
28
+ $lt?: string;
29
+ $lte?: string;
30
+ }
31
+ export interface QueryFilter {
32
+ kind?: 'event' | 'snapshot';
33
+ entityTypeName?: string;
34
+ entityID?: UUID;
35
+ typeName?: string;
36
+ createdAt?: string | CreatedAtConditions;
37
+ deletedAt?: {
38
+ $exists: boolean;
39
+ };
40
+ processedAt?: {
41
+ $exists: boolean;
42
+ };
43
+ _id?: string;
44
+ }
45
+ export {};
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemoryEventRegistry = void 0;
4
+ class MemoryEventRegistry {
5
+ events = new Map();
6
+ snapshots = new Map();
7
+ dispatched = new Set();
8
+ eventsByEntity = new Map();
9
+ snapshotsByEntity = new Map();
10
+ eventIdCounter = 0;
11
+ snapshotIdCounter = 0;
12
+ generateEventId() {
13
+ return `evt-${++this.eventIdCounter}-${Date.now()}`;
14
+ }
15
+ generateSnapshotId() {
16
+ return `snap-${++this.snapshotIdCounter}-${Date.now()}`;
17
+ }
18
+ getEntityKey(entityTypeName, entityID) {
19
+ return `${entityTypeName}:${entityID}`;
20
+ }
21
+ async query(query, sortOrder = 'asc', limit) {
22
+ const results = [];
23
+ // Query events
24
+ if (!query.kind || query.kind === 'event') {
25
+ for (const event of Array.from(this.events.values())) {
26
+ if (this.matchesFilter(event, query)) {
27
+ results.push(event);
28
+ }
29
+ }
30
+ }
31
+ // Query snapshots
32
+ if (query.kind === 'snapshot') {
33
+ for (const snapshot of Array.from(this.snapshots.values())) {
34
+ if (this.matchesFilter(snapshot, query)) {
35
+ results.push(snapshot);
36
+ }
37
+ }
38
+ }
39
+ // Sort by createdAt
40
+ results.sort((a, b) => {
41
+ const aTime = new Date(a.createdAt ?? 0).getTime();
42
+ const bTime = new Date(b.createdAt ?? 0).getTime();
43
+ return sortOrder === 'asc' ? aTime - bTime : bTime - aTime;
44
+ });
45
+ // Apply limit
46
+ if (limit && limit > 0) {
47
+ return results.slice(0, limit);
48
+ }
49
+ return results;
50
+ }
51
+ async queryLatestSnapshot(query) {
52
+ const matchingSnapshots = [];
53
+ for (const snapshot of Array.from(this.snapshots.values())) {
54
+ if (this.matchesFilter(snapshot, { ...query, kind: 'snapshot' })) {
55
+ matchingSnapshots.push(snapshot);
56
+ }
57
+ }
58
+ if (matchingSnapshots.length === 0) {
59
+ return undefined;
60
+ }
61
+ // Sort by snapshottedEventCreatedAt descending and return the first one
62
+ matchingSnapshots.sort((a, b) => {
63
+ const aTime = new Date(a.snapshottedEventCreatedAt).getTime();
64
+ const bTime = new Date(b.snapshottedEventCreatedAt).getTime();
65
+ return bTime - aTime;
66
+ });
67
+ return matchingSnapshots[0];
68
+ }
69
+ async store(envelope) {
70
+ if (envelope.kind === 'event') {
71
+ const eventEnvelope = envelope;
72
+ const id = this.generateEventId();
73
+ const storedEnvelope = { ...eventEnvelope, id };
74
+ this.events.set(id, storedEnvelope);
75
+ // Index by entity
76
+ const entityKey = this.getEntityKey(eventEnvelope.entityTypeName, eventEnvelope.entityID);
77
+ if (!this.eventsByEntity.has(entityKey)) {
78
+ this.eventsByEntity.set(entityKey, new Set());
79
+ }
80
+ this.eventsByEntity.get(entityKey).add(id);
81
+ return id;
82
+ }
83
+ else {
84
+ const snapshotEnvelope = envelope;
85
+ const id = this.generateSnapshotId();
86
+ const storedEnvelope = { ...snapshotEnvelope, id };
87
+ this.snapshots.set(id, storedEnvelope);
88
+ // Index by entity
89
+ const entityKey = this.getEntityKey(snapshotEnvelope.entityTypeName, snapshotEnvelope.entityID);
90
+ if (!this.snapshotsByEntity.has(entityKey)) {
91
+ this.snapshotsByEntity.set(entityKey, new Set());
92
+ }
93
+ this.snapshotsByEntity.get(entityKey).add(id);
94
+ return id;
95
+ }
96
+ }
97
+ async storeDispatched(eventId) {
98
+ if (this.dispatched.has(eventId)) {
99
+ return false;
100
+ }
101
+ this.dispatched.add(eventId);
102
+ return true;
103
+ }
104
+ async replaceOrDeleteItem(id, newValue) {
105
+ // Check in events
106
+ if (this.events.has(id)) {
107
+ if (newValue) {
108
+ this.events.set(id, newValue);
109
+ }
110
+ else {
111
+ const event = this.events.get(id);
112
+ const entityKey = this.getEntityKey(event.entityTypeName, event.entityID);
113
+ this.eventsByEntity.get(entityKey)?.delete(id);
114
+ this.events.delete(id);
115
+ }
116
+ return;
117
+ }
118
+ // Check in snapshots
119
+ if (this.snapshots.has(id)) {
120
+ if (newValue) {
121
+ this.snapshots.set(id, newValue);
122
+ }
123
+ else {
124
+ const snapshot = this.snapshots.get(id);
125
+ const entityKey = this.getEntityKey(snapshot.entityTypeName, snapshot.entityID);
126
+ this.snapshotsByEntity.get(entityKey)?.delete(id);
127
+ this.snapshots.delete(id);
128
+ }
129
+ }
130
+ }
131
+ async deleteAll() {
132
+ const count = this.events.size + this.snapshots.size;
133
+ this.events.clear();
134
+ this.snapshots.clear();
135
+ this.dispatched.clear();
136
+ this.eventsByEntity.clear();
137
+ this.snapshotsByEntity.clear();
138
+ return count;
139
+ }
140
+ async count(query) {
141
+ if (!query) {
142
+ return this.events.size + this.snapshots.size;
143
+ }
144
+ let count = 0;
145
+ if (!query.kind || query.kind === 'event') {
146
+ for (const event of Array.from(this.events.values())) {
147
+ if (this.matchesFilter(event, query)) {
148
+ count++;
149
+ }
150
+ }
151
+ }
152
+ if (query.kind === 'snapshot') {
153
+ for (const snapshot of Array.from(this.snapshots.values())) {
154
+ if (this.matchesFilter(snapshot, query)) {
155
+ count++;
156
+ }
157
+ }
158
+ }
159
+ return count;
160
+ }
161
+ getEventsCount() {
162
+ return this.events.size;
163
+ }
164
+ getSnapshotsCount() {
165
+ return this.snapshots.size;
166
+ }
167
+ matchesFilter(envelope, query) {
168
+ // Check _id
169
+ if (query._id && envelope.id !== query._id) {
170
+ return false;
171
+ }
172
+ // Check kind
173
+ if (query.kind && envelope.kind !== query.kind) {
174
+ return false;
175
+ }
176
+ // Check entityTypeName
177
+ if (query.entityTypeName && envelope.entityTypeName !== query.entityTypeName) {
178
+ return false;
179
+ }
180
+ // Check entityID
181
+ if (query.entityID && envelope.entityID !== query.entityID) {
182
+ return false;
183
+ }
184
+ // Check typeName
185
+ if (query.typeName && envelope.typeName !== query.typeName) {
186
+ return false;
187
+ }
188
+ // Check createdAt conditions
189
+ const envelopeCreatedAt = envelope.createdAt;
190
+ if (query.createdAt && envelopeCreatedAt) {
191
+ if (typeof query.createdAt === 'object') {
192
+ const conditions = query.createdAt;
193
+ const envelopeTime = new Date(envelopeCreatedAt).getTime();
194
+ if (conditions.$gt) {
195
+ const gtTime = new Date(conditions.$gt).getTime();
196
+ if (envelopeTime <= gtTime)
197
+ return false;
198
+ }
199
+ if (conditions.$gte) {
200
+ const gteTime = new Date(conditions.$gte).getTime();
201
+ if (envelopeTime < gteTime)
202
+ return false;
203
+ }
204
+ if (conditions.$lt) {
205
+ const ltTime = new Date(conditions.$lt).getTime();
206
+ if (envelopeTime >= ltTime)
207
+ return false;
208
+ }
209
+ if (conditions.$lte) {
210
+ const lteTime = new Date(conditions.$lte).getTime();
211
+ if (envelopeTime > lteTime)
212
+ return false;
213
+ }
214
+ }
215
+ else if (envelopeCreatedAt !== query.createdAt) {
216
+ return false;
217
+ }
218
+ }
219
+ // Check deletedAt exists condition
220
+ if (query.deletedAt !== undefined) {
221
+ if (typeof query.deletedAt === 'object' && '$exists' in query.deletedAt) {
222
+ const hasDeletedAt = envelope.deletedAt !== undefined;
223
+ if (query.deletedAt.$exists !== hasDeletedAt)
224
+ return false;
225
+ }
226
+ }
227
+ // Check processedAt exists condition
228
+ if (query.processedAt !== undefined) {
229
+ if (typeof query.processedAt === 'object' && '$exists' in query.processedAt) {
230
+ const hasProcessedAt = envelope.processedAt !== undefined;
231
+ if (query.processedAt.$exists !== hasProcessedAt)
232
+ return false;
233
+ }
234
+ }
235
+ return true;
236
+ }
237
+ async markProcessed(id, processedAt) {
238
+ const event = this.events.get(id);
239
+ if (event) {
240
+ this.events.set(id, { ...event, processedAt });
241
+ }
242
+ }
243
+ }
244
+ exports.MemoryEventRegistry = MemoryEventRegistry;
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@magek/adapter-event-store-memory",
3
+ "version": "0.0.10",
4
+ "description": "In-memory event store adapter for the Magek framework",
5
+ "keywords": [
6
+ "event-store",
7
+ "memory",
8
+ "in-memory"
9
+ ],
10
+ "author": "Boosterin Labs SLU",
11
+ "homepage": "https://magek.ai",
12
+ "license": "Apache-2.0",
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "main": "dist/index.js",
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/theam/magek.git"
23
+ },
24
+ "engines": {
25
+ "node": ">=22.0.0 <23.0.0"
26
+ },
27
+ "dependencies": {
28
+ "@magek/common": "workspace:^0.0.10",
29
+ "tslib": "2.8.1"
30
+ },
31
+ "scripts": {
32
+ "format": "prettier --write --ext '.js,.ts' **/*.ts **/*/*.ts",
33
+ "lint:check": "eslint \"**/*.ts\"",
34
+ "lint:fix": "eslint --quiet --fix \"**/*.ts\"",
35
+ "build": "tsc -b tsconfig.json",
36
+ "clean": "rimraf ./dist tsconfig.tsbuildinfo",
37
+ "prepack": "tsc -b tsconfig.json",
38
+ "test": "tsc --noEmit -p tsconfig.test.json && c8 mocha --forbid-only \"test/**/*.test.ts\""
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/theam/magek/issues"
42
+ },
43
+ "devDependencies": {
44
+ "@magek/eslint-config": "workspace:^0.0.10",
45
+ "@types/chai": "5.2.3",
46
+ "@types/chai-as-promised": "8.0.2",
47
+ "@types/mocha": "10.0.10",
48
+ "@types/node": "22.19.8",
49
+ "@types/sinon": "21.0.0",
50
+ "@types/sinon-chai": "4.0.0",
51
+ "chai": "6.2.2",
52
+ "chai-as-promised": "8.0.2",
53
+ "@faker-js/faker": "10.2.0",
54
+ "mocha": "11.7.5",
55
+ "c8": "^10.1.3",
56
+ "rimraf": "6.1.2",
57
+ "sinon": "21.0.1",
58
+ "sinon-chai": "4.0.1",
59
+ "tsx": "^4.19.2",
60
+ "typescript": "5.9.3"
61
+ }
62
+ }