@serfab/cadre-core 1.10.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/cadre-node.d.ts +0 -27
  2. package/dist/cadre-node.js +3 -94
  3. package/dist/cadre-node.js.map +1 -1
  4. package/dist/control-schema.js +1066 -1066
  5. package/dist/diagnostics/connection-path.d.ts +1 -18
  6. package/dist/diagnostics/connection-path.js +1 -20
  7. package/dist/diagnostics/connection-path.js.map +1 -1
  8. package/dist/identity-key.d.ts +0 -30
  9. package/dist/identity-key.js +7 -40
  10. package/dist/identity-key.js.map +1 -1
  11. package/dist/index.d.ts +4 -2
  12. package/dist/index.js +9 -4
  13. package/dist/index.js.map +1 -1
  14. package/dist/relay-stun.d.ts +24 -0
  15. package/dist/relay-stun.js +51 -0
  16. package/dist/relay-stun.js.map +1 -0
  17. package/dist/seed-bootstrap.js +4 -4
  18. package/dist/strand-instance-manager.d.ts +8 -0
  19. package/dist/strand-instance-manager.js +8 -1
  20. package/dist/strand-instance-manager.js.map +1 -1
  21. package/dist/strand-membership-writer.js +32 -32
  22. package/dist/strand-reactivity.d.ts +41 -0
  23. package/dist/strand-reactivity.js +41 -0
  24. package/dist/strand-reactivity.js.map +1 -0
  25. package/dist/types.d.ts +19 -0
  26. package/dist/types.js.map +1 -1
  27. package/package.json +7 -7
  28. package/src/cadre-node.ts +8655 -8753
  29. package/src/control-authorization.ts +117 -117
  30. package/src/control-cohort.ts +128 -128
  31. package/src/control-formation-recorder.ts +353 -353
  32. package/src/control-read-retry.ts +216 -216
  33. package/src/control-schema.ts +1078 -1078
  34. package/src/control-write-retry.ts +567 -567
  35. package/src/diagnostics/connection-path.ts +1 -29
  36. package/src/formation-approval.ts +610 -610
  37. package/src/hibernation-manager.ts +638 -638
  38. package/src/identity-key.ts +7 -62
  39. package/src/index.ts +648 -647
  40. package/src/invitation-bootstrap.ts +40 -40
  41. package/src/joined-strand-store.ts +498 -498
  42. package/src/link-budget.ts +684 -684
  43. package/src/membership-connection-gater.ts +570 -570
  44. package/src/node-local-snapshot.ts +298 -298
  45. package/src/peer-dial.ts +315 -315
  46. package/src/peer-join-backfill.ts +710 -710
  47. package/src/pending-join-runner.ts +735 -735
  48. package/src/relay-reservation.ts +1121 -1121
  49. package/src/relay-server.ts +98 -98
  50. package/src/relay-stun.ts +58 -0
  51. package/src/seed-bootstrap.ts +1448 -1448
  52. package/src/strand-addr-protocol.ts +547 -547
  53. package/src/strand-database.ts +287 -287
  54. package/src/strand-first-sync-gate.ts +391 -391
  55. package/src/strand-formation-deadlines.ts +227 -227
  56. package/src/strand-formation-manager.ts +725 -725
  57. package/src/strand-fret-addrs.ts +145 -145
  58. package/src/strand-instance-manager.ts +1804 -1789
  59. package/src/strand-membership-writer.ts +1974 -1974
  60. package/src/strand-network-state-file.ts +40 -40
  61. package/src/strand-network-state.ts +243 -243
  62. package/src/strand-reactivity.ts +53 -0
  63. package/src/strand-revocation-enforcer.ts +654 -654
  64. package/src/strand-solicitation.ts +532 -532
  65. package/src/strand-wake-protocol.ts +401 -401
  66. package/src/types.ts +2242 -2222
  67. package/dist/diagnostics/webrtc-turn-tracker.d.ts +0 -50
  68. package/dist/diagnostics/webrtc-turn-tracker.js +0 -196
  69. package/dist/diagnostics/webrtc-turn-tracker.js.map +0 -1
  70. package/src/diagnostics/webrtc-turn-tracker.ts +0 -222
@@ -612,23 +612,6 @@ export declare class CadreNode implements SAppIdLookup {
612
612
  private controlConnectionOpenHandler;
613
613
  /** `connection:close` listener re-arming the growth edge (teardown in {@link stopRecordRefresh}). */
614
614
  private controlConnectionCloseHandler;
615
- /**
616
- * Hooks `globalThis.RTCPeerConnection` to observe whether ICE selected a TURN
617
- * relay candidate for each WebRTC session. Installed in {@link start}, disposed
618
- * in {@link cleanup}; inert on Node.js (no `RTCPeerConnection`).
619
- */
620
- private readonly turnTracker;
621
- /**
622
- * Peer IDs whose current WebRTC connection was observed to be TURN-relayed.
623
- * Populated by {@link handleTurnConnectionOpen} (drains the tracker queue on a
624
- * `/webrtc` `connection:open`), cleared per-peer on `connection:close`. Read by
625
- * {@link getConnectionPaths} to promote `webrtc` → `webrtc-turn` (relayed).
626
- */
627
- private turnRelayedPeers;
628
- /** `connection:open` listener feeding TURN detection (teardown in {@link stopRecordRefresh}). */
629
- private turnConnectionOpenHandler;
630
- /** `connection:close` listener clearing a peer's TURN flag (teardown in {@link stopRecordRefresh}). */
631
- private turnConnectionCloseHandler;
632
615
  constructor(config: CadreNodeConfig);
633
616
  /**
634
617
  * SAppIdLookup implementation - get sAppId for a strand: the claiming config's, else
@@ -1852,16 +1835,6 @@ export declare class CadreNode implements SAppIdLookup {
1852
1835
  * Idempotent.
1853
1836
  */
1854
1837
  private wireControlConnectionListeners;
1855
- /**
1856
- * On a control connection opening: if it is a WebRTC connection, drain the TURN
1857
- * tracker for the just-settled ICE verdict and, when it relayed, mark the peer
1858
- * so {@link getConnectionPaths} classifies it `webrtc-turn` (relayed). The
1859
- * settlement↔open correlation is timing-based and best-effort; an unknown
1860
- * verdict degrades to not-relayed. Never throws to the event loop.
1861
- */
1862
- private handleTurnConnectionOpen;
1863
- /** On a control connection closing, drop any TURN-relayed flag for its peer. */
1864
- private handleTurnConnectionClose;
1865
1838
  /**
1866
1839
  * Publish (or refresh) this node's own self-signed `DeviceToken` row so a server
1867
1840
  * peer can resolve its FCM/APNs push token from its PeerId alone. Mirrors
@@ -51,17 +51,10 @@ import { resolveRelayServer } from './relay-server.js';
51
51
  import { replacesAdvertisedAddrs, resolveAnnounceAddrs } from './announce-addrs.js';
52
52
  import { superviseRelayReservation, resolveRelayReservationState } from './relay-reservation.js';
53
53
  import { PushFanoutService } from './push-fanout.js';
54
- import { summarizeConnectionPaths, classifyTransport } from './diagnostics/connection-path.js';
55
- import { TurnRelayTracker } from './diagnostics/webrtc-turn-tracker.js';
54
+ import { summarizeConnectionPaths } from './diagnostics/connection-path.js';
56
55
  import { timedStep } from './timed-step.js';
57
56
  const log = debug('sereus:cadre:node');
58
57
  const timing = debug('sereus:cadre:timing');
59
- /**
60
- * Window (ms) within which a queued TURN-relay settlement is correlated to a
61
- * `connection:open`. Generous relative to the tight async gap between an
62
- * `RTCPeerConnection` reaching `connected` and libp2p surfacing the connection.
63
- */
64
- const TURN_CONSUME_WINDOW_MS = 1000;
65
58
  /**
66
59
  * How often a running strand re-asks each connected sibling that last ANSWERED
67
60
  * (even with nothing) for its strand-network addresses, and re-merges them into
@@ -734,24 +727,6 @@ export class CadreNode {
734
727
  this.controlConnectionOpenHandler = null;
735
728
  /** `connection:close` listener re-arming the growth edge (teardown in {@link stopRecordRefresh}). */
736
729
  this.controlConnectionCloseHandler = null;
737
- // ── WebRTC TURN-relay detection (turn-relayed-path-metrics) ─────────────────
738
- /**
739
- * Hooks `globalThis.RTCPeerConnection` to observe whether ICE selected a TURN
740
- * relay candidate for each WebRTC session. Installed in {@link start}, disposed
741
- * in {@link cleanup}; inert on Node.js (no `RTCPeerConnection`).
742
- */
743
- this.turnTracker = new TurnRelayTracker();
744
- /**
745
- * Peer IDs whose current WebRTC connection was observed to be TURN-relayed.
746
- * Populated by {@link handleTurnConnectionOpen} (drains the tracker queue on a
747
- * `/webrtc` `connection:open`), cleared per-peer on `connection:close`. Read by
748
- * {@link getConnectionPaths} to promote `webrtc` → `webrtc-turn` (relayed).
749
- */
750
- this.turnRelayedPeers = new Set();
751
- /** `connection:open` listener feeding TURN detection (teardown in {@link stopRecordRefresh}). */
752
- this.turnConnectionOpenHandler = null;
753
- /** `connection:close` listener clearing a peer's TURN flag (teardown in {@link stopRecordRefresh}). */
754
- this.turnConnectionCloseHandler = null;
755
730
  this.config = config;
756
731
  this.hostUnclaimedStrands = config.hostUnclaimedStrands ?? config.profile === 'storage';
757
732
  this.strandManager = new StrandInstanceManager();
@@ -831,18 +806,7 @@ export class CadreNode {
831
806
  * direct sibling is considered stuck (default 10_000ms)
832
807
  */
833
808
  getConnectionPaths(settleWindowMs) {
834
- const conns = this.controlNode?.getConnections() ?? [];
835
- // Annotate each connection with the TURN-relay hint so a WebRTC session whose
836
- // ICE selected a TURN candidate classifies as relayed/webrtc-turn rather than
837
- // direct/webrtc (the multiaddr alone cannot reveal it).
838
- const annotated = conns.map((c) => ({
839
- remotePeer: c.remotePeer,
840
- remoteAddr: c.remoteAddr,
841
- direction: c.direction,
842
- timeline: c.timeline,
843
- turnRelayed: this.turnRelayedPeers.has(c.remotePeer.toString()),
844
- }));
845
- return summarizeConnectionPaths(annotated, settleWindowMs);
809
+ return summarizeConnectionPaths(this.controlNode?.getConnections(), settleWindowMs);
846
810
  }
847
811
  /**
848
812
  * Get all strand instances
@@ -902,10 +866,6 @@ export class CadreNode {
902
866
  // yet), so a node with a zero or NaN declaration would otherwise boot and fail later
903
867
  // inside a best-effort path that logs and carries on. `link-budget.ts`.
904
868
  resolveLinkRoundTripMs(this.config.network?.linkRoundTripMs);
905
- // Install the WebRTC TURN-relay tracker BEFORE any libp2p bring-up, so it
906
- // wraps globalThis.RTCPeerConnection before the control node can create one.
907
- // Inert on Node.js (no RTCPeerConnection); disposed in cleanup().
908
- this.turnTracker.install();
909
869
  // Resolve the node identity (keyStore | privateKey | ephemeral) BEFORE any
910
870
  // libp2p/network bring-up, so a misconfiguration or an access-denied secure
911
871
  // store fails closed before a node is created.
@@ -2535,18 +2495,10 @@ export class CadreNode {
2535
2495
  if (this.controlConnectionCloseHandler) {
2536
2496
  this.controlNode.removeEventListener('connection:close', this.controlConnectionCloseHandler);
2537
2497
  }
2538
- if (this.turnConnectionOpenHandler) {
2539
- this.controlNode.removeEventListener('connection:open', this.turnConnectionOpenHandler);
2540
- }
2541
- if (this.turnConnectionCloseHandler) {
2542
- this.controlNode.removeEventListener('connection:close', this.turnConnectionCloseHandler);
2543
- }
2544
2498
  }
2545
2499
  this.selfPeerUpdateHandler = null;
2546
2500
  this.controlConnectionOpenHandler = null;
2547
2501
  this.controlConnectionCloseHandler = null;
2548
- this.turnConnectionOpenHandler = null;
2549
- this.turnConnectionCloseHandler = null;
2550
2502
  // Reset the write-while-alone re-replication state so a stop()→start() cycle
2551
2503
  // re-arms the growth edge and re-runs BOTH one-shot passes. Any queued
2552
2504
  // local-only writes are moot once the node is torn down: owner inserts are
@@ -3815,47 +3767,6 @@ export class CadreNode {
3815
3767
  this.controlConnectionCloseHandler = () => this.handleControlConnectionClose();
3816
3768
  this.controlNode.addEventListener('connection:open', this.controlConnectionOpenHandler);
3817
3769
  this.controlNode.addEventListener('connection:close', this.controlConnectionCloseHandler);
3818
- // TURN-relay detection: tag/untag peers whose WebRTC ICE used a TURN candidate.
3819
- this.turnConnectionOpenHandler = (evt) => this.handleTurnConnectionOpen(evt.detail);
3820
- this.turnConnectionCloseHandler = (evt) => this.handleTurnConnectionClose(evt.detail);
3821
- this.controlNode.addEventListener('connection:open', this.turnConnectionOpenHandler);
3822
- this.controlNode.addEventListener('connection:close', this.turnConnectionCloseHandler);
3823
- }
3824
- /**
3825
- * On a control connection opening: if it is a WebRTC connection, drain the TURN
3826
- * tracker for the just-settled ICE verdict and, when it relayed, mark the peer
3827
- * so {@link getConnectionPaths} classifies it `webrtc-turn` (relayed). The
3828
- * settlement↔open correlation is timing-based and best-effort; an unknown
3829
- * verdict degrades to not-relayed. Never throws to the event loop.
3830
- */
3831
- handleTurnConnectionOpen(conn) {
3832
- try {
3833
- const addr = conn.remoteAddr?.toString() ?? '';
3834
- // Only a genuine `/webrtc` (ICE) session can be TURN-relayed and promoted to
3835
- // webrtc-turn. Use the classifier (which checks `/webrtc-direct` first) rather
3836
- // than a bare substring — `'/webrtc-direct'.includes('/webrtc')` is true, and a
3837
- // webrtc-direct open must not drain a settlement meant for a real webrtc dial.
3838
- if (classifyTransport(addr).transport !== 'webrtc') {
3839
- return;
3840
- }
3841
- if (this.turnTracker.consume(TURN_CONSUME_WINDOW_MS) === true) {
3842
- const peerId = conn.remotePeer.toString();
3843
- this.turnRelayedPeers.add(peerId);
3844
- log('TURN-relayed WebRTC connection detected for peer %s', peerId);
3845
- }
3846
- }
3847
- catch (error) {
3848
- log('handleTurnConnectionOpen failed: %o', error);
3849
- }
3850
- }
3851
- /** On a control connection closing, drop any TURN-relayed flag for its peer. */
3852
- handleTurnConnectionClose(conn) {
3853
- try {
3854
- this.turnRelayedPeers.delete(conn.remotePeer.toString());
3855
- }
3856
- catch (error) {
3857
- log('handleTurnConnectionClose failed: %o', error);
3858
- }
3859
3770
  }
3860
3771
  // ============================================================================
3861
3772
  // Device-token registry (control-network push-token publish + resolve)
@@ -4217,9 +4128,6 @@ export class CadreNode {
4217
4128
  // Stop self-record refresh timers + address-change listener (before the
4218
4129
  // control node is torn down, so removeEventListener has a live target).
4219
4130
  this.stopRecordRefresh();
4220
- // Restore the wrapped globalThis.RTCPeerConnection and drop TURN-relay state.
4221
- this.turnTracker.dispose();
4222
- this.turnRelayedPeers.clear();
4223
4131
  // Stop hibernation manager
4224
4132
  this.hibernationManager.stop();
4225
4133
  // Stop seed bootstrap service
@@ -5404,6 +5312,7 @@ export class CadreNode {
5404
5312
  // than merely weak. The full argument, and the count that will legitimately go here,
5405
5313
  // are on `StartStrandConfig.servingMachines`.
5406
5314
  backfill: this.config.strandBackfill,
5315
+ reactivity: this.config.strandReactivity,
5407
5316
  revocationEnforcement: this.config.strandRevocationEnforcement,
5408
5317
  membershipReconciliation: this.config.strandMembershipReconciliation,
5409
5318
  onSelfRevoked: (revokedStrandId) => {