@delali/sirannon-db 0.1.3 → 0.1.5

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 (51) hide show
  1. package/README.md +655 -80
  2. package/dist/backup-scheduler/index.d.ts +3 -0
  3. package/dist/backup-scheduler/index.mjs +2 -0
  4. package/dist/change-tracker-CFTQ9TSn.d.ts +89 -0
  5. package/dist/chunk-3MCMONVP.mjs +115 -0
  6. package/dist/chunk-74UN4DIE.mjs +14 -0
  7. package/dist/chunk-ER7ODTDA.mjs +23 -0
  8. package/dist/chunk-FB2U2Q3Y.mjs +21 -0
  9. package/dist/chunk-GS7T5YMI.mjs +51 -0
  10. package/dist/chunk-O7BHI3CF.mjs +90 -0
  11. package/dist/chunk-PXKAKK2V.mjs +124 -0
  12. package/dist/chunk-UTO3ZAFS.mjs +514 -0
  13. package/dist/chunk-UVMVN3OT.mjs +111 -0
  14. package/dist/client/index.d.ts +137 -44
  15. package/dist/client/index.mjs +726 -26
  16. package/dist/core/index.d.ts +32 -241
  17. package/dist/core/index.mjs +294 -568
  18. package/dist/database-BVY1GqE7.d.ts +95 -0
  19. package/dist/driver/better-sqlite3.d.ts +8 -0
  20. package/dist/driver/better-sqlite3.mjs +63 -0
  21. package/dist/driver/bun.mjs +61 -0
  22. package/dist/driver/expo.mjs +55 -0
  23. package/dist/driver/node.d.ts +8 -0
  24. package/dist/driver/node.mjs +60 -0
  25. package/dist/driver/wa-sqlite.d.ts +34 -0
  26. package/dist/driver/wa-sqlite.mjs +141 -0
  27. package/dist/errors-C00ed08Q.d.ts +101 -0
  28. package/dist/file-migrations/index.d.ts +16 -0
  29. package/dist/file-migrations/index.mjs +128 -0
  30. package/dist/index-CLdNrcPz.d.ts +16 -0
  31. package/dist/replication/coordinator/etcd.d.ts +44 -0
  32. package/dist/replication/coordinator/etcd.mjs +650 -0
  33. package/dist/replication/index.d.ts +491 -0
  34. package/dist/replication/index.mjs +3784 -0
  35. package/dist/server/index.d.ts +121 -54
  36. package/dist/server/index.mjs +347 -114
  37. package/dist/sirannon-Cd-lK6T0.d.ts +31 -0
  38. package/dist/transport/grpc.d.ts +316 -0
  39. package/dist/transport/grpc.mjs +3341 -0
  40. package/dist/transport/memory.d.ts +221 -0
  41. package/dist/transport/memory.mjs +337 -0
  42. package/dist/types-B2byqt0B.d.ts +273 -0
  43. package/dist/types-BEu1I_9_.d.ts +139 -0
  44. package/dist/types-BFSsG77t.d.ts +29 -0
  45. package/dist/types-BeozgNPr.d.ts +26 -0
  46. package/dist/{types-DArCObcu.d.ts → types-D-74JiXb.d.ts} +80 -1
  47. package/dist/vfs-INWQ5DTE.mjs +2 -0
  48. package/package.json +106 -11
  49. package/dist/chunk-VI4UP4RR.mjs +0 -417
  50. package/dist/protocol-BX1H-_Mz.d.ts +0 -104
  51. package/dist/sirannon-BJ8Yd1Uf.d.ts +0 -148
@@ -0,0 +1,221 @@
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
+ groupId?: string;
110
+ primaryTerm?: bigint;
111
+ }
112
+ interface SyncTableManifest {
113
+ table: string;
114
+ rowCount: number;
115
+ pkHash: string;
116
+ }
117
+ interface SyncComplete {
118
+ requestId: string;
119
+ snapshotSeq: bigint;
120
+ manifests: SyncTableManifest[];
121
+ groupId?: string;
122
+ primaryTerm?: bigint;
123
+ }
124
+ interface SyncAck {
125
+ requestId: string;
126
+ joinerNodeId: string;
127
+ table: string;
128
+ batchIndex: number;
129
+ success: boolean;
130
+ error?: string;
131
+ groupId?: string;
132
+ primaryTerm?: bigint;
133
+ }
134
+
135
+ type BatchHandler = (batch: ReplicationBatch, fromPeerId: string) => Promise<void>;
136
+ type AckHandler = (ack: ReplicationAck, fromPeerId: string) => void;
137
+ type ForwardHandler = (request: ForwardedTransaction, fromPeerId: string) => Promise<ForwardedTransactionResult>;
138
+ type PeerConnectedHandler = (peer: NodeInfo) => void;
139
+ type PeerDisconnectedHandler = (peerId: string) => void;
140
+ type SyncRequestHandler = (request: SyncRequest, fromPeerId: string) => Promise<void>;
141
+ type SyncBatchHandler = (batch: SyncBatch, fromPeerId: string) => Promise<void>;
142
+ type SyncCompleteHandler = (complete: SyncComplete, fromPeerId: string) => Promise<void>;
143
+ type SyncAckHandler = (ack: SyncAck, fromPeerId: string) => void;
144
+
145
+ /**
146
+ * In-process ReplicationTransport for testing and single-process multi-node
147
+ * scenarios.
148
+ *
149
+ * Messages between peers are delivered through a shared MemoryBus via
150
+ * microtask scheduling (`queueMicrotask`), preserving the async delivery
151
+ * semantics of a real network transport while avoiding actual I/O. All
152
+ * message types (batches, acks, forwards) go through runtime
153
+ * validation before delivery, and malformed payloads are silently dropped
154
+ * to match the behavior of a lossy network.
155
+ */
156
+ declare class InMemoryTransport implements ReplicationTransport {
157
+ private localNodeId;
158
+ private localRole;
159
+ private localGroupId;
160
+ private localPrimaryTerm;
161
+ private localProtocolVersion;
162
+ connected: boolean;
163
+ private readonly bus;
164
+ readonly connectedPeers: Map<string, NodeInfo>;
165
+ private batchHandler;
166
+ private ackHandler;
167
+ private forwardHandler;
168
+ peerConnectedHandler: PeerConnectedHandler | null;
169
+ peerDisconnectedHandler: PeerDisconnectedHandler | null;
170
+ private syncRequestHandler;
171
+ private syncBatchHandler;
172
+ private syncCompleteHandler;
173
+ private syncAckHandler;
174
+ constructor(bus: MemoryBus);
175
+ get role(): 'primary' | 'replica';
176
+ connect(localNodeId: string, config: TransportConfig): Promise<void>;
177
+ disconnect(): Promise<void>;
178
+ send(peerId: string, batch: ReplicationBatch): Promise<void>;
179
+ broadcast(batch: ReplicationBatch): Promise<void>;
180
+ sendAck(peerId: string, ack: ReplicationAck): Promise<void>;
181
+ forward(peerId: string, request: ForwardedTransaction): Promise<ForwardedTransactionResult>;
182
+ requestSync(peerId: string, request: SyncRequest): Promise<void>;
183
+ sendSyncBatch(peerId: string, batch: SyncBatch): Promise<void>;
184
+ sendSyncComplete(peerId: string, complete: SyncComplete): Promise<void>;
185
+ sendSyncAck(peerId: string, ack: SyncAck): Promise<void>;
186
+ onBatchReceived(handler: BatchHandler): void;
187
+ onAckReceived(handler: AckHandler): void;
188
+ onForwardReceived(handler: ForwardHandler): void;
189
+ onSyncRequested(handler: SyncRequestHandler): void;
190
+ onSyncBatchReceived(handler: SyncBatchHandler): void;
191
+ onSyncCompleteReceived(handler: SyncCompleteHandler): void;
192
+ onSyncAckReceived(handler: SyncAckHandler): void;
193
+ onPeerConnected(handler: PeerConnectedHandler): void;
194
+ onPeerDisconnected(handler: PeerDisconnectedHandler): void;
195
+ peers(): ReadonlyMap<string, NodeInfo>;
196
+ _receiveBatch(batch: ReplicationBatch, fromPeerId: string): Promise<void>;
197
+ _receiveAck(ack: ReplicationAck, fromPeerId: string): void;
198
+ _receiveForward(request: ForwardedTransaction, fromPeerId: string): Promise<ForwardedTransactionResult>;
199
+ _receiveSyncRequest(request: SyncRequest, fromPeerId: string): Promise<void>;
200
+ _receiveSyncBatch(batch: SyncBatch, fromPeerId: string): Promise<void>;
201
+ _receiveSyncComplete(complete: SyncComplete, fromPeerId: string): Promise<void>;
202
+ _receiveSyncAck(ack: SyncAck, fromPeerId: string): void;
203
+ private ensureConnected;
204
+ }
205
+
206
+ /**
207
+ * Shared message bus that connects InMemoryTransport instances within the
208
+ * same process. Each transport registers itself on `connect()` and messages
209
+ * are delivered via direct method calls on the target transport through
210
+ * microtask scheduling, simulating async network delivery without actual I/O.
211
+ */
212
+ declare class MemoryBus {
213
+ private readonly transports;
214
+ join(peerId: string, transport: InMemoryTransport): void;
215
+ leave(peerId: string): void;
216
+ getTransport(peerId: string): InMemoryTransport | undefined;
217
+ peerIds(): IterableIterator<string>;
218
+ get size(): number;
219
+ }
220
+
221
+ export { InMemoryTransport, MemoryBus };
@@ -0,0 +1,337 @@
1
+ // src/transport/memory/bus.ts
2
+ var MemoryBus = class {
3
+ transports = /* @__PURE__ */ new Map();
4
+ join(peerId, transport) {
5
+ this.transports.set(peerId, transport);
6
+ }
7
+ leave(peerId) {
8
+ this.transports.delete(peerId);
9
+ }
10
+ getTransport(peerId) {
11
+ return this.transports.get(peerId);
12
+ }
13
+ peerIds() {
14
+ return this.transports.keys();
15
+ }
16
+ get size() {
17
+ return this.transports.size;
18
+ }
19
+ };
20
+
21
+ // src/core/errors.ts
22
+ var SirannonError = class extends Error {
23
+ constructor(message, code) {
24
+ super(message);
25
+ this.code = code;
26
+ this.name = "SirannonError";
27
+ }
28
+ };
29
+
30
+ // src/replication/errors.ts
31
+ var ReplicationError = class extends SirannonError {
32
+ constructor(message, code = "REPLICATION_ERROR", details) {
33
+ super(message, code);
34
+ this.details = details;
35
+ this.name = "ReplicationError";
36
+ }
37
+ };
38
+ var TransportError = class extends ReplicationError {
39
+ constructor(message) {
40
+ super(message, "TRANSPORT_ERROR");
41
+ this.name = "TransportError";
42
+ }
43
+ };
44
+
45
+ // src/transport/validators.ts
46
+ function isValidBatch(batch) {
47
+ if (typeof batch !== "object" || batch === null) return false;
48
+ const b = batch;
49
+ return typeof b.sourceNodeId === "string" && typeof b.batchId === "string" && typeof b.fromSeq === "bigint" && typeof b.toSeq === "bigint" && typeof b.checksum === "string" && Array.isArray(b.changes) && typeof b.hlcRange === "object" && b.hlcRange !== null && optionalString(b.groupId) && optionalBigint(b.primaryTerm);
50
+ }
51
+ function isValidAck(ack) {
52
+ if (typeof ack !== "object" || ack === null) return false;
53
+ const a = ack;
54
+ return typeof a.batchId === "string" && typeof a.ackedSeq === "bigint" && typeof a.nodeId === "string" && optionalString(a.groupId) && optionalBigint(a.primaryTerm);
55
+ }
56
+ function isValidForwardedTransaction(req) {
57
+ if (typeof req !== "object" || req === null) return false;
58
+ const r = req;
59
+ return typeof r.requestId === "string" && Array.isArray(r.statements) && optionalString(r.groupId) && optionalBigint(r.primaryTerm);
60
+ }
61
+ function isValidSyncRequest(req) {
62
+ if (typeof req !== "object" || req === null) return false;
63
+ const r = req;
64
+ return typeof r.requestId === "string" && typeof r.joinerNodeId === "string" && Array.isArray(r.completedTables) && optionalString(r.groupId) && optionalBigint(r.primaryTerm);
65
+ }
66
+ function isValidSyncBatch(batch) {
67
+ if (typeof batch !== "object" || batch === null) return false;
68
+ const b = batch;
69
+ return typeof b.requestId === "string" && typeof b.table === "string" && typeof b.batchIndex === "number" && Array.isArray(b.rows) && typeof b.checksum === "string" && typeof b.isLastBatchForTable === "boolean" && optionalString(b.groupId) && optionalBigint(b.primaryTerm);
70
+ }
71
+ function isValidSyncComplete(complete) {
72
+ if (typeof complete !== "object" || complete === null) return false;
73
+ const c = complete;
74
+ return typeof c.requestId === "string" && typeof c.snapshotSeq === "bigint" && Array.isArray(c.manifests) && optionalString(c.groupId) && optionalBigint(c.primaryTerm);
75
+ }
76
+ function isValidSyncAck(ack) {
77
+ if (typeof ack !== "object" || ack === null) return false;
78
+ const a = ack;
79
+ return typeof a.requestId === "string" && typeof a.joinerNodeId === "string" && typeof a.table === "string" && typeof a.batchIndex === "number" && typeof a.success === "boolean" && optionalString(a.groupId) && optionalBigint(a.primaryTerm);
80
+ }
81
+ function optionalString(value) {
82
+ return value === void 0 || typeof value === "string";
83
+ }
84
+ function optionalBigint(value) {
85
+ return value === void 0 || typeof value === "bigint";
86
+ }
87
+
88
+ // src/transport/memory/transport.ts
89
+ var InMemoryTransport = class {
90
+ localNodeId = "";
91
+ localRole = "replica";
92
+ localGroupId;
93
+ localPrimaryTerm;
94
+ localProtocolVersion;
95
+ connected = false;
96
+ bus;
97
+ connectedPeers = /* @__PURE__ */ new Map();
98
+ batchHandler = null;
99
+ ackHandler = null;
100
+ forwardHandler = null;
101
+ peerConnectedHandler = null;
102
+ peerDisconnectedHandler = null;
103
+ syncRequestHandler = null;
104
+ syncBatchHandler = null;
105
+ syncCompleteHandler = null;
106
+ syncAckHandler = null;
107
+ constructor(bus) {
108
+ this.bus = bus;
109
+ }
110
+ get role() {
111
+ return this.localRole;
112
+ }
113
+ async connect(localNodeId, config) {
114
+ if (this.connected) {
115
+ throw new TransportError("Transport is already connected");
116
+ }
117
+ this.localNodeId = localNodeId;
118
+ this.localRole = config.localRole ?? "replica";
119
+ this.localGroupId = config.groupId;
120
+ this.localPrimaryTerm = config.primaryTerm;
121
+ this.localProtocolVersion = config.protocolVersion;
122
+ this.connected = true;
123
+ this.bus.join(localNodeId, this);
124
+ for (const peerId of this.bus.peerIds()) {
125
+ if (peerId === localNodeId) continue;
126
+ const peerTransport = this.bus.getTransport(peerId);
127
+ if (!peerTransport || !peerTransport.connected) continue;
128
+ const peerInfo = {
129
+ id: peerId,
130
+ groupId: peerTransport.localGroupId,
131
+ role: peerTransport.role,
132
+ primaryTerm: peerTransport.localPrimaryTerm,
133
+ protocolVersion: peerTransport.localProtocolVersion,
134
+ joinedAt: Date.now(),
135
+ lastSeenAt: Date.now(),
136
+ lastAckedSeq: 0n
137
+ };
138
+ this.connectedPeers.set(peerId, peerInfo);
139
+ const localInfo = {
140
+ id: localNodeId,
141
+ groupId: this.localGroupId,
142
+ role: this.localRole,
143
+ primaryTerm: this.localPrimaryTerm,
144
+ protocolVersion: this.localProtocolVersion,
145
+ joinedAt: Date.now(),
146
+ lastSeenAt: Date.now(),
147
+ lastAckedSeq: 0n
148
+ };
149
+ peerTransport.connectedPeers.set(localNodeId, localInfo);
150
+ if (this.peerConnectedHandler) {
151
+ this.peerConnectedHandler(peerInfo);
152
+ }
153
+ if (peerTransport.peerConnectedHandler) {
154
+ peerTransport.peerConnectedHandler(localInfo);
155
+ }
156
+ }
157
+ }
158
+ async disconnect() {
159
+ if (!this.connected) return;
160
+ this.connected = false;
161
+ this.bus.leave(this.localNodeId);
162
+ for (const [peerId] of this.connectedPeers) {
163
+ const peerTransport = this.bus.getTransport(peerId);
164
+ if (peerTransport) {
165
+ peerTransport.connectedPeers.delete(this.localNodeId);
166
+ if (peerTransport.peerDisconnectedHandler) {
167
+ peerTransport.peerDisconnectedHandler(this.localNodeId);
168
+ }
169
+ }
170
+ }
171
+ this.connectedPeers.clear();
172
+ }
173
+ async send(peerId, batch) {
174
+ this.ensureConnected();
175
+ if (!isValidBatch(batch)) {
176
+ throw new TransportError("Invalid batch structure");
177
+ }
178
+ const peer = this.bus.getTransport(peerId);
179
+ if (!peer || !peer.connected) {
180
+ throw new TransportError(`Peer '${peerId}' is not connected`);
181
+ }
182
+ const fromPeerId = this.localNodeId;
183
+ queueMicrotask(() => {
184
+ peer._receiveBatch(batch, fromPeerId).catch(() => {
185
+ });
186
+ });
187
+ }
188
+ async broadcast(batch) {
189
+ this.ensureConnected();
190
+ if (!isValidBatch(batch)) {
191
+ throw new TransportError("Invalid batch structure");
192
+ }
193
+ const fromPeerId = this.localNodeId;
194
+ for (const [peerId] of this.connectedPeers) {
195
+ const peer = this.bus.getTransport(peerId);
196
+ if (peer?.connected) {
197
+ queueMicrotask(() => {
198
+ peer._receiveBatch(batch, fromPeerId).catch(() => {
199
+ });
200
+ });
201
+ }
202
+ }
203
+ }
204
+ async sendAck(peerId, ack) {
205
+ this.ensureConnected();
206
+ if (!isValidAck(ack)) {
207
+ throw new TransportError("Invalid ack structure");
208
+ }
209
+ const peer = this.bus.getTransport(peerId);
210
+ if (!peer || !peer.connected) {
211
+ throw new TransportError(`Peer '${peerId}' is not connected`);
212
+ }
213
+ const fromPeerId = this.localNodeId;
214
+ queueMicrotask(() => {
215
+ peer._receiveAck(ack, fromPeerId);
216
+ });
217
+ }
218
+ async forward(peerId, request) {
219
+ this.ensureConnected();
220
+ if (!isValidForwardedTransaction(request)) {
221
+ throw new TransportError("Invalid forward request structure");
222
+ }
223
+ const peer = this.bus.getTransport(peerId);
224
+ if (!peer || !peer.connected) {
225
+ throw new TransportError(`Peer '${peerId}' is not connected`);
226
+ }
227
+ return peer._receiveForward(request, this.localNodeId);
228
+ }
229
+ async requestSync(peerId, request) {
230
+ this.ensureConnected();
231
+ if (!isValidSyncRequest(request)) throw new TransportError("Invalid sync request structure");
232
+ const peer = this.bus.getTransport(peerId);
233
+ if (!peer || !peer.connected) throw new TransportError(`Peer '${peerId}' is not connected`);
234
+ const fromPeerId = this.localNodeId;
235
+ queueMicrotask(() => {
236
+ peer._receiveSyncRequest(request, fromPeerId).catch(() => {
237
+ });
238
+ });
239
+ }
240
+ async sendSyncBatch(peerId, batch) {
241
+ this.ensureConnected();
242
+ if (!isValidSyncBatch(batch)) throw new TransportError("Invalid sync batch structure");
243
+ const peer = this.bus.getTransport(peerId);
244
+ if (!peer || !peer.connected) throw new TransportError(`Peer '${peerId}' is not connected`);
245
+ const fromPeerId = this.localNodeId;
246
+ queueMicrotask(() => {
247
+ peer._receiveSyncBatch(batch, fromPeerId).catch(() => {
248
+ });
249
+ });
250
+ }
251
+ async sendSyncComplete(peerId, complete) {
252
+ this.ensureConnected();
253
+ if (!isValidSyncComplete(complete)) throw new TransportError("Invalid sync complete structure");
254
+ const peer = this.bus.getTransport(peerId);
255
+ if (!peer || !peer.connected) throw new TransportError(`Peer '${peerId}' is not connected`);
256
+ const fromPeerId = this.localNodeId;
257
+ queueMicrotask(() => {
258
+ peer._receiveSyncComplete(complete, fromPeerId).catch(() => {
259
+ });
260
+ });
261
+ }
262
+ async sendSyncAck(peerId, ack) {
263
+ this.ensureConnected();
264
+ if (!isValidSyncAck(ack)) throw new TransportError("Invalid sync ack structure");
265
+ const peer = this.bus.getTransport(peerId);
266
+ if (!peer || !peer.connected) throw new TransportError(`Peer '${peerId}' is not connected`);
267
+ const fromPeerId = this.localNodeId;
268
+ queueMicrotask(() => {
269
+ peer._receiveSyncAck(ack, fromPeerId);
270
+ });
271
+ }
272
+ onBatchReceived(handler) {
273
+ this.batchHandler = handler;
274
+ }
275
+ onAckReceived(handler) {
276
+ this.ackHandler = handler;
277
+ }
278
+ onForwardReceived(handler) {
279
+ this.forwardHandler = handler;
280
+ }
281
+ onSyncRequested(handler) {
282
+ this.syncRequestHandler = handler;
283
+ }
284
+ onSyncBatchReceived(handler) {
285
+ this.syncBatchHandler = handler;
286
+ }
287
+ onSyncCompleteReceived(handler) {
288
+ this.syncCompleteHandler = handler;
289
+ }
290
+ onSyncAckReceived(handler) {
291
+ this.syncAckHandler = handler;
292
+ }
293
+ onPeerConnected(handler) {
294
+ this.peerConnectedHandler = handler;
295
+ }
296
+ onPeerDisconnected(handler) {
297
+ this.peerDisconnectedHandler = handler;
298
+ }
299
+ peers() {
300
+ return this.connectedPeers;
301
+ }
302
+ async _receiveBatch(batch, fromPeerId) {
303
+ if (this.batchHandler) {
304
+ await this.batchHandler(batch, fromPeerId);
305
+ }
306
+ }
307
+ _receiveAck(ack, fromPeerId) {
308
+ if (this.ackHandler) {
309
+ this.ackHandler(ack, fromPeerId);
310
+ }
311
+ }
312
+ async _receiveForward(request, fromPeerId) {
313
+ if (!this.forwardHandler) {
314
+ throw new TransportError("No forward handler registered");
315
+ }
316
+ return this.forwardHandler(request, fromPeerId);
317
+ }
318
+ async _receiveSyncRequest(request, fromPeerId) {
319
+ if (this.syncRequestHandler) await this.syncRequestHandler(request, fromPeerId);
320
+ }
321
+ async _receiveSyncBatch(batch, fromPeerId) {
322
+ if (this.syncBatchHandler) await this.syncBatchHandler(batch, fromPeerId);
323
+ }
324
+ async _receiveSyncComplete(complete, fromPeerId) {
325
+ if (this.syncCompleteHandler) await this.syncCompleteHandler(complete, fromPeerId);
326
+ }
327
+ _receiveSyncAck(ack, fromPeerId) {
328
+ if (this.syncAckHandler) this.syncAckHandler(ack, fromPeerId);
329
+ }
330
+ ensureConnected() {
331
+ if (!this.connected) {
332
+ throw new TransportError("Transport is not connected");
333
+ }
334
+ }
335
+ };
336
+
337
+ export { InMemoryTransport, MemoryBus };