@serfab/cadre-core 1.13.0 → 1.14.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 (120) hide show
  1. package/dist/cadre-invite-protocol.d.ts +348 -0
  2. package/dist/cadre-invite-protocol.js +605 -0
  3. package/dist/cadre-invite-protocol.js.map +1 -0
  4. package/dist/cadre-node.d.ts +523 -180
  5. package/dist/cadre-node.js +921 -293
  6. package/dist/cadre-node.js.map +1 -1
  7. package/dist/claim-proof.d.ts +45 -0
  8. package/dist/claim-proof.js +132 -0
  9. package/dist/claim-proof.js.map +1 -0
  10. package/dist/control-authorization.d.ts +80 -19
  11. package/dist/control-authorization.js +55 -13
  12. package/dist/control-authorization.js.map +1 -1
  13. package/dist/control-cohort.js +1 -1
  14. package/dist/control-cohort.js.map +1 -1
  15. package/dist/control-database.d.ts +514 -97
  16. package/dist/control-database.js +1033 -195
  17. package/dist/control-database.js.map +1 -1
  18. package/dist/control-protocol-guard.d.ts +142 -0
  19. package/dist/control-protocol-guard.js +293 -0
  20. package/dist/control-protocol-guard.js.map +1 -0
  21. package/dist/control-schema.d.ts +1 -1
  22. package/dist/control-schema.js +801 -1067
  23. package/dist/control-schema.js.map +1 -1
  24. package/dist/control-stream.d.ts +4 -0
  25. package/dist/control-stream.js +22 -7
  26. package/dist/control-stream.js.map +1 -1
  27. package/dist/delegate-admission.d.ts +1 -1
  28. package/dist/delegate-admission.js +1 -1
  29. package/dist/device-token.d.ts +11 -9
  30. package/dist/device-token.js +14 -12
  31. package/dist/device-token.js.map +1 -1
  32. package/dist/ed25519-key.d.ts +15 -0
  33. package/dist/ed25519-key.js +28 -1
  34. package/dist/ed25519-key.js.map +1 -1
  35. package/dist/index.d.ts +14 -9
  36. package/dist/index.js +27 -9
  37. package/dist/index.js.map +1 -1
  38. package/dist/link-budget.d.ts +16 -29
  39. package/dist/link-budget.js +16 -31
  40. package/dist/link-budget.js.map +1 -1
  41. package/dist/membership-connection-gater.d.ts +190 -151
  42. package/dist/membership-connection-gater.js +235 -173
  43. package/dist/membership-connection-gater.js.map +1 -1
  44. package/dist/node-claim-payload.d.ts +19 -0
  45. package/dist/node-claim-payload.js +120 -0
  46. package/dist/node-claim-payload.js.map +1 -0
  47. package/dist/owner-anchor-sync.d.ts +22 -0
  48. package/dist/owner-anchor-sync.js +143 -0
  49. package/dist/owner-anchor-sync.js.map +1 -0
  50. package/dist/peer-authorization.d.ts +113 -18
  51. package/dist/peer-authorization.js +225 -29
  52. package/dist/peer-authorization.js.map +1 -1
  53. package/dist/peer-dial.d.ts +19 -0
  54. package/dist/peer-dial.js +22 -1
  55. package/dist/peer-dial.js.map +1 -1
  56. package/dist/peer-join-backfill.d.ts +26 -2
  57. package/dist/peer-join-backfill.js +54 -12
  58. package/dist/peer-join-backfill.js.map +1 -1
  59. package/dist/peer-record.d.ts +13 -9
  60. package/dist/peer-record.js +16 -12
  61. package/dist/peer-record.js.map +1 -1
  62. package/dist/pending-join-runner.d.ts +66 -58
  63. package/dist/pending-join-runner.js +136 -145
  64. package/dist/pending-join-runner.js.map +1 -1
  65. package/dist/push-fanout.d.ts +8 -2
  66. package/dist/push-fanout.js +8 -2
  67. package/dist/push-fanout.js.map +1 -1
  68. package/dist/seed-bootstrap.d.ts +147 -122
  69. package/dist/seed-bootstrap.js +284 -269
  70. package/dist/seed-bootstrap.js.map +1 -1
  71. package/dist/seed-trust-policy.d.ts +98 -37
  72. package/dist/seed-trust-policy.js +188 -2
  73. package/dist/seed-trust-policy.js.map +1 -1
  74. package/dist/strand-addr-protocol.d.ts +24 -26
  75. package/dist/strand-addr-protocol.js +19 -26
  76. package/dist/strand-addr-protocol.js.map +1 -1
  77. package/dist/strand-formation-protocol.js +1 -1
  78. package/dist/strand-formation-protocol.js.map +1 -1
  79. package/dist/strand-revocation-enforcer.d.ts +11 -11
  80. package/dist/strand-revocation-enforcer.js +11 -11
  81. package/dist/strand-wake-protocol.d.ts +13 -16
  82. package/dist/strand-wake-protocol.js +13 -20
  83. package/dist/strand-wake-protocol.js.map +1 -1
  84. package/dist/trusted-owner-store.d.ts +35 -5
  85. package/dist/trusted-owner-store.js +50 -8
  86. package/dist/trusted-owner-store.js.map +1 -1
  87. package/dist/types.d.ts +302 -87
  88. package/dist/types.js.map +1 -1
  89. package/package.json +8 -7
  90. package/src/cadre-invite-protocol.ts +864 -0
  91. package/src/cadre-node.ts +9381 -8686
  92. package/src/claim-proof.ts +147 -0
  93. package/src/control-authorization.ts +203 -117
  94. package/src/control-cohort.ts +1 -1
  95. package/src/control-database.ts +1216 -218
  96. package/src/control-protocol-guard.ts +348 -0
  97. package/src/control-schema.ts +812 -1078
  98. package/src/control-stream.ts +26 -7
  99. package/src/delegate-admission.ts +1 -1
  100. package/src/device-token.ts +14 -10
  101. package/src/ed25519-key.ts +28 -1
  102. package/src/index.ts +84 -10
  103. package/src/link-budget.ts +16 -32
  104. package/src/membership-connection-gater.ts +637 -570
  105. package/src/node-claim-payload.ts +125 -0
  106. package/src/owner-anchor-sync.ts +171 -0
  107. package/src/peer-authorization.ts +258 -29
  108. package/src/peer-dial.ts +22 -1
  109. package/src/peer-join-backfill.ts +56 -11
  110. package/src/peer-record.ts +16 -11
  111. package/src/pending-join-runner.ts +729 -735
  112. package/src/push-fanout.ts +8 -2
  113. package/src/seed-bootstrap.ts +344 -321
  114. package/src/seed-trust-policy.ts +353 -140
  115. package/src/strand-addr-protocol.ts +26 -35
  116. package/src/strand-formation-protocol.ts +1 -1
  117. package/src/strand-revocation-enforcer.ts +11 -11
  118. package/src/strand-wake-protocol.ts +13 -23
  119. package/src/trusted-owner-store.ts +242 -171
  120. package/src/types.ts +2471 -2242
package/dist/types.d.ts CHANGED
@@ -16,7 +16,8 @@ import type { StrandNetworkStateStore } from './strand-network-state.js';
16
16
  import type { EnrolledMachineStore } from './enrolled-machine-store.js';
17
17
  import type { JoinedStrandStore } from './joined-strand-store.js';
18
18
  import type { PushNotifier } from './push-notifier.js';
19
- import type { RevocableTable } from './control-authorization.js';
19
+ import type { CadreInviteSignedFields, RevocableTable } from './control-authorization.js';
20
+ import type { CadreInvitation } from './cadre-invite-protocol.js';
20
21
  import type { ControlRetryAbandonment } from './control-retry.js';
21
22
  import type { FormationRejectionCode } from './strand-formation-rejection.js';
22
23
  /**
@@ -534,7 +535,7 @@ export interface NetworkConfig {
534
535
  /**
535
536
  * Limit on dialing ONE peer — all of its candidate addresses together — in
536
537
  * ms. Bounds a reconcile pass at (dialed siblings) × this. The same limit
537
- * applies to the owner dials of `applySeed` and to `dialInvite`. Defaults to
538
+ * applies to the owner dials of `applySeed`. Defaults to
538
539
  * {@link DEFAULT_CONTROL_COHORT_DIAL_TIMEOUT_MS}.
539
540
  */
540
541
  dialTimeoutMs?: number;
@@ -777,7 +778,7 @@ export interface CadreNodeConfig {
777
778
  * should enable it, because a node without it neither announces nor serves as part of the
778
779
  * group a notification is rooted at. Enabling registers Optimystic's change-notification
779
780
  * protocol handlers on the strand node, which the closed-strand per-stream gate does not
780
- * cover, and each watched table pays a cold-start proof of work on every node build. Both
781
+ * cover, and each watched table registers again on every node build. Both
781
782
  * are spelled out in `docs/strands.md` → "Change notifications (reactivity)". The control
782
783
  * node never gets it.
783
784
  */
@@ -860,9 +861,43 @@ export interface CadreNodeConfig {
860
861
  * inside SeedBootstrapService when unset — a node whose node-local trusted-owner
861
862
  * anchor was never seeded then rejects every seed. A per-call
862
863
  * `applySeed(seed, { trustPolicy })` override still wins over this default for
863
- * callers that hold out-of-band material (e.g. a pinned key from a CadreInvite).
864
+ * callers that hold out-of-band material (e.g. an operator-pinned owner key).
864
865
  */
865
866
  seedTrustPolicy?: SeedTrustPolicy;
867
+ /**
868
+ * Start this node waiting to be CLAIMED: it belongs to nobody until someone delivers
869
+ * a seed carrying a proof of this one-time secret (`claim-proof.ts`,
870
+ * `claimSecretTrustPolicy`), and that signer becomes its anchored owner. The node
871
+ * turns its seed listener on itself and, while unclaimed, lets a stranger do nothing
872
+ * but deliver a seed: connections are admitted, control-database streams and relay
873
+ * reservations are refused (`CadreNode.isAwaitingClaim`).
874
+ *
875
+ * A node has exactly one cold-start trust source, so `claim` beside a non-empty
876
+ * `trustedOwners.pinnedKeys` or a `seedTrustPolicy` fails `start()` closed, and
877
+ * `initializeSeedBootstrap` (an owner key) refuses on such a node: a hosted node never
878
+ * holds an owner key. A claimed node restarted with this still set ignores it (its
879
+ * anchor is non-empty), so the operator need not remove it.
880
+ *
881
+ * The claim also decides which party the node serves: `controlNetwork.partyId` on an
882
+ * unclaimed node is a placeholder, and the real party is the claim seed's. The node
883
+ * itself keeps serving the placeholder for the rest of the process — everything it
884
+ * holds is keyed on the party it started with — so `record` is where the embedder
885
+ * learns the claimed party, and it is the embedder's job to restart into it.
886
+ */
887
+ claim?: {
888
+ /** The one-time claim secret, base64url of 32 bytes. Never written to replicated state or logs. */
889
+ secret: string;
890
+ /**
891
+ * Record the claim durably: called with the seed's party and the claimant's key after
892
+ * the proof verifies and BEFORE the claimant is anchored, and awaited. A rejection
893
+ * refuses the claim `claim-not-persisted` with nothing anchored, so the claimant
894
+ * retries. Record first, anchor second: a crash between the two leaves a record and
895
+ * an empty anchor, and an embedder that starts from its record (cadre-cli does)
896
+ * then comes up claimed by that owner, who is accepted idempotently when it retries.
897
+ * The other order would leave an anchored node with no record of its party.
898
+ */
899
+ record: (claim: NodeClaimRecord) => Promise<void>;
900
+ };
866
901
  /**
867
902
  * Node-local trusted-owner anchor (see `trusted-owner-store.ts`): the
868
903
  * NON-replicated, per-party record of owner keys established out of band —
@@ -883,16 +918,18 @@ export interface CadreNodeConfig {
883
918
  /**
884
919
  * Owner keys (base64url ed25519) established out of band and seeded into
885
920
  * the store during start(): operator pins (e.g. cadre-cli
886
- * `--pin-owner-key` / `CADRE_OWNER_KEYS`) or a `CadreInvite.ownerKeys`
887
- * already known at config time. Seeding is idempotent across restarts.
921
+ * `--pin-owner-key` / `CADRE_OWNER_KEYS`). A cadre invitation's `ownerKeys`
922
+ * are pinned at redemption instead (`CadreNode.redeemCadreInvitation`).
923
+ * Seeding is idempotent across restarts.
888
924
  */
889
925
  pinnedKeys?: string[];
890
926
  /**
891
927
  * Provenance recorded for {@link pinnedKeys}. Default: 'operator'.
892
928
  * ('genesis' is reserved for the node's own founding key, seeded
893
- * internally by `initializeSeedBootstrap`.)
929
+ * internally by `initializeSeedBootstrap`; 'chain' is written only by the
930
+ * anchor sync, `CadreNode.syncOwnerAnchor`.)
894
931
  */
895
- pinnedSource?: Exclude<TrustSource, 'genesis'>;
932
+ pinnedSource?: Exclude<TrustSource, 'genesis' | 'chain'>;
896
933
  };
897
934
  /**
898
935
  * Node-local cold-start bootstrap-peer store (see `bootstrap-peer-store.ts`):
@@ -1124,13 +1161,11 @@ export interface StrandRow {
1124
1161
  FounderOwnerKey: string | null;
1125
1162
  }
1126
1163
  /**
1127
- * A `CadreControl.PendingJoin` row: a join this party asked for through another party's
1128
- * invitation, readable by every machine of the party. Each outcome carries only its own
1129
- * columns (the schema's `OutcomeShape` check): `'joined'` sets `StrandId` (and, for a
1130
- * closed strand, `MembershipInvite`), `'failed'` sets `FailureCode`, and a pending row
1131
- * (`Outcome: null`) sets neither.
1164
+ * A `CadreControl.JoinRequest` row: a join this party asked for through another party's
1165
+ * invitation, readable by every machine of the party. The row never changes; its outcome is
1166
+ * a `JoinSuccess` or `JoinFailure` row keyed by `StampId` (see {@link PendingJoin}).
1132
1167
  */
1133
- export interface PendingJoinRow {
1168
+ export interface JoinRequestRow {
1134
1169
  /** base64url sha256 of the invitation token (`pendingJoinId`). */
1135
1170
  Id: string;
1136
1171
  /** `CadreNode.encodeInvitation` of the invitation. A bearer credential. */
@@ -1141,30 +1176,45 @@ export interface PendingJoinRow {
1141
1176
  RequestedAt: number;
1142
1177
  /** Epoch ms; no attempt starts at or after it. */
1143
1178
  ExpiresAt: number;
1144
- Outcome: null | 'joined' | 'failed';
1145
- /** Epoch ms the outcome was recorded; null while pending. */
1146
- OutcomeAt: number | null;
1147
- /** `'joined'`: the strand the formation returned. */
1148
- StrandId: string | null;
1149
- /** `'joined'`, closed strand: JSON of the {@link StrandMembershipInvite} the formation delivered. */
1150
- MembershipInvite: string | null;
1151
- /** `'failed'`: a `FormationRejectionCode`, `'expired'` or `'local'`. Not constrained by the schema. */
1152
- FailureCode: string | null;
1153
- /** `'failed'`: human-readable text. */
1154
- FailureReason: string | null;
1155
- /** Single-use nonce of this row incarnation; `ControlDatabase.replacePendingJoin` names it as the row it replaces. */
1179
+ /** Single-use nonce of this request incarnation; its outcome rows name it. */
1156
1180
  StampId: string;
1157
1181
  }
1182
+ /**
1183
+ * The outcome of a {@link JoinRequestRow}: a `CadreControl.JoinSuccess` row (`'joined'`) or
1184
+ * a `CadreControl.JoinFailure` row (`'failed'`), without the request stamp that keys it.
1185
+ */
1186
+ export type JoinOutcome = {
1187
+ kind: 'joined';
1188
+ /** Epoch ms the outcome was recorded. */
1189
+ RecordedAt: number;
1190
+ /** The strand the formation returned. */
1191
+ StrandId: string;
1192
+ /** Closed strand: JSON of the {@link StrandMembershipInvite} the formation delivered. */
1193
+ MembershipInvite: string | null;
1194
+ } | {
1195
+ kind: 'failed';
1196
+ /** Epoch ms the outcome was recorded. */
1197
+ RecordedAt: number;
1198
+ /** A `FormationRejectionCode`, `'expired'` or `'local'`. Not constrained by the schema. */
1199
+ Code: string;
1200
+ /** Human-readable text. */
1201
+ Reason: string;
1202
+ };
1203
+ /** A join request with its outcome, as `ControlDatabase.queryPendingJoins` reads the three tables. */
1204
+ export interface PendingJoin extends JoinRequestRow {
1205
+ /** Null while pending. */
1206
+ outcome: JoinOutcome | null;
1207
+ }
1158
1208
  /**
1159
1209
  * A join this party asked for through `CadreNode.requestJoin`, as one machine sees it.
1160
1210
  *
1161
- * `pending`, `joined` and `failed` come from the party-wide `PendingJoin` row and read the same
1211
+ * `pending`, `joined` and `failed` come from the party-wide join request and its outcome row and read the same
1162
1212
  * on every machine. `trying` (an attempt is running on this machine) and `waiting` (this
1163
1213
  * machine's last attempt failed in a way worth retrying) are this machine's own view of a
1164
1214
  * pending row, so two machines can report different states for it.
1165
1215
  */
1166
1216
  export interface PendingJoinStatus {
1167
- /** `PendingJoin.Id`: the sha256 of the invitation token. */
1217
+ /** `JoinRequest.Id`: the sha256 of the invitation token. */
1168
1218
  id: string;
1169
1219
  sAppId: string;
1170
1220
  /** Epoch ms. */
@@ -1377,7 +1427,7 @@ export interface StrandMembershipInvite {
1377
1427
  * whoever holds it can `consumeInvite` exactly once. Same sensitivity class and
1378
1428
  * handling as `memberPrivateKey` — delivered only inside the validated,
1379
1429
  * post-approval formation result. The inviting side never writes it to its control
1380
- * DB. The joining side may copy it into its own `PendingJoin` row
1430
+ * DB. The joining side may copy it into its own `JoinSuccess` row
1381
1431
  * (`MembershipInvite`), owner-signed and party-private like
1382
1432
  * `JoinedStrand.MemberPrivateKey`, so a join finished on one machine of the party
1383
1433
  * can be seated by whichever machine launches the strand first.
@@ -1627,6 +1677,18 @@ export interface CadreNodeEvents {
1627
1677
  partyId: string;
1628
1678
  error: string;
1629
1679
  };
1680
+ /**
1681
+ * Emitted once on a node started with `CadreNodeConfig.claim`, when a seed carrying a
1682
+ * valid claim proof has been recorded (`claim.record`) and has durably anchored its
1683
+ * signer as this node's owner. Carries the claim's party beside the owner key: the
1684
+ * party this node should serve from now on, which its own config did not know. Fires
1685
+ * BEFORE the seed is acknowledged to the claimant, its peers merged and its owners
1686
+ * dialed, so it precedes that seed's `seed:applied`; an embedder that restarts into
1687
+ * the claimed party on this event should wait for that `seed:applied` (or `seed:error`)
1688
+ * so the acknowledgement is not lost with the node. `CadreNode.isAwaitingClaim` is the
1689
+ * matching predicate for a reader that subscribed too late to see the event.
1690
+ */
1691
+ 'claim:accepted': NodeClaimRecord;
1630
1692
  }
1631
1693
  /**
1632
1694
  * A peer's self-published, freshness-stamped, self-signed address record.
@@ -1657,29 +1719,130 @@ export interface PeerAddressRecord {
1657
1719
  }
1658
1720
  /**
1659
1721
  * One `CadreControl.CadrePeer` row as read by `ControlDatabase.queryCadrePeers`:
1660
- * the addressing columns plus the persisted membership voucher.
1722
+ * the addressing columns plus the persisted membership proof.
1661
1723
  *
1662
- * The voucher triple (`stampId`, `vouchOwner`, `vouchSig`) is what
1724
+ * A row carries exactly one proof. An owner-vouched row has `vouchSig`, the owner's
1725
+ * signature over the row's (`peerId`, `stampId`), which
1663
1726
  * {@link CadreNode.listAuthorizedMembers} re-checks against the node-local
1664
- * trusted-owner anchor — it is null on a row written before the voucher columns
1665
- * existed, and all three must be present for the row to be authorizable. Named
1666
- * (rather than restated inline at each read site) so a future column addition
1667
- * cannot reach the query without the predicate seeing it.
1727
+ * trusted-owner anchor. An invitation-admitted row has `vouchSig` null and
1728
+ * `vouchUsage` naming the `CadreInviteUsage` row that admitted it; the reader
1729
+ * verifies the chain row → usage → invitation instead (`verifyInvitationAdmission`),
1730
+ * with `vouchOwner` the invitation's issuer. All columns are null on a row written
1731
+ * before they existed, and such a row is never authorizable. Named (rather than
1732
+ * restated inline at each read site) so a future column addition cannot reach the
1733
+ * query without the predicate seeing it.
1668
1734
  */
1669
1735
  export interface CadrePeerRow {
1670
1736
  /** libp2p peer ID (base58btc) — the row key. */
1671
1737
  peerId: string;
1672
1738
  /** Comma-joined dialable multiaddrs as stored, or null when unpublished. */
1673
1739
  multiaddr: string | null;
1674
- /** Single-use anti-replay nonce the voucher signature is bound to. */
1740
+ /** Single-use anti-replay nonce the voucher signature, or the usage row, is bound to. */
1675
1741
  stampId: string | null;
1676
- /** ed25519 public key (base64url) of the owner that vouched this row. */
1742
+ /** ed25519 public key (base64url) of the owner that vouched this row, or that issued the invitation that admitted it. */
1677
1743
  vouchOwner: string | null;
1678
- /** That owner's signature over `digest('CadreControl.CadrePeer', 'vouch', peerId, stampId)`, base64url. */
1744
+ /** That owner's signature over `digest('CadreControl.CadrePeer', 'vouch', partyId, peerId, stampId)`, base64url; null on an invitation-admitted row. */
1679
1745
  vouchSig: string | null;
1746
+ /** The `CadreInviteUsage.UsageStampId` that admitted this row; null on an owner-vouched row. */
1747
+ vouchUsage: string | null;
1748
+ }
1749
+ /** The proof-bearing subset of a {@link CadrePeerRow} — what the authorized-membership predicate reads. */
1750
+ export type CadrePeerVoucherFields = Pick<CadrePeerRow, 'peerId' | 'stampId' | 'vouchOwner' | 'vouchSig' | 'vouchUsage'>;
1751
+ /**
1752
+ * One live `CadreControl.OwnerKey` row as `ControlDatabase.queryOwnerKeyRows` reads it: the
1753
+ * key and the persisted proof of how it was seated. The three proof shapes are the schema's
1754
+ * (`OwnerKey.Authorized`): the founding row (all three null), an owner-signed add (`vouchOwner`
1755
+ * and `vouchSig`, the signer's signature over `ownerKeyAddDigest(key, stampId)`), or an
1756
+ * owner-granting invitation redeemed by consent (`vouchOwner` the issuer, `vouchSig` null,
1757
+ * `vouchUsage` the `CadreInviteUsage` row). Rows whose stamp is retired in `Revocation`, and
1758
+ * the stampless row the schema permits but no writer produces, never reach a reader, so
1759
+ * `stampId` is non-null here. The anchor sync (`deriveOwnerAnchor`) judges
1760
+ * the proof against the keys it already trusts, never against the table itself.
1761
+ */
1762
+ export interface OwnerKeyRow {
1763
+ /** ed25519 public key (base64url) — the row key. */
1764
+ key: string;
1765
+ /** Single-use anti-replay nonce the voucher signature, or the usage row, is bound to. */
1766
+ stampId: string;
1767
+ /** The owner that signed the add, or that issued the invitation that admitted it; null on the founding row. */
1768
+ vouchOwner: string | null;
1769
+ /** That owner's signature over the row's `'add'` digest, base64url; null on the founding row and on an invitation-admitted row. */
1770
+ vouchSig: string | null;
1771
+ /** The `CadreInviteUsage.UsageStampId` that admitted this row; null otherwise. */
1772
+ vouchUsage: string | null;
1773
+ }
1774
+ /**
1775
+ * One `CadreControl.CadreInvite` row: an owner-signed invitation to join the cadre,
1776
+ * as `ControlDatabase.insertCadreInvite` returns it and `queryCadreInvite` reads it.
1777
+ * Every column is here because the row travels: the holder carries it inside the
1778
+ * invitation bundle and a member re-seats it verbatim (`seatCadreInvite`), so
1779
+ * `expiresAt` is the engine-canonical `datetime` string the row stores, not epoch
1780
+ * ms — the `'add'` signature covers that exact text. The signed subset is
1781
+ * `CadreInviteSignedFields` (`control-authorization.ts`).
1782
+ */
1783
+ export interface CadreInviteRow extends CadreInviteSignedFields {
1784
+ /** The owner that signed the row (`IssuerKey`, base64url ed25519); a reader checks it against its anchor. */
1785
+ issuerKey: string;
1786
+ /** That owner's `'add'` signature over the row (`IssuerSig`, base64url). */
1787
+ issuerSig: string;
1788
+ }
1789
+ /**
1790
+ * One `CadreControl.CadreInviteUsage` row: a redemption of a {@link CadreInviteRow},
1791
+ * as `ControlDatabase.queryCadreInviteUsages` reads it. The two signatures are
1792
+ * stored so any reader can re-verify the admission chain (`verifyInvitationAdmission`).
1793
+ */
1794
+ export interface CadreInviteUsageRow {
1795
+ /** The redemption's single-use nonce (the row key), signed into both signatures. */
1796
+ usageStampId: string;
1797
+ /** The `CadreInvite.Key` redeemed. */
1798
+ inviteKey: string;
1799
+ /** The admitted device's libp2p peer id — the identity multihash of `peerKey`. */
1800
+ peerId: string;
1801
+ /** The admitted device's ed25519 public key (base64url). */
1802
+ peerKey: string;
1803
+ /** The `CadrePeer.StampId` this redemption seated (or found seated). */
1804
+ peerStampId: string;
1805
+ /** The `OwnerKey.StampId` this redemption seated, when the invitation grants ownership; else null. */
1806
+ ownerStampId: string | null;
1807
+ /** The invitation private key's signature over the `'redeem'` digest, base64url. */
1808
+ inviteSig: string;
1809
+ /** The device's signature over the `'consent'` digest, base64url. */
1810
+ peerSig: string;
1811
+ }
1812
+ /**
1813
+ * The usage and invitation rows an invitation-admitted row is verified through, keyed by
1814
+ * `UsageStampId` and `CadreInvite.Key`: a `CadrePeer` row through `verifyInvitationAdmission`
1815
+ * (`CadreNode.listAuthorizedMembers`) and an `OwnerKey` row through
1816
+ * `verifyInvitationOwnerAdmission` (`deriveOwnerAnchor`). Loaded once per membership refresh
1817
+ * (`CadreNode.loadInvitationChain`) and shared by both readers.
1818
+ */
1819
+ export interface InvitationChain {
1820
+ usages: Map<string, CadreInviteUsageRow>;
1821
+ invites: Map<string, CadreInviteRow>;
1822
+ }
1823
+ /**
1824
+ * One {@link CadreInviteRow} with its standing, as `ControlDatabase.listCadreInviteStatuses`
1825
+ * (and `CadreNode.listCadreInvitations`) reports it. `live` is the redemption's own test:
1826
+ * not withdrawn, unexpired, uses left, issuer still an owner here.
1827
+ */
1828
+ export interface CadreInviteStatus {
1829
+ invite: CadreInviteRow;
1830
+ live: boolean;
1831
+ withdrawn: boolean;
1832
+ /** Redemptions this node holds for it (`CadreInviteUsage` rows). */
1833
+ usesRecorded: number;
1834
+ }
1835
+ /**
1836
+ * What `ControlDatabase.redeemCadreInvite` did. `alreadyMember` is the idempotent
1837
+ * retry after a dropped reply: the device's row (and, for an owner-granting
1838
+ * invitation, its `OwnerKey` row) was already present, so nothing was written and
1839
+ * no seat was spent. The stamps are the live rows' either way.
1840
+ */
1841
+ export interface CadreInviteRedemptionResult {
1842
+ alreadyMember: boolean;
1843
+ peerStampId: string;
1844
+ ownerStampId: string | null;
1680
1845
  }
1681
- /** The voucher-bearing subset of a {@link CadrePeerRow} — what the authorized-membership predicate reads. */
1682
- export type CadrePeerVoucherFields = Pick<CadrePeerRow, 'peerId' | 'stampId' | 'vouchOwner' | 'vouchSig'>;
1683
1846
  /**
1684
1847
  * One `CadreControl.Revocation` tombstone as read by
1685
1848
  * `ControlDatabase.queryRevocations`: the identity triple plus the `ReissuedAt`
@@ -1697,6 +1860,10 @@ export interface RevocationRow {
1697
1860
  stampId: string;
1698
1861
  /** Monotonic re-issue counter; carries no semantics (see the schema comment). */
1699
1862
  reissuedAt: number;
1863
+ /** The owner key that filed the tombstone (`Revocation.SignerKey`). */
1864
+ signerKey: string;
1865
+ /** That owner's signature over the tombstone's `'remove'` digest (`Revocation.SignerSig`). */
1866
+ signerSig: string;
1700
1867
  }
1701
1868
  /**
1702
1869
  * Outcome of `ControlDatabase.openRevocationLedger`: `'opened'` when this call filed the
@@ -1907,6 +2074,47 @@ export interface SeedMessage {
1907
2074
  signature: string;
1908
2075
  /** The owner key that signed this message */
1909
2076
  signerKey: string;
2077
+ /**
2078
+ * Proof that the sender holds the receiving node's one-time claim secret
2079
+ * (`claim-proof.ts`), sent only when claiming a brand-new node. Rides beside
2080
+ * the seed rather than inside `ControlNetworkSeed`: it is not part of what the
2081
+ * owner signs, and a claimed node never needs it again.
2082
+ *
2083
+ * The protocol id stays `/sereus/seed/1.0.0` and no version field is added:
2084
+ * there is no backwards compatibility yet, a receiver without this feature
2085
+ * ignores the field and refuses by its anchored policy, and a sender without it
2086
+ * gets a definite refusal (`claim-proof-invalid`) from an unclaimed node.
2087
+ */
2088
+ claimProof?: string;
2089
+ }
2090
+ /**
2091
+ * Why a seed was refused, for callers that must branch on the cause without
2092
+ * parsing the human-readable `reason`. The phone claiming a node needs to tell
2093
+ * "someone else already claimed it" from "wrong secret".
2094
+ *
2095
+ * - `already-claimed`: the node's anchor already holds an owner key other than
2096
+ * the signer's; the claim secret is no longer consulted.
2097
+ * - `claim-proof-invalid`: the node is unclaimed and the seed carried no claim
2098
+ * proof, or a proof that does not verify.
2099
+ * - `claim-rate-limited`: too many failed proofs recently; the proof was not
2100
+ * verified. Retry after the window.
2101
+ * - `claim-not-persisted`: the proof verified but the node could not durably
2102
+ * record the claim; nothing was anchored, so the same claim may be retried.
2103
+ */
2104
+ export type SeedRefusalCode = 'already-claimed' | 'claim-proof-invalid' | 'claim-rate-limited' | 'claim-not-persisted';
2105
+ /**
2106
+ * What a claim settles for the node that accepted it: the party it serves from now on
2107
+ * and the owner it belongs to. Both come from the claim seed — the party is the seed's
2108
+ * `partyId`, the owner the key that signed it — because an unclaimed node's own
2109
+ * configured party is a placeholder; nobody could know the real one before the claim.
2110
+ * Handed to `CadreNodeConfig.claim.record` before the owner is anchored, and carried by
2111
+ * `claim:accepted`.
2112
+ */
2113
+ export interface NodeClaimRecord {
2114
+ /** The party the claim seed named: the cadre this node now serves. */
2115
+ partyId: string;
2116
+ /** The claimant's ed25519 owner key (base64url): the key the claim anchors. */
2117
+ ownerKey: string;
1910
2118
  }
1911
2119
  /**
1912
2120
  * Acknowledgment message from new node to instigator.
@@ -1916,6 +2124,8 @@ export interface SeedAckMessage {
1916
2124
  accepted: boolean;
1917
2125
  /** Reason for rejection (if not accepted) */
1918
2126
  reason?: string;
2127
+ /** Machine-readable refusal cause, when the refusing policy supplies one. */
2128
+ code?: SeedRefusalCode;
1919
2129
  }
1920
2130
  /**
1921
2131
  * Request sent over the control network's `WAKE_PROTOCOL` from a same-cadre peer
@@ -1968,12 +2178,14 @@ export interface StrandAddrRequest {
1968
2178
  *
1969
2179
  * - `ok` — looked up; `multiaddrs` is the truth, possibly empty (strand not running here).
1970
2180
  * - `unavailable` — the responder could not answer: over its concurrency cap, the
1971
- * request was unreadable, or its own lookup threw (e.g. a control-database read failed).
1972
- * - `refused` — the requester is not an authorized member in the responder's
1973
- * current view (possibly because its `CadrePeer` row has not replicated there yet);
1974
- * any `delegatePeerId` it carried was NOT recorded.
2181
+ * request was unreadable, or its own lookup threw.
2182
+ *
2183
+ * A requester the responder does not count as an authorized member (possibly because
2184
+ * its `CadrePeer` row has not replicated there yet) gets no response at all: the
2185
+ * responder's protocol guard resets the stream, and any `delegatePeerId` it carried
2186
+ * is not recorded.
1975
2187
  */
1976
- export type StrandAddrStatus = 'ok' | 'unavailable' | 'refused';
2188
+ export type StrandAddrStatus = 'ok' | 'unavailable';
1977
2189
  /**
1978
2190
  * Response to a {@link StrandAddrRequest}, carrying the responder's strand-node
1979
2191
  * multiaddrs, returned on the same stream.
@@ -1998,6 +2210,17 @@ export interface AuthorizePeerOptions {
1998
2210
  /** Optional multiaddrs for the peer */
1999
2211
  multiaddrs?: string[];
2000
2212
  }
2213
+ /**
2214
+ * Where `deliverSeed` sends a seed: one multiaddr string, dialed as given, or a
2215
+ * peer id with its known addresses. The object form merges the addresses into
2216
+ * the peer store and dials by peer id, so an existing connection is reused and
2217
+ * libp2p tries every address under the one delivery deadline. It is what a phone
2218
+ * uses to claim a node from the addresses it scanned.
2219
+ */
2220
+ export type SeedDeliveryTarget = string | {
2221
+ peerId: string;
2222
+ multiaddrs: string[];
2223
+ };
2001
2224
  /**
2002
2225
  * Result of applying a seed to a node.
2003
2226
  */
@@ -2008,6 +2231,8 @@ export interface ApplySeedResult {
2008
2231
  peersAdded: number;
2009
2232
  /** Error message if not successful */
2010
2233
  error?: string;
2234
+ /** Machine-readable refusal cause, when the refusing trust policy supplied one. */
2235
+ code?: SeedRefusalCode;
2011
2236
  /**
2012
2237
  * Owner-flagged seed peers this apply attempted to dial. Zero when the seed
2013
2238
  * carried no owner peer with an address, or when the seed was rejected before
@@ -2023,7 +2248,8 @@ export interface ApplySeedResult {
2023
2248
  * `CadreNode.dialColdStartBootstrap`), so this is a signal, not a fatal error.
2024
2249
  *
2025
2250
  * Zero failures is NOT proof of a live connection: the receiving node's
2026
- * membership gate denies AFTER the dialer's upgrade completes (see
2251
+ * connection gate decides AFTER the dialer's upgrade completes, and closes a
2252
+ * provisionally admitted connection at its deadline (see
2027
2253
  * `createMembershipConnectionGater`), so a dial can resolve and then be torn
2028
2254
  * down. Treat a non-zero value as certain failure and zero as "no failure
2029
2255
  * observed".
@@ -2035,30 +2261,37 @@ export interface ApplySeedResult {
2035
2261
  */
2036
2262
  export type NodeTopology = 'public' | 'nat';
2037
2263
  /**
2038
- * Invite code for phone-to-server enrollment.
2039
- * Used when a server invites a phone to join the cadre.
2264
+ * What an owner asks `CadreNode.createCadreInvitation` for. The invitation is a keypair the
2265
+ * node mints; whoever holds the returned bundle can redeem it at any member machine.
2040
2266
  */
2041
- export interface CadreInvite {
2042
- /** Party ID of the cadre */
2043
- partyId: string;
2044
- /** Multiaddrs to dial the owner */
2045
- ownerAddrs: string[];
2046
- /**
2047
- * Owner ed25519 public keys (base64url) of the cadre, carried out-of-band
2048
- * so a cold-start invitee can pin the trusted owner set before applying
2049
- * any seed (the seed itself cannot vouch for its own signer). Populated by
2050
- * `createInvite` from the issuer's OWN node-local trusted-owner anchor —
2051
- * not its replicated `OwnerKey` table, because the invitee anchors whatever
2052
- * arrives here and a stranger's genesis-inserted key must not ride an
2053
- * otherwise-legitimate invite into a fresh node's anchor.
2054
- */
2055
- ownerKeys?: string[];
2056
- /** Optional invite token for validation */
2057
- token?: string;
2058
- /** Timestamp when invite was created */
2059
- createdAt: number;
2060
- /** Optional expiration timestamp */
2061
- expiresAt?: number;
2267
+ export interface CreateCadreInvitationOptions {
2268
+ /** The one device that may redeem it; omit for whoever redeems first. */
2269
+ peerId?: string;
2270
+ /** Whether redemption also makes the device an owner (seats an `OwnerKey` row). */
2271
+ grantsOwner: boolean;
2272
+ /**
2273
+ * Lifetime from now, in ms. Defaults to 15 minutes for an untargeted owner-granting
2274
+ * invitation — a bearer credential for admin rights — and 24 hours otherwise. A negative
2275
+ * value mints an already-expired invitation (tests).
2276
+ */
2277
+ expiresInMs?: number;
2278
+ /** How many redemptions it allows; default 1. */
2279
+ uses?: number;
2280
+ }
2281
+ /** What `CadreNode.createCadreInvitation` returns: the bundle, and the same encoded for sharing. */
2282
+ export interface CreateCadreInvitationResult {
2283
+ invitation: CadreInvitation;
2284
+ /** `encodeCadreInvitation(invitation)`: base64url JSON for a QR code, a paste or a link. */
2285
+ encoded: string;
2286
+ }
2287
+ /** What `CadreNode.redeemCadreInvitation` returns once a member accepted. */
2288
+ export interface RedeemCadreInvitationResult {
2289
+ /** The member machine that admitted this device, when its address named one. */
2290
+ peerId: string | null;
2291
+ /** Whether the invitation also seated this device's key as an owner. */
2292
+ grantsOwner: boolean;
2293
+ /** When the member accepted, ISO 8601. */
2294
+ redeemedAt: string;
2062
2295
  }
2063
2296
  /**
2064
2297
  * Options for adding a drone via provider API.
@@ -2069,15 +2302,6 @@ export interface AddDroneOptions {
2069
2302
  /** Multiaddrs of the drone (returned from provider) */
2070
2303
  droneMultiaddrs: string[];
2071
2304
  }
2072
- /**
2073
- * Options for adding a phone via invite flow.
2074
- */
2075
- export interface AddPhoneOptions {
2076
- /** Peer ID of the phone (sent by phone when it connects) */
2077
- phonePeerId: string;
2078
- /** Invite token for validation (must match issued invite) */
2079
- token?: string;
2080
- }
2081
2305
  /**
2082
2306
  * Result of preparing a seed for drone initialization.
2083
2307
  */
@@ -2087,12 +2311,3 @@ export interface DroneInitResult {
2087
2311
  /** Base64url encoded seed for transport */
2088
2312
  encodedSeed: string;
2089
2313
  }
2090
- /**
2091
- * Result of creating an invite for a phone.
2092
- */
2093
- export interface InviteResult {
2094
- /** The invite to share out-of-band */
2095
- invite: CadreInvite;
2096
- /** Base64url encoded invite for QR/link */
2097
- encodedInvite: string;
2098
- }
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAqFA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA6C;IAC5E,QAAQ,EAAE;QACR,WAAW,EAAE,QAAQ,EAAS,aAAa;QAC3C,gBAAgB,EAAE,QAAQ,EAAI,kBAAkB;QAChD,eAAe,EAAE,QAAQ,EAAK,MAAM;QACpC,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,QAAQ,CAAE,MAAM;KACrC;IACD,WAAW,EAAE;QACX,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,YAAY;QAC1C,gBAAgB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,wBAAwB;QAC1D,eAAe,EAAE,EAAE,GAAG,IAAI,EAAI,mBAAmB;QACjD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;KACnD;IACD,UAAU,EAAE;QACV,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,WAAW;QACzC,gBAAgB,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAG,uBAAuB;QACzD,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,kBAAkB;QACpD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,gBAAgB;KACxD;IACD,OAAO,EAAE;QACP,WAAW,EAAE,EAAE,GAAG,IAAI,EAAQ,aAAa;QAC3C,gBAAgB,EAAE,EAAE,GAAG,IAAI,EAAG,wBAAwB;QACtD,eAAe,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAG,eAAe;QACjD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;KAC5D;CACF,CAAC;AA0dF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC,MAAM,CAAC;IACtD,uFAAuF;IACvF,mFAAmF;IACnF,YAAY,EAAE,KAAM;IACpB,kFAAkF;IAClF,kFAAkF;IAClF,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,KAAM,EAAE,UAAU,EAAE,KAAM,EAAE,CAAC;CACjC,CAAC,CAAC;AAmBzC;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,IAAI,CAAC;AAYnD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,+BAA+B,CAAC;AAEvC;;;;;GAKG;AACH,OAAO,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAsFA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA6C;IAC5E,QAAQ,EAAE;QACR,WAAW,EAAE,QAAQ,EAAS,aAAa;QAC3C,gBAAgB,EAAE,QAAQ,EAAI,kBAAkB;QAChD,eAAe,EAAE,QAAQ,EAAK,MAAM;QACpC,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,QAAQ,CAAE,MAAM;KACrC;IACD,WAAW,EAAE;QACX,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,YAAY;QAC1C,gBAAgB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,wBAAwB;QAC1D,eAAe,EAAE,EAAE,GAAG,IAAI,EAAI,mBAAmB;QACjD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;KACnD;IACD,UAAU,EAAE;QACV,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,WAAW;QACzC,gBAAgB,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAG,uBAAuB;QACzD,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,kBAAkB;QACpD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,gBAAgB;KACxD;IACD,OAAO,EAAE;QACP,WAAW,EAAE,EAAE,GAAG,IAAI,EAAQ,aAAa;QAC3C,gBAAgB,EAAE,EAAE,GAAG,IAAI,EAAG,wBAAwB;QACtD,eAAe,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAG,eAAe;QACjD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;KAC5D;CACF,CAAC;AA0dF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC,MAAM,CAAC;IACtD,uFAAuF;IACvF,mFAAmF;IACnF,YAAY,EAAE,KAAM;IACpB,kFAAkF;IAClF,kFAAkF;IAClF,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,KAAM,EAAE,UAAU,EAAE,KAAM,EAAE,CAAC;CACjC,CAAC,CAAC;AAmBzC;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,IAAI,CAAC;AAYnD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,+BAA+B,CAAC;AAEvC;;;;;GAKG;AACH,OAAO,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serfab/cadre-core",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "type": "module",
5
5
  "description": "Core library for Sereus cadre nodes - manages control networks and strand participation",
6
6
  "main": "dist/index.js",
@@ -77,7 +77,7 @@
77
77
  "@libp2p/tcp": "^11.0.28",
78
78
  "@libp2p/webrtc": "6.0.33",
79
79
  "@libp2p/websockets": "^10.1.21",
80
- "@optimystic/db-p2p-storage-fs": "^1.11.0",
80
+ "@optimystic/db-p2p-storage-fs": "^1.12.0",
81
81
  "@types/debug": "^4.1.12",
82
82
  "@types/node": "^25.0.10",
83
83
  "@vitest/coverage-v8": "^4.0.17",
@@ -93,12 +93,13 @@
93
93
  "@libp2p/peer-id": "^6.0.15",
94
94
  "@libp2p/peer-record": "^9.0.16",
95
95
  "@multiformats/multiaddr": "^13.0.3",
96
- "@optimystic/db-core": "^1.11.0",
97
- "@optimystic/db-p2p": "^1.11.0",
98
- "@optimystic/quereus-plugin-crypto": "^1.11.0",
99
- "@optimystic/quereus-plugin-optimystic": "^1.11.0",
96
+ "@noble/hashes": "^2.0.0",
97
+ "@optimystic/db-core": "^1.12.0",
98
+ "@optimystic/db-p2p": "^1.12.0",
99
+ "@optimystic/quereus-plugin-crypto": "^1.12.0",
100
+ "@optimystic/quereus-plugin-optimystic": "^1.12.0",
100
101
  "@quereus/quereus": "^4.20.1",
101
- "@serfab/quereus-plugin-sereus": "^1.13.0",
102
+ "@serfab/quereus-plugin-sereus": "^1.14.0",
102
103
  "debug": "^4.4.3",
103
104
  "libp2p": "^3.3.11",
104
105
  "uint8arrays": "^6.1.1"