db4ai 0.3.0 → 0.3.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 (89) hide show
  1. package/dist/chunk-3DWAMVV5.js +305 -0
  2. package/dist/chunk-3DWAMVV5.js.map +1 -0
  3. package/dist/chunk-COTPYBYM.js +618 -0
  4. package/dist/chunk-COTPYBYM.js.map +1 -0
  5. package/dist/chunk-EERD6CDF.js +735 -0
  6. package/dist/chunk-EERD6CDF.js.map +1 -0
  7. package/dist/chunk-FUF4HJTC.js +758 -0
  8. package/dist/chunk-FUF4HJTC.js.map +1 -0
  9. package/dist/chunk-JLL6FH5L.js +16 -0
  10. package/dist/chunk-JLL6FH5L.js.map +1 -0
  11. package/dist/chunk-JXFW6AIT.js +192 -0
  12. package/dist/chunk-JXFW6AIT.js.map +1 -0
  13. package/dist/chunk-XLSYCQPG.js +854 -0
  14. package/dist/chunk-XLSYCQPG.js.map +1 -0
  15. package/dist/chunk-Y5IXAS7F.js +569 -0
  16. package/dist/chunk-Y5IXAS7F.js.map +1 -0
  17. package/dist/cli/bin.d.ts +13 -12
  18. package/dist/cli/bin.js +277 -307
  19. package/dist/cli/bin.js.map +1 -1
  20. package/dist/cli/dashboard/index.d.ts +295 -14
  21. package/dist/cli/dashboard/index.js +60 -15
  22. package/dist/cli/dashboard/index.js.map +1 -1
  23. package/dist/cli/index.d.ts +10 -16
  24. package/dist/cli/index.js +94 -47
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/cli/runtime/index.d.ts +52 -23
  27. package/dist/cli/runtime/index.js +10 -704
  28. package/dist/cli/runtime/index.js.map +1 -1
  29. package/dist/cli/scanner/index.d.ts +17 -15
  30. package/dist/cli/scanner/index.js +8 -639
  31. package/dist/cli/scanner/index.js.map +1 -1
  32. package/dist/cli/seed/index.d.ts +16 -12
  33. package/dist/cli/seed/index.js +12 -773
  34. package/dist/cli/seed/index.js.map +1 -1
  35. package/dist/cli/sync/index.d.ts +54 -53
  36. package/dist/cli/sync/index.js +23 -704
  37. package/dist/cli/sync/index.js.map +1 -1
  38. package/dist/cli/terminal.d.ts +9 -8
  39. package/dist/cli/terminal.js +6 -209
  40. package/dist/cli/terminal.js.map +1 -1
  41. package/dist/cli/workflow/index.d.ts +18 -10
  42. package/dist/cli/workflow/index.js +6 -307
  43. package/dist/cli/workflow/index.js.map +1 -1
  44. package/dist/handlers.d.ts +10 -9
  45. package/dist/handlers.js +6 -38
  46. package/dist/handlers.js.map +1 -1
  47. package/dist/index.d.ts +120 -118
  48. package/dist/index.js +1963 -3125
  49. package/dist/index.js.map +1 -1
  50. package/package.json +3 -4
  51. package/dist/cli/bin.d.ts.map +0 -1
  52. package/dist/cli/dashboard/App.d.ts +0 -16
  53. package/dist/cli/dashboard/App.d.ts.map +0 -1
  54. package/dist/cli/dashboard/App.js +0 -116
  55. package/dist/cli/dashboard/App.js.map +0 -1
  56. package/dist/cli/dashboard/components/index.d.ts +0 -70
  57. package/dist/cli/dashboard/components/index.d.ts.map +0 -1
  58. package/dist/cli/dashboard/components/index.js +0 -192
  59. package/dist/cli/dashboard/components/index.js.map +0 -1
  60. package/dist/cli/dashboard/hooks/index.d.ts +0 -76
  61. package/dist/cli/dashboard/hooks/index.d.ts.map +0 -1
  62. package/dist/cli/dashboard/hooks/index.js +0 -201
  63. package/dist/cli/dashboard/hooks/index.js.map +0 -1
  64. package/dist/cli/dashboard/index.d.ts.map +0 -1
  65. package/dist/cli/dashboard/types.d.ts +0 -84
  66. package/dist/cli/dashboard/types.d.ts.map +0 -1
  67. package/dist/cli/dashboard/types.js +0 -5
  68. package/dist/cli/dashboard/types.js.map +0 -1
  69. package/dist/cli/dashboard/views/index.d.ts +0 -51
  70. package/dist/cli/dashboard/views/index.d.ts.map +0 -1
  71. package/dist/cli/dashboard/views/index.js +0 -72
  72. package/dist/cli/dashboard/views/index.js.map +0 -1
  73. package/dist/cli/index.d.ts.map +0 -1
  74. package/dist/cli/runtime/index.d.ts.map +0 -1
  75. package/dist/cli/scanner/index.d.ts.map +0 -1
  76. package/dist/cli/seed/index.d.ts.map +0 -1
  77. package/dist/cli/sync/index.d.ts.map +0 -1
  78. package/dist/cli/terminal.d.ts.map +0 -1
  79. package/dist/cli/workflow/index.d.ts.map +0 -1
  80. package/dist/errors.d.ts +0 -43
  81. package/dist/errors.d.ts.map +0 -1
  82. package/dist/errors.js +0 -47
  83. package/dist/errors.js.map +0 -1
  84. package/dist/handlers.d.ts.map +0 -1
  85. package/dist/index.d.ts.map +0 -1
  86. package/dist/types.d.ts +0 -276
  87. package/dist/types.d.ts.map +0 -1
  88. package/dist/types.js +0 -12
  89. package/dist/types.js.map +0 -1
@@ -1,705 +1,11 @@
1
- /**
2
- * Module 14: Local Runtime
3
- *
4
- * SQLite-based local database runtime for offline-first development.
5
- * Provides the same interface as the Cloudflare Durable Object for
6
- * seamless local development and testing.
7
- */
8
- import Database from 'better-sqlite3';
9
- import * as fs from 'node:fs';
10
- import * as path from 'node:path';
11
- import * as crypto from 'node:crypto';
12
- // ============================================================================
13
- // Utility Functions
14
- // ============================================================================
15
- /**
16
- * Computes a deterministic hash of an object by sorting keys recursively.
17
- */
18
- function computeHash(obj) {
19
- const sortedJson = stableStringify(obj);
20
- return crypto.createHash('sha256').update(sortedJson).digest('hex').slice(0, 16);
21
- }
22
- /**
23
- * Stable JSON stringify that sorts object keys for consistent hashing.
24
- */
25
- function stableStringify(obj) {
26
- if (obj === null || typeof obj !== 'object') {
27
- return JSON.stringify(obj);
28
- }
29
- if (Array.isArray(obj)) {
30
- return '[' + obj.map(stableStringify).join(',') + ']';
31
- }
32
- const keys = Object.keys(obj).sort();
33
- const pairs = keys.map((key) => JSON.stringify(key) + ':' + stableStringify(obj[key]));
34
- return '{' + pairs.join(',') + '}';
35
- }
36
- /**
37
- * Ensures parent directories exist for a given file path.
38
- * Silently handles errors (e.g., permission denied, root paths).
39
- */
40
- function ensureDirectoryExists(filePath) {
41
- const dir = path.dirname(filePath);
42
- try {
43
- if (!fs.existsSync(dir)) {
44
- fs.mkdirSync(dir, { recursive: true });
45
- }
46
- }
47
- catch {
48
- // Silently ignore - the database open will fail with a more specific error
49
- }
50
- }
51
- // ============================================================================
52
- // Database Schema Version
53
- // ============================================================================
54
- const SCHEMA_VERSION = 1;
55
- const SCHEMA_SQL = `
56
- -- Things table (entities)
57
- CREATE TABLE IF NOT EXISTS things (
58
- rowid INTEGER PRIMARY KEY AUTOINCREMENT,
59
- type TEXT NOT NULL,
60
- id TEXT NOT NULL,
61
- data TEXT NOT NULL,
62
- content_hash TEXT NOT NULL,
63
- created_at INTEGER NOT NULL,
64
- created_by_action INTEGER,
65
- FOREIGN KEY (created_by_action) REFERENCES actions(rowid)
66
- );
67
-
68
- CREATE INDEX IF NOT EXISTS idx_things_type_id ON things(type, id);
69
- CREATE INDEX IF NOT EXISTS idx_things_content_hash ON things(content_hash);
70
- CREATE INDEX IF NOT EXISTS idx_things_type ON things(type);
71
-
72
- -- Relationships table (edges)
73
- CREATE TABLE IF NOT EXISTS relationships (
74
- rowid INTEGER PRIMARY KEY AUTOINCREMENT,
75
- from_rowid INTEGER NOT NULL,
76
- to_rowid INTEGER NOT NULL,
77
- type TEXT NOT NULL,
78
- path TEXT NOT NULL,
79
- label TEXT NOT NULL,
80
- created_at INTEGER NOT NULL,
81
- created_by_action INTEGER,
82
- FOREIGN KEY (from_rowid) REFERENCES things(rowid),
83
- FOREIGN KEY (to_rowid) REFERENCES things(rowid),
84
- FOREIGN KEY (created_by_action) REFERENCES actions(rowid),
85
- UNIQUE (from_rowid, to_rowid, path)
86
- );
87
-
88
- CREATE INDEX IF NOT EXISTS idx_relationships_from ON relationships(from_rowid);
89
- CREATE INDEX IF NOT EXISTS idx_relationships_to ON relationships(to_rowid);
90
- CREATE INDEX IF NOT EXISTS idx_relationships_type ON relationships(type);
91
-
92
- -- Actions table (for caching and tracking)
93
- CREATE TABLE IF NOT EXISTS actions (
94
- rowid INTEGER PRIMARY KEY AUTOINCREMENT,
95
- type TEXT NOT NULL,
96
- input_hash TEXT NOT NULL,
97
- input TEXT NOT NULL,
98
- output TEXT,
99
- model TEXT,
100
- status TEXT NOT NULL DEFAULT 'pending',
101
- error TEXT,
102
- duration_ms INTEGER,
103
- cost_tokens INTEGER,
104
- created_at INTEGER NOT NULL
105
- );
106
-
107
- CREATE INDEX IF NOT EXISTS idx_actions_input_hash ON actions(input_hash);
108
- CREATE INDEX IF NOT EXISTS idx_actions_status ON actions(status);
109
-
110
- -- Events table (audit log)
111
- CREATE TABLE IF NOT EXISTS events (
112
- rowid INTEGER PRIMARY KEY AUTOINCREMENT,
113
- type TEXT NOT NULL,
114
- action TEXT NOT NULL,
115
- entity_type TEXT NOT NULL,
116
- entity_id TEXT NOT NULL,
117
- entity_rowid INTEGER NOT NULL,
118
- data TEXT NOT NULL,
119
- changes TEXT,
120
- timestamp INTEGER NOT NULL,
121
- action_id INTEGER,
122
- correlation_id TEXT,
123
- FOREIGN KEY (action_id) REFERENCES actions(rowid)
124
- );
125
-
126
- CREATE INDEX IF NOT EXISTS idx_events_type ON events(type);
127
- CREATE INDEX IF NOT EXISTS idx_events_action ON events(action);
128
- CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
129
- CREATE INDEX IF NOT EXISTS idx_events_correlation_id ON events(correlation_id);
130
-
131
- -- Schema version tracking
132
- CREATE TABLE IF NOT EXISTS schema_version (
133
- version INTEGER NOT NULL
134
- );
135
- `;
136
- // ============================================================================
137
- // LocalDB Class
138
- // ============================================================================
139
- export class LocalDB {
140
- db;
141
- path;
142
- version = SCHEMA_VERSION;
143
- things;
144
- relationships;
145
- actions;
146
- events;
147
- constructor(dbPath) {
148
- // Use default path if not provided
149
- this.path = dbPath || path.join(process.cwd(), '.db4', 'local.db');
150
- // Ensure parent directory exists
151
- ensureDirectoryExists(this.path);
152
- // Open database, falling back to in-memory if file path fails
153
- try {
154
- this.db = new Database(this.path);
155
- }
156
- catch {
157
- // If we can't open the file database, use in-memory as fallback
158
- // This allows graceful degradation when the path is invalid
159
- this.db = new Database(':memory:');
160
- }
161
- // Enable WAL mode for better concurrent performance (only for file-based DBs)
162
- try {
163
- this.db.pragma('journal_mode = WAL');
164
- }
165
- catch {
166
- // WAL mode may not be available for in-memory databases
167
- }
168
- // Initialize schema
169
- this.initSchema();
170
- // Initialize APIs
171
- this.things = new ThingsAPI(this.db);
172
- this.relationships = new RelationshipsAPI(this.db);
173
- this.actions = new ActionsAPI(this.db);
174
- this.events = new EventsAPI(this.db);
175
- }
176
- initSchema() {
177
- // Check if schema exists
178
- const tableCheck = this.db
179
- .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='schema_version'`)
180
- .get();
181
- if (!tableCheck) {
182
- // Initialize fresh database
183
- this.db.exec(SCHEMA_SQL);
184
- this.db.prepare('INSERT INTO schema_version (version) VALUES (?)').run(SCHEMA_VERSION);
185
- }
186
- }
187
- /**
188
- * Closes the database connection.
189
- */
190
- close() {
191
- this.db.close();
192
- }
193
- /**
194
- * Runs VACUUM to reclaim disk space.
195
- */
196
- vacuum() {
197
- this.db.exec('VACUUM');
198
- return Promise.resolve();
199
- }
200
- }
201
- // ============================================================================
202
- // Things API
203
- // ============================================================================
204
- class ThingsAPI {
205
- db;
206
- constructor(db) {
207
- this.db = db;
208
- }
209
- /**
210
- * Upsert a thing. Returns existing rowid if content_hash matches,
211
- * otherwise creates a new version.
212
- */
213
- async upsert(params) {
214
- const { type, id, data, created_by_action } = params;
215
- const dataJson = JSON.stringify(data);
216
- const content_hash = computeHash({ type, id, data });
217
- const created_at = Date.now();
218
- // Check if identical content already exists
219
- const existing = this.db
220
- .prepare('SELECT rowid FROM things WHERE type = ? AND id = ? AND content_hash = ?')
221
- .get(type, id, content_hash);
222
- if (existing) {
223
- return { rowid: existing.rowid, created: false };
224
- }
225
- // Insert new version
226
- const result = this.db
227
- .prepare(`INSERT INTO things (type, id, data, content_hash, created_at, created_by_action)
228
- VALUES (?, ?, ?, ?, ?, ?)`)
229
- .run(type, id, dataJson, content_hash, created_at, created_by_action || null);
230
- return { rowid: result.lastInsertRowid, created: true };
231
- }
232
- /**
233
- * Get the latest version of a thing by type and id.
234
- */
235
- async get(params) {
236
- const { type, id } = params;
237
- const row = this.db
238
- .prepare(`SELECT rowid, type, id, data, content_hash, created_at, created_by_action
239
- FROM things
240
- WHERE type = ? AND id = ?
241
- ORDER BY rowid DESC
242
- LIMIT 1`)
243
- .get(type, id);
244
- if (!row)
245
- return null;
246
- return {
247
- rowid: row.rowid,
248
- type: row.type,
249
- id: row.id,
250
- data: JSON.parse(row.data),
251
- content_hash: row.content_hash,
252
- created_at: row.created_at,
253
- created_by_action: row.created_by_action ?? undefined,
254
- };
255
- }
256
- /**
257
- * Get a specific version by rowid.
258
- */
259
- async getByRowid(rowid) {
260
- const row = this.db
261
- .prepare(`SELECT rowid, type, id, data, content_hash, created_at, created_by_action
262
- FROM things
263
- WHERE rowid = ?`)
264
- .get(rowid);
265
- if (!row)
266
- return null;
267
- return {
268
- rowid: row.rowid,
269
- type: row.type,
270
- id: row.id,
271
- data: JSON.parse(row.data),
272
- content_hash: row.content_hash,
273
- created_at: row.created_at,
274
- created_by_action: row.created_by_action ?? undefined,
275
- };
276
- }
277
- /**
278
- * List things with optional filters.
279
- */
280
- async list(params = {}) {
281
- const { type, limit, offset, where, order = 'asc' } = params;
282
- let sql = `
283
- SELECT t.rowid, t.type, t.id, t.data, t.content_hash, t.created_at, t.created_by_action
284
- FROM things t
285
- INNER JOIN (
286
- SELECT type, id, MAX(rowid) as max_rowid
287
- FROM things
288
- ${type ? 'WHERE type = ?' : ''}
289
- GROUP BY type, id
290
- ) latest ON t.rowid = latest.max_rowid
291
- `;
292
- const queryParams = [];
293
- if (type) {
294
- queryParams.push(type);
295
- }
296
- // Handle where clause
297
- if (where && Object.keys(where).length > 0) {
298
- const whereConditions = Object.keys(where).map((key) => {
299
- const value = where[key];
300
- // json_extract returns the raw value, so for strings we compare directly
301
- queryParams.push(value);
302
- return `json_extract(t.data, '$.${key}') = ?`;
303
- });
304
- sql += ` WHERE ${whereConditions.join(' AND ')}`;
305
- }
306
- sql += ` ORDER BY t.rowid ${order === 'desc' ? 'DESC' : 'ASC'}`;
307
- if (limit !== undefined) {
308
- sql += ` LIMIT ?`;
309
- queryParams.push(limit);
310
- }
311
- if (offset !== undefined) {
312
- sql += ` OFFSET ?`;
313
- queryParams.push(offset);
314
- }
315
- const rows = this.db.prepare(sql).all(...queryParams);
316
- return rows.map((row) => ({
317
- rowid: row.rowid,
318
- type: row.type,
319
- id: row.id,
320
- data: JSON.parse(row.data),
321
- content_hash: row.content_hash,
322
- created_at: row.created_at,
323
- created_by_action: row.created_by_action ?? undefined,
324
- }));
325
- }
326
- /**
327
- * Delete a thing by rowid.
328
- */
329
- async delete(rowid) {
330
- this.db.prepare('DELETE FROM things WHERE rowid = ?').run(rowid);
331
- }
332
- }
333
- // ============================================================================
334
- // Relationships API
335
- // ============================================================================
336
- class RelationshipsAPI {
337
- db;
338
- constructor(db) {
339
- this.db = db;
340
- }
341
- /**
342
- * Create or update a relationship edge.
343
- * If (from_rowid, to_rowid, path) already exists, updates it.
344
- */
345
- async create(params) {
346
- const { from_rowid, to_rowid, type, path, label, created_by_action } = params;
347
- const created_at = Date.now();
348
- // Check if edge exists with same from/to/path
349
- const existing = this.db
350
- .prepare(`SELECT rowid FROM relationships
351
- WHERE from_rowid = ? AND to_rowid = ? AND path = ?`)
352
- .get(from_rowid, to_rowid, path);
353
- if (existing) {
354
- // Update existing edge
355
- this.db
356
- .prepare(`UPDATE relationships
357
- SET type = ?, label = ?, created_by_action = ?
358
- WHERE rowid = ?`)
359
- .run(type, label, created_by_action || null, existing.rowid);
360
- const row = this.db
361
- .prepare(`SELECT rowid, from_rowid, to_rowid, type, path, label, created_at, created_by_action
362
- FROM relationships WHERE rowid = ?`)
363
- .get(existing.rowid);
364
- return {
365
- rowid: row.rowid,
366
- from_rowid: row.from_rowid,
367
- to_rowid: row.to_rowid,
368
- type: row.type,
369
- path: row.path,
370
- label: row.label,
371
- created_at: row.created_at,
372
- created_by_action: row.created_by_action ?? undefined,
373
- };
374
- }
375
- // Insert new edge
376
- const result = this.db
377
- .prepare(`INSERT INTO relationships (from_rowid, to_rowid, type, path, label, created_at, created_by_action)
378
- VALUES (?, ?, ?, ?, ?, ?, ?)`)
379
- .run(from_rowid, to_rowid, type, path, label, created_at, created_by_action || null);
380
- return {
381
- rowid: result.lastInsertRowid,
382
- from_rowid,
383
- to_rowid,
384
- type,
385
- path,
386
- label,
387
- created_at,
388
- created_by_action,
389
- };
390
- }
391
- /**
392
- * List all relationships.
393
- */
394
- async list() {
395
- const rows = this.db
396
- .prepare(`SELECT rowid, from_rowid, to_rowid, type, path, label, created_at, created_by_action
397
- FROM relationships`)
398
- .all();
399
- return rows.map((row) => ({
400
- rowid: row.rowid,
401
- from_rowid: row.from_rowid,
402
- to_rowid: row.to_rowid,
403
- type: row.type,
404
- path: row.path,
405
- label: row.label,
406
- created_at: row.created_at,
407
- created_by_action: row.created_by_action ?? undefined,
408
- }));
409
- }
410
- /**
411
- * Traverse forward from an entity.
412
- */
413
- async traverse(params) {
414
- const { from_rowid, type } = params;
415
- let sql = `
416
- SELECT rowid, from_rowid, to_rowid, type, path, label, created_at, created_by_action
417
- FROM relationships
418
- WHERE from_rowid = ?
419
- `;
420
- const queryParams = [from_rowid];
421
- if (type) {
422
- sql += ' AND type = ?';
423
- queryParams.push(type);
424
- }
425
- const rows = this.db.prepare(sql).all(...queryParams);
426
- return rows.map((row) => ({
427
- rowid: row.rowid,
428
- from_rowid: row.from_rowid,
429
- to_rowid: row.to_rowid,
430
- type: row.type,
431
- path: row.path,
432
- label: row.label,
433
- created_at: row.created_at,
434
- created_by_action: row.created_by_action ?? undefined,
435
- }));
436
- }
437
- /**
438
- * Find incoming edges to an entity.
439
- */
440
- async incoming(params) {
441
- const { to_rowid, type } = params;
442
- let sql = `
443
- SELECT rowid, from_rowid, to_rowid, type, path, label, created_at, created_by_action
444
- FROM relationships
445
- WHERE to_rowid = ?
446
- `;
447
- const queryParams = [to_rowid];
448
- if (type) {
449
- sql += ' AND type = ?';
450
- queryParams.push(type);
451
- }
452
- const rows = this.db.prepare(sql).all(...queryParams);
453
- return rows.map((row) => ({
454
- rowid: row.rowid,
455
- from_rowid: row.from_rowid,
456
- to_rowid: row.to_rowid,
457
- type: row.type,
458
- path: row.path,
459
- label: row.label,
460
- created_at: row.created_at,
461
- created_by_action: row.created_by_action ?? undefined,
462
- }));
463
- }
464
- /**
465
- * Traverse multiple hops from an entity (BFS).
466
- */
467
- async traverseMultiHop(params) {
468
- const { from_rowid, depth, type } = params;
469
- const visited = new Set([from_rowid]);
470
- const results = [];
471
- let currentLevel = [from_rowid];
472
- for (let d = 1; d <= depth && currentLevel.length > 0; d++) {
473
- const nextLevel = [];
474
- for (const nodeId of currentLevel) {
475
- const edges = await this.traverse({ from_rowid: nodeId, type });
476
- for (const edge of edges) {
477
- if (!visited.has(edge.to_rowid)) {
478
- visited.add(edge.to_rowid);
479
- results.push({ to_rowid: edge.to_rowid, depth: d });
480
- nextLevel.push(edge.to_rowid);
481
- }
482
- }
483
- }
484
- currentLevel = nextLevel;
485
- }
486
- return results;
487
- }
488
- }
489
- // ============================================================================
490
- // Actions API
491
- // ============================================================================
492
- class ActionsAPI {
493
- db;
494
- constructor(db) {
495
- this.db = db;
496
- }
497
- /**
498
- * Create a new action in pending status.
499
- */
500
- async create(params) {
501
- const { type, input, model } = params;
502
- const inputJson = JSON.stringify(input);
503
- const input_hash = computeHash(input);
504
- const created_at = Date.now();
505
- const result = this.db
506
- .prepare(`INSERT INTO actions (type, input_hash, input, model, status, created_at)
507
- VALUES (?, ?, ?, ?, 'pending', ?)`)
508
- .run(type, input_hash, inputJson, model || null, created_at);
509
- return {
510
- rowid: result.lastInsertRowid,
511
- type,
512
- input_hash,
513
- input,
514
- model,
515
- status: 'pending',
516
- created_at,
517
- };
518
- }
519
- /**
520
- * Find a completed action by input hash (cache lookup).
521
- * Only returns actions with status='complete'.
522
- */
523
- async findByHash(input_hash) {
524
- const row = this.db
525
- .prepare(`SELECT rowid, type, input_hash, input, output, model, status, error, duration_ms, cost_tokens, created_at
526
- FROM actions
527
- WHERE input_hash = ? AND status = 'complete'
528
- ORDER BY rowid DESC
529
- LIMIT 1`)
530
- .get(input_hash);
531
- if (!row)
532
- return null;
533
- return {
534
- rowid: row.rowid,
535
- type: row.type,
536
- input_hash: row.input_hash,
537
- input: JSON.parse(row.input),
538
- output: row.output ? JSON.parse(row.output) : undefined,
539
- model: row.model ?? undefined,
540
- status: row.status,
541
- error: row.error ?? undefined,
542
- duration_ms: row.duration_ms ?? undefined,
543
- cost_tokens: row.cost_tokens ?? undefined,
544
- created_at: row.created_at,
545
- };
546
- }
547
- /**
548
- * Complete an action with output.
549
- */
550
- async complete(params) {
551
- const { rowid, output, duration_ms, cost_tokens } = params;
552
- const outputJson = JSON.stringify(output);
553
- // Check if action exists and is pending
554
- const existing = this.db
555
- .prepare('SELECT status FROM actions WHERE rowid = ?')
556
- .get(rowid);
557
- if (!existing) {
558
- throw new Error(`Action with rowid ${rowid} not found`);
559
- }
560
- if (existing.status !== 'pending') {
561
- throw new Error(`Cannot complete action with status '${existing.status}'`);
562
- }
563
- this.db
564
- .prepare(`UPDATE actions
565
- SET status = 'complete', output = ?, duration_ms = ?, cost_tokens = ?
566
- WHERE rowid = ?`)
567
- .run(outputJson, duration_ms || null, cost_tokens || null, rowid);
568
- const row = this.db
569
- .prepare(`SELECT rowid, type, input_hash, input, output, model, status, error, duration_ms, cost_tokens, created_at
570
- FROM actions WHERE rowid = ?`)
571
- .get(rowid);
572
- return {
573
- rowid: row.rowid,
574
- type: row.type,
575
- input_hash: row.input_hash,
576
- input: JSON.parse(row.input),
577
- output: row.output ? JSON.parse(row.output) : undefined,
578
- model: row.model ?? undefined,
579
- status: row.status,
580
- error: row.error ?? undefined,
581
- duration_ms: row.duration_ms ?? undefined,
582
- cost_tokens: row.cost_tokens ?? undefined,
583
- created_at: row.created_at,
584
- };
585
- }
586
- /**
587
- * Mark an action as failed.
588
- */
589
- async fail(params) {
590
- const { rowid, error } = params;
591
- // Check if action exists and is pending
592
- const existing = this.db
593
- .prepare('SELECT status FROM actions WHERE rowid = ?')
594
- .get(rowid);
595
- if (!existing) {
596
- throw new Error(`Action with rowid ${rowid} not found`);
597
- }
598
- if (existing.status !== 'pending') {
599
- throw new Error(`Cannot fail action with status '${existing.status}'`);
600
- }
601
- this.db.prepare(`UPDATE actions SET status = 'error', error = ? WHERE rowid = ?`).run(error, rowid);
602
- const row = this.db
603
- .prepare(`SELECT rowid, type, input_hash, input, output, model, status, error, duration_ms, cost_tokens, created_at
604
- FROM actions WHERE rowid = ?`)
605
- .get(rowid);
606
- return {
607
- rowid: row.rowid,
608
- type: row.type,
609
- input_hash: row.input_hash,
610
- input: JSON.parse(row.input),
611
- output: row.output ? JSON.parse(row.output) : undefined,
612
- model: row.model ?? undefined,
613
- status: row.status,
614
- error: row.error ?? undefined,
615
- duration_ms: row.duration_ms ?? undefined,
616
- cost_tokens: row.cost_tokens ?? undefined,
617
- created_at: row.created_at,
618
- };
619
- }
620
- }
621
- // ============================================================================
622
- // Events API
623
- // ============================================================================
624
- class EventsAPI {
625
- db;
626
- constructor(db) {
627
- this.db = db;
628
- }
629
- /**
630
- * Emit an event.
631
- */
632
- async emit(params) {
633
- const { type, action, entity_type, entity_id, entity_rowid, data, changes, action_id, correlation_id, } = params;
634
- const timestamp = Date.now();
635
- const dataJson = JSON.stringify(data);
636
- const changesJson = changes ? JSON.stringify(changes) : null;
637
- const result = this.db
638
- .prepare(`INSERT INTO events (type, action, entity_type, entity_id, entity_rowid, data, changes, timestamp, action_id, correlation_id)
639
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
640
- .run(type, action, entity_type, entity_id, entity_rowid, dataJson, changesJson, timestamp, action_id || null, correlation_id || null);
641
- return {
642
- rowid: result.lastInsertRowid,
643
- type,
644
- action,
645
- entity_type,
646
- entity_id,
647
- entity_rowid,
648
- data,
649
- changes,
650
- timestamp,
651
- action_id,
652
- correlation_id,
653
- };
654
- }
655
- /**
656
- * List events with optional filters.
657
- */
658
- async list(params = {}) {
659
- const { type, action, since, correlation_id, limit } = params;
660
- let sql = `
661
- SELECT rowid, type, action, entity_type, entity_id, entity_rowid, data, changes, timestamp, action_id, correlation_id
662
- FROM events
663
- WHERE 1=1
664
- `;
665
- const queryParams = [];
666
- if (type) {
667
- sql += ' AND type = ?';
668
- queryParams.push(type);
669
- }
670
- if (action) {
671
- sql += ' AND action = ?';
672
- queryParams.push(action);
673
- }
674
- if (since !== undefined) {
675
- sql += ' AND timestamp > ?';
676
- queryParams.push(since);
677
- }
678
- if (correlation_id) {
679
- sql += ' AND correlation_id = ?';
680
- queryParams.push(correlation_id);
681
- }
682
- sql += ' ORDER BY timestamp ASC';
683
- if (limit !== undefined) {
684
- sql += ' LIMIT ?';
685
- queryParams.push(limit);
686
- }
687
- const rows = this.db.prepare(sql).all(...queryParams);
688
- return rows.map((row) => ({
689
- rowid: row.rowid,
690
- type: row.type,
691
- action: row.action,
692
- entity_type: row.entity_type,
693
- entity_id: row.entity_id,
694
- entity_rowid: row.entity_rowid,
695
- data: JSON.parse(row.data),
696
- changes: row.changes ? JSON.parse(row.changes) : undefined,
697
- timestamp: row.timestamp,
698
- action_id: row.action_id ?? undefined,
699
- correlation_id: row.correlation_id ?? undefined,
700
- }));
701
- }
702
- }
703
- // Default export for convenience
704
- export default LocalDB;
1
+ import {
2
+ ConnectionPool,
3
+ LocalDB,
4
+ runtime_default
5
+ } from "../../chunk-FUF4HJTC.js";
6
+ export {
7
+ ConnectionPool,
8
+ LocalDB,
9
+ runtime_default as default
10
+ };
705
11
  //# sourceMappingURL=index.js.map