@delali/sirannon-db 0.3.1-next.43 → 0.3.1-next.46

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 (59) hide show
  1. package/dist/backup/index.d.ts +6 -6
  2. package/dist/backup/index.mjs +3 -3
  3. package/dist/backup-scheduler/index.d.ts +3 -3
  4. package/dist/backup-scheduler/index.mjs +4 -4
  5. package/dist/{change-tracker-uG9gWvsY.d.ts → change-tracker-BY8_k6lS.d.ts} +2 -2
  6. package/dist/chunk-3LXXH3RA.mjs +6 -0
  7. package/dist/{chunk-7FQRQH5Z.mjs → chunk-45MKELYA.mjs} +13 -1
  8. package/dist/{chunk-7R4ER4FB.mjs → chunk-6CMCO7S4.mjs} +8 -1
  9. package/dist/{chunk-OJQHM4MT.mjs → chunk-ASEZCQNA.mjs} +29 -24
  10. package/dist/{chunk-2QCPVE67.mjs → chunk-E6IMX7RS.mjs} +1 -1
  11. package/dist/{chunk-63VBFSCS.mjs → chunk-E7Q7HE46.mjs} +3 -3
  12. package/dist/{chunk-3UHAPQBW.mjs → chunk-EVA2RWPP.mjs} +51 -23
  13. package/dist/{chunk-DVS4QSIZ.mjs → chunk-GYCEJNU4.mjs} +8 -1
  14. package/dist/{chunk-DXXCLTFF.mjs → chunk-JQWGHSEH.mjs} +7 -9
  15. package/dist/{chunk-W77EEVOT.mjs → chunk-KDAHYFW7.mjs} +3 -3
  16. package/dist/{chunk-P2VJYRVY.mjs → chunk-KXTYR2OQ.mjs} +8 -5
  17. package/dist/{chunk-ECEGYTVF.mjs → chunk-M2BEAH5I.mjs} +18 -17
  18. package/dist/{chunk-YLAVDZCS.mjs → chunk-MVSES6MS.mjs} +2 -2
  19. package/dist/{chunk-HCCGEIZ2.mjs → chunk-MYNI2WFS.mjs} +1 -1
  20. package/dist/chunk-QBBLSQHQ.mjs +35 -0
  21. package/dist/{chunk-XF2HH5E6.mjs → chunk-QP5L5DFJ.mjs} +2 -2
  22. package/dist/client/index.d.ts +15 -14
  23. package/dist/client/index.mjs +8 -16
  24. package/dist/client/topology.d.ts +26 -8
  25. package/dist/client/topology.mjs +84 -2
  26. package/dist/{client-base-C-B8u5Lm.d.ts → client-base-DrfhyZVo.d.ts} +43 -10
  27. package/dist/codegen/index.d.ts +2 -2
  28. package/dist/core/index.d.ts +62 -13
  29. package/dist/core/index.mjs +158 -58
  30. package/dist/core/writer-worker.mjs +4 -4
  31. package/dist/{database-BlhUdJAO.d.ts → database-DHxMvGza.d.ts} +23 -13
  32. package/dist/{database-backup-C090lMHc.d.ts → database-backup-CAuL6aA-.d.ts} +1 -1
  33. package/dist/driver/better-sqlite3.d.ts +2 -2
  34. package/dist/driver/better-sqlite3.mjs +7 -7
  35. package/dist/driver/bun.d.ts +2 -2
  36. package/dist/driver/expo.d.ts +2 -2
  37. package/dist/driver/node.d.ts +2 -2
  38. package/dist/driver/node.mjs +7 -7
  39. package/dist/driver/wa-sqlite.d.ts +2 -2
  40. package/dist/file-migrations/index.d.ts +2 -2
  41. package/dist/{operation-registry-C1FmwQWR.d.ts → operation-registry-oiPuSYI6.d.ts} +1 -1
  42. package/dist/{protocol-QekTGoKn.d.ts → protocol-BM2_usOB.d.ts} +2 -2
  43. package/dist/{query-types-Cv8N7pXj.d.ts → query-types-p1liOP-b.d.ts} +27 -4
  44. package/dist/react/index.d.ts +3 -3
  45. package/dist/react/index.mjs +1 -7
  46. package/dist/replication/index.d.ts +10 -10
  47. package/dist/replication/index.mjs +8 -19
  48. package/dist/{restore-options-C9MW9gpm.d.ts → restore-options-DDOqVqDn.d.ts} +1 -1
  49. package/dist/server/index.d.ts +14 -12
  50. package/dist/server/index.mjs +96 -29
  51. package/dist/{server-options-DeK6ZG8u.d.ts → server-options-C3KHEL8z.d.ts} +14 -6
  52. package/dist/{sirannon-C9cTgFrw.d.ts → sirannon-BoOZwMkx.d.ts} +34 -10
  53. package/dist/transport/grpc.d.ts +4 -4
  54. package/dist/transport/memory.d.ts +4 -4
  55. package/dist/{types-C1yBGTdx.d.ts → types-6QmvKWho.d.ts} +2 -2
  56. package/dist/{types-DApb7dvw.d.ts → types-_k29or0d.d.ts} +37 -15
  57. package/dist/{types-BCejqzNA.d.ts → types-qohUrQx6.d.ts} +6 -0
  58. package/package.json +7 -7
  59. package/dist/chunk-V5FUJEYY.mjs +0 -8
@@ -1,9 +1,9 @@
1
- import { B as BackupDestination, f as BackupRunReport } from '../types-DApb7dvw.js';
2
- export { g as BackupChain, h as BackupChainBase, i as BackupChainChange, j as BackupChainPosition, k as BackupChainRecord, l as BackupCycle, m as BackupCycleError, n as BackupCycleOptions, o as BackupCycleStatus, p as BackupFileReport, q as BackupGroupMembership, r as BackupGroupSource, s as BackupLogPosition, t as BackupNodePreference, u as BackupPiece, v as BackupProgress, w as BackupSkip, x as BackupSkipReason, y as BackupToDestinationOptions, z as BackupVerifyResult, C as DEFAULT_CHAIN_NAME, E as chainLogName, F as readBackupChains, G as verifyBackupRecord } from '../types-DApb7dvw.js';
3
- export { B as BackupCapabilities, a as BackupChainLocation, b as BackupRestorePlan, c as BackupSafeToDeleteOptions, d as backupPiecesSafeToDelete, p as planBackupRestore } from '../database-backup-C090lMHc.js';
4
- import { B as BackupRestoreOptions, a as BackupRestoreReport } from '../restore-options-C9MW9gpm.js';
5
- export { b as BackupRestoreProgress } from '../restore-options-C9MW9gpm.js';
6
- import '../query-types-Cv8N7pXj.js';
1
+ import { B as BackupDestination, f as BackupRunReport } from '../types-_k29or0d.js';
2
+ export { g as BackupChain, h as BackupChainBase, i as BackupChainChange, j as BackupChainPosition, k as BackupChainRecord, l as BackupCycle, m as BackupCycleError, n as BackupCycleOptions, o as BackupCycleStatus, p as BackupFileReport, q as BackupGroupMembership, r as BackupGroupSource, s as BackupLogPosition, t as BackupNodePreference, u as BackupPiece, v as BackupProgress, w as BackupSkip, x as BackupSkipReason, y as BackupToDestinationOptions, z as BackupVerifyResult, C as DEFAULT_CHAIN_NAME, E as chainLogName, F as readBackupChains, G as verifyBackupRecord } from '../types-_k29or0d.js';
3
+ export { B as BackupCapabilities, a as BackupChainLocation, b as BackupRestorePlan, c as BackupSafeToDeleteOptions, d as backupPiecesSafeToDelete, p as planBackupRestore } from '../database-backup-CAuL6aA-.js';
4
+ import { B as BackupRestoreOptions, a as BackupRestoreReport } from '../restore-options-DDOqVqDn.js';
5
+ export { b as BackupRestoreProgress } from '../restore-options-DDOqVqDn.js';
6
+ import '../query-types-p1liOP-b.js';
7
7
 
8
8
  /** What one assembled file took to build.
9
9
  * @public
@@ -1,8 +1,8 @@
1
- export { assembleFromDestination, restoreBackup } from '../chunk-63VBFSCS.mjs';
1
+ export { assembleFromDestination, restoreBackup } from '../chunk-E7Q7HE46.mjs';
2
2
  export { backupPiecesSafeToDelete, planBackupRestore } from '../chunk-YNTDOFTN.mjs';
3
3
  export { verifyBackupRecord } from '../chunk-7SC2TZAS.mjs';
4
4
  import '../chunk-U445A3C4.mjs';
5
- import '../chunk-DVS4QSIZ.mjs';
5
+ import '../chunk-GYCEJNU4.mjs';
6
6
  export { DEFAULT_CHAIN_NAME, chainLogName, readBackupChains } from '../chunk-YVF2ZJTE.mjs';
7
- import '../chunk-V5FUJEYY.mjs';
7
+ import '../chunk-QBBLSQHQ.mjs';
8
8
  import '../chunk-PBRXXISQ.mjs';
@@ -1,6 +1,6 @@
1
- import { I as SQLiteConnection, J as BackupFileCopy, K as BackupRunRequest, f as BackupRunReport, L as BackupScheduleRequest } from '../types-DApb7dvw.js';
2
- export { p as BackupFileReport, O as BackupScheduleOptions, R as RunExclusive } from '../types-DApb7dvw.js';
3
- import '../query-types-Cv8N7pXj.js';
1
+ import { I as SQLiteConnection, J as BackupFileCopy, K as BackupRunRequest, f as BackupRunReport, L as BackupScheduleRequest } from '../types-_k29or0d.js';
2
+ export { p as BackupFileReport, O as BackupScheduleOptions, R as RunExclusive } from '../types-_k29or0d.js';
3
+ import '../query-types-p1liOP-b.js';
4
4
 
5
5
  /** What one runtime needs before a copy can reach a destination without a local file.
6
6
  * @internal
@@ -1,6 +1,6 @@
1
- export { BackupScheduler } from '../chunk-DXXCLTFF.mjs';
1
+ export { BackupScheduler } from '../chunk-JQWGHSEH.mjs';
2
2
  import '../chunk-W67A4H2E.mjs';
3
- import '../chunk-2QCPVE67.mjs';
4
- import '../chunk-DVS4QSIZ.mjs';
5
- import '../chunk-V5FUJEYY.mjs';
3
+ import '../chunk-E6IMX7RS.mjs';
4
+ import '../chunk-GYCEJNU4.mjs';
5
+ import '../chunk-QBBLSQHQ.mjs';
6
6
  import '../chunk-PBRXXISQ.mjs';
@@ -1,5 +1,5 @@
1
- import { I as SQLiteConnection } from './types-DApb7dvw.js';
2
- import { C as ChangeEvent } from './query-types-Cv8N7pXj.js';
1
+ import { I as SQLiteConnection } from './types-_k29or0d.js';
2
+ import { C as ChangeEvent } from './query-types-p1liOP-b.js';
3
3
 
4
4
  /**
5
5
  * How long a change tracker keeps changes, and how much it reads at a time.
@@ -0,0 +1,6 @@
1
+ // src/core/operation-registry.ts
2
+ function operationRef(name) {
3
+ return { name };
4
+ }
5
+
6
+ export { operationRef };
@@ -1,4 +1,4 @@
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';
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, isReservedIdentifier } from './chunk-6CMCO7S4.mjs';
2
2
  import { SirannonError } from './chunk-PBRXXISQ.mjs';
3
3
 
4
4
  // src/core/system-catalog/sqlite-catalog.ts
@@ -636,7 +636,19 @@ var DDL_DENY_RE = /\b(load_extension|ATTACH|randomblob|zeroblob|writefile|readfi
636
636
  function validateIdentifier(name) {
637
637
  return IDENTIFIER_RE.test(name);
638
638
  }
639
+ var CREATE_INDEX_TARGETS_RE = /^\s*CREATE\s+INDEX(?:\s+IF\s+NOT\s+EXISTS)?\s+(?:["`[]?[A-Za-z_][A-Za-z0-9_]*["`\]]?\s*\.\s*)?["`[]?([A-Za-z_][A-Za-z0-9_]*)["`\]]?\s+ON\s+(?:["`[]?[A-Za-z_][A-Za-z0-9_]*["`\]]?\s*\.\s*)?["`[]?([A-Za-z_][A-Za-z0-9_]*)/i;
640
+ var DDL_TARGET_RE = /^\s*(?:CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?|ALTER\s+TABLE|DROP\s+TABLE(?:\s+IF\s+EXISTS)?|DROP\s+INDEX(?:\s+IF\s+EXISTS)?)\s+(?:["`[]?[A-Za-z_][A-Za-z0-9_]*["`\]]?\s*\.\s*)?["`[]?([A-Za-z_][A-Za-z0-9_]*)/i;
641
+ function ddlTargetsReservedIdentifier(sql) {
642
+ const indexTargets = CREATE_INDEX_TARGETS_RE.exec(sql);
643
+ if (indexTargets !== null) {
644
+ return isReservedIdentifier(indexTargets[1]) || isReservedIdentifier(indexTargets[2]);
645
+ }
646
+ const target = DDL_TARGET_RE.exec(sql);
647
+ if (target !== null) return isReservedIdentifier(target[1]);
648
+ return false;
649
+ }
639
650
  function validateDdlSafety(sql) {
651
+ if (ddlTargetsReservedIdentifier(sql)) return false;
640
652
  if (!SAFE_DDL_RE.test(sql)) return false;
641
653
  if (sql.includes(";")) return false;
642
654
  if (/\bAS\s+SELECT\b/i.test(sql)) return false;
@@ -166,6 +166,13 @@ var SAFE_INT_BOUND_TEXT = "9007199254740991";
166
166
  var SAFE_INT_BOUND = 9007199254740991n;
167
167
  var HEX_BYTES_RE = /^[0-9a-fA-F]*$/;
168
168
  var INT_PAYLOAD_RE = /^-?\d{1,19}$/;
169
+ var MILLISECONDS_PER_SECOND = 1e3;
170
+ function changedAtToEventTimestamp(changedAt) {
171
+ return Math.round(changedAt * MILLISECONDS_PER_SECOND);
172
+ }
173
+ function eventTimestampToChangedAt(timestamp) {
174
+ return timestamp / MILLISECONDS_PER_SECOND;
175
+ }
169
176
  function encodeTaggedValues(value) {
170
177
  if (typeof value === "bigint" || isBinaryValue(value)) {
171
178
  return encodeTaggedLeaf(value);
@@ -268,4 +275,4 @@ function decodeHexBytes(hex) {
268
275
  return bytes;
269
276
  }
270
277
 
271
- export { APPLIED_CHANGES_TABLE, CDC_TRIGGER_PREFIX, CHANGES_TABLE, COLUMN_VERSIONS_TABLE, DEVICE_CURSORS_TABLE, INTERNAL_TABLE_PREFIX, LIVE_PROBE_TABLE_PREFIX, META_TABLE, MIGRATIONS_TABLE, PEER_STATE_TABLE, SAFE_INT_BOUND_TEXT, STAGED_CHANGES_TABLE, SYNC_STATE_TABLE, assertSqlAllowed, decodeTaggedValues, encodeTaggedValues, encodeWireRowsInPlace, isReservedIdentifier };
278
+ export { APPLIED_CHANGES_TABLE, CDC_TRIGGER_PREFIX, CHANGES_TABLE, COLUMN_VERSIONS_TABLE, DEVICE_CURSORS_TABLE, INTERNAL_TABLE_PREFIX, LIVE_PROBE_TABLE_PREFIX, META_TABLE, MIGRATIONS_TABLE, PEER_STATE_TABLE, SAFE_INT_BOUND_TEXT, STAGED_CHANGES_TABLE, SYNC_STATE_TABLE, assertSqlAllowed, changedAtToEventTimestamp, decodeTaggedValues, encodeTaggedValues, encodeWireRowsInPlace, eventTimestampToChangedAt, isReservedIdentifier };
@@ -1,13 +1,13 @@
1
1
  import { verifyBackupRecord } from './chunk-7SC2TZAS.mjs';
2
- import { BackupManager, BackupScheduler, DEFAULT_PIECE_BYTES, sendFileInPieces } from './chunk-DXXCLTFF.mjs';
2
+ import { BackupManager, BackupScheduler, DEFAULT_PIECE_BYTES, sendFileInPieces } from './chunk-JQWGHSEH.mjs';
3
3
  import { DEFAULT_BACKUP_NAME_PREFIX, defaultStagingDir, DEFAULT_CAPTURE_INTERVAL_MS, DEFAULT_FULL_COPY_INTERVAL_MS } from './chunk-LXCGPZPA.mjs';
4
- import { WORKER_CANCELLED_CODE, deserializeError } from './chunk-YLAVDZCS.mjs';
5
- import { readCycleState, writeCycleState, removeCycleState, stagedCapturePath, captureAndCheckpointTurn } from './chunk-W77EEVOT.mjs';
4
+ import { WORKER_CANCELLED_CODE, WORKER_COPY_STOPPED_CODE, deserializeError } from './chunk-MVSES6MS.mjs';
5
+ import { readCycleState, writeCycleState, removeCycleState, stagedCapturePath, captureAndCheckpointTurn } from './chunk-KDAHYFW7.mjs';
6
6
  import { checkpointLog } from './chunk-U445A3C4.mjs';
7
- import { logPathFor } from './chunk-2QCPVE67.mjs';
8
- import { destinationWithDeadline, DEFAULT_DESTINATION_TIMEOUT_MS } from './chunk-DVS4QSIZ.mjs';
7
+ import { logPathFor } from './chunk-E6IMX7RS.mjs';
8
+ import { destinationWithDeadline, DEFAULT_DESTINATION_TIMEOUT_MS, reportQuietly } from './chunk-GYCEJNU4.mjs';
9
9
  import { DEFAULT_CHAIN_NAME, readBackupChains, appendChainRecord, appendChainHead, readChainHeadAt, readChainHeads } from './chunk-YVF2ZJTE.mjs';
10
- import { randomHex } from './chunk-V5FUJEYY.mjs';
10
+ import { randomHex } from './chunk-QBBLSQHQ.mjs';
11
11
  import { SirannonError, ExtensionError } from './chunk-PBRXXISQ.mjs';
12
12
  import { Worker } from 'worker_threads';
13
13
  import { existsSync } from 'fs';
@@ -180,12 +180,16 @@ var WriterWorker = class _WriterWorker {
180
180
  if (res.error.code === WORKER_CANCELLED_CODE) {
181
181
  entry.reject(
182
182
  new SirannonError(
183
- `The writer worker could not take this operation within ${this.timeoutMs}ms; it was not applied and is safe to retry`,
183
+ `The writer worker could not take this operation within ${entry.deadlineMs}ms; it was not applied and is safe to retry`,
184
184
  "WRITE_OVERLOADED"
185
185
  )
186
186
  );
187
187
  return;
188
188
  }
189
+ if (res.error.code === WORKER_COPY_STOPPED_CODE) {
190
+ entry.reject(this.unresponsiveError(entry.deadlineMs, entry.kind));
191
+ return;
192
+ }
189
193
  entry.reject(deserializeError(res.error));
190
194
  }
191
195
  onCopyStep(id, step) {
@@ -193,7 +197,7 @@ var WriterWorker = class _WriterWorker {
193
197
  if (!entry) return;
194
198
  if (entry.timer) {
195
199
  clearTimeout(entry.timer);
196
- entry.timer = this.timeoutMs > 0 ? setTimeout(() => this.onDeadline(id), this.timeoutMs) : null;
200
+ entry.timer = entry.deadlineMs > 0 ? setTimeout(() => this.onDeadline(id), entry.deadlineMs) : null;
197
201
  entry.timer?.unref?.();
198
202
  }
199
203
  try {
@@ -236,18 +240,18 @@ var WriterWorker = class _WriterWorker {
236
240
  if (!entry) return;
237
241
  const worker = this.worker;
238
242
  if (!entry.cancellable || !worker) {
239
- this.rejectPending(id, this.unresponsiveError(this.timeoutMs, entry.kind));
243
+ this.rejectPending(id, this.unresponsiveError(entry.deadlineMs, entry.kind));
240
244
  return;
241
245
  }
242
246
  try {
243
247
  worker.postMessage({ kind: "cancel", id });
244
248
  } catch {
245
- this.rejectPending(id, this.unresponsiveError(this.timeoutMs, entry.kind));
249
+ this.rejectPending(id, this.unresponsiveError(entry.deadlineMs, entry.kind));
246
250
  return;
247
251
  }
248
252
  entry.graceTimer = setTimeout(() => {
249
- this.rejectPending(id, this.unresponsiveError(this.timeoutMs * 2, entry.kind));
250
- }, this.timeoutMs);
253
+ this.rejectPending(id, this.unresponsiveError(entry.deadlineMs * 2, entry.kind));
254
+ }, entry.deadlineMs);
251
255
  entry.graceTimer.unref?.();
252
256
  }
253
257
  fault(errLike) {
@@ -291,10 +295,11 @@ var WriterWorker = class _WriterWorker {
291
295
  }
292
296
  const id = this.nextId++;
293
297
  const message = { ...request, id };
298
+ const deadlineMs = copyStallDeadline(request) ?? this.timeoutMs;
294
299
  return new Promise((resolve2, reject) => {
295
300
  let timer = null;
296
- if (this.timeoutMs > 0) {
297
- timer = setTimeout(() => this.onDeadline(id), this.timeoutMs);
301
+ if (deadlineMs > 0) {
302
+ timer = setTimeout(() => this.onDeadline(id), deadlineMs);
298
303
  timer.unref?.();
299
304
  }
300
305
  const cancellable = request.kind !== "open" && request.kind !== "close" && request.kind !== "loadExtension";
@@ -303,6 +308,7 @@ var WriterWorker = class _WriterWorker {
303
308
  reject,
304
309
  timer,
305
310
  graceTimer: null,
311
+ deadlineMs,
306
312
  cancellable,
307
313
  kind: request.kind,
308
314
  ...onStep ? { onStep } : {}
@@ -352,7 +358,12 @@ var WriterWorker = class _WriterWorker {
352
358
  }),
353
359
  copyRunsOffCallerThread: true,
354
360
  copyDatabase: (request) => this.request(
355
- { kind: "copyDatabase", destPath: request.destPath, pagesPerStep: request.pagesPerStep },
361
+ {
362
+ kind: "copyDatabase",
363
+ destPath: request.destPath,
364
+ pagesPerStep: request.pagesPerStep,
365
+ ...request.stallTimeoutMs === void 0 ? {} : { stallTimeoutMs: request.stallTimeoutMs }
366
+ },
356
367
  request.onStep
357
368
  ),
358
369
  loadExtension: async (extensionPath) => {
@@ -403,6 +414,9 @@ var WriterWorker = class _WriterWorker {
403
414
  this.pending.clear();
404
415
  }
405
416
  };
417
+ function copyStallDeadline(request) {
418
+ return request.kind === "copyDatabase" ? request.stallTimeoutMs : void 0;
419
+ }
406
420
  function clearPendingTimers(entry) {
407
421
  if (entry.timer) clearTimeout(entry.timer);
408
422
  if (entry.graceTimer) clearTimeout(entry.graceTimer);
@@ -544,15 +558,6 @@ async function chainLostFromList(request, chainName, state) {
544
558
  return chainMissingFromList(request.destination, chainName, state.chainId, request.databaseId, state.headIndex);
545
559
  }
546
560
 
547
- // src/core/backup/cycle-callbacks.ts
548
- function reportQuietly(callback, value) {
549
- if (!callback) return;
550
- try {
551
- callback(value);
552
- } catch {
553
- }
554
- }
555
-
556
561
  // src/core/backup/cycle-status.ts
557
562
  var BackupCycleStatusRecorder = class {
558
563
  turnRunning = false;
@@ -1,4 +1,4 @@
1
- import { LOG_HEADER_BYTES, readLogHeader, logFrameOffset, readValidLogFrame } from './chunk-DVS4QSIZ.mjs';
1
+ import { LOG_HEADER_BYTES, readLogHeader, logFrameOffset, readValidLogFrame } from './chunk-GYCEJNU4.mjs';
2
2
  import { SirannonError } from './chunk-PBRXXISQ.mjs';
3
3
  import { open } from 'fs/promises';
4
4
 
@@ -1,8 +1,8 @@
1
1
  import { planBackupRestore } from './chunk-YNTDOFTN.mjs';
2
2
  import { listStoredFilePieces, fetchStoredFile, checkpointLog } from './chunk-U445A3C4.mjs';
3
- import { destinationWithDeadline, DEFAULT_DESTINATION_TIMEOUT_MS, LOG_HEADER_BYTES, LOG_FRAME_HEADER_BYTES, readLogHeader, foldLogChecksum, MAGIC_WITH_LITTLE_ENDIAN_CONTENT, LOG_FORMAT_VERSION } from './chunk-DVS4QSIZ.mjs';
3
+ import { destinationWithDeadline, DEFAULT_DESTINATION_TIMEOUT_MS, reportQuietly, LOG_HEADER_BYTES, LOG_FRAME_HEADER_BYTES, readLogHeader, foldLogChecksum, MAGIC_WITH_LITTLE_ENDIAN_CONTENT, LOG_FORMAT_VERSION } from './chunk-GYCEJNU4.mjs';
4
4
  import { readBackupChains, DEFAULT_CHAIN_NAME } from './chunk-YVF2ZJTE.mjs';
5
- import { randomHex } from './chunk-V5FUJEYY.mjs';
5
+ import { randomHex } from './chunk-QBBLSQHQ.mjs';
6
6
  import { SirannonError } from './chunk-PBRXXISQ.mjs';
7
7
  import { rename, open, rm, stat } from 'fs/promises';
8
8
 
@@ -457,7 +457,7 @@ async function restoreBackup(options) {
457
457
  let changesApplied = 0;
458
458
  let framesApplied = 0;
459
459
  const batches = batchesOf(plan.changes, batchSize);
460
- const reportProgress = (phase) => options.onProgress?.({
460
+ const reportProgress = (phase) => reportQuietly(options.onProgress, {
461
461
  phase,
462
462
  piecesFetched,
463
463
  bytesFetched,
@@ -9,6 +9,33 @@ var RemoteError = class extends Error {
9
9
  }
10
10
  };
11
11
 
12
+ // src/core/caller-callbacks.ts
13
+ function isThenable(value) {
14
+ return value != null && typeof value.then === "function";
15
+ }
16
+ function toError(reason) {
17
+ return reason instanceof Error ? reason : new Error(String(reason));
18
+ }
19
+ function reportCallerFailure(onFailure, reason) {
20
+ if (!onFailure) return;
21
+ try {
22
+ onFailure(toError(reason));
23
+ } catch {
24
+ }
25
+ }
26
+ function invokeCallerCallback(callback, onFailure) {
27
+ let returned;
28
+ try {
29
+ returned = callback();
30
+ } catch (err) {
31
+ reportCallerFailure(onFailure, err);
32
+ return;
33
+ }
34
+ if (isThenable(returned)) {
35
+ Promise.resolve(returned).then(void 0, (reason) => reportCallerFailure(onFailure, reason));
36
+ }
37
+ }
38
+
12
39
  // src/client/remote-live-query.ts
13
40
  var RemoteLiveQuery = class _RemoteLiveQuery {
14
41
  state = { status: "pending" };
@@ -16,9 +43,11 @@ var RemoteLiveQuery = class _RemoteLiveQuery {
16
43
  listeners = /* @__PURE__ */ new Set();
17
44
  subscription = null;
18
45
  closed = false;
46
+ onError;
19
47
  /** @internal */
20
- static async open(subscribe) {
48
+ static async open(subscribe, onError) {
21
49
  const query = new _RemoteLiveQuery();
50
+ query.onError = onError;
22
51
  try {
23
52
  query.subscription = await subscribe(query.handlers());
24
53
  } catch (err) {
@@ -104,10 +133,7 @@ var RemoteLiveQuery = class _RemoteLiveQuery {
104
133
  publish(next, update) {
105
134
  this.state = next;
106
135
  for (const listener of [...this.listeners]) {
107
- try {
108
- listener(update);
109
- } catch {
110
- }
136
+ invokeCallerCallback(() => listener(update), this.onError);
111
137
  }
112
138
  }
113
139
  };
@@ -172,10 +198,11 @@ var RemoteDatabase = class {
172
198
  await this.capabilities.assertSqlAccepted();
173
199
  return this.transport.execute(operation, params);
174
200
  }
175
- async live(operation, args) {
201
+ async live(operation, args, options) {
176
202
  const name = typeof operation === "string" ? operation : operation.name;
177
203
  return RemoteLiveQuery.open(
178
- (handlers) => this.transport.liveSubscribe(name, args, handlers, (refresh) => this.capabilities.registryDigest(refresh))
204
+ (handlers) => this.transport.liveSubscribe(name, args, handlers, (refresh) => this.capabilities.registryDigest(refresh)),
205
+ options?.onError
179
206
  );
180
207
  }
181
208
  /**
@@ -855,22 +882,19 @@ function applySubscribedMessage(sub, msg) {
855
882
  }
856
883
  if (msg.resync) {
857
884
  sub.lastSeq = baseline;
858
- try {
859
- sub.onReset?.();
860
- } catch {
861
- }
885
+ invokeCallerCallback(() => sub.onReset?.(), sub.onError);
862
886
  } else if (sub.lastSeq === void 0 && baseline !== void 0) {
863
887
  sub.lastSeq = baseline;
864
888
  }
865
- try {
866
- sub.onSubscribed?.({
889
+ invokeCallerCallback(
890
+ () => sub.onSubscribed?.({
867
891
  seq: baseline,
868
892
  epoch: sub.epoch,
869
893
  resync: msg.resync === true,
870
894
  maxUnacknowledgedChanges: msg.maxUnacknowledgedChanges
871
- });
872
- } catch {
873
- }
895
+ }),
896
+ sub.onError
897
+ );
874
898
  }
875
899
  function deliverChangeMessage(sub, msg) {
876
900
  deliverWireEvent(sub, msg.event);
@@ -882,8 +906,9 @@ function deliverChangesMessage(sub, msg) {
882
906
  }
883
907
  }
884
908
  function deliverWireEvent(sub, wire) {
909
+ let event;
885
910
  try {
886
- const event = {
911
+ event = {
887
912
  type: wire.type,
888
913
  table: wire.table,
889
914
  row: decodeTaggedValues(wire.row),
@@ -896,12 +921,14 @@ function deliverWireEvent(sub, wire) {
896
921
  ...wire.txId !== void 0 ? { txId: wire.txId } : {},
897
922
  ...wire.txEnd === true ? { txEnd: true } : {}
898
923
  };
899
- if (sub.lastSeq === void 0 || event.seq > sub.lastSeq) {
900
- sub.lastSeq = event.seq;
901
- }
902
- sub.callback(event);
903
- } catch {
924
+ } catch (err) {
925
+ reportCallerFailure(sub.onError, err);
926
+ return;
927
+ }
928
+ if (sub.lastSeq === void 0 || event.seq > sub.lastSeq) {
929
+ sub.lastSeq = event.seq;
904
930
  }
931
+ invokeCallerCallback(() => sub.callback(event), sub.onError);
905
932
  }
906
933
  function buildResubscribeMessage(id, sub) {
907
934
  const resumeFrom = sub.resumeSeq === void 0 ? sub.lastSeq : sub.resumeSeq();
@@ -1245,6 +1272,7 @@ var WebSocketTransport = class {
1245
1272
  table,
1246
1273
  filter,
1247
1274
  callback,
1275
+ onError: options?.onError,
1248
1276
  onReset: options?.onReset,
1249
1277
  onSubscribed: options?.onSubscribed,
1250
1278
  deviceId: options?.deviceId,
@@ -1470,4 +1498,4 @@ var DatabaseClient = class {
1470
1498
  }
1471
1499
  };
1472
1500
 
1473
- export { DEFAULT_HTTP_REQUEST_TIMEOUT_MS, DatabaseClient, HttpTransport, RemoteDatabase, RemoteError, RemoteLiveQuery, RemoteSubscriptionBuilderImpl, SQL_REFUSED_MESSAGE, STAGED_STREAM_CAPABILITY, ServerCapabilities, WebSocketTransport, assertWebSocketCredentials, createEndpointTransport, decodeTaggedValues, encodeTaggedValues, postJson, toBaseUrl, toServerBaseUrl, toWsUrl, unrefTimer, verifyDeviceSyncCapabilities };
1501
+ export { DEFAULT_HTTP_REQUEST_TIMEOUT_MS, DatabaseClient, HttpTransport, RemoteDatabase, RemoteError, RemoteLiveQuery, RemoteSubscriptionBuilderImpl, SQL_REFUSED_MESSAGE, STAGED_STREAM_CAPABILITY, ServerCapabilities, WebSocketTransport, assertWebSocketCredentials, createEndpointTransport, decodeTaggedValues, encodeTaggedValues, invokeCallerCallback, postJson, toBaseUrl, toServerBaseUrl, toWsUrl, unrefTimer, verifyDeviceSyncCapabilities };
@@ -1,5 +1,12 @@
1
+ import { invokeCallerCallback } from './chunk-QBBLSQHQ.mjs';
1
2
  import { SirannonError } from './chunk-PBRXXISQ.mjs';
2
3
 
4
+ // src/core/backup/cycle-callbacks.ts
5
+ function reportQuietly(callback, value) {
6
+ if (!callback) return;
7
+ invokeCallerCallback(() => callback(value));
8
+ }
9
+
3
10
  // src/core/backup/destination-deadline.ts
4
11
  var DEFAULT_DESTINATION_TIMEOUT_MS = 6e5;
5
12
  var LONGEST_DEADLINE_MS = 2147483647;
@@ -121,4 +128,4 @@ function logFrameOffset(frameNumber, frameBytes) {
121
128
  return LOG_HEADER_BYTES + (frameNumber - 1) * frameBytes;
122
129
  }
123
130
 
124
- export { DEFAULT_DESTINATION_TIMEOUT_MS, LOG_FORMAT_VERSION, LOG_FRAME_HEADER_BYTES, LOG_HEADER_BYTES, MAGIC_WITH_LITTLE_ENDIAN_CONTENT, assertDeadline, destinationWithDeadline, foldLogChecksum, logFrameOffset, readLogHeader, readValidLogFrame, withinDeadline };
131
+ export { DEFAULT_DESTINATION_TIMEOUT_MS, LOG_FORMAT_VERSION, LOG_FRAME_HEADER_BYTES, LOG_HEADER_BYTES, MAGIC_WITH_LITTLE_ENDIAN_CONTENT, assertDeadline, destinationWithDeadline, foldLogChecksum, logFrameOffset, readLogHeader, readValidLogFrame, reportQuietly, withinDeadline };
@@ -1,7 +1,7 @@
1
1
  import { startCopyWithoutHoldingWriter } from './chunk-W67A4H2E.mjs';
2
- import { readLogPosition } from './chunk-2QCPVE67.mjs';
3
- import { destinationWithDeadline, DEFAULT_DESTINATION_TIMEOUT_MS, assertDeadline, withinDeadline } from './chunk-DVS4QSIZ.mjs';
4
- import { randomHex } from './chunk-V5FUJEYY.mjs';
2
+ import { readLogPosition } from './chunk-E6IMX7RS.mjs';
3
+ import { destinationWithDeadline, DEFAULT_DESTINATION_TIMEOUT_MS, assertDeadline, withinDeadline, reportQuietly } from './chunk-GYCEJNU4.mjs';
4
+ import { randomHex, invokeCallerCallback } from './chunk-QBBLSQHQ.mjs';
5
5
  import { BackupError, SirannonError } from './chunk-PBRXXISQ.mjs';
6
6
  import { existsSync, mkdirSync, statSync, readdirSync, lstatSync, rmSync } from 'fs';
7
7
  import { resolve, dirname, join, basename, extname } from 'path';
@@ -155,6 +155,7 @@ async function copyDatabaseStepwise(conn, options) {
155
155
  const copy = conn.copyDatabase({
156
156
  destPath: options.destPath,
157
157
  pagesPerStep,
158
+ stallTimeoutMs,
158
159
  onStep: (step) => {
159
160
  if (stopped) throw stopped;
160
161
  armStall();
@@ -216,7 +217,7 @@ async function copyToDestinationStaged(conn, request) {
216
217
  const stagedPath = join(stagingRoot, STAGED_FILE_NAME);
217
218
  let firstStepSeen = false;
218
219
  let copyLeftRunning = null;
219
- const emit = (progress) => request.onProgress?.({ runId, ...progress });
220
+ const emit = (progress) => reportQuietly(request.onProgress, { runId, ...progress });
220
221
  try {
221
222
  const pageSize = await readPageSize(conn);
222
223
  const copyStartedAt = Date.now();
@@ -567,7 +568,7 @@ async function copyToDestinationStreamed(conn, request, support) {
567
568
  let remainingPages = 0;
568
569
  let restarts = 0;
569
570
  let pumpFailure = null;
570
- const emit = (progress) => request.onProgress?.({ runId, ...progress });
571
+ const emit = (progress) => reportQuietly(request.onProgress, { runId, ...progress });
571
572
  const pump = async () => {
572
573
  for (; ; ) {
573
574
  const piece = await host.take(streamId);
@@ -1252,10 +1253,7 @@ var BackupScheduler = class {
1252
1253
  let tickState = INITIAL_TICK_STATE;
1253
1254
  const announce = (err) => {
1254
1255
  if (!onError) return;
1255
- try {
1256
- onError(toError(err));
1257
- } catch {
1258
- }
1256
+ invokeCallerCallback(() => onError(toError(err)));
1259
1257
  };
1260
1258
  let source = null;
1261
1259
  const runBackup = async () => {
@@ -1,8 +1,8 @@
1
1
  import { checkpointLog } from './chunk-U445A3C4.mjs';
2
- import { readLogFileHeader, sameLog, cursorChecksum, scanLogFrames, copyLogRange } from './chunk-2QCPVE67.mjs';
3
- import { logFrameOffset } from './chunk-DVS4QSIZ.mjs';
2
+ import { readLogFileHeader, sameLog, cursorChecksum, scanLogFrames, copyLogRange } from './chunk-E6IMX7RS.mjs';
3
+ import { logFrameOffset } from './chunk-GYCEJNU4.mjs';
4
4
  import { isBackupChainPosition } from './chunk-YVF2ZJTE.mjs';
5
- import { randomHex } from './chunk-V5FUJEYY.mjs';
5
+ import { randomHex } from './chunk-QBBLSQHQ.mjs';
6
6
  import { SirannonError } from './chunk-PBRXXISQ.mjs';
7
7
  import { readFile, mkdir, writeFile, rename, rm, readdir } from 'fs/promises';
8
8
  import { dirname, join } from 'path';
@@ -1,7 +1,7 @@
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';
1
+ import { query, execute, executeBatch } from './chunk-MYNI2WFS.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-45MKELYA.mjs';
3
3
  import { ReplicationError, BatchValidationError } from './chunk-2QLXDHAP.mjs';
4
- import { CHANGES_TABLE, decodeTaggedValues } from './chunk-7R4ER4FB.mjs';
4
+ import { CHANGES_TABLE, isReservedIdentifier, decodeTaggedValues } from './chunk-6CMCO7S4.mjs';
5
5
  import { sha256Hex } from './chunk-GVCNMPOS.mjs';
6
6
 
7
7
  // src/core/transaction.ts
@@ -363,7 +363,7 @@ var BatchApplier = class {
363
363
  }
364
364
  for (const change of batch.changes) {
365
365
  if (change.operation !== "ddl") {
366
- if (!IDENTIFIER_RE.test(change.table)) {
366
+ if (!IDENTIFIER_RE.test(change.table) || isReservedIdentifier(change.table)) {
367
367
  throw new BatchValidationError(`Invalid table name: ${change.table}`);
368
368
  }
369
369
  }
@@ -482,7 +482,7 @@ var BatchApplier = class {
482
482
  if (change.operation === "ddl") {
483
483
  throw new BatchValidationError("A staged device transaction cannot carry a DDL change");
484
484
  }
485
- if (!IDENTIFIER_RE.test(change.table)) {
485
+ if (!IDENTIFIER_RE.test(change.table) || isReservedIdentifier(change.table)) {
486
486
  throw new BatchValidationError(`Invalid table name: ${change.table}`);
487
487
  }
488
488
  if (!sawFirst) {
@@ -510,6 +510,9 @@ var BatchApplier = class {
510
510
  });
511
511
  }
512
512
  async applyDataChange(tx, change, resolver, tally) {
513
+ if (isReservedIdentifier(change.table)) {
514
+ throw new BatchValidationError(`Invalid table name: ${change.table}`);
515
+ }
513
516
  const existingRow = await this.rows.findExistingRow(tx, change);
514
517
  if (existingRow === void 0) {
515
518
  if (change.operation === "insert" && change.newData) {
@@ -1,7 +1,7 @@
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';
1
+ import { tableColumnNames, tablePkColumns, selectMinChangeSeqSql, selectMaxChangeSeq, deleteChangesBeforeUpToSeqSql, deleteChangesBeforeSql, selectTableExists, ensureChangesTable, ensureMetaTable, insertMetaValueIfAbsent, selectMetaValue, selectChangesAfterSeqSql, selectTablesChangesInRangeSql } from './chunk-45MKELYA.mjs';
2
+ import { CHANGES_TABLE, isReservedIdentifier, CDC_TRIGGER_PREFIX, encodeTaggedValues, changedAtToEventTimestamp, decodeTaggedValues, SAFE_INT_BOUND_TEXT } from './chunk-6CMCO7S4.mjs';
3
3
  import { synchronousPragmaValue } from './chunk-OUSWVNWT.mjs';
4
- import { randomHex } from './chunk-V5FUJEYY.mjs';
4
+ import { randomHex, invokeCallerCallback, reportCallerFailure, toError } from './chunk-QBBLSQHQ.mjs';
5
5
  import { SirannonError, ForbiddenSqlError, CDCError, MigrationError } from './chunk-PBRXXISQ.mjs';
6
6
 
7
7
  // src/core/bulk-load.ts
@@ -68,7 +68,7 @@ function rowToEvent(row) {
68
68
  row: row.new_data ? decodeTaggedValues(JSON.parse(row.new_data)) : {},
69
69
  oldRow: row.old_data ? decodeTaggedValues(JSON.parse(row.old_data)) : void 0,
70
70
  seq: BigInt(row.seq),
71
- timestamp: row.changed_at,
71
+ timestamp: changedAtToEventTimestamp(row.changed_at),
72
72
  rowId: String(row.row_id),
73
73
  ...row.node_id ? { origin: row.node_id } : {},
74
74
  ...row.hlc ? { hlc: row.hlc } : {},
@@ -568,9 +568,9 @@ var SubscriptionManager = class {
568
568
  subscriptions = /* @__PURE__ */ new Map();
569
569
  byTable = /* @__PURE__ */ new Map();
570
570
  batchEndListeners = /* @__PURE__ */ new Set();
571
- subscribe(table, filter, callback) {
571
+ subscribe(table, filter, callback, options) {
572
572
  const id = this.nextId++;
573
- this.subscriptions.set(id, { id, table, filter, callback });
573
+ this.subscriptions.set(id, { id, table, filter, callback, onError: options?.onError });
574
574
  let tableSet = this.byTable.get(table);
575
575
  if (!tableSet) {
576
576
  tableSet = /* @__PURE__ */ new Set();
@@ -599,13 +599,15 @@ var SubscriptionManager = class {
599
599
  if (!sub) continue;
600
600
  const delivered = sub.filter === void 0 ? event : filteredChange(event, sub.filter);
601
601
  if (delivered === null) continue;
602
- try {
603
- sub.callback(delivered);
604
- } catch {
605
- }
602
+ invokeCallerCallback(() => sub.callback(delivered), sub.onError);
606
603
  }
607
604
  }
608
605
  }
606
+ reportError(error) {
607
+ for (const sub of this.subscriptions.values()) {
608
+ reportCallerFailure(sub.onError, error);
609
+ }
610
+ }
609
611
  addBatchEndListener(listener) {
610
612
  this.batchEndListeners.add(listener);
611
613
  return () => {
@@ -614,10 +616,7 @@ var SubscriptionManager = class {
614
616
  }
615
617
  endBatch(atTxBoundary) {
616
618
  for (const listener of this.batchEndListeners) {
617
- try {
618
- listener(atTxBoundary);
619
- } catch {
620
- }
619
+ invokeCallerCallback(() => listener(atTxBoundary));
621
620
  }
622
621
  }
623
622
  get size() {
@@ -637,8 +636,8 @@ var SubscriptionBuilderImpl = class {
637
636
  this.conditions = { ...this.conditions, ...conditions };
638
637
  return this;
639
638
  }
640
- subscribe(callback) {
641
- return this.manager.subscribe(this.table, this.conditions, callback);
639
+ subscribe(callback, options) {
640
+ return this.manager.subscribe(this.table, this.conditions, callback, options);
642
641
  }
643
642
  };
644
643
  function startPolling(conn, tracker, manager, intervalMs, onError, runExclusive) {
@@ -666,11 +665,13 @@ function startPolling(conn, tracker, manager, intervalMs, onError, runExclusive)
666
665
  }
667
666
  } catch (err) {
668
667
  consecutiveErrors++;
668
+ const failure = toError(err);
669
669
  if (onError) {
670
- onError(err instanceof Error ? err : new Error(String(err)));
670
+ onError(failure);
671
671
  }
672
672
  if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
673
673
  stop();
674
+ manager.reportError(failure);
674
675
  }
675
676
  } finally {
676
677
  polling = false;
@@ -1,6 +1,6 @@
1
1
  // src/core/worker/protocol.ts
2
2
  var WORKER_CANCELLED_CODE = "WRITER_WORKER_CANCELLED";
3
- var WORKER_COPY_ABORTED_CODE = "BACKUP_ABORTED";
3
+ var WORKER_COPY_STOPPED_CODE = "WRITER_WORKER_COPY_STOPPED";
4
4
  function serializeError(err) {
5
5
  if (err instanceof Error) {
6
6
  const code = err.code;
@@ -19,4 +19,4 @@ function deserializeError(error) {
19
19
  return err;
20
20
  }
21
21
 
22
- export { WORKER_CANCELLED_CODE, WORKER_COPY_ABORTED_CODE, deserializeError, serializeError };
22
+ export { WORKER_CANCELLED_CODE, WORKER_COPY_STOPPED_CODE, deserializeError, serializeError };