@serfab/cadre-core 1.13.0 → 1.15.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 (230) hide show
  1. package/README.md +293 -274
  2. package/dist/cadre-invite-protocol.d.ts +383 -0
  3. package/dist/cadre-invite-protocol.js +774 -0
  4. package/dist/cadre-invite-protocol.js.map +1 -0
  5. package/dist/cadre-join-request.d.ts +42 -0
  6. package/dist/cadre-join-request.js +144 -0
  7. package/dist/cadre-join-request.js.map +1 -0
  8. package/dist/cadre-node.d.ts +849 -210
  9. package/dist/cadre-node.js +1574 -374
  10. package/dist/cadre-node.js.map +1 -1
  11. package/dist/claim-proof.d.ts +45 -0
  12. package/dist/claim-proof.js +132 -0
  13. package/dist/claim-proof.js.map +1 -0
  14. package/dist/control-authorization.d.ts +80 -19
  15. package/dist/control-authorization.js +55 -13
  16. package/dist/control-authorization.js.map +1 -1
  17. package/dist/control-cohort.js +1 -1
  18. package/dist/control-cohort.js.map +1 -1
  19. package/dist/control-database.d.ts +605 -108
  20. package/dist/control-database.js +1299 -280
  21. package/dist/control-database.js.map +1 -1
  22. package/dist/control-protocol-guard.d.ts +142 -0
  23. package/dist/control-protocol-guard.js +293 -0
  24. package/dist/control-protocol-guard.js.map +1 -0
  25. package/dist/control-schema.d.ts +1 -1
  26. package/dist/control-schema.js +817 -1067
  27. package/dist/control-schema.js.map +1 -1
  28. package/dist/control-stream.d.ts +4 -0
  29. package/dist/control-stream.js +22 -7
  30. package/dist/control-stream.js.map +1 -1
  31. package/dist/delegate-admission.d.ts +1 -1
  32. package/dist/delegate-admission.js +1 -1
  33. package/dist/device-token.d.ts +11 -9
  34. package/dist/device-token.js +14 -12
  35. package/dist/device-token.js.map +1 -1
  36. package/dist/ed25519-key.d.ts +22 -9
  37. package/dist/ed25519-key.js +47 -10
  38. package/dist/ed25519-key.js.map +1 -1
  39. package/dist/fetch-impl.d.ts +12 -0
  40. package/dist/fetch-impl.js +23 -0
  41. package/dist/fetch-impl.js.map +1 -0
  42. package/dist/file-durable-slot.js +2 -1
  43. package/dist/file-durable-slot.js.map +1 -1
  44. package/dist/file-safe-name.d.ts +25 -0
  45. package/dist/file-safe-name.js +29 -0
  46. package/dist/file-safe-name.js.map +1 -0
  47. package/dist/formation-approval.js +5 -11
  48. package/dist/formation-approval.js.map +1 -1
  49. package/dist/fs-atomic.d.ts +0 -19
  50. package/dist/fs-atomic.js +3 -24
  51. package/dist/fs-atomic.js.map +1 -1
  52. package/dist/index.d.ts +22 -10
  53. package/dist/index.js +54 -11
  54. package/dist/index.js.map +1 -1
  55. package/dist/invitation-bootstrap.d.ts +50 -12
  56. package/dist/invitation-bootstrap.js +76 -13
  57. package/dist/invitation-bootstrap.js.map +1 -1
  58. package/dist/joined-strand-store.d.ts +7 -0
  59. package/dist/joined-strand-store.js +9 -0
  60. package/dist/joined-strand-store.js.map +1 -1
  61. package/dist/key-store-file.js +2 -1
  62. package/dist/key-store-file.js.map +1 -1
  63. package/dist/link-budget.d.ts +25 -33
  64. package/dist/link-budget.js +25 -35
  65. package/dist/link-budget.js.map +1 -1
  66. package/dist/machine-removal.d.ts +78 -0
  67. package/dist/machine-removal.js +166 -0
  68. package/dist/machine-removal.js.map +1 -0
  69. package/dist/membership-connection-gater.d.ts +191 -151
  70. package/dist/membership-connection-gater.js +236 -173
  71. package/dist/membership-connection-gater.js.map +1 -1
  72. package/dist/node-claim-payload.d.ts +74 -0
  73. package/dist/node-claim-payload.js +224 -0
  74. package/dist/node-claim-payload.js.map +1 -0
  75. package/dist/node-default-transports.d.ts +27 -0
  76. package/dist/node-default-transports.js +35 -0
  77. package/dist/node-default-transports.js.map +1 -0
  78. package/dist/node-transports.d.ts +30 -0
  79. package/dist/node-transports.js +40 -0
  80. package/dist/node-transports.js.map +1 -0
  81. package/dist/owner-anchor-sync.d.ts +22 -0
  82. package/dist/owner-anchor-sync.js +143 -0
  83. package/dist/owner-anchor-sync.js.map +1 -0
  84. package/dist/peer-authorization.d.ts +113 -18
  85. package/dist/peer-authorization.js +225 -29
  86. package/dist/peer-authorization.js.map +1 -1
  87. package/dist/peer-dial.d.ts +143 -27
  88. package/dist/peer-dial.js +276 -31
  89. package/dist/peer-dial.js.map +1 -1
  90. package/dist/peer-join-backfill.d.ts +26 -2
  91. package/dist/peer-join-backfill.js +60 -12
  92. package/dist/peer-join-backfill.js.map +1 -1
  93. package/dist/peer-record.d.ts +17 -52
  94. package/dist/peer-record.js +20 -58
  95. package/dist/peer-record.js.map +1 -1
  96. package/dist/pending-join-runner.d.ts +66 -58
  97. package/dist/pending-join-runner.js +136 -145
  98. package/dist/pending-join-runner.js.map +1 -1
  99. package/dist/primary-lan-address.d.ts +8 -0
  100. package/dist/primary-lan-address.js +46 -0
  101. package/dist/primary-lan-address.js.map +1 -0
  102. package/dist/provider/client.d.ts +131 -0
  103. package/dist/provider/client.js +226 -0
  104. package/dist/provider/client.js.map +1 -0
  105. package/dist/provider/descriptor.d.ts +41 -0
  106. package/dist/provider/descriptor.js +103 -0
  107. package/dist/provider/descriptor.js.map +1 -0
  108. package/dist/provider/index.d.ts +9 -0
  109. package/dist/provider/index.js +10 -0
  110. package/dist/provider/index.js.map +1 -0
  111. package/dist/provider/oauth.d.ts +125 -0
  112. package/dist/provider/oauth.js +199 -0
  113. package/dist/provider/oauth.js.map +1 -0
  114. package/dist/provider/rent-node.d.ts +101 -0
  115. package/dist/provider/rent-node.js +220 -0
  116. package/dist/provider/rent-node.js.map +1 -0
  117. package/dist/push-fanout.d.ts +8 -2
  118. package/dist/push-fanout.js +8 -2
  119. package/dist/push-fanout.js.map +1 -1
  120. package/dist/relay-addrs.d.ts +9 -4
  121. package/dist/relay-addrs.js +9 -4
  122. package/dist/relay-addrs.js.map +1 -1
  123. package/dist/relay-reservation.d.ts +51 -16
  124. package/dist/relay-reservation.js +107 -24
  125. package/dist/relay-reservation.js.map +1 -1
  126. package/dist/seed-bootstrap.d.ts +165 -123
  127. package/dist/seed-bootstrap.js +313 -275
  128. package/dist/seed-bootstrap.js.map +1 -1
  129. package/dist/seed-trust-policy.d.ts +98 -37
  130. package/dist/seed-trust-policy.js +188 -2
  131. package/dist/seed-trust-policy.js.map +1 -1
  132. package/dist/strand-addr-protocol.d.ts +24 -26
  133. package/dist/strand-addr-protocol.js +19 -26
  134. package/dist/strand-addr-protocol.js.map +1 -1
  135. package/dist/strand-commit-durability.d.ts +54 -0
  136. package/dist/strand-commit-durability.js +74 -0
  137. package/dist/strand-commit-durability.js.map +1 -0
  138. package/dist/strand-database.d.ts +23 -8
  139. package/dist/strand-database.js +41 -13
  140. package/dist/strand-database.js.map +1 -1
  141. package/dist/strand-first-sync-gate.d.ts +7 -1
  142. package/dist/strand-first-sync-gate.js +7 -1
  143. package/dist/strand-first-sync-gate.js.map +1 -1
  144. package/dist/strand-formation-protocol.js +5 -2
  145. package/dist/strand-formation-protocol.js.map +1 -1
  146. package/dist/strand-fret-addrs.d.ts +19 -1
  147. package/dist/strand-fret-addrs.js +27 -9
  148. package/dist/strand-fret-addrs.js.map +1 -1
  149. package/dist/strand-instance-manager.d.ts +81 -19
  150. package/dist/strand-instance-manager.js +216 -105
  151. package/dist/strand-instance-manager.js.map +1 -1
  152. package/dist/strand-move.d.ts +124 -0
  153. package/dist/strand-move.js +438 -0
  154. package/dist/strand-move.js.map +1 -0
  155. package/dist/strand-network-config.js +7 -6
  156. package/dist/strand-network-config.js.map +1 -1
  157. package/dist/strand-peer-redial.d.ts +113 -0
  158. package/dist/strand-peer-redial.js +236 -0
  159. package/dist/strand-peer-redial.js.map +1 -0
  160. package/dist/strand-revocation-enforcer.d.ts +11 -11
  161. package/dist/strand-revocation-enforcer.js +11 -11
  162. package/dist/strand-wake-protocol.d.ts +13 -16
  163. package/dist/strand-wake-protocol.js +23 -27
  164. package/dist/strand-wake-protocol.js.map +1 -1
  165. package/dist/trusted-owner-store.d.ts +35 -5
  166. package/dist/trusted-owner-store.js +50 -8
  167. package/dist/trusted-owner-store.js.map +1 -1
  168. package/dist/types.d.ts +512 -89
  169. package/dist/types.js +10 -0
  170. package/dist/types.js.map +1 -1
  171. package/package.json +19 -10
  172. package/src/cadre-invite-protocol.ts +1052 -0
  173. package/src/cadre-join-request.ts +167 -0
  174. package/src/cadre-node.ts +1703 -386
  175. package/src/claim-proof.ts +147 -0
  176. package/src/control-authorization.ts +203 -117
  177. package/src/control-cohort.ts +1 -1
  178. package/src/control-database.ts +4663 -3453
  179. package/src/control-protocol-guard.ts +348 -0
  180. package/src/control-schema.ts +828 -1078
  181. package/src/control-stream.ts +26 -7
  182. package/src/delegate-admission.ts +1 -1
  183. package/src/device-token.ts +14 -10
  184. package/src/ed25519-key.ts +47 -10
  185. package/src/fetch-impl.ts +23 -0
  186. package/src/file-durable-slot.ts +64 -63
  187. package/src/file-safe-name.ts +32 -0
  188. package/src/formation-approval.ts +604 -610
  189. package/src/fs-atomic.ts +92 -117
  190. package/src/index.ts +789 -648
  191. package/src/invitation-bootstrap.ts +91 -13
  192. package/src/joined-strand-store.ts +508 -498
  193. package/src/key-store-file.ts +142 -141
  194. package/src/link-budget.ts +25 -36
  195. package/src/machine-removal.ts +216 -0
  196. package/src/membership-connection-gater.ts +259 -191
  197. package/src/node-claim-payload.ts +259 -0
  198. package/src/node-default-transports.ts +38 -0
  199. package/src/node-transports.ts +49 -0
  200. package/src/owner-anchor-sync.ts +171 -0
  201. package/src/peer-authorization.ts +258 -29
  202. package/src/peer-dial.ts +604 -315
  203. package/src/peer-join-backfill.ts +62 -11
  204. package/src/peer-record.ts +159 -197
  205. package/src/pending-join-runner.ts +729 -735
  206. package/src/primary-lan-address.ts +47 -0
  207. package/src/provider/client.ts +326 -0
  208. package/src/provider/descriptor.ts +129 -0
  209. package/src/provider/index.ts +59 -0
  210. package/src/provider/oauth.ts +285 -0
  211. package/src/provider/rent-node.ts +275 -0
  212. package/src/push-fanout.ts +8 -2
  213. package/src/relay-addrs.ts +9 -4
  214. package/src/relay-reservation.ts +1211 -1121
  215. package/src/seed-bootstrap.ts +1502 -1448
  216. package/src/seed-trust-policy.ts +353 -140
  217. package/src/strand-addr-protocol.ts +26 -35
  218. package/src/strand-commit-durability.ts +116 -0
  219. package/src/strand-database.ts +46 -14
  220. package/src/strand-first-sync-gate.ts +7 -1
  221. package/src/strand-formation-protocol.ts +1039 -1036
  222. package/src/strand-fret-addrs.ts +179 -145
  223. package/src/strand-instance-manager.ts +2026 -1883
  224. package/src/strand-move.ts +585 -0
  225. package/src/strand-network-config.ts +7 -6
  226. package/src/strand-peer-redial.ts +307 -0
  227. package/src/strand-revocation-enforcer.ts +11 -11
  228. package/src/strand-wake-protocol.ts +23 -30
  229. package/src/trusted-owner-store.ts +242 -171
  230. package/src/types.ts +2687 -2242
@@ -0,0 +1,74 @@
1
+ /** Version 1 of the payload; the only one either side reads. */
2
+ export declare const NODE_CLAIM_PAYLOAD_PREFIX = "sereus-join:1.";
3
+ export interface NodeClaimPayload {
4
+ /** The node's peer id. */
5
+ peerId: string;
6
+ /** Addresses the phone may dial the node at, each ending in `/p2p/<peerId>`. */
7
+ multiaddrs: string[];
8
+ /** The node's claim secret, base64url (`parseClaimSecret`). */
9
+ secret: string;
10
+ }
11
+ /** Encode a payload as the text the host shows. Refuses what {@link decodeNodeClaimPayload} would. */
12
+ export declare function encodeNodeClaimPayload(payload: NodeClaimPayload): string;
13
+ /**
14
+ * Decode the text a phone scanned or pasted. Refuses, naming the problem: any version but
15
+ * 1, a body that is not base64url JSON of the right shape, a peer id that does not parse,
16
+ * an empty address list, an address that does not parse or whose last `/p2p/` is not that
17
+ * peer id, and a secret {@link parseClaimSecret} refuses. The secret is never echoed.
18
+ */
19
+ export declare function decodeNodeClaimPayload(text: string): NodeClaimPayload;
20
+ /** How {@link selectNodeClaimAddresses} narrows a node's addresses. */
21
+ export interface NodeClaimAddressOptions {
22
+ /**
23
+ * The machine's LAN address, the one a phone at home reaches it on. A string keeps only
24
+ * the private addresses on that IP (dropping Docker bridges, VPN and other interfaces no
25
+ * phone can reach); `null` drops every private address (a machine reached only by its
26
+ * public name); absent keeps them all, for a caller that cannot tell.
27
+ */
28
+ lan?: string | null;
29
+ /** Keep addresses a phone cannot dial: plain TCP. Default false, since phones dial WebSocket and relay only. */
30
+ includeTcp?: boolean;
31
+ }
32
+ /**
33
+ * The addresses a node code should carry, from the ones a node knows it has (`/status`,
34
+ * a NAT layer's public addresses). A phone dials them in turn, each on its own timeout, so
35
+ * every address it cannot reach only delays a failing claim, and makes the QR code bigger.
36
+ *
37
+ * - Each gains `/p2p/<peerId>` when it lacks a destination; loopback, unspecified and
38
+ * unparsable ones are dropped, and so is plain TCP unless `includeTcp`.
39
+ * - Public names (`/dns*`) come first: they work away from home. Public IP addresses are
40
+ * kept only when there is no public name, since they reach the same machine.
41
+ * - Private addresses follow, narrowed by {@link NodeClaimAddressOptions.lan}; relay
42
+ * addresses last.
43
+ *
44
+ * Pure and dependency-light, like the codec beside it, so it loads on React Native too.
45
+ * Finding the LAN address is the caller's (Node: `@serfab/cadre-core/primary-lan-address`).
46
+ */
47
+ export declare function selectNodeClaimAddresses(reported: readonly string[], peerId: string, options?: NodeClaimAddressOptions): string[];
48
+ /**
49
+ * `addr` as a node code carries it: with `/p2p/<peerId>` appended unless it already names a
50
+ * destination. A relay address that ends at its hop (`…/p2p/<relay>/p2p-circuit`) names none,
51
+ * so it gains the node's id too. Throws when `addr` does not parse. For callers that take
52
+ * exact addresses from an operator; {@link selectNodeClaimAddresses} applies it itself.
53
+ */
54
+ export declare function withClaimDestination(addr: string, peerId: string): string;
55
+ /**
56
+ * Where a phone could dial an address from: a relayed address (`/p2p-circuit`), a public name,
57
+ * a public IP, a private (LAN, VPN, link-local) IP, or this machine's own loopback.
58
+ */
59
+ export type DialAddressKind = 'relay' | 'name' | 'public' | 'private' | 'loopback';
60
+ /**
61
+ * Classify `addr` for a phone dialing it, or undefined when no phone can dial it at all: it
62
+ * does not parse, names the unspecified address, or is plain TCP without `includeTcp` (phones
63
+ * dial WebSocket and relay only).
64
+ */
65
+ export declare function classifyDialAddress(addr: string, options?: {
66
+ includeTcp?: boolean;
67
+ }): DialAddressKind | undefined;
68
+ /**
69
+ * The peer an address reaches: its last `/p2p/` component. A relayed address
70
+ * (`…/p2p/<relay>/p2p-circuit/p2p/<destination>`) names its destination after the
71
+ * circuit hop; one that ends at the hop names nobody. Same rule as
72
+ * `groupAddrsByPeerId` in `peer-addr-book.ts`. Throws when `addr` does not parse.
73
+ */
74
+ export declare function destinationPeerIdOf(addr: string): string | null;
@@ -0,0 +1,224 @@
1
+ /**
2
+ * The claim payload: what a host shows as a QR code (and as text) for a node that is
3
+ * waiting to be claimed, and what the owner's phone scans to claim it.
4
+ *
5
+ * `sereus-join:1.<base64url of canonical JSON>` where the JSON is
6
+ * `{ multiaddrs, peerId, secret }`: the node's peer id, every address the phone may
7
+ * dial it at (each ending in `/p2p/<peerId>`), and the node's one-time claim secret
8
+ * (`claim-proof.ts`). The phone hands all three to `CadreNode.claimNode`. The payload
9
+ * carries no party id: the claim supplies it, and the node records it.
10
+ *
11
+ * The decoder lives here, beside the encoder, because the phone and the host both need
12
+ * it and neither depends on the other. Imports only `@multiformats/multiaddr`,
13
+ * `@libp2p/peer-id` and `uint8arrays`, so it loads on React Native and in the browser.
14
+ */
15
+ import { peerIdFromString } from '@libp2p/peer-id';
16
+ import { multiaddr, CODE_DNS, CODE_DNS4, CODE_DNS6, CODE_DNSADDR, CODE_IP4, CODE_IP6, CODE_IP6ZONE, CODE_P2P, CODE_P2P_CIRCUIT, CODE_WS, CODE_WSS, } from '@multiformats/multiaddr';
17
+ import { fromString as uint8ArrayFromString, toString as uint8ArrayToString } from 'uint8arrays';
18
+ import { canonicalJson } from './canonical-json.js';
19
+ import { parseClaimSecret } from './claim-proof.js';
20
+ /** Version 1 of the payload; the only one either side reads. */
21
+ export const NODE_CLAIM_PAYLOAD_PREFIX = 'sereus-join:1.';
22
+ /** Encode a payload as the text the host shows. Refuses what {@link decodeNodeClaimPayload} would. */
23
+ export function encodeNodeClaimPayload(payload) {
24
+ const checked = requireNodeClaimPayload(payload);
25
+ const json = canonicalJson({ multiaddrs: checked.multiaddrs, peerId: checked.peerId, secret: checked.secret });
26
+ return `${NODE_CLAIM_PAYLOAD_PREFIX}${uint8ArrayToString(new TextEncoder().encode(json), 'base64url')}`;
27
+ }
28
+ /**
29
+ * Decode the text a phone scanned or pasted. Refuses, naming the problem: any version but
30
+ * 1, a body that is not base64url JSON of the right shape, a peer id that does not parse,
31
+ * an empty address list, an address that does not parse or whose last `/p2p/` is not that
32
+ * peer id, and a secret {@link parseClaimSecret} refuses. The secret is never echoed.
33
+ */
34
+ export function decodeNodeClaimPayload(text) {
35
+ const trimmed = text.trim();
36
+ if (!trimmed.startsWith(NODE_CLAIM_PAYLOAD_PREFIX)) {
37
+ throw new Error(`A claim payload must start with "${NODE_CLAIM_PAYLOAD_PREFIX}" (this one starts with "${trimmed.slice(0, NODE_CLAIM_PAYLOAD_PREFIX.length)}")`);
38
+ }
39
+ let parsed;
40
+ try {
41
+ const json = new TextDecoder().decode(uint8ArrayFromString(trimmed.slice(NODE_CLAIM_PAYLOAD_PREFIX.length), 'base64url'));
42
+ parsed = JSON.parse(json);
43
+ }
44
+ catch (error) {
45
+ throw new Error('A claim payload must carry base64url-encoded JSON after its prefix', { cause: error });
46
+ }
47
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
48
+ throw new Error('A claim payload must decode to a JSON object');
49
+ }
50
+ const { peerId, multiaddrs, secret } = parsed;
51
+ if (typeof peerId !== 'string')
52
+ throw new Error('A claim payload must name the node\'s peer id');
53
+ if (!Array.isArray(multiaddrs) || !multiaddrs.every((a) => typeof a === 'string')) {
54
+ throw new Error('A claim payload must carry the node\'s addresses as a list of strings');
55
+ }
56
+ if (typeof secret !== 'string')
57
+ throw new Error('A claim payload must carry the claim secret');
58
+ return requireNodeClaimPayload({ peerId, multiaddrs, secret });
59
+ }
60
+ /**
61
+ * The addresses a node code should carry, from the ones a node knows it has (`/status`,
62
+ * a NAT layer's public addresses). A phone dials them in turn, each on its own timeout, so
63
+ * every address it cannot reach only delays a failing claim, and makes the QR code bigger.
64
+ *
65
+ * - Each gains `/p2p/<peerId>` when it lacks a destination; loopback, unspecified and
66
+ * unparsable ones are dropped, and so is plain TCP unless `includeTcp`.
67
+ * - Public names (`/dns*`) come first: they work away from home. Public IP addresses are
68
+ * kept only when there is no public name, since they reach the same machine.
69
+ * - Private addresses follow, narrowed by {@link NodeClaimAddressOptions.lan}; relay
70
+ * addresses last.
71
+ *
72
+ * Pure and dependency-light, like the codec beside it, so it loads on React Native too.
73
+ * Finding the LAN address is the caller's (Node: `@serfab/cadre-core/primary-lan-address`).
74
+ */
75
+ export function selectNodeClaimAddresses(reported, peerId, options = {}) {
76
+ const names = [];
77
+ const publicIps = [];
78
+ const privates = [];
79
+ const relayed = [];
80
+ for (const raw of reported) {
81
+ const classified = classifyClaimAddress(raw.trim(), peerId, options);
82
+ if (!classified)
83
+ continue;
84
+ ({ name: names, public: publicIps, private: privates, relay: relayed })[classified.kind].push(classified.addr);
85
+ }
86
+ return [...new Set([...names, ...(names.length > 0 ? [] : publicIps), ...privates, ...relayed])];
87
+ }
88
+ /**
89
+ * `addr` as a node code carries it: with `/p2p/<peerId>` appended unless it already names a
90
+ * destination. A relay address that ends at its hop (`…/p2p/<relay>/p2p-circuit`) names none,
91
+ * so it gains the node's id too. Throws when `addr` does not parse. For callers that take
92
+ * exact addresses from an operator; {@link selectNodeClaimAddresses} applies it itself.
93
+ */
94
+ export function withClaimDestination(addr, peerId) {
95
+ const trimmed = addr.trim();
96
+ return destinationPeerIdOf(trimmed) === null ? `${trimmed}/p2p/${peerId}` : trimmed;
97
+ }
98
+ /**
99
+ * Classify `addr` for a phone dialing it, or undefined when no phone can dial it at all: it
100
+ * does not parse, names the unspecified address, or is plain TCP without `includeTcp` (phones
101
+ * dial WebSocket and relay only).
102
+ */
103
+ export function classifyDialAddress(addr, options = {}) {
104
+ const components = componentsOf(addr);
105
+ return components ? classifyComponents(components, options.includeTcp ?? false)?.kind : undefined;
106
+ }
107
+ function componentsOf(addr) {
108
+ try {
109
+ return multiaddr(addr).getComponents();
110
+ }
111
+ catch {
112
+ return undefined;
113
+ }
114
+ }
115
+ /** {@link classifyDialAddress}, keeping the IP for a caller that narrows private addresses by it. */
116
+ function classifyComponents(components, includeTcp) {
117
+ if (components.some((c) => c.code === CODE_P2P_CIRCUIT))
118
+ return { kind: 'relay' };
119
+ if (!includeTcp && !components.some((c) => c.code === CODE_WS || c.code === CODE_WSS))
120
+ return undefined;
121
+ const host = components[0];
122
+ if (!host?.value)
123
+ return undefined;
124
+ if (host.code === CODE_DNS || host.code === CODE_DNS4 || host.code === CODE_DNS6 || host.code === CODE_DNSADDR) {
125
+ return { kind: host.value === 'localhost' ? 'loopback' : 'name' };
126
+ }
127
+ if (host.code !== CODE_IP4 && host.code !== CODE_IP6 && host.code !== CODE_IP6ZONE)
128
+ return undefined;
129
+ const ip = host.code === CODE_IP6ZONE ? components[1]?.value ?? '' : host.value;
130
+ if (ip === '0.0.0.0' || ip === '::')
131
+ return undefined;
132
+ if (ip.startsWith('127.') || ip === '::1')
133
+ return { kind: 'loopback', ip };
134
+ if (host.code !== CODE_IP6ZONE && !isPrivateIp(ip))
135
+ return { kind: 'public', ip };
136
+ return { kind: 'private', ip };
137
+ }
138
+ /** One address's place in {@link selectNodeClaimAddresses}, or undefined to drop it. */
139
+ function classifyClaimAddress(addr, peerId, options) {
140
+ const components = componentsOf(addr);
141
+ if (!components)
142
+ return undefined;
143
+ const classified = classifyComponents(components, options.includeTcp ?? false);
144
+ if (!classified || classified.kind === 'loopback')
145
+ return undefined;
146
+ if (classified.kind === 'private' && (options.lan === null || (options.lan !== undefined && classified.ip !== options.lan))) {
147
+ return undefined;
148
+ }
149
+ return { kind: classified.kind, addr: destinationIn(components) === null ? `${addr}/p2p/${peerId}` : addr };
150
+ }
151
+ /** RFC 1918, carrier-grade NAT (100.64/10), link-local, and IPv6 unique-local / link-local. */
152
+ function isPrivateIp(ip) {
153
+ if (ip.includes(':'))
154
+ return /^(f[cd]|fe[89ab])/i.test(ip);
155
+ const [a, b] = ip.split('.').map(Number);
156
+ return a === 10
157
+ || (a === 172 && b >= 16 && b <= 31)
158
+ || (a === 192 && b === 168)
159
+ || (a === 169 && b === 254)
160
+ || (a === 100 && b >= 64 && b <= 127);
161
+ }
162
+ /** The shape rules both directions apply. Returns the payload with its fields trimmed. */
163
+ function requireNodeClaimPayload(payload) {
164
+ const peerId = parsePeerId(payload.peerId);
165
+ const multiaddrs = payload.multiaddrs.map((a) => a.trim());
166
+ if (multiaddrs.length === 0)
167
+ throw new Error('A claim payload must carry at least one address for the node');
168
+ for (const addr of multiaddrs)
169
+ requireAddressOf(addr, peerId);
170
+ // The secret is checked, never kept in a message: see `parseClaimSecret`.
171
+ parseClaimSecret(payload.secret);
172
+ return { peerId: peerId.toString(), multiaddrs, secret: payload.secret.trim() };
173
+ }
174
+ function parsePeerId(text) {
175
+ try {
176
+ return peerIdFromString(text.trim());
177
+ }
178
+ catch (error) {
179
+ throw new Error(`A claim payload's peer id does not parse ("${text}")`, { cause: error });
180
+ }
181
+ }
182
+ /** `addr` parses, and its destination (the last `/p2p/`, past any relay hop) is `peerId`. */
183
+ function requireAddressOf(addr, peerId) {
184
+ let destination;
185
+ try {
186
+ destination = destinationPeerIdOf(addr);
187
+ }
188
+ catch (error) {
189
+ throw new Error(`A claim payload address does not parse ("${addr}")`, { cause: error });
190
+ }
191
+ if (destination === null) {
192
+ throw new Error(`A claim payload address must end in /p2p/${peerId.toString()} ("${addr}" names no peer)`);
193
+ }
194
+ let named;
195
+ try {
196
+ named = peerIdFromString(destination);
197
+ }
198
+ catch (error) {
199
+ throw new Error(`A claim payload address names a peer id that does not parse ("${addr}")`, { cause: error });
200
+ }
201
+ if (!named.equals(peerId)) {
202
+ throw new Error(`A claim payload address names another peer ("${addr}" is not an address of ${peerId.toString()})`);
203
+ }
204
+ }
205
+ /**
206
+ * The peer an address reaches: its last `/p2p/` component. A relayed address
207
+ * (`…/p2p/<relay>/p2p-circuit/p2p/<destination>`) names its destination after the
208
+ * circuit hop; one that ends at the hop names nobody. Same rule as
209
+ * `groupAddrsByPeerId` in `peer-addr-book.ts`. Throws when `addr` does not parse.
210
+ */
211
+ export function destinationPeerIdOf(addr) {
212
+ return destinationIn(multiaddr(addr).getComponents());
213
+ }
214
+ function destinationIn(components) {
215
+ for (let i = components.length - 1; i >= 0; i--) {
216
+ const component = components[i];
217
+ if (component.code === CODE_P2P_CIRCUIT)
218
+ return null;
219
+ if (component.code === CODE_P2P && component.value)
220
+ return component.value;
221
+ }
222
+ return null;
223
+ }
224
+ //# sourceMappingURL=node-claim-payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-claim-payload.js","sourceRoot":"","sources":["../src/node-claim-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EACN,SAAS,EACT,QAAQ,EACR,SAAS,EACT,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,OAAO,EACP,QAAQ,GACR,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjG,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,gEAAgE;AAChE,MAAM,CAAC,MAAM,yBAAyB,GAAG,gBAAgB,CAAC;AAW1D,sGAAsG;AACtG,MAAM,UAAU,sBAAsB,CAAC,OAAyB;IAC/D,MAAM,OAAO,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,aAAa,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/G,OAAO,GAAG,yBAAyB,GAAG,kBAAkB,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC;AACzG,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,yBAAyB,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,oCAAoC,yBAAyB,4BAA4B,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,yBAAyB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAClK,CAAC;IACD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;QAC1H,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,oEAAoE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACzG,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAiC,CAAC;IACzE,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACjG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;QAChG,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAC/F,OAAO,uBAAuB,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;AAChE,CAAC;AAeD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CAAC,QAA2B,EAAE,MAAc,EAAE,UAAmC,EAAE;IAC1H,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,oBAAoB,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QACrE,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAChH,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAClG,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,MAAc;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,OAAO,mBAAmB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,QAAQ,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AACrF,CAAC;AAQD;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,UAAoC,EAAE;IACvF,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACnG,CAAC;AAID,SAAS,YAAY,CAAC,IAAY;IACjC,IAAI,CAAC;QACJ,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,qGAAqG;AACrG,SAAS,kBAAkB,CAAC,UAA6B,EAAE,UAAmB;IAC7E,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAClF,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IACxG,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI,EAAE,KAAK;QAAE,OAAO,SAAS,CAAC;IACnC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAChH,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACnE,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,SAAS,CAAC;IACrG,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;IAChF,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACtD,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IAC3E,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAClF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;AAChC,CAAC;AAED,wFAAwF;AACxF,SAAS,oBAAoB,CAAC,IAAY,EAAE,MAAc,EAAE,OAAgC;IAC3F,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAClC,MAAM,UAAU,GAAG,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC,CAAC;IAC/E,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,SAAS,CAAC;IACpE,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,KAAK,SAAS,IAAI,UAAU,CAAC,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC7H,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,QAAQ,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC7G,CAAC;AAED,+FAA+F;AAC/F,SAAS,WAAW,CAAC,EAAU;IAC9B,IAAI,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3D,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAqB,CAAC;IAC7D,OAAO,CAAC,KAAK,EAAE;WACX,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;WACjC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC;WACxB,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC;WACxB,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;AACxC,CAAC;AAED,0FAA0F;AAC1F,SAAS,uBAAuB,CAAC,OAAyB;IACzD,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAC7G,KAAK,MAAM,IAAI,IAAI,UAAU;QAAE,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9D,0EAA0E;IAC1E,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;AACjF,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAChC,IAAI,CAAC;QACJ,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,8CAA8C,IAAI,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3F,CAAC;AACF,CAAC;AAED,6FAA6F;AAC7F,SAAS,gBAAgB,CAAC,IAAY,EAAE,MAA2C;IAClF,IAAI,WAA0B,CAAC;IAC/B,IAAI,CAAC;QACJ,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,4CAA4C,MAAM,CAAC,QAAQ,EAAE,MAAM,IAAI,kBAAkB,CAAC,CAAC;IAC5G,CAAC;IACD,IAAI,KAA0C,CAAC;IAC/C,IAAI,CAAC;QACJ,KAAK,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,iEAAiE,IAAI,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9G,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,gDAAgD,IAAI,0BAA0B,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACrH,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC/C,OAAO,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,aAAa,CAAC,UAA6B;IACnD,KAAK,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;QACjC,IAAI,SAAS,CAAC,IAAI,KAAK,gBAAgB;YAAE,OAAO,IAAI,CAAC;QACrD,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,IAAI,SAAS,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC,KAAK,CAAC;IAC5E,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Node-only: `@optimystic/db-p2p`'s default transport list, for `NetworkConfig.defaultTransports`.
3
+ *
4
+ * A node with configured relays is built from an explicit transport list, so that libp2p's relay
5
+ * discovery can be switched off in it (`node-transports.ts`). A Node host that supplies no
6
+ * `network.transports` passes this function so that list still matches what db-p2p would have
7
+ * built. A subpath module (`@serfab/cadre-core/node-default-transports`), like `push-node`,
8
+ * because it names `@libp2p/tcp`: some bundlers (the NativeScript reference app's webpack) take
9
+ * its Node implementation rather than its browser stub, and that needs `net`, `os` and `path`.
10
+ */
11
+ import type { Libp2pTransports } from '@optimystic/db-p2p';
12
+ import type { ListenTransportOptions } from './relay-addrs.js';
13
+ /**
14
+ * TCP, WebSocket exactly when the node's listen entries switch it on, and the circuit-relay
15
+ * transport.
16
+ *
17
+ * Passing an explicit list makes db-p2p ignore `wsPort` for transports, which is why WebSocket is
18
+ * decided here from the same switch. Its other use of `wsPort`, a default WebSocket listen
19
+ * address, never applies: a node with configured relays always has explicit listen entries.
20
+ *
21
+ * NOTE: mirrors `createLibp2pNode`'s default list in
22
+ * `../optimystic/packages/db-p2p/src/libp2p-node.ts` (cadre never sets its `disableTcp`). That file
23
+ * is the source of truth; if its defaults change, this list has to follow. If db-p2p ever takes an
24
+ * option to build its default list with relay discovery off, use that and drop this module and
25
+ * `NetworkConfig.defaultTransports`.
26
+ */
27
+ export declare function nodeDefaultTransports({ wsPort }: ListenTransportOptions): Libp2pTransports;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Node-only: `@optimystic/db-p2p`'s default transport list, for `NetworkConfig.defaultTransports`.
3
+ *
4
+ * A node with configured relays is built from an explicit transport list, so that libp2p's relay
5
+ * discovery can be switched off in it (`node-transports.ts`). A Node host that supplies no
6
+ * `network.transports` passes this function so that list still matches what db-p2p would have
7
+ * built. A subpath module (`@serfab/cadre-core/node-default-transports`), like `push-node`,
8
+ * because it names `@libp2p/tcp`: some bundlers (the NativeScript reference app's webpack) take
9
+ * its Node implementation rather than its browser stub, and that needs `net`, `os` and `path`.
10
+ */
11
+ import { tcp } from '@libp2p/tcp';
12
+ import { webSockets } from '@libp2p/websockets';
13
+ import { circuitRelayTransport } from '@libp2p/circuit-relay-v2';
14
+ /**
15
+ * TCP, WebSocket exactly when the node's listen entries switch it on, and the circuit-relay
16
+ * transport.
17
+ *
18
+ * Passing an explicit list makes db-p2p ignore `wsPort` for transports, which is why WebSocket is
19
+ * decided here from the same switch. Its other use of `wsPort`, a default WebSocket listen
20
+ * address, never applies: a node with configured relays always has explicit listen entries.
21
+ *
22
+ * NOTE: mirrors `createLibp2pNode`'s default list in
23
+ * `../optimystic/packages/db-p2p/src/libp2p-node.ts` (cadre never sets its `disableTcp`). That file
24
+ * is the source of truth; if its defaults change, this list has to follow. If db-p2p ever takes an
25
+ * option to build its default list with relay discovery off, use that and drop this module and
26
+ * `NetworkConfig.defaultTransports`.
27
+ */
28
+ export function nodeDefaultTransports({ wsPort }) {
29
+ return [
30
+ tcp(),
31
+ ...(wsPort === undefined ? [] : [webSockets()]),
32
+ circuitRelayTransport()
33
+ ];
34
+ }
35
+ //# sourceMappingURL=node-default-transports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-default-transports.js","sourceRoot":"","sources":["../src/node-default-transports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAIjE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAE,MAAM,EAA0B;IACtE,OAAO;QACL,GAAG,EAAE;QACL,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QAC/C,qBAAqB,EAAE;KACxB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The `transports` option for a cadre-built libp2p node, control and strand alike.
3
+ *
4
+ * A node whose bare `/p2p-circuit` search entries cadre generated for configured relays gets its
5
+ * transports through {@link withoutRelayDiscovery}, so libp2p's relay discovery cannot hand those
6
+ * slots to some other relay-capable peer before the per-relay supervisors fill them (see
7
+ * `relay-reservation.ts`, "WHY LIBP2P'S RELAY DISCOVERY IS SWITCHED OFF"). Every other node gets
8
+ * the embedder's list as it was, or no option at all, and `@optimystic/db-p2p` builds its own
9
+ * default list.
10
+ *
11
+ * The wrapper needs a list to wrap. React Native and browser embedders always supply one
12
+ * (`network.transports`); a Node host supplies the default list through
13
+ * `network.defaultTransports` instead, since db-p2p builds its default internally and it names
14
+ * `@libp2p/tcp`, which this module's graph must not reach (`node-default-transports.ts`).
15
+ */
16
+ import type { Libp2pTransports } from '@optimystic/db-p2p';
17
+ import type { ListenTransportOptions } from './relay-addrs.js';
18
+ import type { NetworkConfig } from './types.js';
19
+ /**
20
+ * The `transports` option to spread into a node's `createLibp2pNode` options.
21
+ *
22
+ * @param listenTransports what the node's resolved listen entries imply (`resolveTransportOptions`
23
+ * in `relay-addrs.ts`), handed to `network.defaultTransports`.
24
+ * @param relaySlotsSupervised whether cadre generated this node's bare `/p2p-circuit` entries for
25
+ * configured relays and runs a supervisor over them — `network.relayAddrs` on the control node,
26
+ * a non-empty relay list from `strandNodeAddrs` on a strand node.
27
+ */
28
+ export declare function nodeTransportsOption(network: NetworkConfig | undefined, listenTransports: ListenTransportOptions, relaySlotsSupervised: boolean): {
29
+ transports?: Libp2pTransports;
30
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The `transports` option for a cadre-built libp2p node, control and strand alike.
3
+ *
4
+ * A node whose bare `/p2p-circuit` search entries cadre generated for configured relays gets its
5
+ * transports through {@link withoutRelayDiscovery}, so libp2p's relay discovery cannot hand those
6
+ * slots to some other relay-capable peer before the per-relay supervisors fill them (see
7
+ * `relay-reservation.ts`, "WHY LIBP2P'S RELAY DISCOVERY IS SWITCHED OFF"). Every other node gets
8
+ * the embedder's list as it was, or no option at all, and `@optimystic/db-p2p` builds its own
9
+ * default list.
10
+ *
11
+ * The wrapper needs a list to wrap. React Native and browser embedders always supply one
12
+ * (`network.transports`); a Node host supplies the default list through
13
+ * `network.defaultTransports` instead, since db-p2p builds its default internally and it names
14
+ * `@libp2p/tcp`, which this module's graph must not reach (`node-default-transports.ts`).
15
+ */
16
+ import debug from 'debug';
17
+ import { withoutRelayDiscovery } from './relay-reservation.js';
18
+ const log = debug('sereus:cadre:node-transports');
19
+ /**
20
+ * The `transports` option to spread into a node's `createLibp2pNode` options.
21
+ *
22
+ * @param listenTransports what the node's resolved listen entries imply (`resolveTransportOptions`
23
+ * in `relay-addrs.ts`), handed to `network.defaultTransports`.
24
+ * @param relaySlotsSupervised whether cadre generated this node's bare `/p2p-circuit` entries for
25
+ * configured relays and runs a supervisor over them — `network.relayAddrs` on the control node,
26
+ * a non-empty relay list from `strandNodeAddrs` on a strand node.
27
+ */
28
+ export function nodeTransportsOption(network, listenTransports, relaySlotsSupervised) {
29
+ if (!relaySlotsSupervised) {
30
+ return network?.transports ? { transports: network.transports } : {};
31
+ }
32
+ const transports = network?.transports ?? network?.defaultTransports?.(listenTransports);
33
+ if (transports === undefined) {
34
+ log('Relays are configured but no transport list was supplied (network.transports or ' +
35
+ 'network.defaultTransports); libp2p relay discovery stays on and can take their slots');
36
+ return {};
37
+ }
38
+ return { transports: withoutRelayDiscovery(transports) };
39
+ }
40
+ //# sourceMappingURL=node-transports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-transports.js","sourceRoot":"","sources":["../src/node-transports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAI/D,MAAM,GAAG,GAAG,KAAK,CAAC,8BAA8B,CAAC,CAAC;AAElD;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAkC,EAClC,gBAAwC,EACxC,oBAA6B;IAE7B,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC1B,OAAO,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvE,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,OAAO,EAAE,iBAAiB,EAAE,CAAC,gBAAgB,CAAC,CAAC;IACzF,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,GAAG,CAAC,kFAAkF;YACpF,sFAAsF,CAAC,CAAC;QAC1F,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,qBAAqB,CAAC,UAAU,CAAC,EAAE,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { TrustSource } from './trusted-owner-store.js';
2
+ import type { InvitationChain, OwnerKeyRow, RevocationRow } from './types.js';
3
+ export interface OwnerAnchorInputs {
4
+ /** The party whose table is being read; every stored proof is judged for it, so a voucher or tombstone signed for another party neither seats nor removes a key. */
5
+ partyId: string;
6
+ /** The anchor at the start of the pass, every key with its provenance (`TrustedOwnerStore.sources`). */
7
+ anchor: ReadonlyMap<string, TrustSource>;
8
+ /** `OwnerKey` rows as read; rows whose stamp a tombstone in `tombstones` retires are dropped here too. */
9
+ rows: readonly OwnerKeyRow[];
10
+ /** `Revocation` rows; only those with `tableName === 'OwnerKey'` are consulted. */
11
+ tombstones: readonly RevocationRow[];
12
+ /** The usage and invitation rows, when some owner row is invitation-admitted; null skips those rows. */
13
+ chain: InvitationChain | null;
14
+ }
15
+ export interface OwnerAnchorDerivation {
16
+ /** The keys the anchor should hold after this pass. */
17
+ target: ReadonlySet<string>;
18
+ /** Keys whose verifiable removal was NOT applied because the anchor would have emptied. */
19
+ refusedRemovals: readonly string[];
20
+ }
21
+ /** The rule above, as one pure function. */
22
+ export declare function deriveOwnerAnchor({ partyId, anchor, rows, tombstones, chain }: OwnerAnchorInputs): OwnerAnchorDerivation;
@@ -0,0 +1,143 @@
1
+ /**
2
+ * How the node-local trusted-owner anchor follows the replicated `OwnerKey` table along
3
+ * VERIFIABLE chains — the pure rule, with no I/O, so it can be tested without a database.
4
+ * `CadreNode.syncOwnerAnchor` reads the table, the tombstones and the invitation chain,
5
+ * calls {@link deriveOwnerAnchor}, and applies the difference to the store.
6
+ *
7
+ * Why not simply trust the table: an empty local copy can seat any key through the
8
+ * schema's genesis branch and that row replicates (`docs/architecture.md` → "Node-local
9
+ * trusted-owner anchor"). So every node grows its anchor only through rows whose stored
10
+ * proof verifies against a key it already trusts, on every membership refresh. The terms
11
+ * used throughout:
12
+ *
13
+ * - **base**: the anchor's entries whose provenance is not `chain` (trusted out of band).
14
+ * - **live row**: an `OwnerKey` row whose stamp no tombstone retires.
15
+ * - **kept**: a `chain` entry that still has a live row. A derived entry is state, not
16
+ * recomputed from the base each pass: it entered through a proof that verified then, and
17
+ * it stays until its own row is retired or a verifiable tombstone removes it. This is what
18
+ * lets an owner rotate (A adds A', A' removes A): A' keeps its place after A's row is
19
+ * retired, although nothing could re-derive it from the remaining base.
20
+ * - **derivable from S**: a live row whose stored proof verifies against S — owner-signed
21
+ * (`vouchSig` set): `vouchOwner` is in S and `verifyOwnerKeyVoucher` holds;
22
+ * invitation-admitted (`vouchSig` null, `vouchUsage` set): `verifyInvitationOwnerAdmission`
23
+ * holds with S as the anchor. The founding row (all three null) is never derivable:
24
+ * founders enter anchors only out of band.
25
+ * - **derived**: the least fixpoint from base ∪ kept — add every key whose live row is
26
+ * derivable from what is already in the set, until nothing changes. **chainDerived** is the
27
+ * keys whose live row was derivable in this pass, base keys included.
28
+ * - **removed**: a key K in derived is removed when an `OwnerKey` tombstone names K, its
29
+ * signer is in derived and is not K, its stored signature verifies
30
+ * (`verifyRevocationSigner`), AND K is not in chainDerived. The last condition is what
31
+ * makes a re-add win over an older tombstone: a removed owner re-added under a fresh
32
+ * stamp has a live derivable row again, and the old stamp's tombstone no longer applies.
33
+ * - **target** = derived minus removed. If that would be empty, no removal is applied this
34
+ * pass (target = derived) and the refused removals are reported for the caller to log.
35
+ *
36
+ * Every tombstone is judged against the pass-start set (derived) at once, so the outcome
37
+ * does not depend on the order they are read in: a signer that is itself removed in this
38
+ * pass still counts, and a mutual removal of the last two owners is refused rather than
39
+ * decided by read order.
40
+ *
41
+ * An owner C that a removed owner B had added therefore stays where it was already derived
42
+ * (its row is live) and cannot be derived on a machine that never held it (the chain from
43
+ * that machine's base runs through B's retired row) until a remaining owner re-adds it or
44
+ * an invitation pins it there. The rotation case above is the same shape with C = A', so the
45
+ * two cannot be told apart from replicated state; keeping is the only rule under which a
46
+ * sole owner can rotate at all.
47
+ */
48
+ import { verifyInvitationOwnerAdmission, verifyOwnerKeyVoucher, verifyRevocationSigner } from './peer-authorization.js';
49
+ /** The rule above, as one pure function. */
50
+ export function deriveOwnerAnchor({ partyId, anchor, rows, tombstones, chain }) {
51
+ const ownerTombstones = tombstones.filter(tombstone => tombstone.tableName === 'OwnerKey');
52
+ // NOTE: a stamp is retired by any tombstone that names it, verified or not — the same
53
+ // reading `queryCadrePeers` and `getOwnerKeys` give the table. A forged tombstone can
54
+ // therefore prune a derived entry (its row goes) but never seat or keep one; if tombstone
55
+ // pollution is ever closed at the write side, judge retirement by the verified signer too.
56
+ const retired = new Set(ownerTombstones.map(tombstone => tombstone.stampId));
57
+ const liveRows = rows.filter(row => !retired.has(row.stampId));
58
+ const derived = passStartSet(anchor, liveRows);
59
+ const chainDerived = deriveFixpoint(partyId, derived, liveRows, chain);
60
+ const removed = removedKeys(partyId, derived, chainDerived, ownerTombstones);
61
+ if (removed.size > 0 && removed.size === derived.size) {
62
+ return { target: derived, refusedRemovals: Array.from(removed) };
63
+ }
64
+ const target = new Set(Array.from(derived).filter(key => !removed.has(key)));
65
+ return { target, refusedRemovals: [] };
66
+ }
67
+ /** base ∪ kept: every out-of-band entry, and every `chain` entry whose row is still live. */
68
+ function passStartSet(anchor, liveRows) {
69
+ const liveKeys = new Set(liveRows.map(row => row.key));
70
+ const start = new Set();
71
+ for (const [key, source] of anchor) {
72
+ if (source !== 'chain' || liveKeys.has(key)) {
73
+ start.add(key);
74
+ }
75
+ }
76
+ return start;
77
+ }
78
+ /**
79
+ * Grow `derived` to the least fixpoint and return chainDerived: every key whose live row was
80
+ * derivable. A row is judged once its voucher is in the set, and settled either way then:
81
+ * trust only grows within a pass, and a proof that failed against a trusted voucher cannot
82
+ * pass later, so no row is verified twice.
83
+ */
84
+ function deriveFixpoint(partyId, derived, liveRows, chain) {
85
+ const chainDerived = new Set();
86
+ const pending = new Set(liveRows);
87
+ let progress = true;
88
+ while (progress) {
89
+ progress = false;
90
+ for (const row of pending) {
91
+ if (row.vouchOwner === null || !derived.has(row.vouchOwner)) {
92
+ continue;
93
+ }
94
+ pending.delete(row);
95
+ if (proofVerifies(partyId, row, derived, chain)) {
96
+ chainDerived.add(row.key);
97
+ derived.add(row.key);
98
+ progress = true;
99
+ }
100
+ }
101
+ }
102
+ return chainDerived;
103
+ }
104
+ /** Does `row`'s stored proof verify against `trusted`, for `partyId`, by the kind of proof it carries (see the module doc)? */
105
+ function proofVerifies(partyId, row, trusted, chain) {
106
+ if (row.vouchOwner === null) {
107
+ return false;
108
+ }
109
+ if (row.vouchSig !== null) {
110
+ return verifyOwnerKeyVoucher(partyId, row.key, row.stampId, row.vouchOwner, row.vouchSig);
111
+ }
112
+ if (row.vouchUsage === null) {
113
+ return false;
114
+ }
115
+ const usage = chain?.usages.get(row.vouchUsage);
116
+ const invite = usage === undefined ? undefined : chain?.invites.get(usage.inviteKey);
117
+ if (usage === undefined || invite === undefined) {
118
+ return false;
119
+ }
120
+ return verifyInvitationOwnerAdmission(partyId, row, usage, invite, key => trusted.has(key));
121
+ }
122
+ /**
123
+ * The keys of `derived` that a verifiable tombstone removes (see the module doc), every
124
+ * tombstone judged against the same pass-start set. A tombstone for a key outside `derived`
125
+ * changes nothing and is skipped before any signature work.
126
+ */
127
+ function removedKeys(partyId, derived, chainDerived, ownerTombstones) {
128
+ const removed = new Set();
129
+ for (const tombstone of ownerTombstones) {
130
+ const key = tombstone.rowKey;
131
+ if (!derived.has(key) || chainDerived.has(key) || removed.has(key)) {
132
+ continue;
133
+ }
134
+ if (tombstone.signerKey === key || !derived.has(tombstone.signerKey)) {
135
+ continue;
136
+ }
137
+ if (verifyRevocationSigner(partyId, tombstone)) {
138
+ removed.add(key);
139
+ }
140
+ }
141
+ return removed;
142
+ }
143
+ //# sourceMappingURL=owner-anchor-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner-anchor-sync.js","sourceRoot":"","sources":["../src/owner-anchor-sync.ts"],"names":[],"mappings":"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"}