@serfab/cadre-core 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +255 -253
  2. package/dist/bootstrap-peer-store-file.d.ts +13 -0
  3. package/dist/bootstrap-peer-store-file.js +42 -0
  4. package/dist/bootstrap-peer-store-file.js.map +1 -0
  5. package/dist/bootstrap-peer-store.d.ts +73 -0
  6. package/dist/bootstrap-peer-store.js +128 -0
  7. package/dist/bootstrap-peer-store.js.map +1 -0
  8. package/dist/cadre-node.d.ts +1121 -81
  9. package/dist/cadre-node.js +2276 -262
  10. package/dist/cadre-node.js.map +1 -1
  11. package/dist/control-authorization.d.ts +93 -0
  12. package/dist/control-authorization.js +57 -0
  13. package/dist/control-authorization.js.map +1 -0
  14. package/dist/control-cohort.d.ts +26 -0
  15. package/dist/control-cohort.js +26 -0
  16. package/dist/control-cohort.js.map +1 -1
  17. package/dist/control-database.d.ts +959 -54
  18. package/dist/control-database.js +1421 -148
  19. package/dist/control-database.js.map +1 -1
  20. package/dist/control-formation-recorder.d.ts +90 -10
  21. package/dist/control-formation-recorder.js +130 -14
  22. package/dist/control-formation-recorder.js.map +1 -1
  23. package/dist/control-schema.d.ts +1 -1
  24. package/dist/control-schema.js +651 -72
  25. package/dist/control-schema.js.map +1 -1
  26. package/dist/control-stream.d.ts +38 -4
  27. package/dist/control-stream.js +70 -4
  28. package/dist/control-stream.js.map +1 -1
  29. package/dist/control-write-retry.d.ts +161 -0
  30. package/dist/control-write-retry.js +412 -0
  31. package/dist/control-write-retry.js.map +1 -0
  32. package/dist/delegate-admission.d.ts +134 -0
  33. package/dist/delegate-admission.js +244 -0
  34. package/dist/delegate-admission.js.map +1 -0
  35. package/dist/device-token.d.ts +11 -11
  36. package/dist/device-token.js +14 -13
  37. package/dist/device-token.js.map +1 -1
  38. package/dist/ed25519-key.d.ts +26 -0
  39. package/dist/ed25519-key.js +56 -1
  40. package/dist/ed25519-key.js.map +1 -1
  41. package/dist/file-durable-slot.d.ts +20 -0
  42. package/dist/file-durable-slot.js +53 -0
  43. package/dist/file-durable-slot.js.map +1 -0
  44. package/dist/formation-approval.d.ts +157 -0
  45. package/dist/formation-approval.js +375 -0
  46. package/dist/formation-approval.js.map +1 -0
  47. package/dist/fs-atomic.d.ts +38 -0
  48. package/dist/fs-atomic.js +97 -0
  49. package/dist/fs-atomic.js.map +1 -0
  50. package/dist/identity-key.d.ts +49 -0
  51. package/dist/identity-key.js +81 -0
  52. package/dist/identity-key.js.map +1 -0
  53. package/dist/index.d.ts +17 -7
  54. package/dist/index.js +40 -6
  55. package/dist/index.js.map +1 -1
  56. package/dist/key-store-file.d.ts +2 -24
  57. package/dist/key-store-file.js +10 -77
  58. package/dist/key-store-file.js.map +1 -1
  59. package/dist/membership-connection-gater.d.ts +146 -0
  60. package/dist/membership-connection-gater.js +180 -0
  61. package/dist/membership-connection-gater.js.map +1 -0
  62. package/dist/node-local-snapshot.d.ts +109 -0
  63. package/dist/node-local-snapshot.js +182 -0
  64. package/dist/node-local-snapshot.js.map +1 -0
  65. package/dist/peer-addr-book.d.ts +92 -0
  66. package/dist/peer-addr-book.js +220 -0
  67. package/dist/peer-addr-book.js.map +1 -0
  68. package/dist/peer-authorization.d.ts +135 -18
  69. package/dist/peer-authorization.js +152 -21
  70. package/dist/peer-authorization.js.map +1 -1
  71. package/dist/peer-record.d.ts +21 -8
  72. package/dist/peer-record.js +26 -10
  73. package/dist/peer-record.js.map +1 -1
  74. package/dist/relay-addrs.d.ts +45 -0
  75. package/dist/relay-addrs.js +103 -0
  76. package/dist/relay-addrs.js.map +1 -0
  77. package/dist/relay-reservation.d.ts +266 -0
  78. package/dist/relay-reservation.js +613 -0
  79. package/dist/relay-reservation.js.map +1 -0
  80. package/dist/seed-bootstrap.d.ts +228 -56
  81. package/dist/seed-bootstrap.js +340 -198
  82. package/dist/seed-bootstrap.js.map +1 -1
  83. package/dist/seed-trust-policy.d.ts +47 -21
  84. package/dist/seed-trust-policy.js +24 -15
  85. package/dist/seed-trust-policy.js.map +1 -1
  86. package/dist/strand-addr-protocol.d.ts +42 -13
  87. package/dist/strand-addr-protocol.js +58 -52
  88. package/dist/strand-addr-protocol.js.map +1 -1
  89. package/dist/strand-backfill.d.ts +109 -0
  90. package/dist/strand-backfill.js +279 -0
  91. package/dist/strand-backfill.js.map +1 -0
  92. package/dist/strand-cohort.d.ts +4 -37
  93. package/dist/strand-cohort.js +4 -15
  94. package/dist/strand-cohort.js.map +1 -1
  95. package/dist/strand-database.d.ts +11 -16
  96. package/dist/strand-database.js +19 -7
  97. package/dist/strand-database.js.map +1 -1
  98. package/dist/strand-formation-manager.d.ts +36 -7
  99. package/dist/strand-formation-manager.js +115 -15
  100. package/dist/strand-formation-manager.js.map +1 -1
  101. package/dist/strand-formation-protocol.d.ts +103 -4
  102. package/dist/strand-formation-protocol.js +232 -4
  103. package/dist/strand-formation-protocol.js.map +1 -1
  104. package/dist/strand-instance-manager.d.ts +88 -19
  105. package/dist/strand-instance-manager.js +178 -34
  106. package/dist/strand-instance-manager.js.map +1 -1
  107. package/dist/strand-member-registry.d.ts +5 -5
  108. package/dist/strand-member-registry.js +18 -10
  109. package/dist/strand-member-registry.js.map +1 -1
  110. package/dist/strand-membership-writer.d.ts +484 -88
  111. package/dist/strand-membership-writer.js +751 -128
  112. package/dist/strand-membership-writer.js.map +1 -1
  113. package/dist/strand-solicitation.d.ts +99 -33
  114. package/dist/strand-solicitation.js +100 -52
  115. package/dist/strand-solicitation.js.map +1 -1
  116. package/dist/strand-transport-key.d.ts +40 -0
  117. package/dist/strand-transport-key.js +56 -0
  118. package/dist/strand-transport-key.js.map +1 -0
  119. package/dist/strand-wake-protocol.d.ts +9 -7
  120. package/dist/strand-wake-protocol.js +22 -46
  121. package/dist/strand-wake-protocol.js.map +1 -1
  122. package/dist/strand-watcher.d.ts +17 -2
  123. package/dist/strand-watcher.js +47 -3
  124. package/dist/strand-watcher.js.map +1 -1
  125. package/dist/trusted-owner-store-file.d.ts +12 -0
  126. package/dist/trusted-owner-store-file.js +39 -0
  127. package/dist/trusted-owner-store-file.js.map +1 -0
  128. package/dist/trusted-owner-store.d.ts +64 -0
  129. package/dist/trusted-owner-store.js +126 -0
  130. package/dist/trusted-owner-store.js.map +1 -0
  131. package/dist/types.d.ts +307 -44
  132. package/dist/types.js +13 -0
  133. package/dist/types.js.map +1 -1
  134. package/package.json +20 -8
  135. package/src/arachnode-stub.ts +159 -159
  136. package/src/bootstrap-peer-store-file.ts +44 -0
  137. package/src/bootstrap-peer-store.ts +172 -0
  138. package/src/cadre-node.ts +5158 -2981
  139. package/src/canonical-json.ts +30 -30
  140. package/src/control-authorization.ts +114 -0
  141. package/src/control-cohort.ts +130 -103
  142. package/src/control-database.ts +2406 -948
  143. package/src/control-formation-recorder.ts +305 -151
  144. package/src/control-schema.ts +651 -72
  145. package/src/control-stream.ts +205 -128
  146. package/src/control-write-retry.ts +483 -0
  147. package/src/delegate-admission.ts +302 -0
  148. package/src/device-token.ts +94 -89
  149. package/src/diagnostics/connection-path.ts +277 -277
  150. package/src/diagnostics/webrtc-turn-tracker.ts +222 -222
  151. package/src/ed25519-key.ts +66 -1
  152. package/src/enrollment.ts +199 -199
  153. package/src/file-durable-slot.ts +61 -0
  154. package/src/formation-approval.ts +604 -0
  155. package/src/fs-atomic.ts +107 -0
  156. package/src/hibernation-manager.ts +437 -437
  157. package/src/identity-key.ts +109 -0
  158. package/src/index.ts +137 -5
  159. package/src/key-store-file.ts +132 -203
  160. package/src/key-store.ts +99 -99
  161. package/src/membership-connection-gater.ts +204 -0
  162. package/src/node-local-snapshot.ts +260 -0
  163. package/src/peer-addr-book.ts +250 -0
  164. package/src/peer-authorization.ts +259 -81
  165. package/src/peer-record.ts +164 -146
  166. package/src/push-credentials.ts +84 -84
  167. package/src/push-node.ts +64 -64
  168. package/src/push-notifier-apns.ts +247 -247
  169. package/src/push-notifier-fcm.ts +220 -220
  170. package/src/push-notifier-shared.ts +28 -28
  171. package/src/push-notifier.ts +52 -52
  172. package/src/relay-addrs.ts +111 -0
  173. package/src/relay-reservation.ts +823 -0
  174. package/src/seed-bootstrap.ts +409 -209
  175. package/src/seed-trust-policy.ts +140 -107
  176. package/src/strand-addr-protocol.ts +441 -410
  177. package/src/strand-backfill.ts +366 -0
  178. package/src/strand-cohort.ts +38 -77
  179. package/src/strand-database.ts +202 -204
  180. package/src/strand-formation-manager.ts +491 -368
  181. package/src/strand-formation-protocol.ts +692 -391
  182. package/src/strand-instance-manager.ts +201 -46
  183. package/src/strand-member-key.ts +39 -39
  184. package/src/strand-member-registry.ts +182 -177
  185. package/src/strand-membership-writer.ts +938 -146
  186. package/src/strand-solicitation.ts +472 -407
  187. package/src/strand-transport-key.ts +58 -0
  188. package/src/strand-wake-payload.ts +32 -32
  189. package/src/strand-wake-protocol.ts +314 -331
  190. package/src/strand-watcher.ts +314 -251
  191. package/src/trusted-owner-store-file.ts +41 -0
  192. package/src/trusted-owner-store.ts +171 -0
  193. package/src/types.ts +1309 -1032
@@ -0,0 +1,58 @@
1
+ import { generateKeyPairFromSeed } from '@libp2p/crypto/keys';
2
+ import type { PrivateKey } from '@libp2p/interface';
3
+ import { digest } from '@optimystic/quereus-plugin-crypto';
4
+ import { ed25519KeyPairFromLibp2p } from './ed25519-key.js';
5
+
6
+ /**
7
+ * Domain-separation tag for the strand-transport-key derivation. Versioned so a
8
+ * future change to the derivation (different KDF, different inputs) can bump to
9
+ * `.v2` and be recognized as a deliberate identity migration rather than silent
10
+ * peerId churn — a strand node's transport peerId must stay stable across
11
+ * process restarts, or any peer-store entry or `MemberPeer` row that names it
12
+ * goes stale on every boot.
13
+ */
14
+ const STRAND_TRANSPORT_KEY_DOMAIN = 'sereus.strand-transport-key.v1';
15
+
16
+ /**
17
+ * Derive a strand node's libp2p transport key from the cadre identity key and
18
+ * the strand id.
19
+ *
20
+ * A `CadreNode` runs its control node and each strand node as separate libp2p
21
+ * instances. Handing them all the same private key gives them all the same
22
+ * peerId, and `@libp2p/circuit-relay-v2` keys reservations and hop-connects by
23
+ * peerId — so a control node and a strand node reserving through one shared
24
+ * relay collide, and relayed streams for one land on the other
25
+ * (https://github.com/gotchoices/sereus/issues/1). Each strand node therefore
26
+ * gets its own transport identity. Cadre *authority* is untouched: the control
27
+ * node keeps the identity key, and every peerId→authority derivation
28
+ * (`ed25519PublicKeyB64FromPeerId`) is a control-network path.
29
+ *
30
+ * The derivation is deterministic — `sha256(domain, identity seed, strandId)`
31
+ * as an Ed25519 seed — rather than a fresh random key per launch, so the
32
+ * strand's transport peerId survives restarts. The identity *private* seed is
33
+ * an input (not the public key) so that no third party can enumerate a member's
34
+ * strand peerIds from public data; only the key holder can compute them.
35
+ *
36
+ * NOTE: the derived peerId *is* attested at runtime: before a strand node
37
+ * starts, its control node announces it over the strand-addr RPC, and a
38
+ * membership-gated relay (a party control node running the relay server) holds
39
+ * a short-lived delegate admission grant for it (`delegate-admission.ts`) —
40
+ * without that grant the relay denies the strand node's reservation and
41
+ * `libp2p.start()` fails. The strand *mesh* itself still does not gate
42
+ * admission by peerId (strand peers are legitimately cross-party); if
43
+ * strand-mesh admission control is ever added, the durable binding it needs is
44
+ * a `MemberPeer(MemberKey, PeerId)` row: the table and its self-signed
45
+ * `Authorized` constraint already exist in `schemas/strand.qsql`; production
46
+ * code simply never writes one.
47
+ *
48
+ * @param identityKey - The cadre's Ed25519 identity key (the control node's key).
49
+ * @param strandId - The strand whose transport key to derive.
50
+ * @returns A stable, per-strand Ed25519 libp2p private key, distinct from the
51
+ * identity key and from every other strand's.
52
+ * @throws If the identity key is not Ed25519.
53
+ */
54
+ export async function strandTransportKey(identityKey: PrivateKey, strandId: string): Promise<PrivateKey> {
55
+ const { privateKeyB64 } = ed25519KeyPairFromLibp2p(identityKey);
56
+ const seed = digest([STRAND_TRANSPORT_KEY_DOMAIN, privateKeyB64, strandId], 'sha256', 'bytes') as Uint8Array;
57
+ return generateKeyPairFromSeed('Ed25519', seed);
58
+ }
@@ -1,32 +1,32 @@
1
- /**
2
- * strand-wake-payload.ts — the canonical wire contract for a strand-wake data
3
- * message, shared by the server-side sender (`PushNotifier`, this package) and
4
- * the mobile receiver (`@serfab/reference-app-rn`'s `push-wake.ts`).
5
- *
6
- * A strand-wake is a data-only push delivered to an OS-suspended phone over its
7
- * platform channel (FCM/APNs) when a control-network dial cannot reach the
8
- * hibernating process. It names the strand that has pending activity so the phone
9
- * can run one `serviceWake` cycle and re-hibernate.
10
- *
11
- * This module is intentionally dependency-free (no node/RN/browser-specific
12
- * imports) so it sits cleanly on the cross-platform `cadre-core` entry and can be
13
- * re-exported by the RN receive module without dragging any platform code across
14
- * the send/receive boundary. The defensive `parseStrandWakePayload` parser stays
15
- * on the receive side (it guards untrusted wire input); the sender constructs
16
- * payloads from typed fields and never parses.
17
- */
18
-
19
- /** Discriminator value carried by a strand-wake data message. */
20
- export const STRAND_WAKE_TYPE = 'strand-wake';
21
-
22
- /**
23
- * A data-only push payload telling a suspended phone that `strandId` has pending
24
- * activity. Delivered addressed to the phone's resolved `DeviceToken`.
25
- */
26
- export interface StrandWakePayload {
27
- type: typeof STRAND_WAKE_TYPE;
28
- /** The strand the wake is for. */
29
- strandId: string;
30
- /** Why the wake was sent (e.g. `'activity'`). Free-form, for diagnostics. */
31
- reason: string;
32
- }
1
+ /**
2
+ * strand-wake-payload.ts — the canonical wire contract for a strand-wake data
3
+ * message, shared by the server-side sender (`PushNotifier`, this package) and
4
+ * the mobile receiver (`@serfab/reference-app-rn`'s `push-wake.ts`).
5
+ *
6
+ * A strand-wake is a data-only push delivered to an OS-suspended phone over its
7
+ * platform channel (FCM/APNs) when a control-network dial cannot reach the
8
+ * hibernating process. It names the strand that has pending activity so the phone
9
+ * can run one `serviceWake` cycle and re-hibernate.
10
+ *
11
+ * This module is intentionally dependency-free (no node/RN/browser-specific
12
+ * imports) so it sits cleanly on the cross-platform `cadre-core` entry and can be
13
+ * re-exported by the RN receive module without dragging any platform code across
14
+ * the send/receive boundary. The defensive `parseStrandWakePayload` parser stays
15
+ * on the receive side (it guards untrusted wire input); the sender constructs
16
+ * payloads from typed fields and never parses.
17
+ */
18
+
19
+ /** Discriminator value carried by a strand-wake data message. */
20
+ export const STRAND_WAKE_TYPE = 'strand-wake';
21
+
22
+ /**
23
+ * A data-only push payload telling a suspended phone that `strandId` has pending
24
+ * activity. Delivered addressed to the phone's resolved `DeviceToken`.
25
+ */
26
+ export interface StrandWakePayload {
27
+ type: typeof STRAND_WAKE_TYPE;
28
+ /** The strand the wake is for. */
29
+ strandId: string;
30
+ /** Why the wake was sent (e.g. `'activity'`). Free-form, for diagnostics. */
31
+ reason: string;
32
+ }