@serfab/cadre-core 1.7.0 → 1.9.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.
- package/README.md +8 -6
- package/dist/cadre-node.d.ts +527 -206
- package/dist/cadre-node.js +1084 -528
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-authorization.d.ts +2 -2
- package/dist/control-authorization.js +1 -0
- package/dist/control-authorization.js.map +1 -1
- package/dist/control-cohort.d.ts +6 -0
- package/dist/control-cohort.js +6 -0
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +46 -8
- package/dist/control-database.js +97 -18
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +37 -14
- package/dist/control-formation-recorder.js +60 -10
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-read-retry.d.ts +13 -12
- package/dist/control-read-retry.js +14 -12
- package/dist/control-read-retry.js.map +1 -1
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +67 -5
- package/dist/control-schema.js.map +1 -1
- package/dist/control-stream.d.ts +9 -1
- package/dist/control-stream.js +24 -1
- package/dist/control-stream.js.map +1 -1
- package/dist/control-write-retry.d.ts +12 -2
- package/dist/control-write-retry.js +13 -2
- package/dist/control-write-retry.js.map +1 -1
- package/dist/delegate-admission.d.ts +11 -8
- package/dist/delegate-admission.js +19 -11
- package/dist/delegate-admission.js.map +1 -1
- package/dist/diagnostics/connection-path.d.ts +0 -7
- package/dist/diagnostics/connection-path.js +0 -7
- package/dist/diagnostics/connection-path.js.map +1 -1
- package/dist/formation-approval.d.ts +7 -0
- package/dist/formation-approval.js +9 -3
- package/dist/formation-approval.js.map +1 -1
- package/dist/fs-atomic.d.ts +11 -2
- package/dist/fs-atomic.js +13 -3
- package/dist/fs-atomic.js.map +1 -1
- package/dist/hibernation-manager.d.ts +111 -8
- package/dist/hibernation-manager.js +234 -49
- package/dist/hibernation-manager.js.map +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +25 -20
- package/dist/index.js.map +1 -1
- package/dist/joined-strand-store.d.ts +90 -25
- package/dist/joined-strand-store.js +223 -55
- package/dist/joined-strand-store.js.map +1 -1
- package/dist/key-store-file.js +14 -5
- package/dist/key-store-file.js.map +1 -1
- package/dist/link-budget.d.ts +367 -69
- package/dist/link-budget.js +375 -72
- package/dist/link-budget.js.map +1 -1
- package/dist/membership-connection-gater.d.ts +30 -43
- package/dist/membership-connection-gater.js +31 -42
- package/dist/membership-connection-gater.js.map +1 -1
- package/dist/node-local-snapshot.d.ts +6 -4
- package/dist/node-local-snapshot.js +7 -3
- package/dist/node-local-snapshot.js.map +1 -1
- package/dist/peer-dial.d.ts +24 -4
- package/dist/peer-dial.js +74 -5
- package/dist/peer-dial.js.map +1 -1
- package/dist/peer-join-backfill.d.ts +2 -10
- package/dist/peer-join-backfill.js +8 -8
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/push-fanout.d.ts +6 -0
- package/dist/push-fanout.js +6 -0
- package/dist/push-fanout.js.map +1 -1
- package/dist/relay-reservation.d.ts +3 -1
- package/dist/relay-reservation.js +3 -1
- package/dist/relay-reservation.js.map +1 -1
- package/dist/relay-server.d.ts +79 -0
- package/dist/relay-server.js +74 -0
- package/dist/relay-server.js.map +1 -0
- package/dist/seed-bootstrap.d.ts +57 -4
- package/dist/seed-bootstrap.js +107 -83
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/storage-scope.d.ts +33 -17
- package/dist/storage-scope.js +44 -23
- package/dist/storage-scope.js.map +1 -1
- package/dist/strand-addr-protocol.d.ts +58 -21
- package/dist/strand-addr-protocol.js +133 -85
- package/dist/strand-addr-protocol.js.map +1 -1
- package/dist/strand-database.d.ts +20 -2
- package/dist/strand-database.js +42 -5
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-first-sync-gate.d.ts +59 -21
- package/dist/strand-first-sync-gate.js +58 -19
- package/dist/strand-first-sync-gate.js.map +1 -1
- package/dist/strand-formation-deadlines.d.ts +151 -0
- package/dist/strand-formation-deadlines.js +171 -0
- package/dist/strand-formation-deadlines.js.map +1 -0
- package/dist/strand-formation-manager.d.ts +63 -30
- package/dist/strand-formation-manager.js +67 -41
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +45 -46
- package/dist/strand-formation-protocol.js +62 -126
- package/dist/strand-formation-protocol.js.map +1 -1
- package/dist/strand-fret-addrs.d.ts +54 -0
- package/dist/strand-fret-addrs.js +108 -0
- package/dist/strand-fret-addrs.js.map +1 -0
- package/dist/strand-instance-manager.d.ts +122 -44
- package/dist/strand-instance-manager.js +270 -114
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +6 -0
- package/dist/strand-membership-writer.js +11 -0
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/strand-network-state-file.d.ts +12 -0
- package/dist/strand-network-state-file.js +38 -0
- package/dist/strand-network-state-file.js.map +1 -0
- package/dist/strand-network-state.d.ts +111 -0
- package/dist/strand-network-state.js +191 -0
- package/dist/strand-network-state.js.map +1 -0
- package/dist/strand-revocation-enforcer.js +2 -1
- package/dist/strand-revocation-enforcer.js.map +1 -1
- package/dist/strand-solicitation.d.ts +36 -20
- package/dist/strand-solicitation.js +4 -4
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-wake-protocol.d.ts +80 -23
- package/dist/strand-wake-protocol.js +89 -64
- package/dist/strand-wake-protocol.js.map +1 -1
- package/dist/types.d.ts +148 -61
- package/dist/types.js +4 -3
- package/dist/types.js.map +1 -1
- package/package.json +11 -10
- package/src/cadre-node.ts +8400 -7776
- package/src/control-authorization.ts +2 -1
- package/src/control-cohort.ts +6 -0
- package/src/control-database.ts +122 -18
- package/src/control-formation-recorder.ts +354 -305
- package/src/control-read-retry.ts +14 -12
- package/src/control-schema.ts +67 -5
- package/src/control-stream.ts +25 -1
- package/src/control-write-retry.ts +13 -2
- package/src/delegate-admission.ts +23 -13
- package/src/diagnostics/connection-path.ts +0 -7
- package/src/formation-approval.ts +610 -604
- package/src/fs-atomic.ts +14 -4
- package/src/hibernation-manager.ts +638 -437
- package/src/index.ts +43 -65
- package/src/joined-strand-store.ts +247 -57
- package/src/key-store-file.ts +14 -5
- package/src/link-budget.ts +393 -74
- package/src/membership-connection-gater.ts +31 -45
- package/src/node-local-snapshot.ts +12 -7
- package/src/peer-dial.ts +81 -7
- package/src/peer-join-backfill.ts +10 -9
- package/src/push-fanout.ts +6 -0
- package/src/relay-reservation.ts +3 -1
- package/src/relay-server.ts +98 -0
- package/src/seed-bootstrap.ts +133 -91
- package/src/storage-scope.ts +44 -23
- package/src/strand-addr-protocol.ts +547 -458
- package/src/strand-database.ts +287 -242
- package/src/strand-first-sync-gate.ts +58 -19
- package/src/strand-formation-deadlines.ts +227 -0
- package/src/strand-formation-manager.ts +700 -647
- package/src/strand-formation-protocol.ts +106 -154
- package/src/strand-fret-addrs.ts +145 -0
- package/src/strand-instance-manager.ts +307 -140
- package/src/strand-membership-writer.ts +12 -0
- package/src/strand-network-state-file.ts +40 -0
- package/src/strand-network-state.ts +243 -0
- package/src/strand-revocation-enforcer.ts +2 -1
- package/src/strand-solicitation.ts +519 -500
- package/src/strand-wake-protocol.ts +401 -355
- package/src/types.ts +150 -61
- package/dist/strand-peer-book-file.d.ts +0 -12
- package/dist/strand-peer-book-file.js +0 -37
- package/dist/strand-peer-book-file.js.map +0 -1
- package/dist/strand-peer-book-protocol.d.ts +0 -159
- package/dist/strand-peer-book-protocol.js +0 -360
- package/dist/strand-peer-book-protocol.js.map +0 -1
- package/dist/strand-peer-book-swap.d.ts +0 -104
- package/dist/strand-peer-book-swap.js +0 -284
- package/dist/strand-peer-book-swap.js.map +0 -1
- package/dist/strand-peer-book.d.ts +0 -159
- package/dist/strand-peer-book.js +0 -354
- package/dist/strand-peer-book.js.map +0 -1
- package/dist/strand-peer-observer.d.ts +0 -88
- package/dist/strand-peer-observer.js +0 -180
- package/dist/strand-peer-observer.js.map +0 -1
- package/src/strand-peer-book-file.ts +0 -39
- package/src/strand-peer-book-protocol.ts +0 -463
- package/src/strand-peer-book-swap.ts +0 -338
- package/src/strand-peer-book.ts +0 -468
- package/src/strand-peer-observer.ts +0 -235
package/src/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ConnectionGater, Libp2p, PeerId, PrivateKey } from '@libp2p/interface';
|
|
2
|
+
import type { CircuitRelayServerInit } from '@libp2p/circuit-relay-v2';
|
|
2
3
|
import type { IRawStorage, Libp2pConnectionMonitorInit, Libp2pTransports, NoiseCryptoInterface } from '@optimystic/db-p2p';
|
|
3
4
|
import type { IPeerNetwork, IRepo } from '@optimystic/db-core';
|
|
4
5
|
import type { PeerJoinBackfillConfig } from './peer-join-backfill.js';
|
|
@@ -10,7 +11,7 @@ import type { SeedTrustPolicy } from './seed-trust-policy.js';
|
|
|
10
11
|
import type { KeyStore, KeyId } from './key-store.js';
|
|
11
12
|
import type { TrustedOwnerStore, TrustSource } from './trusted-owner-store.js';
|
|
12
13
|
import type { BootstrapPeerStore } from './bootstrap-peer-store.js';
|
|
13
|
-
import type {
|
|
14
|
+
import type { StrandNetworkStateStore } from './strand-network-state.js';
|
|
14
15
|
import type { EnrolledMachineStore } from './enrolled-machine-store.js';
|
|
15
16
|
import type { JoinedStrandStore } from './joined-strand-store.js';
|
|
16
17
|
import type { PushNotifier } from './push-notifier.js';
|
|
@@ -123,10 +124,12 @@ export const HIBERNATION_TIMEOUTS: Record<LatencyHint, HibernationTimeouts> = {
|
|
|
123
124
|
* Factory functions are useful for creating per-scope storage instances.
|
|
124
125
|
*
|
|
125
126
|
* **The argument is an opaque scope key.** Use it directly as a file name, directory
|
|
126
|
-
* name or database name: every key stays within `[
|
|
127
|
-
* needed and none should be assumed
|
|
128
|
-
*
|
|
129
|
-
*
|
|
127
|
+
* name or database name: every key stays within `[a-z0-9._-]`, so no escaping is
|
|
128
|
+
* needed and none should be assumed, and two different keys are two different names
|
|
129
|
+
* even on a filesystem that ignores case (Windows, macOS). Do not parse it;
|
|
130
|
+
* `controlStorageScope` / `isControlStorageScope` (`storage-scope.ts`) are the supported
|
|
131
|
+
* way to mint and recognize the control key. The control key holds the charset by
|
|
132
|
+
* lowercase hex encoding;
|
|
130
133
|
* a strand's key — its strand id, which may have replicated in from another node in
|
|
131
134
|
* the party — holds it because `StrandInstanceManager.startStrand` runs
|
|
132
135
|
* `assertStrandScopeKey` on every launch and refuses a strand that fails it.
|
|
@@ -171,7 +174,7 @@ export interface StorageConfig {
|
|
|
171
174
|
* the single-instance form cannot serve more than one party.
|
|
172
175
|
*
|
|
173
176
|
* The `scope` a factory receives is an opaque key already safe as a path or
|
|
174
|
-
* database-name segment (always within `[
|
|
177
|
+
* database-name segment (always within `[a-z0-9._-]`), so each example below
|
|
175
178
|
* interpolates it directly.
|
|
176
179
|
*
|
|
177
180
|
* For Node.js environments, use FileRawStorage from @optimystic/db-p2p-storage-fs:
|
|
@@ -319,7 +322,8 @@ export interface NetworkConfig {
|
|
|
319
322
|
* It buys a node that BOOTS, not a node that boots fast: `start()` still waits
|
|
320
323
|
* out that first attempt, which costs the drive's whole timeout
|
|
321
324
|
* (`DEFAULT_RELAY_RESERVE_TIMEOUT_MS`, four link round trips at
|
|
322
|
-
* {@link linkRoundTripMs} —
|
|
325
|
+
* {@link linkRoundTripMs} plus two admission decisions — 18 s at its default) against a relay
|
|
326
|
+
* that is unreachable
|
|
323
327
|
* rather than merely refusing (`relay-reservation.ts` polls to the deadline, in
|
|
324
328
|
* case libp2p's own discovery lands a reservation independently).
|
|
325
329
|
*
|
|
@@ -342,6 +346,31 @@ export interface NetworkConfig {
|
|
|
342
346
|
* better connectivity and uptime), false for transaction profile nodes.
|
|
343
347
|
*/
|
|
344
348
|
enableRelay?: boolean;
|
|
349
|
+
/**
|
|
350
|
+
* Settings for this machine's circuit-relay SERVER, handed to `@libp2p/circuit-relay-v2`'s
|
|
351
|
+
* `circuitRelayServer(...)` (through db-p2p's `NodeOptions.relayServerInit`) on the control
|
|
352
|
+
* node and on every strand node. Only meaningful while {@link enableRelay} is on.
|
|
353
|
+
*
|
|
354
|
+
* Omitted, a party-run relay FORWARDS WITHOUT LIMIT: `reservations.applyDefaultLimit` is
|
|
355
|
+
* `false`, where libp2p's own default caps every relayed connection at 128 KiB or two
|
|
356
|
+
* minutes and resets it — which cut off any database sync or chat history forwarded
|
|
357
|
+
* through a party's own always-on machine. The store also holds
|
|
358
|
+
* `PARTY_RELAY_MAX_RESERVATIONS` (128) reservations instead of libp2p's 15, and each lives
|
|
359
|
+
* `PARTY_RELAY_RESERVATION_TTL_MS` (2 h) unrefreshed. See `relay-server.ts`.
|
|
360
|
+
*
|
|
361
|
+
* A value is MERGED over those defaults, not substituted for them: `reservations` key by
|
|
362
|
+
* key, every other top-level key as given. Setting only `reservations.maxReservations`
|
|
363
|
+
* keeps the limit off; `reservations: { applyDefaultLimit: true }` is how to turn libp2p's
|
|
364
|
+
* cap back on.
|
|
365
|
+
*
|
|
366
|
+
* The accepted tradeoff of the unlimited default: once a slot is granted, nothing caps what
|
|
367
|
+
* is forwarded through it, and a holder that keeps refreshing keeps it indefinitely — the
|
|
368
|
+
* 2 h lifetime only reclaims a slot whose holder went away. On the control node a peer it
|
|
369
|
+
* cannot place as a party member is bounded by COUNT ({@link unauthorizedRelayReservationCap}).
|
|
370
|
+
* A strand node's relay server has no such budget (its peers are cross-party by design), so
|
|
371
|
+
* any peer that reaches it is bounded only by `maxReservations`.
|
|
372
|
+
*/
|
|
373
|
+
relayServerInit?: CircuitRelayServerInit;
|
|
345
374
|
/**
|
|
346
375
|
* Cap on concurrent circuit-relay reservations this node's relay server grants to
|
|
347
376
|
* peers it cannot (yet) recognize as authorized members — the boot-ordering window
|
|
@@ -413,16 +442,21 @@ export interface NetworkConfig {
|
|
|
413
442
|
* How long ONE cohort peer gets to answer ONE read-path request, in milliseconds, for the
|
|
414
443
|
* control node and every strand node — as {@link connectionMonitor} is, and for the same
|
|
415
444
|
* reason: the setting describes the LINK, and a phone's control node and its strand nodes
|
|
416
|
-
* ride the same one. Omitted
|
|
417
|
-
*
|
|
445
|
+
* ride the same one. Omitted, the deadline is DERIVED from {@link linkRoundTripMs}: one
|
|
446
|
+
* request and its answer over an open circuit costs two link round trips, so 7 000 ms at the
|
|
447
|
+
* default declaration (`cohortReadDeadlineMs` in `link-budget.ts`; the plugin's
|
|
448
|
+
* {@link COHORT_READ_DEADLINE_MS} is the same number). Optimystic's own default is 1000 ms.
|
|
418
449
|
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
450
|
+
* Set this only to break the derivation on purpose: an explicit value wins over whatever
|
|
451
|
+
* {@link linkRoundTripMs} would derive, so a deployment that is all LAN can make a departed
|
|
452
|
+
* peer stop holding up a read sooner without declaring a faster link (which would also
|
|
453
|
+
* shorten the dial budgets). A deployment on a slower link should raise
|
|
454
|
+
* {@link linkRoundTripMs} instead, which moves this and every dial budget together. The
|
|
455
|
+
* cost of a larger value is that a peer which is truly gone holds a read of a block missing
|
|
456
|
+
* locally for that long before the read is declined and retried, and a joining machine's
|
|
457
|
+
* first sync runs several such consults — so a change here should be weighed against
|
|
458
|
+
* {@link CadreNodeConfig.strandFirstSync}'s budget. The derivation, its history and what it
|
|
459
|
+
* costs are on {@link COHORT_READ_DEADLINE_MS}.
|
|
426
460
|
*
|
|
427
461
|
* Handed to db-p2p's `clusterPolicy.cohortQueryTimeoutMs` unchanged and NOT re-validated
|
|
428
462
|
* here. Optimystic refuses a value that is not a finite number above zero, or is above its
|
|
@@ -441,11 +475,14 @@ export interface NetworkConfig {
|
|
|
441
475
|
* This is NOT a timeout. It is the one stated assumption that cadre's own dial and
|
|
442
476
|
* reservation deadlines are DERIVED from, each by the number of round trips that operation
|
|
443
477
|
* was measured to cost: a peer-join catch-up's dial to one peer, its push response, one relay
|
|
444
|
-
* reservation drive, the control-cohort dial budgets, and
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
478
|
+
* reservation drive, the control-cohort dial budgets, and the per-peer cohort read deadline
|
|
479
|
+
* ({@link cohortQueryTimeoutMs}, unless set explicitly). It is also handed to Optimystic
|
|
480
|
+
* (`NodeOptions.linkRoundTripMs`), default included, which derives its own deadlines from it:
|
|
481
|
+
* its request dials and responses, its block pushes, and libp2p's `dialTimeout` and
|
|
482
|
+
* `inboundUpgradeTimeout` on every node. Reaching another machine through a
|
|
483
|
+
* relay costs a fixed number of exchanges, so a deadline written as milliseconds has a link
|
|
484
|
+
* speed above which it can never open a connection — which is the defect this declaration
|
|
485
|
+
* exists to make impossible to reintroduce one budget at a time. The counts, the measurement behind them,
|
|
449
486
|
* and what still fails at the supported link are in `link-budget.ts`.
|
|
450
487
|
*
|
|
451
488
|
* The default covers the slowest link sereus supports, a 3-second round trip through a relay.
|
|
@@ -459,7 +496,8 @@ export interface NetworkConfig {
|
|
|
459
496
|
* Refused where the libp2p node is built — inside `CadreNode.start()` for the control
|
|
460
497
|
* network, inside `CadreNode.addStrand` for a strand — if it is not a finite number above
|
|
461
498
|
* zero, because every consumer multiplies it into a deadline where a zero means "give up at
|
|
462
|
-
* once" and a `NaN` means "never".
|
|
499
|
+
* once" and a `NaN` means "never". Optimystic refuses, in the same place, a value above its
|
|
500
|
+
* `MAX_LINK_ROUND_TRIP_MS` (about 1.66 days).
|
|
463
501
|
*/
|
|
464
502
|
linkRoundTripMs?: number;
|
|
465
503
|
/**
|
|
@@ -530,14 +568,19 @@ export interface NetworkConfig {
|
|
|
530
568
|
* {@link dialTimeoutMs}. Each address is dialed on its own under this limit,
|
|
531
569
|
* so an address that never answers cannot use up the time the peer's other
|
|
532
570
|
* addresses needed. Defaults to
|
|
533
|
-
* {@link DEFAULT_CONTROL_COHORT_PER_ADDRESS_DIAL_TIMEOUT_MS}.
|
|
571
|
+
* {@link DEFAULT_CONTROL_COHORT_PER_ADDRESS_DIAL_TIMEOUT_MS}. A value given
|
|
572
|
+
* here replaces that whole derived budget, including its allowance for the
|
|
573
|
+
* called machine's admission decision (`relayedDialBudgetMs`).
|
|
534
574
|
*/
|
|
535
575
|
perAddressDialTimeoutMs?: number;
|
|
536
576
|
/**
|
|
537
|
-
* How
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
577
|
+
* How long a running strand waits, after a sibling answers its strand-addr
|
|
578
|
+
* RPC, before asking that sibling again for its strand-network addresses — a
|
|
579
|
+
* step of the reconcile pass, scheduled per (sibling, strand). A sibling that
|
|
580
|
+
* did not answer is retried sooner, on `STRAND_PEER_ADDR_RETRY_MS` (or this
|
|
581
|
+
* interval, when it is set shorter). Defaults to
|
|
582
|
+
* `STRAND_PEER_ADDR_REFRESH_MS` (10 min); must stay well under the peerStore's
|
|
583
|
+
* one-hour address expiry.
|
|
541
584
|
*/
|
|
542
585
|
strandAddrRefreshMs?: number;
|
|
543
586
|
};
|
|
@@ -656,9 +699,10 @@ export interface ControlNetworkConfig {
|
|
|
656
699
|
*
|
|
657
700
|
* The two `*ClusterPolicy` BUILDERS are the same objects with the block-repair
|
|
658
701
|
* corroboration yardstick declared from the machines enrolled in this party
|
|
659
|
-
* ({@link resolveRepairYardstick}) and, if the host set one
|
|
660
|
-
* deadline in place of {@link COHORT_READ_DEADLINE_MS}
|
|
661
|
-
*
|
|
702
|
+
* ({@link resolveRepairYardstick}) and, if the host set one or declared its link, a
|
|
703
|
+
* per-peer read deadline in place of {@link COHORT_READ_DEADLINE_MS}
|
|
704
|
+
* (`declaredCohortReadDeadlineMs` in `link-budget.ts` settles which). Both arrive in one
|
|
705
|
+
* named declarations object, because both are plain numbers meaning unrelated things;
|
|
662
706
|
* declaring neither returns the frozen base constant unchanged. A network picks the
|
|
663
707
|
* derived numbers up when its libp2p node is built, which for a strand is every wake
|
|
664
708
|
* from hibernation.
|
|
@@ -722,6 +766,22 @@ export interface CadreNodeConfig {
|
|
|
722
766
|
/** Which strands to participate in */
|
|
723
767
|
strandFilter?: StrandFilter;
|
|
724
768
|
|
|
769
|
+
/**
|
|
770
|
+
* Run every strand {@link strandFilter} admits, including ones no app on this machine
|
|
771
|
+
* has claimed with `addStrand`, as a **storage replica**: the strand's own libp2p node,
|
|
772
|
+
* storage and `Strand` membership schema, storing and serving its blocks, without the
|
|
773
|
+
* app's schema (no sApp config needed, none of the app's code or schema runs). This is
|
|
774
|
+
* how an always-on machine keeps a copy of every shared workspace its party runs, so a
|
|
775
|
+
* lost phone loses nothing that had reached it.
|
|
776
|
+
*
|
|
777
|
+
* The strand is still announced as `strand:discovered` (once) and stays in
|
|
778
|
+
* `getDiscoveredStrands()` until an app claims it. A replica is always a joiner.
|
|
779
|
+
*
|
|
780
|
+
* Default: `profile === 'storage'` — always-on machines host replicas, phones
|
|
781
|
+
* (`'transaction'`) keep today's announce-only behaviour.
|
|
782
|
+
*/
|
|
783
|
+
hostUnclaimedStrands?: boolean;
|
|
784
|
+
|
|
725
785
|
/** Storage configuration (only for storage profile) */
|
|
726
786
|
storage?: StorageConfig;
|
|
727
787
|
|
|
@@ -950,11 +1010,12 @@ export interface CadreNodeConfig {
|
|
|
950
1010
|
};
|
|
951
1011
|
|
|
952
1012
|
/**
|
|
953
|
-
* Node-local record of the strands this node joined from ANOTHER party
|
|
954
|
-
* `joined-strand-store.ts`): id,
|
|
955
|
-
*
|
|
956
|
-
* not
|
|
957
|
-
*
|
|
1013
|
+
* Node-local record of the strands this node joined from ANOTHER party and has not yet
|
|
1014
|
+
* published to the party-wide `JoinedStrand` table (see `joined-strand-store.ts`): id,
|
|
1015
|
+
* type and the closed strand's read secret, recorded by `formStrand` and by a joining
|
|
1016
|
+
* (not `founder: true`) `addStrand` whose row this party's control database does not
|
|
1017
|
+
* name, offered on every start as `strand:discovered` until an owner machine's
|
|
1018
|
+
* reconcile pass publishes it — so an embedding app keeps no list of its own.
|
|
958
1019
|
*
|
|
959
1020
|
* Absent ⇒ a `KeyStoreJoinedStrandStore` over {@link keyStore} when one is
|
|
960
1021
|
* configured (the record carries a secret, and the KeyStore is where every platform
|
|
@@ -969,32 +1030,29 @@ export interface CadreNodeConfig {
|
|
|
969
1030
|
};
|
|
970
1031
|
|
|
971
1032
|
/**
|
|
972
|
-
* Node-local strand
|
|
973
|
-
*
|
|
974
|
-
*
|
|
975
|
-
*
|
|
976
|
-
*
|
|
977
|
-
*
|
|
978
|
-
*
|
|
979
|
-
*
|
|
980
|
-
*
|
|
981
|
-
*
|
|
982
|
-
*
|
|
983
|
-
*
|
|
984
|
-
*
|
|
985
|
-
*
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
* `DurableSlot` and inject `PersistentStrandPeerBookStore.open(slot, partyId)`.
|
|
989
|
-
*/
|
|
990
|
-
strandPeers?: {
|
|
1033
|
+
* Node-local strand network state (see `strand-network-state.ts`): per strand, the
|
|
1034
|
+
* state Optimystic's db-p2p saves for the strand's libp2p node — its FRET routing
|
|
1035
|
+
* table, each entry carrying the peer's signed address record. A strand node reads
|
|
1036
|
+
* it back when it is built and re-imports the table, so a restarted machine already
|
|
1037
|
+
* holds addresses for the strand peers it was talking to (gotchoices/sereus#18).
|
|
1038
|
+
* Sibling of {@link bootstrapPeers} — same NON-replicated, per-party,
|
|
1039
|
+
* injected-backend shape — and, like it, nothing here is trust-bearing: FRET
|
|
1040
|
+
* verifies every record at import.
|
|
1041
|
+
*
|
|
1042
|
+
* Absent ⇒ an in-memory store is created at start() (ephemeral: a restarted process
|
|
1043
|
+
* starts every strand with an empty routing table). Every reference embedder
|
|
1044
|
+
* injects a durable backend over the same slot kind as its bootstrap-peer store. A
|
|
1045
|
+
* new platform needs no new store class: supply a `DurableSlot` and inject
|
|
1046
|
+
* `PersistentStrandNetworkStateStore.open(slot, partyId)`.
|
|
1047
|
+
*/
|
|
1048
|
+
strandNetworkState?: {
|
|
991
1049
|
/**
|
|
992
|
-
* Injected store instance — e.g. a `
|
|
993
|
-
* Node-only subpath `@serfab/cadre-core/strand-
|
|
1050
|
+
* Injected store instance — e.g. a `FileStrandNetworkStateStore` from the
|
|
1051
|
+
* Node-only subpath `@serfab/cadre-core/strand-network-state-file`, persisted in
|
|
994
1052
|
* the node's state directory. Its `partyId` must match
|
|
995
1053
|
* `controlNetwork.partyId`; start() fails closed on a mismatch.
|
|
996
1054
|
*/
|
|
997
|
-
store?:
|
|
1055
|
+
store?: StrandNetworkStateStore;
|
|
998
1056
|
};
|
|
999
1057
|
|
|
1000
1058
|
/**
|
|
@@ -1082,6 +1140,12 @@ export interface StrandInstance {
|
|
|
1082
1140
|
|
|
1083
1141
|
/** Activity tracking */
|
|
1084
1142
|
connectedPeers: number;
|
|
1143
|
+
/**
|
|
1144
|
+
* When the strand last saw activity: the app's (`recordStrandActivity`), a requested wake
|
|
1145
|
+
* (`wakeStrand`), or a peer delivering a gated joiner's `Strand.Header`. Always a fresh
|
|
1146
|
+
* `Date`. Bringing the runtime up is NOT activity — a check-in window decides whether to
|
|
1147
|
+
* re-hibernate by whether this changed since before its resume.
|
|
1148
|
+
*/
|
|
1085
1149
|
lastActivity: Date;
|
|
1086
1150
|
nextCheckIn?: Date;
|
|
1087
1151
|
|
|
@@ -1508,6 +1572,12 @@ export interface CadreNodeEvents {
|
|
|
1508
1572
|
* be idempotent (guard on an in-flight set, not only on
|
|
1509
1573
|
* `getStrands().has(id)` — the strand manager tracks an instance only once
|
|
1510
1574
|
* `addStrand` has resolved).
|
|
1575
|
+
*
|
|
1576
|
+
* On a node that hosts storage replicas ({@link CadreNodeConfig.hostUnclaimedStrands},
|
|
1577
|
+
* the default for `profile: 'storage'`) the event still fires once, and the node launches
|
|
1578
|
+
* the strand as a replica right after it — so there `getStrands().has(id)` soon turns
|
|
1579
|
+
* true for a strand no app has claimed; an unclaimed instance has no `sAppInfo`. A
|
|
1580
|
+
* launch that fails is retried by the watcher without a second `strand:discovered`.
|
|
1511
1581
|
*/
|
|
1512
1582
|
'strand:discovered': { strandId: string; strand: StrandRow };
|
|
1513
1583
|
'control:connected': void;
|
|
@@ -1886,7 +1956,11 @@ export interface WakeRequest {
|
|
|
1886
1956
|
export interface WakeAck {
|
|
1887
1957
|
/** Whether the receiver honored the wake (member + participated strand). */
|
|
1888
1958
|
accepted: boolean;
|
|
1889
|
-
/**
|
|
1959
|
+
/**
|
|
1960
|
+
* The strand's status when the receiver accepted the wake (present when `accepted`). The
|
|
1961
|
+
* receiver replies before the wake runs, so `hibernating` or `idle` here means "a wake was
|
|
1962
|
+
* started", not "the strand is now up".
|
|
1963
|
+
*/
|
|
1890
1964
|
status?: StrandStatus;
|
|
1891
1965
|
/** Reason for rejection (non-member, unknown strand, malformed frame). */
|
|
1892
1966
|
reason?: string;
|
|
@@ -1915,17 +1989,32 @@ export interface StrandAddrRequest {
|
|
|
1915
1989
|
delegatePeerId?: string;
|
|
1916
1990
|
}
|
|
1917
1991
|
|
|
1992
|
+
/**
|
|
1993
|
+
* How a strand-addr responder handled a {@link StrandAddrRequest}. Carried so the
|
|
1994
|
+
* asker can tell "I have nothing" from "I could not answer" — the two need
|
|
1995
|
+
* different retry timing, and an empty address list alone cannot say which.
|
|
1996
|
+
*
|
|
1997
|
+
* - `ok` — looked up; `multiaddrs` is the truth, possibly empty (strand not running here).
|
|
1998
|
+
* - `unavailable` — the responder could not answer: over its concurrency cap, the
|
|
1999
|
+
* request was unreadable, or its own lookup threw (e.g. a control-database read failed).
|
|
2000
|
+
* - `refused` — the requester is not an authorized member in the responder's
|
|
2001
|
+
* current view (possibly because its `CadrePeer` row has not replicated there yet);
|
|
2002
|
+
* any `delegatePeerId` it carried was NOT recorded.
|
|
2003
|
+
*/
|
|
2004
|
+
export type StrandAddrStatus = 'ok' | 'unavailable' | 'refused';
|
|
2005
|
+
|
|
1918
2006
|
/**
|
|
1919
2007
|
* Response to a {@link StrandAddrRequest}, carrying the responder's strand-node
|
|
1920
2008
|
* multiaddrs, returned on the same stream.
|
|
1921
2009
|
*/
|
|
1922
2010
|
export interface StrandAddrResponse {
|
|
1923
|
-
/**
|
|
2011
|
+
/** How the responder handled the request; a reply without one is malformed. */
|
|
2012
|
+
status: StrandAddrStatus;
|
|
2013
|
+
/** Echoes the requested strand id; always empty on an `unavailable` reply. */
|
|
1924
2014
|
strandId: string;
|
|
1925
2015
|
/**
|
|
1926
2016
|
* Dialable strand-network multiaddr strings (signaling/`p2p-circuit` first);
|
|
1927
|
-
* empty
|
|
1928
|
-
* strand, or the exchange failed.
|
|
2017
|
+
* empty unless `status` is `ok` and the responder runs that strand.
|
|
1929
2018
|
*/
|
|
1930
2019
|
multiaddrs: string[];
|
|
1931
2020
|
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { StrandPeerBookOptions, StrandPeerBookStore } from './strand-peer-book.js';
|
|
2
|
-
/**
|
|
3
|
-
* File-backed {@link StrandPeerBookStore}. Open via {@link open}, which loads the
|
|
4
|
-
* existing file and returns the cross-platform store over it; an absent, corrupt,
|
|
5
|
-
* or wrong-party file is a cold start (empty book) and structurally junk or
|
|
6
|
-
* aged-out entries are dropped, while a present-but-unreadable file throws. Those
|
|
7
|
-
* rules and their reasoning live on `NodeLocalSnapshot.open`.
|
|
8
|
-
*/
|
|
9
|
-
export declare const FileStrandPeerBookStore: {
|
|
10
|
-
/** Load (or cold-start) the party's strand peer book from a file in `dir`. */
|
|
11
|
-
open(dir: string, partyId: string, options?: StrandPeerBookOptions): Promise<StrandPeerBookStore>;
|
|
12
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Node-only file-backed {@link StrandPeerBookStore}: one JSON file per party under
|
|
3
|
-
* a configured directory (the node's state directory — `cadre-cli` passes
|
|
4
|
-
* `ResolvedConfig.nodeStateDir`), holding the node-local, non-replicated strand
|
|
5
|
-
* peer book (the strand peers this node has met, with their last-known addresses).
|
|
6
|
-
*
|
|
7
|
-
* Nothing but the file itself lives here: the envelope, load policy, per-entry
|
|
8
|
-
* validation, the merge rule and the serialised snapshot writes are cross-platform
|
|
9
|
-
* in `PersistentStrandPeerBookStore` / `node-local-snapshot.ts`, and the file is a
|
|
10
|
-
* `FileDurableSlot`. This module exists only so the `node:fs` edge stays out of the
|
|
11
|
-
* package's cross-platform default entry (`./index.js`) — import it from the
|
|
12
|
-
* dedicated subpath instead:
|
|
13
|
-
*
|
|
14
|
-
* ```ts
|
|
15
|
-
* import { FileStrandPeerBookStore } from '@serfab/cadre-core/strand-peer-book-file';
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* Same isolation pattern as `bootstrap-peer-store-file.ts` / `key-store-file.ts`.
|
|
19
|
-
*/
|
|
20
|
-
import { FileDurableSlot } from './file-durable-slot.js';
|
|
21
|
-
import { PersistentStrandPeerBookStore } from './strand-peer-book.js';
|
|
22
|
-
/** Base name of the store file: `<dir>/strand-peers.<encoded partyId>.json`. */
|
|
23
|
-
const SLOT_NAME = 'strand-peers';
|
|
24
|
-
/**
|
|
25
|
-
* File-backed {@link StrandPeerBookStore}. Open via {@link open}, which loads the
|
|
26
|
-
* existing file and returns the cross-platform store over it; an absent, corrupt,
|
|
27
|
-
* or wrong-party file is a cold start (empty book) and structurally junk or
|
|
28
|
-
* aged-out entries are dropped, while a present-but-unreadable file throws. Those
|
|
29
|
-
* rules and their reasoning live on `NodeLocalSnapshot.open`.
|
|
30
|
-
*/
|
|
31
|
-
export const FileStrandPeerBookStore = {
|
|
32
|
-
/** Load (or cold-start) the party's strand peer book from a file in `dir`. */
|
|
33
|
-
async open(dir, partyId, options) {
|
|
34
|
-
return PersistentStrandPeerBookStore.open(new FileDurableSlot(dir, SLOT_NAME, partyId), partyId, options);
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
//# sourceMappingURL=strand-peer-book-file.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"strand-peer-book-file.js","sourceRoot":"","sources":["../src/strand-peer-book-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AAGtE,gFAAgF;AAChF,MAAM,SAAS,GAAG,cAAc,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACtC,8EAA8E;IAC9E,KAAK,CAAC,IAAI,CAAC,GAAW,EAAE,OAAe,EAAE,OAA+B;QACvE,OAAO,6BAA6B,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3G,CAAC;CACD,CAAC"}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import type { Connection, Libp2p, PrivateKey } from '@libp2p/interface';
|
|
2
|
-
/** Protocol id of the strand peer book swap, registered on every running strand node. */
|
|
3
|
-
export declare const STRAND_PEER_BOOK_PROTOCOL = "/sereus/strand-peers/1.0.0";
|
|
4
|
-
/** Version tag inside every signed payload, so a later payload shape cannot verify as this one. */
|
|
5
|
-
export declare const SIGNED_STRAND_PEER_ENTRY_VERSION = 1;
|
|
6
|
-
/**
|
|
7
|
-
* How far ahead of the receiver's clock a signed entry's `issuedAt` may be. Skew
|
|
8
|
-
* between honest machines is seconds; a stamp further ahead than this is a broken
|
|
9
|
-
* clock or an attempt to pin an entry, and is rejected rather than held.
|
|
10
|
-
*/
|
|
11
|
-
export declare const STRAND_PEER_ISSUED_AT_SKEW_MS: number;
|
|
12
|
-
/**
|
|
13
|
-
* Cap on one frame's bytes. A typical full frame — {@link MAX_STRAND_PEERS} entries of
|
|
14
|
-
* {@link MAX_STRAND_ADDRS} addresses at roughly 150 bytes each, plus a peer id and
|
|
15
|
-
* signature per entry — is about 40 KiB, but nothing bounds a multiaddr's length (a
|
|
16
|
-
* long DNS name can take one past 300 bytes), so a sender trims its forwarded
|
|
17
|
-
* entries to fit ({@link trimBookFrameToFit}) rather than trusting the arithmetic;
|
|
18
|
-
* {@link assertBookFrameFits} is then the invariant check.
|
|
19
|
-
*/
|
|
20
|
-
export declare const MAX_BOOK_FRAME_SIZE: number;
|
|
21
|
-
/**
|
|
22
|
-
* One peer's own signed statement of where it is: a `StrandPeerEntry` without the
|
|
23
|
-
* receiver-local `lastSeenAt`. `addrs` may be empty — a peer that lost its relay
|
|
24
|
-
* reservation truthfully says "not reachable now", and that displaces a stale
|
|
25
|
-
* reachable list at every receiver.
|
|
26
|
-
*/
|
|
27
|
-
export interface SignedStrandPeerEntry {
|
|
28
|
-
/** The signer's strand transport peer id (Ed25519, so it embeds the verifying key). */
|
|
29
|
-
peerId: string;
|
|
30
|
-
/** Bound to `peerId`, signaling-first, at most `MAX_STRAND_ADDRS`. */
|
|
31
|
-
addrs: string[];
|
|
32
|
-
/** Signer's clock, ms. Greater wins between two statements by the same signer. */
|
|
33
|
-
issuedAt: number;
|
|
34
|
-
/** base64url Ed25519 signature over {@link signedStrandPeerEntryPayload}. */
|
|
35
|
-
sig: string;
|
|
36
|
-
}
|
|
37
|
-
/** Request and response of the swap: the sender's signed book for one strand. */
|
|
38
|
-
export interface StrandPeerBookFrame {
|
|
39
|
-
/** Must name the strand whose network the frame arrived on; anything else is refused. */
|
|
40
|
-
strandId: string;
|
|
41
|
-
/** At most {@link MAX_STRAND_PEERS}. */
|
|
42
|
-
entries: SignedStrandPeerEntry[];
|
|
43
|
-
}
|
|
44
|
-
/** The bytes a signed entry's signature covers. */
|
|
45
|
-
export declare function signedStrandPeerEntryPayload(strandId: string, entry: Pick<SignedStrandPeerEntry, 'peerId' | 'addrs' | 'issuedAt'>): Uint8Array;
|
|
46
|
-
/**
|
|
47
|
-
* Sign this node's own entry with its strand transport key. `addrs` must already be
|
|
48
|
-
* bound to the key's peer id (`dialableAddrs` in `strand-peer-observer.ts` does that);
|
|
49
|
-
* a receiver rejects an entry whose addresses do not all attribute to the signer.
|
|
50
|
-
*/
|
|
51
|
-
export declare function signStrandPeerEntry(privateKey: PrivateKey, strandId: string, addrs: string[], issuedAt: number): Promise<SignedStrandPeerEntry>;
|
|
52
|
-
/** Why a received entry was dropped — for logs and for the verification test. */
|
|
53
|
-
export type StrandPeerEntryVerdict = {
|
|
54
|
-
ok: true;
|
|
55
|
-
entry: SignedStrandPeerEntry;
|
|
56
|
-
} | {
|
|
57
|
-
ok: false;
|
|
58
|
-
reason: string;
|
|
59
|
-
};
|
|
60
|
-
/**
|
|
61
|
-
* Verify one received entry: well-formed, an Ed25519 peer id, every address bound to
|
|
62
|
-
* that peer id, `issuedAt` not further ahead of `now` than the skew ceiling, and a
|
|
63
|
-
* valid self-signature. Never throws: junk from a peer is a verdict, not an error.
|
|
64
|
-
*/
|
|
65
|
-
export declare function verifySignedStrandPeerEntry(strandId: string, raw: unknown, now: number): Promise<StrandPeerEntryVerdict>;
|
|
66
|
-
/**
|
|
67
|
-
* Verify a whole received frame. A frame-level violation — the wrong strand, entries
|
|
68
|
-
* not a list, more entries than {@link MAX_STRAND_PEERS} — throws, and the caller
|
|
69
|
-
* refuses the frame. An entry that fails {@link verifySignedStrandPeerEntry} is
|
|
70
|
-
* dropped INDIVIDUALLY with a debug line; its siblings are kept. An entry naming
|
|
71
|
-
* `selfPeerId` is dropped too: this node's own statement is authoritative locally
|
|
72
|
-
* and a remote copy of it is at best redundant. One entry per peer id (the first).
|
|
73
|
-
*/
|
|
74
|
-
export declare function verifyStrandPeerBookFrame(strandId: string, raw: unknown, selfPeerId: string, now: number): Promise<SignedStrandPeerEntry[]>;
|
|
75
|
-
/**
|
|
76
|
-
* The frame with its LAST entries dropped until it encodes within
|
|
77
|
-
* {@link MAX_BOOK_FRAME_SIZE} and {@link MAX_STRAND_PEERS}. Callers list the entries
|
|
78
|
-
* in the order they would rather keep them (the own entry first, then freshest
|
|
79
|
-
* first), so what goes is the stalest forwarded statement, and a frame that fits is
|
|
80
|
-
* returned as is. Dropping an entry is logged: a forwarded peer the recipient never
|
|
81
|
-
* learns of is worth seeing in a trace.
|
|
82
|
-
*/
|
|
83
|
-
export declare function trimBookFrameToFit(frame: StrandPeerBookFrame): StrandPeerBookFrame;
|
|
84
|
-
/**
|
|
85
|
-
* Refuse to send a frame the receiver would reject: over the entry cap, or over
|
|
86
|
-
* {@link MAX_BOOK_FRAME_SIZE} once encoded. A caller that built its frame through
|
|
87
|
-
* {@link trimBookFrameToFit} cannot trip this; it is the invariant check, not a
|
|
88
|
-
* runtime condition to handle.
|
|
89
|
-
*/
|
|
90
|
-
export declare function assertBookFrameFits(frame: StrandPeerBookFrame): void;
|
|
91
|
-
/** What the {@link StrandPeerBookService} receiver needs from its host, injected so it is testable without a node. */
|
|
92
|
-
export interface StrandPeerBookServiceDeps {
|
|
93
|
-
strandId: string;
|
|
94
|
-
/** This strand node's own peer id: a received entry naming it is never merged. */
|
|
95
|
-
selfPeerId: string;
|
|
96
|
-
/**
|
|
97
|
-
* The entries to answer `forPeerId` with — this node's own signed entry plus every
|
|
98
|
-
* signed entry it holds, minus `forPeerId`'s own (the asker knows where it is).
|
|
99
|
-
*/
|
|
100
|
-
localEntries(forPeerId: string): SignedStrandPeerEntry[];
|
|
101
|
-
/** The asker's VERIFIED entries, for the host to merge. Must not throw. */
|
|
102
|
-
onEntries(entries: SignedStrandPeerEntry[], fromPeerId: string): void;
|
|
103
|
-
/** Clock, for tests. Default `Date.now`. */
|
|
104
|
-
now?: () => number;
|
|
105
|
-
/** Default {@link DEFAULT_READ_TIMEOUT_MS}. */
|
|
106
|
-
readTimeoutMs?: number;
|
|
107
|
-
/** Default {@link DEFAULT_MAX_CONCURRENT}. Over it, an empty frame is returned unread. */
|
|
108
|
-
maxConcurrent?: number;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Receiver side: registers the protocol on a strand node and, per inbound frame,
|
|
112
|
-
* verifies and hands over the asker's entries, then answers with the local book.
|
|
113
|
-
* Registered through `node.handle`, so on a closed strand every inbound stream
|
|
114
|
-
* passes the revocation gate first — a revoked machine cannot push addresses into
|
|
115
|
-
* anyone's book.
|
|
116
|
-
*/
|
|
117
|
-
export declare class StrandPeerBookService {
|
|
118
|
-
private readonly deps;
|
|
119
|
-
private readonly readTimeoutMs;
|
|
120
|
-
private readonly maxConcurrent;
|
|
121
|
-
private readonly now;
|
|
122
|
-
private node;
|
|
123
|
-
private activeStreams;
|
|
124
|
-
constructor(deps: StrandPeerBookServiceDeps);
|
|
125
|
-
/** In-flight inbound streams. */
|
|
126
|
-
get activeCount(): number;
|
|
127
|
-
/** Register the handler. Resolves once libp2p has recorded the protocol on the self record. */
|
|
128
|
-
initialize(node: Libp2p): Promise<void>;
|
|
129
|
-
/** Unregister the handler and release the node reference. */
|
|
130
|
-
shutdown(): Promise<void>;
|
|
131
|
-
/**
|
|
132
|
-
* Read the request, merge what verifies, answer with the local book. Every failure
|
|
133
|
-
* (cap, malformed or oversized frame, wrong strand, read timeout) answers an empty
|
|
134
|
-
* frame rather than hanging or dropping the stream, so the asker's exchange settles.
|
|
135
|
-
*
|
|
136
|
-
* NOTE: the concurrency cap bounds streams in flight, not frames per peer per unit
|
|
137
|
-
* time — the ten-minute throttle is the CLIENT's, so a connected peer can push a
|
|
138
|
-
* verified frame, and the persist it costs, as fast as it likes; see
|
|
139
|
-
* `backlog/debt-strand-peer-book-remote-write-bounds`.
|
|
140
|
-
*/
|
|
141
|
-
private handleStream;
|
|
142
|
-
private reply;
|
|
143
|
-
}
|
|
144
|
-
/** Options for {@link exchangeStrandPeerBook}. */
|
|
145
|
-
export interface ExchangeStrandPeerBookOptions {
|
|
146
|
-
/** This strand node's own peer id: a returned entry naming it is dropped. */
|
|
147
|
-
selfPeerId: string;
|
|
148
|
-
/** Whole-exchange deadline (ms). Default {@link DEFAULT_EXCHANGE_TIMEOUT_MS}. */
|
|
149
|
-
timeoutMs?: number;
|
|
150
|
-
/** Clock, for tests. Default `Date.now`. */
|
|
151
|
-
now?: () => number;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Client side: open one stream on `connection` — the live connection to the peer,
|
|
155
|
-
* relayed or not — send `request`, and return the peer's VERIFIED entries. Throws on
|
|
156
|
-
* any failure (the peer does not speak the protocol, a deadline, a refused frame);
|
|
157
|
-
* the caller logs and moves on, never retrying before its throttle expires.
|
|
158
|
-
*/
|
|
159
|
-
export declare function exchangeStrandPeerBook(connection: Connection, request: StrandPeerBookFrame, options: ExchangeStrandPeerBookOptions): Promise<SignedStrandPeerEntry[]>;
|