@delali/sirannon-db 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backup-scheduler/index.d.ts +15 -1
- package/dist/backup-scheduler/index.mjs +2 -2
- package/dist/baseline-D93hcIEE.d.ts +17 -0
- package/dist/{change-tracker-DKRVUC3l.d.ts → change-tracker-DDmXB754.d.ts} +56 -8
- package/dist/{chunk-5NOIGN5Y.mjs → chunk-2QLXDHAP.mjs} +1 -1
- package/dist/{chunk-LNY2VVHE.mjs → chunk-7C36BCSN.mjs} +1 -1
- package/dist/{chunk-NVQS53NT.mjs → chunk-7FQRQH5Z.mjs} +53 -64
- package/dist/{chunk-D7LAYTKN.mjs → chunk-7R4ER4FB.mjs} +1 -1
- package/dist/{chunk-FHWTZFI4.mjs → chunk-BQFQ65OL.mjs} +1 -1
- package/dist/{chunk-O7SLN3GI.mjs → chunk-BTTFW4Z4.mjs} +1 -1
- package/dist/{chunk-H6PIVVDN.mjs → chunk-CCZK6LCB.mjs} +38 -25
- package/dist/{chunk-JZGINXTN.mjs → chunk-HCCGEIZ2.mjs} +2 -2
- package/dist/{chunk-67M7KAH6.mjs → chunk-IWGIYDMZ.mjs} +1 -1
- package/dist/{chunk-LFZ37BSX.mjs → chunk-OUSWVNWT.mjs} +1 -1
- package/dist/{chunk-HR5CWTLC.mjs → chunk-P2VJYRVY.mjs} +60 -7
- package/dist/{chunk-UC3SCMIN.mjs → chunk-PBRXXISQ.mjs} +3 -0
- package/dist/{chunk-JU64Y7HM.mjs → chunk-SBL6GN43.mjs} +1 -1
- package/dist/{chunk-EBJXPQQO.mjs → chunk-UPKKSUPA.mjs} +2 -2
- package/dist/{chunk-TJF5GZSV.mjs → chunk-VOSJBZ6Q.mjs} +1 -1
- package/dist/{chunk-PIKHN33N.mjs → chunk-VOYGMAU7.mjs} +9 -1
- package/dist/{chunk-H237TXZW.mjs → chunk-WJ67DTD6.mjs} +48 -6
- package/dist/{chunk-OQVZBEBY.mjs → chunk-XF2HH5E6.mjs} +4 -61
- package/dist/client/index.d.ts +211 -12
- package/dist/client/index.mjs +155 -67
- package/dist/client/topology.d.ts +55 -7
- package/dist/client/topology.mjs +20 -1
- package/dist/{client-base-CLWmH5Ln.d.ts → client-base-CmZO0v3m.d.ts} +133 -24
- package/dist/codegen/cli.mjs +3 -3
- package/dist/codegen/index.d.ts +92 -2
- package/dist/codegen/index.mjs +3 -3
- package/dist/core/index.d.ts +177 -15
- package/dist/core/index.mjs +2481 -2226
- package/dist/core/writer-worker.mjs +3 -3
- package/dist/database-B5Qv1-cU.d.ts +380 -0
- package/dist/driver/better-sqlite3.d.ts +18 -1
- package/dist/driver/better-sqlite3.mjs +5 -5
- package/dist/driver/bun.d.ts +28 -0
- package/dist/driver/expo.d.ts +17 -0
- package/dist/driver/node.d.ts +18 -1
- package/dist/driver/node.mjs +5 -5
- package/dist/driver/wa-sqlite.d.ts +18 -1
- package/dist/{errors-Bw5MdNCu.d.ts → errors-Dei4GdBb.d.ts} +80 -7
- package/dist/file-migrations/index.d.ts +54 -2
- package/dist/file-migrations/index.mjs +3 -3
- package/dist/{operation-registry-9DcvxcE5.d.ts → operation-registry-hlbhqu7q.d.ts} +50 -1
- package/dist/{primary-wins-DPAm2AKG.d.ts → primary-wins-B0np8JS3.d.ts} +25 -1
- package/dist/protocol-rqANt-9Q.d.ts +152 -0
- package/dist/query-types-DL3LtPvY.d.ts +95 -0
- package/dist/react/index.d.ts +58 -3
- package/dist/replication/coordinator/etcd.d.ts +63 -3
- package/dist/replication/coordinator/etcd.mjs +82 -46
- package/dist/replication/index.d.ts +329 -95
- package/dist/replication/index.mjs +256 -141
- package/dist/server/index.d.ts +230 -12
- package/dist/server/index.mjs +63 -50
- package/dist/{server-options-1JHu8pid.d.ts → server-options-Dab_Jvd_.d.ts} +96 -12
- package/dist/sirannon-CMhiJa5Y.d.ts +111 -0
- package/dist/transport/grpc.d.ts +93 -9
- package/dist/transport/grpc.mjs +63 -20
- package/dist/transport/memory.d.ts +50 -20
- package/dist/transport/memory.mjs +25 -0
- package/dist/{types-CL6piSnD.d.ts → types-BCejqzNA.d.ts} +20 -0
- package/dist/types-CMBcFPhb.d.ts +336 -0
- package/dist/types-CjhxcjhA.d.ts +123 -0
- package/dist/types-DyrCiWuc.d.ts +499 -0
- package/dist/types-rVZKnKN-.d.ts +591 -0
- package/package.json +7 -1
- package/dist/baseline-Br77Fnhb.d.ts +0 -6
- package/dist/database-BY0L5Q2n.d.ts +0 -172
- package/dist/protocol-6KrSq2Hy.d.ts +0 -66
- package/dist/sirannon-DaQSyhbJ.d.ts +0 -36
- package/dist/types-B7gmEsZW.d.ts +0 -221
- package/dist/types-BsVabqSI.d.ts +0 -139
- package/dist/types-C_D8IhpO.d.ts +0 -60
- package/dist/types-zhnRXrsb.d.ts +0 -384
package/dist/transport/grpc.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { TransportError } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
3
|
-
import '../chunk-
|
|
1
|
+
import { TransportError } from '../chunk-BTTFW4Z4.mjs';
|
|
2
|
+
import '../chunk-2QLXDHAP.mjs';
|
|
3
|
+
import '../chunk-PBRXXISQ.mjs';
|
|
4
4
|
import { BinaryWriter, BinaryReader } from '@bufbuild/protobuf/wire';
|
|
5
5
|
import { makeGenericClientConstructor, Server, Metadata, status, ServerCredentials, credentials } from '@grpc/grpc-js';
|
|
6
6
|
import { readFileSync } from 'fs';
|
|
@@ -2778,6 +2778,18 @@ function buildChannelCreds(options) {
|
|
|
2778
2778
|
}
|
|
2779
2779
|
|
|
2780
2780
|
// src/transport/grpc/peer-streams.ts
|
|
2781
|
+
function replicateWriteStream(serverPeerStreams, clientPeerStreams, peerId) {
|
|
2782
|
+
return serverPeerStreams.get(peerId)?.replicateStream ?? clientPeerStreams.get(peerId)?.replicateStream ?? null;
|
|
2783
|
+
}
|
|
2784
|
+
function syncWriteStream(serverPeerStreams, clientPeerStreams, peerId) {
|
|
2785
|
+
return serverPeerStreams.get(peerId)?.syncStream ?? clientPeerStreams.get(peerId)?.syncStream ?? null;
|
|
2786
|
+
}
|
|
2787
|
+
function peerIdForServerStream(serverPeerStreams, entry) {
|
|
2788
|
+
for (const [peerId, candidate] of serverPeerStreams) {
|
|
2789
|
+
if (candidate === entry) return peerId;
|
|
2790
|
+
}
|
|
2791
|
+
return null;
|
|
2792
|
+
}
|
|
2781
2793
|
function registerPeer(connectedPeers, peerConnectedHandler, nodeId, role, metadata = {}) {
|
|
2782
2794
|
if (connectedPeers.has(nodeId)) return;
|
|
2783
2795
|
const peerInfo = {
|
|
@@ -3196,34 +3208,58 @@ function writeWithBackpressure(stream, message) {
|
|
|
3196
3208
|
|
|
3197
3209
|
// src/transport/grpc/transport.ts
|
|
3198
3210
|
var GrpcReplicationTransport = class {
|
|
3211
|
+
/** @internal */
|
|
3199
3212
|
options;
|
|
3213
|
+
/** @internal */
|
|
3200
3214
|
localNodeId = "";
|
|
3215
|
+
/** @internal */
|
|
3201
3216
|
localRole = "replica";
|
|
3217
|
+
/** @internal */
|
|
3202
3218
|
localGroupId;
|
|
3219
|
+
/** @internal */
|
|
3203
3220
|
localPrimaryTerm;
|
|
3221
|
+
/** @internal */
|
|
3204
3222
|
localProtocolVersion;
|
|
3223
|
+
/** @internal */
|
|
3205
3224
|
connected = false;
|
|
3225
|
+
/** @internal */
|
|
3206
3226
|
server = null;
|
|
3227
|
+
/** @internal */
|
|
3207
3228
|
boundPort = 0;
|
|
3229
|
+
/** @internal */
|
|
3208
3230
|
healthImpl = null;
|
|
3231
|
+
/** @internal */
|
|
3209
3232
|
connectedPeers = /* @__PURE__ */ new Map();
|
|
3233
|
+
/** @internal */
|
|
3210
3234
|
serverPeerStreams = /* @__PURE__ */ new Map();
|
|
3235
|
+
/** @internal */
|
|
3211
3236
|
clientPeerStreams = /* @__PURE__ */ new Map();
|
|
3237
|
+
/** @internal */
|
|
3212
3238
|
batchHandler = null;
|
|
3239
|
+
/** @internal */
|
|
3213
3240
|
ackHandler = null;
|
|
3241
|
+
/** @internal */
|
|
3214
3242
|
forwardHandler = null;
|
|
3243
|
+
/** @internal */
|
|
3215
3244
|
peerConnectedHandler = null;
|
|
3245
|
+
/** @internal */
|
|
3216
3246
|
peerDisconnectedHandler = null;
|
|
3247
|
+
/** @internal */
|
|
3217
3248
|
syncRequestHandler = null;
|
|
3249
|
+
/** @internal */
|
|
3218
3250
|
syncBatchHandler = null;
|
|
3251
|
+
/** @internal */
|
|
3219
3252
|
syncCompleteHandler = null;
|
|
3253
|
+
/** @internal */
|
|
3220
3254
|
syncAckHandler = null;
|
|
3221
3255
|
constructor(options = {}) {
|
|
3222
3256
|
this.options = options;
|
|
3223
3257
|
}
|
|
3258
|
+
/** Returns the port the gRPC server bound to, which is the resolved port when you asked for 0. */
|
|
3224
3259
|
getPort() {
|
|
3225
3260
|
return this.boundPort;
|
|
3226
3261
|
}
|
|
3262
|
+
/** Connects to the configured peers and announces this node. */
|
|
3227
3263
|
async connect(localNodeId, config) {
|
|
3228
3264
|
if (this.connected) {
|
|
3229
3265
|
throw new TransportError("Transport is already connected");
|
|
@@ -3246,6 +3282,7 @@ var GrpcReplicationTransport = class {
|
|
|
3246
3282
|
}
|
|
3247
3283
|
}
|
|
3248
3284
|
}
|
|
3285
|
+
/** Closes every peer connection. */
|
|
3249
3286
|
async disconnect() {
|
|
3250
3287
|
if (!this.connected) return;
|
|
3251
3288
|
this.connected = false;
|
|
@@ -3286,6 +3323,7 @@ var GrpcReplicationTransport = class {
|
|
|
3286
3323
|
this.server = null;
|
|
3287
3324
|
}
|
|
3288
3325
|
}
|
|
3326
|
+
/** Sends one batch of changes to one peer. */
|
|
3289
3327
|
async send(peerId, batch) {
|
|
3290
3328
|
this.ensureConnected();
|
|
3291
3329
|
const stream = this.getReplicateWriteStream(peerId);
|
|
@@ -3295,6 +3333,7 @@ var GrpcReplicationTransport = class {
|
|
|
3295
3333
|
const msg = { batch: toBatchPayload(batch) };
|
|
3296
3334
|
await writeWithBackpressure(stream, msg);
|
|
3297
3335
|
}
|
|
3336
|
+
/** Sends one batch of changes to every connected peer. */
|
|
3298
3337
|
async broadcast(batch) {
|
|
3299
3338
|
this.ensureConnected();
|
|
3300
3339
|
const msg = { batch: toBatchPayload(batch) };
|
|
@@ -3307,6 +3346,7 @@ var GrpcReplicationTransport = class {
|
|
|
3307
3346
|
}
|
|
3308
3347
|
await Promise.all(promises);
|
|
3309
3348
|
}
|
|
3349
|
+
/** Confirms to a peer that this node applied one of its batches. */
|
|
3310
3350
|
async sendAck(peerId, ack) {
|
|
3311
3351
|
this.ensureConnected();
|
|
3312
3352
|
const stream = this.getReplicateWriteStream(peerId);
|
|
@@ -3316,6 +3356,7 @@ var GrpcReplicationTransport = class {
|
|
|
3316
3356
|
const msg = { ack: toAckPayload(ack) };
|
|
3317
3357
|
await writeWithBackpressure(stream, msg);
|
|
3318
3358
|
}
|
|
3359
|
+
/** Sends a write to the primary and waits for its result. */
|
|
3319
3360
|
async forward(peerId, request) {
|
|
3320
3361
|
this.ensureConnected();
|
|
3321
3362
|
const clientEntry = this.clientPeerStreams.get(peerId);
|
|
@@ -3324,6 +3365,7 @@ var GrpcReplicationTransport = class {
|
|
|
3324
3365
|
}
|
|
3325
3366
|
return forwardOverRpc(clientEntry, request, this.options.forwardDeadlineMs ?? DEFAULT_FORWARD_DEADLINE_MS);
|
|
3326
3367
|
}
|
|
3368
|
+
/** Asks a peer to stream a full copy of the database. */
|
|
3327
3369
|
async requestSync(peerId, request) {
|
|
3328
3370
|
this.ensureConnected();
|
|
3329
3371
|
const stream = this.getSyncWriteStream(peerId);
|
|
@@ -3333,6 +3375,7 @@ var GrpcReplicationTransport = class {
|
|
|
3333
3375
|
const msg = { syncRequest: toSyncRequestPayload(request) };
|
|
3334
3376
|
await writeWithBackpressure(stream, msg);
|
|
3335
3377
|
}
|
|
3378
|
+
/** Sends one page of first-sync table data. */
|
|
3336
3379
|
async sendSyncBatch(peerId, batch) {
|
|
3337
3380
|
this.ensureConnected();
|
|
3338
3381
|
const stream = this.getSyncWriteStream(peerId);
|
|
@@ -3342,6 +3385,7 @@ var GrpcReplicationTransport = class {
|
|
|
3342
3385
|
const msg = { syncBatch: toSyncBatchPayload(batch) };
|
|
3343
3386
|
await writeWithBackpressure(stream, msg);
|
|
3344
3387
|
}
|
|
3388
|
+
/** Tells a joining node that first sync has finished, and sends the manifests to verify it. */
|
|
3345
3389
|
async sendSyncComplete(peerId, complete) {
|
|
3346
3390
|
this.ensureConnected();
|
|
3347
3391
|
const stream = this.getSyncWriteStream(peerId);
|
|
@@ -3351,6 +3395,7 @@ var GrpcReplicationTransport = class {
|
|
|
3351
3395
|
const msg = { syncComplete: toSyncCompletePayload(complete) };
|
|
3352
3396
|
await writeWithBackpressure(stream, msg);
|
|
3353
3397
|
}
|
|
3398
|
+
/** Confirms to the source that a joining node stored one first-sync page. */
|
|
3354
3399
|
async sendSyncAck(peerId, ack) {
|
|
3355
3400
|
this.ensureConnected();
|
|
3356
3401
|
const stream = this.getSyncWriteStream(peerId);
|
|
@@ -3360,33 +3405,43 @@ var GrpcReplicationTransport = class {
|
|
|
3360
3405
|
const msg = { syncAck: toSyncAckPayload(ack) };
|
|
3361
3406
|
await writeWithBackpressure(stream, msg);
|
|
3362
3407
|
}
|
|
3408
|
+
/** Registers the handler that applies incoming change batches. */
|
|
3363
3409
|
onBatchReceived(handler) {
|
|
3364
3410
|
this.batchHandler = handler;
|
|
3365
3411
|
}
|
|
3412
|
+
/** Registers the handler that records incoming acknowledgements. */
|
|
3366
3413
|
onAckReceived(handler) {
|
|
3367
3414
|
this.ackHandler = handler;
|
|
3368
3415
|
}
|
|
3416
|
+
/** Registers the handler that runs a write a replica forwarded. */
|
|
3369
3417
|
onForwardReceived(handler) {
|
|
3370
3418
|
this.forwardHandler = handler;
|
|
3371
3419
|
}
|
|
3420
|
+
/** Registers the handler that serves a first-sync request. */
|
|
3372
3421
|
onSyncRequested(handler) {
|
|
3373
3422
|
this.syncRequestHandler = handler;
|
|
3374
3423
|
}
|
|
3424
|
+
/** Registers the handler that stores an incoming first-sync page. */
|
|
3375
3425
|
onSyncBatchReceived(handler) {
|
|
3376
3426
|
this.syncBatchHandler = handler;
|
|
3377
3427
|
}
|
|
3428
|
+
/** Registers the handler that finishes first sync and verifies the manifests. */
|
|
3378
3429
|
onSyncCompleteReceived(handler) {
|
|
3379
3430
|
this.syncCompleteHandler = handler;
|
|
3380
3431
|
}
|
|
3432
|
+
/** Registers the handler that records first-sync page acknowledgements. */
|
|
3381
3433
|
onSyncAckReceived(handler) {
|
|
3382
3434
|
this.syncAckHandler = handler;
|
|
3383
3435
|
}
|
|
3436
|
+
/** Registers the handler that runs when a peer connects. */
|
|
3384
3437
|
onPeerConnected(handler) {
|
|
3385
3438
|
this.peerConnectedHandler = handler;
|
|
3386
3439
|
}
|
|
3440
|
+
/** Registers the handler that runs when a peer disconnects. */
|
|
3387
3441
|
onPeerDisconnected(handler) {
|
|
3388
3442
|
this.peerDisconnectedHandler = handler;
|
|
3389
3443
|
}
|
|
3444
|
+
/** Returns every connected peer, keyed by identifier. */
|
|
3390
3445
|
peers() {
|
|
3391
3446
|
return this.connectedPeers;
|
|
3392
3447
|
}
|
|
@@ -3402,12 +3457,14 @@ var GrpcReplicationTransport = class {
|
|
|
3402
3457
|
if (Array.isArray(certCN)) return certCN[0] ?? null;
|
|
3403
3458
|
return certCN;
|
|
3404
3459
|
}
|
|
3460
|
+
/** @internal */
|
|
3405
3461
|
validateTlsIdentity(call, claimedNodeId) {
|
|
3406
3462
|
if (this.options.insecure) return true;
|
|
3407
3463
|
if (!this.options.tlsCaCert) return true;
|
|
3408
3464
|
const cn = this.extractTlsCN(call);
|
|
3409
3465
|
return cn === claimedNodeId;
|
|
3410
3466
|
}
|
|
3467
|
+
/** @internal */
|
|
3411
3468
|
resolveForwardPeerId(call) {
|
|
3412
3469
|
const cn = this.extractTlsCN(call);
|
|
3413
3470
|
if (cn) {
|
|
@@ -3417,36 +3474,22 @@ var GrpcReplicationTransport = class {
|
|
|
3417
3474
|
const peerAddr = call.getPeer();
|
|
3418
3475
|
for (const [, entry] of this.serverPeerStreams) {
|
|
3419
3476
|
if (entry.replicateStream?.getPeer() === peerAddr) {
|
|
3420
|
-
const streamPeerId = this.
|
|
3477
|
+
const streamPeerId = peerIdForServerStream(this.serverPeerStreams, entry);
|
|
3421
3478
|
if (streamPeerId) return streamPeerId;
|
|
3422
3479
|
}
|
|
3423
3480
|
}
|
|
3424
3481
|
return null;
|
|
3425
3482
|
}
|
|
3426
|
-
findPeerIdForStream(entry) {
|
|
3427
|
-
for (const [peerId, ps] of this.serverPeerStreams) {
|
|
3428
|
-
if (ps === entry) return peerId;
|
|
3429
|
-
}
|
|
3430
|
-
return null;
|
|
3431
|
-
}
|
|
3432
3483
|
ensureConnected() {
|
|
3433
3484
|
if (!this.connected) {
|
|
3434
3485
|
throw new TransportError("Transport is not connected");
|
|
3435
3486
|
}
|
|
3436
3487
|
}
|
|
3437
3488
|
getReplicateWriteStream(peerId) {
|
|
3438
|
-
|
|
3439
|
-
if (serverStream?.replicateStream) return serverStream.replicateStream;
|
|
3440
|
-
const clientEntry = this.clientPeerStreams.get(peerId);
|
|
3441
|
-
if (clientEntry?.replicateStream) return clientEntry.replicateStream;
|
|
3442
|
-
return null;
|
|
3489
|
+
return replicateWriteStream(this.serverPeerStreams, this.clientPeerStreams, peerId);
|
|
3443
3490
|
}
|
|
3444
3491
|
getSyncWriteStream(peerId) {
|
|
3445
|
-
|
|
3446
|
-
if (serverStream?.syncStream) return serverStream.syncStream;
|
|
3447
|
-
const clientEntry = this.clientPeerStreams.get(peerId);
|
|
3448
|
-
if (clientEntry?.syncStream) return clientEntry.syncStream;
|
|
3449
|
-
return null;
|
|
3492
|
+
return syncWriteStream(this.serverPeerStreams, this.clientPeerStreams, peerId);
|
|
3450
3493
|
}
|
|
3451
3494
|
};
|
|
3452
3495
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { R as ReplicationBatch } from '../types-
|
|
3
|
-
import '../change-tracker-
|
|
4
|
-
import '../types-
|
|
5
|
-
import '../types-
|
|
1
|
+
import { R as ReplicationAck, F as ForwardedTransaction, a as ForwardedTransactionResult, S as SyncRequest, b as SyncBatch, c as SyncComplete, d as SyncAck, N as NodeInfo, e as ReplicationTransport, T as TransportConfig } from '../types-DyrCiWuc.js';
|
|
2
|
+
import { R as ReplicationBatch } from '../types-CjhxcjhA.js';
|
|
3
|
+
import '../change-tracker-DDmXB754.js';
|
|
4
|
+
import '../types-rVZKnKN-.js';
|
|
5
|
+
import '../query-types-DL3LtPvY.js';
|
|
6
|
+
import '../types-CMBcFPhb.js';
|
|
6
7
|
|
|
7
8
|
type BatchHandler = (batch: ReplicationBatch, fromPeerId: string) => Promise<void>;
|
|
8
9
|
type AckHandler = (ack: ReplicationAck, fromPeerId: string) => void;
|
|
@@ -20,10 +21,12 @@ type SyncAckHandler = (ack: SyncAck, fromPeerId: string) => void;
|
|
|
20
21
|
*
|
|
21
22
|
* Messages between peers are delivered through a shared MemoryBus via
|
|
22
23
|
* microtask scheduling (`queueMicrotask`), preserving the async delivery
|
|
23
|
-
* semantics of a real network transport
|
|
24
|
+
* semantics of a real network transport with no I/O. All
|
|
24
25
|
* message types (batches, acks, forwards) go through runtime
|
|
25
26
|
* validation before delivery, and malformed payloads are silently dropped
|
|
26
|
-
* to match the
|
|
27
|
+
* to match the behaviour of a lossy network.
|
|
28
|
+
*
|
|
29
|
+
* @public
|
|
27
30
|
*/
|
|
28
31
|
declare class InMemoryTransport implements ReplicationTransport {
|
|
29
32
|
private localNodeId;
|
|
@@ -31,47 +34,67 @@ declare class InMemoryTransport implements ReplicationTransport {
|
|
|
31
34
|
private localGroupId;
|
|
32
35
|
private localPrimaryTerm;
|
|
33
36
|
private localProtocolVersion;
|
|
34
|
-
connected
|
|
37
|
+
private connected;
|
|
35
38
|
private readonly bus;
|
|
36
|
-
readonly connectedPeers
|
|
39
|
+
private readonly connectedPeers;
|
|
37
40
|
private batchHandler;
|
|
38
41
|
private ackHandler;
|
|
39
42
|
private forwardHandler;
|
|
40
|
-
peerConnectedHandler
|
|
41
|
-
peerDisconnectedHandler
|
|
43
|
+
private peerConnectedHandler;
|
|
44
|
+
private peerDisconnectedHandler;
|
|
42
45
|
private syncRequestHandler;
|
|
43
46
|
private syncBatchHandler;
|
|
44
47
|
private syncCompleteHandler;
|
|
45
48
|
private syncAckHandler;
|
|
46
49
|
constructor(bus: MemoryBus);
|
|
47
|
-
get role()
|
|
50
|
+
private get role();
|
|
51
|
+
/** Connects to the configured peers and announces this node. */
|
|
48
52
|
connect(localNodeId: string, config: TransportConfig): Promise<void>;
|
|
53
|
+
/** Closes every peer connection. */
|
|
49
54
|
disconnect(): Promise<void>;
|
|
55
|
+
/** Sends one batch of changes to one peer. */
|
|
50
56
|
send(peerId: string, batch: ReplicationBatch): Promise<void>;
|
|
57
|
+
/** Sends one batch of changes to every connected peer. */
|
|
51
58
|
broadcast(batch: ReplicationBatch): Promise<void>;
|
|
59
|
+
/** Confirms to a peer that this node applied one of its batches. */
|
|
52
60
|
sendAck(peerId: string, ack: ReplicationAck): Promise<void>;
|
|
61
|
+
/** Sends a write to the primary and waits for its result. */
|
|
53
62
|
forward(peerId: string, request: ForwardedTransaction): Promise<ForwardedTransactionResult>;
|
|
63
|
+
/** Asks a peer to stream a full copy of the database. */
|
|
54
64
|
requestSync(peerId: string, request: SyncRequest): Promise<void>;
|
|
65
|
+
/** Sends one page of first-sync table data. */
|
|
55
66
|
sendSyncBatch(peerId: string, batch: SyncBatch): Promise<void>;
|
|
67
|
+
/** Tells a joining node that first sync has finished, and sends the manifests to verify it. */
|
|
56
68
|
sendSyncComplete(peerId: string, complete: SyncComplete): Promise<void>;
|
|
69
|
+
/** Confirms to the source that a joining node stored one first-sync page. */
|
|
57
70
|
sendSyncAck(peerId: string, ack: SyncAck): Promise<void>;
|
|
71
|
+
/** Registers the handler that applies incoming change batches. */
|
|
58
72
|
onBatchReceived(handler: BatchHandler): void;
|
|
73
|
+
/** Registers the handler that records incoming acknowledgements. */
|
|
59
74
|
onAckReceived(handler: AckHandler): void;
|
|
75
|
+
/** Registers the handler that runs a write a replica forwarded. */
|
|
60
76
|
onForwardReceived(handler: ForwardHandler): void;
|
|
77
|
+
/** Registers the handler that serves a first-sync request. */
|
|
61
78
|
onSyncRequested(handler: SyncRequestHandler): void;
|
|
79
|
+
/** Registers the handler that stores an incoming first-sync page. */
|
|
62
80
|
onSyncBatchReceived(handler: SyncBatchHandler): void;
|
|
81
|
+
/** Registers the handler that finishes first sync and verifies the manifests. */
|
|
63
82
|
onSyncCompleteReceived(handler: SyncCompleteHandler): void;
|
|
83
|
+
/** Registers the handler that records first-sync page acknowledgements. */
|
|
64
84
|
onSyncAckReceived(handler: SyncAckHandler): void;
|
|
85
|
+
/** Registers the handler that runs when a peer connects. */
|
|
65
86
|
onPeerConnected(handler: PeerConnectedHandler): void;
|
|
87
|
+
/** Registers the handler that runs when a peer disconnects. */
|
|
66
88
|
onPeerDisconnected(handler: PeerDisconnectedHandler): void;
|
|
89
|
+
/** Returns every connected peer, keyed by identifier. */
|
|
67
90
|
peers(): ReadonlyMap<string, NodeInfo>;
|
|
68
|
-
_receiveBatch
|
|
69
|
-
_receiveAck
|
|
70
|
-
_receiveForward
|
|
71
|
-
_receiveSyncRequest
|
|
72
|
-
_receiveSyncBatch
|
|
73
|
-
_receiveSyncComplete
|
|
74
|
-
_receiveSyncAck
|
|
91
|
+
private _receiveBatch;
|
|
92
|
+
private _receiveAck;
|
|
93
|
+
private _receiveForward;
|
|
94
|
+
private _receiveSyncRequest;
|
|
95
|
+
private _receiveSyncBatch;
|
|
96
|
+
private _receiveSyncComplete;
|
|
97
|
+
private _receiveSyncAck;
|
|
75
98
|
private ensureConnected;
|
|
76
99
|
}
|
|
77
100
|
|
|
@@ -79,14 +102,21 @@ declare class InMemoryTransport implements ReplicationTransport {
|
|
|
79
102
|
* Shared message bus that connects InMemoryTransport instances within the
|
|
80
103
|
* same process. Each transport registers itself on `connect()` and messages
|
|
81
104
|
* are delivered via direct method calls on the target transport through
|
|
82
|
-
* microtask scheduling, simulating async network delivery
|
|
105
|
+
* microtask scheduling, simulating async network delivery with no I/O.
|
|
106
|
+
*
|
|
107
|
+
* @public
|
|
83
108
|
*/
|
|
84
109
|
declare class MemoryBus {
|
|
85
110
|
private readonly transports;
|
|
111
|
+
/** @internal */
|
|
86
112
|
join(peerId: string, transport: InMemoryTransport): void;
|
|
113
|
+
/** @internal */
|
|
87
114
|
leave(peerId: string): void;
|
|
115
|
+
/** @internal */
|
|
88
116
|
getTransport(peerId: string): InMemoryTransport | undefined;
|
|
117
|
+
/** @internal */
|
|
89
118
|
peerIds(): IterableIterator<string>;
|
|
119
|
+
/** @internal */
|
|
90
120
|
get size(): number;
|
|
91
121
|
}
|
|
92
122
|
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
// src/transport/memory/bus.ts
|
|
2
2
|
var MemoryBus = class {
|
|
3
3
|
transports = /* @__PURE__ */ new Map();
|
|
4
|
+
/** @internal */
|
|
4
5
|
join(peerId, transport) {
|
|
5
6
|
this.transports.set(peerId, transport);
|
|
6
7
|
}
|
|
8
|
+
/** @internal */
|
|
7
9
|
leave(peerId) {
|
|
8
10
|
this.transports.delete(peerId);
|
|
9
11
|
}
|
|
12
|
+
/** @internal */
|
|
10
13
|
getTransport(peerId) {
|
|
11
14
|
return this.transports.get(peerId);
|
|
12
15
|
}
|
|
16
|
+
/** @internal */
|
|
13
17
|
peerIds() {
|
|
14
18
|
return this.transports.keys();
|
|
15
19
|
}
|
|
20
|
+
/** @internal */
|
|
16
21
|
get size() {
|
|
17
22
|
return this.transports.size;
|
|
18
23
|
}
|
|
@@ -115,6 +120,7 @@ var InMemoryTransport = class {
|
|
|
115
120
|
get role() {
|
|
116
121
|
return this.localRole;
|
|
117
122
|
}
|
|
123
|
+
/** Connects to the configured peers and announces this node. */
|
|
118
124
|
async connect(localNodeId, config) {
|
|
119
125
|
if (this.connected) {
|
|
120
126
|
throw new TransportError("Transport is already connected");
|
|
@@ -160,6 +166,7 @@ var InMemoryTransport = class {
|
|
|
160
166
|
}
|
|
161
167
|
}
|
|
162
168
|
}
|
|
169
|
+
/** Closes every peer connection. */
|
|
163
170
|
async disconnect() {
|
|
164
171
|
if (!this.connected) return;
|
|
165
172
|
this.connected = false;
|
|
@@ -175,6 +182,7 @@ var InMemoryTransport = class {
|
|
|
175
182
|
}
|
|
176
183
|
this.connectedPeers.clear();
|
|
177
184
|
}
|
|
185
|
+
/** Sends one batch of changes to one peer. */
|
|
178
186
|
async send(peerId, batch) {
|
|
179
187
|
this.ensureConnected();
|
|
180
188
|
if (!isValidBatch(batch)) {
|
|
@@ -190,6 +198,7 @@ var InMemoryTransport = class {
|
|
|
190
198
|
});
|
|
191
199
|
});
|
|
192
200
|
}
|
|
201
|
+
/** Sends one batch of changes to every connected peer. */
|
|
193
202
|
async broadcast(batch) {
|
|
194
203
|
this.ensureConnected();
|
|
195
204
|
if (!isValidBatch(batch)) {
|
|
@@ -206,6 +215,7 @@ var InMemoryTransport = class {
|
|
|
206
215
|
}
|
|
207
216
|
}
|
|
208
217
|
}
|
|
218
|
+
/** Confirms to a peer that this node applied one of its batches. */
|
|
209
219
|
async sendAck(peerId, ack) {
|
|
210
220
|
this.ensureConnected();
|
|
211
221
|
if (!isValidAck(ack)) {
|
|
@@ -220,6 +230,7 @@ var InMemoryTransport = class {
|
|
|
220
230
|
peer._receiveAck(ack, fromPeerId);
|
|
221
231
|
});
|
|
222
232
|
}
|
|
233
|
+
/** Sends a write to the primary and waits for its result. */
|
|
223
234
|
async forward(peerId, request) {
|
|
224
235
|
this.ensureConnected();
|
|
225
236
|
if (!isValidForwardedTransaction(request)) {
|
|
@@ -231,6 +242,7 @@ var InMemoryTransport = class {
|
|
|
231
242
|
}
|
|
232
243
|
return peer._receiveForward(request, this.localNodeId);
|
|
233
244
|
}
|
|
245
|
+
/** Asks a peer to stream a full copy of the database. */
|
|
234
246
|
async requestSync(peerId, request) {
|
|
235
247
|
this.ensureConnected();
|
|
236
248
|
if (!isValidSyncRequest(request)) throw new TransportError("Invalid sync request structure");
|
|
@@ -242,6 +254,7 @@ var InMemoryTransport = class {
|
|
|
242
254
|
});
|
|
243
255
|
});
|
|
244
256
|
}
|
|
257
|
+
/** Sends one page of first-sync table data. */
|
|
245
258
|
async sendSyncBatch(peerId, batch) {
|
|
246
259
|
this.ensureConnected();
|
|
247
260
|
if (!isValidSyncBatch(batch)) throw new TransportError("Invalid sync batch structure");
|
|
@@ -253,6 +266,7 @@ var InMemoryTransport = class {
|
|
|
253
266
|
});
|
|
254
267
|
});
|
|
255
268
|
}
|
|
269
|
+
/** Tells a joining node that first sync has finished, and sends the manifests to verify it. */
|
|
256
270
|
async sendSyncComplete(peerId, complete) {
|
|
257
271
|
this.ensureConnected();
|
|
258
272
|
if (!isValidSyncComplete(complete)) throw new TransportError("Invalid sync complete structure");
|
|
@@ -264,6 +278,7 @@ var InMemoryTransport = class {
|
|
|
264
278
|
});
|
|
265
279
|
});
|
|
266
280
|
}
|
|
281
|
+
/** Confirms to the source that a joining node stored one first-sync page. */
|
|
267
282
|
async sendSyncAck(peerId, ack) {
|
|
268
283
|
this.ensureConnected();
|
|
269
284
|
if (!isValidSyncAck(ack)) throw new TransportError("Invalid sync ack structure");
|
|
@@ -274,33 +289,43 @@ var InMemoryTransport = class {
|
|
|
274
289
|
peer._receiveSyncAck(ack, fromPeerId);
|
|
275
290
|
});
|
|
276
291
|
}
|
|
292
|
+
/** Registers the handler that applies incoming change batches. */
|
|
277
293
|
onBatchReceived(handler) {
|
|
278
294
|
this.batchHandler = handler;
|
|
279
295
|
}
|
|
296
|
+
/** Registers the handler that records incoming acknowledgements. */
|
|
280
297
|
onAckReceived(handler) {
|
|
281
298
|
this.ackHandler = handler;
|
|
282
299
|
}
|
|
300
|
+
/** Registers the handler that runs a write a replica forwarded. */
|
|
283
301
|
onForwardReceived(handler) {
|
|
284
302
|
this.forwardHandler = handler;
|
|
285
303
|
}
|
|
304
|
+
/** Registers the handler that serves a first-sync request. */
|
|
286
305
|
onSyncRequested(handler) {
|
|
287
306
|
this.syncRequestHandler = handler;
|
|
288
307
|
}
|
|
308
|
+
/** Registers the handler that stores an incoming first-sync page. */
|
|
289
309
|
onSyncBatchReceived(handler) {
|
|
290
310
|
this.syncBatchHandler = handler;
|
|
291
311
|
}
|
|
312
|
+
/** Registers the handler that finishes first sync and verifies the manifests. */
|
|
292
313
|
onSyncCompleteReceived(handler) {
|
|
293
314
|
this.syncCompleteHandler = handler;
|
|
294
315
|
}
|
|
316
|
+
/** Registers the handler that records first-sync page acknowledgements. */
|
|
295
317
|
onSyncAckReceived(handler) {
|
|
296
318
|
this.syncAckHandler = handler;
|
|
297
319
|
}
|
|
320
|
+
/** Registers the handler that runs when a peer connects. */
|
|
298
321
|
onPeerConnected(handler) {
|
|
299
322
|
this.peerConnectedHandler = handler;
|
|
300
323
|
}
|
|
324
|
+
/** Registers the handler that runs when a peer disconnects. */
|
|
301
325
|
onPeerDisconnected(handler) {
|
|
302
326
|
this.peerDisconnectedHandler = handler;
|
|
303
327
|
}
|
|
328
|
+
/** Returns every connected peer, keyed by identifier. */
|
|
304
329
|
peers() {
|
|
305
330
|
return this.connectedPeers;
|
|
306
331
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/** Where a live query stands: waiting for its first rows, holding rows, or failed.
|
|
2
|
+
* @public
|
|
3
|
+
*/
|
|
1
4
|
type LiveQueryState<T> = {
|
|
2
5
|
status: 'pending';
|
|
3
6
|
} | {
|
|
@@ -8,6 +11,9 @@ type LiveQueryState<T> = {
|
|
|
8
11
|
status: 'error';
|
|
9
12
|
error: Error;
|
|
10
13
|
};
|
|
14
|
+
/** One change to a live query's result set, as a position and the row at it.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
11
17
|
type ResultOp<T> = {
|
|
12
18
|
op: 'insert';
|
|
13
19
|
index: number;
|
|
@@ -20,6 +26,9 @@ type ResultOp<T> = {
|
|
|
20
26
|
op: 'delete';
|
|
21
27
|
index: number;
|
|
22
28
|
};
|
|
29
|
+
/** What a live query tells its listeners: the rows replaced, edited in place, being re-read, or failed.
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
23
32
|
type LiveUpdate<T> = {
|
|
24
33
|
kind: 'rows';
|
|
25
34
|
} | {
|
|
@@ -30,13 +39,24 @@ type LiveUpdate<T> = {
|
|
|
30
39
|
} | {
|
|
31
40
|
kind: 'error';
|
|
32
41
|
};
|
|
42
|
+
/** A registered read that keeps its rows current as the underlying tables change.
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
33
45
|
interface LiveQuery<T = Record<string, unknown>> {
|
|
46
|
+
/** Returns the rows the query holds right now. */
|
|
34
47
|
getState(): LiveQueryState<T>;
|
|
48
|
+
/** Calls back on each update and returns a function that stops the listener. */
|
|
35
49
|
subscribe(listener: (update: LiveUpdate<T>) => void): () => void;
|
|
50
|
+
/** Ends the query and releases its subscription. */
|
|
36
51
|
close(): Promise<void>;
|
|
37
52
|
}
|
|
53
|
+
/** Settings for one live query.
|
|
54
|
+
* @public
|
|
55
|
+
*/
|
|
38
56
|
interface LiveQueryOptions {
|
|
57
|
+
/** Milliseconds of random delay before a re-read, which spreads the load of many queries reacting at once. */
|
|
39
58
|
rereadJitterMs?: number;
|
|
59
|
+
/** Changes in one transaction above which the query re-reads instead of applying them one by one. */
|
|
40
60
|
maxTransactionChanges?: number;
|
|
41
61
|
}
|
|
42
62
|
|