@serfab/cadre-core 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +255 -255
  2. package/dist/cadre-node.d.ts +203 -28
  3. package/dist/cadre-node.js +445 -84
  4. package/dist/cadre-node.js.map +1 -1
  5. package/dist/control-cohort.d.ts +26 -0
  6. package/dist/control-cohort.js +26 -0
  7. package/dist/control-cohort.js.map +1 -1
  8. package/dist/control-database.d.ts +82 -117
  9. package/dist/control-database.js +217 -295
  10. package/dist/control-database.js.map +1 -1
  11. package/dist/control-formation-recorder.d.ts +8 -7
  12. package/dist/control-formation-recorder.js +8 -7
  13. package/dist/control-formation-recorder.js.map +1 -1
  14. package/dist/control-schema.d.ts +1 -1
  15. package/dist/control-schema.js +789 -774
  16. package/dist/control-schema.js.map +1 -1
  17. package/dist/control-write-retry.d.ts +15 -5
  18. package/dist/control-write-retry.js +19 -18
  19. package/dist/control-write-retry.js.map +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/peer-addr-book.d.ts +92 -0
  24. package/dist/peer-addr-book.js +220 -0
  25. package/dist/peer-addr-book.js.map +1 -0
  26. package/dist/seed-bootstrap.d.ts +7 -0
  27. package/dist/seed-bootstrap.js +15 -13
  28. package/dist/seed-bootstrap.js.map +1 -1
  29. package/dist/strand-cohort.d.ts +4 -37
  30. package/dist/strand-cohort.js +4 -15
  31. package/dist/strand-cohort.js.map +1 -1
  32. package/dist/strand-database.d.ts +11 -16
  33. package/dist/strand-database.js +19 -7
  34. package/dist/strand-database.js.map +1 -1
  35. package/dist/strand-formation-manager.d.ts +8 -8
  36. package/dist/strand-formation-manager.js +15 -18
  37. package/dist/strand-formation-manager.js.map +1 -1
  38. package/dist/strand-instance-manager.d.ts +52 -21
  39. package/dist/strand-instance-manager.js +100 -34
  40. package/dist/strand-instance-manager.js.map +1 -1
  41. package/dist/strand-membership-writer.d.ts +6 -4
  42. package/dist/strand-membership-writer.js +38 -36
  43. package/dist/strand-membership-writer.js.map +1 -1
  44. package/dist/types.d.ts +39 -31
  45. package/dist/types.js.map +1 -1
  46. package/package.json +8 -7
  47. package/src/arachnode-stub.ts +159 -159
  48. package/src/bootstrap-peer-store-file.ts +44 -44
  49. package/src/bootstrap-peer-store.ts +172 -172
  50. package/src/cadre-node.ts +5158 -4771
  51. package/src/canonical-json.ts +30 -30
  52. package/src/control-authorization.ts +114 -114
  53. package/src/control-cohort.ts +130 -103
  54. package/src/control-database.ts +2406 -2506
  55. package/src/control-formation-recorder.ts +305 -304
  56. package/src/control-schema.ts +801 -786
  57. package/src/control-stream.ts +205 -205
  58. package/src/control-write-retry.ts +483 -473
  59. package/src/delegate-admission.ts +302 -302
  60. package/src/device-token.ts +94 -94
  61. package/src/diagnostics/connection-path.ts +277 -277
  62. package/src/diagnostics/webrtc-turn-tracker.ts +222 -222
  63. package/src/ed25519-key.ts +134 -134
  64. package/src/enrollment.ts +199 -199
  65. package/src/file-durable-slot.ts +61 -61
  66. package/src/formation-approval.ts +604 -604
  67. package/src/fs-atomic.ts +107 -107
  68. package/src/hibernation-manager.ts +437 -437
  69. package/src/identity-key.ts +109 -109
  70. package/src/index.ts +1 -0
  71. package/src/key-store-file.ts +132 -132
  72. package/src/key-store.ts +99 -99
  73. package/src/membership-connection-gater.ts +204 -204
  74. package/src/node-local-snapshot.ts +260 -260
  75. package/src/peer-addr-book.ts +250 -0
  76. package/src/peer-authorization.ts +259 -259
  77. package/src/peer-record.ts +164 -164
  78. package/src/push-credentials.ts +84 -84
  79. package/src/push-node.ts +64 -64
  80. package/src/push-notifier-apns.ts +247 -247
  81. package/src/push-notifier-fcm.ts +220 -220
  82. package/src/push-notifier-shared.ts +28 -28
  83. package/src/push-notifier.ts +52 -52
  84. package/src/relay-addrs.ts +111 -111
  85. package/src/relay-reservation.ts +823 -823
  86. package/src/seed-bootstrap.ts +15 -15
  87. package/src/seed-trust-policy.ts +140 -140
  88. package/src/strand-addr-protocol.ts +441 -441
  89. package/src/strand-backfill.ts +366 -366
  90. package/src/strand-cohort.ts +38 -77
  91. package/src/strand-database.ts +202 -204
  92. package/src/strand-formation-manager.ts +491 -494
  93. package/src/strand-formation-protocol.ts +692 -692
  94. package/src/strand-instance-manager.ts +108 -50
  95. package/src/strand-member-key.ts +39 -39
  96. package/src/strand-member-registry.ts +182 -182
  97. package/src/strand-membership-writer.ts +1432 -1430
  98. package/src/strand-solicitation.ts +472 -472
  99. package/src/strand-transport-key.ts +58 -58
  100. package/src/strand-wake-payload.ts +32 -32
  101. package/src/strand-wake-protocol.ts +314 -314
  102. package/src/strand-watcher.ts +314 -314
  103. package/src/trusted-owner-store-file.ts +41 -41
  104. package/src/trusted-owner-store.ts +171 -171
  105. package/src/types.ts +1309 -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
+ }