@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.
- package/README.md +255 -255
- package/dist/cadre-node.d.ts +203 -28
- package/dist/cadre-node.js +445 -84
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-cohort.d.ts +26 -0
- package/dist/control-cohort.js +26 -0
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +82 -117
- package/dist/control-database.js +217 -295
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +8 -7
- package/dist/control-formation-recorder.js +8 -7
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +789 -774
- package/dist/control-schema.js.map +1 -1
- package/dist/control-write-retry.d.ts +15 -5
- package/dist/control-write-retry.js +19 -18
- package/dist/control-write-retry.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/peer-addr-book.d.ts +92 -0
- package/dist/peer-addr-book.js +220 -0
- package/dist/peer-addr-book.js.map +1 -0
- package/dist/seed-bootstrap.d.ts +7 -0
- package/dist/seed-bootstrap.js +15 -13
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/strand-cohort.d.ts +4 -37
- package/dist/strand-cohort.js +4 -15
- package/dist/strand-cohort.js.map +1 -1
- package/dist/strand-database.d.ts +11 -16
- package/dist/strand-database.js +19 -7
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-formation-manager.d.ts +8 -8
- package/dist/strand-formation-manager.js +15 -18
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +52 -21
- package/dist/strand-instance-manager.js +100 -34
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +6 -4
- package/dist/strand-membership-writer.js +38 -36
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/types.d.ts +39 -31
- package/dist/types.js.map +1 -1
- package/package.json +8 -7
- package/src/arachnode-stub.ts +159 -159
- package/src/bootstrap-peer-store-file.ts +44 -44
- package/src/bootstrap-peer-store.ts +172 -172
- package/src/cadre-node.ts +5158 -4771
- package/src/canonical-json.ts +30 -30
- package/src/control-authorization.ts +114 -114
- package/src/control-cohort.ts +130 -103
- package/src/control-database.ts +2406 -2506
- package/src/control-formation-recorder.ts +305 -304
- package/src/control-schema.ts +801 -786
- package/src/control-stream.ts +205 -205
- package/src/control-write-retry.ts +483 -473
- package/src/delegate-admission.ts +302 -302
- package/src/device-token.ts +94 -94
- package/src/diagnostics/connection-path.ts +277 -277
- package/src/diagnostics/webrtc-turn-tracker.ts +222 -222
- package/src/ed25519-key.ts +134 -134
- package/src/enrollment.ts +199 -199
- package/src/file-durable-slot.ts +61 -61
- package/src/formation-approval.ts +604 -604
- package/src/fs-atomic.ts +107 -107
- package/src/hibernation-manager.ts +437 -437
- package/src/identity-key.ts +109 -109
- package/src/index.ts +1 -0
- package/src/key-store-file.ts +132 -132
- package/src/key-store.ts +99 -99
- package/src/membership-connection-gater.ts +204 -204
- package/src/node-local-snapshot.ts +260 -260
- package/src/peer-addr-book.ts +250 -0
- package/src/peer-authorization.ts +259 -259
- package/src/peer-record.ts +164 -164
- package/src/push-credentials.ts +84 -84
- package/src/push-node.ts +64 -64
- package/src/push-notifier-apns.ts +247 -247
- package/src/push-notifier-fcm.ts +220 -220
- package/src/push-notifier-shared.ts +28 -28
- package/src/push-notifier.ts +52 -52
- package/src/relay-addrs.ts +111 -111
- package/src/relay-reservation.ts +823 -823
- package/src/seed-bootstrap.ts +15 -15
- package/src/seed-trust-policy.ts +140 -140
- package/src/strand-addr-protocol.ts +441 -441
- package/src/strand-backfill.ts +366 -366
- package/src/strand-cohort.ts +38 -77
- package/src/strand-database.ts +202 -204
- package/src/strand-formation-manager.ts +491 -494
- package/src/strand-formation-protocol.ts +692 -692
- package/src/strand-instance-manager.ts +108 -50
- package/src/strand-member-key.ts +39 -39
- package/src/strand-member-registry.ts +182 -182
- package/src/strand-membership-writer.ts +1432 -1430
- package/src/strand-solicitation.ts +472 -472
- package/src/strand-transport-key.ts +58 -58
- package/src/strand-wake-payload.ts +32 -32
- package/src/strand-wake-protocol.ts +314 -314
- package/src/strand-watcher.ts +314 -314
- package/src/trusted-owner-store-file.ts +41 -41
- package/src/trusted-owner-store.ts +171 -171
- 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
|
+
}
|