@delali/sirannon-db 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +117 -969
  2. package/dist/backup-scheduler/index.d.ts +1 -1
  3. package/dist/backup-scheduler/index.mjs +2 -2
  4. package/dist/baseline-Br77Fnhb.d.ts +6 -0
  5. package/dist/{change-tracker-CbmaMO-N.d.ts → change-tracker-DKRVUC3l.d.ts} +5 -8
  6. package/dist/{chunk-DJLX6CAE.mjs → chunk-4ISB7XMA.mjs} +2 -1
  7. package/dist/chunk-5NOIGN5Y.mjs +18 -0
  8. package/dist/chunk-67M7KAH6.mjs +90 -0
  9. package/dist/{chunk-GEZUUIKV.mjs → chunk-D7LAYTKN.mjs} +5 -2
  10. package/dist/{chunk-4IGMIJQK.mjs → chunk-EBJXPQQO.mjs} +59 -20
  11. package/dist/{chunk-BNUTBHHH.mjs → chunk-FHWTZFI4.mjs} +1 -1
  12. package/dist/chunk-GVCNMPOS.mjs +130 -0
  13. package/dist/chunk-H237TXZW.mjs +1407 -0
  14. package/dist/{chunk-HHRMRFFR.mjs → chunk-H6PIVVDN.mjs} +353 -142
  15. package/dist/chunk-HR5CWTLC.mjs +661 -0
  16. package/dist/chunk-JU64Y7HM.mjs +299 -0
  17. package/dist/{chunk-CW6S3WL5.mjs → chunk-JZGINXTN.mjs} +7 -5
  18. package/dist/{chunk-CJLYFDP5.mjs → chunk-LFZ37BSX.mjs} +1 -1
  19. package/dist/chunk-LNY2VVHE.mjs +18 -0
  20. package/dist/chunk-NVQS53NT.mjs +665 -0
  21. package/dist/{chunk-H5AB6NIR.mjs → chunk-O7SLN3GI.mjs} +2 -15
  22. package/dist/chunk-OQVZBEBY.mjs +283 -0
  23. package/dist/{chunk-VLTICJOD.mjs → chunk-PIKHN33N.mjs} +1 -1
  24. package/dist/chunk-TJF5GZSV.mjs +187 -0
  25. package/dist/chunk-TUD5CJ76.mjs +126 -0
  26. package/dist/{chunk-YPYVQJ4C.mjs → chunk-UC3SCMIN.mjs} +9 -1
  27. package/dist/client/index.d.ts +216 -321
  28. package/dist/client/index.mjs +1192 -1342
  29. package/dist/client/topology.d.ts +61 -0
  30. package/dist/client/topology.mjs +682 -0
  31. package/dist/client-base-CLWmH5Ln.d.ts +234 -0
  32. package/dist/codegen/cli.d.ts +2 -0
  33. package/dist/codegen/cli.mjs +11 -0
  34. package/dist/codegen/index.d.ts +30 -0
  35. package/dist/codegen/index.mjs +5 -0
  36. package/dist/core/index.d.ts +37 -16
  37. package/dist/core/index.mjs +2322 -298
  38. package/dist/core/writer-worker.mjs +28 -6
  39. package/dist/{database-DuGp0Rtr.d.ts → database-BY0L5Q2n.d.ts} +59 -14
  40. package/dist/driver/better-sqlite3.d.ts +1 -1
  41. package/dist/driver/better-sqlite3.mjs +6 -6
  42. package/dist/driver/node.d.ts +1 -1
  43. package/dist/driver/node.mjs +6 -6
  44. package/dist/driver/wa-sqlite.d.ts +1 -136
  45. package/dist/{errors-5Nf5ZAEC.d.ts → errors-Bw5MdNCu.d.ts} +5 -1
  46. package/dist/file-migrations/index.d.ts +7 -5
  47. package/dist/file-migrations/index.mjs +42 -37
  48. package/dist/operation-registry-9DcvxcE5.d.ts +45 -0
  49. package/dist/primary-wins-DPAm2AKG.d.ts +61 -0
  50. package/dist/protocol-6KrSq2Hy.d.ts +66 -0
  51. package/dist/react/index.d.ts +20 -0
  52. package/dist/react/index.mjs +137 -0
  53. package/dist/replication/coordinator/etcd.d.ts +5 -3
  54. package/dist/replication/coordinator/etcd.mjs +554 -462
  55. package/dist/replication/index.d.ts +51 -105
  56. package/dist/replication/index.mjs +1415 -2061
  57. package/dist/server/index.d.ts +111 -87
  58. package/dist/server/index.mjs +1917 -489
  59. package/dist/server-options-1JHu8pid.d.ts +191 -0
  60. package/dist/{sirannon-4SspRvP5.d.ts → sirannon-DaQSyhbJ.d.ts} +7 -2
  61. package/dist/transport/grpc.d.ts +7 -4
  62. package/dist/transport/grpc.mjs +191 -97
  63. package/dist/transport/memory.d.ts +5 -134
  64. package/dist/transport/memory.mjs +3 -1
  65. package/dist/{types-BsjobKbl.d.ts → types-B7gmEsZW.d.ts} +8 -61
  66. package/dist/{types-BEu1I_9_.d.ts → types-BsVabqSI.d.ts} +1 -1
  67. package/dist/types-CL6piSnD.d.ts +43 -0
  68. package/dist/types-C_D8IhpO.d.ts +60 -0
  69. package/dist/{types-D_hQW1hr.d.ts → types-zhnRXrsb.d.ts} +55 -165
  70. package/package.json +44 -6
  71. package/dist/chunk-TKGHYWQ6.mjs +0 -35
  72. package/dist/types-D4p4UyDK.d.ts +0 -26
@@ -1,7 +1,8 @@
1
- import { TransportError } from '../chunk-H5AB6NIR.mjs';
2
- import '../chunk-YPYVQJ4C.mjs';
3
- import { makeGenericClientConstructor, Metadata, Server, status, ServerCredentials, credentials } from '@grpc/grpc-js';
1
+ import { TransportError } from '../chunk-O7SLN3GI.mjs';
2
+ import '../chunk-5NOIGN5Y.mjs';
3
+ import '../chunk-UC3SCMIN.mjs';
4
4
  import { BinaryWriter, BinaryReader } from '@bufbuild/protobuf/wire';
5
+ import { makeGenericClientConstructor, Server, Metadata, status, ServerCredentials, credentials } from '@grpc/grpc-js';
5
6
  import { readFileSync } from 'fs';
6
7
  import { HealthImplementation } from 'grpc-health-check';
7
8
 
@@ -138,7 +139,8 @@ function toSyncRequestPayload(req) {
138
139
  joinerNodeId: req.joinerNodeId,
139
140
  completedTables: req.completedTables,
140
141
  groupId: req.groupId ?? "",
141
- primaryTerm: req.primaryTerm ?? 0n
142
+ primaryTerm: req.primaryTerm ?? 0n,
143
+ supportsStreamVerification: req.supportsStreamVerification === true
142
144
  };
143
145
  }
144
146
  function fromSyncRequestPayload(p) {
@@ -146,6 +148,7 @@ function fromSyncRequestPayload(p) {
146
148
  requestId: p.requestId,
147
149
  joinerNodeId: p.joinerNodeId,
148
150
  completedTables: p.completedTables,
151
+ supportsStreamVerification: p.supportsStreamVerification === true ? true : void 0,
149
152
  groupId: p.groupId || void 0,
150
153
  primaryTerm: p.primaryTerm === 0n ? void 0 : p.primaryTerm
151
154
  };
@@ -185,7 +188,8 @@ function toSyncCompletePayload(complete) {
185
188
  manifests: complete.manifests.map((m) => ({
186
189
  table: m.table,
187
190
  rowCount: m.rowCount,
188
- pkHash: m.pkHash
191
+ pkHash: m.pkHash ?? "",
192
+ batchDigest: m.batchDigest ?? ""
189
193
  })),
190
194
  groupId: complete.groupId ?? "",
191
195
  primaryTerm: complete.primaryTerm ?? 0n
@@ -199,7 +203,8 @@ function fromSyncCompletePayload(p) {
199
203
  (m) => ({
200
204
  table: m.table,
201
205
  rowCount: m.rowCount,
202
- pkHash: m.pkHash
206
+ pkHash: m.pkHash || void 0,
207
+ batchDigest: m.batchDigest || void 0
203
208
  })
204
209
  ),
205
210
  groupId: p.groupId || void 0,
@@ -272,6 +277,63 @@ function fromForwardRequest(proto) {
272
277
  primaryTerm: proto.primaryTerm === 0n ? void 0 : proto.primaryTerm
273
278
  };
274
279
  }
280
+
281
+ // src/transport/grpc/client-reconnect.ts
282
+ var RECONNECT_MIN_DELAY_MS = 250;
283
+ var RECONNECT_MAX_DELAY_MS = 5e3;
284
+ var stateByTransport = /* @__PURE__ */ new WeakMap();
285
+ function stateFor(transport) {
286
+ const existing = stateByTransport.get(transport);
287
+ if (existing) return existing;
288
+ const created = { timers: /* @__PURE__ */ new Map(), delays: /* @__PURE__ */ new Map(), dialled: /* @__PURE__ */ new Map() };
289
+ stateByTransport.set(transport, created);
290
+ return created;
291
+ }
292
+ function claimEndpoint(transport, endpoint) {
293
+ const state = stateFor(transport);
294
+ if (state.dialled.has(endpoint)) return false;
295
+ state.dialled.set(endpoint, () => void 0);
296
+ return true;
297
+ }
298
+ function registerEndpointAbort(transport, endpoint, abort) {
299
+ const state = stateFor(transport);
300
+ if (!state.dialled.has(endpoint)) return;
301
+ state.dialled.set(endpoint, abort);
302
+ }
303
+ function releaseEndpoint(transport, endpoint) {
304
+ stateFor(transport).dialled.delete(endpoint);
305
+ }
306
+ function noteEndpointReachable(transport, endpoint) {
307
+ stateFor(transport).delays.delete(endpoint);
308
+ }
309
+ function scheduleEndpointRedial(transport, endpoint, redial) {
310
+ if (!transport.connected) return;
311
+ const state = stateFor(transport);
312
+ if (state.timers.has(endpoint)) return;
313
+ const delayMs = state.delays.get(endpoint) ?? RECONNECT_MIN_DELAY_MS;
314
+ state.delays.set(endpoint, Math.min(delayMs * 2, RECONNECT_MAX_DELAY_MS));
315
+ const timer = setTimeout(() => {
316
+ state.timers.delete(endpoint);
317
+ if (!transport.connected) return;
318
+ redial();
319
+ }, delayMs);
320
+ timer.unref?.();
321
+ state.timers.set(endpoint, timer);
322
+ }
323
+ function stopEndpointDialling(transport) {
324
+ const state = stateByTransport.get(transport);
325
+ if (!state) return;
326
+ for (const timer of state.timers.values()) {
327
+ clearTimeout(timer);
328
+ }
329
+ state.timers.clear();
330
+ state.delays.clear();
331
+ const aborts = [...state.dialled.values()];
332
+ state.dialled.clear();
333
+ for (const abort of aborts) {
334
+ abort();
335
+ }
336
+ }
275
337
  function createBaseColumnValue() {
276
338
  return {
277
339
  nullValue: void 0,
@@ -1332,7 +1394,14 @@ var ReplicationMessage = {
1332
1394
  }
1333
1395
  };
1334
1396
  function createBaseSyncRequestPayload() {
1335
- return { requestId: "", joinerNodeId: "", completedTables: [], groupId: "", primaryTerm: 0n };
1397
+ return {
1398
+ requestId: "",
1399
+ joinerNodeId: "",
1400
+ completedTables: [],
1401
+ groupId: "",
1402
+ primaryTerm: 0n,
1403
+ supportsStreamVerification: false
1404
+ };
1336
1405
  }
1337
1406
  var SyncRequestPayload = {
1338
1407
  encode(message, writer = new BinaryWriter()) {
@@ -1354,6 +1423,9 @@ var SyncRequestPayload = {
1354
1423
  }
1355
1424
  writer.uint32(40).int64(message.primaryTerm);
1356
1425
  }
1426
+ if (message.supportsStreamVerification !== false) {
1427
+ writer.uint32(48).bool(message.supportsStreamVerification);
1428
+ }
1357
1429
  return writer;
1358
1430
  },
1359
1431
  decode(input, length) {
@@ -1398,6 +1470,13 @@ var SyncRequestPayload = {
1398
1470
  message.primaryTerm = reader.int64();
1399
1471
  continue;
1400
1472
  }
1473
+ case 6: {
1474
+ if (tag !== 48) {
1475
+ break;
1476
+ }
1477
+ message.supportsStreamVerification = reader.bool();
1478
+ continue;
1479
+ }
1401
1480
  }
1402
1481
  if ((tag & 7) === 4 || tag === 0) {
1403
1482
  break;
@@ -1412,7 +1491,8 @@ var SyncRequestPayload = {
1412
1491
  joinerNodeId: isSet(object.joinerNodeId) ? globalThis.String(object.joinerNodeId) : isSet(object.joiner_node_id) ? globalThis.String(object.joiner_node_id) : "",
1413
1492
  completedTables: globalThis.Array.isArray(object?.completedTables) ? object.completedTables.map((e) => globalThis.String(e)) : globalThis.Array.isArray(object?.completed_tables) ? object.completed_tables.map((e) => globalThis.String(e)) : [],
1414
1493
  groupId: isSet(object.groupId) ? globalThis.String(object.groupId) : isSet(object.group_id) ? globalThis.String(object.group_id) : "",
1415
- primaryTerm: isSet(object.primaryTerm) ? BigInt(object.primaryTerm) : isSet(object.primary_term) ? BigInt(object.primary_term) : 0n
1494
+ primaryTerm: isSet(object.primaryTerm) ? BigInt(object.primaryTerm) : isSet(object.primary_term) ? BigInt(object.primary_term) : 0n,
1495
+ supportsStreamVerification: isSet(object.supportsStreamVerification) ? globalThis.Boolean(object.supportsStreamVerification) : isSet(object.supports_stream_verification) ? globalThis.Boolean(object.supports_stream_verification) : false
1416
1496
  };
1417
1497
  },
1418
1498
  toJSON(message) {
@@ -1432,6 +1512,9 @@ var SyncRequestPayload = {
1432
1512
  if (message.primaryTerm !== 0n) {
1433
1513
  obj.primaryTerm = message.primaryTerm.toString();
1434
1514
  }
1515
+ if (message.supportsStreamVerification !== false) {
1516
+ obj.supportsStreamVerification = message.supportsStreamVerification;
1517
+ }
1435
1518
  return obj;
1436
1519
  },
1437
1520
  create(base) {
@@ -1444,6 +1527,7 @@ var SyncRequestPayload = {
1444
1527
  message.completedTables = object.completedTables?.map((e) => e) || [];
1445
1528
  message.groupId = object.groupId ?? "";
1446
1529
  message.primaryTerm = object.primaryTerm ?? 0n;
1530
+ message.supportsStreamVerification = object.supportsStreamVerification ?? false;
1447
1531
  return message;
1448
1532
  }
1449
1533
  };
@@ -1769,7 +1853,7 @@ var SyncCompletePayload = {
1769
1853
  }
1770
1854
  };
1771
1855
  function createBaseSyncTableManifest() {
1772
- return { table: "", rowCount: 0, pkHash: "" };
1856
+ return { table: "", rowCount: 0, pkHash: "", batchDigest: "" };
1773
1857
  }
1774
1858
  var SyncTableManifest = {
1775
1859
  encode(message, writer = new BinaryWriter()) {
@@ -1782,6 +1866,9 @@ var SyncTableManifest = {
1782
1866
  if (message.pkHash !== "") {
1783
1867
  writer.uint32(26).string(message.pkHash);
1784
1868
  }
1869
+ if (message.batchDigest !== "") {
1870
+ writer.uint32(34).string(message.batchDigest);
1871
+ }
1785
1872
  return writer;
1786
1873
  },
1787
1874
  decode(input, length) {
@@ -1812,6 +1899,13 @@ var SyncTableManifest = {
1812
1899
  message.pkHash = reader.string();
1813
1900
  continue;
1814
1901
  }
1902
+ case 4: {
1903
+ if (tag !== 34) {
1904
+ break;
1905
+ }
1906
+ message.batchDigest = reader.string();
1907
+ continue;
1908
+ }
1815
1909
  }
1816
1910
  if ((tag & 7) === 4 || tag === 0) {
1817
1911
  break;
@@ -1824,7 +1918,8 @@ var SyncTableManifest = {
1824
1918
  return {
1825
1919
  table: isSet(object.table) ? globalThis.String(object.table) : "",
1826
1920
  rowCount: isSet(object.rowCount) ? globalThis.Number(object.rowCount) : isSet(object.row_count) ? globalThis.Number(object.row_count) : 0,
1827
- pkHash: isSet(object.pkHash) ? globalThis.String(object.pkHash) : isSet(object.pk_hash) ? globalThis.String(object.pk_hash) : ""
1921
+ pkHash: isSet(object.pkHash) ? globalThis.String(object.pkHash) : isSet(object.pk_hash) ? globalThis.String(object.pk_hash) : "",
1922
+ batchDigest: isSet(object.batchDigest) ? globalThis.String(object.batchDigest) : isSet(object.batch_digest) ? globalThis.String(object.batch_digest) : ""
1828
1923
  };
1829
1924
  },
1830
1925
  toJSON(message) {
@@ -1838,6 +1933,9 @@ var SyncTableManifest = {
1838
1933
  if (message.pkHash !== "") {
1839
1934
  obj.pkHash = message.pkHash;
1840
1935
  }
1936
+ if (message.batchDigest !== "") {
1937
+ obj.batchDigest = message.batchDigest;
1938
+ }
1841
1939
  return obj;
1842
1940
  },
1843
1941
  create(base) {
@@ -1848,6 +1946,7 @@ var SyncTableManifest = {
1848
1946
  message.table = object.table ?? "";
1849
1947
  message.rowCount = object.rowCount ?? 0;
1850
1948
  message.pkHash = object.pkHash ?? "";
1949
+ message.batchDigest = object.batchDigest ?? "";
1851
1950
  return message;
1852
1951
  }
1853
1952
  };
@@ -2702,7 +2801,15 @@ function removePeer(connectedPeers, serverPeerStreams, peerDisconnectedHandler,
2702
2801
  }
2703
2802
 
2704
2803
  // src/transport/grpc/client-streams.ts
2705
- async function connectToEndpoint(t, endpoint) {
2804
+ function cancelQuietly(stream) {
2805
+ try {
2806
+ stream.cancel();
2807
+ } catch {
2808
+ }
2809
+ }
2810
+ function connectToEndpoint(t, endpoint) {
2811
+ if (!t.connected) return;
2812
+ if (!claimEndpoint(t, endpoint)) return;
2706
2813
  const channelCreds = buildChannelCreds(t.options);
2707
2814
  const clientOpts = {};
2708
2815
  const client = new ReplicationClient(endpoint, channelCreds, clientOpts);
@@ -2713,34 +2820,47 @@ async function connectToEndpoint(t, endpoint) {
2713
2820
  replicateStream,
2714
2821
  syncStream
2715
2822
  };
2716
- replicateStream.write({
2717
- hello: {
2718
- nodeId: t.localNodeId,
2719
- role: t.localRole,
2720
- groupId: t.localGroupId ?? "",
2721
- primaryTerm: t.localPrimaryTerm ?? 0n,
2722
- protocolVersion: t.localProtocolVersion ?? ""
2723
- }
2724
- });
2725
- syncStream.write({
2726
- hello: {
2727
- nodeId: t.localNodeId,
2728
- role: t.localRole,
2729
- groupId: t.localGroupId ?? "",
2730
- primaryTerm: t.localPrimaryTerm ?? 0n,
2731
- protocolVersion: t.localProtocolVersion ?? ""
2732
- }
2733
- });
2734
2823
  let replicatePeerId = null;
2824
+ let syncPeerId = null;
2825
+ let closed = false;
2826
+ const teardown = () => {
2827
+ if (closed) return;
2828
+ closed = true;
2829
+ releaseEndpoint(t, endpoint);
2830
+ const peerId = replicatePeerId ?? syncPeerId;
2831
+ if (peerId !== null && t.clientPeerStreams.get(peerId) === entry) {
2832
+ t.clientPeerStreams.delete(peerId);
2833
+ removePeer(t.connectedPeers, t.serverPeerStreams, t.peerDisconnectedHandler, peerId);
2834
+ }
2835
+ entry.replicateStream = null;
2836
+ entry.syncStream = null;
2837
+ cancelQuietly(replicateStream);
2838
+ cancelQuietly(syncStream);
2839
+ client.close();
2840
+ scheduleEndpointRedial(t, endpoint, () => {
2841
+ connectToEndpoint(t, endpoint);
2842
+ });
2843
+ };
2844
+ registerEndpointAbort(t, endpoint, teardown);
2845
+ const hello = {
2846
+ nodeId: t.localNodeId,
2847
+ role: t.localRole,
2848
+ groupId: t.localGroupId ?? "",
2849
+ primaryTerm: t.localPrimaryTerm ?? 0n,
2850
+ protocolVersion: t.localProtocolVersion ?? ""
2851
+ };
2852
+ replicateStream.write({ hello });
2853
+ syncStream.write({ hello });
2735
2854
  replicateStream.on("data", (msg) => {
2736
2855
  if (replicatePeerId === null) {
2737
2856
  if (!msg.hello) {
2738
- replicateStream.cancel();
2857
+ teardown();
2739
2858
  return;
2740
2859
  }
2741
2860
  replicatePeerId = msg.hello.nodeId;
2742
2861
  const peerRole = msg.hello.role;
2743
2862
  t.clientPeerStreams.set(replicatePeerId, entry);
2863
+ noteEndpointReachable(t, endpoint);
2744
2864
  registerPeer(t.connectedPeers, t.peerConnectedHandler, replicatePeerId, peerRole, {
2745
2865
  groupId: msg.hello.groupId || void 0,
2746
2866
  primaryTerm: msg.hello.primaryTerm === 0n ? void 0 : msg.hello.primaryTerm,
@@ -2755,17 +2875,12 @@ async function connectToEndpoint(t, endpoint) {
2755
2875
  t.ackHandler?.(fromAckPayload(msg.ack), replicatePeerId);
2756
2876
  }
2757
2877
  });
2758
- replicateStream.on("end", () => {
2759
- detachReplicate(t, replicatePeerId);
2760
- });
2761
- replicateStream.on("error", () => {
2762
- detachReplicate(t, replicatePeerId);
2763
- });
2764
- let syncPeerId = null;
2878
+ replicateStream.on("end", teardown);
2879
+ replicateStream.on("error", teardown);
2765
2880
  syncStream.on("data", (msg) => {
2766
2881
  if (syncPeerId === null) {
2767
2882
  if (!msg.hello) {
2768
- syncStream.cancel();
2883
+ teardown();
2769
2884
  return;
2770
2885
  }
2771
2886
  syncPeerId = msg.hello.nodeId;
@@ -2784,32 +2899,42 @@ async function connectToEndpoint(t, endpoint) {
2784
2899
  t.syncAckHandler?.(fromSyncAckPayload(msg.syncAck), syncPeerId);
2785
2900
  }
2786
2901
  });
2787
- syncStream.on("end", () => {
2788
- detachSync(t, syncPeerId);
2789
- });
2790
- syncStream.on("error", () => {
2791
- detachSync(t, syncPeerId);
2792
- });
2902
+ syncStream.on("end", teardown);
2903
+ syncStream.on("error", teardown);
2793
2904
  }
2794
- function detachReplicate(t, peerId) {
2795
- if (!peerId) return;
2796
- const e = t.clientPeerStreams.get(peerId);
2797
- if (!e) return;
2798
- e.replicateStream = null;
2799
- if (!e.syncStream) {
2800
- t.clientPeerStreams.delete(peerId);
2801
- removePeer(t.connectedPeers, t.serverPeerStreams, t.peerDisconnectedHandler, peerId);
2802
- }
2803
- }
2804
- function detachSync(t, peerId) {
2805
- if (!peerId) return;
2806
- const e = t.clientPeerStreams.get(peerId);
2807
- if (!e) return;
2808
- e.syncStream = null;
2809
- if (!e.replicateStream) {
2810
- t.clientPeerStreams.delete(peerId);
2811
- removePeer(t.connectedPeers, t.serverPeerStreams, t.peerDisconnectedHandler, peerId);
2812
- }
2905
+ function forwardOverRpc(entry, request, deadlineMs) {
2906
+ const protoRequest = toForwardRequest(request);
2907
+ const deadline = new Date(Date.now() + deadlineMs);
2908
+ return new Promise((resolve, reject) => {
2909
+ entry.client.forward(
2910
+ protoRequest,
2911
+ new Metadata(),
2912
+ { deadline },
2913
+ (err, response) => {
2914
+ if (err) {
2915
+ reject(new TransportError(`Forward RPC failed: ${err.message}`));
2916
+ return;
2917
+ }
2918
+ if (!response) {
2919
+ reject(new TransportError("Forward RPC returned empty response"));
2920
+ return;
2921
+ }
2922
+ if (response.error) {
2923
+ reject(new TransportError(`Forward RPC error: ${response.error}`));
2924
+ return;
2925
+ }
2926
+ resolve({
2927
+ requestId: response.requestId,
2928
+ results: response.results.map((r) => ({
2929
+ changes: r.changes,
2930
+ lastInsertRowId: Number(r.lastInsertRowId)
2931
+ })),
2932
+ groupId: response.groupId || void 0,
2933
+ primaryTerm: response.primaryTerm === 0n ? void 0 : response.primaryTerm
2934
+ });
2935
+ }
2936
+ );
2937
+ });
2813
2938
  }
2814
2939
 
2815
2940
  // src/transport/grpc/options.ts
@@ -3117,13 +3242,14 @@ var GrpcReplicationTransport = class {
3117
3242
  }
3118
3243
  if (config.endpoints && config.endpoints.length > 0) {
3119
3244
  for (const endpoint of config.endpoints) {
3120
- await connectToEndpoint(this, endpoint);
3245
+ connectToEndpoint(this, endpoint);
3121
3246
  }
3122
3247
  }
3123
3248
  }
3124
3249
  async disconnect() {
3125
3250
  if (!this.connected) return;
3126
3251
  this.connected = false;
3252
+ stopEndpointDialling(this);
3127
3253
  for (const [peerId, entry] of this.clientPeerStreams) {
3128
3254
  entry.replicateStream?.cancel();
3129
3255
  entry.syncStream?.cancel();
@@ -3196,39 +3322,7 @@ var GrpcReplicationTransport = class {
3196
3322
  if (!clientEntry) {
3197
3323
  throw new TransportError(`Peer '${peerId}' is not connected`);
3198
3324
  }
3199
- const protoReq = toForwardRequest(request);
3200
- const deadlineMs = this.options.forwardDeadlineMs ?? DEFAULT_FORWARD_DEADLINE_MS;
3201
- const deadline = new Date(Date.now() + deadlineMs);
3202
- return new Promise((resolve, reject) => {
3203
- clientEntry.client.forward(
3204
- protoReq,
3205
- new Metadata(),
3206
- { deadline },
3207
- (err, response) => {
3208
- if (err) {
3209
- reject(new TransportError(`Forward RPC failed: ${err.message}`));
3210
- return;
3211
- }
3212
- if (!response) {
3213
- reject(new TransportError("Forward RPC returned empty response"));
3214
- return;
3215
- }
3216
- if (response.error) {
3217
- reject(new TransportError(`Forward RPC error: ${response.error}`));
3218
- return;
3219
- }
3220
- resolve({
3221
- requestId: response.requestId,
3222
- results: response.results.map((r) => ({
3223
- changes: r.changes,
3224
- lastInsertRowId: Number(r.lastInsertRowId)
3225
- })),
3226
- groupId: response.groupId || void 0,
3227
- primaryTerm: response.primaryTerm === 0n ? void 0 : response.primaryTerm
3228
- });
3229
- }
3230
- );
3231
- });
3325
+ return forwardOverRpc(clientEntry, request, this.options.forwardDeadlineMs ?? DEFAULT_FORWARD_DEADLINE_MS);
3232
3326
  }
3233
3327
  async requestSync(peerId, request) {
3234
3328
  this.ensureConnected();
@@ -1,137 +1,8 @@
1
- interface NodeInfo {
2
- id: string;
3
- groupId?: string;
4
- role: 'primary' | 'replica';
5
- primaryTerm?: bigint;
6
- protocolVersion?: string;
7
- joinedAt: number;
8
- lastSeenAt: number;
9
- lastAckedSeq: bigint;
10
- metadata?: Record<string, unknown>;
11
- }
12
- interface ReplicationChange {
13
- table: string;
14
- operation: 'insert' | 'update' | 'delete' | 'ddl';
15
- rowId: string;
16
- primaryKey: Record<string, unknown>;
17
- hlc: string;
18
- txId: string;
19
- nodeId: string;
20
- newData: Record<string, unknown> | null;
21
- oldData: Record<string, unknown> | null;
22
- ddlStatement?: string;
23
- }
24
- interface ReplicationBatch {
25
- sourceNodeId: string;
26
- batchId: string;
27
- fromSeq: bigint;
28
- toSeq: bigint;
29
- hlcRange: {
30
- min: string;
31
- max: string;
32
- };
33
- changes: ReplicationChange[];
34
- checksum: string;
35
- groupId?: string;
36
- primaryTerm?: bigint;
37
- }
38
- interface ReplicationAck {
39
- batchId: string;
40
- ackedSeq: bigint;
41
- nodeId: string;
42
- groupId?: string;
43
- primaryTerm?: bigint;
44
- }
45
- interface ForwardedTransaction {
46
- statements: Array<{
47
- sql: string;
48
- params?: Record<string, unknown> | unknown[];
49
- }>;
50
- requestId: string;
51
- groupId?: string;
52
- primaryTerm?: bigint;
53
- }
54
- interface ForwardedTransactionResult {
55
- results: Array<{
56
- changes: number;
57
- lastInsertRowId: number | string;
58
- }>;
59
- requestId: string;
60
- groupId?: string;
61
- primaryTerm?: bigint;
62
- }
63
- type TopologyRole = 'primary' | 'replica';
64
- interface TransportConfig {
65
- endpoints?: string[];
66
- localRole?: TopologyRole;
67
- groupId?: string;
68
- primaryTerm?: bigint;
69
- protocolVersion?: string;
70
- metadata?: Record<string, unknown>;
71
- }
72
- interface ReplicationTransport {
73
- connect(localNodeId: string, config: TransportConfig): Promise<void>;
74
- disconnect(): Promise<void>;
75
- send(peerId: string, batch: ReplicationBatch): Promise<void>;
76
- broadcast(batch: ReplicationBatch): Promise<void>;
77
- sendAck(peerId: string, ack: ReplicationAck): Promise<void>;
78
- forward(peerId: string, request: ForwardedTransaction): Promise<ForwardedTransactionResult>;
79
- requestSync(peerId: string, request: SyncRequest): Promise<void>;
80
- sendSyncBatch(peerId: string, batch: SyncBatch): Promise<void>;
81
- sendSyncComplete(peerId: string, complete: SyncComplete): Promise<void>;
82
- sendSyncAck(peerId: string, ack: SyncAck): Promise<void>;
83
- onBatchReceived(handler: (batch: ReplicationBatch, fromPeerId: string) => Promise<void>): void;
84
- onAckReceived(handler: (ack: ReplicationAck, fromPeerId: string) => void): void;
85
- onForwardReceived(handler: (request: ForwardedTransaction, fromPeerId: string) => Promise<ForwardedTransactionResult>): void;
86
- onSyncRequested(handler: (request: SyncRequest, fromPeerId: string) => Promise<void>): void;
87
- onSyncBatchReceived(handler: (batch: SyncBatch, fromPeerId: string) => Promise<void>): void;
88
- onSyncCompleteReceived(handler: (complete: SyncComplete, fromPeerId: string) => Promise<void>): void;
89
- onSyncAckReceived(handler: (ack: SyncAck, fromPeerId: string) => void): void;
90
- onPeerConnected(handler: (peer: NodeInfo) => void): void;
91
- onPeerDisconnected(handler: (peerId: string) => void): void;
92
- peers(): ReadonlyMap<string, NodeInfo>;
93
- }
94
- interface SyncRequest {
95
- requestId: string;
96
- joinerNodeId: string;
97
- completedTables: string[];
98
- groupId?: string;
99
- primaryTerm?: bigint;
100
- }
101
- interface SyncBatch {
102
- requestId: string;
103
- table: string;
104
- batchIndex: number;
105
- rows: Record<string, unknown>[];
106
- schema?: string[];
107
- checksum: string;
108
- isLastBatchForTable: boolean;
109
- totalTables?: number;
110
- groupId?: string;
111
- primaryTerm?: bigint;
112
- }
113
- interface SyncTableManifest {
114
- table: string;
115
- rowCount: number;
116
- pkHash: string;
117
- }
118
- interface SyncComplete {
119
- requestId: string;
120
- snapshotSeq: bigint;
121
- manifests: SyncTableManifest[];
122
- groupId?: string;
123
- primaryTerm?: bigint;
124
- }
125
- interface SyncAck {
126
- requestId: string;
127
- joinerNodeId: string;
128
- table: string;
129
- batchIndex: number;
130
- success: boolean;
131
- error?: string;
132
- groupId?: string;
133
- primaryTerm?: bigint;
134
- }
1
+ import { N as NodeInfo, R as ReplicationAck, F as ForwardedTransaction, a as ForwardedTransactionResult, S as SyncRequest, b as SyncBatch, c as SyncComplete, d as SyncAck, e as ReplicationTransport, T as TransportConfig } from '../types-B7gmEsZW.js';
2
+ import { R as ReplicationBatch } from '../types-C_D8IhpO.js';
3
+ import '../change-tracker-DKRVUC3l.js';
4
+ import '../types-zhnRXrsb.js';
5
+ import '../types-BsVabqSI.js';
135
6
 
136
7
  type BatchHandler = (batch: ReplicationBatch, fromPeerId: string) => Promise<void>;
137
8
  type AckHandler = (ack: ReplicationAck, fromPeerId: string) => void;
@@ -27,7 +27,7 @@ var SirannonError = class extends Error {
27
27
  }
28
28
  };
29
29
 
30
- // src/replication/errors.ts
30
+ // src/core/sync/errors.ts
31
31
  var ReplicationError = class extends SirannonError {
32
32
  constructor(message, code = "REPLICATION_ERROR", details) {
33
33
  super(message, code);
@@ -35,6 +35,8 @@ var ReplicationError = class extends SirannonError {
35
35
  this.name = "ReplicationError";
36
36
  }
37
37
  };
38
+
39
+ // src/replication/errors.ts
38
40
  var TransportError = class extends ReplicationError {
39
41
  constructor(message) {
40
42
  super(message, "TRANSPORT_ERROR");