@defai.digital/sqlite-adapter 13.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.
@@ -0,0 +1,307 @@
1
+ /**
2
+ * SQLite Dead Letter Storage Implementation
3
+ *
4
+ * Persistent storage for dead letter queue entries.
5
+ *
6
+ * Invariants:
7
+ * - INV-DLQ-001: Failed events captured with full context
8
+ * - INV-DLQ-002: Retries respect maxRetries limit
9
+ * - INV-DLQ-003: Exhausted entries marked appropriately
10
+ */
11
+ /**
12
+ * Error thrown by SQLite dead letter store operations
13
+ */
14
+ export class SqliteDeadLetterStoreError extends Error {
15
+ code;
16
+ details;
17
+ constructor(code, message, details) {
18
+ super(message);
19
+ this.code = code;
20
+ this.details = details;
21
+ this.name = 'SqliteDeadLetterStoreError';
22
+ }
23
+ }
24
+ /**
25
+ * Error codes for SQLite dead letter store
26
+ */
27
+ export const SqliteDeadLetterStoreErrorCodes = {
28
+ DATABASE_ERROR: 'SQLITE_DLQ_DATABASE_ERROR',
29
+ INVALID_ENTRY: 'SQLITE_DLQ_INVALID_ENTRY',
30
+ SERIALIZATION_ERROR: 'SQLITE_DLQ_SERIALIZATION_ERROR',
31
+ INVALID_TABLE_NAME: 'SQLITE_DLQ_INVALID_TABLE_NAME',
32
+ };
33
+ /**
34
+ * Validates a SQL table name to prevent SQL injection
35
+ * Only allows alphanumeric characters and underscores, must start with letter or underscore
36
+ */
37
+ function isValidTableName(name) {
38
+ return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name) && name.length <= 64;
39
+ }
40
+ /**
41
+ * SQLite implementation of DeadLetterStorage
42
+ *
43
+ * Invariants:
44
+ * - INV-DLQ-001: All entry data is serialized and stored
45
+ * - INV-DLQ-002: Status transitions tracked via updates
46
+ * - INV-DLQ-003: countByStatus provides accurate status breakdown
47
+ */
48
+ export class SqliteDeadLetterStorage {
49
+ db;
50
+ tableName;
51
+ constructor(db, tableName = 'dead_letter_entries') {
52
+ // Validate table name to prevent SQL injection
53
+ if (!isValidTableName(tableName)) {
54
+ throw new SqliteDeadLetterStoreError(SqliteDeadLetterStoreErrorCodes.INVALID_TABLE_NAME, `Invalid table name: ${tableName}. Must start with letter or underscore, contain only alphanumeric and underscores, max 64 chars.`);
55
+ }
56
+ this.db = db;
57
+ this.tableName = tableName;
58
+ this.initialize();
59
+ }
60
+ /**
61
+ * Initializes the database schema
62
+ */
63
+ initialize() {
64
+ this.db.exec(`
65
+ CREATE TABLE IF NOT EXISTS ${this.tableName} (
66
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
67
+ entry_id TEXT NOT NULL UNIQUE,
68
+ original_event_id TEXT NOT NULL,
69
+ event_type TEXT NOT NULL,
70
+ event_payload TEXT,
71
+ error TEXT NOT NULL,
72
+ retry_count INTEGER NOT NULL DEFAULT 0,
73
+ max_retries INTEGER NOT NULL,
74
+ last_retry_at TEXT,
75
+ next_retry_at TEXT,
76
+ status TEXT NOT NULL,
77
+ created_at TEXT NOT NULL,
78
+ correlation_id TEXT,
79
+ source TEXT NOT NULL,
80
+ context TEXT,
81
+ resolution_notes TEXT,
82
+ resolved_by TEXT,
83
+ resolved_at TEXT
84
+ );
85
+
86
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_status
87
+ ON ${this.tableName}(status);
88
+
89
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_source
90
+ ON ${this.tableName}(source);
91
+
92
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_event_type
93
+ ON ${this.tableName}(event_type);
94
+
95
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_created_at
96
+ ON ${this.tableName}(created_at DESC);
97
+
98
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_next_retry_at
99
+ ON ${this.tableName}(next_retry_at);
100
+
101
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_status_next_retry
102
+ ON ${this.tableName}(status, next_retry_at);
103
+ `);
104
+ }
105
+ /**
106
+ * Add entry to DLQ
107
+ * INV-DLQ-001: All context captured
108
+ */
109
+ async add(entry) {
110
+ try {
111
+ const stmt = this.db.prepare(`
112
+ INSERT INTO ${this.tableName} (
113
+ entry_id, original_event_id, event_type, event_payload,
114
+ error, retry_count, max_retries, last_retry_at, next_retry_at,
115
+ status, created_at, correlation_id, source, context,
116
+ resolution_notes, resolved_by, resolved_at
117
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
118
+ `);
119
+ stmt.run(entry.entryId, entry.originalEventId, entry.eventType, entry.eventPayload !== undefined ? JSON.stringify(entry.eventPayload) : null, JSON.stringify(entry.error), entry.retryCount, entry.maxRetries, entry.lastRetryAt ?? null, entry.nextRetryAt ?? null, entry.status, entry.createdAt, entry.correlationId ?? null, entry.source, entry.context !== undefined ? JSON.stringify(entry.context) : null, entry.resolutionNotes ?? null, entry.resolvedBy ?? null, entry.resolvedAt ?? null);
120
+ }
121
+ catch (error) {
122
+ throw new SqliteDeadLetterStoreError(SqliteDeadLetterStoreErrorCodes.DATABASE_ERROR, `Failed to add DLQ entry: ${error instanceof Error ? error.message : 'Unknown error'}`, { entryId: entry.entryId });
123
+ }
124
+ }
125
+ /**
126
+ * Get entry by ID
127
+ */
128
+ async get(entryId) {
129
+ try {
130
+ const stmt = this.db.prepare(`
131
+ SELECT entry_id, original_event_id, event_type, event_payload,
132
+ error, retry_count, max_retries, last_retry_at, next_retry_at,
133
+ status, created_at, correlation_id, source, context,
134
+ resolution_notes, resolved_by, resolved_at
135
+ FROM ${this.tableName}
136
+ WHERE entry_id = ?
137
+ `);
138
+ const row = stmt.get(entryId);
139
+ return row !== undefined ? rowToDeadLetterEntry(row) : null;
140
+ }
141
+ catch (error) {
142
+ throw new SqliteDeadLetterStoreError(SqliteDeadLetterStoreErrorCodes.DATABASE_ERROR, `Failed to get DLQ entry: ${error instanceof Error ? error.message : 'Unknown error'}`, { entryId });
143
+ }
144
+ }
145
+ /**
146
+ * List entries with optional status filter
147
+ */
148
+ async list(status) {
149
+ try {
150
+ let sql = `
151
+ SELECT entry_id, original_event_id, event_type, event_payload,
152
+ error, retry_count, max_retries, last_retry_at, next_retry_at,
153
+ status, created_at, correlation_id, source, context,
154
+ resolution_notes, resolved_by, resolved_at
155
+ FROM ${this.tableName}
156
+ `;
157
+ const params = [];
158
+ if (status !== undefined) {
159
+ sql += ' WHERE status = ?';
160
+ params.push(status);
161
+ }
162
+ sql += ' ORDER BY created_at DESC';
163
+ const stmt = this.db.prepare(sql);
164
+ const rows = (params.length > 0 ? stmt.all(...params) : stmt.all());
165
+ return rows.map(rowToDeadLetterEntry);
166
+ }
167
+ catch (error) {
168
+ throw new SqliteDeadLetterStoreError(SqliteDeadLetterStoreErrorCodes.DATABASE_ERROR, `Failed to list DLQ entries: ${error instanceof Error ? error.message : 'Unknown error'}`, { status });
169
+ }
170
+ }
171
+ /**
172
+ * Update entry
173
+ * INV-DLQ-002, INV-DLQ-003: Status transitions handled
174
+ */
175
+ async update(entry) {
176
+ try {
177
+ const stmt = this.db.prepare(`
178
+ UPDATE ${this.tableName} SET
179
+ original_event_id = ?,
180
+ event_type = ?,
181
+ event_payload = ?,
182
+ error = ?,
183
+ retry_count = ?,
184
+ max_retries = ?,
185
+ last_retry_at = ?,
186
+ next_retry_at = ?,
187
+ status = ?,
188
+ correlation_id = ?,
189
+ source = ?,
190
+ context = ?,
191
+ resolution_notes = ?,
192
+ resolved_by = ?,
193
+ resolved_at = ?
194
+ WHERE entry_id = ?
195
+ `);
196
+ stmt.run(entry.originalEventId, entry.eventType, entry.eventPayload !== undefined ? JSON.stringify(entry.eventPayload) : null, JSON.stringify(entry.error), entry.retryCount, entry.maxRetries, entry.lastRetryAt ?? null, entry.nextRetryAt ?? null, entry.status, entry.correlationId ?? null, entry.source, entry.context !== undefined ? JSON.stringify(entry.context) : null, entry.resolutionNotes ?? null, entry.resolvedBy ?? null, entry.resolvedAt ?? null, entry.entryId);
197
+ }
198
+ catch (error) {
199
+ throw new SqliteDeadLetterStoreError(SqliteDeadLetterStoreErrorCodes.DATABASE_ERROR, `Failed to update DLQ entry: ${error instanceof Error ? error.message : 'Unknown error'}`, { entryId: entry.entryId });
200
+ }
201
+ }
202
+ /**
203
+ * Delete entry
204
+ */
205
+ async delete(entryId) {
206
+ try {
207
+ const stmt = this.db.prepare(`
208
+ DELETE FROM ${this.tableName} WHERE entry_id = ?
209
+ `);
210
+ const result = stmt.run(entryId);
211
+ return result.changes > 0;
212
+ }
213
+ catch (error) {
214
+ throw new SqliteDeadLetterStoreError(SqliteDeadLetterStoreErrorCodes.DATABASE_ERROR, `Failed to delete DLQ entry: ${error instanceof Error ? error.message : 'Unknown error'}`, { entryId });
215
+ }
216
+ }
217
+ /**
218
+ * Count entries by status
219
+ */
220
+ async countByStatus() {
221
+ try {
222
+ const stmt = this.db.prepare(`
223
+ SELECT status, COUNT(*) as count
224
+ FROM ${this.tableName}
225
+ GROUP BY status
226
+ `);
227
+ const rows = stmt.all();
228
+ const counts = {
229
+ pending: 0,
230
+ retrying: 0,
231
+ exhausted: 0,
232
+ resolved: 0,
233
+ discarded: 0,
234
+ };
235
+ for (const row of rows) {
236
+ const status = row.status;
237
+ if (status in counts) {
238
+ counts[status] = row.count;
239
+ }
240
+ }
241
+ return counts;
242
+ }
243
+ catch (error) {
244
+ throw new SqliteDeadLetterStoreError(SqliteDeadLetterStoreErrorCodes.DATABASE_ERROR, `Failed to count DLQ entries by status: ${error instanceof Error ? error.message : 'Unknown error'}`);
245
+ }
246
+ }
247
+ /**
248
+ * Clears all entries (for testing only)
249
+ */
250
+ clear() {
251
+ this.db.exec(`DELETE FROM ${this.tableName}`);
252
+ }
253
+ }
254
+ /**
255
+ * Safely parses JSON with error handling
256
+ */
257
+ function safeJsonParse(json, fieldName, entryId) {
258
+ try {
259
+ return JSON.parse(json);
260
+ }
261
+ catch (error) {
262
+ throw new SqliteDeadLetterStoreError(SqliteDeadLetterStoreErrorCodes.SERIALIZATION_ERROR, `Failed to parse ${fieldName} for entry ${entryId}: ${error instanceof Error ? error.message : 'Invalid JSON'}`, { entryId, fieldName });
263
+ }
264
+ }
265
+ function rowToDeadLetterEntry(row) {
266
+ const entry = {
267
+ entryId: row.entry_id,
268
+ originalEventId: row.original_event_id,
269
+ eventType: row.event_type,
270
+ eventPayload: row.event_payload !== null ? safeJsonParse(row.event_payload, 'eventPayload', row.entry_id) : undefined,
271
+ error: safeJsonParse(row.error, 'error', row.entry_id),
272
+ retryCount: row.retry_count,
273
+ maxRetries: row.max_retries,
274
+ status: row.status,
275
+ createdAt: row.created_at,
276
+ source: row.source,
277
+ };
278
+ if (row.last_retry_at !== null) {
279
+ entry.lastRetryAt = row.last_retry_at;
280
+ }
281
+ if (row.next_retry_at !== null) {
282
+ entry.nextRetryAt = row.next_retry_at;
283
+ }
284
+ if (row.correlation_id !== null) {
285
+ entry.correlationId = row.correlation_id;
286
+ }
287
+ if (row.context !== null) {
288
+ entry.context = safeJsonParse(row.context, 'context', row.entry_id);
289
+ }
290
+ if (row.resolution_notes !== null) {
291
+ entry.resolutionNotes = row.resolution_notes;
292
+ }
293
+ if (row.resolved_by !== null) {
294
+ entry.resolvedBy = row.resolved_by;
295
+ }
296
+ if (row.resolved_at !== null) {
297
+ entry.resolvedAt = row.resolved_at;
298
+ }
299
+ return entry;
300
+ }
301
+ /**
302
+ * Creates a SQLite dead letter storage
303
+ */
304
+ export function createSqliteDeadLetterStorage(db, tableName) {
305
+ return new SqliteDeadLetterStorage(db, tableName);
306
+ }
307
+ //# sourceMappingURL=dead-letter-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dead-letter-store.js","sourceRoot":"","sources":["../src/dead-letter-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import type { MemoryEvent, MemoryEventType } from '@defai.digital/contracts';
2
+ import type { EventStore } from '@defai.digital/memory-domain';
3
+ import type Database from 'better-sqlite3';
4
+ /**
5
+ * Error thrown by SQLite event store operations
6
+ */
7
+ export declare class SqliteEventStoreError extends Error {
8
+ readonly code: string;
9
+ readonly details?: Record<string, unknown> | undefined;
10
+ constructor(code: string, message: string, details?: Record<string, unknown> | undefined);
11
+ }
12
+ /**
13
+ * Error codes for SQLite event store
14
+ */
15
+ export declare const SqliteEventStoreErrorCodes: {
16
+ readonly VERSION_CONFLICT: "SQLITE_VERSION_CONFLICT";
17
+ readonly INVALID_EVENT: "SQLITE_INVALID_EVENT";
18
+ readonly DATABASE_ERROR: "SQLITE_DATABASE_ERROR";
19
+ readonly INVALID_TABLE_NAME: "SQLITE_INVALID_TABLE_NAME";
20
+ };
21
+ /**
22
+ * SQLite implementation of EventStore
23
+ * INV-MEM-001: Events are immutable - stored as read-only rows
24
+ * INV-MEM-003: Adapter does not accept domain objects directly (uses MemoryEvent contract)
25
+ * INV-MEM-004: Events are ordered by version within aggregate
26
+ */
27
+ export declare class SqliteEventStore implements EventStore {
28
+ private readonly db;
29
+ private readonly tableName;
30
+ constructor(db: Database.Database, tableName?: string);
31
+ /**
32
+ * Initializes the database schema
33
+ */
34
+ private initialize;
35
+ /**
36
+ * Appends an event to the store
37
+ * INV-MEM-001: Events are immutable once stored
38
+ * INV-MEM-004: Version ordering enforced via constraint
39
+ */
40
+ append(event: MemoryEvent): Promise<void>;
41
+ /**
42
+ * Gets all events for an aggregate
43
+ * INV-MEM-004: Events returned in version order
44
+ */
45
+ getEvents(aggregateId: string): Promise<MemoryEvent[]>;
46
+ /**
47
+ * Gets events by type
48
+ */
49
+ getEventsByType(type: MemoryEventType): Promise<MemoryEvent[]>;
50
+ /**
51
+ * Gets events by correlation ID
52
+ * INV-MEM-005: Support correlation tracing
53
+ */
54
+ getEventsByCorrelation(correlationId: string): Promise<MemoryEvent[]>;
55
+ /**
56
+ * Gets the current version for an aggregate
57
+ */
58
+ getVersion(aggregateId: string): Promise<number>;
59
+ /**
60
+ * Clears all events (for testing only)
61
+ */
62
+ clear(): void;
63
+ }
64
+ /**
65
+ * Creates a SQLite event store
66
+ */
67
+ export declare function createSqliteEventStore(db: Database.Database, tableName?: string): SqliteEventStore;
68
+ //# sourceMappingURL=event-store.d.ts.map
@@ -0,0 +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,8BAA8B,CAAC;AAC/D,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;aAE5B,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;;GAEG;AACH,eAAO,MAAM,0BAA0B;;;;;CAK7B,CAAC;AAUX;;;;;GAKG;AACH,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,SAAkB;IAa9D;;OAEG;IACH,OAAO,CAAC,UAAU;IA4BlB;;;;OAIG;IACG,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAwE/C;;;OAGG;IACH,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAYtD;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAY9D;;;OAGG;IACH,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAYrE;;OAEG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBhD;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd;AAsDD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,CAAC,EAAE,MAAM,GACjB,gBAAgB,CAElB"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Error thrown by SQLite event store operations
3
+ */
4
+ export class SqliteEventStoreError extends Error {
5
+ code;
6
+ details;
7
+ constructor(code, message, details) {
8
+ super(message);
9
+ this.code = code;
10
+ this.details = details;
11
+ this.name = 'SqliteEventStoreError';
12
+ }
13
+ }
14
+ /**
15
+ * Error codes for SQLite event store
16
+ */
17
+ export const SqliteEventStoreErrorCodes = {
18
+ VERSION_CONFLICT: 'SQLITE_VERSION_CONFLICT',
19
+ INVALID_EVENT: 'SQLITE_INVALID_EVENT',
20
+ DATABASE_ERROR: 'SQLITE_DATABASE_ERROR',
21
+ INVALID_TABLE_NAME: 'SQLITE_INVALID_TABLE_NAME',
22
+ };
23
+ /**
24
+ * Validates a SQL table name to prevent SQL injection
25
+ * Only allows alphanumeric characters and underscores, must start with letter or underscore
26
+ */
27
+ function isValidTableName(name) {
28
+ return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name) && name.length <= 64;
29
+ }
30
+ /**
31
+ * SQLite implementation of EventStore
32
+ * INV-MEM-001: Events are immutable - stored as read-only rows
33
+ * INV-MEM-003: Adapter does not accept domain objects directly (uses MemoryEvent contract)
34
+ * INV-MEM-004: Events are ordered by version within aggregate
35
+ */
36
+ export class SqliteEventStore {
37
+ db;
38
+ tableName;
39
+ constructor(db, tableName = 'memory_events') {
40
+ // Validate table name to prevent SQL injection
41
+ if (!isValidTableName(tableName)) {
42
+ throw new SqliteEventStoreError(SqliteEventStoreErrorCodes.INVALID_TABLE_NAME, `Invalid table name: ${tableName}. Must start with letter or underscore, contain only alphanumeric and underscores, max 64 chars.`);
43
+ }
44
+ this.db = db;
45
+ this.tableName = tableName;
46
+ this.initialize();
47
+ }
48
+ /**
49
+ * Initializes the database schema
50
+ */
51
+ initialize() {
52
+ this.db.exec(`
53
+ CREATE TABLE IF NOT EXISTS ${this.tableName} (
54
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
55
+ event_id TEXT NOT NULL UNIQUE,
56
+ type TEXT NOT NULL,
57
+ aggregate_id TEXT,
58
+ version INTEGER,
59
+ timestamp TEXT NOT NULL,
60
+ payload TEXT NOT NULL,
61
+ metadata TEXT,
62
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
63
+ );
64
+
65
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_aggregate_id
66
+ ON ${this.tableName}(aggregate_id);
67
+
68
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_type
69
+ ON ${this.tableName}(type);
70
+
71
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_correlation_id
72
+ ON ${this.tableName}(json_extract(metadata, '$.correlationId'));
73
+
74
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_aggregate_version
75
+ ON ${this.tableName}(aggregate_id, version);
76
+ `);
77
+ }
78
+ /**
79
+ * Appends an event to the store
80
+ * INV-MEM-001: Events are immutable once stored
81
+ * INV-MEM-004: Version ordering enforced via constraint
82
+ */
83
+ async append(event) {
84
+ // Validate event
85
+ if (event.eventId === '') {
86
+ throw new SqliteEventStoreError(SqliteEventStoreErrorCodes.INVALID_EVENT, 'Event must have an eventId');
87
+ }
88
+ const aggregateId = event.aggregateId ?? 'global';
89
+ // Use a transaction to atomically check version and insert
90
+ // This prevents TOCTOU race conditions between version check and insert
91
+ const transaction = this.db.transaction(() => {
92
+ // Check version ordering if version is specified (INV-MEM-004)
93
+ if (event.version !== undefined) {
94
+ const versionStmt = this.db.prepare(`
95
+ SELECT MAX(version) as max_version, COUNT(*) as count
96
+ FROM ${this.tableName}
97
+ WHERE aggregate_id = ?
98
+ `);
99
+ const row = versionStmt.get(aggregateId);
100
+ const currentVersion = row.count === 0 ? 0 : (row.max_version ?? row.count);
101
+ if (event.version !== currentVersion + 1) {
102
+ throw new SqliteEventStoreError(SqliteEventStoreErrorCodes.VERSION_CONFLICT, `Version conflict: expected ${String(currentVersion + 1)}, got ${String(event.version)}`, { expected: currentVersion + 1, actual: event.version });
103
+ }
104
+ }
105
+ const stmt = this.db.prepare(`
106
+ INSERT INTO ${this.tableName} (
107
+ event_id, type, aggregate_id, version, timestamp, payload, metadata
108
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
109
+ `);
110
+ stmt.run(event.eventId, event.type, aggregateId, event.version ?? null, event.timestamp, JSON.stringify(event.payload), event.metadata !== undefined ? JSON.stringify(event.metadata) : null);
111
+ });
112
+ try {
113
+ transaction();
114
+ }
115
+ catch (error) {
116
+ if (error instanceof SqliteEventStoreError) {
117
+ throw error;
118
+ }
119
+ if (error instanceof Error &&
120
+ error.message.includes('UNIQUE constraint failed')) {
121
+ throw new SqliteEventStoreError(SqliteEventStoreErrorCodes.INVALID_EVENT, `Event with ID ${event.eventId} already exists`);
122
+ }
123
+ throw new SqliteEventStoreError(SqliteEventStoreErrorCodes.DATABASE_ERROR, `Failed to append event: ${error instanceof Error ? error.message : 'Unknown error'}`);
124
+ }
125
+ }
126
+ /**
127
+ * Gets all events for an aggregate
128
+ * INV-MEM-004: Events returned in version order
129
+ */
130
+ getEvents(aggregateId) {
131
+ const stmt = this.db.prepare(`
132
+ SELECT event_id, type, aggregate_id, version, timestamp, payload, metadata
133
+ FROM ${this.tableName}
134
+ WHERE aggregate_id = ?
135
+ ORDER BY COALESCE(version, id)
136
+ `);
137
+ const rows = stmt.all(aggregateId);
138
+ return Promise.resolve(rows.map(rowToEvent));
139
+ }
140
+ /**
141
+ * Gets events by type
142
+ */
143
+ getEventsByType(type) {
144
+ const stmt = this.db.prepare(`
145
+ SELECT event_id, type, aggregate_id, version, timestamp, payload, metadata
146
+ FROM ${this.tableName}
147
+ WHERE type = ?
148
+ ORDER BY id
149
+ `);
150
+ const rows = stmt.all(type);
151
+ return Promise.resolve(rows.map(rowToEvent));
152
+ }
153
+ /**
154
+ * Gets events by correlation ID
155
+ * INV-MEM-005: Support correlation tracing
156
+ */
157
+ getEventsByCorrelation(correlationId) {
158
+ const stmt = this.db.prepare(`
159
+ SELECT event_id, type, aggregate_id, version, timestamp, payload, metadata
160
+ FROM ${this.tableName}
161
+ WHERE json_extract(metadata, '$.correlationId') = ?
162
+ ORDER BY id
163
+ `);
164
+ const rows = stmt.all(correlationId);
165
+ return Promise.resolve(rows.map(rowToEvent));
166
+ }
167
+ /**
168
+ * Gets the current version for an aggregate
169
+ */
170
+ getVersion(aggregateId) {
171
+ const stmt = this.db.prepare(`
172
+ SELECT MAX(version) as max_version, COUNT(*) as count
173
+ FROM ${this.tableName}
174
+ WHERE aggregate_id = ?
175
+ `);
176
+ const row = stmt.get(aggregateId);
177
+ if (row.count === 0) {
178
+ return Promise.resolve(0);
179
+ }
180
+ return Promise.resolve(row.max_version ?? row.count);
181
+ }
182
+ /**
183
+ * Clears all events (for testing only)
184
+ */
185
+ clear() {
186
+ this.db.exec(`DELETE FROM ${this.tableName}`);
187
+ }
188
+ }
189
+ /**
190
+ * Safely parses JSON with error handling
191
+ */
192
+ function safeJsonParse(json, fieldName, eventId) {
193
+ try {
194
+ return JSON.parse(json);
195
+ }
196
+ catch (error) {
197
+ throw new SqliteEventStoreError(SqliteEventStoreErrorCodes.DATABASE_ERROR, `Failed to parse ${fieldName} for event ${eventId}: ${error instanceof Error ? error.message : 'Invalid JSON'}`, { eventId, fieldName });
198
+ }
199
+ }
200
+ /**
201
+ * Converts a database row to a MemoryEvent
202
+ */
203
+ function rowToEvent(row) {
204
+ const event = {
205
+ eventId: row.event_id,
206
+ type: row.type,
207
+ timestamp: row.timestamp,
208
+ payload: safeJsonParse(row.payload, 'payload', row.event_id),
209
+ };
210
+ if (row.aggregate_id !== null) {
211
+ event.aggregateId = row.aggregate_id;
212
+ }
213
+ if (row.version !== null) {
214
+ event.version = row.version;
215
+ }
216
+ if (row.metadata !== null) {
217
+ event.metadata = safeJsonParse(row.metadata, 'metadata', row.event_id);
218
+ }
219
+ return event;
220
+ }
221
+ /**
222
+ * Creates a SQLite event store
223
+ */
224
+ export function createSqliteEventStore(db, tableName) {
225
+ return new SqliteEventStore(db, tableName);
226
+ }
227
+ //# sourceMappingURL=event-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-store.js","sourceRoot":"","sources":["../src/event-store.ts"],"names":[],"mappings":"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"}