@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,137 @@
1
+ /**
2
+ * FTS5 Full-Text Search Store
3
+ *
4
+ * Provides full-text search capabilities using SQLite FTS5 extension.
5
+ * Used for semantic search over memory items.
6
+ *
7
+ * Invariants:
8
+ * - INV-FTS-001: FTS index updated on every insert/update/delete
9
+ * - INV-FTS-002: Search results ranked by relevance (BM25)
10
+ * - INV-FTS-003: Support for phrase and prefix queries
11
+ */
12
+ import type Database from 'better-sqlite3';
13
+ /**
14
+ * FTS search result
15
+ */
16
+ export interface FTSResult {
17
+ key: string;
18
+ namespace: string;
19
+ value: string;
20
+ snippet: string;
21
+ rank: number;
22
+ createdAt: string;
23
+ }
24
+ /**
25
+ * FTS search options
26
+ */
27
+ export interface FTSSearchOptions {
28
+ /** Namespace to search within */
29
+ namespace?: string | undefined;
30
+ /** Maximum results to return */
31
+ limit?: number | undefined;
32
+ /** Offset for pagination */
33
+ offset?: number | undefined;
34
+ /** Highlight snippets around matches */
35
+ highlight?: boolean | undefined;
36
+ /** Prefix for highlighted text */
37
+ highlightPrefix?: string | undefined;
38
+ /** Suffix for highlighted text */
39
+ highlightSuffix?: string | undefined;
40
+ }
41
+ /**
42
+ * FTS item to index
43
+ */
44
+ export interface FTSItem {
45
+ key: string;
46
+ namespace: string;
47
+ value: string;
48
+ tags?: string[] | undefined;
49
+ metadata?: Record<string, unknown> | undefined;
50
+ }
51
+ /**
52
+ * Error thrown by FTS store operations
53
+ */
54
+ export declare class FTSStoreError extends Error {
55
+ readonly code: string;
56
+ readonly details?: Record<string, unknown> | undefined;
57
+ constructor(code: string, message: string, details?: Record<string, unknown> | undefined);
58
+ }
59
+ /**
60
+ * Error codes for FTS store
61
+ */
62
+ export declare const FTSStoreErrorCodes: {
63
+ readonly INDEX_ERROR: "FTS_INDEX_ERROR";
64
+ readonly SEARCH_ERROR: "FTS_SEARCH_ERROR";
65
+ readonly DATABASE_ERROR: "FTS_DATABASE_ERROR";
66
+ };
67
+ /**
68
+ * SQLite FTS5 Store implementation
69
+ */
70
+ export declare class SQLiteFTSStore {
71
+ private readonly db;
72
+ private readonly tableName;
73
+ private readonly ftsTableName;
74
+ constructor(db: Database.Database, tableName?: string);
75
+ /**
76
+ * Initializes the database schema with FTS5 support
77
+ */
78
+ private initialize;
79
+ /**
80
+ * Stores an item with full-text indexing
81
+ */
82
+ store(item: FTSItem): void;
83
+ /**
84
+ * Retrieves an item by key and namespace
85
+ */
86
+ get(key: string, namespace?: string): FTSItem | null;
87
+ /**
88
+ * Deletes an item by key and namespace
89
+ */
90
+ delete(key: string, namespace?: string): boolean;
91
+ /**
92
+ * Full-text search with BM25 ranking
93
+ * INV-FTS-002: Results ranked by relevance
94
+ * INV-FTS-003: Supports phrase and prefix queries
95
+ *
96
+ * @param query - FTS5 query string (supports AND, OR, NOT, phrases, prefixes)
97
+ * @param options - Search options
98
+ */
99
+ search(query: string, options?: FTSSearchOptions): FTSResult[];
100
+ /**
101
+ * Lists all items in a namespace
102
+ */
103
+ list(namespace?: string, limit?: number, offset?: number): FTSItem[];
104
+ /**
105
+ * Counts items in a namespace
106
+ */
107
+ count(namespace?: string): number;
108
+ /**
109
+ * Clears all items in a namespace
110
+ */
111
+ clear(namespace?: string): number;
112
+ /**
113
+ * Rebuilds the FTS index
114
+ */
115
+ rebuildIndex(): void;
116
+ /**
117
+ * Optimizes the FTS index
118
+ */
119
+ optimizeIndex(): void;
120
+ /**
121
+ * Gets index statistics
122
+ */
123
+ getStats(): {
124
+ totalItems: number;
125
+ namespaces: string[];
126
+ indexSize: number;
127
+ };
128
+ /**
129
+ * Escapes special characters in FTS5 query
130
+ */
131
+ private escapeQuery;
132
+ }
133
+ /**
134
+ * Creates a SQLite FTS store
135
+ */
136
+ export declare function createSQLiteFTSStore(db: Database.Database, tableName?: string): SQLiteFTSStore;
137
+ //# sourceMappingURL=fts-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fts-store.d.ts","sourceRoot":"","sources":["../src/fts-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,wCAAwC;IACxC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,kCAAkC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,kCAAkC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CAChD;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;aAEpB,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,kBAAkB;;;;CAIrB,CAAC;AAEX;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,SAAiB;IAO7D;;OAEG;IACH,OAAO,CAAC,UAAU;IAyDlB;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAwB1B;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAY,GAAG,OAAO,GAAG,IAAI;IAgBvD;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAY,GAAG,OAAO;IAUnD;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS,EAAE;IA6DlE;;OAEG;IACH,IAAI,CAAC,SAAS,SAAY,EAAE,KAAK,SAAM,EAAE,MAAM,SAAI,GAAG,OAAO,EAAE;IAa/D;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAcjC;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAcjC;;OAEG;IACH,YAAY,IAAI,IAAI;IAIpB;;OAEG;IACH,aAAa,IAAI,IAAI;IAIrB;;OAEG;IACH,QAAQ,IAAI;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAwB3E;;OAEG;IACH,OAAO,CAAC,WAAW;CAapB;AA8CD;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,CAAC,EAAE,MAAM,GACjB,cAAc,CAEhB"}
@@ -0,0 +1,312 @@
1
+ /**
2
+ * FTS5 Full-Text Search Store
3
+ *
4
+ * Provides full-text search capabilities using SQLite FTS5 extension.
5
+ * Used for semantic search over memory items.
6
+ *
7
+ * Invariants:
8
+ * - INV-FTS-001: FTS index updated on every insert/update/delete
9
+ * - INV-FTS-002: Search results ranked by relevance (BM25)
10
+ * - INV-FTS-003: Support for phrase and prefix queries
11
+ */
12
+ /**
13
+ * Error thrown by FTS store operations
14
+ */
15
+ export class FTSStoreError extends Error {
16
+ code;
17
+ details;
18
+ constructor(code, message, details) {
19
+ super(message);
20
+ this.code = code;
21
+ this.details = details;
22
+ this.name = 'FTSStoreError';
23
+ }
24
+ }
25
+ /**
26
+ * Error codes for FTS store
27
+ */
28
+ export const FTSStoreErrorCodes = {
29
+ INDEX_ERROR: 'FTS_INDEX_ERROR',
30
+ SEARCH_ERROR: 'FTS_SEARCH_ERROR',
31
+ DATABASE_ERROR: 'FTS_DATABASE_ERROR',
32
+ };
33
+ /**
34
+ * SQLite FTS5 Store implementation
35
+ */
36
+ export class SQLiteFTSStore {
37
+ db;
38
+ tableName;
39
+ ftsTableName;
40
+ constructor(db, tableName = 'memory_items') {
41
+ this.db = db;
42
+ this.tableName = tableName;
43
+ this.ftsTableName = `${tableName}_fts`;
44
+ this.initialize();
45
+ }
46
+ /**
47
+ * Initializes the database schema with FTS5 support
48
+ */
49
+ initialize() {
50
+ // Main table for memory items
51
+ this.db.exec(`
52
+ CREATE TABLE IF NOT EXISTS ${this.tableName} (
53
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
54
+ key TEXT NOT NULL,
55
+ namespace TEXT NOT NULL DEFAULT 'default',
56
+ value TEXT NOT NULL,
57
+ tags TEXT,
58
+ metadata TEXT,
59
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
60
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
61
+ UNIQUE(key, namespace)
62
+ );
63
+
64
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_namespace
65
+ ON ${this.tableName}(namespace);
66
+
67
+ CREATE INDEX IF NOT EXISTS idx_${this.tableName}_created_at
68
+ ON ${this.tableName}(created_at);
69
+ `);
70
+ // FTS5 virtual table for full-text search
71
+ // INV-FTS-002: Using BM25 ranking algorithm
72
+ this.db.exec(`
73
+ CREATE VIRTUAL TABLE IF NOT EXISTS ${this.ftsTableName} USING fts5(
74
+ key,
75
+ namespace,
76
+ value,
77
+ tags,
78
+ content='${this.tableName}',
79
+ content_rowid='id',
80
+ tokenize='porter unicode61'
81
+ );
82
+ `);
83
+ // Triggers to keep FTS index in sync (INV-FTS-001)
84
+ this.db.exec(`
85
+ CREATE TRIGGER IF NOT EXISTS ${this.tableName}_ai AFTER INSERT ON ${this.tableName} BEGIN
86
+ INSERT INTO ${this.ftsTableName}(rowid, key, namespace, value, tags)
87
+ VALUES (new.id, new.key, new.namespace, new.value, new.tags);
88
+ END;
89
+
90
+ CREATE TRIGGER IF NOT EXISTS ${this.tableName}_ad AFTER DELETE ON ${this.tableName} BEGIN
91
+ INSERT INTO ${this.ftsTableName}(${this.ftsTableName}, rowid, key, namespace, value, tags)
92
+ VALUES ('delete', old.id, old.key, old.namespace, old.value, old.tags);
93
+ END;
94
+
95
+ CREATE TRIGGER IF NOT EXISTS ${this.tableName}_au AFTER UPDATE ON ${this.tableName} BEGIN
96
+ INSERT INTO ${this.ftsTableName}(${this.ftsTableName}, rowid, key, namespace, value, tags)
97
+ VALUES ('delete', old.id, old.key, old.namespace, old.value, old.tags);
98
+ INSERT INTO ${this.ftsTableName}(rowid, key, namespace, value, tags)
99
+ VALUES (new.id, new.key, new.namespace, new.value, new.tags);
100
+ END;
101
+ `);
102
+ }
103
+ /**
104
+ * Stores an item with full-text indexing
105
+ */
106
+ store(item) {
107
+ const tagsStr = item.tags?.join(' ') ?? null;
108
+ const metadataStr = item.metadata ? JSON.stringify(item.metadata) : null;
109
+ try {
110
+ const stmt = this.db.prepare(`
111
+ INSERT INTO ${this.tableName} (key, namespace, value, tags, metadata)
112
+ VALUES (?, ?, ?, ?, ?)
113
+ ON CONFLICT(key, namespace) DO UPDATE SET
114
+ value = excluded.value,
115
+ tags = excluded.tags,
116
+ metadata = excluded.metadata,
117
+ updated_at = datetime('now')
118
+ `);
119
+ stmt.run(item.key, item.namespace, item.value, tagsStr, metadataStr);
120
+ }
121
+ catch (error) {
122
+ throw new FTSStoreError(FTSStoreErrorCodes.INDEX_ERROR, `Failed to store item: ${error instanceof Error ? error.message : 'Unknown error'}`);
123
+ }
124
+ }
125
+ /**
126
+ * Retrieves an item by key and namespace
127
+ */
128
+ get(key, namespace = 'default') {
129
+ const stmt = this.db.prepare(`
130
+ SELECT key, namespace, value, tags, metadata
131
+ FROM ${this.tableName}
132
+ WHERE key = ? AND namespace = ?
133
+ `);
134
+ const row = stmt.get(key, namespace);
135
+ if (!row) {
136
+ return null;
137
+ }
138
+ return rowToItem(row);
139
+ }
140
+ /**
141
+ * Deletes an item by key and namespace
142
+ */
143
+ delete(key, namespace = 'default') {
144
+ const stmt = this.db.prepare(`
145
+ DELETE FROM ${this.tableName}
146
+ WHERE key = ? AND namespace = ?
147
+ `);
148
+ const result = stmt.run(key, namespace);
149
+ return result.changes > 0;
150
+ }
151
+ /**
152
+ * Full-text search with BM25 ranking
153
+ * INV-FTS-002: Results ranked by relevance
154
+ * INV-FTS-003: Supports phrase and prefix queries
155
+ *
156
+ * @param query - FTS5 query string (supports AND, OR, NOT, phrases, prefixes)
157
+ * @param options - Search options
158
+ */
159
+ search(query, options = {}) {
160
+ const { namespace, limit = 50, offset = 0, highlight = true, highlightPrefix = '**', highlightSuffix = '**', } = options;
161
+ try {
162
+ // Escape special FTS5 characters in query
163
+ const escapedQuery = this.escapeQuery(query);
164
+ let sql = `
165
+ SELECT
166
+ m.key,
167
+ m.namespace,
168
+ m.value,
169
+ ${highlight ? `highlight(${this.ftsTableName}, 2, '${highlightPrefix}', '${highlightSuffix}')` : 'm.value'} as snippet,
170
+ bm25(${this.ftsTableName}) as rank,
171
+ m.created_at
172
+ FROM ${this.ftsTableName} fts
173
+ JOIN ${this.tableName} m ON fts.rowid = m.id
174
+ WHERE ${this.ftsTableName} MATCH ?
175
+ `;
176
+ const params = [escapedQuery];
177
+ if (namespace !== undefined) {
178
+ sql += ` AND m.namespace = ?`;
179
+ params.push(namespace);
180
+ }
181
+ sql += `
182
+ ORDER BY rank
183
+ LIMIT ? OFFSET ?
184
+ `;
185
+ params.push(limit, offset);
186
+ const stmt = this.db.prepare(sql);
187
+ const rows = stmt.all(...params);
188
+ return rows.map((row) => ({
189
+ key: row.key,
190
+ namespace: row.namespace,
191
+ value: row.value,
192
+ snippet: row.snippet,
193
+ rank: row.rank,
194
+ createdAt: row.created_at,
195
+ }));
196
+ }
197
+ catch (error) {
198
+ throw new FTSStoreError(FTSStoreErrorCodes.SEARCH_ERROR, `Search failed: ${error instanceof Error ? error.message : 'Unknown error'}`, { query });
199
+ }
200
+ }
201
+ /**
202
+ * Lists all items in a namespace
203
+ */
204
+ list(namespace = 'default', limit = 100, offset = 0) {
205
+ const stmt = this.db.prepare(`
206
+ SELECT key, namespace, value, tags, metadata
207
+ FROM ${this.tableName}
208
+ WHERE namespace = ?
209
+ ORDER BY created_at DESC
210
+ LIMIT ? OFFSET ?
211
+ `);
212
+ const rows = stmt.all(namespace, limit, offset);
213
+ return rows.map(rowToItem);
214
+ }
215
+ /**
216
+ * Counts items in a namespace
217
+ */
218
+ count(namespace) {
219
+ let sql = `SELECT COUNT(*) as count FROM ${this.tableName}`;
220
+ const params = [];
221
+ if (namespace !== undefined) {
222
+ sql += ` WHERE namespace = ?`;
223
+ params.push(namespace);
224
+ }
225
+ const stmt = this.db.prepare(sql);
226
+ const row = stmt.get(...params);
227
+ return row.count;
228
+ }
229
+ /**
230
+ * Clears all items in a namespace
231
+ */
232
+ clear(namespace) {
233
+ let sql = `DELETE FROM ${this.tableName}`;
234
+ const params = [];
235
+ if (namespace !== undefined) {
236
+ sql += ` WHERE namespace = ?`;
237
+ params.push(namespace);
238
+ }
239
+ const stmt = this.db.prepare(sql);
240
+ const result = stmt.run(...params);
241
+ return result.changes;
242
+ }
243
+ /**
244
+ * Rebuilds the FTS index
245
+ */
246
+ rebuildIndex() {
247
+ this.db.exec(`INSERT INTO ${this.ftsTableName}(${this.ftsTableName}) VALUES('rebuild')`);
248
+ }
249
+ /**
250
+ * Optimizes the FTS index
251
+ */
252
+ optimizeIndex() {
253
+ this.db.exec(`INSERT INTO ${this.ftsTableName}(${this.ftsTableName}) VALUES('optimize')`);
254
+ }
255
+ /**
256
+ * Gets index statistics
257
+ */
258
+ getStats() {
259
+ const countStmt = this.db.prepare(`SELECT COUNT(*) as count FROM ${this.tableName}`);
260
+ const countRow = countStmt.get();
261
+ const nsStmt = this.db.prepare(`SELECT DISTINCT namespace FROM ${this.tableName}`);
262
+ const nsRows = nsStmt.all();
263
+ // Approximate index size from page count
264
+ const sizeStmt = this.db.prepare(`
265
+ SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()
266
+ `);
267
+ const sizeRow = sizeStmt.get();
268
+ return {
269
+ totalItems: countRow.count,
270
+ namespaces: nsRows.map((r) => r.namespace),
271
+ indexSize: sizeRow?.size ?? 0,
272
+ };
273
+ }
274
+ /**
275
+ * Escapes special characters in FTS5 query
276
+ */
277
+ escapeQuery(query) {
278
+ // Handle common query patterns
279
+ // Allow: AND, OR, NOT, quotes for phrases, * for prefix
280
+ // Escape: - at start, special chars
281
+ // If query looks like natural language, wrap in quotes for phrase search
282
+ if (!query.includes('"') && !query.includes('*') && !(/\b(AND|OR|NOT)\b/i.exec(query))) {
283
+ // Simple query - treat as phrase
284
+ return `"${query.replace(/"/g, '""')}"`;
285
+ }
286
+ return query;
287
+ }
288
+ }
289
+ /**
290
+ * Converts a database row to an FTSItem
291
+ */
292
+ function rowToItem(row) {
293
+ const item = {
294
+ key: row.key,
295
+ namespace: row.namespace,
296
+ value: row.value,
297
+ };
298
+ if (row.tags !== null) {
299
+ item.tags = row.tags.split(' ').filter((t) => t.length > 0);
300
+ }
301
+ if (row.metadata !== null) {
302
+ item.metadata = JSON.parse(row.metadata);
303
+ }
304
+ return item;
305
+ }
306
+ /**
307
+ * Creates a SQLite FTS store
308
+ */
309
+ export function createSQLiteFTSStore(db, tableName) {
310
+ return new SQLiteFTSStore(db, tableName);
311
+ }
312
+ //# sourceMappingURL=fts-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fts-store.js","sourceRoot":"","sources":["../src/fts-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { SqliteEventStore, SqliteEventStoreError, SqliteEventStoreErrorCodes, createSqliteEventStore, } from './event-store.js';
2
+ export { SqliteTraceStore, SqliteTraceStoreError, SqliteTraceStoreErrorCodes, createSqliteTraceStore, } from './trace-store.js';
3
+ export { SQLiteFTSStore, FTSStoreError, FTSStoreErrorCodes, createSQLiteFTSStore, type FTSResult, type FTSSearchOptions, type FTSItem, } from './fts-store.js';
4
+ export { SqliteCheckpointStorage, SqliteCheckpointStoreError, SqliteCheckpointStoreErrorCodes, createSqliteCheckpointStorage, } from './checkpoint-store.js';
5
+ export { SqliteDeadLetterStorage, SqliteDeadLetterStoreError, SqliteDeadLetterStoreErrorCodes, createSqliteDeadLetterStorage, } from './dead-letter-store.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,OAAO,GACb,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,+BAA+B,EAC/B,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,+BAA+B,EAC/B,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { SqliteEventStore, SqliteEventStoreError, SqliteEventStoreErrorCodes, createSqliteEventStore, } from './event-store.js';
2
+ export { SqliteTraceStore, SqliteTraceStoreError, SqliteTraceStoreErrorCodes, createSqliteTraceStore, } from './trace-store.js';
3
+ export { SQLiteFTSStore, FTSStoreError, FTSStoreErrorCodes, createSQLiteFTSStore, } from './fts-store.js';
4
+ export { SqliteCheckpointStorage, SqliteCheckpointStoreError, SqliteCheckpointStoreErrorCodes, createSqliteCheckpointStorage, } from './checkpoint-store.js';
5
+ export { SqliteDeadLetterStorage, SqliteDeadLetterStoreError, SqliteDeadLetterStoreErrorCodes, createSqliteDeadLetterStorage, } from './dead-letter-store.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,oBAAoB,GAIrB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,+BAA+B,EAC/B,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,+BAA+B,EAC/B,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,74 @@
1
+ import type { TraceEvent } from '@defai.digital/contracts';
2
+ import type { TraceStore, TraceSummary } from '@defai.digital/trace-domain';
3
+ import type Database from 'better-sqlite3';
4
+ /**
5
+ * Error thrown by SQLite trace store operations
6
+ */
7
+ export declare class SqliteTraceStoreError 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 trace store
14
+ */
15
+ export declare const SqliteTraceStoreErrorCodes: {
16
+ readonly DATABASE_ERROR: "SQLITE_TRACE_DATABASE_ERROR";
17
+ readonly INVALID_EVENT: "SQLITE_TRACE_INVALID_EVENT";
18
+ };
19
+ /**
20
+ * SQLite implementation of TraceStore
21
+ * INV-TR-002: Events are strictly ordered by sequence
22
+ * INV-TR-004: Each trace is independent and self-contained
23
+ */
24
+ export declare class SqliteTraceStore implements TraceStore {
25
+ private readonly db;
26
+ private readonly eventsTable;
27
+ private readonly summariesTable;
28
+ constructor(db: Database.Database, eventsTable?: string, summariesTable?: string);
29
+ /**
30
+ * Initializes the database schema
31
+ */
32
+ private initialize;
33
+ /**
34
+ * Writes a trace event
35
+ * INV-TR-002: Events must be strictly ordered
36
+ */
37
+ write(event: TraceEvent): Promise<void>;
38
+ /**
39
+ * Flushes pending writes
40
+ * For SQLite, this is a no-op since we write immediately
41
+ */
42
+ flush(): Promise<void>;
43
+ /**
44
+ * Gets all events for a trace
45
+ * INV-TR-002: Events returned in sequence order
46
+ */
47
+ getTrace(traceId: string): Promise<TraceEvent[]>;
48
+ /**
49
+ * Gets a specific event
50
+ */
51
+ getEvent(traceId: string, eventId: string): Promise<TraceEvent | undefined>;
52
+ /**
53
+ * Lists recent traces
54
+ */
55
+ listTraces(limit?: number): Promise<TraceSummary[]>;
56
+ /**
57
+ * Updates trace summary based on event
58
+ */
59
+ private updateSummary;
60
+ /**
61
+ * Clears all traces (for testing only)
62
+ */
63
+ clear(): void;
64
+ /**
65
+ * Deletes a trace and all its events
66
+ * @returns true if trace existed and was deleted
67
+ */
68
+ deleteTrace(traceId: string): Promise<boolean>;
69
+ }
70
+ /**
71
+ * Creates a SQLite trace store
72
+ */
73
+ export declare function createSqliteTraceStore(db: Database.Database, eventsTable?: string, summariesTable?: string): SqliteTraceStore;
74
+ //# sourceMappingURL=trace-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-store.d.ts","sourceRoot":"","sources":["../src/trace-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,0BAA0B,CAAC;AACxE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,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;;;CAG7B,CAAC;AAEX;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAGtC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,WAAW,SAAiB,EAC5B,cAAc,SAAoB;IAQpC;;OAEG;IACH,OAAO,CAAC,UAAU;IA8ClB;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAmCvC;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAahD;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAY3E;;OAEG;IACH,UAAU,CAAC,KAAK,SAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAahD;;OAEG;IACH,OAAO,CAAC,aAAa;IA6DrB;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAuB/C;AAqGD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,WAAW,CAAC,EAAE,MAAM,EACpB,cAAc,CAAC,EAAE,MAAM,GACtB,gBAAgB,CAElB"}