@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.
Files changed (93) hide show
  1. package/README.md +2 -2
  2. package/dist/cadre-node.d.ts +101 -61
  3. package/dist/cadre-node.js +165 -124
  4. package/dist/cadre-node.js.map +1 -1
  5. package/dist/control-cohort.d.ts +15 -15
  6. package/dist/control-cohort.js +14 -14
  7. package/dist/control-cohort.js.map +1 -1
  8. package/dist/control-database.d.ts +51 -34
  9. package/dist/control-database.js +72 -56
  10. package/dist/control-database.js.map +1 -1
  11. package/dist/control-formation-recorder.d.ts +2 -2
  12. package/dist/control-formation-recorder.js +2 -2
  13. package/dist/control-schema.d.ts +1 -1
  14. package/dist/control-schema.js +57 -33
  15. package/dist/control-schema.js.map +1 -1
  16. package/dist/device-token.d.ts +1 -1
  17. package/dist/device-token.js +1 -1
  18. package/dist/{authority-key.d.ts → ed25519-key.d.ts} +11 -10
  19. package/dist/{authority-key.js → ed25519-key.js} +9 -10
  20. package/dist/ed25519-key.js.map +1 -0
  21. package/dist/index.d.ts +3 -3
  22. package/dist/index.js +8 -8
  23. package/dist/index.js.map +1 -1
  24. package/dist/key-store.d.ts +1 -1
  25. package/dist/key-store.js +1 -1
  26. package/dist/peer-authorization.d.ts +28 -6
  27. package/dist/peer-authorization.js +33 -7
  28. package/dist/peer-authorization.js.map +1 -1
  29. package/dist/peer-record.d.ts +3 -3
  30. package/dist/peer-record.js +3 -3
  31. package/dist/push-node.d.ts +38 -0
  32. package/dist/push-node.js +48 -0
  33. package/dist/push-node.js.map +1 -0
  34. package/dist/push-notifier-apns.d.ts +10 -2
  35. package/dist/push-notifier-apns.js +14 -10
  36. package/dist/push-notifier-apns.js.map +1 -1
  37. package/dist/push-notifier-fcm.d.ts +7 -1
  38. package/dist/push-notifier-fcm.js +9 -10
  39. package/dist/push-notifier-fcm.js.map +1 -1
  40. package/dist/push-notifier.d.ts +16 -35
  41. package/dist/push-notifier.js +16 -44
  42. package/dist/push-notifier.js.map +1 -1
  43. package/dist/seed-bootstrap.d.ts +70 -51
  44. package/dist/seed-bootstrap.js +168 -106
  45. package/dist/seed-bootstrap.js.map +1 -1
  46. package/dist/seed-trust-policy.d.ts +11 -11
  47. package/dist/seed-trust-policy.js +11 -11
  48. package/dist/seed-trust-policy.js.map +1 -1
  49. package/dist/strand-database.d.ts +5 -5
  50. package/dist/strand-database.js +4 -4
  51. package/dist/strand-database.js.map +1 -1
  52. package/dist/strand-formation-protocol.d.ts +1 -1
  53. package/dist/strand-formation-protocol.js +1 -1
  54. package/dist/strand-instance-manager.d.ts +1 -1
  55. package/dist/strand-instance-manager.js +1 -1
  56. package/dist/strand-instance-manager.js.map +1 -1
  57. package/dist/strand-member-key.d.ts +6 -6
  58. package/dist/strand-member-key.js +6 -6
  59. package/dist/strand-member-key.js.map +1 -1
  60. package/dist/strand-member-registry.d.ts +7 -7
  61. package/dist/strand-member-registry.js +5 -5
  62. package/dist/strand-member-registry.js.map +1 -1
  63. package/dist/strand-membership-writer.d.ts +84 -84
  64. package/dist/strand-membership-writer.js +90 -90
  65. package/dist/strand-membership-writer.js.map +1 -1
  66. package/dist/types.d.ts +52 -32
  67. package/dist/types.js.map +1 -1
  68. package/package.json +7 -3
  69. package/src/cadre-node.ts +170 -126
  70. package/src/control-cohort.ts +17 -17
  71. package/src/control-database.ts +76 -59
  72. package/src/control-formation-recorder.ts +2 -2
  73. package/src/control-schema.ts +57 -33
  74. package/src/device-token.ts +1 -1
  75. package/src/{authority-key.ts → ed25519-key.ts} +12 -11
  76. package/src/index.ts +21 -19
  77. package/src/key-store.ts +1 -1
  78. package/src/peer-authorization.ts +35 -7
  79. package/src/peer-record.ts +3 -3
  80. package/src/push-node.ts +64 -0
  81. package/src/push-notifier-apns.ts +16 -12
  82. package/src/push-notifier-fcm.ts +9 -10
  83. package/src/push-notifier.ts +16 -57
  84. package/src/seed-bootstrap.ts +179 -115
  85. package/src/seed-trust-policy.ts +18 -18
  86. package/src/strand-database.ts +6 -6
  87. package/src/strand-formation-protocol.ts +1 -1
  88. package/src/strand-instance-manager.ts +2 -2
  89. package/src/strand-member-key.ts +7 -7
  90. package/src/strand-member-registry.ts +10 -10
  91. package/src/strand-membership-writer.ts +127 -127
  92. package/src/types.ts +52 -32
  93. package/dist/authority-key.js.map +0 -1
@@ -18,10 +18,10 @@ export declare function decodeLengthPrefixedFrame(data: Uint8Array, maxLength?:
18
18
  *
19
19
  * An Ed25519 PeerId is an identity multihash of the public key, so
20
20
  * `peerIdFromString(id).publicKey.raw` is the 32-byte ed25519 key whose
21
- * base64url form matches the `AuthorityKey.Key` representation (and
22
- * `authorityKeyFromLibp2p().publicKeyB64`). Returns null for a non-Ed25519
21
+ * base64url form matches the `OwnerKey.Key` representation (and
22
+ * `ed25519KeyPairFromLibp2p().publicKeyB64`). Returns null for a non-Ed25519
23
23
  * id, a missing embedded key, or any parse failure — callers treat null as
24
- * "not an authority" rather than throwing.
24
+ * "not an owner" rather than throwing.
25
25
  */
26
26
  export declare function ed25519PublicKeyB64FromPeerId(peerId: string): string | null;
27
27
  /**
@@ -40,10 +40,10 @@ export declare function canonicalSeedPayload(seed: Pick<ControlNetworkSeed, 'par
40
40
  export interface SeedBootstrapConfig {
41
41
  /** Party ID for this cadre */
42
42
  partyId: string;
43
- /** Authority private key for signing seeds and peer authorizations (base64url) */
44
- authorityPrivateKey?: string;
45
- /** Authority public key (base64url) - derived from private key if not provided */
46
- authorityPublicKey?: string;
43
+ /** Owner private key for signing seeds and peer authorizations (base64url) */
44
+ ownerPrivateKey?: string;
45
+ /** Owner public key (base64url) - derived from private key if not provided */
46
+ ownerPublicKey?: string;
47
47
  /**
48
48
  * Optional async resolver returning the multiaddrs to embed in invites.
49
49
  * When unset, `libp2pNode.getMultiaddrs()` is used. Hosts behind NAT supply
@@ -53,9 +53,9 @@ export interface SeedBootstrapConfig {
53
53
  inviteAddressResolver?: () => Promise<string[]>;
54
54
  /**
55
55
  * Trust anchor for incoming seeds. Decides whether a signature-verified
56
- * `signerKey` should be trusted, against the receiver's known authority
56
+ * `signerKey` should be trusted, against the receiver's known owner
57
57
  * keys (NOT the seed body). Defaults to `dbAnchoredTrustPolicy()`, which
58
- * rejects any signer not already in the `AuthorityKey` table. An enrollment
58
+ * rejects any signer not already in the `OwnerKey` table. An enrollment
59
59
  * caller can pass a per-seed override to `applySeed` instead.
60
60
  *
61
61
  * A `CadreNode` forwards its node-wide `CadreNodeConfig.seedTrustPolicy` here
@@ -98,7 +98,7 @@ export declare class SeedBootstrapService {
98
98
  private readonly config;
99
99
  private libp2pNode;
100
100
  private controlDatabase;
101
- private readonly authorityPublicKey;
101
+ private readonly ownerPublicKey;
102
102
  private readonly trustPolicy;
103
103
  private readonly seedReadTimeoutMs;
104
104
  private readonly maxConcurrentSeeds;
@@ -112,12 +112,12 @@ export declare class SeedBootstrapService {
112
112
  */
113
113
  setEventCallbacks(callbacks: SeedEventCallbacks): void;
114
114
  /**
115
- * Whether this service holds an authority private key, i.e. can produce the
116
- * authority signatures that gate `CadrePeer` / `DeviceToken` inserts, deletes,
115
+ * Whether this service holds an owner private key, i.e. can produce the
116
+ * owner signatures that gate `CadrePeer` / `DeviceToken` inserts, deletes,
117
117
  * and re-authorizations. A seed-listener-only service (`enableSeedListener`,
118
- * no authority key) returns false: it can receive/apply seeds but cannot author
119
- * or re-issue authority writes. Used by the write-while-alone re-replication
120
- * drain to skip authority work on a non-authority node.
118
+ * no owner key) returns false: it can receive/apply seeds but cannot author
119
+ * or re-issue owner writes. Used by the write-while-alone re-replication
120
+ * drain to skip owner work on a non-owner node.
121
121
  */
122
122
  canAuthorize(): boolean;
123
123
  /**
@@ -137,73 +137,92 @@ export declare class SeedBootstrapService {
137
137
  }): void;
138
138
  /**
139
139
  * Authorize a new peer to join the cadre.
140
- * Signs the peer ID with the authority key and inserts into CadrePeer table.
140
+ * Signs the peer ID with the owner key and inserts into CadrePeer table.
141
141
  *
142
- * The authority vouches the `PublicKey <-> PeerId` binding: rather than trust a
142
+ * The owner vouches the `PublicKey <-> PeerId` binding: rather than trust a
143
143
  * caller-supplied key, the binding is enforced by construction — `PublicKey` is
144
144
  * DERIVED from the (Ed25519) `peerId`. A non-Ed25519 peer id yields a null
145
145
  * `PublicKey`, and such a row can never be self-updated (it has no key to
146
146
  * verify against), which is correct. The row is inserted with a fresh
147
- * `UpdatedAt` but no self-signature (`Sig` null) — the authority cannot produce
147
+ * `UpdatedAt` but no self-signature (`Sig` null) — the owner cannot produce
148
148
  * the peer's self-signature, so the peer must self-publish (see
149
149
  * {@link CadreNode.registerSelf}) before the row resolves.
150
150
  */
151
151
  authorizePeer(options: AuthorizePeerOptions): Promise<void>;
152
152
  /**
153
- * Authority-signed INSERT of this node's OWN self-signed address record.
153
+ * Owner-signed INSERT of this node's OWN self-signed address record.
154
154
  *
155
155
  * Used by {@link CadreNode.registerSelf} when the node is not yet a member and
156
- * is its own authority (it holds the authority key): the row is authority-signed
156
+ * is its own owner (it holds the owner key): the row is owner-signed
157
157
  * (satisfying `AuthorizedInsert`) AND carries a valid self-`Sig`, so it resolves
158
158
  * immediately without a follow-up self-update.
159
159
  */
160
160
  insertSelfPeerRecord(record: PeerAddressRecord): Promise<void>;
161
161
  /**
162
- * Shared authority-signed `CadrePeer` INSERT. Signs `digest(peerId)` with the
163
- * authority key (satisfying `AuthorizedInsert`) and writes the full record
164
- * row. The authority signature does NOT cover the address columns — those are
165
- * vouched only as far as the authority asserts them, and a peer's own `Sig`
166
- * (when present) is what makes the row resolvable.
162
+ * Shared owner-signed `CadrePeer` INSERT. Mints a fresh single-use `StampId`
163
+ * and signs the voucher digest `digest(peerId, stampId)` ({@link cadrePeerVoucherDigest})
164
+ * with the owner key (satisfying `AuthorizedInsert`), then writes the full record
165
+ * row with the vouching (owner, signature) persisted into VouchOwner/VouchSig.
166
+ * The owner signature does NOT cover the address columns — those are vouched only
167
+ * as far as the owner asserts them, and a peer's own `Sig` (when present) is what
168
+ * makes the row resolvable.
167
169
  */
168
170
  private insertCadrePeerRow;
169
171
  /**
170
- * Authority-signed INSERT of a peer's OWN self-signed `DeviceToken` row.
172
+ * Owner-signed INSERT of a peer's OWN self-signed `DeviceToken` row.
171
173
  *
172
174
  * Counterpart to {@link insertSelfPeerRecord} for the device-token registry: the
173
- * row is authority-signed (satisfying `DeviceToken.AuthorizedInsert`, which vouches
175
+ * row is owner-signed (satisfying `DeviceToken.AuthorizedInsert`, which vouches
174
176
  * membership exactly as `CadrePeer.AuthorizedInsert` does) AND carries the peer's
175
- * own self-`Sig` over the token payload. The authority signature covers only the
177
+ * own self-`Sig` over the token payload. The owner signature covers only the
176
178
  * PeerId — it does NOT vouch the token contents; the peer's `Sig` (verified at
177
179
  * resolve time against the bound `CadrePeer.PublicKey`) is what makes the row
178
180
  * resolvable. Used by {@link CadreNode.registerDeviceToken} for the first publish
179
- * when the node is its own authority.
181
+ * when the node is its own owner.
180
182
  */
181
183
  insertSelfDeviceToken(record: DeviceTokenRecord): Promise<void>;
182
184
  /**
183
- * Authority-signed DELETE of a peer's `DeviceToken` row (logout / token
185
+ * Owner-signed DELETE of a peer's `DeviceToken` row (logout / token
184
186
  * invalidation). The `DeviceToken.AuthorizedInsert` constraint gates both insert
185
- * AND delete on an authority signature over `digest(old.PeerId)`, so — like
186
- * {@link removePeer} for `CadrePeer` — clearing a token requires the authority key.
187
+ * AND delete on an owner signature over `digest(old.PeerId)`, so — like
188
+ * {@link removePeer} for `CadrePeer` — clearing a token requires the owner key.
187
189
  */
188
190
  deleteDeviceToken(peerId: string): Promise<void>;
189
191
  /**
190
- * Sign a peer ID with the authority key for a `CadrePeer` / `DeviceToken`
192
+ * Sign a peer ID with the owner key for a `CadrePeer` / `DeviceToken`
191
193
  * insert-or-delete. The signed bytes come from the shared
192
194
  * {@link peerAuthorizationDigest} helper so the offline `cadre enroll register`
193
- * verifier checks the exact same construction. Throws if no authority key is set.
195
+ * verifier checks the exact same construction. Throws if no owner key is set.
194
196
  */
195
197
  private signPeerAuthorization;
196
198
  /**
197
- * Remove a peer from the cadre by authority signature.
199
+ * Return the configured owner private key, or throw if none is set. The single
200
+ * precondition gate for every owner-signed write. {@link removePeer} /
201
+ * {@link reauthorizePeer} read the row's `StampId` from the DB BEFORE they sign, so
202
+ * they call this up front — otherwise a keyless service would either surface the
203
+ * wrong "Control database not initialized" error or, worse, silently no-op when the
204
+ * target row is absent (the early `stampId === null` return) instead of rejecting.
205
+ */
206
+ private requireOwnerPrivateKey;
207
+ /**
208
+ * Sign a base64url digest with the owner key (ed25519). The single place the
209
+ * owner private key is applied; callers pass the canonical digest for the specific
210
+ * action ({@link cadrePeerVoucherDigest} / {@link cadrePeerRemoveDigest} /
211
+ * {@link peerAuthorizationDigest}). Throws if no owner key is set.
212
+ */
213
+ private signDigest;
214
+ /**
215
+ * Remove a peer from the cadre by owner signature.
198
216
  *
199
- * The constraint over CadrePeer's `check on insert, delete` validates a
200
- * signature over `digest(old.PeerId)` by an authority key. We use the same
201
- * digest pattern as authorizePeer.
217
+ * The `CadrePeer.AuthorizedDelete` (`check on delete`) constraint validates a
218
+ * signature over the DISTINCT 'remove'-scoped digest `digest(old.PeerId, old.StampId,
219
+ * 'remove')` ({@link cadrePeerRemoveDigest}) by an owner key — deliberately NOT the
220
+ * insert voucher digest, so the row's stored `VouchSig` can never be replayed to delete.
202
221
  */
203
222
  removePeer(peerId: string): Promise<void>;
204
223
  /**
205
- * Authority "re-touch" of an existing `CadrePeer` membership row: bump
206
- * `UpdatedAt` under the authority branch of `CadrePeer.AuthorizedUpdate` (a
224
+ * Owner "re-touch" of an existing `CadrePeer` membership row: bump
225
+ * `UpdatedAt` under the owner branch of `CadrePeer.AuthorizedUpdate` (a
207
226
  * signature over `digest(peerId)` — the same construction {@link authorizePeer}
208
227
  * uses) so the row is re-emitted as a fresh, broadcasting transaction.
209
228
  *
@@ -220,13 +239,13 @@ export declare class SeedBootstrapService {
220
239
  *
221
240
  * @param peerId - the membership row to re-touch.
222
241
  * @param updatedAt - the strictly-increasing freshness stamp to write.
223
- * @throws if no authority private key is configured (a non-authority cannot
242
+ * @throws if no owner private key is configured (a non-owner cannot
224
243
  * re-sign another peer's row) or the control database is not initialized.
225
244
  */
226
245
  reauthorizePeer(peerId: string, updatedAt: number): Promise<void>;
227
246
  /**
228
247
  * Create a seed from the current control network state.
229
- * The seed contains peer information and is signed by an authority.
248
+ * The seed contains peer information and is signed by an owner.
230
249
  */
231
250
  createSeed(): Promise<ControlNetworkSeed>;
232
251
  /**
@@ -234,9 +253,9 @@ export declare class SeedBootstrapService {
234
253
  *
235
254
  * Validates the seed signature, then evaluates a trust anchor for the
236
255
  * `signerKey` that does NOT come from the seed body: the receiver's
237
- * `AuthorityKey` table (DB-anchored), optionally augmented by pinned keys or
256
+ * `OwnerKey` table (DB-anchored), optionally augmented by pinned keys or
238
257
  * TOFU via the configured/overriding `SeedTrustPolicy`. A forged
239
- * self-asserting seed — one that merely lists its own signer as an authority
258
+ * self-asserting seed — one that merely lists its own signer as an owner
240
259
  * peer — no longer passes.
241
260
  *
242
261
  * @param seed - The seed to apply (already transport-decoded).
@@ -271,12 +290,12 @@ export declare class SeedBootstrapService {
271
290
  /**
272
291
  * Query peers from the control database.
273
292
  *
274
- * Authority identity is sourced from the `AuthorityKey` table, not from the
293
+ * Owner identity is sourced from the `OwnerKey` table, not from the
275
294
  * transport peer ID. An Ed25519 libp2p PeerId embeds its public key (identity
276
295
  * multihash), so each peer's ed25519 key is derivable from its `PeerId`; a
277
- * peer is an authority iff that derived key is in the `AuthorityKey` set.
278
- * This makes any authority node markable — not just the local one — and ties
279
- * `isAuthority` to the control table rather than to `peerId === self`.
296
+ * peer is an owner iff that derived key is in the `OwnerKey` set.
297
+ * This makes any owner node markable — not just the local one — and ties
298
+ * `isOwner` to the control table rather than to `peerId === self`.
280
299
  */
281
300
  private queryPeers;
282
301
  /**
@@ -357,11 +376,11 @@ export declare class SeedBootstrapService {
357
376
  */
358
377
  decodeInvite(encoded: string): CadreInvite;
359
378
  /**
360
- * Dial an authority from an invite.
361
- * Use this on a phone after receiving an invite to connect to the authority.
379
+ * Dial an owner from an invite.
380
+ * Use this on a phone after receiving an invite to connect to the owner.
362
381
  *
363
382
  * @param invite - The invite received out-of-band
364
- * @returns Connection to the authority
383
+ * @returns Connection to the owner
365
384
  */
366
385
  dialInvite(invite: CadreInvite): Promise<void>;
367
386
  }