@fleettools/squawk 0.1.0 → 0.1.1

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.
Files changed (66) hide show
  1. package/package.json +1 -1
  2. package/AGENTS.md +0 -28
  3. package/dist/src/db/checkpoint-storage.d.ts +0 -19
  4. package/dist/src/db/checkpoint-storage.d.ts.map +0 -1
  5. package/dist/src/db/checkpoint-storage.js +0 -355
  6. package/dist/src/db/checkpoint-storage.js.map +0 -1
  7. package/dist/src/db/index.d.ts +0 -30
  8. package/dist/src/db/index.d.ts.map +0 -1
  9. package/dist/src/db/index.js +0 -329
  10. package/dist/src/db/index.js.map +0 -1
  11. package/dist/src/db/sqlite.d.ts +0 -31
  12. package/dist/src/db/sqlite.d.ts.map +0 -1
  13. package/dist/src/db/sqlite.js +0 -558
  14. package/dist/src/db/sqlite.js.map +0 -1
  15. package/dist/src/db/types.d.ts +0 -611
  16. package/dist/src/db/types.d.ts.map +0 -1
  17. package/dist/src/db/types.js +0 -4
  18. package/dist/src/db/types.js.map +0 -1
  19. package/dist/src/index.d.ts +0 -2
  20. package/dist/src/index.d.ts.map +0 -1
  21. package/dist/src/index.js +0 -285
  22. package/dist/src/index.js.map +0 -1
  23. package/dist/src/recovery/checkpointing.d.ts +0 -244
  24. package/dist/src/recovery/checkpointing.d.ts.map +0 -1
  25. package/dist/src/recovery/checkpointing.js +0 -511
  26. package/dist/src/recovery/checkpointing.js.map +0 -1
  27. package/dist/src/recovery/detection.d.ts +0 -137
  28. package/dist/src/recovery/detection.d.ts.map +0 -1
  29. package/dist/src/recovery/detection.js +0 -240
  30. package/dist/src/recovery/detection.js.map +0 -1
  31. package/dist/src/recovery/detector.d.ts +0 -34
  32. package/dist/src/recovery/detector.d.ts.map +0 -1
  33. package/dist/src/recovery/detector.js +0 -42
  34. package/dist/src/recovery/detector.js.map +0 -1
  35. package/dist/src/recovery/index.d.ts +0 -3
  36. package/dist/src/recovery/index.d.ts.map +0 -1
  37. package/dist/src/recovery/index.js +0 -3
  38. package/dist/src/recovery/index.js.map +0 -1
  39. package/dist/src/recovery/restorer.d.ts +0 -51
  40. package/dist/src/recovery/restorer.d.ts.map +0 -1
  41. package/dist/src/recovery/restorer.js +0 -266
  42. package/dist/src/recovery/restorer.js.map +0 -1
  43. package/dist/src/schemas.d.ts +0 -142
  44. package/dist/src/schemas.d.ts.map +0 -1
  45. package/dist/src/schemas.js +0 -110
  46. package/dist/src/schemas.js.map +0 -1
  47. package/src/db/checkpoint-storage.ts +0 -443
  48. package/src/db/index.d.ts +0 -30
  49. package/src/db/index.d.ts.map +0 -1
  50. package/src/db/index.js.map +0 -1
  51. package/src/db/index.ts +0 -417
  52. package/src/db/schema.sql +0 -112
  53. package/src/db/sqlite.d.ts +0 -31
  54. package/src/db/sqlite.d.ts.map +0 -1
  55. package/src/db/sqlite.js +0 -667
  56. package/src/db/sqlite.js.map +0 -1
  57. package/src/db/sqlite.ts +0 -677
  58. package/src/db/types.d.ts +0 -612
  59. package/src/db/types.d.ts.map +0 -1
  60. package/src/db/types.js +0 -4
  61. package/src/db/types.js.map +0 -1
  62. package/src/db/types.ts +0 -771
  63. package/src/index.ts +0 -332
  64. package/src/recovery/detector.ts +0 -82
  65. package/src/recovery/index.ts +0 -3
  66. package/src/recovery/restorer.ts +0 -377
package/src/db/sqlite.ts DELETED
@@ -1,677 +0,0 @@
1
-
2
-
3
- import Database from 'bun:sqlite';
4
- import fs from 'fs';
5
- import path from 'path';
6
- import type {
7
- DatabaseAdapter,
8
- DatabaseStats,
9
- VersionedInterface,
10
- MissionOps,
11
- SortieOps,
12
- LockOps,
13
- EventOps,
14
- CheckpointOps,
15
- SpecialistOps,
16
- MessageOps,
17
- CursorOps,
18
- Event,
19
- AppendEventInput,
20
- EventFilter,
21
- StreamType,
22
- Lock,
23
- Mailbox,
24
- Cursor
25
- } from './types.js';
26
-
27
- export class SQLiteAdapter implements DatabaseAdapter {
28
- version = '1.0.0' as const;
29
-
30
- private db: Database | null = null;
31
- private dbPath: string;
32
- private schemaPath: string;
33
-
34
- public missions: MissionOps = {} as MissionOps;
35
- public sorties: SortieOps = {} as SortieOps;
36
- public locks: LockOps = {} as LockOps;
37
- public events: EventOps = {} as EventOps;
38
- public checkpoints: CheckpointOps = {} as CheckpointOps;
39
- public specialists: SpecialistOps = {} as SpecialistOps;
40
- public messages: MessageOps = {} as MessageOps;
41
- public cursors: CursorOps = {} as CursorOps;
42
-
43
- constructor(dbPath: string = ':memory:', schemaPath?: string) {
44
- this.dbPath = dbPath;
45
-
46
- if (schemaPath) {
47
- this.schemaPath = schemaPath;
48
- return;
49
- }
50
-
51
- this.schemaPath = this.resolveSchemaPath();
52
- }
53
-
54
- private resolveSchemaPath(): string {
55
- const possiblePaths: string[] = [];
56
-
57
- try {
58
- const __filename = new URL('', import.meta.url).pathname;
59
- const __dirname = path.dirname(__filename);
60
- possiblePaths.push(path.join(__dirname, 'schema.sql'));
61
- } catch {
62
- }
63
-
64
- possiblePaths.push(path.join(process.cwd(), 'squawk', 'src', 'db', 'schema.sql'));
65
-
66
- const projectRoot = process.cwd();
67
- const modulePaths = [
68
- path.join(projectRoot, 'src', 'db', 'schema.sql'),
69
- path.join(projectRoot, 'db', 'schema.sql'),
70
- path.join(projectRoot, 'lib', 'db', 'schema.sql'),
71
- ];
72
- possiblePaths.push(...modulePaths);
73
-
74
- try {
75
- const stack = new Error().stack;
76
- if (stack) {
77
- const match = stack.match(/at.*\((.*):.*\)/);
78
- if (match && match[1]) {
79
- const callerDir = path.dirname(match[1]);
80
- possiblePaths.push(path.join(callerDir, 'schema.sql'));
81
- possiblePaths.push(path.join(callerDir, '..', 'src', 'db', 'schema.sql'));
82
- }
83
- }
84
- } catch {
85
- }
86
-
87
- for (const candidatePath of possiblePaths) {
88
- if (fs.existsSync(candidatePath)) {
89
- return candidatePath;
90
- }
91
- }
92
-
93
- return possiblePaths[0] || path.join(process.cwd(), 'squawk', 'src', 'db', 'schema.sql');
94
- }
95
-
96
- async initialize(): Promise<void> {
97
- try {
98
- this.db = new Database(this.dbPath);
99
-
100
- if (this.dbPath !== ':memory:') {
101
- this.db!.exec('PRAGMA journal_mode = WAL');
102
- }
103
-
104
- this.db!.exec('PRAGMA foreign_keys = ON');
105
-
106
- if (fs.existsSync(this.schemaPath)) {
107
- const schema = fs.readFileSync(this.schemaPath, 'utf-8');
108
- this.db!.exec(schema);
109
- } else {
110
- throw new Error(`Schema file not found: ${this.schemaPath}`);
111
- }
112
-
113
- this.initializeOperations();
114
-
115
- console.log(`SQLite database initialized: ${this.dbPath}`);
116
- } catch (error) {
117
- console.error('Failed to initialize database:', error);
118
- throw error;
119
- }
120
- }
121
-
122
- private initializeOperations(): void {
123
- if (!this.db) {
124
- throw new Error('Database not initialized');
125
- }
126
-
127
- // TypeScript workaround for property access
128
- const adapter = this as any;
129
-
130
- adapter.mailboxes = {
131
- version: '1.0.0',
132
-
133
- create: async (input: any): Promise<any> => {
134
- const now = new Date().toISOString();
135
- const createdAt = input.created_at || now;
136
- const updatedAt = input.updated_at || now;
137
- this.db!.prepare(`
138
- INSERT INTO mailboxes (id, created_at, updated_at)
139
- VALUES (?, ?, ?)
140
- `).run(input.id, createdAt, updatedAt);
141
- return { id: input.id, created_at: createdAt, updated_at: updatedAt };
142
- },
143
-
144
- getById: async (id: string): Promise<any | null> => {
145
- const row = this.db!.prepare(`
146
- SELECT * FROM mailboxes WHERE id = ?
147
- `).get(id) as any;
148
- return row || null;
149
- },
150
-
151
- getAll: async (): Promise<any[]> => {
152
- const rows = this.db!.prepare(`
153
- SELECT * FROM mailboxes ORDER BY created_at DESC
154
- `).all() as any[];
155
- return rows;
156
- },
157
-
158
- update: async (id: string, data: any): Promise<any | null> => {
159
- const now = new Date().toISOString();
160
- const result = this.db!.prepare(`
161
- UPDATE mailboxes
162
- SET updated_at = COALESCE(?, updated_at)
163
- WHERE id = ?
164
- `).run(now, id);
165
- if (result.changes === 0) return null;
166
- return await (this as any).mailboxes.getById(id);
167
- },
168
-
169
- delete: async (id: string): Promise<boolean> => {
170
- const result = this.db!.prepare(`
171
- DELETE FROM mailboxes WHERE id = ?
172
- `).run(id);
173
- return result.changes > 0;
174
- }
175
- };
176
-
177
- this.cursors = {
178
- version: '1.0.0',
179
-
180
- create: async (input: any): Promise<any> => {
181
- const now = new Date().toISOString();
182
- this.db!.prepare(`
183
- INSERT INTO cursors (id, stream_id, position, consumer_id, updated_at)
184
- VALUES (?, ?, ?, ?, ?)
185
- `).run(input.id, input.stream_id, input.position, input.consumer_id, now);
186
- return { id: input.id, stream_id: input.stream_id, position: input.position, consumer_id: input.consumer_id, updated_at: now };
187
- },
188
-
189
- getById: async (id: string): Promise<any | null> => {
190
- const row = this.db!.prepare(`
191
- SELECT * FROM cursors WHERE id = ?
192
- `).get(id) as any;
193
- return row || null;
194
- },
195
-
196
- getByStream: async (streamId: string): Promise<any | null> => {
197
- const row = this.db!.prepare(`
198
- SELECT * FROM cursors WHERE stream_id = ?
199
- `).get(streamId) as any;
200
- return row || null;
201
- },
202
-
203
- advance: async (streamId: string, position: number): Promise<any> => {
204
- const now = new Date().toISOString();
205
- this.db!.prepare(`
206
- INSERT INTO cursors (id, stream_id, position, updated_at)
207
- VALUES (?, ?, ?, ?)
208
- ON CONFLICT(stream_id) DO UPDATE SET
209
- position = excluded.position,
210
- updated_at = excluded.updated_at
211
- `).run(`${streamId}_cursor`, streamId, position, now);
212
- return await adapter.cursors.getByStream(streamId);
213
- },
214
-
215
- update: async (id: string, data: any): Promise<any> => {
216
- const now = new Date().toISOString();
217
- this.db!.prepare(`
218
- UPDATE cursors
219
- SET position = COALESCE(?, position),
220
- updated_at = COALESCE(?, updated_at)
221
- WHERE id = ?
222
- `).run(data.position, now, id);
223
- return await adapter.cursors.getById(id);
224
- },
225
-
226
- getAll: async (filter?: any): Promise<any[]> => {
227
- let query = 'SELECT * FROM cursors';
228
- const params: any[] = [];
229
-
230
- if (filter?.stream_type) {
231
- query += ' WHERE stream_id LIKE ?';
232
- params.push(`${filter.stream_type}_%`);
233
- }
234
-
235
- query += ' ORDER BY updated_at DESC';
236
-
237
- const rows = this.db!.prepare(query).all(...params) as any[];
238
- return rows;
239
- }
240
- };
241
-
242
- this.locks = {
243
- version: '1.0.0',
244
-
245
- acquire: async (input: any): Promise<any> => {
246
- const id = `lock_${Math.random().toString(36).substring(2, 10)}`;
247
- const now = new Date().toISOString();
248
- const expiresAt = new Date(Date.now() + input.timeout_ms).toISOString();
249
-
250
- const existing = this.db!.prepare(`
251
- SELECT * FROM locks
252
- WHERE file = ? AND released_at IS NULL AND expires_at > datetime('now')
253
- `).get(input.file) as any;
254
-
255
- if (existing) {
256
- return {
257
- conflict: true,
258
- existing_lock: existing
259
- };
260
- }
261
-
262
- this.db!.prepare(`
263
- INSERT INTO locks (id, file, reserved_by, reserved_at, purpose, timeout_ms, checksum, expires_at, metadata)
264
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
265
- `).run(id, input.file, input.specialist_id, now, input.purpose || 'edit', input.timeout_ms, input.checksum, expiresAt, JSON.stringify(input.metadata || {}));
266
-
267
- const lock = await adapter.locks.getById(id);
268
- return {
269
- conflict: false,
270
- lock: {
271
- ...lock,
272
- status: 'active',
273
- expires_at: expiresAt,
274
- normalized_path: input.file
275
- }
276
- };
277
- },
278
-
279
- release: async (id: string): Promise<boolean> => {
280
- const result = this.db!.prepare(`
281
- UPDATE locks
282
- SET released_at = datetime('now'),
283
- status = 'released'
284
- WHERE id = ?
285
- `).run(id);
286
- return result.changes > 0;
287
- },
288
-
289
- getById: async (id: string): Promise<any | null> => {
290
- const row = this.db!.prepare(`
291
- SELECT * FROM locks WHERE id = ?
292
- `).get(id) as any;
293
- return row || null;
294
- },
295
-
296
- getByFile: async (file: string): Promise<any | null> => {
297
- const row = this.db!.prepare(`
298
- SELECT * FROM locks
299
- WHERE file = ? AND released_at IS NULL AND expires_at > datetime('now')
300
- `).get(file) as any;
301
- return row || null;
302
- },
303
-
304
- getActive: async (): Promise<any[]> => {
305
- const rows = this.db!.prepare(`
306
- SELECT * FROM locks
307
- WHERE released_at IS NULL AND expires_at > datetime('now')
308
- `).all() as any[];
309
- return rows.map((row: any) => ({
310
- ...row,
311
- status: 'active',
312
- normalized_path: row.file
313
- }));
314
- },
315
-
316
- getAll: async (): Promise<any[]> => {
317
- const rows = this.db!.prepare(`
318
- SELECT * FROM locks ORDER BY reserved_at DESC
319
- `).all() as any[];
320
- return rows;
321
- },
322
-
323
- forceRelease: async (id: string): Promise<boolean> => {
324
- const result = this.db!.prepare(`
325
- UPDATE locks
326
- SET released_at = datetime('now'),
327
- status = 'force_released'
328
- WHERE id = ?
329
- `).run(id);
330
- return result.changes > 0;
331
- },
332
-
333
- releaseExpired: async (): Promise<number> => {
334
- const result = this.db!.prepare(`
335
- UPDATE locks
336
- SET released_at = datetime('now'),
337
- status = 'expired'
338
- WHERE released_at IS NULL
339
- AND timeout_ms IS NOT NULL
340
- AND expires_at IS NOT NULL
341
- AND expires_at < datetime('now')
342
- `).run();
343
- return result.changes;
344
- }
345
- };
346
-
347
- this.events = {
348
- version: '1.0.0',
349
-
350
- append: async (input: AppendEventInput): Promise<Event> => {
351
- const eventId = `evt_${Math.random().toString(36).substring(2, 10)}`;
352
-
353
- const lastSeq = this.db!.prepare(`
354
- SELECT MAX(sequence_number) as last_seq
355
- FROM events
356
- WHERE stream_type = ? AND stream_id = ?
357
- `).get(input.stream_type, input.stream_id) as { last_seq: number | null } | undefined;
358
-
359
- const sequenceNumber = (lastSeq?.last_seq || 0) + 1;
360
-
361
- const now = new Date().toISOString();
362
-
363
- let mailboxId = input.stream_id;
364
- const existingMailbox = this.db!.prepare(`
365
- SELECT id FROM mailboxes WHERE id = ?
366
- `).get(input.stream_id);
367
-
368
- if (!existingMailbox) {
369
- mailboxId = `mbx_${input.stream_type}_${input.stream_id}`;
370
- this.db!.prepare(`
371
- INSERT OR IGNORE INTO mailboxes (id, created_at, updated_at)
372
- VALUES (?, ?, ?)
373
- `).run(mailboxId, now, now);
374
- }
375
-
376
- this.db!.prepare(`
377
- INSERT INTO events (
378
- id, mailbox_id, type, stream_type, stream_id, sequence_number,
379
- data, occurred_at, causation_id, correlation_id, metadata
380
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
381
- ` ).run(
382
- eventId,
383
- mailboxId,
384
- input.event_type,
385
- input.stream_type,
386
- input.stream_id,
387
- sequenceNumber,
388
- JSON.stringify(input.data),
389
- input.occurred_at || now,
390
- input.causation_id || null,
391
- input.correlation_id || null,
392
- JSON.stringify(input.metadata || {})
393
- );
394
-
395
- return {
396
- sequence_number: sequenceNumber,
397
- event_id: eventId,
398
- event_type: input.event_type,
399
- stream_type: input.stream_type,
400
- stream_id: input.stream_id,
401
- data: input.data,
402
- causation_id: input.causation_id,
403
- correlation_id: input.correlation_id,
404
- metadata: input.metadata,
405
- occurred_at: input.occurred_at || now,
406
- recorded_at: now,
407
- schema_version: input.schema_version || 1
408
- };
409
- },
410
-
411
- queryByStream: async (streamType: string, streamId: string, afterSequence?: number): Promise<Event[]> => {
412
- const query = `
413
- SELECT * FROM events
414
- WHERE stream_type = ? AND stream_id = ?
415
- ${afterSequence ? 'AND sequence_number > ?' : ''}
416
- ORDER BY sequence_number ASC
417
- `;
418
-
419
- const params: any[] = [streamType, streamId];
420
- if (afterSequence !== undefined) params.push(afterSequence);
421
-
422
- const rows = this.db!.prepare(query).all(...params) as any[];
423
-
424
- return rows.map(row => ({
425
- sequence_number: row.sequence_number,
426
- event_id: row.id,
427
- event_type: row.type,
428
- stream_type: row.stream_type,
429
- stream_id: row.stream_id,
430
- data: JSON.parse(row.data),
431
- causation_id: row.causation_id,
432
- correlation_id: row.correlation_id,
433
- metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
434
- occurred_at: row.occurred_at,
435
- recorded_at: row.occurred_at,
436
- schema_version: 1
437
- }));
438
- },
439
-
440
- queryByType: async (eventType: string): Promise<Event[]> => {
441
- const rows = this.db!.prepare(`
442
- SELECT * FROM events WHERE type = ? ORDER BY occurred_at ASC
443
- `).all(eventType) as any[];
444
-
445
- return rows.map(row => ({
446
- sequence_number: row.sequence_number,
447
- event_id: row.id,
448
- event_type: row.type,
449
- stream_type: row.stream_type,
450
- stream_id: row.stream_id,
451
- data: JSON.parse(row.data),
452
- causation_id: row.causation_id,
453
- correlation_id: row.correlation_id,
454
- metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
455
- occurred_at: row.occurred_at,
456
- recorded_at: row.occurred_at,
457
- schema_version: 1
458
- }));
459
- },
460
-
461
- getEvents: async (filter: EventFilter): Promise<Event[]> => {
462
- let query = 'SELECT * FROM events WHERE 1=1';
463
- const params: any[] = [];
464
-
465
- if (filter.event_type) {
466
- if (Array.isArray(filter.event_type)) {
467
- query += ` AND type IN (${filter.event_type.map(() => '?').join(',')})`;
468
- params.push(...filter.event_type);
469
- } else {
470
- query += ' AND type = ?';
471
- params.push(filter.event_type);
472
- }
473
- }
474
-
475
- if (filter.stream_type) {
476
- if (Array.isArray(filter.stream_type)) {
477
- query += ` AND stream_type IN (${filter.stream_type.map(() => '?').join(',')})`;
478
- params.push(...filter.stream_type);
479
- } else {
480
- query += ' AND stream_type = ?';
481
- params.push(filter.stream_type);
482
- }
483
- }
484
-
485
- if (filter.stream_id) {
486
- query += ' AND stream_id = ?';
487
- params.push(filter.stream_id);
488
- }
489
-
490
- if (filter.after_sequence !== undefined) {
491
- query += ' AND sequence_number > ?';
492
- params.push(filter.after_sequence);
493
- }
494
-
495
- query += ' ORDER BY occurred_at ASC';
496
-
497
- const rows = this.db!.prepare(query).all(...params) as any[];
498
-
499
- return rows.map(row => ({
500
- sequence_number: row.sequence_number,
501
- event_id: row.id,
502
- event_type: row.type,
503
- stream_type: row.stream_type,
504
- stream_id: row.stream_id,
505
- data: JSON.parse(row.data),
506
- causation_id: row.causation_id,
507
- correlation_id: row.correlation_id,
508
- metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
509
- occurred_at: row.occurred_at,
510
- recorded_at: row.occurred_at,
511
- schema_version: 1
512
- }));
513
- },
514
-
515
- getLatestByStream: async (streamType: string, streamId: string): Promise<any | null> => {
516
- const row = this.db!.prepare(`
517
- SELECT * FROM events
518
- WHERE stream_type = ? AND stream_id = ?
519
- ORDER BY sequence_number DESC
520
- LIMIT 1
521
- `).get(streamType, streamId) as any;
522
- return row ? {
523
- sequence_number: row.sequence_number,
524
- event_id: row.id,
525
- event_type: row.type,
526
- stream_type: row.stream_type,
527
- stream_id: row.stream_id,
528
- data: JSON.parse(row.data),
529
- causation_id: row.causation_id,
530
- correlation_id: row.correlation_id,
531
- metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
532
- occurred_at: row.occurred_at,
533
- recorded_at: row.occurred_at,
534
- schema_version: 1
535
- } : null;
536
- }
537
- };
538
-
539
- this.missions = {} as MissionOps;
540
- this.sorties = {} as SortieOps;
541
- this.checkpoints = {} as CheckpointOps;
542
- this.specialists = {} as SpecialistOps;
543
- this.messages = {} as MessageOps;
544
- }
545
-
546
- async close(): Promise<void> {
547
- try {
548
- if (this.db) {
549
- this.db.close();
550
- this.db = null;
551
- console.log(`SQLite database closed: ${this.dbPath}`);
552
- }
553
- } catch (error) {
554
- console.error('Error closing database:', error);
555
- throw error;
556
- }
557
- }
558
-
559
- async isHealthy(): Promise<boolean> {
560
- try {
561
- if (!this.db) {
562
- return false;
563
- }
564
-
565
- this.db.prepare('SELECT 1').get();
566
- return true;
567
- } catch {
568
- return false;
569
- }
570
- }
571
-
572
- async getStats(): Promise<DatabaseStats> {
573
- if (!this.db) {
574
- throw new Error('Database not initialized');
575
- }
576
-
577
- const eventCount = this.db.prepare('SELECT COUNT(*) as count FROM events').get() as { count: number };
578
-
579
- const missionCount = 0; // TODO: Implement when mission table exists
580
- const activeMissionCount = 0; // TODO: Implement
581
-
582
- const activeLockCount = this.db.prepare(
583
- "SELECT COUNT(*) as count FROM locks WHERE released_at IS NULL AND expires_at > datetime('now')"
584
- ).get() as { count: number };
585
-
586
- const checkpointCount = 0; // TODO: Implement
587
-
588
- let dbSize = 0;
589
- let walSize = 0;
590
-
591
- if (this.dbPath !== ':memory:' && fs.existsSync(this.dbPath)) {
592
- dbSize = fs.statSync(this.dbPath).size;
593
-
594
- const walPath = `${this.dbPath}-wal`;
595
- if (fs.existsSync(walPath)) {
596
- walSize = fs.statSync(walPath).size;
597
- }
598
- }
599
-
600
- return {
601
- total_events: eventCount.count,
602
- total_missions: missionCount,
603
- active_missions: activeMissionCount,
604
- active_locks: activeLockCount.count,
605
- total_checkpoints: checkpointCount,
606
- database_size_bytes: dbSize,
607
- wal_size_bytes: walSize
608
- };
609
- }
610
-
611
- async maintenance(): Promise<void> {
612
- if (!this.db) {
613
- throw new Error('Database not initialized');
614
- }
615
-
616
- try {
617
- this.db.exec('VACUUM');
618
- console.log('Database maintenance completed');
619
- } catch (error) {
620
- console.error('Error running database maintenance:', error);
621
- throw error;
622
- }
623
- }
624
-
625
- async beginTransaction(): Promise<void> {
626
- if (!this.db) {
627
- throw new Error('Database not initialized');
628
- }
629
-
630
- try {
631
- this.db.exec('BEGIN TRANSACTION');
632
- } catch (error) {
633
- console.error('Error beginning transaction:', error);
634
- throw error;
635
- }
636
- }
637
-
638
- async commitTransaction(): Promise<void> {
639
- if (!this.db) {
640
- throw new Error('Database not initialized');
641
- }
642
-
643
- try {
644
- this.db.exec('COMMIT');
645
- } catch (error) {
646
- console.error('Error committing transaction:', error);
647
- throw error;
648
- }
649
- }
650
-
651
- async rollbackTransaction(): Promise<void> {
652
- if (!this.db) {
653
- throw new Error('Database not initialized');
654
- }
655
-
656
- try {
657
- this.db.exec('ROLLBACK');
658
- } catch (error) {
659
- console.error('Error rolling back transaction:', error);
660
- throw error;
661
- }
662
- }
663
-
664
- getDatabase(): Database | null {
665
- return this.db;
666
- }
667
- }
668
-
669
- export async function createSQLiteAdapter(dbPath: string = ':memory:'): Promise<SQLiteAdapter> {
670
- const adapter = new SQLiteAdapter(dbPath);
671
- await adapter.initialize();
672
- return adapter;
673
- }
674
-
675
- export async function createInMemoryAdapter(): Promise<SQLiteAdapter> {
676
- return createSQLiteAdapter(':memory:');
677
- }