latticesql 0.9.0 → 0.10.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.
package/dist/cli.js CHANGED
@@ -1389,6 +1389,7 @@ var Lattice = class {
1389
1389
  _renderHandlers = [];
1390
1390
  _writebackHandlers = [];
1391
1391
  _errorHandlers = [];
1392
+ _writeHooks = [];
1392
1393
  constructor(pathOrConfig, options = {}) {
1393
1394
  let dbPath;
1394
1395
  let configTables;
@@ -1448,6 +1449,14 @@ var Lattice = class {
1448
1449
  this._schema.defineEntityContext(table, def);
1449
1450
  return this;
1450
1451
  }
1452
+ /**
1453
+ * Register a write hook that fires after insert/update/delete operations.
1454
+ * Hooks run synchronously after the DB write and audit emit.
1455
+ */
1456
+ defineWriteHook(hook) {
1457
+ this._writeHooks.push(hook);
1458
+ return this;
1459
+ }
1451
1460
  defineWriteback(def) {
1452
1461
  this._writeback.define(def);
1453
1462
  return this;
@@ -1497,6 +1506,7 @@ var Lattice = class {
1497
1506
  const rawPk = rowWithPk[pkCol];
1498
1507
  const pkValue = rawPk != null ? String(rawPk) : "";
1499
1508
  this._sanitizer.emitAudit(table, "insert", pkValue);
1509
+ this._fireWriteHooks(table, "insert", rowWithPk, pkValue);
1500
1510
  return Promise.resolve(pkValue);
1501
1511
  }
1502
1512
  upsert(table, row) {
@@ -1550,6 +1560,7 @@ var Lattice = class {
1550
1560
  this._adapter.run(`UPDATE "${table}" SET ${setCols} WHERE ${clause}`, values);
1551
1561
  const auditId = typeof id === "string" ? id : JSON.stringify(id);
1552
1562
  this._sanitizer.emitAudit(table, "update", auditId);
1563
+ this._fireWriteHooks(table, "update", sanitized, auditId, Object.keys(sanitized));
1553
1564
  return Promise.resolve();
1554
1565
  }
1555
1566
  delete(table, id) {
@@ -1559,6 +1570,7 @@ var Lattice = class {
1559
1570
  this._adapter.run(`DELETE FROM "${table}" WHERE ${clause}`, params);
1560
1571
  const auditId = typeof id === "string" ? id : JSON.stringify(id);
1561
1572
  this._sanitizer.emitAudit(table, "delete", auditId);
1573
+ this._fireWriteHooks(table, "delete", { id: auditId }, auditId);
1562
1574
  return Promise.resolve();
1563
1575
  }
1564
1576
  get(table, id) {
@@ -1796,6 +1808,22 @@ var Lattice = class {
1796
1808
  return { clauses, params };
1797
1809
  }
1798
1810
  /** Returns a rejected Promise if not initialized; null if ready. */
1811
+ _fireWriteHooks(table, op, row, pk, changedColumns) {
1812
+ for (const hook of this._writeHooks) {
1813
+ if (hook.table !== table) continue;
1814
+ if (!hook.on.includes(op)) continue;
1815
+ if (op === "update" && hook.watchColumns && changedColumns) {
1816
+ if (!hook.watchColumns.some((c) => changedColumns.includes(c))) continue;
1817
+ }
1818
+ try {
1819
+ const ctx = { table, op, row, pk };
1820
+ if (changedColumns) ctx.changedColumns = changedColumns;
1821
+ hook.handler(ctx);
1822
+ } catch (err) {
1823
+ for (const h of this._errorHandlers) h(err instanceof Error ? err : new Error(String(err)));
1824
+ }
1825
+ }
1826
+ }
1799
1827
  _notInitError() {
1800
1828
  if (!this._initialized) {
1801
1829
  return Promise.reject(
package/dist/index.cjs CHANGED
@@ -1363,6 +1363,7 @@ var Lattice = class {
1363
1363
  _renderHandlers = [];
1364
1364
  _writebackHandlers = [];
1365
1365
  _errorHandlers = [];
1366
+ _writeHooks = [];
1366
1367
  constructor(pathOrConfig, options = {}) {
1367
1368
  let dbPath;
1368
1369
  let configTables;
@@ -1422,6 +1423,14 @@ var Lattice = class {
1422
1423
  this._schema.defineEntityContext(table, def);
1423
1424
  return this;
1424
1425
  }
1426
+ /**
1427
+ * Register a write hook that fires after insert/update/delete operations.
1428
+ * Hooks run synchronously after the DB write and audit emit.
1429
+ */
1430
+ defineWriteHook(hook) {
1431
+ this._writeHooks.push(hook);
1432
+ return this;
1433
+ }
1425
1434
  defineWriteback(def) {
1426
1435
  this._writeback.define(def);
1427
1436
  return this;
@@ -1471,6 +1480,7 @@ var Lattice = class {
1471
1480
  const rawPk = rowWithPk[pkCol];
1472
1481
  const pkValue = rawPk != null ? String(rawPk) : "";
1473
1482
  this._sanitizer.emitAudit(table, "insert", pkValue);
1483
+ this._fireWriteHooks(table, "insert", rowWithPk, pkValue);
1474
1484
  return Promise.resolve(pkValue);
1475
1485
  }
1476
1486
  upsert(table, row) {
@@ -1524,6 +1534,7 @@ var Lattice = class {
1524
1534
  this._adapter.run(`UPDATE "${table}" SET ${setCols} WHERE ${clause}`, values);
1525
1535
  const auditId = typeof id === "string" ? id : JSON.stringify(id);
1526
1536
  this._sanitizer.emitAudit(table, "update", auditId);
1537
+ this._fireWriteHooks(table, "update", sanitized, auditId, Object.keys(sanitized));
1527
1538
  return Promise.resolve();
1528
1539
  }
1529
1540
  delete(table, id) {
@@ -1533,6 +1544,7 @@ var Lattice = class {
1533
1544
  this._adapter.run(`DELETE FROM "${table}" WHERE ${clause}`, params);
1534
1545
  const auditId = typeof id === "string" ? id : JSON.stringify(id);
1535
1546
  this._sanitizer.emitAudit(table, "delete", auditId);
1547
+ this._fireWriteHooks(table, "delete", { id: auditId }, auditId);
1536
1548
  return Promise.resolve();
1537
1549
  }
1538
1550
  get(table, id) {
@@ -1770,6 +1782,22 @@ var Lattice = class {
1770
1782
  return { clauses, params };
1771
1783
  }
1772
1784
  /** Returns a rejected Promise if not initialized; null if ready. */
1785
+ _fireWriteHooks(table, op, row, pk, changedColumns) {
1786
+ for (const hook of this._writeHooks) {
1787
+ if (hook.table !== table) continue;
1788
+ if (!hook.on.includes(op)) continue;
1789
+ if (op === "update" && hook.watchColumns && changedColumns) {
1790
+ if (!hook.watchColumns.some((c) => changedColumns.includes(c))) continue;
1791
+ }
1792
+ try {
1793
+ const ctx = { table, op, row, pk };
1794
+ if (changedColumns) ctx.changedColumns = changedColumns;
1795
+ hook.handler(ctx);
1796
+ } catch (err) {
1797
+ for (const h of this._errorHandlers) h(err instanceof Error ? err : new Error(String(err)));
1798
+ }
1799
+ }
1800
+ }
1773
1801
  _notInitError() {
1774
1802
  if (!this._initialized) {
1775
1803
  return Promise.reject(
package/dist/index.d.cts CHANGED
@@ -749,6 +749,45 @@ interface AuditEvent {
749
749
  id: string;
750
750
  timestamp: string;
751
751
  }
752
+ /**
753
+ * Context passed to write hook handlers.
754
+ */
755
+ interface WriteHookContext {
756
+ /** Table that was modified. */
757
+ table: string;
758
+ /** The operation that triggered the hook. */
759
+ op: 'insert' | 'update' | 'delete';
760
+ /** The row data (for insert: full row; for update: changed fields; for delete: { id }). */
761
+ row: Row;
762
+ /** Primary key value(s) of the affected row. */
763
+ pk: string;
764
+ /** For updates: the column names that were changed. */
765
+ changedColumns?: string[];
766
+ }
767
+ /**
768
+ * A write hook fires after insert/update/delete operations.
769
+ *
770
+ * @example
771
+ * ```ts
772
+ * db.defineWriteHook({
773
+ * table: 'agents',
774
+ * on: ['insert', 'update'],
775
+ * watchColumns: ['team_id'],
776
+ * handler: (ctx) => { denormalizeTeamFields(ctx.pk); },
777
+ * });
778
+ * ```
779
+ */
780
+ interface WriteHook {
781
+ /** Table the hook fires on. */
782
+ table: string;
783
+ /** Operations that trigger the hook. */
784
+ on: Array<'insert' | 'update' | 'delete'>;
785
+ /** Only fire on update when these columns changed. Omit = fire on any change. */
786
+ watchColumns?: string[];
787
+ /** Handler function. Runs synchronously after the DB write. */
788
+ handler: (ctx: WriteHookContext) => void;
789
+ }
790
+
752
791
  interface ReconcileOptions {
753
792
  /** Remove entity directories whose slug is no longer in the DB. Default: true. */
754
793
  removeOrphanedDirectories?: boolean;
@@ -801,10 +840,16 @@ declare class Lattice {
801
840
  private readonly _renderHandlers;
802
841
  private readonly _writebackHandlers;
803
842
  private readonly _errorHandlers;
843
+ private readonly _writeHooks;
804
844
  constructor(pathOrConfig: string | LatticeConfigInput, options?: LatticeOptions);
805
845
  define(table: string, def: TableDefinition): this;
806
846
  defineMulti(name: string, def: MultiTableDefinition): this;
807
847
  defineEntityContext(table: string, def: EntityContextDefinition): this;
848
+ /**
849
+ * Register a write hook that fires after insert/update/delete operations.
850
+ * Hooks run synchronously after the DB write and audit emit.
851
+ */
852
+ defineWriteHook(hook: WriteHook): this;
808
853
  defineWriteback(def: WritebackDefinition): this;
809
854
  init(options?: InitOptions): Promise<void>;
810
855
  close(): void;
@@ -850,6 +895,7 @@ declare class Lattice {
850
895
  */
851
896
  private _buildFilters;
852
897
  /** Returns a rejected Promise if not initialized; null if ready. */
898
+ private _fireWriteHooks;
853
899
  private _notInitError;
854
900
  /**
855
901
  * Returns a rejected Promise if any of the given column names are not present
@@ -1305,4 +1351,4 @@ declare function createReadOnlyHeader(options?: ReadOnlyHeaderOptions): string;
1305
1351
  */
1306
1352
  declare const READ_ONLY_HEADER: string;
1307
1353
 
1308
- export { type ApplyWriteResult, type AuditEvent, type BelongsToRelation, type BelongsToSource, type BuiltinTemplateName, type CleanupOptions, type CleanupResult, type CountOptions, type CustomSource, DEFAULT_ENTRY_TYPES, DEFAULT_TYPE_ALIASES, type EnrichedSource, type EnrichmentLookup, type EntityContextDefinition, type EntityContextManifestEntry, type EntityFileSource, type EntityFileSpec, type EntityProfileField, type EntityProfileSection, type EntityProfileTemplate, type EntityRenderSpec, type EntityRenderTemplate, type EntitySectionPerRow, type EntitySectionsTemplate, type EntityTableColumn, type EntityTableTemplate, type Filter, type FilterOp, type HasManyRelation, type HasManySource, type InitOptions, Lattice, type LatticeConfig, type LatticeConfigInput, type LatticeEntityDef, type LatticeEntityRenderSpec, type LatticeFieldDef, type LatticeFieldType, type LatticeManifest, type LatticeOptions, type ManyToManySource, type MarkdownTableColumn, type Migration, type MultiTableDefinition, type OrderBySpec, type ParseError, type ParseResult, type ParsedConfig, type PkLookup, type PrimaryKey, type QueryOptions, READ_ONLY_HEADER, type ReadOnlyHeaderOptions, type ReconcileOptions, type ReconcileResult, type Relation, type RenderHooks, type RenderResult, type RenderSpec, type Row, type SecurityOptions, type SelfSource, type SessionEntry, type SessionParseOptions, type SessionWriteEntry, type SessionWriteOp, type SessionWriteParseResult, type SourceQueryOptions, type StopFn, type SyncResult, type TableDefinition, type TemplateRenderSpec, type WatchOptions, type WritebackDefinition, applyWriteEntry, createReadOnlyHeader, frontmatter, generateEntryId, generateWriteEntryId, manifestPath, markdownTable, parseConfigFile, parseConfigString, parseMarkdownEntries, parseSessionMD, parseSessionWrites, readManifest, slugify, truncate, validateEntryId, writeManifest };
1354
+ export { type ApplyWriteResult, type AuditEvent, type BelongsToRelation, type BelongsToSource, type BuiltinTemplateName, type CleanupOptions, type CleanupResult, type CountOptions, type CustomSource, DEFAULT_ENTRY_TYPES, DEFAULT_TYPE_ALIASES, type EnrichedSource, type EnrichmentLookup, type EntityContextDefinition, type EntityContextManifestEntry, type EntityFileSource, type EntityFileSpec, type EntityProfileField, type EntityProfileSection, type EntityProfileTemplate, type EntityRenderSpec, type EntityRenderTemplate, type EntitySectionPerRow, type EntitySectionsTemplate, type EntityTableColumn, type EntityTableTemplate, type Filter, type FilterOp, type HasManyRelation, type HasManySource, type InitOptions, Lattice, type LatticeConfig, type LatticeConfigInput, type LatticeEntityDef, type LatticeEntityRenderSpec, type LatticeFieldDef, type LatticeFieldType, type LatticeManifest, type LatticeOptions, type ManyToManySource, type MarkdownTableColumn, type Migration, type MultiTableDefinition, type OrderBySpec, type ParseError, type ParseResult, type ParsedConfig, type PkLookup, type PrimaryKey, type QueryOptions, READ_ONLY_HEADER, type ReadOnlyHeaderOptions, type ReconcileOptions, type ReconcileResult, type Relation, type RenderHooks, type RenderResult, type RenderSpec, type Row, type SecurityOptions, type SelfSource, type SessionEntry, type SessionParseOptions, type SessionWriteEntry, type SessionWriteOp, type SessionWriteParseResult, type SourceQueryOptions, type StopFn, type SyncResult, type TableDefinition, type TemplateRenderSpec, type WatchOptions, type WriteHook, type WriteHookContext, type WritebackDefinition, applyWriteEntry, createReadOnlyHeader, frontmatter, generateEntryId, generateWriteEntryId, manifestPath, markdownTable, parseConfigFile, parseConfigString, parseMarkdownEntries, parseSessionMD, parseSessionWrites, readManifest, slugify, truncate, validateEntryId, writeManifest };
package/dist/index.d.ts CHANGED
@@ -749,6 +749,45 @@ interface AuditEvent {
749
749
  id: string;
750
750
  timestamp: string;
751
751
  }
752
+ /**
753
+ * Context passed to write hook handlers.
754
+ */
755
+ interface WriteHookContext {
756
+ /** Table that was modified. */
757
+ table: string;
758
+ /** The operation that triggered the hook. */
759
+ op: 'insert' | 'update' | 'delete';
760
+ /** The row data (for insert: full row; for update: changed fields; for delete: { id }). */
761
+ row: Row;
762
+ /** Primary key value(s) of the affected row. */
763
+ pk: string;
764
+ /** For updates: the column names that were changed. */
765
+ changedColumns?: string[];
766
+ }
767
+ /**
768
+ * A write hook fires after insert/update/delete operations.
769
+ *
770
+ * @example
771
+ * ```ts
772
+ * db.defineWriteHook({
773
+ * table: 'agents',
774
+ * on: ['insert', 'update'],
775
+ * watchColumns: ['team_id'],
776
+ * handler: (ctx) => { denormalizeTeamFields(ctx.pk); },
777
+ * });
778
+ * ```
779
+ */
780
+ interface WriteHook {
781
+ /** Table the hook fires on. */
782
+ table: string;
783
+ /** Operations that trigger the hook. */
784
+ on: Array<'insert' | 'update' | 'delete'>;
785
+ /** Only fire on update when these columns changed. Omit = fire on any change. */
786
+ watchColumns?: string[];
787
+ /** Handler function. Runs synchronously after the DB write. */
788
+ handler: (ctx: WriteHookContext) => void;
789
+ }
790
+
752
791
  interface ReconcileOptions {
753
792
  /** Remove entity directories whose slug is no longer in the DB. Default: true. */
754
793
  removeOrphanedDirectories?: boolean;
@@ -801,10 +840,16 @@ declare class Lattice {
801
840
  private readonly _renderHandlers;
802
841
  private readonly _writebackHandlers;
803
842
  private readonly _errorHandlers;
843
+ private readonly _writeHooks;
804
844
  constructor(pathOrConfig: string | LatticeConfigInput, options?: LatticeOptions);
805
845
  define(table: string, def: TableDefinition): this;
806
846
  defineMulti(name: string, def: MultiTableDefinition): this;
807
847
  defineEntityContext(table: string, def: EntityContextDefinition): this;
848
+ /**
849
+ * Register a write hook that fires after insert/update/delete operations.
850
+ * Hooks run synchronously after the DB write and audit emit.
851
+ */
852
+ defineWriteHook(hook: WriteHook): this;
808
853
  defineWriteback(def: WritebackDefinition): this;
809
854
  init(options?: InitOptions): Promise<void>;
810
855
  close(): void;
@@ -850,6 +895,7 @@ declare class Lattice {
850
895
  */
851
896
  private _buildFilters;
852
897
  /** Returns a rejected Promise if not initialized; null if ready. */
898
+ private _fireWriteHooks;
853
899
  private _notInitError;
854
900
  /**
855
901
  * Returns a rejected Promise if any of the given column names are not present
@@ -1305,4 +1351,4 @@ declare function createReadOnlyHeader(options?: ReadOnlyHeaderOptions): string;
1305
1351
  */
1306
1352
  declare const READ_ONLY_HEADER: string;
1307
1353
 
1308
- export { type ApplyWriteResult, type AuditEvent, type BelongsToRelation, type BelongsToSource, type BuiltinTemplateName, type CleanupOptions, type CleanupResult, type CountOptions, type CustomSource, DEFAULT_ENTRY_TYPES, DEFAULT_TYPE_ALIASES, type EnrichedSource, type EnrichmentLookup, type EntityContextDefinition, type EntityContextManifestEntry, type EntityFileSource, type EntityFileSpec, type EntityProfileField, type EntityProfileSection, type EntityProfileTemplate, type EntityRenderSpec, type EntityRenderTemplate, type EntitySectionPerRow, type EntitySectionsTemplate, type EntityTableColumn, type EntityTableTemplate, type Filter, type FilterOp, type HasManyRelation, type HasManySource, type InitOptions, Lattice, type LatticeConfig, type LatticeConfigInput, type LatticeEntityDef, type LatticeEntityRenderSpec, type LatticeFieldDef, type LatticeFieldType, type LatticeManifest, type LatticeOptions, type ManyToManySource, type MarkdownTableColumn, type Migration, type MultiTableDefinition, type OrderBySpec, type ParseError, type ParseResult, type ParsedConfig, type PkLookup, type PrimaryKey, type QueryOptions, READ_ONLY_HEADER, type ReadOnlyHeaderOptions, type ReconcileOptions, type ReconcileResult, type Relation, type RenderHooks, type RenderResult, type RenderSpec, type Row, type SecurityOptions, type SelfSource, type SessionEntry, type SessionParseOptions, type SessionWriteEntry, type SessionWriteOp, type SessionWriteParseResult, type SourceQueryOptions, type StopFn, type SyncResult, type TableDefinition, type TemplateRenderSpec, type WatchOptions, type WritebackDefinition, applyWriteEntry, createReadOnlyHeader, frontmatter, generateEntryId, generateWriteEntryId, manifestPath, markdownTable, parseConfigFile, parseConfigString, parseMarkdownEntries, parseSessionMD, parseSessionWrites, readManifest, slugify, truncate, validateEntryId, writeManifest };
1354
+ export { type ApplyWriteResult, type AuditEvent, type BelongsToRelation, type BelongsToSource, type BuiltinTemplateName, type CleanupOptions, type CleanupResult, type CountOptions, type CustomSource, DEFAULT_ENTRY_TYPES, DEFAULT_TYPE_ALIASES, type EnrichedSource, type EnrichmentLookup, type EntityContextDefinition, type EntityContextManifestEntry, type EntityFileSource, type EntityFileSpec, type EntityProfileField, type EntityProfileSection, type EntityProfileTemplate, type EntityRenderSpec, type EntityRenderTemplate, type EntitySectionPerRow, type EntitySectionsTemplate, type EntityTableColumn, type EntityTableTemplate, type Filter, type FilterOp, type HasManyRelation, type HasManySource, type InitOptions, Lattice, type LatticeConfig, type LatticeConfigInput, type LatticeEntityDef, type LatticeEntityRenderSpec, type LatticeFieldDef, type LatticeFieldType, type LatticeManifest, type LatticeOptions, type ManyToManySource, type MarkdownTableColumn, type Migration, type MultiTableDefinition, type OrderBySpec, type ParseError, type ParseResult, type ParsedConfig, type PkLookup, type PrimaryKey, type QueryOptions, READ_ONLY_HEADER, type ReadOnlyHeaderOptions, type ReconcileOptions, type ReconcileResult, type Relation, type RenderHooks, type RenderResult, type RenderSpec, type Row, type SecurityOptions, type SelfSource, type SessionEntry, type SessionParseOptions, type SessionWriteEntry, type SessionWriteOp, type SessionWriteParseResult, type SourceQueryOptions, type StopFn, type SyncResult, type TableDefinition, type TemplateRenderSpec, type WatchOptions, type WriteHook, type WriteHookContext, type WritebackDefinition, applyWriteEntry, createReadOnlyHeader, frontmatter, generateEntryId, generateWriteEntryId, manifestPath, markdownTable, parseConfigFile, parseConfigString, parseMarkdownEntries, parseSessionMD, parseSessionWrites, readManifest, slugify, truncate, validateEntryId, writeManifest };
package/dist/index.js CHANGED
@@ -1307,6 +1307,7 @@ var Lattice = class {
1307
1307
  _renderHandlers = [];
1308
1308
  _writebackHandlers = [];
1309
1309
  _errorHandlers = [];
1310
+ _writeHooks = [];
1310
1311
  constructor(pathOrConfig, options = {}) {
1311
1312
  let dbPath;
1312
1313
  let configTables;
@@ -1366,6 +1367,14 @@ var Lattice = class {
1366
1367
  this._schema.defineEntityContext(table, def);
1367
1368
  return this;
1368
1369
  }
1370
+ /**
1371
+ * Register a write hook that fires after insert/update/delete operations.
1372
+ * Hooks run synchronously after the DB write and audit emit.
1373
+ */
1374
+ defineWriteHook(hook) {
1375
+ this._writeHooks.push(hook);
1376
+ return this;
1377
+ }
1369
1378
  defineWriteback(def) {
1370
1379
  this._writeback.define(def);
1371
1380
  return this;
@@ -1415,6 +1424,7 @@ var Lattice = class {
1415
1424
  const rawPk = rowWithPk[pkCol];
1416
1425
  const pkValue = rawPk != null ? String(rawPk) : "";
1417
1426
  this._sanitizer.emitAudit(table, "insert", pkValue);
1427
+ this._fireWriteHooks(table, "insert", rowWithPk, pkValue);
1418
1428
  return Promise.resolve(pkValue);
1419
1429
  }
1420
1430
  upsert(table, row) {
@@ -1468,6 +1478,7 @@ var Lattice = class {
1468
1478
  this._adapter.run(`UPDATE "${table}" SET ${setCols} WHERE ${clause}`, values);
1469
1479
  const auditId = typeof id === "string" ? id : JSON.stringify(id);
1470
1480
  this._sanitizer.emitAudit(table, "update", auditId);
1481
+ this._fireWriteHooks(table, "update", sanitized, auditId, Object.keys(sanitized));
1471
1482
  return Promise.resolve();
1472
1483
  }
1473
1484
  delete(table, id) {
@@ -1477,6 +1488,7 @@ var Lattice = class {
1477
1488
  this._adapter.run(`DELETE FROM "${table}" WHERE ${clause}`, params);
1478
1489
  const auditId = typeof id === "string" ? id : JSON.stringify(id);
1479
1490
  this._sanitizer.emitAudit(table, "delete", auditId);
1491
+ this._fireWriteHooks(table, "delete", { id: auditId }, auditId);
1480
1492
  return Promise.resolve();
1481
1493
  }
1482
1494
  get(table, id) {
@@ -1714,6 +1726,22 @@ var Lattice = class {
1714
1726
  return { clauses, params };
1715
1727
  }
1716
1728
  /** Returns a rejected Promise if not initialized; null if ready. */
1729
+ _fireWriteHooks(table, op, row, pk, changedColumns) {
1730
+ for (const hook of this._writeHooks) {
1731
+ if (hook.table !== table) continue;
1732
+ if (!hook.on.includes(op)) continue;
1733
+ if (op === "update" && hook.watchColumns && changedColumns) {
1734
+ if (!hook.watchColumns.some((c) => changedColumns.includes(c))) continue;
1735
+ }
1736
+ try {
1737
+ const ctx = { table, op, row, pk };
1738
+ if (changedColumns) ctx.changedColumns = changedColumns;
1739
+ hook.handler(ctx);
1740
+ } catch (err) {
1741
+ for (const h of this._errorHandlers) h(err instanceof Error ? err : new Error(String(err)));
1742
+ }
1743
+ }
1744
+ }
1717
1745
  _notInitError() {
1718
1746
  if (!this._initialized) {
1719
1747
  return Promise.reject(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "latticesql",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Persistent structured memory for AI agent systems — SQLite ↔ LLM context bridge",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",