| 1 | import { DatabaseSync } from 'node:sqlite';
|
| 2 | import type { AuditStore } from '../../core/src/index.js';
|
| 3 |
|
| 4 | export * from './hosted.js';
|
| 5 | export * from './onboarding.js';
|
| 6 | export * from './relay.js';
|
| 7 | export * from './runtime.js';
|
| 8 |
|
| 9 | export class SqliteAuditStore implements AuditStore {
|
| 10 | private db: DatabaseSync;
|
| 11 | constructor(path = 'openclasp.db') {
|
| 12 | this.db = new DatabaseSync(path);
|
| 13 | this.db.exec(`
|
| 14 | PRAGMA journal_mode=WAL;
|
| 15 | CREATE TABLE IF NOT EXISTS audit_records (
|
| 16 | kind TEXT NOT NULL, id TEXT NOT NULL, value TEXT NOT NULL, created_at TEXT NOT NULL,
|
| 17 | PRIMARY KEY (kind, id)
|
| 18 | );
|
| 19 | `);
|
| 20 | }
|
| 21 | append(kind: string, id: string, value: unknown): void {
|
| 22 | const encoded = JSON.stringify(value);
|
| 23 | const row = this.db
|
| 24 | .prepare('SELECT value FROM audit_records WHERE kind=? AND id=?')
|
| 25 | .get(kind, id) as { value: string } | undefined;
|
| 26 | if (row && row.value !== encoded) throw new Error(`Conflicting duplicate ${kind}:${id}`);
|
| 27 | if (!row)
|
| 28 | this.db
|
| 29 | .prepare('INSERT INTO audit_records(kind,id,value,created_at) VALUES(?,?,?,?)')
|
| 30 | .run(kind, id, encoded, new Date().toISOString());
|
| 31 | }
|
| 32 | list(kind: string): unknown[] {
|
| 33 | return (
|
| 34 | this.db
|
| 35 | .prepare('SELECT value FROM audit_records WHERE kind=? ORDER BY created_at')
|
| 36 | .all(kind) as { value: string }[]
|
| 37 | ).map((row) => JSON.parse(row.value));
|
| 38 | }
|
| 39 | close(): void {
|
| 40 | this.db.close();
|
| 41 | }
|
| 42 | }
|