@serfab/cadre-core 1.16.0 → 1.17.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 (199) hide show
  1. package/README.md +1 -1
  2. package/dist/bootstrap-peer-store-file.js +1 -1
  3. package/dist/bootstrap-peer-store.d.ts +1 -1
  4. package/dist/bootstrap-peer-store.js +4 -4
  5. package/dist/cadre-invite-protocol.d.ts +55 -138
  6. package/dist/cadre-invite-protocol.js +94 -449
  7. package/dist/cadre-invite-protocol.js.map +1 -1
  8. package/dist/cadre-join-request.d.ts +15 -2
  9. package/dist/cadre-join-request.js +22 -3
  10. package/dist/cadre-join-request.js.map +1 -1
  11. package/dist/cadre-node.d.ts +530 -247
  12. package/dist/cadre-node.js +1046 -525
  13. package/dist/cadre-node.js.map +1 -1
  14. package/dist/control-authorization.d.ts +36 -14
  15. package/dist/control-authorization.js +20 -3
  16. package/dist/control-authorization.js.map +1 -1
  17. package/dist/control-cohort.d.ts +22 -23
  18. package/dist/control-cohort.js +24 -24
  19. package/dist/control-cohort.js.map +1 -1
  20. package/dist/control-database.d.ts +416 -136
  21. package/dist/control-database.js +757 -378
  22. package/dist/control-database.js.map +1 -1
  23. package/dist/control-protocol-guard.d.ts +5 -4
  24. package/dist/control-protocol-guard.js +6 -3
  25. package/dist/control-protocol-guard.js.map +1 -1
  26. package/dist/control-schema-version.d.ts +80 -0
  27. package/dist/control-schema-version.js +203 -0
  28. package/dist/control-schema-version.js.map +1 -0
  29. package/dist/control-schema.d.ts +45 -5
  30. package/dist/control-schema.js +254 -70
  31. package/dist/control-schema.js.map +1 -1
  32. package/dist/control-write-retry.d.ts +5 -5
  33. package/dist/control-write-retry.js +10 -8
  34. package/dist/control-write-retry.js.map +1 -1
  35. package/dist/delegate-admission.d.ts +13 -0
  36. package/dist/delegate-admission.js +27 -0
  37. package/dist/delegate-admission.js.map +1 -1
  38. package/dist/ed25519-key.d.ts +10 -7
  39. package/dist/ed25519-key.js +23 -20
  40. package/dist/ed25519-key.js.map +1 -1
  41. package/dist/edge-node/config.d.ts +122 -0
  42. package/dist/edge-node/config.js +199 -0
  43. package/dist/edge-node/config.js.map +1 -0
  44. package/dist/edge-node/dissolve.d.ts +95 -0
  45. package/dist/edge-node/dissolve.js +184 -0
  46. package/dist/edge-node/dissolve.js.map +1 -0
  47. package/dist/edge-node/edge-join.d.ts +44 -0
  48. package/dist/edge-node/edge-join.js +227 -0
  49. package/dist/edge-node/edge-join.js.map +1 -0
  50. package/dist/edge-node/edge-node.d.ts +295 -0
  51. package/dist/edge-node/edge-node.js +704 -0
  52. package/dist/edge-node/edge-node.js.map +1 -0
  53. package/dist/edge-node/index.d.ts +18 -0
  54. package/dist/edge-node/index.js +18 -0
  55. package/dist/edge-node/index.js.map +1 -0
  56. package/dist/edge-node/join-credential.d.ts +11 -0
  57. package/dist/edge-node/join-credential.js +11 -0
  58. package/dist/edge-node/join-credential.js.map +1 -0
  59. package/dist/edge-node/lazy-raw-storage.d.ts +40 -0
  60. package/dist/edge-node/lazy-raw-storage.js +134 -0
  61. package/dist/edge-node/lazy-raw-storage.js.map +1 -0
  62. package/dist/edge-node/node-local.d.ts +60 -0
  63. package/dist/edge-node/node-local.js +58 -0
  64. package/dist/edge-node/node-local.js.map +1 -0
  65. package/dist/edge-node/options.d.ts +83 -0
  66. package/dist/edge-node/options.js +110 -0
  67. package/dist/edge-node/options.js.map +1 -0
  68. package/dist/edge-node/owner-grant.d.ts +41 -0
  69. package/dist/edge-node/owner-grant.js +38 -0
  70. package/dist/edge-node/owner-grant.js.map +1 -0
  71. package/dist/edge-node/platform.d.ts +140 -0
  72. package/dist/edge-node/platform.js +12 -0
  73. package/dist/edge-node/platform.js.map +1 -0
  74. package/dist/edge-node/strand-move.d.ts +115 -0
  75. package/dist/edge-node/strand-move.js +223 -0
  76. package/dist/edge-node/strand-move.js.map +1 -0
  77. package/dist/edge-node/strands.d.ts +28 -0
  78. package/dist/edge-node/strands.js +60 -0
  79. package/dist/edge-node/strands.js.map +1 -0
  80. package/dist/index.d.ts +16 -7
  81. package/dist/index.js +26 -7
  82. package/dist/index.js.map +1 -1
  83. package/dist/joined-strand-store.d.ts +3 -3
  84. package/dist/joined-strand-store.js +3 -3
  85. package/dist/joined-strand-store.js.map +1 -1
  86. package/dist/key-store.d.ts +9 -4
  87. package/dist/key-store.js +9 -4
  88. package/dist/key-store.js.map +1 -1
  89. package/dist/machine-removal.d.ts +19 -39
  90. package/dist/machine-removal.js +24 -98
  91. package/dist/machine-removal.js.map +1 -1
  92. package/dist/member-redemption.d.ts +250 -0
  93. package/dist/member-redemption.js +485 -0
  94. package/dist/member-redemption.js.map +1 -0
  95. package/dist/owner-anchor-sync.d.ts +4 -4
  96. package/dist/owner-anchor-sync.js +16 -15
  97. package/dist/owner-anchor-sync.js.map +1 -1
  98. package/dist/owner-grant-protocol.d.ts +247 -0
  99. package/dist/owner-grant-protocol.js +330 -0
  100. package/dist/owner-grant-protocol.js.map +1 -0
  101. package/dist/owner-key-export.d.ts +70 -0
  102. package/dist/owner-key-export.js +279 -0
  103. package/dist/owner-key-export.js.map +1 -0
  104. package/dist/owner-key-flows.d.ts +55 -0
  105. package/dist/owner-key-flows.js +60 -0
  106. package/dist/owner-key-flows.js.map +1 -0
  107. package/dist/owner-key-store.d.ts +31 -0
  108. package/dist/owner-key-store.js +81 -0
  109. package/dist/owner-key-store.js.map +1 -0
  110. package/dist/owner-keys.d.ts +78 -0
  111. package/dist/owner-keys.js +133 -0
  112. package/dist/owner-keys.js.map +1 -0
  113. package/dist/owner-signer.d.ts +54 -0
  114. package/dist/owner-signer.js +51 -0
  115. package/dist/owner-signer.js.map +1 -0
  116. package/dist/peer-authorization.d.ts +83 -18
  117. package/dist/peer-authorization.js +123 -53
  118. package/dist/peer-authorization.js.map +1 -1
  119. package/dist/provider/rent-node.js +1 -1
  120. package/dist/provider/rent-node.js.map +1 -1
  121. package/dist/seed-bootstrap.d.ts +131 -109
  122. package/dist/seed-bootstrap.js +260 -248
  123. package/dist/seed-bootstrap.js.map +1 -1
  124. package/dist/seed-trust-policy.js +4 -4
  125. package/dist/strand-addr-protocol.d.ts +4 -1
  126. package/dist/strand-addr-protocol.js +8 -2
  127. package/dist/strand-addr-protocol.js.map +1 -1
  128. package/dist/strand-cohort.d.ts +3 -0
  129. package/dist/strand-cohort.js.map +1 -1
  130. package/dist/strand-database.d.ts +1 -0
  131. package/dist/strand-database.js +3 -0
  132. package/dist/strand-database.js.map +1 -1
  133. package/dist/strand-first-sync-gate.d.ts +4 -3
  134. package/dist/strand-first-sync-gate.js +4 -3
  135. package/dist/strand-first-sync-gate.js.map +1 -1
  136. package/dist/strand-instance-manager.d.ts +1 -1
  137. package/dist/strand-membership-writer.d.ts +13 -2
  138. package/dist/strand-membership-writer.js +52 -16
  139. package/dist/strand-membership-writer.js.map +1 -1
  140. package/dist/strand-move.d.ts +6 -5
  141. package/dist/strand-move.js +31 -30
  142. package/dist/strand-move.js.map +1 -1
  143. package/dist/strand-peer-redial.js +2 -3
  144. package/dist/strand-peer-redial.js.map +1 -1
  145. package/dist/types.d.ts +286 -103
  146. package/dist/types.js.map +1 -1
  147. package/package.json +11 -2
  148. package/src/bootstrap-peer-store-file.ts +44 -44
  149. package/src/bootstrap-peer-store.ts +214 -214
  150. package/src/cadre-invite-protocol.ts +652 -1052
  151. package/src/cadre-join-request.ts +24 -3
  152. package/src/cadre-node.ts +1166 -541
  153. package/src/control-authorization.ts +47 -14
  154. package/src/control-cohort.ts +127 -128
  155. package/src/control-database.ts +940 -456
  156. package/src/control-protocol-guard.ts +7 -4
  157. package/src/control-schema-version.ts +251 -0
  158. package/src/control-schema.ts +265 -70
  159. package/src/control-write-retry.ts +569 -567
  160. package/src/delegate-admission.ts +37 -0
  161. package/src/ed25519-key.ts +174 -171
  162. package/src/edge-node/config.ts +277 -0
  163. package/src/edge-node/dissolve.ts +251 -0
  164. package/src/edge-node/edge-join.ts +319 -0
  165. package/src/edge-node/edge-node.ts +1045 -0
  166. package/src/edge-node/index.ts +59 -0
  167. package/src/edge-node/join-credential.ts +16 -0
  168. package/src/edge-node/lazy-raw-storage.ts +178 -0
  169. package/src/edge-node/node-local.ts +84 -0
  170. package/src/edge-node/options.ts +179 -0
  171. package/src/edge-node/owner-grant.ts +63 -0
  172. package/src/edge-node/platform.ts +151 -0
  173. package/src/edge-node/strand-move.ts +270 -0
  174. package/src/edge-node/strands.ts +72 -0
  175. package/src/index.ts +886 -789
  176. package/src/joined-strand-store.ts +4 -4
  177. package/src/key-store.ts +10 -4
  178. package/src/machine-removal.ts +26 -111
  179. package/src/member-redemption.ts +642 -0
  180. package/src/owner-anchor-sync.ts +19 -18
  181. package/src/owner-grant-protocol.ts +532 -0
  182. package/src/owner-key-export.ts +348 -0
  183. package/src/owner-key-flows.ts +109 -0
  184. package/src/owner-key-store.ts +85 -0
  185. package/src/owner-keys.ts +178 -0
  186. package/src/owner-signer.ts +94 -0
  187. package/src/peer-authorization.ts +558 -488
  188. package/src/provider/rent-node.ts +1 -1
  189. package/src/seed-bootstrap.ts +301 -312
  190. package/src/seed-trust-policy.ts +4 -4
  191. package/src/strand-addr-protocol.ts +547 -538
  192. package/src/strand-cohort.ts +4 -0
  193. package/src/strand-database.ts +3 -0
  194. package/src/strand-first-sync-gate.ts +4 -3
  195. package/src/strand-instance-manager.ts +1 -1
  196. package/src/strand-membership-writer.ts +61 -16
  197. package/src/strand-move.ts +45 -36
  198. package/src/strand-peer-redial.ts +2 -3
  199. package/src/types.ts +304 -103
@@ -38,6 +38,7 @@
38
38
  * {@link dueRelayAnnounces} and {@link prunePeerStrandKeys} are that
39
39
  * decision, pure and testable, kept here beside the TTL they are derived from.
40
40
  */
41
+ import type { StrandAddrOutcome } from './strand-addr-protocol.js';
41
42
  /**
42
43
  * How long one announced delegate grant stays valid without a re-announce.
43
44
  * Announcers refresh at half this (`CadreNode`'s reconcile pass), so a live
@@ -121,6 +122,18 @@ export declare function extractCircuitRelayTargets(addrs: string[]): CircuitRela
121
122
  * {@link peerStrandKey} on the peer announced TO.
122
123
  */
123
124
  export declare function dueRelayAnnounces(announceAt: ReadonlyMap<string, number>, relays: readonly CircuitRelayTarget[], strandId: string, now: number, ttlMs?: number): CircuitRelayTarget[];
125
+ /**
126
+ * Fold one announce pass's outcomes into `refusing`, the relay peerIds remembered
127
+ * as refusing the strand-addr protocol. A relay whose negotiation refused it
128
+ * (`unsupported`) is added; one that replied with any status is removed, because
129
+ * it serves the protocol now. A relay that did not reply (`unreachable`) is left
130
+ * as it was: being down says nothing about what it serves. Only `relayPeerIds`
131
+ * are read, so a sibling asked in the same pass is never recorded. Mutates in
132
+ * place.
133
+ */
134
+ export declare function recordRelayRefusals(refusing: Set<string>, relayPeerIds: readonly string[], outcomes: ReadonlyMap<string, StrandAddrOutcome>): void;
135
+ /** Of `relays`, the ones not remembered in `refusing` (see {@link recordRelayRefusals}). */
136
+ export declare function relaysNotRefusing(relays: readonly CircuitRelayTarget[], refusing: ReadonlySet<string>): CircuitRelayTarget[];
124
137
  /**
125
138
  * Drop the entries of a {@link peerStrandKey}-keyed map whose strand is no longer
126
139
  * running, and — when `livePeerIds` is given — whose peer is not among them. A
@@ -183,6 +183,33 @@ export function extractCircuitRelayTargets(addrs) {
183
183
  export function dueRelayAnnounces(announceAt, relays, strandId, now, ttlMs = DELEGATE_GRANT_TTL_MS) {
184
184
  return relays.filter((relay) => now - (announceAt.get(peerStrandKey(relay.relayPeerId, strandId)) ?? 0) >= ttlMs / 2);
185
185
  }
186
+ /**
187
+ * Fold one announce pass's outcomes into `refusing`, the relay peerIds remembered
188
+ * as refusing the strand-addr protocol. A relay whose negotiation refused it
189
+ * (`unsupported`) is added; one that replied with any status is removed, because
190
+ * it serves the protocol now. A relay that did not reply (`unreachable`) is left
191
+ * as it was: being down says nothing about what it serves. Only `relayPeerIds`
192
+ * are read, so a sibling asked in the same pass is never recorded. Mutates in
193
+ * place.
194
+ */
195
+ export function recordRelayRefusals(refusing, relayPeerIds, outcomes) {
196
+ for (const relayPeerId of relayPeerIds) {
197
+ switch (outcomes.get(relayPeerId)) {
198
+ case 'unsupported':
199
+ refusing.add(relayPeerId);
200
+ break;
201
+ case 'answered':
202
+ case 'empty':
203
+ case 'unavailable':
204
+ refusing.delete(relayPeerId);
205
+ break;
206
+ }
207
+ }
208
+ }
209
+ /** Of `relays`, the ones not remembered in `refusing` (see {@link recordRelayRefusals}). */
210
+ export function relaysNotRefusing(relays, refusing) {
211
+ return relays.filter((relay) => !refusing.has(relay.relayPeerId));
212
+ }
186
213
  /**
187
214
  * Drop the entries of a {@link peerStrandKey}-keyed map whose strand is no longer
188
215
  * running, and — when `livePeerIds` is given — whose peer is not among them. A
@@ -1 +1 @@
1
- {"version":3,"file":"delegate-admission.js","sourceRoot":"","sources":["../src/delegate-admission.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"delegate-admission.js","sourceRoot":"","sources":["../src/delegate-admission.ts"],"names":[],"mappings":"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"}
@@ -40,6 +40,16 @@ export declare function ed25519KeyPairFromLibp2p(privateKey: PrivateKey): Ed2551
40
40
  * @returns The base64url-encoded Ed25519 public key.
41
41
  */
42
42
  export declare function ed25519PublicKeyFromPrivate(privateKeyB64: string): string;
43
+ /**
44
+ * Reject a value that isn't a base64url-encoded 32-byte Ed25519 seed, the private-key form
45
+ * {@link ed25519PublicKeyFromPrivate} and the crypto plugin's `sign` take. Unlike
46
+ * {@link requireEd25519PublicKeyB64}, no message names the value: it is a private key.
47
+ *
48
+ * @param value - Candidate base64url-encoded Ed25519 seed; surrounding whitespace is ignored.
49
+ * @param label - Human-readable name of the field, used in error messages.
50
+ * @returns The seed re-encoded as canonical base64url, so two spellings of one key compare equal.
51
+ */
52
+ export declare function requireEd25519PrivateKeyB64(value: string, label: string): string;
43
53
  /**
44
54
  * Derive the base64url ed25519 public key embedded in an Ed25519 libp2p PeerId.
45
55
  *
@@ -55,13 +65,6 @@ export declare function ed25519PublicKeyFromPrivate(privateKeyB64: string): stri
55
65
  * without importing the seed-bootstrap runtime.
56
66
  */
57
67
  export declare function ed25519PublicKeyB64FromPeerId(peerId: string): string | null;
58
- /**
59
- * The inverse of {@link ed25519PublicKeyB64FromPeerId}: the libp2p peer id whose identity
60
- * is this ed25519 public key (base64url), or null when the value does not decode to a
61
- * 32-byte key. How an `OwnerKey` row is matched to the machine it names
62
- * (`machine-removal.ts`), since a machine's owner key is the key behind its peer id.
63
- */
64
- export declare function peerIdFromEd25519PublicKeyB64(publicKeyB64: string): string | null;
65
68
  /**
66
69
  * Reject a value that isn't shaped like a base64url-encoded 32-byte Ed25519 public key
67
70
  * before it reaches the control database, where a malformed key would otherwise sit
@@ -1,7 +1,6 @@
1
1
  import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays';
2
2
  import { getPublicKey } from '@optimystic/quereus-plugin-crypto';
3
- import { peerIdFromPublicKey, peerIdFromString } from '@libp2p/peer-id';
4
- import { publicKeyFromRaw } from '@libp2p/crypto/keys';
3
+ import { peerIdFromString } from '@libp2p/peer-id';
5
4
  /**
6
5
  * Bridge a libp2p Ed25519 private key into the base64url keypair used by the
7
6
  * control- and strand-database signing constraints.
@@ -50,6 +49,28 @@ export function ed25519KeyPairFromLibp2p(privateKey) {
50
49
  export function ed25519PublicKeyFromPrivate(privateKeyB64) {
51
50
  return getPublicKey(privateKeyB64, 'ed25519', 'base64url', 'base64url');
52
51
  }
52
+ /**
53
+ * Reject a value that isn't a base64url-encoded 32-byte Ed25519 seed, the private-key form
54
+ * {@link ed25519PublicKeyFromPrivate} and the crypto plugin's `sign` take. Unlike
55
+ * {@link requireEd25519PublicKeyB64}, no message names the value: it is a private key.
56
+ *
57
+ * @param value - Candidate base64url-encoded Ed25519 seed; surrounding whitespace is ignored.
58
+ * @param label - Human-readable name of the field, used in error messages.
59
+ * @returns The seed re-encoded as canonical base64url, so two spellings of one key compare equal.
60
+ */
61
+ export function requireEd25519PrivateKeyB64(value, label) {
62
+ let decoded;
63
+ try {
64
+ decoded = uint8ArrayFromString(value.trim(), 'base64url');
65
+ }
66
+ catch (error) {
67
+ throw new Error(`The ${label} must be a base64url-encoded Ed25519 private key (it does not decode as base64url)`, { cause: error });
68
+ }
69
+ if (decoded.length !== 32) {
70
+ throw new Error(`The ${label} must be a base64url-encoded 32-byte Ed25519 private key (it decoded to ${decoded.length} bytes)`);
71
+ }
72
+ return uint8ArrayToString(decoded, 'base64url');
73
+ }
53
74
  /**
54
75
  * Derive the base64url ed25519 public key embedded in an Ed25519 libp2p PeerId.
55
76
  *
@@ -76,24 +97,6 @@ export function ed25519PublicKeyB64FromPeerId(peerId) {
76
97
  return null;
77
98
  }
78
99
  }
79
- /**
80
- * The inverse of {@link ed25519PublicKeyB64FromPeerId}: the libp2p peer id whose identity
81
- * is this ed25519 public key (base64url), or null when the value does not decode to a
82
- * 32-byte key. How an `OwnerKey` row is matched to the machine it names
83
- * (`machine-removal.ts`), since a machine's owner key is the key behind its peer id.
84
- */
85
- export function peerIdFromEd25519PublicKeyB64(publicKeyB64) {
86
- try {
87
- const raw = uint8ArrayFromString(publicKeyB64, 'base64url');
88
- if (raw.length !== 32) {
89
- return null;
90
- }
91
- return peerIdFromPublicKey(publicKeyFromRaw(raw)).toString();
92
- }
93
- catch {
94
- return null;
95
- }
96
- }
97
100
  /** Longest rejected key value echoed back in an error — a real key is 43 base64url chars. */
98
101
  const REJECTED_VALUE_ECHO_LIMIT = 64;
99
102
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ed25519-key.js","sourceRoot":"","sources":["../src/ed25519-key.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ed25519-key.js","sourceRoot":"","sources":["../src/ed25519-key.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * The edge node's `CadreNodeConfig` and how a start settles its owner key. Nothing here needs a
3
+ * node started, so a test can build the node shape an edge device runs.
4
+ */
5
+ import { type KeyStore } from '../key-store.js';
6
+ import type { CadreNode } from '../cadre-node.js';
7
+ import type { CadreNodeConfig } from '../types.js';
8
+ import type { BootstrapPeerStore } from '../bootstrap-peer-store.js';
9
+ import type { EnrolledMachineStore } from '../enrolled-machine-store.js';
10
+ import type { StrandNetworkStateStore } from '../strand-network-state.js';
11
+ import type { TrustedOwnerStore } from '../trusted-owner-store.js';
12
+ import type { IRawStorage, Libp2pTransports, NoiseCryptoInterface } from '@optimystic/db-p2p';
13
+ import type { EdgeNodeOptions } from './options.js';
14
+ /** What {@link buildEdgeNodeConfig} takes: one start's options plus what the platform built. */
15
+ export interface EdgeNodeConfigInputs extends EdgeNodeOptions {
16
+ /** `undefined` keeps libp2p-noise's own crypto. */
17
+ noiseCrypto?: NoiseCryptoInterface;
18
+ /**
19
+ * Holds the node identity, which the node loads on start, generating it on first run, and the
20
+ * owner key in its own slot (`DEFAULT_OWNER_KEY_ID`), which only {@link runOwnerGenesis} creates.
21
+ */
22
+ keyStore: KeyStore;
23
+ /**
24
+ * Raw block storage per cadre-core storage scope: `controlStorageScope(partyId)` for the
25
+ * control network, the strand id for each strand. The key is already safe as a database-name
26
+ * segment — use it verbatim, do not parse it.
27
+ */
28
+ storageProvider: (scope: string) => IRawStorage;
29
+ /** libp2p transport factories: what the node dials with, and what listens on `listenAddrs`. */
30
+ transports: Libp2pTransports;
31
+ /**
32
+ * Listen addresses besides the bare `/p2p-circuit` entry cadre-core adds for a named relay.
33
+ * Default `[]`: an edge device accepts no inbound connection. See `EdgeNodePlatform.listenAddrs`.
34
+ */
35
+ listenAddrs?: string[];
36
+ /** See `EdgeNodePlatform.allowPrivateDial`. */
37
+ allowPrivateDial: boolean;
38
+ trustedOwnerStore: TrustedOwnerStore;
39
+ bootstrapPeerStore: BootstrapPeerStore;
40
+ enrolledMachineStore: EnrolledMachineStore;
41
+ strandNetworkStateStore: StrandNetworkStateStore;
42
+ }
43
+ /**
44
+ * The edge node's config: transaction profile (Ring Zulu only, intermittent connectivity), no
45
+ * listen address unless the platform names one, reachability through the configured relays (if
46
+ * any) but never a hard requirement for one, every strand the control network lists, and no
47
+ * automatic hibernation (the app's lifecycle runner hibernates on background). Schema signing is
48
+ * left at cadre-core's fail-closed default; an app with unsigned schemas relaxes it in
49
+ * `EdgeNodePlatform.configure`.
50
+ */
51
+ export declare function buildEdgeNodeConfig(inputs: EdgeNodeConfigInputs): CadreNodeConfig;
52
+ /**
53
+ * How the start settled this node's owner key: `EdgeNodeStatus.owner`. `'enrolled'`: a key is
54
+ * an owner and wired for signing. `'member'`: the party lists no key this app holds (a party it
55
+ * joined, or one it founded whose owner slot was lost). `'failed'` and `'timed-out'`: see
56
+ * {@link runOwnerGenesis}.
57
+ */
58
+ export type OwnerGenesisResult = 'enrolled' | 'member' | 'failed' | 'timed-out';
59
+ /**
60
+ * Default bound on {@link runOwnerGenesis} and {@link wireJoinedOwnerKey}: what a start can wait
61
+ * for its owner step, which runs control reads and one control write, before it goes on without
62
+ * it. Not derived from the link, since a start that waited out a stalled write (about 84 s, see
63
+ * `docs/cadre-consistency.md`) would be a start the user gave up on.
64
+ */
65
+ export declare const DEFAULT_OWNER_GENESIS_TIMEOUT_MS = 60000;
66
+ /** Default `EdgeNodeOptions.ownerKeyLabel`: the founding owner key's name on its `OwnerKey` row. */
67
+ export declare const DEFAULT_OWNER_KEY_LABEL = "phone";
68
+ /**
69
+ * Refuses an `ownerKeyLabel` the founding `OwnerKey` row would refuse, so a start naming one
70
+ * fails outright: fail-soft genesis would only log it, on that start and every later one.
71
+ */
72
+ export declare function requireOwnerKeyLabel(label: string | undefined): void;
73
+ /** What {@link runOwnerGenesis} takes. */
74
+ export interface OwnerGenesisOptions {
75
+ /** The key store whose owner slot holds this app's owner key: the one the identity is in. */
76
+ keyStore: KeyStore;
77
+ /** The founding row's label; default {@link DEFAULT_OWNER_KEY_LABEL}. */
78
+ label?: string;
79
+ /** Default {@link DEFAULT_OWNER_GENESIS_TIMEOUT_MS}. */
80
+ timeoutMs?: number;
81
+ }
82
+ /** What {@link wireJoinedOwnerKey} takes. */
83
+ export interface JoinedOwnerKeyOptions {
84
+ /** The key store whose owner slot holds this app's owner key, if it holds one. */
85
+ keyStore: KeyStore;
86
+ /** Default {@link DEFAULT_OWNER_GENESIS_TIMEOUT_MS}. */
87
+ timeoutMs?: number;
88
+ /** An owner grant has just seated the slot's key: keep asking until the row arrives. */
89
+ granted?: boolean;
90
+ }
91
+ /**
92
+ * The owner step of a party this app founded. On a party with no `OwnerKey` row yet, the owner
93
+ * slot's key (created there now unless the slot already holds one) becomes the founding owner
94
+ * under `label` and is wired for signing, which also lets the node author its own `CadrePeer` row.
95
+ * On a party that has owners, the slot's key is wired only when it is a live owner, and no key is
96
+ * created: a new one could not be seated without another owner's signature. A node must be an
97
+ * enrolled owner to publish strands, and `CadreNode.requestJoin` works only on one. A joined
98
+ * party's start runs {@link wireJoinedOwnerKey} instead.
99
+ *
100
+ * Fail-soft and bounded: a failure or a genesis that has not settled within `timeoutMs` is logged
101
+ * and returned, and the start stands — the app can still join discovered strands and sync. A
102
+ * genesis that times out keeps running; its later failure is logged.
103
+ *
104
+ * NOTE: the bound is here, in cadre-core, so every edge node gets it; a Node host runs genesis
105
+ * through the CLI's own flow instead. Since v1.10 a control write against an unresponsive member
106
+ * can hold the write lock for about 84 s, so an unbounded wait here would be a real stall. A bound
107
+ * on that write itself, in `ControlDatabase`, would make this one redundant; drop `timeoutMs` then.
108
+ */
109
+ export declare function runOwnerGenesis(node: CadreNode, options: OwnerGenesisOptions): Promise<OwnerGenesisResult>;
110
+ /**
111
+ * The owner step of a party this app joined: wire a key only when the party lists it as a live
112
+ * owner, never insert an `OwnerKey` row, so a joined app can neither seat itself as a founder nor
113
+ * anchor a key that is no owner's. Only the owner slot's key is tried: the key an owner grant
114
+ * seated, one imported here, or one an owner of the party added. The identity key is never
115
+ * tried, since a machine's network identity is never an owner key. Fail-soft and bounded as
116
+ * {@link runOwnerGenesis} is.
117
+ *
118
+ * `granted`: an owner grant has just made this app an owner, so a key not listed yet means the
119
+ * row has not reached this node, not that it is no owner. It is asked again every 2 s until it
120
+ * is wired or the bound passes; a start that timed out wires it on the next start.
121
+ */
122
+ export declare function wireJoinedOwnerKey(node: CadreNode, options: JoinedOwnerKeyOptions): Promise<OwnerGenesisResult>;
@@ -0,0 +1,199 @@
1
+ /**
2
+ * The edge node's `CadreNodeConfig` and how a start settles its owner key. Nothing here needs a
3
+ * node started, so a test can build the node shape an edge device runs.
4
+ */
5
+ import { DEFAULT_IDENTITY_KEY_ID } from '../key-store.js';
6
+ import { createOwnerKey, loadOwnerSigner } from '../owner-key-store.js';
7
+ import { OWNER_KEY_MAX_LABEL } from '../owner-key-export.js';
8
+ /**
9
+ * The edge node's config: transaction profile (Ring Zulu only, intermittent connectivity), no
10
+ * listen address unless the platform names one, reachability through the configured relays (if
11
+ * any) but never a hard requirement for one, every strand the control network lists, and no
12
+ * automatic hibernation (the app's lifecycle runner hibernates on background). Schema signing is
13
+ * left at cadre-core's fail-closed default; an app with unsigned schemas relaxes it in
14
+ * `EdgeNodePlatform.configure`.
15
+ */
16
+ export function buildEdgeNodeConfig(inputs) {
17
+ return {
18
+ // Identity comes from the key store (loaded when present, generated and persisted on first
19
+ // run). Mutually exclusive with `privateKey`, which would take it out of the key store.
20
+ keyStore: inputs.keyStore,
21
+ identityKeyId: DEFAULT_IDENTITY_KEY_ID,
22
+ controlNetwork: {
23
+ partyId: inputs.partyId,
24
+ bootstrapNodes: inputs.bootstrapAddrs,
25
+ },
26
+ profile: 'transaction',
27
+ storage: {
28
+ provider: inputs.storageProvider,
29
+ },
30
+ network: {
31
+ transports: inputs.transports,
32
+ // An edge device accepts no inbound connection, so by default it listens on nothing:
33
+ // the only address it ever has is the `/p2p-circuit` address a relay reservation earns
34
+ // it. An explicitly empty `listenAddrs` stays empty through cadre-core's derivation, and
35
+ // naming a relay adds the bare `/p2p-circuit` search entry to it
36
+ // (`cadre-core/src/relay-addrs.ts` → `resolveListenAddrs`). A browser adds `/webrtc`.
37
+ listenAddrs: inputs.listenAddrs ?? [],
38
+ // Through this config field rather than `CadreNode.reserveRelays()`, which reaches the
39
+ // control node only: formation has the invitee dial the control node and then the strand
40
+ // nodes, so both need a circuit address.
41
+ //
42
+ // NOTE: naming a relay starts a reservation supervisor that runs for as long as the
43
+ // control node does, including while backgrounded (hibernation stops strands, not the
44
+ // control node): a 5 s local check while the reservation holds, a dial every backoff
45
+ // interval (2 s → 60 s) while it does not. If background battery use becomes a complaint,
46
+ // raise `checkMs`/`maxBackoffMs` in cadre-core rather than stopping the supervisor here,
47
+ // which would leave a device that silently stopped being invitable.
48
+ relayAddrs: inputs.relayAddrs,
49
+ // An edge device must come up with its relay down — on a plane, on dead Wi-Fi, or with
50
+ // none configured. A first reservation attempt that lands nothing is logged and retried in
51
+ // the background instead of failing `start()`. A malformed entry still throws.
52
+ requireRelay: false,
53
+ // The platform's Noise primitives (native SHA-256 / ChaCha20-Poly1305, and X25519 in
54
+ // `full` mode, on a phone); only local primitives change, not the wire protocol.
55
+ noiseCrypto: inputs.noiseCrypto,
56
+ // libp2p's `connection-gater` points its `react-native` and `browser` fields at a build
57
+ // that refuses to dial plain `ws://`, loopback and private addresses. A cadre-host node
58
+ // claimed by its code on the same Wi-Fi, an emulator reaching `10.0.2.2` and a self-run
59
+ // relay without TLS are all of those. Only the dial is permitted: the connection is still
60
+ // Noise, the pinned `/p2p/<id>` decides which machine answers, and membership is still
61
+ // gated by `denyDialPeer` and the inbound hooks. cadre-core hands this gater to strand nodes too.
62
+ ...(inputs.allowPrivateDial ? { connectionGater: { denyDialMultiaddr: () => false } } : {}),
63
+ },
64
+ strandFilter: { mode: 'all' },
65
+ hibernation: { enabled: false },
66
+ trustedOwners: { store: inputs.trustedOwnerStore },
67
+ bootstrapPeers: { store: inputs.bootstrapPeerStore },
68
+ enrolledMachines: { store: inputs.enrolledMachineStore },
69
+ strandNetworkState: { store: inputs.strandNetworkStateStore },
70
+ };
71
+ }
72
+ /**
73
+ * Default bound on {@link runOwnerGenesis} and {@link wireJoinedOwnerKey}: what a start can wait
74
+ * for its owner step, which runs control reads and one control write, before it goes on without
75
+ * it. Not derived from the link, since a start that waited out a stalled write (about 84 s, see
76
+ * `docs/cadre-consistency.md`) would be a start the user gave up on.
77
+ */
78
+ // eslint-disable-next-line no-restricted-syntax -- cuts off by design: a start goes on without its owner step rather than wait out a stalled control write; see docs/cadre-consistency.md → "Deadlines Over Optimystic's Reads and Commits"
79
+ export const DEFAULT_OWNER_GENESIS_TIMEOUT_MS = 60000;
80
+ /** Default `EdgeNodeOptions.ownerKeyLabel`: the founding owner key's name on its `OwnerKey` row. */
81
+ export const DEFAULT_OWNER_KEY_LABEL = 'phone';
82
+ /**
83
+ * Refuses an `ownerKeyLabel` the founding `OwnerKey` row would refuse, so a start naming one
84
+ * fails outright: fail-soft genesis would only log it, on that start and every later one.
85
+ */
86
+ export function requireOwnerKeyLabel(label) {
87
+ const length = label?.trim().length ?? 0;
88
+ if (length > OWNER_KEY_MAX_LABEL) {
89
+ throw new Error(`ownerKeyLabel must be at most ${OWNER_KEY_MAX_LABEL} characters (this one has ${length})`);
90
+ }
91
+ }
92
+ /** How often {@link wireJoinedOwnerKey} asks again for an owner key an owner grant just seated. */
93
+ const GRANTED_OWNER_RECHECK_MS = 2000;
94
+ /**
95
+ * The owner step of a party this app founded. On a party with no `OwnerKey` row yet, the owner
96
+ * slot's key (created there now unless the slot already holds one) becomes the founding owner
97
+ * under `label` and is wired for signing, which also lets the node author its own `CadrePeer` row.
98
+ * On a party that has owners, the slot's key is wired only when it is a live owner, and no key is
99
+ * created: a new one could not be seated without another owner's signature. A node must be an
100
+ * enrolled owner to publish strands, and `CadreNode.requestJoin` works only on one. A joined
101
+ * party's start runs {@link wireJoinedOwnerKey} instead.
102
+ *
103
+ * Fail-soft and bounded: a failure or a genesis that has not settled within `timeoutMs` is logged
104
+ * and returned, and the start stands — the app can still join discovered strands and sync. A
105
+ * genesis that times out keeps running; its later failure is logged.
106
+ *
107
+ * NOTE: the bound is here, in cadre-core, so every edge node gets it; a Node host runs genesis
108
+ * through the CLI's own flow instead. Since v1.10 a control write against an unresponsive member
109
+ * can hold the write lock for about 84 s, so an unbounded wait here would be a real stall. A bound
110
+ * on that write itself, in `ControlDatabase`, would make this one redundant; drop `timeoutMs` then.
111
+ */
112
+ export function runOwnerGenesis(node, options) {
113
+ const label = options.label ?? DEFAULT_OWNER_KEY_LABEL;
114
+ return withinBound('owner self-genesis', enrollFoundedOwner(node, options.keyStore, label), options.timeoutMs ?? DEFAULT_OWNER_GENESIS_TIMEOUT_MS);
115
+ }
116
+ /**
117
+ * The owner step of a party this app joined: wire a key only when the party lists it as a live
118
+ * owner, never insert an `OwnerKey` row, so a joined app can neither seat itself as a founder nor
119
+ * anchor a key that is no owner's. Only the owner slot's key is tried: the key an owner grant
120
+ * seated, one imported here, or one an owner of the party added. The identity key is never
121
+ * tried, since a machine's network identity is never an owner key. Fail-soft and bounded as
122
+ * {@link runOwnerGenesis} is.
123
+ *
124
+ * `granted`: an owner grant has just made this app an owner, so a key not listed yet means the
125
+ * row has not reached this node, not that it is no owner. It is asked again every 2 s until it
126
+ * is wired or the bound passes; a start that timed out wires it on the next start.
127
+ */
128
+ export function wireJoinedOwnerKey(node, options) {
129
+ let expired = false;
130
+ const wiring = async () => {
131
+ const held = await loadOwnerSigner(options.keyStore);
132
+ while (!(await wireJoinedOwner(node, held))) {
133
+ if (!options.granted)
134
+ return 'member';
135
+ await new Promise((resolve) => setTimeout(resolve, GRANTED_OWNER_RECHECK_MS));
136
+ // Past the bound the start has gone on as `'timed-out'`, and may have stopped the node.
137
+ if (expired)
138
+ return 'member';
139
+ }
140
+ return 'enrolled';
141
+ };
142
+ return withinBound('wiring the joined owner key', wiring(), options.timeoutMs ?? DEFAULT_OWNER_GENESIS_TIMEOUT_MS)
143
+ .finally(() => {
144
+ expired = true;
145
+ });
146
+ }
147
+ /** `settling`, or `'failed'` when it rejects (logged), or `'timed-out'` when it has not settled within `timeoutMs` (logged). */
148
+ async function withinBound(label, settling, timeoutMs) {
149
+ const settled = settling.catch((err) => {
150
+ console.warn(`[cadre-core/edge-node] ${label} failed:`, err);
151
+ return 'failed';
152
+ });
153
+ let timer;
154
+ const deadline = new Promise((resolve) => {
155
+ timer = setTimeout(() => resolve('timed-out'), timeoutMs);
156
+ });
157
+ try {
158
+ const result = await Promise.race([settled, deadline]);
159
+ if (result === 'timed-out') {
160
+ console.warn(`[cadre-core/edge-node] ${label} has not settled after ${timeoutMs} ms; starting without it`);
161
+ }
162
+ return result;
163
+ }
164
+ finally {
165
+ clearTimeout(timer);
166
+ }
167
+ }
168
+ async function enrollFoundedOwner(node, keyStore, label) {
169
+ const controlDb = node.getControlDatabase();
170
+ if (!controlDb) {
171
+ throw new Error('control database unavailable after start; cannot run owner genesis');
172
+ }
173
+ const held = await loadOwnerSigner(keyStore);
174
+ if (await controlDb.hasOwnerKey()) {
175
+ return held ? wiredIfOwner(node, held) : 'member';
176
+ }
177
+ // Loaded rather than created when the slot already holds a key: one imported before founding,
178
+ // or one an iOS reinstall kept in the Keychain while the app's data went.
179
+ const founding = held ?? (await createOwnerKey(keyStore));
180
+ if (!(await controlDb.ensureOwnerKey(founding.publicKey, label))) {
181
+ // A row arrived between the two reads: the party has an owner now, so judge the key as above.
182
+ return wiredIfOwner(node, founding);
183
+ }
184
+ await node.useOwnerSigner(founding);
185
+ return 'enrolled';
186
+ }
187
+ async function wiredIfOwner(node, signer) {
188
+ return (await node.wireOwnKeyIfOwner(signer)) ? 'enrolled' : 'member';
189
+ }
190
+ /**
191
+ * Wire `held`, the owner slot's key, when the party lists it. A node takes one owner signer, so
192
+ * a signer already wired is asked about instead (is it still a live owner?) and never replaced.
193
+ */
194
+ async function wireJoinedOwner(node, held) {
195
+ if (node.getOwnerSigner() !== null)
196
+ return await node.wireOwnKeyIfOwner();
197
+ return held !== undefined && (await node.wireOwnKeyIfOwner(held));
198
+ }
199
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/edge-node/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Dissolving the party this app founded and left (docs/architecture.md → "An app joins an
3
+ * existing cadre" → "Dissolving the party it left"): the check that the running party holds
4
+ * everything the left one holds, and the removal of the left party's local storage. The same
5
+ * removal deletes a party whose owner removed this app ("Removed from A"), with no check.
6
+ *
7
+ * The removal is local: it writes nothing to either party's control database. A marker in the
8
+ * node-local database names the party from before the first deletion until after the saved
9
+ * start stops naming it, so a removal that a crash or a failed step interrupts is finished by
10
+ * the next start or the next dissolve without checking again: the decision to remove was made
11
+ * before the marker was written. Every step deletes what may already be gone.
12
+ */
13
+ import type { StrandBundle, StrandHoldings } from '../strand-move.js';
14
+ import type { CadreNode } from '../cadre-node.js';
15
+ import type { KeyStore } from '../key-store.js';
16
+ import { type NodeLocalKv } from './node-local.js';
17
+ import type { RemovableSlot } from './platform.js';
18
+ import { type EdgeNodeOptions } from './options.js';
19
+ import { type PendingStrandMove, type StrandMoveRecords } from './strand-move.js';
20
+ /** How `EdgeNode.dissolveFormerParty` runs. */
21
+ export interface DissolveFormerPartyOptions {
22
+ /** Strand and pending-join ids of the former party to give up although the running party does not hold them; from a `FormerPartyNotEmptyError`. */
23
+ discard?: readonly string[];
24
+ }
25
+ /**
26
+ * `EdgeNode.dissolveFormerParty` refused, nothing stopped: moving the former party's strands has
27
+ * not finished. A move into the running party finishes with `finishStrandMove()`; one into
28
+ * another party is adopted only there.
29
+ */
30
+ export declare class StrandMovePendingError extends Error {
31
+ readonly pending: PendingStrandMove;
32
+ constructor(pending: PendingStrandMove);
33
+ }
34
+ /** What keeps a former party from being dissolved: `FormerPartyNotEmptyError`'s lists. */
35
+ interface FormerPartyRemains {
36
+ otherMachines: string[];
37
+ strandIds: string[];
38
+ pendingJoinIds: string[];
39
+ }
40
+ /** `EdgeNode.dissolveFormerParty` refused, nothing deleted: the former party holds what the running party lacks, or has other machines. */
41
+ export declare class FormerPartyNotEmptyError extends Error {
42
+ readonly partyId: string;
43
+ /** Peer ids of `CadrePeer` rows other than this node's. Not discardable: removing them is the user's choice, made in that party. */
44
+ readonly otherMachines: string[];
45
+ /** Not held by the running party and not in `discard`. */
46
+ readonly strandIds: string[];
47
+ /** Open pending joins the running party does not hold, and not in `discard`. */
48
+ readonly pendingJoinIds: string[];
49
+ constructor(partyId: string, remains: FormerPartyRemains);
50
+ }
51
+ /** What the former party holds, read from a node started for it alone. */
52
+ export interface FormerPartyContent {
53
+ bundle: StrandBundle;
54
+ /** Peer ids of its `CadrePeer` rows other than the reading node's. */
55
+ otherMachines: string[];
56
+ }
57
+ export declare function readFormerParty(node: CadreNode): Promise<FormerPartyContent>;
58
+ /** The refusal `content` earns against what the running party holds, or null when it may be dissolved. */
59
+ export declare function formerPartyRefusal(content: FormerPartyContent, holdings: StrandHoldings, discard: readonly string[], nowMs: number): FormerPartyNotEmptyError | null;
60
+ /** The former party's start for {@link readFormerParty}: nothing to dial or reserve on, the running Noise mode. */
61
+ export declare function formerPartyRead(partyId: string, running: EdgeNodeOptions): EdgeNodeOptions;
62
+ /** `options` without `formerPartyId` when it names `partyId`. */
63
+ export declare function withoutFormerParty(options: EdgeNodeOptions, partyId: string | undefined): EdgeNodeOptions;
64
+ /** The edge node's storage a removal reaches. No handle on the party removed may be open. */
65
+ export interface PartyStorage {
66
+ /** The node-local key-value store (`EdgeNodeStorage.nodeLocal`). */
67
+ nodeLocal: NodeLocalKv;
68
+ /** `EdgeNodeNames.dissolveMarkerKey`. */
69
+ markerKey: string;
70
+ /** `EdgeNodeNames.savedStartKey`. */
71
+ savedStartKey: string;
72
+ /** `EdgeNodeStorage.destroyScope`. */
73
+ destroyScope: (scope: string) => Promise<void>;
74
+ /** The party's trusted-owner anchor slot, the platform's own or the node-local default, for its removal. */
75
+ trustedOwnerSlot: (partyId: string) => RemovableSlot;
76
+ keyStore: KeyStore;
77
+ moves: StrandMoveRecords;
78
+ }
79
+ /** Mark `partyId` as being removed, then remove its local storage. Only once removing it is decided: a dissolve's check passed, or an owner removed this app. */
80
+ export declare function removeParty(storage: PartyStorage, partyId: string): Promise<void>;
81
+ /** Finish the removal a marker names, if any. */
82
+ export declare function finishMarkedRemoval(storage: PartyStorage): Promise<void>;
83
+ /** What {@link finishRemovalAtStart} found: the party the marker named, if any, and why finishing its removal failed, if it did. */
84
+ export interface RemovalAtStart {
85
+ /** Absent when there was no marker, or when it could not be read (`error` says so). */
86
+ partyId?: string;
87
+ error?: Error;
88
+ }
89
+ /**
90
+ * {@link finishMarkedRemoval} before a start, which must then not keep the party it names as
91
+ * `formerPartyId`, finished or not. A failure is logged and reported, and the start goes on; the
92
+ * marker stays for the next.
93
+ */
94
+ export declare function finishRemovalAtStart(storage: PartyStorage): Promise<RemovalAtStart>;
95
+ export {};