@serfab/cadre-core 0.8.1 → 0.9.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 +2 -2
- package/dist/cadre-node.d.ts +101 -61
- package/dist/cadre-node.js +165 -124
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-cohort.d.ts +15 -15
- package/dist/control-cohort.js +14 -14
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +51 -34
- package/dist/control-database.js +72 -56
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +2 -2
- package/dist/control-formation-recorder.js +2 -2
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +57 -33
- package/dist/control-schema.js.map +1 -1
- package/dist/device-token.d.ts +1 -1
- package/dist/device-token.js +1 -1
- package/dist/{authority-key.d.ts → ed25519-key.d.ts} +11 -10
- package/dist/{authority-key.js → ed25519-key.js} +9 -10
- package/dist/ed25519-key.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/key-store.d.ts +1 -1
- package/dist/key-store.js +1 -1
- package/dist/peer-authorization.d.ts +28 -6
- package/dist/peer-authorization.js +33 -7
- package/dist/peer-authorization.js.map +1 -1
- package/dist/peer-record.d.ts +3 -3
- package/dist/peer-record.js +3 -3
- package/dist/push-node.d.ts +38 -0
- package/dist/push-node.js +48 -0
- package/dist/push-node.js.map +1 -0
- package/dist/push-notifier-apns.d.ts +10 -2
- package/dist/push-notifier-apns.js +14 -10
- package/dist/push-notifier-apns.js.map +1 -1
- package/dist/push-notifier-fcm.d.ts +7 -1
- package/dist/push-notifier-fcm.js +9 -10
- package/dist/push-notifier-fcm.js.map +1 -1
- package/dist/push-notifier.d.ts +16 -35
- package/dist/push-notifier.js +16 -44
- package/dist/push-notifier.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +70 -51
- package/dist/seed-bootstrap.js +168 -106
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/seed-trust-policy.d.ts +11 -11
- package/dist/seed-trust-policy.js +11 -11
- package/dist/seed-trust-policy.js.map +1 -1
- package/dist/strand-database.d.ts +5 -5
- package/dist/strand-database.js +4 -4
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +1 -1
- package/dist/strand-formation-protocol.js +1 -1
- package/dist/strand-instance-manager.d.ts +1 -1
- package/dist/strand-instance-manager.js +1 -1
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-member-key.d.ts +6 -6
- package/dist/strand-member-key.js +6 -6
- package/dist/strand-member-key.js.map +1 -1
- package/dist/strand-member-registry.d.ts +7 -7
- package/dist/strand-member-registry.js +5 -5
- package/dist/strand-member-registry.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +84 -84
- package/dist/strand-membership-writer.js +90 -90
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/types.d.ts +52 -32
- package/dist/types.js.map +1 -1
- package/package.json +7 -3
- package/src/cadre-node.ts +170 -126
- package/src/control-cohort.ts +17 -17
- package/src/control-database.ts +76 -59
- package/src/control-formation-recorder.ts +2 -2
- package/src/control-schema.ts +57 -33
- package/src/device-token.ts +1 -1
- package/src/{authority-key.ts → ed25519-key.ts} +12 -11
- package/src/index.ts +21 -19
- package/src/key-store.ts +1 -1
- package/src/peer-authorization.ts +35 -7
- package/src/peer-record.ts +3 -3
- package/src/push-node.ts +64 -0
- package/src/push-notifier-apns.ts +16 -12
- package/src/push-notifier-fcm.ts +9 -10
- package/src/push-notifier.ts +16 -57
- package/src/seed-bootstrap.ts +179 -115
- package/src/seed-trust-policy.ts +18 -18
- package/src/strand-database.ts +6 -6
- package/src/strand-formation-protocol.ts +1 -1
- package/src/strand-instance-manager.ts +2 -2
- package/src/strand-member-key.ts +7 -7
- package/src/strand-member-registry.ts +10 -10
- package/src/strand-membership-writer.ts +127 -127
- package/src/types.ts +52 -32
- package/dist/authority-key.js.map +0 -1
package/README.md
CHANGED
|
@@ -126,9 +126,9 @@ Adding a new device to your cadre uses the Seed Bootstrap API:
|
|
|
126
126
|
// On the new device: generate identity
|
|
127
127
|
const enrollment = new EnrollmentService();
|
|
128
128
|
const { peerId, privateKey } = await enrollment.createCadrePeer();
|
|
129
|
-
// Store privateKey securely, send peerId + multiaddrs to
|
|
129
|
+
// Store privateKey securely, send peerId + multiaddrs to owner
|
|
130
130
|
|
|
131
|
-
// On
|
|
131
|
+
// On owner device: authorize the new peer and create seed
|
|
132
132
|
await node.authorizePeer(newDevicePeerId, newDeviceMultiaddrs);
|
|
133
133
|
const seed = await node.createSeed();
|
|
134
134
|
|
package/dist/cadre-node.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Libp2p, PeerId } from '@libp2p/interface';
|
|
2
2
|
import type { Multiaddr } from '@multiformats/multiaddr';
|
|
3
3
|
import type { CadreNodeConfig, StrandInstance, StrandConfig, SAppConfig, CadreNodeEvents, ControlNetworkSeed, ApplySeedResult, AddDroneOptions, AddPhoneOptions, DroneInitResult, InviteResult, CadreInvite, OpenInvitation, FormStrandResult, StrandFormationDisclosure, ResolveOpts, SelfRegistrationOutcome, ServiceWakeResult, PushPlatform, DeviceTokenRecord, ResolveDeviceTokenOpts } from './types.js';
|
|
4
|
-
import { type
|
|
4
|
+
import { type Ed25519KeyPair } from './ed25519-key.js';
|
|
5
5
|
import { type SAppIdLookup } from './strand-watcher.js';
|
|
6
6
|
import { EnrollmentService } from './enrollment.js';
|
|
7
7
|
import { ControlDatabase } from './control-database.js';
|
|
@@ -26,7 +26,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
26
26
|
* The resolved node identity key, set once by {@link resolveIdentityKey}
|
|
27
27
|
* during {@link start} (from `config.keyStore`, else `config.privateKey`).
|
|
28
28
|
* Left undefined when neither is configured — libp2p then generates an
|
|
29
|
-
* ephemeral key internally and there is no exposed
|
|
29
|
+
* ephemeral key internally and there is no exposed owner key. Every
|
|
30
30
|
* identity-dependent path (control node creation, self-record signing, strand
|
|
31
31
|
* launch) reads this resolved field, never `config.privateKey` directly.
|
|
32
32
|
*/
|
|
@@ -49,9 +49,9 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
49
49
|
private strandAddrService;
|
|
50
50
|
/**
|
|
51
51
|
* Server-side push-wake fan-out. Constructed by {@link start} only when
|
|
52
|
-
* `config.push` (
|
|
53
|
-
* exactly as before (no notifier, no fan-out). Owns who/when
|
|
54
|
-
* hibernating mobile peers on strand activity.
|
|
52
|
+
* `config.push` (an injected `PushNotifier` + policy) is present — without it
|
|
53
|
+
* the node behaves exactly as before (no notifier, no fan-out). Owns who/when
|
|
54
|
+
* to wake hibernating mobile peers on strand activity.
|
|
55
55
|
*/
|
|
56
56
|
private pushFanoutService;
|
|
57
57
|
/** Backing field for the {@link running} / {@link isRunning} getters. */
|
|
@@ -101,13 +101,13 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
101
101
|
private reconcileControlCohortInFlight;
|
|
102
102
|
/**
|
|
103
103
|
* Single-flight guard for {@link registerSelf}. Concurrent callers (the explicit
|
|
104
|
-
* CLI `--
|
|
104
|
+
* CLI `--owner` publish, the 1s startup timer, the TTL heartbeat, and the
|
|
105
105
|
* address-change listener) share one in-flight publish so two of them can never
|
|
106
106
|
* both read "no row yet" and race a duplicate INSERT (a `CadrePeer` PK conflict).
|
|
107
107
|
*/
|
|
108
108
|
private registerSelfInFlight;
|
|
109
109
|
/**
|
|
110
|
-
* Re-replication queue for
|
|
110
|
+
* Re-replication queue for owner control writes that committed while this
|
|
111
111
|
* node was alone — `controlNode.getConnections().length === 0` at write time
|
|
112
112
|
* means the Optimystic commit was local-only (the block's cluster was ≤1) and
|
|
113
113
|
* never broadcast. Maps the affected subject peerId → the write to re-issue once
|
|
@@ -121,7 +121,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
121
121
|
/** This node's own `DeviceToken` self-write committed local-only (re-touched on growth). */
|
|
122
122
|
private pendingSelfDeviceWrite;
|
|
123
123
|
/**
|
|
124
|
-
* Guards the one-shot, first-cohort-growth reconstruction: an
|
|
124
|
+
* Guards the one-shot, first-cohort-growth reconstruction: an owner re-touches
|
|
125
125
|
* every membership row it may have authored that could be unreplicated (covering
|
|
126
126
|
* writes made before this process started, which the in-memory queue cannot know).
|
|
127
127
|
* Set true after the first drain so later passes only drain the in-memory queue.
|
|
@@ -218,6 +218,19 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
218
218
|
* Start the cadre node
|
|
219
219
|
*/
|
|
220
220
|
start(): Promise<void>;
|
|
221
|
+
/**
|
|
222
|
+
* Build the server-side push-wake fan-out over an injected {@link PushNotifier}.
|
|
223
|
+
*
|
|
224
|
+
* The notifier reaches for `node:http2`/`node:crypto`, so the cross-platform
|
|
225
|
+
* core never constructs it — the Node host builds it from
|
|
226
|
+
* `@serfab/cadre-core/push-node` and passes the instance in
|
|
227
|
+
* `CadreNodeConfig.push`. This node owns that instance's lifecycle from here:
|
|
228
|
+
* {@link cleanup} closes the fan-out, which closes the notifier (freeing the
|
|
229
|
+
* APNs HTTP/2 session). Every other primitive the fan-out needs (member
|
|
230
|
+
* enumeration, participation, direct dial, token resolve/expire) is an
|
|
231
|
+
* import-clean closure over this node.
|
|
232
|
+
*/
|
|
233
|
+
private buildPushFanout;
|
|
221
234
|
/**
|
|
222
235
|
* Stop the cadre node
|
|
223
236
|
*/
|
|
@@ -253,7 +266,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
253
266
|
/**
|
|
254
267
|
* Schedule the node's initial self-record publish + ongoing refresh shortly
|
|
255
268
|
* after start (non-blocking). {@link registerSelf} is idempotent and safely
|
|
256
|
-
* no-ops when it cannot yet sign/insert (e.g.
|
|
269
|
+
* no-ops when it cannot yet sign/insert (e.g. owner key not installed),
|
|
257
270
|
* so the timer is harmless even when registration only becomes possible later.
|
|
258
271
|
*/
|
|
259
272
|
private scheduleSelfRegistration;
|
|
@@ -266,10 +279,10 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
266
279
|
* (signaling/`p2p-circuit` first), signed with the ed25519 key behind its
|
|
267
280
|
* PeerId (the resolved node identity from `keyStore`/`config.privateKey`).
|
|
268
281
|
* - If the row already exists: a self-signed UPDATE bumping `UpdatedAt`.
|
|
269
|
-
* - If not, and the node is its own
|
|
282
|
+
* - If not, and the node is its own owner: an owner-signed INSERT that
|
|
270
283
|
* also carries the self-signature.
|
|
271
|
-
* - Otherwise: logs and returns (a non-
|
|
272
|
-
* wait for an
|
|
284
|
+
* - Otherwise: logs and returns (a non-owner node with no row yet must
|
|
285
|
+
* wait for an owner to insert it; it can then self-refresh).
|
|
273
286
|
*
|
|
274
287
|
* Safe to call repeatedly (heartbeat / address-change driven); each successful
|
|
275
288
|
* publish strictly increases `UpdatedAt`. Concurrent calls are collapsed into a
|
|
@@ -291,23 +304,23 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
291
304
|
*/
|
|
292
305
|
private getSelfSigningKey;
|
|
293
306
|
/**
|
|
294
|
-
* The
|
|
295
|
-
* identity key. In the single-key reference model the
|
|
296
|
-
* *derived from* the node identity (see {@link
|
|
307
|
+
* The owner keypair (base64url Ed25519) derived from this node's resolved
|
|
308
|
+
* identity key. In the single-key reference model the owner signing key is
|
|
309
|
+
* *derived from* the node identity (see {@link ed25519KeyPairFromLibp2p}), so the
|
|
297
310
|
* same key material protected in a secure enclave backs both.
|
|
298
311
|
*
|
|
299
|
-
* Exposed so the hosting app retains control of
|
|
312
|
+
* Exposed so the hosting app retains control of owner genesis: cadre-core
|
|
300
313
|
* resolves + protects the identity, then the app sources this pair to drive
|
|
301
|
-
* `
|
|
302
|
-
* never silently runs genesis. A future separate-
|
|
314
|
+
* `ensureOwnerKey(pub)` + `initializeSeedBootstrap(priv)` itself — cadre-core
|
|
315
|
+
* never silently runs genesis. A future separate-owner slot would return a
|
|
303
316
|
* distinct key here instead of the identity-derived one.
|
|
304
317
|
*
|
|
305
|
-
* @returns The base64url seed/public-key
|
|
318
|
+
* @returns The base64url seed/public-key owner pair.
|
|
306
319
|
* @throws If called before {@link start} has resolved the identity, or when the
|
|
307
320
|
* node runs on an ephemeral libp2p key (no `keyStore`/`privateKey` configured),
|
|
308
321
|
* since that key is internal to libp2p and not exposed.
|
|
309
322
|
*/
|
|
310
|
-
|
|
323
|
+
getIdentityOwnerKey(): Ed25519KeyPair;
|
|
311
324
|
/**
|
|
312
325
|
* Collect this node's current dialable addresses for publication, signaling
|
|
313
326
|
* (`/p2p-circuit`) first. Prefers the best invite/NAT-resolved set and folds
|
|
@@ -366,7 +379,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
366
379
|
*
|
|
367
380
|
* A per-peer failure (NAT, offline, relay down, connection-gater denial) is
|
|
368
381
|
* logged and swallowed so one unreachable sibling never aborts the pass —
|
|
369
|
-
* exactly like {@link SeedBootstrapService.applySeed}'s
|
|
382
|
+
* exactly like {@link SeedBootstrapService.applySeed}'s owner-dial loop. A
|
|
370
383
|
* failed dial is simply retried on the next pass.
|
|
371
384
|
*/
|
|
372
385
|
private dialControlSibling;
|
|
@@ -398,7 +411,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
398
411
|
*/
|
|
399
412
|
private committedAlone;
|
|
400
413
|
/**
|
|
401
|
-
* Record (or clear) a just-committed
|
|
414
|
+
* Record (or clear) a just-committed owner membership write in the
|
|
402
415
|
* write-while-alone re-replication queue. If the control node had no connections
|
|
403
416
|
* at commit, the Optimystic write was local-only and must be re-issued once the
|
|
404
417
|
* cohort grows; otherwise the write replicated and any stale queue entry for this
|
|
@@ -432,28 +445,28 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
432
445
|
private retouchSelfDeviceToken;
|
|
433
446
|
/**
|
|
434
447
|
* One-shot, first-cohort-growth reconstruction of the write-while-alone queue for
|
|
435
|
-
* an
|
|
436
|
-
*
|
|
448
|
+
* an OWNER node: re-touch every membership row that may be an unreplicated
|
|
449
|
+
* owner insert. A row is a candidate iff it is not self (handled by
|
|
437
450
|
* {@link registerSelf}), is not already tracked in the in-memory queue (handled by
|
|
438
451
|
* {@link drainPendingPeerWrites}), and carries no self-`Sig` yet (an
|
|
439
|
-
*
|
|
452
|
+
* owner-authored row the peer has not self-published — the only kind safe to
|
|
440
453
|
* bump without invalidating a self-signature). O(rows) on the small control
|
|
441
|
-
* tables; safe to over-apply (a monotonic
|
|
454
|
+
* tables; safe to over-apply (a monotonic owner bump on an already-replicated
|
|
442
455
|
* row is a no-op-equivalent).
|
|
443
456
|
*
|
|
444
|
-
* A node with no
|
|
457
|
+
* A node with no owner private key skips this entirely — it cannot re-sign
|
|
445
458
|
* rows for other peers, and rows it merely holds are not its to re-issue. DELETEs
|
|
446
459
|
* cannot be reconstructed here (a removed row leaves no local trace and the schema
|
|
447
460
|
* carries no tombstone) — see the delete-path note in {@link drainPendingPeerWrites}.
|
|
448
461
|
*/
|
|
449
462
|
private reconstructAuthoredMembership;
|
|
450
463
|
/**
|
|
451
|
-
* Drain the in-session write-while-alone queue: re-issue each pending
|
|
464
|
+
* Drain the in-session write-while-alone queue: re-issue each pending owner
|
|
452
465
|
* membership write now that the cohort can broadcast it. Sequential (no fan-out)
|
|
453
466
|
* to avoid a thundering re-touch; an entry is cleared only on success, so a
|
|
454
467
|
* failure (or a still-alone re-commit) leaves it queued for the next growth.
|
|
455
468
|
*
|
|
456
|
-
* - `authorize`: re-issue as an idempotent monotonic
|
|
469
|
+
* - `authorize`: re-issue as an idempotent monotonic owner UPDATE
|
|
457
470
|
* ({@link reissuePeerAuthorize}). Skipped (and cleared) if the row vanished
|
|
458
471
|
* (raced a delete) or now carries a self-`Sig` (the peer self-published and owns
|
|
459
472
|
* its republish).
|
|
@@ -466,9 +479,9 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
466
479
|
*/
|
|
467
480
|
private drainPendingPeerWrites;
|
|
468
481
|
/**
|
|
469
|
-
* Re-issue an
|
|
482
|
+
* Re-issue an owner membership row as a monotonic owner UPDATE: bump
|
|
470
483
|
* `UpdatedAt` strictly above the stored value (and the wall clock) and re-sign via
|
|
471
|
-
* the
|
|
484
|
+
* the owner branch of `CadrePeer.AuthorizedUpdate`. The row already exists
|
|
472
485
|
* locally (it committed there, just local-only), so this is an UPDATE, not the
|
|
473
486
|
* original INSERT.
|
|
474
487
|
*/
|
|
@@ -508,11 +521,11 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
508
521
|
* for any member — the `AuthorizedUpdate` self-branch verifies the new `Sig`
|
|
509
522
|
* against the bound `CadrePeer.PublicKey`). Platform/Token may change here
|
|
510
523
|
* (rotation / platform switch / reinstall are all normal self-updates).
|
|
511
|
-
* - If not, and the node holds an
|
|
524
|
+
* - If not, and the node holds an owner service: an owner-signed INSERT
|
|
512
525
|
* that also carries the self-signature.
|
|
513
526
|
* - Otherwise: throws. Like `CadrePeer`, the first `DeviceToken` row requires an
|
|
514
|
-
*
|
|
515
|
-
* seeded by an
|
|
527
|
+
* owner signature; a non-owner peer (e.g. a phone) must have its row
|
|
528
|
+
* seeded by an owner — typically the server it enrolled with — before it
|
|
516
529
|
* can self-refresh. (Establishing that phone→server registration handshake is
|
|
517
530
|
* the downstream "RN registration" ticket; this node only owns the cadre-core
|
|
518
531
|
* write path.)
|
|
@@ -523,7 +536,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
523
536
|
* @param platform - `'fcm'` (Android/Firebase) or `'apns'` (Apple).
|
|
524
537
|
* @param token - the opaque platform device/registration token.
|
|
525
538
|
* @throws if the node is not started, exposes no self-signing key, or has no
|
|
526
|
-
* existing row and no
|
|
539
|
+
* existing row and no owner service to self-insert.
|
|
527
540
|
*/
|
|
528
541
|
registerDeviceToken(platform: PushPlatform, token: string): Promise<void>;
|
|
529
542
|
/**
|
|
@@ -548,11 +561,11 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
548
561
|
/**
|
|
549
562
|
* Delete this node's own `DeviceToken` row (logout / token invalidation). No-op
|
|
550
563
|
* when no row exists. Like {@link registerDeviceToken}'s first insert, the delete
|
|
551
|
-
* is gated on an
|
|
552
|
-
* AND delete), so it requires this node's
|
|
553
|
-
* must route the clear through its
|
|
564
|
+
* is gated on an owner signature (`DeviceToken.AuthorizedInsert` covers insert
|
|
565
|
+
* AND delete), so it requires this node's owner service; a non-owner peer
|
|
566
|
+
* must route the clear through its owner (downstream RN registration path).
|
|
554
567
|
*
|
|
555
|
-
* @throws if the node is not started, or a row exists but no
|
|
568
|
+
* @throws if the node is not started, or a row exists but no owner service is
|
|
556
569
|
* available to sign the delete.
|
|
557
570
|
*/
|
|
558
571
|
clearDeviceToken(): Promise<void>;
|
|
@@ -561,10 +574,10 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
561
574
|
* unregistered during a push-wake fan-out. Unlike {@link clearDeviceToken}
|
|
562
575
|
* (self-only — it hardcodes the local peerId), this takes an arbitrary peerId.
|
|
563
576
|
*
|
|
564
|
-
* - When this node holds an
|
|
565
|
-
* (`deleteDeviceToken` is
|
|
577
|
+
* - When this node holds an owner seed service, it deletes the row
|
|
578
|
+
* (`deleteDeviceToken` is owner-gated and accepts any peerId), so the peer
|
|
566
579
|
* is not retried until it re-registers.
|
|
567
|
-
* - When this node is NOT an
|
|
580
|
+
* - When this node is NOT an owner it cannot delete the row, so it only logs
|
|
568
581
|
* that a re-registration is needed. The fan-out's own in-memory dead-token set
|
|
569
582
|
* is what actually stops re-pushing to the dead token this process — see
|
|
570
583
|
* {@link PushFanoutService}. That set is acceptably lossy across restarts (a
|
|
@@ -663,19 +676,19 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
663
676
|
addStrand(config: StrandConfig): Promise<StrandInstance>;
|
|
664
677
|
/**
|
|
665
678
|
* Publish a strand row to the shared control database under this node's own
|
|
666
|
-
*
|
|
679
|
+
* owner identity, so other cadre members discover it via control-network
|
|
667
680
|
* sync (their {@link StrandWatcher} fires `strand:discovered`).
|
|
668
681
|
*
|
|
669
|
-
* This is the
|
|
682
|
+
* This is the owner-signed `Strand` INSERT that {@link addStrand}
|
|
670
683
|
* deliberately omits: `addStrand` only starts the LOCAL strand instance,
|
|
671
684
|
* whereas publishing makes the strand visible cadre-wide. A typical creator
|
|
672
685
|
* does both (start locally + publish); a discovering peer only does
|
|
673
686
|
* `addStrand` (the row already exists).
|
|
674
687
|
*
|
|
675
688
|
* The insert is signed with the ed25519 key behind this node's PeerId — which
|
|
676
|
-
* {@link
|
|
677
|
-
* so peer identity and
|
|
678
|
-
* enrolled in `
|
|
689
|
+
* {@link ed25519KeyPairFromLibp2p} also exposes as the node's owner keypair,
|
|
690
|
+
* so peer identity and owner key are one and the same. That key must be
|
|
691
|
+
* enrolled in `OwnerKey` (e.g. via {@link ControlDatabase.ensureOwnerKey}
|
|
679
692
|
* at genesis) or the schema's `Strand.Authorized` constraint rejects the write.
|
|
680
693
|
* Failing loudly here is intentional: a silently-unpublished strand would run
|
|
681
694
|
* as a local-only island that no peer could ever discover or join.
|
|
@@ -684,12 +697,12 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
684
697
|
* {@link addStrand}).
|
|
685
698
|
* @param type - `'o'` for open (default) or `'c'` for closed.
|
|
686
699
|
* @param memberPrivateKey - Optional membership key for a closed strand.
|
|
687
|
-
* @throws if the node is not started, exposes no
|
|
700
|
+
* @throws if the node is not started, exposes no owner signing key, or the
|
|
688
701
|
* control DB rejects the (unauthorized) insert.
|
|
689
702
|
*/
|
|
690
703
|
publishStrand(strandId: string, type?: 'o' | 'c', memberPrivateKey?: string): Promise<void>;
|
|
691
704
|
/**
|
|
692
|
-
* Publish an
|
|
705
|
+
* Publish an owner-signed `FormationInvite` (open-invitation token) to the
|
|
693
706
|
* shared control database, so a later {@link formStrand} redemption can be
|
|
694
707
|
* validated against it (the consent branch of `Strand.Authorized`).
|
|
695
708
|
*
|
|
@@ -700,8 +713,8 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
700
713
|
* from this row. A host minting a closed-strand invite does both (mint +
|
|
701
714
|
* publish), exactly as the integration harness's `createInvitation` does.
|
|
702
715
|
*
|
|
703
|
-
* Signs with the same self-
|
|
704
|
-
* key behind this node's PeerId, which must be an enrolled `
|
|
716
|
+
* Signs with the same self-owner key as {@link publishStrand} (the ed25519
|
|
717
|
+
* key behind this node's PeerId, which must be an enrolled `OwnerKey`).
|
|
705
718
|
* Throws loudly if the node isn't started or exposes no signing key.
|
|
706
719
|
*
|
|
707
720
|
* @param token - Invitation token (the `FormationInvite` primary key); use the
|
|
@@ -841,12 +854,12 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
841
854
|
*/
|
|
842
855
|
getSAppConfig(strandId: string): SAppConfig | undefined;
|
|
843
856
|
/**
|
|
844
|
-
* Initialize the seed bootstrap service with an
|
|
857
|
+
* Initialize the seed bootstrap service with an owner key.
|
|
845
858
|
* Must be called before using seed-related methods that require signing.
|
|
846
859
|
*
|
|
847
|
-
* @param
|
|
860
|
+
* @param ownerPrivateKey - The owner's private key (base64url encoded)
|
|
848
861
|
*/
|
|
849
|
-
initializeSeedBootstrap(
|
|
862
|
+
initializeSeedBootstrap(ownerPrivateKey: string): void;
|
|
850
863
|
/**
|
|
851
864
|
* Push the multiaddrs that future invites should advertise. Pass `null` to
|
|
852
865
|
* revert to the libp2p-reported addresses (the default). The host calls this
|
|
@@ -867,8 +880,35 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
867
880
|
}>>;
|
|
868
881
|
/**
|
|
869
882
|
* Probe whether a given peer is a `CadrePeer` member.
|
|
883
|
+
*
|
|
884
|
+
* This is the ADDRESSABLE surface ("do I have a dialable address record for this
|
|
885
|
+
* peer") — it includes this node's own self-published row. Address resolution and
|
|
886
|
+
* push fan-out use this. The trust-facing gate is {@link isAuthorizedMember}.
|
|
870
887
|
*/
|
|
871
888
|
isMember(peerId: string): Promise<boolean>;
|
|
889
|
+
/**
|
|
890
|
+
* Enumerate the party's AUTHORIZED members — the trust-facing set, distinct from
|
|
891
|
+
* the addressable set ({@link listMembers}). Excludes this node itself: a node
|
|
892
|
+
* publishes its own `CadrePeer` address row so its dialable address rides in seeds,
|
|
893
|
+
* but "self" is not a peer this node authorized. The control-network wake and
|
|
894
|
+
* strand-address gates consult this set, NOT the addressable one.
|
|
895
|
+
*
|
|
896
|
+
* NOTE: this is the addressable set minus self for now. The real trust predicate
|
|
897
|
+
* (voucher recorded on the row ∈ node-local trusted-owner anchor, signature
|
|
898
|
+
* verified) lands with the `membership-node-local-owner-anchor` /
|
|
899
|
+
* `membership-authorized-predicate-and-gates` tickets; keeping the filter in this one
|
|
900
|
+
* method means that change touches a single place.
|
|
901
|
+
*/
|
|
902
|
+
listAuthorizedMembers(): Promise<Array<{
|
|
903
|
+
peerId: string;
|
|
904
|
+
multiaddr: string | null;
|
|
905
|
+
}>>;
|
|
906
|
+
/**
|
|
907
|
+
* Probe whether a given peer is an AUTHORIZED party member (see
|
|
908
|
+
* {@link listAuthorizedMembers}) — the gate the control-network wake and
|
|
909
|
+
* strand-address responders consult, NOT {@link isMember} (the addressable surface).
|
|
910
|
+
*/
|
|
911
|
+
isAuthorizedMember(peerId: string): Promise<boolean>;
|
|
872
912
|
/**
|
|
873
913
|
* Push-wake a hibernating cadre peer over the control network.
|
|
874
914
|
*
|
|
@@ -887,8 +927,8 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
887
927
|
pushWake(targetPeerId: string, strandId: string, reason?: string): Promise<WakeAck>;
|
|
888
928
|
/**
|
|
889
929
|
* Enable the seed listener for receiving seeds via the /sereus/seed/1.0.0 protocol.
|
|
890
|
-
* This is for drone nodes that need to receive seeds without being an
|
|
891
|
-
* Does not require an
|
|
930
|
+
* This is for drone nodes that need to receive seeds without being an owner.
|
|
931
|
+
* Does not require an owner key.
|
|
892
932
|
*/
|
|
893
933
|
enableSeedListener(): void;
|
|
894
934
|
/**
|
|
@@ -897,7 +937,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
897
937
|
getSeedBootstrapService(): SeedBootstrapService | null;
|
|
898
938
|
/**
|
|
899
939
|
* Authorize a new peer to join the cadre.
|
|
900
|
-
* Signs the peer ID with the
|
|
940
|
+
* Signs the peer ID with the owner key and inserts into CadrePeer table.
|
|
901
941
|
*
|
|
902
942
|
* @param peerId - The peer ID to authorize
|
|
903
943
|
* @param multiaddrs - Optional multiaddrs for the peer
|
|
@@ -905,14 +945,14 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
905
945
|
authorizePeer(peerId: string, multiaddrs?: string[]): Promise<void>;
|
|
906
946
|
/**
|
|
907
947
|
* Remove a previously-authorized peer from the cadre.
|
|
908
|
-
* Signs the peer ID with the
|
|
948
|
+
* Signs the peer ID with the owner key and deletes the CadrePeer row.
|
|
909
949
|
*
|
|
910
950
|
* @param peerId - The peer ID to remove
|
|
911
951
|
*/
|
|
912
952
|
removePeer(peerId: string): Promise<void>;
|
|
913
953
|
/**
|
|
914
954
|
* Create a seed from the current control network state.
|
|
915
|
-
* The seed contains peer information and is signed by an
|
|
955
|
+
* The seed contains peer information and is signed by an owner.
|
|
916
956
|
*/
|
|
917
957
|
createSeed(): Promise<ControlNetworkSeed>;
|
|
918
958
|
/**
|
|
@@ -921,7 +961,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
921
961
|
* Validates the seed signature, then evaluates a trust anchor for the signer
|
|
922
962
|
* key (see `SeedTrustPolicy`). An enrollment caller can pass a per-seed
|
|
923
963
|
* `trustPolicy` override — e.g. a `pinnedKeyTrustPolicy` built from a
|
|
924
|
-
* `CadreInvite.
|
|
964
|
+
* `CadreInvite.ownerKeys` — so a cold-start node can accept its first
|
|
925
965
|
* seed without reconfiguring the service.
|
|
926
966
|
*/
|
|
927
967
|
applySeed(seed: ControlNetworkSeed, options?: {
|
|
@@ -976,7 +1016,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
976
1016
|
*/
|
|
977
1017
|
decodeInvite(encoded: string): CadreInvite;
|
|
978
1018
|
/**
|
|
979
|
-
* Dial an
|
|
1019
|
+
* Dial an owner from an invite (for phone joining via invite).
|
|
980
1020
|
*/
|
|
981
1021
|
dialInvite(invite: CadreInvite): Promise<void>;
|
|
982
1022
|
/**
|