@serfab/cadre-core 0.10.0 → 0.12.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 (145) hide show
  1. package/README.md +255 -255
  2. package/dist/announce-addrs.d.ts +49 -0
  3. package/dist/announce-addrs.js +78 -0
  4. package/dist/announce-addrs.js.map +1 -0
  5. package/dist/cadre-node.d.ts +484 -58
  6. package/dist/cadre-node.js +953 -182
  7. package/dist/cadre-node.js.map +1 -1
  8. package/dist/control-cohort.d.ts +26 -0
  9. package/dist/control-cohort.js +26 -0
  10. package/dist/control-cohort.js.map +1 -1
  11. package/dist/control-database.d.ts +222 -125
  12. package/dist/control-database.js +356 -266
  13. package/dist/control-database.js.map +1 -1
  14. package/dist/control-formation-recorder.d.ts +8 -7
  15. package/dist/control-formation-recorder.js +8 -7
  16. package/dist/control-formation-recorder.js.map +1 -1
  17. package/dist/control-read-retry.d.ts +103 -0
  18. package/dist/control-read-retry.js +145 -0
  19. package/dist/control-read-retry.js.map +1 -0
  20. package/dist/control-retry.d.ts +101 -0
  21. package/dist/control-retry.js +108 -0
  22. package/dist/control-retry.js.map +1 -0
  23. package/dist/control-schema.d.ts +1 -1
  24. package/dist/control-schema.js +805 -774
  25. package/dist/control-schema.js.map +1 -1
  26. package/dist/control-write-retry.d.ts +65 -31
  27. package/dist/control-write-retry.js +33 -103
  28. package/dist/control-write-retry.js.map +1 -1
  29. package/dist/delegate-admission.d.ts +17 -15
  30. package/dist/delegate-admission.js +17 -15
  31. package/dist/delegate-admission.js.map +1 -1
  32. package/dist/index.d.ts +7 -5
  33. package/dist/index.js +18 -9
  34. package/dist/index.js.map +1 -1
  35. package/dist/membership-connection-gater.d.ts +211 -25
  36. package/dist/membership-connection-gater.js +309 -29
  37. package/dist/membership-connection-gater.js.map +1 -1
  38. package/dist/peer-addr-book.d.ts +92 -0
  39. package/dist/peer-addr-book.js +220 -0
  40. package/dist/peer-addr-book.js.map +1 -0
  41. package/dist/peer-record.d.ts +26 -0
  42. package/dist/peer-record.js +32 -0
  43. package/dist/peer-record.js.map +1 -1
  44. package/dist/relay-addrs.d.ts +76 -26
  45. package/dist/relay-addrs.js +115 -27
  46. package/dist/relay-addrs.js.map +1 -1
  47. package/dist/relay-reservation.d.ts +20 -15
  48. package/dist/relay-reservation.js +18 -14
  49. package/dist/relay-reservation.js.map +1 -1
  50. package/dist/seed-bootstrap.d.ts +7 -0
  51. package/dist/seed-bootstrap.js +15 -13
  52. package/dist/seed-bootstrap.js.map +1 -1
  53. package/dist/strand-addr-protocol.js +16 -0
  54. package/dist/strand-addr-protocol.js.map +1 -1
  55. package/dist/strand-backfill.js +13 -4
  56. package/dist/strand-backfill.js.map +1 -1
  57. package/dist/strand-cohort.d.ts +4 -37
  58. package/dist/strand-cohort.js +4 -15
  59. package/dist/strand-cohort.js.map +1 -1
  60. package/dist/strand-database.d.ts +11 -16
  61. package/dist/strand-database.js +19 -7
  62. package/dist/strand-database.js.map +1 -1
  63. package/dist/strand-formation-manager.d.ts +18 -17
  64. package/dist/strand-formation-manager.js +25 -27
  65. package/dist/strand-formation-manager.js.map +1 -1
  66. package/dist/strand-formation-protocol.d.ts +7 -7
  67. package/dist/strand-formation-protocol.js +8 -8
  68. package/dist/strand-formation-protocol.js.map +1 -1
  69. package/dist/strand-instance-manager.d.ts +53 -21
  70. package/dist/strand-instance-manager.js +128 -37
  71. package/dist/strand-instance-manager.js.map +1 -1
  72. package/dist/strand-membership-writer.d.ts +113 -19
  73. package/dist/strand-membership-writer.js +219 -51
  74. package/dist/strand-membership-writer.js.map +1 -1
  75. package/dist/strand-solicitation.d.ts +3 -3
  76. package/dist/strand-solicitation.js +4 -5
  77. package/dist/strand-solicitation.js.map +1 -1
  78. package/dist/strand-wake-protocol.d.ts +47 -2
  79. package/dist/strand-wake-protocol.js +76 -6
  80. package/dist/strand-wake-protocol.js.map +1 -1
  81. package/dist/types.d.ts +107 -54
  82. package/dist/types.js.map +1 -1
  83. package/package.json +8 -7
  84. package/src/announce-addrs.ts +93 -0
  85. package/src/arachnode-stub.ts +159 -159
  86. package/src/bootstrap-peer-store-file.ts +44 -44
  87. package/src/bootstrap-peer-store.ts +172 -172
  88. package/src/cadre-node.ts +1026 -194
  89. package/src/canonical-json.ts +30 -30
  90. package/src/control-authorization.ts +114 -114
  91. package/src/control-cohort.ts +130 -103
  92. package/src/control-database.ts +376 -298
  93. package/src/control-formation-recorder.ts +305 -304
  94. package/src/control-read-retry.ts +167 -0
  95. package/src/control-retry.ts +190 -0
  96. package/src/control-schema.ts +817 -786
  97. package/src/control-stream.ts +205 -205
  98. package/src/control-write-retry.ts +383 -473
  99. package/src/delegate-admission.ts +304 -302
  100. package/src/device-token.ts +94 -94
  101. package/src/diagnostics/connection-path.ts +277 -277
  102. package/src/diagnostics/webrtc-turn-tracker.ts +222 -222
  103. package/src/ed25519-key.ts +134 -134
  104. package/src/enrollment.ts +199 -199
  105. package/src/file-durable-slot.ts +61 -61
  106. package/src/formation-approval.ts +604 -604
  107. package/src/fs-atomic.ts +107 -107
  108. package/src/hibernation-manager.ts +437 -437
  109. package/src/identity-key.ts +109 -109
  110. package/src/index.ts +435 -406
  111. package/src/key-store-file.ts +132 -132
  112. package/src/key-store.ts +99 -99
  113. package/src/membership-connection-gater.ts +368 -39
  114. package/src/node-local-snapshot.ts +260 -260
  115. package/src/peer-addr-book.ts +250 -0
  116. package/src/peer-authorization.ts +259 -259
  117. package/src/peer-record.ts +197 -164
  118. package/src/push-credentials.ts +84 -84
  119. package/src/push-node.ts +64 -64
  120. package/src/push-notifier-apns.ts +247 -247
  121. package/src/push-notifier-fcm.ts +220 -220
  122. package/src/push-notifier-shared.ts +28 -28
  123. package/src/push-notifier.ts +52 -52
  124. package/src/relay-addrs.ts +134 -27
  125. package/src/relay-reservation.ts +22 -17
  126. package/src/seed-bootstrap.ts +15 -15
  127. package/src/seed-trust-policy.ts +140 -140
  128. package/src/strand-addr-protocol.ts +458 -441
  129. package/src/strand-backfill.ts +28 -5
  130. package/src/strand-cohort.ts +38 -77
  131. package/src/strand-database.ts +202 -204
  132. package/src/strand-formation-manager.ts +26 -28
  133. package/src/strand-formation-protocol.ts +692 -692
  134. package/src/strand-instance-manager.ts +636 -553
  135. package/src/strand-member-key.ts +39 -39
  136. package/src/strand-member-registry.ts +182 -182
  137. package/src/strand-membership-writer.ts +1627 -1430
  138. package/src/strand-solicitation.ts +471 -472
  139. package/src/strand-transport-key.ts +58 -58
  140. package/src/strand-wake-payload.ts +32 -32
  141. package/src/strand-wake-protocol.ts +400 -314
  142. package/src/strand-watcher.ts +314 -314
  143. package/src/trusted-owner-store-file.ts +41 -41
  144. package/src/trusted-owner-store.ts +171 -171
  145. package/src/types.ts +1354 -1303
@@ -1,58 +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
+ 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
+ }