@serfab/cadre-core 0.10.0 → 0.11.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 (105) hide show
  1. package/README.md +255 -255
  2. package/dist/cadre-node.d.ts +203 -28
  3. package/dist/cadre-node.js +445 -84
  4. package/dist/cadre-node.js.map +1 -1
  5. package/dist/control-cohort.d.ts +26 -0
  6. package/dist/control-cohort.js +26 -0
  7. package/dist/control-cohort.js.map +1 -1
  8. package/dist/control-database.d.ts +82 -117
  9. package/dist/control-database.js +217 -295
  10. package/dist/control-database.js.map +1 -1
  11. package/dist/control-formation-recorder.d.ts +8 -7
  12. package/dist/control-formation-recorder.js +8 -7
  13. package/dist/control-formation-recorder.js.map +1 -1
  14. package/dist/control-schema.d.ts +1 -1
  15. package/dist/control-schema.js +789 -774
  16. package/dist/control-schema.js.map +1 -1
  17. package/dist/control-write-retry.d.ts +15 -5
  18. package/dist/control-write-retry.js +19 -18
  19. package/dist/control-write-retry.js.map +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/peer-addr-book.d.ts +92 -0
  24. package/dist/peer-addr-book.js +220 -0
  25. package/dist/peer-addr-book.js.map +1 -0
  26. package/dist/seed-bootstrap.d.ts +7 -0
  27. package/dist/seed-bootstrap.js +15 -13
  28. package/dist/seed-bootstrap.js.map +1 -1
  29. package/dist/strand-cohort.d.ts +4 -37
  30. package/dist/strand-cohort.js +4 -15
  31. package/dist/strand-cohort.js.map +1 -1
  32. package/dist/strand-database.d.ts +11 -16
  33. package/dist/strand-database.js +19 -7
  34. package/dist/strand-database.js.map +1 -1
  35. package/dist/strand-formation-manager.d.ts +8 -8
  36. package/dist/strand-formation-manager.js +15 -18
  37. package/dist/strand-formation-manager.js.map +1 -1
  38. package/dist/strand-instance-manager.d.ts +52 -21
  39. package/dist/strand-instance-manager.js +100 -34
  40. package/dist/strand-instance-manager.js.map +1 -1
  41. package/dist/strand-membership-writer.d.ts +6 -4
  42. package/dist/strand-membership-writer.js +38 -36
  43. package/dist/strand-membership-writer.js.map +1 -1
  44. package/dist/types.d.ts +39 -31
  45. package/dist/types.js.map +1 -1
  46. package/package.json +8 -7
  47. package/src/arachnode-stub.ts +159 -159
  48. package/src/bootstrap-peer-store-file.ts +44 -44
  49. package/src/bootstrap-peer-store.ts +172 -172
  50. package/src/cadre-node.ts +5158 -4771
  51. package/src/canonical-json.ts +30 -30
  52. package/src/control-authorization.ts +114 -114
  53. package/src/control-cohort.ts +130 -103
  54. package/src/control-database.ts +2406 -2506
  55. package/src/control-formation-recorder.ts +305 -304
  56. package/src/control-schema.ts +801 -786
  57. package/src/control-stream.ts +205 -205
  58. package/src/control-write-retry.ts +483 -473
  59. package/src/delegate-admission.ts +302 -302
  60. package/src/device-token.ts +94 -94
  61. package/src/diagnostics/connection-path.ts +277 -277
  62. package/src/diagnostics/webrtc-turn-tracker.ts +222 -222
  63. package/src/ed25519-key.ts +134 -134
  64. package/src/enrollment.ts +199 -199
  65. package/src/file-durable-slot.ts +61 -61
  66. package/src/formation-approval.ts +604 -604
  67. package/src/fs-atomic.ts +107 -107
  68. package/src/hibernation-manager.ts +437 -437
  69. package/src/identity-key.ts +109 -109
  70. package/src/index.ts +1 -0
  71. package/src/key-store-file.ts +132 -132
  72. package/src/key-store.ts +99 -99
  73. package/src/membership-connection-gater.ts +204 -204
  74. package/src/node-local-snapshot.ts +260 -260
  75. package/src/peer-addr-book.ts +250 -0
  76. package/src/peer-authorization.ts +259 -259
  77. package/src/peer-record.ts +164 -164
  78. package/src/push-credentials.ts +84 -84
  79. package/src/push-node.ts +64 -64
  80. package/src/push-notifier-apns.ts +247 -247
  81. package/src/push-notifier-fcm.ts +220 -220
  82. package/src/push-notifier-shared.ts +28 -28
  83. package/src/push-notifier.ts +52 -52
  84. package/src/relay-addrs.ts +111 -111
  85. package/src/relay-reservation.ts +823 -823
  86. package/src/seed-bootstrap.ts +15 -15
  87. package/src/seed-trust-policy.ts +140 -140
  88. package/src/strand-addr-protocol.ts +441 -441
  89. package/src/strand-backfill.ts +366 -366
  90. package/src/strand-cohort.ts +38 -77
  91. package/src/strand-database.ts +202 -204
  92. package/src/strand-formation-manager.ts +491 -494
  93. package/src/strand-formation-protocol.ts +692 -692
  94. package/src/strand-instance-manager.ts +108 -50
  95. package/src/strand-member-key.ts +39 -39
  96. package/src/strand-member-registry.ts +182 -182
  97. package/src/strand-membership-writer.ts +1432 -1430
  98. package/src/strand-solicitation.ts +472 -472
  99. package/src/strand-transport-key.ts +58 -58
  100. package/src/strand-wake-payload.ts +32 -32
  101. package/src/strand-wake-protocol.ts +314 -314
  102. package/src/strand-watcher.ts +314 -314
  103. package/src/trusted-owner-store-file.ts +41 -41
  104. package/src/trusted-owner-store.ts +171 -171
  105. package/src/types.ts +1309 -1303
@@ -1,111 +1,111 @@
1
- /**
2
- * Translate `network.relayAddrs` — the operator-facing "use these relay servers"
3
- * setting — into the mechanism this repo already has for reserving a circuit-relay
4
- * slot: a `…/p2p/<relayPeerId>/p2p-circuit` entry in the node's listen addrs.
5
- *
6
- * `@libp2p/circuit-relay-v2`'s transport is always present on the Node path
7
- * (`../optimystic/packages/db-p2p/src/libp2p-node.ts` pushes `circuitRelayTransport()`
8
- * unconditionally), and listening on a relay's circuit addr is what makes libp2p dial
9
- * that relay and hold a reservation. Everything downstream of the listen list —
10
- * the reservation itself, `CadreNode.circuitRelayTargets()` picking delegate-announce
11
- * targets, strand nodes inheriting the listen addrs, the `/p2p-circuit`-first address
12
- * publishing in `registerSelf` — then works unchanged.
13
- *
14
- * So `relayAddrs` is a second, friendlier door onto an existing mechanism:
15
- *
16
- * effective listen addrs = listenAddrs ++ relayAddrs.map(a => a + '/p2p-circuit')
17
- *
18
- * NOTE: this is the FAIL-FAST route to a reservation — libp2p's transport manager
19
- * throws when a configured circuit listener cannot listen, so naming a relay that
20
- * is down means the node does not start. The fail-soft route is the bare
21
- * `/p2p-circuit` search listener driven by `relay-reservation.ts`. The two are
22
- * ALTERNATIVES, not layers: configuring `relayAddrs` on a node that already
23
- * reserves via the search listener adds the fatal listener back and the node
24
- * stops booting when its relay is down.
25
- */
26
-
27
- import { multiaddr, type Component } from '@multiformats/multiaddr';
28
- import { circuitRelayTargetOrThrow } from './delegate-admission.js';
29
- import type { NetworkConfig } from './types.js';
30
-
31
- /**
32
- * The direct listener a node keeps when it configures `relayAddrs` but no
33
- * `listenAddrs`. Without this, naming a relay would silently REPLACE the node's
34
- * direct TCP listener with a circuit-only one.
35
- *
36
- * NOTE: mirrors `createLibp2pNode`'s own default listen addr in
37
- * `../optimystic/packages/db-p2p/src/libp2p-node.ts` (`/ip4/0.0.0.0/tcp/<port>`,
38
- * and `CadreNode` passes `port: 0`) — that file is the source of truth. If it
39
- * ever changes its default, this constant has to follow.
40
- */
41
- const DEFAULT_DIRECT_LISTEN_ADDR = '/ip4/0.0.0.0/tcp/0';
42
-
43
- /**
44
- * The circuit-listen multiaddr for each configured relay: `<relayAddr>/p2p-circuit`.
45
- * An entry that already carries `/p2p-circuit` is passed through unchanged.
46
- * Throws on an entry that is unparsable or names no relay peerId — this is
47
- * operator configuration, so a typo must fail loudly at start rather than
48
- * silently costing the node its reachability.
49
- *
50
- * Deliberately unlike `extractCircuitRelayTargets` (`delegate-admission.ts`), which
51
- * SKIPS a bad entry: that one reads addresses discovered at runtime from peers, where
52
- * one bad entry must not be fatal.
53
- */
54
- export function relayCircuitAddrs(relayAddrs: readonly string[]): string[] {
55
- return dedupe(relayAddrs.map(circuitListenAddr));
56
- }
57
-
58
- /**
59
- * The listen multiaddrs a node actually binds: configured `listenAddrs` plus the
60
- * circuit-listen addr of every configured relay, deduplicated, order-stable
61
- * (configured entries first). Returns `undefined` when neither field is set, so
62
- * callers keep omitting `listenAddrs` and inherit db-p2p's default.
63
- */
64
- export function resolveListenAddrs(network: NetworkConfig | undefined): string[] | undefined {
65
- const circuits = relayCircuitAddrs(network?.relayAddrs ?? []);
66
- const listenAddrs = network?.listenAddrs;
67
- if (!listenAddrs && circuits.length === 0) {
68
- return undefined;
69
- }
70
- // An explicitly empty `listenAddrs` (the React Native "cannot listen" case) stays
71
- // empty — but a relay named alongside it still gets its circuit listener, since
72
- // acquiring one is the whole point of configuring a relay.
73
- return dedupe([...(listenAddrs ?? [DEFAULT_DIRECT_LISTEN_ADDR]), ...circuits]);
74
- }
75
-
76
- /**
77
- * One entry of {@link relayCircuitAddrs}: the addr the node listens on for this relay.
78
- *
79
- * NOTE: an entry carrying components AFTER `/p2p-circuit` — a full relayed DIAL addr,
80
- * `…/p2p/<relay>/p2p-circuit/p2p/<someone else>` — is passed through as written and
81
- * would be listened on verbatim. It validates (the relay it names is real), so only an
82
- * operator who pastes a peer's relayed address into `relayAddrs` hits it; if that turns
83
- * out to be a common paste, truncate at the `/p2p-circuit` component here.
84
- */
85
- function circuitListenAddr(relayAddr: string): string {
86
- const alreadyCircuit = parseComponents(relayAddr).some((c) => c.name === 'p2p-circuit');
87
- const listenAddr = alreadyCircuit ? relayAddr : `${relayAddr}/p2p-circuit`;
88
- try {
89
- circuitRelayTargetOrThrow(listenAddr); // validates the relay peerId
90
- } catch (err) {
91
- throw new Error(
92
- `network.relayAddrs entry names no relay peerId (expected <dial addr>/p2p/<relayPeerId>): ${relayAddr}`,
93
- { cause: err }
94
- );
95
- }
96
- return listenAddr;
97
- }
98
-
99
- /** Multiaddr components of `relayAddr`, with the config field named on a parse failure. */
100
- function parseComponents(relayAddr: string): Component[] {
101
- try {
102
- return multiaddr(relayAddr).getComponents();
103
- } catch (err) {
104
- throw new Error(`network.relayAddrs entry is not a valid multiaddr: ${relayAddr}`, { cause: err });
105
- }
106
- }
107
-
108
- /** Exact-string dedupe, first occurrence wins, so the list is stable across restarts. */
109
- function dedupe(addrs: readonly string[]): string[] {
110
- return [...new Set(addrs)];
111
- }
1
+ /**
2
+ * Translate `network.relayAddrs` — the operator-facing "use these relay servers"
3
+ * setting — into the mechanism this repo already has for reserving a circuit-relay
4
+ * slot: a `…/p2p/<relayPeerId>/p2p-circuit` entry in the node's listen addrs.
5
+ *
6
+ * `@libp2p/circuit-relay-v2`'s transport is always present on the Node path
7
+ * (`../optimystic/packages/db-p2p/src/libp2p-node.ts` pushes `circuitRelayTransport()`
8
+ * unconditionally), and listening on a relay's circuit addr is what makes libp2p dial
9
+ * that relay and hold a reservation. Everything downstream of the listen list —
10
+ * the reservation itself, `CadreNode.circuitRelayTargets()` picking delegate-announce
11
+ * targets, strand nodes inheriting the listen addrs, the `/p2p-circuit`-first address
12
+ * publishing in `registerSelf` — then works unchanged.
13
+ *
14
+ * So `relayAddrs` is a second, friendlier door onto an existing mechanism:
15
+ *
16
+ * effective listen addrs = listenAddrs ++ relayAddrs.map(a => a + '/p2p-circuit')
17
+ *
18
+ * NOTE: this is the FAIL-FAST route to a reservation — libp2p's transport manager
19
+ * throws when a configured circuit listener cannot listen, so naming a relay that
20
+ * is down means the node does not start. The fail-soft route is the bare
21
+ * `/p2p-circuit` search listener driven by `relay-reservation.ts`. The two are
22
+ * ALTERNATIVES, not layers: configuring `relayAddrs` on a node that already
23
+ * reserves via the search listener adds the fatal listener back and the node
24
+ * stops booting when its relay is down.
25
+ */
26
+
27
+ import { multiaddr, type Component } from '@multiformats/multiaddr';
28
+ import { circuitRelayTargetOrThrow } from './delegate-admission.js';
29
+ import type { NetworkConfig } from './types.js';
30
+
31
+ /**
32
+ * The direct listener a node keeps when it configures `relayAddrs` but no
33
+ * `listenAddrs`. Without this, naming a relay would silently REPLACE the node's
34
+ * direct TCP listener with a circuit-only one.
35
+ *
36
+ * NOTE: mirrors `createLibp2pNode`'s own default listen addr in
37
+ * `../optimystic/packages/db-p2p/src/libp2p-node.ts` (`/ip4/0.0.0.0/tcp/<port>`,
38
+ * and `CadreNode` passes `port: 0`) — that file is the source of truth. If it
39
+ * ever changes its default, this constant has to follow.
40
+ */
41
+ const DEFAULT_DIRECT_LISTEN_ADDR = '/ip4/0.0.0.0/tcp/0';
42
+
43
+ /**
44
+ * The circuit-listen multiaddr for each configured relay: `<relayAddr>/p2p-circuit`.
45
+ * An entry that already carries `/p2p-circuit` is passed through unchanged.
46
+ * Throws on an entry that is unparsable or names no relay peerId — this is
47
+ * operator configuration, so a typo must fail loudly at start rather than
48
+ * silently costing the node its reachability.
49
+ *
50
+ * Deliberately unlike `extractCircuitRelayTargets` (`delegate-admission.ts`), which
51
+ * SKIPS a bad entry: that one reads addresses discovered at runtime from peers, where
52
+ * one bad entry must not be fatal.
53
+ */
54
+ export function relayCircuitAddrs(relayAddrs: readonly string[]): string[] {
55
+ return dedupe(relayAddrs.map(circuitListenAddr));
56
+ }
57
+
58
+ /**
59
+ * The listen multiaddrs a node actually binds: configured `listenAddrs` plus the
60
+ * circuit-listen addr of every configured relay, deduplicated, order-stable
61
+ * (configured entries first). Returns `undefined` when neither field is set, so
62
+ * callers keep omitting `listenAddrs` and inherit db-p2p's default.
63
+ */
64
+ export function resolveListenAddrs(network: NetworkConfig | undefined): string[] | undefined {
65
+ const circuits = relayCircuitAddrs(network?.relayAddrs ?? []);
66
+ const listenAddrs = network?.listenAddrs;
67
+ if (!listenAddrs && circuits.length === 0) {
68
+ return undefined;
69
+ }
70
+ // An explicitly empty `listenAddrs` (the React Native "cannot listen" case) stays
71
+ // empty — but a relay named alongside it still gets its circuit listener, since
72
+ // acquiring one is the whole point of configuring a relay.
73
+ return dedupe([...(listenAddrs ?? [DEFAULT_DIRECT_LISTEN_ADDR]), ...circuits]);
74
+ }
75
+
76
+ /**
77
+ * One entry of {@link relayCircuitAddrs}: the addr the node listens on for this relay.
78
+ *
79
+ * NOTE: an entry carrying components AFTER `/p2p-circuit` — a full relayed DIAL addr,
80
+ * `…/p2p/<relay>/p2p-circuit/p2p/<someone else>` — is passed through as written and
81
+ * would be listened on verbatim. It validates (the relay it names is real), so only an
82
+ * operator who pastes a peer's relayed address into `relayAddrs` hits it; if that turns
83
+ * out to be a common paste, truncate at the `/p2p-circuit` component here.
84
+ */
85
+ function circuitListenAddr(relayAddr: string): string {
86
+ const alreadyCircuit = parseComponents(relayAddr).some((c) => c.name === 'p2p-circuit');
87
+ const listenAddr = alreadyCircuit ? relayAddr : `${relayAddr}/p2p-circuit`;
88
+ try {
89
+ circuitRelayTargetOrThrow(listenAddr); // validates the relay peerId
90
+ } catch (err) {
91
+ throw new Error(
92
+ `network.relayAddrs entry names no relay peerId (expected <dial addr>/p2p/<relayPeerId>): ${relayAddr}`,
93
+ { cause: err }
94
+ );
95
+ }
96
+ return listenAddr;
97
+ }
98
+
99
+ /** Multiaddr components of `relayAddr`, with the config field named on a parse failure. */
100
+ function parseComponents(relayAddr: string): Component[] {
101
+ try {
102
+ return multiaddr(relayAddr).getComponents();
103
+ } catch (err) {
104
+ throw new Error(`network.relayAddrs entry is not a valid multiaddr: ${relayAddr}`, { cause: err });
105
+ }
106
+ }
107
+
108
+ /** Exact-string dedupe, first occurrence wins, so the list is stable across restarts. */
109
+ function dedupe(addrs: readonly string[]): string[] {
110
+ return [...new Set(addrs)];
111
+ }