@delali/sirannon-db 0.2.0 → 0.2.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 (75) hide show
  1. package/dist/backup-scheduler/index.d.ts +15 -1
  2. package/dist/backup-scheduler/index.mjs +2 -2
  3. package/dist/baseline-D93hcIEE.d.ts +17 -0
  4. package/dist/{change-tracker-DKRVUC3l.d.ts → change-tracker-DDmXB754.d.ts} +56 -8
  5. package/dist/{chunk-5NOIGN5Y.mjs → chunk-2QLXDHAP.mjs} +1 -1
  6. package/dist/{chunk-LNY2VVHE.mjs → chunk-7C36BCSN.mjs} +1 -1
  7. package/dist/{chunk-NVQS53NT.mjs → chunk-7FQRQH5Z.mjs} +53 -64
  8. package/dist/{chunk-D7LAYTKN.mjs → chunk-7R4ER4FB.mjs} +1 -1
  9. package/dist/{chunk-FHWTZFI4.mjs → chunk-BQFQ65OL.mjs} +1 -1
  10. package/dist/{chunk-O7SLN3GI.mjs → chunk-BTTFW4Z4.mjs} +1 -1
  11. package/dist/{chunk-H6PIVVDN.mjs → chunk-CCZK6LCB.mjs} +38 -25
  12. package/dist/{chunk-JZGINXTN.mjs → chunk-HCCGEIZ2.mjs} +2 -2
  13. package/dist/{chunk-67M7KAH6.mjs → chunk-IWGIYDMZ.mjs} +1 -1
  14. package/dist/{chunk-LFZ37BSX.mjs → chunk-OUSWVNWT.mjs} +1 -1
  15. package/dist/{chunk-HR5CWTLC.mjs → chunk-P2VJYRVY.mjs} +60 -7
  16. package/dist/{chunk-UC3SCMIN.mjs → chunk-PBRXXISQ.mjs} +3 -0
  17. package/dist/{chunk-JU64Y7HM.mjs → chunk-SBL6GN43.mjs} +1 -1
  18. package/dist/{chunk-EBJXPQQO.mjs → chunk-UPKKSUPA.mjs} +2 -2
  19. package/dist/{chunk-TJF5GZSV.mjs → chunk-VOSJBZ6Q.mjs} +1 -1
  20. package/dist/{chunk-PIKHN33N.mjs → chunk-VOYGMAU7.mjs} +9 -1
  21. package/dist/{chunk-H237TXZW.mjs → chunk-WJ67DTD6.mjs} +48 -6
  22. package/dist/{chunk-OQVZBEBY.mjs → chunk-XF2HH5E6.mjs} +4 -61
  23. package/dist/client/index.d.ts +211 -12
  24. package/dist/client/index.mjs +155 -67
  25. package/dist/client/topology.d.ts +55 -7
  26. package/dist/client/topology.mjs +20 -1
  27. package/dist/{client-base-CLWmH5Ln.d.ts → client-base-CmZO0v3m.d.ts} +133 -24
  28. package/dist/codegen/cli.mjs +3 -3
  29. package/dist/codegen/index.d.ts +92 -2
  30. package/dist/codegen/index.mjs +3 -3
  31. package/dist/core/index.d.ts +177 -15
  32. package/dist/core/index.mjs +2481 -2226
  33. package/dist/core/writer-worker.mjs +3 -3
  34. package/dist/database-B5Qv1-cU.d.ts +380 -0
  35. package/dist/driver/better-sqlite3.d.ts +18 -1
  36. package/dist/driver/better-sqlite3.mjs +5 -5
  37. package/dist/driver/bun.d.ts +28 -0
  38. package/dist/driver/expo.d.ts +17 -0
  39. package/dist/driver/node.d.ts +18 -1
  40. package/dist/driver/node.mjs +5 -5
  41. package/dist/driver/wa-sqlite.d.ts +18 -1
  42. package/dist/{errors-Bw5MdNCu.d.ts → errors-Dei4GdBb.d.ts} +80 -7
  43. package/dist/file-migrations/index.d.ts +54 -2
  44. package/dist/file-migrations/index.mjs +3 -3
  45. package/dist/{operation-registry-9DcvxcE5.d.ts → operation-registry-hlbhqu7q.d.ts} +50 -1
  46. package/dist/{primary-wins-DPAm2AKG.d.ts → primary-wins-B0np8JS3.d.ts} +25 -1
  47. package/dist/protocol-rqANt-9Q.d.ts +152 -0
  48. package/dist/query-types-DL3LtPvY.d.ts +95 -0
  49. package/dist/react/index.d.ts +58 -3
  50. package/dist/replication/coordinator/etcd.d.ts +63 -3
  51. package/dist/replication/coordinator/etcd.mjs +82 -46
  52. package/dist/replication/index.d.ts +329 -95
  53. package/dist/replication/index.mjs +256 -141
  54. package/dist/server/index.d.ts +230 -12
  55. package/dist/server/index.mjs +63 -50
  56. package/dist/{server-options-1JHu8pid.d.ts → server-options-Dab_Jvd_.d.ts} +96 -12
  57. package/dist/sirannon-CMhiJa5Y.d.ts +111 -0
  58. package/dist/transport/grpc.d.ts +93 -9
  59. package/dist/transport/grpc.mjs +63 -20
  60. package/dist/transport/memory.d.ts +50 -20
  61. package/dist/transport/memory.mjs +25 -0
  62. package/dist/{types-CL6piSnD.d.ts → types-BCejqzNA.d.ts} +20 -0
  63. package/dist/types-CMBcFPhb.d.ts +336 -0
  64. package/dist/types-CjhxcjhA.d.ts +123 -0
  65. package/dist/types-DyrCiWuc.d.ts +499 -0
  66. package/dist/types-rVZKnKN-.d.ts +591 -0
  67. package/package.json +7 -1
  68. package/dist/baseline-Br77Fnhb.d.ts +0 -6
  69. package/dist/database-BY0L5Q2n.d.ts +0 -172
  70. package/dist/protocol-6KrSq2Hy.d.ts +0 -66
  71. package/dist/sirannon-DaQSyhbJ.d.ts +0 -36
  72. package/dist/types-B7gmEsZW.d.ts +0 -221
  73. package/dist/types-BsVabqSI.d.ts +0 -139
  74. package/dist/types-C_D8IhpO.d.ts +0 -60
  75. package/dist/types-zhnRXrsb.d.ts +0 -384
@@ -1,4 +1,5 @@
1
- import { e as SQLiteConnection, f as BackupScheduleOptions } from '../types-zhnRXrsb.js';
1
+ import { e as SQLiteConnection, f as BackupScheduleOptions } from '../types-rVZKnKN-.js';
2
+ import '../query-types-DL3LtPvY.js';
2
3
 
3
4
  declare class BackupManager {
4
5
  backup(conn: SQLiteConnection, destPath: string): Promise<void>;
@@ -8,9 +9,22 @@ declare class BackupManager {
8
9
 
9
10
  /** Runs a backup while the caller's writer lock is held, so it never shares the writer connection with another write. */
10
11
  type RunExclusive = (op: () => Promise<void>) => Promise<void>;
12
+ /**
13
+ * @public
14
+ *
15
+ * Repeats a database backup on a cron schedule and keeps a bounded number of files.
16
+ */
11
17
  declare class BackupScheduler {
12
18
  private readonly manager;
13
19
  constructor(manager?: BackupManager);
20
+ /**
21
+ * Starts repeating backups and returns a function that stops them.
22
+ *
23
+ * @param conn - Connection to the database being copied.
24
+ * @param options - Cron expression, destination directory, retention, time zone, and failure callback.
25
+ * @param runExclusive - Runs each copy with the database's writer held so that no write commits mid-copy.
26
+ * @returns A function that stops the schedule.
27
+ */
14
28
  schedule(conn: SQLiteConnection, options: BackupScheduleOptions, runExclusive?: RunExclusive): () => void;
15
29
  private run;
16
30
  }
@@ -1,2 +1,2 @@
1
- export { BackupScheduler } from '../chunk-PIKHN33N.mjs';
2
- import '../chunk-UC3SCMIN.mjs';
1
+ export { BackupScheduler } from '../chunk-VOYGMAU7.mjs';
2
+ import '../chunk-PBRXXISQ.mjs';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Marks the migration an existing database starts from, so earlier versions are recorded without running.
3
+ *
4
+ * @public
5
+ */
6
+ interface BaselineFileOption {
7
+ /**
8
+ * Version of the migration carrying the baseline.
9
+ */
10
+ version: number;
11
+ /**
12
+ * Highest version this baseline covers.
13
+ */
14
+ through: number;
15
+ }
16
+
17
+ export type { BaselineFileOption as B };
@@ -1,11 +1,33 @@
1
- import { e as SQLiteConnection, h as ChangeEvent } from './types-zhnRXrsb.js';
1
+ import { e as SQLiteConnection } from './types-rVZKnKN-.js';
2
+ import { C as ChangeEvent } from './query-types-DL3LtPvY.js';
2
3
 
4
+ /**
5
+ * How long a change tracker keeps changes, and how much it reads at a time.
6
+ *
7
+ * @public
8
+ */
3
9
  interface ChangeTrackerOptions {
10
+ /**
11
+ * Milliseconds a change stays readable before it is pruned. Default: 3_600_000 (one hour).
12
+ */
4
13
  retention?: number;
14
+ /**
15
+ * Name of the table changes are recorded in.
16
+ */
5
17
  changesTable?: string;
18
+ /**
19
+ * Changes read in one poll. Default: 1000.
20
+ */
6
21
  pollBatchSize?: number;
7
22
  }
8
23
 
24
+ /**
25
+ * Records every change to the tables you watch so that subscribers and replication can read them in order.
26
+ *
27
+ * Construct one, watch the tables you want captured, and pass it to a replication engine or leave it to the database that owns it.
28
+ *
29
+ * @public
30
+ */
9
31
  declare class ChangeTracker {
10
32
  private readonly watched;
11
33
  private lastSeq;
@@ -19,7 +41,19 @@ declare class ChangeTracker {
19
41
  private pruneBoundary;
20
42
  private lastPollAtTxBoundary;
21
43
  constructor(options?: ChangeTrackerOptions);
44
+ /**
45
+ * Starts recording changes to a table by installing its change-capture triggers.
46
+ *
47
+ * @param conn - Writer connection the triggers are created on.
48
+ * @param table - Name of the table to watch.
49
+ */
22
50
  watch(conn: SQLiteConnection, table: string): Promise<void>;
51
+ /**
52
+ * Stops recording changes to a table and drops its triggers.
53
+ *
54
+ * @param conn - Writer connection the triggers are dropped from.
55
+ * @param table - Name of the table to stop watching.
56
+ */
23
57
  unwatch(conn: SQLiteConnection, table: string): Promise<void>;
24
58
  /**
25
59
  * Rebuilds CDC triggers for every watched table directly on the supplied
@@ -45,6 +79,8 @@ declare class ChangeTracker {
45
79
  * `conn`. The cached column list is updated on success.
46
80
  * - Any other error (driver failure, identifier validation failure) is
47
81
  * rethrown so the caller's transaction can roll back deterministically.
82
+ *
83
+ * @internal
48
84
  */
49
85
  refreshAllTriggersUsingConnection(conn: SQLiteConnection): Promise<void>;
50
86
  /**
@@ -66,25 +102,37 @@ declare class ChangeTracker {
66
102
  * re-installed triggers compiled against the new schema. Those triggers
67
103
  * are dropped here so the recreated table starts with a clean slate and
68
104
  * the caller must explicitly `watch` it again.
105
+ *
106
+ * @internal
69
107
  */
70
108
  pruneDroppedTables(conn: SQLiteConnection, tables: readonly string[]): Promise<void>;
109
+ /** @internal */
71
110
  poll(conn: SQLiteConnection): Promise<ChangeEvent[]>;
111
+ /** @internal */
72
112
  get pollEndedAtTxBoundary(): boolean;
73
- /** The highest seq already polled; live subscribers receive events beyond it. */
74
- get cursor(): bigint;
75
113
  /**
76
- * Reads retained changes for one table with seq in `(afterSeq, upToSeq]`,
77
- * ordered ascending and capped at `limit`. Used to replay history to a
78
- * resuming subscriber without disturbing the shared poll cursor.
114
+ * The highest seq already polled; live subscribers receive events beyond it.
115
+ *
116
+ * @internal
79
117
  */
80
- readSince(conn: SQLiteConnection, table: string, afterSeq: bigint, upToSeq: bigint, limit: number): Promise<ChangeEvent[]>;
118
+ get cursor(): bigint;
119
+ /** @internal */
81
120
  readSinceTables(conn: SQLiteConnection, tables: readonly string[], afterSeq: bigint, upToSeq: bigint, limit: number): Promise<ChangeEvent[]>;
82
- /** The lowest retained seq, or `null` when the change log is empty. */
121
+ /**
122
+ * The lowest retained seq, or `null` when the change log is empty.
123
+ *
124
+ * @internal
125
+ */
83
126
  getMinSeq(conn: SQLiteConnection): Promise<bigint | null>;
127
+ /** @internal */
84
128
  advanceToLatest(conn: SQLiteConnection): Promise<void>;
129
+ /** @internal */
85
130
  cleanup(conn: SQLiteConnection): Promise<number>;
131
+ /** @internal */
86
132
  setPruneBoundary(seq: bigint): void;
133
+ /** @internal */
87
134
  clearPruneBoundary(): void;
135
+ /** @internal */
88
136
  get watchedTables(): ReadonlySet<string>;
89
137
  private computeSeqBound;
90
138
  private assertIdentifier;
@@ -1,4 +1,4 @@
1
- import { SirannonError } from './chunk-UC3SCMIN.mjs';
1
+ import { SirannonError } from './chunk-PBRXXISQ.mjs';
2
2
 
3
3
  // src/core/sync/errors.ts
4
4
  var ReplicationError = class extends SirannonError {
@@ -1,4 +1,4 @@
1
- import { MigrationError } from './chunk-UC3SCMIN.mjs';
1
+ import { MigrationError } from './chunk-PBRXXISQ.mjs';
2
2
 
3
3
  // src/core/migrations/lazy-down.ts
4
4
  var LAZY_DOWN_SQL = /* @__PURE__ */ Symbol("sirannon.file-migration.lazy-down");
@@ -1,56 +1,5 @@
1
- import { META_TABLE, CHANGES_TABLE, APPLIED_CHANGES_TABLE, MIGRATIONS_TABLE, COLUMN_VERSIONS_TABLE, DEVICE_CURSORS_TABLE, PEER_STATE_TABLE, SYNC_STATE_TABLE, STAGED_CHANGES_TABLE } from './chunk-D7LAYTKN.mjs';
2
- import { sha256Hex } from './chunk-GVCNMPOS.mjs';
3
- import { SirannonError } from './chunk-UC3SCMIN.mjs';
4
-
5
- // src/core/system-catalog/applied-changes-table.ts
6
- function toSeq(value) {
7
- if (value === null || value === void 0) return 0n;
8
- return typeof value === "bigint" ? value : BigInt(String(value));
9
- }
10
- async function ensureAppliedChangesTable(conn) {
11
- await conn.exec(`
12
- CREATE TABLE IF NOT EXISTS "${APPLIED_CHANGES_TABLE}" (
13
- source_node_id TEXT NOT NULL,
14
- source_seq INTEGER NOT NULL,
15
- applied_at REAL NOT NULL,
16
- PRIMARY KEY (source_node_id, source_seq)
17
- )`);
18
- }
19
- function prepareInsertAppliedChange(conn) {
20
- return conn.prepare(
21
- `INSERT OR IGNORE INTO ${APPLIED_CHANGES_TABLE} (source_node_id, source_seq, applied_at) VALUES (?, ?, ?)`
22
- );
23
- }
24
- async function selectMaxAppliedSourceSeq(conn, sourceNodeId) {
25
- const stmt = await conn.prepare(
26
- `SELECT MAX(source_seq) AS max_seq FROM ${APPLIED_CHANGES_TABLE} WHERE source_node_id = ?`
27
- );
28
- const row = await stmt.get(sourceNodeId);
29
- return toSeq(row?.max_seq);
30
- }
31
- async function selectMaxAppliedSourceSeqByNode(conn) {
32
- const stmt = await conn.prepare(
33
- `SELECT source_node_id, MAX(source_seq) AS max_seq FROM ${APPLIED_CHANGES_TABLE} GROUP BY source_node_id`
34
- );
35
- const rows = await stmt.all();
36
- const byNode = /* @__PURE__ */ new Map();
37
- for (const row of rows) {
38
- if (row.max_seq === null || row.max_seq === void 0) continue;
39
- byNode.set(row.source_node_id, toSeq(row.max_seq));
40
- }
41
- return byNode;
42
- }
43
- async function selectAppliedSourceSeqsInRange(conn, sourceNodeId, fromSeq, toSeqBound) {
44
- const stmt = await conn.prepare(
45
- `SELECT source_seq FROM ${APPLIED_CHANGES_TABLE} WHERE source_node_id = ? AND source_seq >= ? AND source_seq <= ?`
46
- );
47
- const rows = await stmt.all(sourceNodeId, fromSeq.toString(), toSeqBound.toString());
48
- const seqs = /* @__PURE__ */ new Set();
49
- for (const row of rows) {
50
- seqs.add(String(row.source_seq));
51
- }
52
- return seqs;
53
- }
1
+ import { META_TABLE, CHANGES_TABLE, MIGRATIONS_TABLE, APPLIED_CHANGES_TABLE, COLUMN_VERSIONS_TABLE, DEVICE_CURSORS_TABLE, PEER_STATE_TABLE, SYNC_STATE_TABLE, STAGED_CHANGES_TABLE } from './chunk-7R4ER4FB.mjs';
2
+ import { SirannonError } from './chunk-PBRXXISQ.mjs';
54
3
 
55
4
  // src/core/system-catalog/sqlite-catalog.ts
56
5
  async function selectTableExists(conn, table) {
@@ -167,11 +116,6 @@ var DDL_CHANGE_ROW_TABLE = "__ddl__";
167
116
  function selectChangesAfterSeqSql(tableName) {
168
117
  return `SELECT ${CHANGE_LOG_COLUMNS} FROM "${tableName}" WHERE seq > ? ORDER BY seq ASC LIMIT ?`;
169
118
  }
170
- function selectTableChangesInRangeSql(tableName) {
171
- return `SELECT ${CHANGE_LOG_COLUMNS} FROM "${tableName}"
172
- WHERE table_name = ? AND seq > ? AND seq <= ?
173
- ORDER BY seq ASC LIMIT ?`;
174
- }
175
119
  function selectTablesChangesInRangeSql(tableName, tableCount) {
176
120
  const placeholders = Array.from({ length: tableCount }, () => "?").join(", ");
177
121
  return `SELECT ${CHANGE_LOG_COLUMNS} FROM "${tableName}"
@@ -312,6 +256,56 @@ function highestMigrationVersion(rows) {
312
256
  return highest;
313
257
  }
314
258
 
259
+ // src/core/system-catalog/applied-changes-table.ts
260
+ function toSeq(value) {
261
+ if (value === null || value === void 0) return 0n;
262
+ return typeof value === "bigint" ? value : BigInt(String(value));
263
+ }
264
+ async function ensureAppliedChangesTable(conn) {
265
+ await conn.exec(`
266
+ CREATE TABLE IF NOT EXISTS "${APPLIED_CHANGES_TABLE}" (
267
+ source_node_id TEXT NOT NULL,
268
+ source_seq INTEGER NOT NULL,
269
+ applied_at REAL NOT NULL,
270
+ PRIMARY KEY (source_node_id, source_seq)
271
+ )`);
272
+ }
273
+ function prepareInsertAppliedChange(conn) {
274
+ return conn.prepare(
275
+ `INSERT OR IGNORE INTO ${APPLIED_CHANGES_TABLE} (source_node_id, source_seq, applied_at) VALUES (?, ?, ?)`
276
+ );
277
+ }
278
+ async function selectMaxAppliedSourceSeq(conn, sourceNodeId) {
279
+ const stmt = await conn.prepare(
280
+ `SELECT MAX(source_seq) AS max_seq FROM ${APPLIED_CHANGES_TABLE} WHERE source_node_id = ?`
281
+ );
282
+ const row = await stmt.get(sourceNodeId);
283
+ return toSeq(row?.max_seq);
284
+ }
285
+ async function selectMaxAppliedSourceSeqByNode(conn) {
286
+ const stmt = await conn.prepare(
287
+ `SELECT source_node_id, MAX(source_seq) AS max_seq FROM ${APPLIED_CHANGES_TABLE} GROUP BY source_node_id`
288
+ );
289
+ const rows = await stmt.all();
290
+ const byNode = /* @__PURE__ */ new Map();
291
+ for (const row of rows) {
292
+ if (row.max_seq === null || row.max_seq === void 0) continue;
293
+ byNode.set(row.source_node_id, toSeq(row.max_seq));
294
+ }
295
+ return byNode;
296
+ }
297
+ async function selectAppliedSourceSeqsInRange(conn, sourceNodeId, fromSeq, toSeqBound) {
298
+ const stmt = await conn.prepare(
299
+ `SELECT source_seq FROM ${APPLIED_CHANGES_TABLE} WHERE source_node_id = ? AND source_seq >= ? AND source_seq <= ?`
300
+ );
301
+ const rows = await stmt.all(sourceNodeId, fromSeq.toString(), toSeqBound.toString());
302
+ const seqs = /* @__PURE__ */ new Set();
303
+ for (const row of rows) {
304
+ seqs.add(String(row.source_seq));
305
+ }
306
+ return seqs;
307
+ }
308
+
315
309
  // src/core/system-catalog/column-versions-table.ts
316
310
  var UPSERT_COLUMN_VERSION = `INSERT INTO ${COLUMN_VERSIONS_TABLE} (table_name, row_id, column_name, hlc, node_id)
317
311
  VALUES (?, ?, ?, ?, ?)
@@ -634,11 +628,6 @@ var PkResolver = class {
634
628
  }
635
629
  };
636
630
 
637
- // src/core/sync/checksum.ts
638
- function computeChecksum(changes) {
639
- return sha256Hex(canonicaliseForChecksum(changes));
640
- }
641
-
642
631
  // src/core/sync/validators.ts
643
632
  var IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
644
633
  var SEQ_STRING_RE = /^\d{1,19}$/;
@@ -662,4 +651,4 @@ function extractDroppedTable(sql) {
662
651
  return m?.[1] ?? null;
663
652
  }
664
653
 
665
- export { IDENTIFIER_RE, PkResolver, SEQ_STRING_RE, UPSERT_META_VALUE_SQL, assertSafeIdentifier, canonicaliseForChecksum, computeChecksum, deleteAllStagedChanges, deleteChangesBeforeSql, deleteChangesBeforeUpToSeqSql, deleteDeviceCursorsUpdatedBefore, deleteMetaValue, deleteStagedChangesUpToSeq, deleteSyncTableStates, ensureBatchApplyTables, ensureChangesTable, ensureDeviceCursorsTable, ensureMetaTable, ensureMigrationsTable, ensureReplicationStateTables, ensureStagedChangesTable, extractDroppedTable, highestMigrationVersion, insertDdlChange, insertMetaValueIfAbsent, prepareDeleteMigration, prepareDeleteRowColumnVersions, prepareDeleteRowColumnVersionsUpToHlc, prepareInsertAppliedChange, prepareInsertMigration, prepareUpdateMigrationChecksum, prepareUpsertColumnVersion, prepareUpsertNewerColumnVersion, referencedTables, replaceMigrationHistory, selectAppliedMigrations, selectAppliedMigrationsNewestFirst, selectAppliedSourceSeqsInRange, selectChangesAfterSeqSql, selectCompletedSyncTableNames, selectCountOutboundChanges, selectCountTableRows, selectDeviceCursors, selectFirstStagedTransactionEnd, selectMaxAppliedSourceSeq, selectMaxAppliedSourceSeqByNode, selectMaxChangeHlc, selectMaxChangeSeq, selectMaxColumnVersionHlc, selectMaxColumnVersionHlcForRow, selectMaxRowChangeHlc, selectMaxStagedSeq, selectMetaValue, selectMinChangeSeqSql, selectMinForeignChangeSeqSql, selectMinPeerAckedSeq, selectNodeChangesAfterSeqSql, selectOutboundChangesSql, selectPeerAckedSeq, selectStagedChangesInRange, selectSyncMetaRow, selectTableChangesInRangeSql, selectTableExists, selectTableSql, selectTablesChangesInRangeSql, selectUserSchemaObjects, selectUserTableNames, setForeignKeysEnabled, tableColumnNames, tableInfoRows, tablePkColumns, updateChangeStampsAfterSeqSql, updateUnstampedChangeStampsSql, upsertDeviceCursor, upsertMetaValue, upsertPeerAckedSeq, upsertStagedChangeSql, upsertSyncMeta, upsertSyncTableStatus, validateDdlSafety, validateIdentifier };
654
+ export { IDENTIFIER_RE, PkResolver, SEQ_STRING_RE, UPSERT_META_VALUE_SQL, assertSafeIdentifier, canonicaliseForChecksum, deleteAllStagedChanges, deleteChangesBeforeSql, deleteChangesBeforeUpToSeqSql, deleteDeviceCursorsUpdatedBefore, deleteMetaValue, deleteStagedChangesUpToSeq, deleteSyncTableStates, ensureBatchApplyTables, ensureChangesTable, ensureDeviceCursorsTable, ensureMetaTable, ensureMigrationsTable, ensureReplicationStateTables, ensureStagedChangesTable, extractDroppedTable, highestMigrationVersion, insertDdlChange, insertMetaValueIfAbsent, prepareDeleteMigration, prepareDeleteRowColumnVersions, prepareDeleteRowColumnVersionsUpToHlc, prepareInsertAppliedChange, prepareInsertMigration, prepareUpdateMigrationChecksum, prepareUpsertColumnVersion, prepareUpsertNewerColumnVersion, referencedTables, replaceMigrationHistory, selectAppliedMigrations, selectAppliedMigrationsNewestFirst, selectAppliedSourceSeqsInRange, selectChangesAfterSeqSql, selectCompletedSyncTableNames, selectCountOutboundChanges, selectCountTableRows, selectDeviceCursors, selectFirstStagedTransactionEnd, selectMaxAppliedSourceSeq, selectMaxAppliedSourceSeqByNode, selectMaxChangeHlc, selectMaxChangeSeq, selectMaxColumnVersionHlc, selectMaxColumnVersionHlcForRow, selectMaxRowChangeHlc, selectMaxStagedSeq, selectMetaValue, selectMinChangeSeqSql, selectMinForeignChangeSeqSql, selectMinPeerAckedSeq, selectNodeChangesAfterSeqSql, selectOutboundChangesSql, selectPeerAckedSeq, selectStagedChangesInRange, selectSyncMetaRow, selectTableExists, selectTableSql, selectTablesChangesInRangeSql, selectUserSchemaObjects, selectUserTableNames, setForeignKeysEnabled, tableColumnNames, tableInfoRows, tablePkColumns, updateChangeStampsAfterSeqSql, updateUnstampedChangeStampsSql, upsertDeviceCursor, upsertMetaValue, upsertPeerAckedSeq, upsertStagedChangeSql, upsertSyncMeta, upsertSyncTableStatus, validateDdlSafety, validateIdentifier };
@@ -1,4 +1,4 @@
1
- import { ForbiddenSqlError } from './chunk-UC3SCMIN.mjs';
1
+ import { ForbiddenSqlError } from './chunk-PBRXXISQ.mjs';
2
2
 
3
3
  // src/core/internal-tables.ts
4
4
  var INTERNAL_TABLE_PREFIX = "_sirannon_";
@@ -1,4 +1,4 @@
1
- import { SirannonError } from './chunk-UC3SCMIN.mjs';
1
+ import { SirannonError } from './chunk-PBRXXISQ.mjs';
2
2
 
3
3
  // src/core/driver/define.ts
4
4
  function defineDriver(config) {
@@ -1,4 +1,4 @@
1
- import { ReplicationError } from './chunk-5NOIGN5Y.mjs';
1
+ import { ReplicationError } from './chunk-2QLXDHAP.mjs';
2
2
 
3
3
  // src/replication/errors.ts
4
4
  var ConflictError = class extends ReplicationError {
@@ -1,7 +1,7 @@
1
- import { tableColumnNames, tablePkColumns, selectMinChangeSeqSql, selectMaxChangeSeq, deleteChangesBeforeUpToSeqSql, deleteChangesBeforeSql, selectTableExists, ensureChangesTable, ensureMetaTable, insertMetaValueIfAbsent, selectMetaValue, selectChangesAfterSeqSql, selectTableChangesInRangeSql, selectTablesChangesInRangeSql } from './chunk-NVQS53NT.mjs';
2
- import { CHANGES_TABLE, isReservedIdentifier, CDC_TRIGGER_PREFIX, encodeTaggedValues, decodeTaggedValues, SAFE_INT_BOUND_TEXT } from './chunk-D7LAYTKN.mjs';
3
- import { synchronousPragmaValue } from './chunk-LFZ37BSX.mjs';
4
- import { SirannonError, ForbiddenSqlError, CDCError, MigrationError } from './chunk-UC3SCMIN.mjs';
1
+ import { tableColumnNames, tablePkColumns, selectMinChangeSeqSql, selectMaxChangeSeq, deleteChangesBeforeUpToSeqSql, deleteChangesBeforeSql, selectTableExists, ensureChangesTable, ensureMetaTable, insertMetaValueIfAbsent, selectMetaValue, selectChangesAfterSeqSql, selectTablesChangesInRangeSql } from './chunk-7FQRQH5Z.mjs';
2
+ import { CHANGES_TABLE, isReservedIdentifier, CDC_TRIGGER_PREFIX, encodeTaggedValues, decodeTaggedValues, SAFE_INT_BOUND_TEXT } from './chunk-7R4ER4FB.mjs';
3
+ import { synchronousPragmaValue } from './chunk-OUSWVNWT.mjs';
4
+ import { SirannonError, ForbiddenSqlError, CDCError, MigrationError } from './chunk-PBRXXISQ.mjs';
5
5
 
6
6
  // src/core/bulk-load.ts
7
7
  var DEFAULT_LOAD_DURABILITY = "off";
@@ -107,11 +107,6 @@ async function pollChanges(conn, cache, changesTable, afterSeq, batchSize) {
107
107
  }
108
108
  return { events, lastSeq, atTxBoundary: false };
109
109
  }
110
- async function readSinceOneTable(conn, cache, changesTable, table, afterSeq, upToSeq, limit) {
111
- const stmt = await cache.get(conn, "read_since", selectTableChangesInRangeSql(changesTable));
112
- const rows = await stmt.all(table, afterSeq.toString(), upToSeq.toString(), limit);
113
- return rows.map(rowToEvent);
114
- }
115
110
  async function readSinceTables(conn, cache, changesTable, tables, afterSeq, upToSeq, limit) {
116
111
  if (tables.length === 0) return [];
117
112
  const stmt = await cache.get(
@@ -228,6 +223,12 @@ var ChangeTracker = class {
228
223
  this.pollBatchSize = options?.pollBatchSize ?? DEFAULT_POLL_BATCH_SIZE;
229
224
  this.assertIdentifier(this.changesTable, "changes table name");
230
225
  }
226
+ /**
227
+ * Starts recording changes to a table by installing its change-capture triggers.
228
+ *
229
+ * @param conn - Writer connection the triggers are created on.
230
+ * @param table - Name of the table to watch.
231
+ */
231
232
  async watch(conn, table) {
232
233
  this.assertIdentifier(table, "table name");
233
234
  if (isReservedIdentifier(table)) {
@@ -258,6 +259,12 @@ var ChangeTracker = class {
258
259
  this.watched.set(table, { table, columns, pkColumns });
259
260
  this.watchedTablesCache = null;
260
261
  }
262
+ /**
263
+ * Stops recording changes to a table and drops its triggers.
264
+ *
265
+ * @param conn - Writer connection the triggers are dropped from.
266
+ * @param table - Name of the table to stop watching.
267
+ */
261
268
  async unwatch(conn, table) {
262
269
  if (!this.watched.has(table)) {
263
270
  return;
@@ -290,6 +297,8 @@ var ChangeTracker = class {
290
297
  * `conn`. The cached column list is updated on success.
291
298
  * - Any other error (driver failure, identifier validation failure) is
292
299
  * rethrown so the caller's transaction can roll back deterministically.
300
+ *
301
+ * @internal
293
302
  */
294
303
  async refreshAllTriggersUsingConnection(conn) {
295
304
  const tables = Array.from(this.watched.keys());
@@ -337,6 +346,8 @@ var ChangeTracker = class {
337
346
  * re-installed triggers compiled against the new schema. Those triggers
338
347
  * are dropped here so the recreated table starts with a clean slate and
339
348
  * the caller must explicitly `watch` it again.
349
+ *
350
+ * @internal
340
351
  */
341
352
  async pruneDroppedTables(conn, tables) {
342
353
  let mutated = false;
@@ -352,6 +363,7 @@ var ChangeTracker = class {
352
363
  this.watchedTablesCache = null;
353
364
  }
354
365
  }
366
+ /** @internal */
355
367
  async poll(conn) {
356
368
  if (!this.changesTableReady) {
357
369
  await this.detectChangesTable(conn);
@@ -368,27 +380,19 @@ var ChangeTracker = class {
368
380
  this.lastSeq = result.lastSeq;
369
381
  return result.events;
370
382
  }
383
+ /** @internal */
371
384
  get pollEndedAtTxBoundary() {
372
385
  return this.lastPollAtTxBoundary;
373
386
  }
374
- /** The highest seq already polled; live subscribers receive events beyond it. */
375
- get cursor() {
376
- return this.lastSeq;
377
- }
378
387
  /**
379
- * Reads retained changes for one table with seq in `(afterSeq, upToSeq]`,
380
- * ordered ascending and capped at `limit`. Used to replay history to a
381
- * resuming subscriber without disturbing the shared poll cursor.
388
+ * The highest seq already polled; live subscribers receive events beyond it.
389
+ *
390
+ * @internal
382
391
  */
383
- async readSince(conn, table, afterSeq, upToSeq, limit) {
384
- if (!this.changesTableReady) {
385
- await this.detectChangesTable(conn);
386
- if (!this.changesTableReady) {
387
- return [];
388
- }
389
- }
390
- return readSinceOneTable(conn, this.stmtCache, this.changesTable, table, afterSeq, upToSeq, limit);
392
+ get cursor() {
393
+ return this.lastSeq;
391
394
  }
395
+ /** @internal */
392
396
  async readSinceTables(conn, tables, afterSeq, upToSeq, limit) {
393
397
  if (tables.length === 0) return [];
394
398
  if (!this.changesTableReady) {
@@ -399,7 +403,11 @@ var ChangeTracker = class {
399
403
  }
400
404
  return readSinceTables(conn, this.stmtCache, this.changesTable, tables, afterSeq, upToSeq, limit);
401
405
  }
402
- /** The lowest retained seq, or `null` when the change log is empty. */
406
+ /**
407
+ * The lowest retained seq, or `null` when the change log is empty.
408
+ *
409
+ * @internal
410
+ */
403
411
  async getMinSeq(conn) {
404
412
  if (!this.changesTableReady) {
405
413
  await this.detectChangesTable(conn);
@@ -415,6 +423,7 @@ var ChangeTracker = class {
415
423
  }
416
424
  return typeof seq === "bigint" ? seq : BigInt(String(seq));
417
425
  }
426
+ /** @internal */
418
427
  async advanceToLatest(conn) {
419
428
  if (!this.changesTableReady) {
420
429
  await this.detectChangesTable(conn);
@@ -427,6 +436,7 @@ var ChangeTracker = class {
427
436
  this.lastSeq = latestSeq;
428
437
  }
429
438
  }
439
+ /** @internal */
430
440
  async cleanup(conn) {
431
441
  if (!this.changesTableReady) {
432
442
  await this.detectChangesTable(conn);
@@ -449,12 +459,15 @@ var ChangeTracker = class {
449
459
  const result = await stmt.run(cutoff);
450
460
  return result.changes;
451
461
  }
462
+ /** @internal */
452
463
  setPruneBoundary(seq) {
453
464
  this.pruneBoundary = seq;
454
465
  }
466
+ /** @internal */
455
467
  clearPruneBoundary() {
456
468
  this.pruneBoundary = null;
457
469
  }
470
+ /** @internal */
458
471
  get watchedTables() {
459
472
  if (!this.watchedTablesCache) {
460
473
  this.watchedTablesCache = new Set(this.watched.keys());
@@ -1,5 +1,5 @@
1
- import { assertSqlAllowed, encodeWireRowsInPlace } from './chunk-D7LAYTKN.mjs';
2
- import { SirannonError, QueryError } from './chunk-UC3SCMIN.mjs';
1
+ import { assertSqlAllowed, encodeWireRowsInPlace } from './chunk-7R4ER4FB.mjs';
2
+ import { SirannonError, QueryError } from './chunk-PBRXXISQ.mjs';
3
3
 
4
4
  // src/core/query-executor.ts
5
5
  var STATEMENT_CACHE_CAPACITY = 128;
@@ -1,4 +1,4 @@
1
- import { MigrationError } from './chunk-UC3SCMIN.mjs';
1
+ import { MigrationError } from './chunk-PBRXXISQ.mjs';
2
2
 
3
3
  // src/core/migrations/baseline.ts
4
4
  var SQLITE_USER_VERSION_MAX = 2147483647;
@@ -1,4 +1,4 @@
1
- import { SirannonError } from './chunk-UC3SCMIN.mjs';
1
+ import { SirannonError } from './chunk-PBRXXISQ.mjs';
2
2
 
3
3
  // src/core/driver/synchronous.ts
4
4
  var DEFAULT_SYNCHRONOUS = "normal";
@@ -1,7 +1,8 @@
1
- import { query, execute, executeBatch } from './chunk-JZGINXTN.mjs';
2
- import { ensureMetaTable, selectMetaValue, computeChecksum, IDENTIFIER_RE, selectAppliedSourceSeqsInRange, prepareInsertAppliedChange, validateDdlSafety, extractDroppedTable, selectMaxChangeSeq, updateChangeStampsAfterSeqSql, selectOutboundChangesSql, selectNodeChangesAfterSeqSql, prepareDeleteRowColumnVersionsUpToHlc, canonicaliseForChecksum, prepareUpsertNewerColumnVersion, upsertMetaValue, selectMaxColumnVersionHlcForRow, selectMaxRowChangeHlc, validateIdentifier, prepareDeleteRowColumnVersions, prepareUpsertColumnVersion } from './chunk-NVQS53NT.mjs';
3
- import { ReplicationError, BatchValidationError } from './chunk-5NOIGN5Y.mjs';
4
- import { CHANGES_TABLE, decodeTaggedValues } from './chunk-D7LAYTKN.mjs';
1
+ import { query, execute, executeBatch } from './chunk-HCCGEIZ2.mjs';
2
+ import { ensureMetaTable, selectMetaValue, IDENTIFIER_RE, selectAppliedSourceSeqsInRange, prepareInsertAppliedChange, validateDdlSafety, extractDroppedTable, selectMaxChangeSeq, updateChangeStampsAfterSeqSql, selectOutboundChangesSql, selectNodeChangesAfterSeqSql, prepareDeleteRowColumnVersionsUpToHlc, canonicaliseForChecksum, prepareUpsertNewerColumnVersion, upsertMetaValue, selectMaxColumnVersionHlcForRow, selectMaxRowChangeHlc, validateIdentifier, prepareDeleteRowColumnVersions, prepareUpsertColumnVersion } from './chunk-7FQRQH5Z.mjs';
3
+ import { ReplicationError, BatchValidationError } from './chunk-2QLXDHAP.mjs';
4
+ import { CHANGES_TABLE, decodeTaggedValues } from './chunk-7R4ER4FB.mjs';
5
+ import { sha256Hex } from './chunk-GVCNMPOS.mjs';
5
6
 
6
7
  // src/core/transaction.ts
7
8
  var Transaction = class _Transaction {
@@ -9,14 +10,35 @@ var Transaction = class _Transaction {
9
10
  this.conn = conn;
10
11
  }
11
12
  _lastInsertRowId = 0;
13
+ /**
14
+ * Runs a read inside this transaction.
15
+ *
16
+ * @param sql - The statement to run.
17
+ * @param params - Values bound to the statement, named or positional.
18
+ * @returns The rows the statement produced.
19
+ */
12
20
  async query(sql, params) {
13
21
  return query(this.conn, sql, params);
14
22
  }
23
+ /**
24
+ * Runs one write inside this transaction.
25
+ *
26
+ * @param sql - The statement to run.
27
+ * @param params - Values bound to the statement, named or positional.
28
+ * @returns How many rows changed, and the last inserted row id.
29
+ */
15
30
  async execute(sql, params) {
16
31
  const result = await execute(this.conn, sql, params);
17
32
  this._lastInsertRowId = result.lastInsertRowId;
18
33
  return result;
19
34
  }
35
+ /**
36
+ * Runs one statement over many parameter sets inside this transaction.
37
+ *
38
+ * @param sql - The statement to run for each parameter set.
39
+ * @param paramsBatch - One parameter set per run.
40
+ * @returns One result per parameter set, in order.
41
+ */
20
42
  async executeBatch(sql, paramsBatch) {
21
43
  const results = await executeBatch(this.conn, sql, paramsBatch);
22
44
  if (results.length > 0) {
@@ -24,9 +46,13 @@ var Transaction = class _Transaction {
24
46
  }
25
47
  return results;
26
48
  }
49
+ /**
50
+ * Row id SQLite assigned to the last row this transaction inserted.
51
+ */
27
52
  get lastInsertRowId() {
28
53
  return this._lastInsertRowId;
29
54
  }
55
+ /** @internal */
30
56
  static async run(conn, fn) {
31
57
  return conn.transaction(async (txConn) => {
32
58
  const tx = new _Transaction(txConn);
@@ -46,7 +72,11 @@ var HLC = class _HLC {
46
72
  this.wallMs = 0;
47
73
  this.logical = 0;
48
74
  }
49
- /** Generate a new HLC timestamp, advancing the clock. */
75
+ /**
76
+ * Generate a new HLC timestamp, advancing the clock.
77
+ *
78
+ * @internal
79
+ */
50
80
  now() {
51
81
  const physicalMs = Date.now();
52
82
  if (physicalMs > this.wallMs) {
@@ -60,7 +90,11 @@ var HLC = class _HLC {
60
90
  }
61
91
  return _HLC.encode(this.wallMs, this.logical, this.nodeId);
62
92
  }
63
- /** Merge a remote HLC timestamp into the local clock and return the updated value. */
93
+ /**
94
+ * Merge a remote HLC timestamp into the local clock and return the updated value.
95
+ *
96
+ * @internal
97
+ */
64
98
  receive(remote) {
65
99
  const r = _HLC.decode(remote);
66
100
  const physicalMs = Date.now();
@@ -98,6 +132,14 @@ var HLC = class _HLC {
98
132
  nodeId: parts.slice(2).join("-")
99
133
  };
100
134
  }
135
+ /**
136
+ * Builds the string form of a clock reading, which sorts in the same order as the reading itself.
137
+ *
138
+ * @param wallMs - Wall-clock milliseconds since the Unix epoch.
139
+ * @param logical - Counter that orders events sharing one millisecond.
140
+ * @param nodeId - Identifier of the node taking the reading.
141
+ * @returns The encoded stamp.
142
+ */
101
143
  static encode(wallMs, logical, nodeId) {
102
144
  const wallHex = wallMs.toString(16).padStart(12, "0");
103
145
  const logicalHex = logical.toString(16).padStart(4, "0");
@@ -107,6 +149,12 @@ var HLC = class _HLC {
107
149
 
108
150
  // src/core/sync/conflict/lww.ts
109
151
  var LWWResolver = class {
152
+ /**
153
+ * Takes the incoming row when its stamp is higher, and keeps the local row otherwise.
154
+ *
155
+ * @param ctx - The local and incoming versions of one row.
156
+ * @returns Which version to write.
157
+ */
110
158
  resolve(ctx) {
111
159
  if (ctx.remoteChange.operation === "delete") {
112
160
  return { action: "accept_remote" };
@@ -128,6 +176,11 @@ var LWWResolver = class {
128
176
  }
129
177
  };
130
178
 
179
+ // src/core/sync/checksum.ts
180
+ function computeChecksum(changes) {
181
+ return sha256Hex(canonicaliseForChecksum(changes));
182
+ }
183
+
131
184
  // src/core/sync/hlc-store.ts
132
185
  var HLC_CLOCK_META_KEY = "hlc_clock";
133
186
  function isWellFormedHlc(candidate) {
@@ -403,7 +456,7 @@ var BatchApplier = class {
403
456
  }
404
457
  /**
405
458
  * Applies one pulled transaction whose changes are read from disk in
406
- * batches, so a transaction of any size is applied with bounded memory.
459
+ * batches so that a transaction of any size is applied with bounded memory.
407
460
  * The whole group runs in one local transaction: the batches, the echo
408
461
  * stamping, and `withinTx` commit together or not at all.
409
462
  */
@@ -54,6 +54,9 @@ var HookDeniedError = class extends SirannonError {
54
54
  }
55
55
  };
56
56
  var RequestDeniedError = class extends SirannonError {
57
+ /**
58
+ * HTTP status the server answers the refused request with.
59
+ */
57
60
  status;
58
61
  constructor(status, code, message) {
59
62
  super(message, code);