@delali/sirannon-db 0.3.5 → 0.3.6-next.78

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 (72) hide show
  1. package/dist/backup/index.d.ts +5 -5
  2. package/dist/backup/index.mjs +5 -3
  3. package/dist/backup-scheduler/index.d.ts +2 -2
  4. package/dist/backup-scheduler/index.mjs +2 -2
  5. package/dist/chunk-22TYGH7J.mjs +55 -0
  6. package/dist/{chunk-SB3MIFLG.mjs → chunk-2ZQOZFX7.mjs} +29 -6
  7. package/dist/{chunk-UIDQGPJY.mjs → chunk-4O7WYZHN.mjs} +38 -3
  8. package/dist/{chunk-ZFFUVYYE.mjs → chunk-5DKWHT6K.mjs} +109 -1
  9. package/dist/chunk-5O4J6LQQ.mjs +35 -0
  10. package/dist/{chunk-CZL4D3BM.mjs → chunk-6CABU54O.mjs} +2 -2
  11. package/dist/{chunk-JAQ2I4OT.mjs → chunk-A5ULJVK7.mjs} +11 -11
  12. package/dist/{chunk-RLBKZZ24.mjs → chunk-AC7TKWNH.mjs} +1 -0
  13. package/dist/chunk-BKO4SCEC.mjs +99 -0
  14. package/dist/{chunk-KOTBP4AW.mjs → chunk-C7E4H6UN.mjs} +24 -4
  15. package/dist/{chunk-G4AG3ESO.mjs → chunk-FBA7P4ZA.mjs} +114 -149
  16. package/dist/{chunk-DKML5425.mjs → chunk-GBVB6WSC.mjs} +2 -2
  17. package/dist/chunk-I4JY5QPA.mjs +51 -0
  18. package/dist/{chunk-L6EX6K27.mjs → chunk-MO4APBYG.mjs} +54 -13
  19. package/dist/{chunk-RPWBYASV.mjs → chunk-MTOQ6QIS.mjs} +1 -1
  20. package/dist/chunk-MX77PGEN.mjs +60 -0
  21. package/dist/{chunk-BTUD6XQO.mjs → chunk-N3MHZV3B.mjs} +11 -29
  22. package/dist/{chunk-UHUDPQFI.mjs → chunk-OJXV4L3N.mjs} +1 -3
  23. package/dist/chunk-QF7WF7RJ.mjs +34 -0
  24. package/dist/chunk-RLBV4YTB.mjs +22 -0
  25. package/dist/{chunk-ISDT4RBD.mjs → chunk-ULUZUBON.mjs} +1 -1
  26. package/dist/{chunk-AP4367HK.mjs → chunk-VGRAAQX3.mjs} +4 -4
  27. package/dist/chunk-W74HFQFD.mjs +153 -0
  28. package/dist/chunk-Y4SP7CRF.mjs +9 -0
  29. package/dist/{chunk-JFVEGN7J.mjs → chunk-ZAUHAJ4G.mjs} +2 -1
  30. package/dist/{chunk-DDIHBUEN.mjs → chunk-ZWW53O5P.mjs} +19 -7
  31. package/dist/client/index.d.ts +8 -8
  32. package/dist/client/topology.d.ts +4 -4
  33. package/dist/{client-base-Doaqwrx3.d.ts → client-base-DJZbSY55.d.ts} +2 -2
  34. package/dist/{client-streams-MKPE4MXW.mjs → client-streams-F7IG3PTU.mjs} +13 -16
  35. package/dist/core/index.d.ts +48 -12
  36. package/dist/core/index.mjs +1812 -107
  37. package/dist/core/writer-worker.mjs +28 -4
  38. package/dist/{database-fz-8CJBP.d.ts → database-BZ96ZzAx.d.ts} +411 -184
  39. package/dist/{database-backup-BwTNiBm2.d.ts → database-backup-BhM8yJ1A.d.ts} +32 -2
  40. package/dist/driver/better-sqlite3.d.ts +11 -1
  41. package/dist/driver/better-sqlite3.mjs +212 -23
  42. package/dist/driver/bun.d.ts +1 -1
  43. package/dist/driver/bun.mjs +15 -22
  44. package/dist/driver/expo.d.ts +1 -1
  45. package/dist/driver/expo.mjs +185 -16
  46. package/dist/driver/node.d.ts +1 -1
  47. package/dist/driver/node.mjs +15 -62
  48. package/dist/driver/wa-sqlite.d.ts +1 -1
  49. package/dist/driver/wa-sqlite.mjs +14 -153
  50. package/dist/{change-tracker-Dpo99EI-.d.ts → errors-DLMAGQFb.d.ts} +200 -2
  51. package/dist/file-migrations/index.d.ts +1 -1
  52. package/dist/peer-refusal-RR37UOLV.mjs +1 -0
  53. package/dist/{protocol-DZSYSv0S.d.ts → protocol-DE10taas.d.ts} +1 -1
  54. package/dist/replication/coordinator/etcd.mjs +1 -1
  55. package/dist/replication/index.d.ts +7 -7
  56. package/dist/replication/index.mjs +66 -9
  57. package/dist/{restore-options-CcMukOLO.d.ts → restore-options-B6HV_5XT.d.ts} +6 -1
  58. package/dist/server/index.d.ts +10 -10
  59. package/dist/server/index.mjs +506 -350
  60. package/dist/{server-options-B9CsAZp5.d.ts → server-options-Bhdlvehe.d.ts} +14 -1
  61. package/dist/{server-streams-SBYCHWWM.mjs → server-streams-Q2AZAW3N.mjs} +6 -30
  62. package/dist/{sirannon-D0CjDULa.d.ts → sirannon-Ba1o2HUQ.d.ts} +5 -5
  63. package/dist/transport/grpc.d.ts +15 -4
  64. package/dist/transport/grpc.mjs +34 -37
  65. package/dist/transport/memory.d.ts +4 -3
  66. package/dist/transport/memory.mjs +8 -26
  67. package/dist/{types-DTmi7pXp.d.ts → types-BWyv_N18.d.ts} +189 -1
  68. package/dist/{types-BlZ9GG1a.d.ts → types-CDnlkVRK.d.ts} +8 -2
  69. package/package.json +17 -9
  70. package/dist/chunk-DBN57KVR.mjs +0 -171
  71. package/dist/chunk-W67A4H2E.mjs +0 -23
  72. package/dist/chunk-YW7IKQ7T.mjs +0 -62
@@ -1,20 +1,21 @@
1
1
  import { groupMemberIds, isGroupMember, sameNodeIdSet, compatibilityAllowsPromotion, arraysEqual } from '../chunk-PJRCMG7L.mjs';
2
2
  import { CoordinatorError, TopologyError, WriteConcernError, AuthorityError, SyncError, StalePrimaryError, NodeDrainingError, NodeNotInSyncError, ReadConcernError, ProtocolVersionMismatchError } from '../chunk-KU32OT4H.mjs';
3
3
  export { AuthorityError, CoordinatorError, FailoverError, NoSafePrimaryError, NodeDrainingError, NodeNotInSyncError, ProtocolVersionMismatchError, ReadConcernError, StalePrimaryError, SyncError, TopologyError, TransportError, UnsafeRecoveryRequiredError, WriteConcernError } from '../chunk-KU32OT4H.mjs';
4
- import { LWWResolver, BatchReader, BatchApplier, StampOps, writeOutcome, failedStatementOutcome, StatementRecorder, batchWriteOutcome, isWellFormedHlc, Transaction, loadPersistedHlc } from '../chunk-AP4367HK.mjs';
5
- export { LWWResolver } from '../chunk-AP4367HK.mjs';
6
- import '../chunk-ZFFUVYYE.mjs';
7
- import { runWriterTransaction, execute, withoutRowCounts } from '../chunk-DDIHBUEN.mjs';
8
- import { DumpOps, dumpSchema, tablesInFkOrder } from '../chunk-DKML5425.mjs';
9
- import { canonicaliseForChecksum, HLC, PkResolver, selectMaxChangeHlc, selectMaxColumnVersionHlc, selectMaxAppliedSourceSeq, upsertPeerAckedSeq, selectPeerAckedSeq, selectMaxChangeSeq, selectMaxNodeChangeSeq, selectMinPeerAckedSeq, upsertSyncTableStatus, upsertSyncMeta, selectSyncMetaRow, selectCompletedSyncTableNames, ensureChangesTable, ensureReplicationStateTables, ensureMetaTable, IDENTIFIER_RE, setForeignKeysEnabled, deleteSyncTableStates, extractDroppedTable, insertDdlChange, validateDdlSafety, prepareInsertAppliedChange, selectNewestHistoryChange, upsertQuarantined, deleteStampedChangesUpToSeq, deleteColumnVersions, upsertHistoryBase, deleteAppliedChangesAfterSeq, deletePeerState, upsertAnchoredTerm, selectPrimaryTermStart, selectMaxHistoryChangeSeq, deletePeerStates, upsertPrimaryTermStart, selectHistoryTransaction, selectMaxAppliedSourceSeqByNode, selectAnchoredTerm, selectQuarantined, selectHistoryBase, selectHistoryChangesAfterHlc, deleteHistoryChangesAfterHlc, deleteColumnVersionsAfterHlc, tablePkColumns, deletePrimaryTermStart, selectMaxAssignedChangeSeq } from '../chunk-RPWBYASV.mjs';
10
- export { HLC } from '../chunk-RPWBYASV.mjs';
4
+ import { LWWResolver, BatchReader, BatchApplier, StampOps, writeOutcome, failedStatementOutcome, StatementRecorder, batchWriteOutcome, isWellFormedHlc, Transaction, loadPersistedHlc } from '../chunk-VGRAAQX3.mjs';
5
+ export { LWWResolver } from '../chunk-VGRAAQX3.mjs';
6
+ import { runWriterTransaction, execute, withoutRowCounts } from '../chunk-ZWW53O5P.mjs';
7
+ import { DumpOps, dumpSchema, tablesInFkOrder } from '../chunk-GBVB6WSC.mjs';
8
+ import { canonicaliseForChecksum, HLC, PkResolver, selectMaxChangeHlc, selectMaxColumnVersionHlc, selectMaxAppliedSourceSeq, upsertPeerAckedSeq, selectPeerAckedSeq, selectMaxChangeSeq, selectMaxNodeChangeSeq, selectMinPeerAckedSeq, upsertSyncTableStatus, upsertSyncMeta, selectSyncMetaRow, selectCompletedSyncTableNames, ensureChangesTable, ensureReplicationStateTables, ensureMetaTable, IDENTIFIER_RE, setForeignKeysEnabled, deleteSyncTableStates, extractDroppedTable, insertDdlChange, validateDdlSafety, prepareInsertAppliedChange, selectNewestHistoryChange, upsertQuarantined, deleteStampedChangesUpToSeq, deleteColumnVersions, upsertHistoryBase, deleteAppliedChangesAfterSeq, deletePeerState, upsertAnchoredTerm, selectPrimaryTermStart, selectMaxHistoryChangeSeq, deletePeerStates, upsertPrimaryTermStart, selectHistoryTransaction, selectMaxAppliedSourceSeqByNode, selectAnchoredTerm, selectQuarantined, selectHistoryBase, selectHistoryChangesAfterHlc, deleteHistoryChangesAfterHlc, deleteColumnVersionsAfterHlc, tablePkColumns, deletePrimaryTermStart, selectMaxAssignedChangeSeq } from '../chunk-MTOQ6QIS.mjs';
9
+ export { HLC } from '../chunk-MTOQ6QIS.mjs';
10
+ import '../chunk-5DKWHT6K.mjs';
11
11
  import { ReplicationError, BatchValidationError } from '../chunk-BLMRNSUG.mjs';
12
12
  export { BatchValidationError, ConflictError, ReplicationError } from '../chunk-BLMRNSUG.mjs';
13
- import { CHANGES_TABLE, INTERNAL_TABLE_PREFIX, isReservedIdentifier, decodeTaggedValues } from '../chunk-JFVEGN7J.mjs';
13
+ import { CHANGES_TABLE, INTERNAL_TABLE_PREFIX, isReservedIdentifier, decodeTaggedValues } from '../chunk-ZAUHAJ4G.mjs';
14
14
  import '../chunk-GVCNMPOS.mjs';
15
15
  import '../chunk-K43WJORM.mjs';
16
16
  import { rowCountsOf } from '../chunk-E2GRX4ZD.mjs';
17
17
  import '../chunk-HO2XTXVX.mjs';
18
+ import { EncryptionError } from '../chunk-5O4J6LQQ.mjs';
18
19
  import '../chunk-KINDFBQP.mjs';
19
20
  import { EventEmitter } from 'events';
20
21
  import { randomBytes, randomUUID, createHash } from 'crypto';
@@ -2948,6 +2949,39 @@ var RejoinState = class {
2948
2949
  quarantineRecorded = false;
2949
2950
  };
2950
2951
 
2952
+ // src/replication/engine/encryption-refusal.ts
2953
+ var PLAINTEXT_PEER_MESSAGE = "This node holds an encrypted database, so it sends no batch and no snapshot to a peer that announces a plaintext database";
2954
+ var refusedPeers = /* @__PURE__ */ new WeakMap();
2955
+ function refusedBy(engine) {
2956
+ const existing = refusedPeers.get(engine);
2957
+ if (existing) return existing;
2958
+ const created = /* @__PURE__ */ new Set();
2959
+ refusedPeers.set(engine, created);
2960
+ return created;
2961
+ }
2962
+ function withholdsDataFrom(engine, peer) {
2963
+ return engine.database.encryptedFile && peer?.encrypted !== true;
2964
+ }
2965
+ function encryptionRequired(peerId) {
2966
+ return new EncryptionError(`${PLAINTEXT_PEER_MESSAGE}, and peer '${peerId}' announces one`, "ENCRYPTION_REQUIRED");
2967
+ }
2968
+ function refusePlaintextPeer(engine, peerId) {
2969
+ const refused = refusedBy(engine);
2970
+ const error = encryptionRequired(peerId);
2971
+ const transport = engine.config.transport;
2972
+ if (!refused.has(peerId)) {
2973
+ refused.add(peerId);
2974
+ engine.emitError({ error, operation: "encryption-required", peerId, recoverable: true });
2975
+ }
2976
+ transport.refusePeer?.(peerId, error).catch((err) => {
2977
+ const wrappedErr = err instanceof Error ? err : new Error(String(err));
2978
+ engine.emitError({ error: wrappedErr, operation: "encryption-required", peerId, recoverable: true });
2979
+ });
2980
+ }
2981
+ function forgetPeerRefusal(engine, peerId) {
2982
+ refusedPeers.get(engine)?.delete(peerId);
2983
+ }
2984
+
2951
2985
  // src/replication/engine/sender-loop.ts
2952
2986
  var SenderLoop = class {
2953
2987
  constructor(engine) {
@@ -3009,6 +3043,10 @@ var SenderLoop = class {
3009
3043
  if (!this.shouldReplicateTo(peerId, peerInfo.role)) {
3010
3044
  continue;
3011
3045
  }
3046
+ if (withholdsDataFrom(engine, peerInfo)) {
3047
+ refusePlaintextPeer(engine, peerId);
3048
+ continue;
3049
+ }
3012
3050
  const peerState = engine.peerTracker.getPeerState(peerId);
3013
3051
  if (peerState) {
3014
3052
  engine.peerTracker.expireTimedOutBatches(peerId, nowMs, engine.ackTimeoutMs);
@@ -3240,6 +3278,7 @@ function wireTransportHandlers(engine) {
3240
3278
  }
3241
3279
  });
3242
3280
  engine.config.transport.onPeerDisconnected((peerId) => {
3281
+ forgetPeerRefusal(engine, peerId);
3243
3282
  engine.peerTracker.removePeer(peerId);
3244
3283
  engine.syncServer.abortSessionsForPeer(peerId);
3245
3284
  if (engine.syncState.phase === "syncing" && engine.syncState.sourcePeerId === peerId) {
@@ -3319,8 +3358,10 @@ async function recoverHlcFromDurableState(engine) {
3319
3358
  if (maxObserved === null) return;
3320
3359
  engine.hlc.receive(maxObserved);
3321
3360
  }
3361
+ var databaseRegistrations = /* @__PURE__ */ new WeakMap();
3322
3362
  async function startEngine(engine) {
3323
3363
  if (engine.running) return;
3364
+ databaseRegistrations.set(engine, engine.database.registerReplicationEngine());
3324
3365
  engine.running = true;
3325
3366
  engine.history.active = false;
3326
3367
  await startEngineSteps(engine);
@@ -3341,7 +3382,8 @@ async function startEngineSteps(engine) {
3341
3382
  localRole: engine.config.topology.role,
3342
3383
  groupId: engine.config.coordinator?.groupId ?? engine.config.transportConfig?.groupId,
3343
3384
  primaryTerm: engine.coordinatorState?.primaryTerm ?? engine.config.transportConfig?.primaryTerm,
3344
- protocolVersion: engine.config.coordinator?.compatibility?.protocolVersion ?? engine.config.transportConfig?.protocolVersion
3385
+ protocolVersion: engine.config.coordinator?.compatibility?.protocolVersion ?? engine.config.transportConfig?.protocolVersion,
3386
+ encrypted: engine.database.encryptedFile
3345
3387
  };
3346
3388
  await engine.config.transport.connect(engine.nodeId, transportConfig);
3347
3389
  await refreshMemberAddresses(engine).catch(
@@ -3411,6 +3453,14 @@ async function startEngineSteps(engine) {
3411
3453
  async function stopEngine(engine) {
3412
3454
  if (!engine.running) return;
3413
3455
  engine.running = false;
3456
+ try {
3457
+ await stopEngineSteps(engine);
3458
+ } finally {
3459
+ databaseRegistrations.get(engine)?.();
3460
+ databaseRegistrations.delete(engine);
3461
+ }
3462
+ }
3463
+ async function stopEngineSteps(engine) {
3414
3464
  stopCoordinatorTimers(engine);
3415
3465
  engine.syncJoiner.stopTimers();
3416
3466
  engine.syncServer.abortAll();
@@ -3807,6 +3857,13 @@ var SyncServer = class {
3807
3857
  const engine = this.engine;
3808
3858
  const knownPeers = engine.config.transport.peers();
3809
3859
  if (!knownPeers.has(fromPeerId)) return;
3860
+ if (withholdsDataFrom(engine, knownPeers.get(fromPeerId))) {
3861
+ const refusal = encryptionRequired(fromPeerId);
3862
+ await this.rejectSyncRequest(fromPeerId, request, `${refusal.code}: ${refusal.message}`).finally(
3863
+ () => refusePlaintextPeer(engine, fromPeerId)
3864
+ );
3865
+ return;
3866
+ }
3810
3867
  if (engine.isCoordinatorMode()) {
3811
3868
  try {
3812
3869
  await engine.verifyPrimaryAuthority();
@@ -1,4 +1,4 @@
1
- import { B as BackupDestination, S as SQLiteDriver } from './types-DTmi7pXp.js';
1
+ import { B as BackupDestination, S as SQLiteDriver, E as EncryptionOptions } from './types-BWyv_N18.js';
2
2
 
3
3
  /** The progress of one restore, which Sirannon reports after every piece that it fetches and after every batch.
4
4
  * @public
@@ -50,6 +50,11 @@ interface BackupRestoreOptions {
50
50
  destinationTimeoutMs?: number;
51
51
  /** Called after every piece that Sirannon fetches, and after every batch. */
52
52
  onProgress?: (progress: BackupRestoreProgress) => void;
53
+ /**
54
+ * The key of the database that the restore rebuilds, which the backups of an encrypted database need. Sirannon
55
+ * opens the rebuilt file under this key, so the result holds ciphertext under the same key as the backups.
56
+ */
57
+ encryption?: EncryptionOptions;
53
58
  }
54
59
  /** The report of one finished restore.
55
60
  * @public
@@ -1,13 +1,13 @@
1
- import { h as BackupChain, l as BackupChainRecord, p as BackupCycleStatus, C as BackupVerifyResult } from '../types-DTmi7pXp.js';
2
- import { b as BackupRestoreProgress, a as BackupRestoreReport } from '../restore-options-CcMukOLO.js';
3
- import { a as TransactionStatement, Q as QueryResponse, E as ExecuteResponse, T as TransactionResponse, B as BatchResponse, L as LoadResponse, A as AckResponse } from '../protocol-DZSYSv0S.js';
4
- export { b as BatchRequest, c as ErrorResponse, d as ExecuteRequest, e as LoadRequest, f as QueryRequest, g as TransactionRequest, t as toExecuteResponse } from '../protocol-DZSYSv0S.js';
5
- import { S as Sirannon } from '../sirannon-D0CjDULa.js';
6
- import { B as BulkLoadDurability, S as ServerOptions, W as WSHandlerOptions } from '../server-options-B9CsAZp5.js';
1
+ import { h as BackupChain, l as BackupChainRecord, p as BackupCycleStatus, C as BackupVerifyResult } from '../types-BWyv_N18.js';
2
+ import { b as BackupRestoreProgress, a as BackupRestoreReport } from '../restore-options-B6HV_5XT.js';
3
+ import { a as TransactionStatement, Q as QueryResponse, E as ExecuteResponse, T as TransactionResponse, B as BatchResponse, L as LoadResponse, A as AckResponse } from '../protocol-DE10taas.js';
4
+ export { b as BatchRequest, c as ErrorResponse, d as ExecuteRequest, e as LoadRequest, f as QueryRequest, g as TransactionRequest, t as toExecuteResponse } from '../protocol-DE10taas.js';
5
+ import { S as Sirannon } from '../sirannon-Ba1o2HUQ.js';
6
+ import { B as BulkLoadDurability, S as ServerOptions, W as WSHandlerOptions } from '../server-options-Bhdlvehe.js';
7
7
  import { W as WriteConcern, R as ReadConcern } from '../query-types-5B02ixH0.js';
8
- import '../database-fz-8CJBP.js';
9
- import '../change-tracker-Dpo99EI-.js';
10
- import '../database-backup-BwTNiBm2.js';
8
+ import '../database-BZ96ZzAx.js';
9
+ import '../errors-DLMAGQFb.js';
10
+ import '../database-backup-BhM8yJ1A.js';
11
11
  import '../types-BG31TtrQ.js';
12
12
  import '../types-CEJG0eFS.js';
13
13
  import '../operation-registry-CGhNT-Sn.js';
@@ -495,6 +495,7 @@ declare class SirannonServer<Identity = unknown> {
495
495
  private readonly authenticateHook;
496
496
  private readonly acceptSql;
497
497
  private readonly acceptBackupRestore;
498
+ private readonly encryptionChange;
498
499
  private readonly acceptDeviceSync;
499
500
  private readonly restoreRuns;
500
501
  private readonly drain;
@@ -542,7 +543,6 @@ declare class SirannonServer<Identity = unknown> {
542
543
  get listeningPort(): number;
543
544
  private loadRuntime;
544
545
  private registerRoutes;
545
- private registerBackupRoutes;
546
546
  private withCors;
547
547
  private routeDeps;
548
548
  private wrapDbRoute;