@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.
- package/README.md +255 -255
- package/dist/cadre-node.d.ts +203 -28
- package/dist/cadre-node.js +445 -84
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-cohort.d.ts +26 -0
- package/dist/control-cohort.js +26 -0
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +82 -117
- package/dist/control-database.js +217 -295
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +8 -7
- package/dist/control-formation-recorder.js +8 -7
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +789 -774
- package/dist/control-schema.js.map +1 -1
- package/dist/control-write-retry.d.ts +15 -5
- package/dist/control-write-retry.js +19 -18
- package/dist/control-write-retry.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/peer-addr-book.d.ts +92 -0
- package/dist/peer-addr-book.js +220 -0
- package/dist/peer-addr-book.js.map +1 -0
- package/dist/seed-bootstrap.d.ts +7 -0
- package/dist/seed-bootstrap.js +15 -13
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/strand-cohort.d.ts +4 -37
- package/dist/strand-cohort.js +4 -15
- package/dist/strand-cohort.js.map +1 -1
- package/dist/strand-database.d.ts +11 -16
- package/dist/strand-database.js +19 -7
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-formation-manager.d.ts +8 -8
- package/dist/strand-formation-manager.js +15 -18
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +52 -21
- package/dist/strand-instance-manager.js +100 -34
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +6 -4
- package/dist/strand-membership-writer.js +38 -36
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/types.d.ts +39 -31
- package/dist/types.js.map +1 -1
- package/package.json +8 -7
- package/src/arachnode-stub.ts +159 -159
- package/src/bootstrap-peer-store-file.ts +44 -44
- package/src/bootstrap-peer-store.ts +172 -172
- package/src/cadre-node.ts +5158 -4771
- package/src/canonical-json.ts +30 -30
- package/src/control-authorization.ts +114 -114
- package/src/control-cohort.ts +130 -103
- package/src/control-database.ts +2406 -2506
- package/src/control-formation-recorder.ts +305 -304
- package/src/control-schema.ts +801 -786
- package/src/control-stream.ts +205 -205
- package/src/control-write-retry.ts +483 -473
- package/src/delegate-admission.ts +302 -302
- package/src/device-token.ts +94 -94
- package/src/diagnostics/connection-path.ts +277 -277
- package/src/diagnostics/webrtc-turn-tracker.ts +222 -222
- package/src/ed25519-key.ts +134 -134
- package/src/enrollment.ts +199 -199
- package/src/file-durable-slot.ts +61 -61
- package/src/formation-approval.ts +604 -604
- package/src/fs-atomic.ts +107 -107
- package/src/hibernation-manager.ts +437 -437
- package/src/identity-key.ts +109 -109
- package/src/index.ts +1 -0
- package/src/key-store-file.ts +132 -132
- package/src/key-store.ts +99 -99
- package/src/membership-connection-gater.ts +204 -204
- package/src/node-local-snapshot.ts +260 -260
- package/src/peer-addr-book.ts +250 -0
- package/src/peer-authorization.ts +259 -259
- package/src/peer-record.ts +164 -164
- package/src/push-credentials.ts +84 -84
- package/src/push-node.ts +64 -64
- package/src/push-notifier-apns.ts +247 -247
- package/src/push-notifier-fcm.ts +220 -220
- package/src/push-notifier-shared.ts +28 -28
- package/src/push-notifier.ts +52 -52
- package/src/relay-addrs.ts +111 -111
- package/src/relay-reservation.ts +823 -823
- package/src/seed-bootstrap.ts +15 -15
- package/src/seed-trust-policy.ts +140 -140
- package/src/strand-addr-protocol.ts +441 -441
- package/src/strand-backfill.ts +366 -366
- package/src/strand-cohort.ts +38 -77
- package/src/strand-database.ts +202 -204
- package/src/strand-formation-manager.ts +491 -494
- package/src/strand-formation-protocol.ts +692 -692
- package/src/strand-instance-manager.ts +108 -50
- package/src/strand-member-key.ts +39 -39
- package/src/strand-member-registry.ts +182 -182
- package/src/strand-membership-writer.ts +1432 -1430
- package/src/strand-solicitation.ts +472 -472
- package/src/strand-transport-key.ts +58 -58
- package/src/strand-wake-payload.ts +32 -32
- package/src/strand-wake-protocol.ts +314 -314
- package/src/strand-watcher.ts +314 -314
- package/src/trusted-owner-store-file.ts +41 -41
- package/src/trusted-owner-store.ts +171 -171
- package/src/types.ts +1309 -1303
package/src/relay-addrs.ts
CHANGED
|
@@ -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
|
+
}
|