@aletheia-labs/store-sqlite 0.1.0

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,22 @@
1
+ /**
2
+ * Schema migrations for @aletheia-labs/store-sqlite.
3
+ *
4
+ * Migrations are embedded as strings so the package works the same when
5
+ * bundled. Each migration runs once and is recorded in `schema_migrations`.
6
+ *
7
+ * To add a migration: append to the MIGRATIONS array with the next version
8
+ * number. NEVER edit an existing migration — write a new one.
9
+ */
10
+ import type Database from 'better-sqlite3';
11
+ export interface Migration {
12
+ readonly version: number;
13
+ readonly name: string;
14
+ readonly sql: string;
15
+ }
16
+ export declare const MIGRATIONS: readonly Migration[];
17
+ /**
18
+ * Apply all pending migrations in order, inside a single transaction per migration.
19
+ * Idempotent — already-applied migrations are skipped.
20
+ */
21
+ export declare function applyMigrations(db: Database.Database): readonly Migration[];
22
+ //# sourceMappingURL=migrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,UAAU,EAAE,SAAS,SAAS,EA+G1C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,SAAS,SAAS,EAAE,CAoC3E"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Schema migrations for @aletheia-labs/store-sqlite.
3
+ *
4
+ * Migrations are embedded as strings so the package works the same when
5
+ * bundled. Each migration runs once and is recorded in `schema_migrations`.
6
+ *
7
+ * To add a migration: append to the MIGRATIONS array with the next version
8
+ * number. NEVER edit an existing migration — write a new one.
9
+ */
10
+ export const MIGRATIONS = [
11
+ {
12
+ version: 1,
13
+ name: 'initial-schema',
14
+ sql: `
15
+ -- Schema versioning ----------------------------------------------------------
16
+ CREATE TABLE IF NOT EXISTS schema_migrations (
17
+ version INTEGER PRIMARY KEY,
18
+ name TEXT NOT NULL,
19
+ applied_at TEXT NOT NULL
20
+ );
21
+
22
+ -- Events: append-only --------------------------------------------------------
23
+ CREATE TABLE IF NOT EXISTS events (
24
+ event_id TEXT PRIMARY KEY,
25
+ kind TEXT NOT NULL,
26
+ agent_id TEXT,
27
+ occurred_at TEXT NOT NULL,
28
+ payload_json TEXT NOT NULL,
29
+ scope_json TEXT NOT NULL,
30
+ visibility_json TEXT NOT NULL,
31
+ scope_key TEXT NOT NULL,
32
+ visibility_key TEXT NOT NULL,
33
+ inserted_at TEXT NOT NULL
34
+ );
35
+
36
+ CREATE INDEX IF NOT EXISTS idx_events_occurred_at ON events(occurred_at);
37
+ CREATE INDEX IF NOT EXISTS idx_events_agent ON events(agent_id);
38
+ CREATE INDEX IF NOT EXISTS idx_events_visibility_key ON events(visibility_key);
39
+ CREATE INDEX IF NOT EXISTS idx_events_scope_key ON events(scope_key);
40
+
41
+ -- Memory atoms ---------------------------------------------------------------
42
+ CREATE TABLE IF NOT EXISTS memory_atoms (
43
+ memory_id TEXT PRIMARY KEY,
44
+ memory_type TEXT NOT NULL,
45
+ content TEXT NOT NULL,
46
+ source_agent_id TEXT NOT NULL,
47
+ source_event_ids_json TEXT NOT NULL,
48
+ source_memory_ids_json TEXT NOT NULL,
49
+ scope_json TEXT NOT NULL,
50
+ visibility_json TEXT NOT NULL,
51
+ status TEXT NOT NULL,
52
+ scores_json TEXT NOT NULL,
53
+ valid_from TEXT NOT NULL,
54
+ valid_until TEXT,
55
+ last_confirmed_at TEXT,
56
+ links_json TEXT NOT NULL,
57
+ scope_key TEXT NOT NULL,
58
+ visibility_key TEXT NOT NULL,
59
+ inserted_at TEXT NOT NULL
60
+ );
61
+
62
+ CREATE INDEX IF NOT EXISTS idx_atoms_status ON memory_atoms(status);
63
+ CREATE INDEX IF NOT EXISTS idx_atoms_visibility_key ON memory_atoms(visibility_key);
64
+ CREATE INDEX IF NOT EXISTS idx_atoms_scope_key ON memory_atoms(scope_key);
65
+ CREATE INDEX IF NOT EXISTS idx_atoms_valid_from ON memory_atoms(valid_from);
66
+
67
+ -- Status history -------------------------------------------------------------
68
+ CREATE TABLE IF NOT EXISTS memory_status_history (
69
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
70
+ memory_id TEXT NOT NULL REFERENCES memory_atoms(memory_id),
71
+ from_status TEXT,
72
+ to_status TEXT NOT NULL,
73
+ rationale TEXT NOT NULL,
74
+ actor TEXT NOT NULL,
75
+ conflict_id TEXT,
76
+ at TEXT NOT NULL
77
+ );
78
+
79
+ CREATE INDEX IF NOT EXISTS idx_msh_memory_at ON memory_status_history(memory_id, at);
80
+
81
+ -- Conflicts ------------------------------------------------------------------
82
+ CREATE TABLE IF NOT EXISTS conflicts (
83
+ conflict_id TEXT PRIMARY KEY,
84
+ topic TEXT NOT NULL,
85
+ scope_json TEXT NOT NULL,
86
+ scope_key TEXT NOT NULL,
87
+ claims_json TEXT NOT NULL,
88
+ status TEXT NOT NULL,
89
+ decision_policy TEXT NOT NULL,
90
+ recorded_at TEXT NOT NULL,
91
+ resolved_at TEXT
92
+ );
93
+
94
+ CREATE INDEX IF NOT EXISTS idx_conflicts_status ON conflicts(status);
95
+ CREATE INDEX IF NOT EXISTS idx_conflicts_scope_key ON conflicts(scope_key);
96
+
97
+ -- Conflict → atoms (many-to-many) for "touchingMemoryIds" queries -----------
98
+ CREATE TABLE IF NOT EXISTS conflict_claim_atoms (
99
+ conflict_id TEXT NOT NULL REFERENCES conflicts(conflict_id),
100
+ memory_id TEXT NOT NULL,
101
+ PRIMARY KEY (conflict_id, memory_id)
102
+ );
103
+
104
+ CREATE INDEX IF NOT EXISTS idx_cca_memory ON conflict_claim_atoms(memory_id);
105
+
106
+ -- Conflict resolution history ------------------------------------------------
107
+ CREATE TABLE IF NOT EXISTS conflict_resolution_history (
108
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
109
+ conflict_id TEXT NOT NULL REFERENCES conflicts(conflict_id),
110
+ from_status TEXT NOT NULL,
111
+ to_status TEXT NOT NULL,
112
+ rationale TEXT NOT NULL,
113
+ actor TEXT NOT NULL,
114
+ preferred_memory_id TEXT,
115
+ at TEXT NOT NULL
116
+ );
117
+
118
+ CREATE INDEX IF NOT EXISTS idx_crh_conflict_at ON conflict_resolution_history(conflict_id, at);
119
+ `.trim(),
120
+ },
121
+ ];
122
+ /**
123
+ * Apply all pending migrations in order, inside a single transaction per migration.
124
+ * Idempotent — already-applied migrations are skipped.
125
+ */
126
+ export function applyMigrations(db) {
127
+ // Bootstrap the schema_migrations table if it doesn't exist yet.
128
+ // Done outside the migration loop so the loop can rely on its presence.
129
+ db.exec(`
130
+ CREATE TABLE IF NOT EXISTS schema_migrations (
131
+ version INTEGER PRIMARY KEY,
132
+ name TEXT NOT NULL,
133
+ applied_at TEXT NOT NULL
134
+ );
135
+ `);
136
+ const applied = new Set(db
137
+ .prepare('SELECT version FROM schema_migrations')
138
+ .all()
139
+ .map((r) => r.version));
140
+ const newlyApplied = [];
141
+ const insertMigration = db.prepare('INSERT INTO schema_migrations (version, name, applied_at) VALUES (?, ?, ?)');
142
+ for (const migration of MIGRATIONS) {
143
+ if (applied.has(migration.version))
144
+ continue;
145
+ const tx = db.transaction(() => {
146
+ db.exec(migration.sql);
147
+ insertMigration.run(migration.version, migration.name, new Date().toISOString());
148
+ });
149
+ tx();
150
+ newlyApplied.push(migration);
151
+ }
152
+ return newlyApplied;
153
+ }
154
+ //# sourceMappingURL=migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,MAAM,CAAC,MAAM,UAAU,GAAyB;IAC9C;QACE,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,gBAAgB;QACtB,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyGJ,CAAC,IAAI,EAAE;KACT;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAAqB;IACnD,iEAAiE;IACjE,wEAAwE;IACxE,EAAE,CAAC,IAAI,CAAC;;;;;;GAMP,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,EAAE;SACC,OAAO,CAA0B,uCAAuC,CAAC;SACzE,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CACzB,CAAC;IAEF,MAAM,YAAY,GAAgB,EAAE,CAAC;IAErC,MAAM,eAAe,GAAG,EAAE,CAAC,OAAO,CAChC,4EAA4E,CAC7E,CAAC;IAEF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;YAAE,SAAS;QAE7C,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;YAC7B,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACvB,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QACnF,CAAC,CAAC,CAAC;QACH,EAAE,EAAE,CAAC;QACL,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * SQLite-backed ConflictRegistry.
3
+ *
4
+ * Conflicts are append-only by ID; the only allowed mutation is `resolve`,
5
+ * which updates `status` + `resolved_at` and records an entry in
6
+ * `conflict_resolution_history`.
7
+ */
8
+ import { type ConflictId, type ConflictQuery, type ConflictRecord, type ConflictRegistry, type ConflictStatus, type IsoTimestamp, type ResolveReason, type Visibility } from '@aletheia-labs/core';
9
+ import type Database from 'better-sqlite3';
10
+ export declare class SqliteConflictRegistry implements ConflictRegistry {
11
+ private readonly db;
12
+ private readonly insertConflict;
13
+ private readonly insertClaimLink;
14
+ private readonly getConflictByID;
15
+ private readonly updateConflictStatus;
16
+ private readonly insertResolution;
17
+ private readonly resolutionHistoryStmt;
18
+ /**
19
+ * Create a ConflictRegistry backed by an existing SQLite connection.
20
+ *
21
+ * @remarks
22
+ * The constructor prepares all statements up front. Use `openSqliteStores()`
23
+ * unless a host needs direct control over connection ownership.
24
+ */
25
+ constructor(db: Database.Database);
26
+ /**
27
+ * Record a new first-class conflict and index all touched memory IDs.
28
+ *
29
+ * @remarks
30
+ * Conflict rows are append-only by ID. The join table is maintained inside
31
+ * the same transaction so `touchingMemoryIds` queries stay deterministic.
32
+ */
33
+ record(conflict: ConflictRecord): Promise<ConflictRecord>;
34
+ /**
35
+ * Retrieve one conflict if conflict access is permitted.
36
+ *
37
+ * @remarks
38
+ * Phase 1 conflict visibility is coarse: an empty permitted set fails closed;
39
+ * action paths still re-check the visibility of cited memory atoms before use.
40
+ */
41
+ get(conflictId: ConflictId, permittedVisibilities: readonly Visibility[]): Promise<ConflictRecord | null>;
42
+ /**
43
+ * Query conflicts by status, scope, and touched memory IDs.
44
+ *
45
+ * @remarks
46
+ * Returns an empty list when no visibility planes are permitted. This mirrors
47
+ * the fail-closed behavior of the other stores.
48
+ */
49
+ query(filter: ConflictQuery): Promise<readonly ConflictRecord[]>;
50
+ /**
51
+ * Resolve a conflict and append a resolution-history row.
52
+ *
53
+ * @remarks
54
+ * Resolution is the only mutation path for conflicts. A repeated transition
55
+ * to the current status returns the existing row without adding history.
56
+ */
57
+ resolve(conflictId: ConflictId, nextStatus: Exclude<ConflictStatus, 'unresolved'>, reason: ResolveReason): Promise<ConflictRecord | null>;
58
+ /**
59
+ * Return the audited resolution history for one conflict.
60
+ */
61
+ resolutionHistory(conflictId: ConflictId): Promise<readonly {
62
+ at: IsoTimestamp;
63
+ fromStatus: ConflictStatus;
64
+ toStatus: ConflictStatus;
65
+ reason: ResolveReason;
66
+ }[]>;
67
+ }
68
+ //# sourceMappingURL=sqlite-conflict-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-conflict-registry.d.ts","sourceRoot":"","sources":["../src/sqlite-conflict-registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,cAAc,EAEnB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,YAAY,EAEjB,KAAK,aAAa,EAClB,KAAK,UAAU,EAEhB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAY3C,qBAAa,sBAAuB,YAAW,gBAAgB;IAejD,OAAO,CAAC,QAAQ,CAAC,EAAE;IAd/B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA+B;IAC/D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAqB;IAC1D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA+B;IAErE;;;;;;OAMG;gBAC0B,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAkClD;;;;;;OAMG;IACG,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;IAuB/D;;;;;;OAMG;IACG,GAAG,CACP,UAAU,EAAE,UAAU,EACtB,qBAAqB,EAAE,SAAS,UAAU,EAAE,GAC3C,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAWjC;;;;;;OAMG;IACG,KAAK,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC;IAoCtE;;;;;;OAMG;IACG,OAAO,CACX,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,OAAO,CAAC,cAAc,EAAE,YAAY,CAAC,EACjD,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IA8BjC;;OAEG;IACG,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CACtD,SAAS;QACP,EAAE,EAAE,YAAY,CAAC;QACjB,UAAU,EAAE,cAAc,CAAC;QAC3B,QAAQ,EAAE,cAAc,CAAC;QACzB,MAAM,EAAE,aAAa,CAAC;KACvB,EAAE,CACJ;CAaF"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * SQLite-backed ConflictRegistry.
3
+ *
4
+ * Conflicts are append-only by ID; the only allowed mutation is `resolve`,
5
+ * which updates `status` + `resolved_at` and records an entry in
6
+ * `conflict_resolution_history`.
7
+ */
8
+ import { ConflictRecordSchema, scopeKey, } from '@aletheia-labs/core';
9
+ import { conflictToRow, rowToConflict } from './codec.js';
10
+ export class SqliteConflictRegistry {
11
+ db;
12
+ insertConflict;
13
+ insertClaimLink;
14
+ getConflictByID;
15
+ updateConflictStatus;
16
+ insertResolution;
17
+ resolutionHistoryStmt;
18
+ /**
19
+ * Create a ConflictRegistry backed by an existing SQLite connection.
20
+ *
21
+ * @remarks
22
+ * The constructor prepares all statements up front. Use `openSqliteStores()`
23
+ * unless a host needs direct control over connection ownership.
24
+ */
25
+ constructor(db) {
26
+ this.db = db;
27
+ this.insertConflict = db.prepare(`
28
+ INSERT INTO conflicts (
29
+ conflict_id, topic, scope_json, scope_key,
30
+ claims_json, status, decision_policy, recorded_at, resolved_at
31
+ ) VALUES (
32
+ @conflict_id, @topic, @scope_json, @scope_key,
33
+ @claims_json, @status, @decision_policy, @recorded_at, @resolved_at
34
+ )
35
+ `);
36
+ this.insertClaimLink = db.prepare('INSERT OR IGNORE INTO conflict_claim_atoms (conflict_id, memory_id) VALUES (?, ?)');
37
+ this.getConflictByID = db.prepare('SELECT * FROM conflicts WHERE conflict_id = ?');
38
+ this.updateConflictStatus = db.prepare('UPDATE conflicts SET status = ?, resolved_at = ? WHERE conflict_id = ?');
39
+ this.insertResolution = db.prepare(`
40
+ INSERT INTO conflict_resolution_history (
41
+ conflict_id, from_status, to_status, rationale, actor, preferred_memory_id, at
42
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
43
+ `);
44
+ this.resolutionHistoryStmt = db.prepare('SELECT * FROM conflict_resolution_history WHERE conflict_id = ? ORDER BY at ASC, id ASC');
45
+ }
46
+ /**
47
+ * Record a new first-class conflict and index all touched memory IDs.
48
+ *
49
+ * @remarks
50
+ * Conflict rows are append-only by ID. The join table is maintained inside
51
+ * the same transaction so `touchingMemoryIds` queries stay deterministic.
52
+ */
53
+ async record(conflict) {
54
+ const validated = ConflictRecordSchema.parse(conflict);
55
+ const row = conflictToRow(validated);
56
+ const tx = this.db.transaction(() => {
57
+ try {
58
+ this.insertConflict.run(row);
59
+ }
60
+ catch (err) {
61
+ if (err instanceof Error && err.message.includes('UNIQUE')) {
62
+ throw new Error(`ConflictRegistry.record: duplicate conflict_id "${row.conflict_id}"`);
63
+ }
64
+ throw err;
65
+ }
66
+ // Mirror claim atoms into the join table for "touchingMemoryIds" queries.
67
+ for (const claim of validated.claims) {
68
+ this.insertClaimLink.run(validated.conflictId, claim.memoryId);
69
+ }
70
+ });
71
+ tx();
72
+ return validated;
73
+ }
74
+ /**
75
+ * Retrieve one conflict if conflict access is permitted.
76
+ *
77
+ * @remarks
78
+ * Phase 1 conflict visibility is coarse: an empty permitted set fails closed;
79
+ * action paths still re-check the visibility of cited memory atoms before use.
80
+ */
81
+ async get(conflictId, permittedVisibilities) {
82
+ // Conflicts don't carry their own visibility; permission inherits from the
83
+ // most-restrictive scope of their claim atoms. For Phase 1 we treat
84
+ // conflict visibility as "any atom involved is visible to the caller".
85
+ // The caller must still respect the touching atoms' visibility when acting.
86
+ const row = this.getConflictByID.get(conflictId);
87
+ if (!row)
88
+ return null;
89
+ if (permittedVisibilities.length === 0)
90
+ return null;
91
+ return rowToConflict(row);
92
+ }
93
+ /**
94
+ * Query conflicts by status, scope, and touched memory IDs.
95
+ *
96
+ * @remarks
97
+ * Returns an empty list when no visibility planes are permitted. This mirrors
98
+ * the fail-closed behavior of the other stores.
99
+ */
100
+ async query(filter) {
101
+ if (filter.permittedVisibilities.length === 0) {
102
+ return [];
103
+ }
104
+ const where = [];
105
+ const params = [];
106
+ if (filter.statuses !== undefined && filter.statuses.length > 0) {
107
+ where.push(`status IN (${filter.statuses.map(() => '?').join(', ')})`);
108
+ params.push(...filter.statuses);
109
+ }
110
+ if (filter.scope !== undefined) {
111
+ where.push('scope_key = ?');
112
+ params.push(scopeKey(filter.scope));
113
+ }
114
+ if (filter.touchingMemoryIds !== undefined && filter.touchingMemoryIds.length > 0) {
115
+ where.push(`conflict_id IN (
116
+ SELECT conflict_id FROM conflict_claim_atoms
117
+ WHERE memory_id IN (${filter.touchingMemoryIds.map(() => '?').join(', ')})
118
+ )`);
119
+ params.push(...filter.touchingMemoryIds);
120
+ }
121
+ const whereClause = where.length > 0 ? `WHERE ${where.join(' AND ')}` : '';
122
+ const sql = `
123
+ SELECT * FROM conflicts
124
+ ${whereClause}
125
+ ORDER BY recorded_at DESC, conflict_id ASC
126
+ `;
127
+ const rows = this.db.prepare(sql).all(...params);
128
+ return rows.map(rowToConflict);
129
+ }
130
+ /**
131
+ * Resolve a conflict and append a resolution-history row.
132
+ *
133
+ * @remarks
134
+ * Resolution is the only mutation path for conflicts. A repeated transition
135
+ * to the current status returns the existing row without adding history.
136
+ */
137
+ async resolve(conflictId, nextStatus, reason) {
138
+ const row = this.getConflictByID.get(conflictId);
139
+ if (!row)
140
+ return null;
141
+ const current = row.status;
142
+ if (current === nextStatus) {
143
+ // Already in this status — no-op, but record the attempted resolution.
144
+ return rowToConflict(row);
145
+ }
146
+ const now = new Date().toISOString();
147
+ // The TS type already excludes 'unresolved' — `now` is always the resolution timestamp.
148
+ const tx = this.db.transaction(() => {
149
+ this.updateConflictStatus.run(nextStatus, now, conflictId);
150
+ this.insertResolution.run(conflictId, current, nextStatus, reason.rationale, reason.actor, reason.preferredMemoryId, now);
151
+ });
152
+ tx();
153
+ const updated = this.getConflictByID.get(conflictId);
154
+ return rowToConflict(updated);
155
+ }
156
+ /**
157
+ * Return the audited resolution history for one conflict.
158
+ */
159
+ async resolutionHistory(conflictId) {
160
+ const rows = this.resolutionHistoryStmt.all(conflictId);
161
+ return rows.map((r) => ({
162
+ at: r.at,
163
+ fromStatus: r.from_status,
164
+ toStatus: r.to_status,
165
+ reason: {
166
+ rationale: r.rationale,
167
+ actor: r.actor,
168
+ preferredMemoryId: r.preferred_memory_id,
169
+ },
170
+ }));
171
+ }
172
+ }
173
+ //# sourceMappingURL=sqlite-conflict-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-conflict-registry.js","sourceRoot":"","sources":["../src/sqlite-conflict-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * SQLite-backed EventLedger.
3
+ *
4
+ * Enforces append-only at the storage layer:
5
+ * - INSERT only. Duplicate event_id throws (no OR REPLACE, no OR IGNORE).
6
+ * - No DELETE or UPDATE path exposed.
7
+ *
8
+ * Permission filtering is done in SQL via the `visibility_key` index.
9
+ */
10
+ import { type Event, type EventId, type EventLedger, type EventQuery, type Visibility } from '@aletheia-labs/core';
11
+ import type Database from 'better-sqlite3';
12
+ export declare class SqliteEventLedger implements EventLedger {
13
+ private readonly db;
14
+ private readonly insertStmt;
15
+ private readonly getStmt;
16
+ /**
17
+ * Create an EventLedger backed by an existing `better-sqlite3` connection.
18
+ *
19
+ * @remarks
20
+ * Callers normally use `openSqliteStores()` instead. Direct construction is
21
+ * useful when a host owns connection lifecycle or wants to compose stores
22
+ * manually.
23
+ */
24
+ constructor(db: Database.Database);
25
+ /**
26
+ * Append one validated event to SQLite.
27
+ *
28
+ * @remarks
29
+ * Implementation uses plain INSERT and lets the primary key enforce
30
+ * append-only semantics. Duplicate IDs throw instead of replacing or ignoring
31
+ * existing evidence.
32
+ */
33
+ append(event: Event): Promise<EventId>;
34
+ /**
35
+ * Load one event if the caller can see its visibility plane.
36
+ *
37
+ * @remarks
38
+ * A missing row and a hidden row both return `null` so callers cannot infer
39
+ * the existence of inaccessible evidence.
40
+ */
41
+ get(eventId: EventId, permittedVisibilities: readonly Visibility[]): Promise<Event | null>;
42
+ /**
43
+ * Query visible events in deterministic chronological order.
44
+ *
45
+ * @remarks
46
+ * The SQL WHERE clause always starts with the permission predicate generated
47
+ * by `permittedClause()`, preserving permission-before-selection.
48
+ */
49
+ query(filter: EventQuery): Promise<readonly Event[]>;
50
+ /**
51
+ * Count visible events matching the same filters as `query()`.
52
+ *
53
+ * @remarks
54
+ * Use this for coverage/audit summaries without materializing rows.
55
+ */
56
+ count(filter: EventQuery): Promise<number>;
57
+ }
58
+ //# sourceMappingURL=sqlite-event-ledger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-event-ledger.d.ts","sourceRoot":"","sources":["../src/sqlite-event-ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,KAAK,KAAK,EACV,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,UAAU,EAEf,KAAK,UAAU,EAEhB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C,qBAAa,iBAAkB,YAAW,WAAW;IAYvC,OAAO,CAAC,QAAQ,CAAC,EAAE;IAX/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IAEvD;;;;;;;OAOG;gBAC0B,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAgBlD;;;;;;;OAOG;IACG,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IAkB5C;;;;;;OAMG;IACG,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAahG;;;;;;OAMG;IACG,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,KAAK,EAAE,CAAC;IAsC1D;;;;;OAKG;IACG,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;CA6BjD"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * SQLite-backed EventLedger.
3
+ *
4
+ * Enforces append-only at the storage layer:
5
+ * - INSERT only. Duplicate event_id throws (no OR REPLACE, no OR IGNORE).
6
+ * - No DELETE or UPDATE path exposed.
7
+ *
8
+ * Permission filtering is done in SQL via the `visibility_key` index.
9
+ */
10
+ import { EventSchema, scopeKey, } from '@aletheia-labs/core';
11
+ import { eventToRow, permittedClause, rowToEvent } from './codec.js';
12
+ export class SqliteEventLedger {
13
+ db;
14
+ insertStmt;
15
+ getStmt;
16
+ /**
17
+ * Create an EventLedger backed by an existing `better-sqlite3` connection.
18
+ *
19
+ * @remarks
20
+ * Callers normally use `openSqliteStores()` instead. Direct construction is
21
+ * useful when a host owns connection lifecycle or wants to compose stores
22
+ * manually.
23
+ */
24
+ constructor(db) {
25
+ this.db = db;
26
+ this.insertStmt = db.prepare(`
27
+ INSERT INTO events (
28
+ event_id, kind, agent_id, occurred_at,
29
+ payload_json, scope_json, visibility_json,
30
+ scope_key, visibility_key, inserted_at
31
+ ) VALUES (
32
+ @event_id, @kind, @agent_id, @occurred_at,
33
+ @payload_json, @scope_json, @visibility_json,
34
+ @scope_key, @visibility_key, @inserted_at
35
+ )
36
+ `);
37
+ this.getStmt = db.prepare('SELECT * FROM events WHERE event_id = ?');
38
+ }
39
+ /**
40
+ * Append one validated event to SQLite.
41
+ *
42
+ * @remarks
43
+ * Implementation uses plain INSERT and lets the primary key enforce
44
+ * append-only semantics. Duplicate IDs throw instead of replacing or ignoring
45
+ * existing evidence.
46
+ */
47
+ async append(event) {
48
+ // Validate before persisting. The schema enforces shape; SQLite enforces uniqueness.
49
+ const validated = EventSchema.parse(event);
50
+ const row = eventToRow(validated, new Date().toISOString());
51
+ try {
52
+ this.insertStmt.run(row);
53
+ }
54
+ catch (err) {
55
+ // better-sqlite3 throws SqliteError with code SQLITE_CONSTRAINT_PRIMARYKEY on duplicate
56
+ if (err instanceof Error && err.message.includes('UNIQUE')) {
57
+ throw new Error(`EventLedger.append: duplicate event_id "${row.event_id}"`);
58
+ }
59
+ throw err;
60
+ }
61
+ return validated.eventId;
62
+ }
63
+ /**
64
+ * Load one event if the caller can see its visibility plane.
65
+ *
66
+ * @remarks
67
+ * A missing row and a hidden row both return `null` so callers cannot infer
68
+ * the existence of inaccessible evidence.
69
+ */
70
+ async get(eventId, permittedVisibilities) {
71
+ const row = this.getStmt.get(eventId);
72
+ if (!row)
73
+ return null;
74
+ // Permission filter: never leak existence of events the caller can't see.
75
+ const allowed = permittedClause(permittedVisibilities);
76
+ if (allowed.params.length === 0 || !allowed.params.includes(row.visibility_key)) {
77
+ return null;
78
+ }
79
+ return rowToEvent(row);
80
+ }
81
+ /**
82
+ * Query visible events in deterministic chronological order.
83
+ *
84
+ * @remarks
85
+ * The SQL WHERE clause always starts with the permission predicate generated
86
+ * by `permittedClause()`, preserving permission-before-selection.
87
+ */
88
+ async query(filter) {
89
+ const where = [];
90
+ const params = [];
91
+ // Permission filter ALWAYS first.
92
+ const allowed = permittedClause(filter.permittedVisibilities);
93
+ where.push(allowed.clause);
94
+ params.push(...allowed.params);
95
+ if (filter.agentId !== undefined) {
96
+ where.push('agent_id = ?');
97
+ params.push(filter.agentId);
98
+ }
99
+ if (filter.since !== undefined) {
100
+ where.push('occurred_at >= ?');
101
+ params.push(filter.since);
102
+ }
103
+ if (filter.until !== undefined) {
104
+ where.push('occurred_at <= ?');
105
+ params.push(filter.until);
106
+ }
107
+ if (filter.scope !== undefined) {
108
+ where.push('scope_key = ?');
109
+ params.push(scopeKey(filter.scope));
110
+ }
111
+ const limitClause = filter.limit !== undefined ? `LIMIT ${Math.floor(filter.limit)}` : '';
112
+ const sql = `
113
+ SELECT * FROM events
114
+ WHERE ${where.join(' AND ')}
115
+ ORDER BY occurred_at ASC, event_id ASC
116
+ ${limitClause}
117
+ `;
118
+ const rows = this.db.prepare(sql).all(...params);
119
+ return rows.map(rowToEvent);
120
+ }
121
+ /**
122
+ * Count visible events matching the same filters as `query()`.
123
+ *
124
+ * @remarks
125
+ * Use this for coverage/audit summaries without materializing rows.
126
+ */
127
+ async count(filter) {
128
+ const where = [];
129
+ const params = [];
130
+ const allowed = permittedClause(filter.permittedVisibilities);
131
+ where.push(allowed.clause);
132
+ params.push(...allowed.params);
133
+ if (filter.agentId !== undefined) {
134
+ where.push('agent_id = ?');
135
+ params.push(filter.agentId);
136
+ }
137
+ if (filter.since !== undefined) {
138
+ where.push('occurred_at >= ?');
139
+ params.push(filter.since);
140
+ }
141
+ if (filter.until !== undefined) {
142
+ where.push('occurred_at <= ?');
143
+ params.push(filter.until);
144
+ }
145
+ if (filter.scope !== undefined) {
146
+ where.push('scope_key = ?');
147
+ params.push(scopeKey(filter.scope));
148
+ }
149
+ const sql = `SELECT COUNT(*) as n FROM events WHERE ${where.join(' AND ')}`;
150
+ const row = this.db.prepare(sql).get(...params);
151
+ return row.n;
152
+ }
153
+ }
154
+ //# sourceMappingURL=sqlite-event-ledger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-event-ledger.js","sourceRoot":"","sources":["../src/sqlite-event-ledger.ts"],"names":[],"mappings":"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"}