@serfab/cadre-core 1.16.0 → 1.18.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 (268) hide show
  1. package/README.md +4 -3
  2. package/dist/bootstrap-peer-store-file.js +1 -1
  3. package/dist/bootstrap-peer-store.d.ts +1 -1
  4. package/dist/bootstrap-peer-store.js +4 -4
  5. package/dist/cadre-invite-protocol.d.ts +81 -142
  6. package/dist/cadre-invite-protocol.js +168 -458
  7. package/dist/cadre-invite-protocol.js.map +1 -1
  8. package/dist/cadre-join-request.d.ts +15 -2
  9. package/dist/cadre-join-request.js +22 -3
  10. package/dist/cadre-join-request.js.map +1 -1
  11. package/dist/cadre-node.d.ts +1089 -475
  12. package/dist/cadre-node.js +2170 -1037
  13. package/dist/cadre-node.js.map +1 -1
  14. package/dist/control-authorization.d.ts +36 -14
  15. package/dist/control-authorization.js +20 -3
  16. package/dist/control-authorization.js.map +1 -1
  17. package/dist/control-cohort.d.ts +88 -32
  18. package/dist/control-cohort.js +91 -33
  19. package/dist/control-cohort.js.map +1 -1
  20. package/dist/control-database.d.ts +856 -318
  21. package/dist/control-database.js +1422 -701
  22. package/dist/control-database.js.map +1 -1
  23. package/dist/control-formation-recorder.d.ts +46 -43
  24. package/dist/control-formation-recorder.js +77 -78
  25. package/dist/control-formation-recorder.js.map +1 -1
  26. package/dist/control-protocol-guard.d.ts +11 -4
  27. package/dist/control-protocol-guard.js +20 -5
  28. package/dist/control-protocol-guard.js.map +1 -1
  29. package/dist/control-schema-version.d.ts +97 -0
  30. package/dist/control-schema-version.js +225 -0
  31. package/dist/control-schema-version.js.map +1 -0
  32. package/dist/control-schema.d.ts +45 -5
  33. package/dist/control-schema.js +262 -78
  34. package/dist/control-schema.js.map +1 -1
  35. package/dist/control-write-retry.d.ts +45 -10
  36. package/dist/control-write-retry.js +92 -22
  37. package/dist/control-write-retry.js.map +1 -1
  38. package/dist/delegate-admission.d.ts +13 -0
  39. package/dist/delegate-admission.js +27 -0
  40. package/dist/delegate-admission.js.map +1 -1
  41. package/dist/ed25519-key.d.ts +10 -7
  42. package/dist/ed25519-key.js +23 -20
  43. package/dist/ed25519-key.js.map +1 -1
  44. package/dist/edge-node/config.d.ts +122 -0
  45. package/dist/edge-node/config.js +199 -0
  46. package/dist/edge-node/config.js.map +1 -0
  47. package/dist/edge-node/dissolve.d.ts +95 -0
  48. package/dist/edge-node/dissolve.js +184 -0
  49. package/dist/edge-node/dissolve.js.map +1 -0
  50. package/dist/edge-node/edge-join.d.ts +44 -0
  51. package/dist/edge-node/edge-join.js +227 -0
  52. package/dist/edge-node/edge-join.js.map +1 -0
  53. package/dist/edge-node/edge-node.d.ts +295 -0
  54. package/dist/edge-node/edge-node.js +704 -0
  55. package/dist/edge-node/edge-node.js.map +1 -0
  56. package/dist/edge-node/index.d.ts +18 -0
  57. package/dist/edge-node/index.js +18 -0
  58. package/dist/edge-node/index.js.map +1 -0
  59. package/dist/edge-node/join-credential.d.ts +11 -0
  60. package/dist/edge-node/join-credential.js +11 -0
  61. package/dist/edge-node/join-credential.js.map +1 -0
  62. package/dist/edge-node/lazy-raw-storage.d.ts +40 -0
  63. package/dist/edge-node/lazy-raw-storage.js +134 -0
  64. package/dist/edge-node/lazy-raw-storage.js.map +1 -0
  65. package/dist/edge-node/node-local.d.ts +60 -0
  66. package/dist/edge-node/node-local.js +58 -0
  67. package/dist/edge-node/node-local.js.map +1 -0
  68. package/dist/edge-node/options.d.ts +83 -0
  69. package/dist/edge-node/options.js +110 -0
  70. package/dist/edge-node/options.js.map +1 -0
  71. package/dist/edge-node/owner-grant.d.ts +41 -0
  72. package/dist/edge-node/owner-grant.js +38 -0
  73. package/dist/edge-node/owner-grant.js.map +1 -0
  74. package/dist/edge-node/platform.d.ts +140 -0
  75. package/dist/edge-node/platform.js +12 -0
  76. package/dist/edge-node/platform.js.map +1 -0
  77. package/dist/edge-node/strand-move.d.ts +115 -0
  78. package/dist/edge-node/strand-move.js +223 -0
  79. package/dist/edge-node/strand-move.js.map +1 -0
  80. package/dist/edge-node/strands.d.ts +28 -0
  81. package/dist/edge-node/strands.js +60 -0
  82. package/dist/edge-node/strands.js.map +1 -0
  83. package/dist/enrolled-machine-store.d.ts +3 -3
  84. package/dist/enrolled-machine-store.js +3 -3
  85. package/dist/formation-token.d.ts +48 -0
  86. package/dist/formation-token.js +26 -0
  87. package/dist/formation-token.js.map +1 -0
  88. package/dist/index.d.ts +27 -17
  89. package/dist/index.js +39 -17
  90. package/dist/index.js.map +1 -1
  91. package/dist/joined-strand-store.d.ts +29 -12
  92. package/dist/joined-strand-store.js +66 -27
  93. package/dist/joined-strand-store.js.map +1 -1
  94. package/dist/key-store.d.ts +9 -4
  95. package/dist/key-store.js +9 -4
  96. package/dist/key-store.js.map +1 -1
  97. package/dist/link-budget.d.ts +9 -7
  98. package/dist/link-budget.js +9 -7
  99. package/dist/link-budget.js.map +1 -1
  100. package/dist/machine-removal.d.ts +19 -39
  101. package/dist/machine-removal.js +24 -98
  102. package/dist/machine-removal.js.map +1 -1
  103. package/dist/member-redemption.d.ts +256 -0
  104. package/dist/member-redemption.js +490 -0
  105. package/dist/member-redemption.js.map +1 -0
  106. package/dist/membership-view.d.ts +91 -0
  107. package/dist/membership-view.js +110 -0
  108. package/dist/membership-view.js.map +1 -0
  109. package/dist/owner-anchor-sync.d.ts +4 -4
  110. package/dist/owner-anchor-sync.js +16 -15
  111. package/dist/owner-anchor-sync.js.map +1 -1
  112. package/dist/owner-grant-protocol.d.ts +251 -0
  113. package/dist/owner-grant-protocol.js +344 -0
  114. package/dist/owner-grant-protocol.js.map +1 -0
  115. package/dist/owner-key-export.d.ts +70 -0
  116. package/dist/owner-key-export.js +279 -0
  117. package/dist/owner-key-export.js.map +1 -0
  118. package/dist/owner-key-flows.d.ts +55 -0
  119. package/dist/owner-key-flows.js +60 -0
  120. package/dist/owner-key-flows.js.map +1 -0
  121. package/dist/owner-key-store.d.ts +31 -0
  122. package/dist/owner-key-store.js +81 -0
  123. package/dist/owner-key-store.js.map +1 -0
  124. package/dist/owner-keys.d.ts +78 -0
  125. package/dist/owner-keys.js +133 -0
  126. package/dist/owner-keys.js.map +1 -0
  127. package/dist/owner-signer.d.ts +54 -0
  128. package/dist/owner-signer.js +51 -0
  129. package/dist/owner-signer.js.map +1 -0
  130. package/dist/peer-addr-book.d.ts +10 -1
  131. package/dist/peer-addr-book.js +4 -3
  132. package/dist/peer-addr-book.js.map +1 -1
  133. package/dist/peer-authorization.d.ts +83 -18
  134. package/dist/peer-authorization.js +123 -53
  135. package/dist/peer-authorization.js.map +1 -1
  136. package/dist/peer-join-backfill.d.ts +89 -20
  137. package/dist/peer-join-backfill.js +265 -108
  138. package/dist/peer-join-backfill.js.map +1 -1
  139. package/dist/pending-join-runner.d.ts +48 -18
  140. package/dist/pending-join-runner.js +74 -56
  141. package/dist/pending-join-runner.js.map +1 -1
  142. package/dist/provider/rent-node.js +1 -1
  143. package/dist/provider/rent-node.js.map +1 -1
  144. package/dist/seed-bootstrap.d.ts +162 -133
  145. package/dist/seed-bootstrap.js +300 -283
  146. package/dist/seed-bootstrap.js.map +1 -1
  147. package/dist/seed-trust-policy.js +4 -4
  148. package/dist/strand-addr-protocol.d.ts +4 -1
  149. package/dist/strand-addr-protocol.js +8 -2
  150. package/dist/strand-addr-protocol.js.map +1 -1
  151. package/dist/strand-cohort.d.ts +3 -0
  152. package/dist/strand-cohort.js.map +1 -1
  153. package/dist/strand-database.d.ts +24 -2
  154. package/dist/strand-database.js +29 -6
  155. package/dist/strand-database.js.map +1 -1
  156. package/dist/strand-first-sync-gate.d.ts +176 -88
  157. package/dist/strand-first-sync-gate.js +288 -121
  158. package/dist/strand-first-sync-gate.js.map +1 -1
  159. package/dist/strand-formation-deadlines.d.ts +9 -9
  160. package/dist/strand-formation-deadlines.js +9 -9
  161. package/dist/strand-formation-manager.d.ts +23 -17
  162. package/dist/strand-formation-manager.js +46 -44
  163. package/dist/strand-formation-manager.js.map +1 -1
  164. package/dist/strand-formation-protocol.d.ts +5 -8
  165. package/dist/strand-formation-protocol.js +101 -16
  166. package/dist/strand-formation-protocol.js.map +1 -1
  167. package/dist/strand-instance-manager.d.ts +27 -18
  168. package/dist/strand-instance-manager.js +119 -50
  169. package/dist/strand-instance-manager.js.map +1 -1
  170. package/dist/strand-membership-reconciler.d.ts +16 -13
  171. package/dist/strand-membership-reconciler.js +30 -22
  172. package/dist/strand-membership-reconciler.js.map +1 -1
  173. package/dist/strand-membership-writer.d.ts +45 -22
  174. package/dist/strand-membership-writer.js +226 -131
  175. package/dist/strand-membership-writer.js.map +1 -1
  176. package/dist/strand-move.d.ts +6 -5
  177. package/dist/strand-move.js +36 -32
  178. package/dist/strand-move.js.map +1 -1
  179. package/dist/strand-peer-redial.js +2 -3
  180. package/dist/strand-peer-redial.js.map +1 -1
  181. package/dist/strand-revocation-enforcer.d.ts +134 -60
  182. package/dist/strand-revocation-enforcer.js +144 -71
  183. package/dist/strand-revocation-enforcer.js.map +1 -1
  184. package/dist/strand-solicitation.d.ts +50 -39
  185. package/dist/strand-solicitation.js +10 -3
  186. package/dist/strand-solicitation.js.map +1 -1
  187. package/dist/strand-watcher.d.ts +80 -13
  188. package/dist/strand-watcher.js +152 -48
  189. package/dist/strand-watcher.js.map +1 -1
  190. package/dist/table-change-watch.d.ts +63 -0
  191. package/dist/table-change-watch.js +209 -0
  192. package/dist/table-change-watch.js.map +1 -0
  193. package/dist/timeout-scheduler.d.ts +4 -3
  194. package/dist/timeout-scheduler.js +4 -3
  195. package/dist/timeout-scheduler.js.map +1 -1
  196. package/dist/types.d.ts +374 -150
  197. package/dist/types.js +4 -4
  198. package/dist/types.js.map +1 -1
  199. package/package.json +17 -8
  200. package/src/bootstrap-peer-store-file.ts +44 -44
  201. package/src/bootstrap-peer-store.ts +214 -214
  202. package/src/cadre-invite-protocol.ts +740 -1052
  203. package/src/cadre-join-request.ts +24 -3
  204. package/src/cadre-node.ts +2402 -1079
  205. package/src/control-authorization.ts +47 -14
  206. package/src/control-cohort.ts +204 -128
  207. package/src/control-database.ts +1749 -820
  208. package/src/control-formation-recorder.ts +359 -353
  209. package/src/control-protocol-guard.ts +23 -6
  210. package/src/control-schema-version.ts +301 -0
  211. package/src/control-schema.ts +273 -78
  212. package/src/control-write-retry.ts +641 -567
  213. package/src/delegate-admission.ts +351 -314
  214. package/src/ed25519-key.ts +174 -171
  215. package/src/edge-node/config.ts +277 -0
  216. package/src/edge-node/dissolve.ts +251 -0
  217. package/src/edge-node/edge-join.ts +319 -0
  218. package/src/edge-node/edge-node.ts +1045 -0
  219. package/src/edge-node/index.ts +59 -0
  220. package/src/edge-node/join-credential.ts +16 -0
  221. package/src/edge-node/lazy-raw-storage.ts +178 -0
  222. package/src/edge-node/node-local.ts +84 -0
  223. package/src/edge-node/options.ts +179 -0
  224. package/src/edge-node/owner-grant.ts +63 -0
  225. package/src/edge-node/platform.ts +151 -0
  226. package/src/edge-node/strand-move.ts +270 -0
  227. package/src/edge-node/strands.ts +72 -0
  228. package/src/enrolled-machine-store.ts +3 -3
  229. package/src/formation-token.ts +63 -0
  230. package/src/index.ts +899 -789
  231. package/src/joined-strand-store.ts +73 -28
  232. package/src/key-store.ts +10 -4
  233. package/src/link-budget.ts +9 -7
  234. package/src/machine-removal.ts +26 -111
  235. package/src/member-redemption.ts +649 -0
  236. package/src/membership-view.ts +144 -0
  237. package/src/owner-anchor-sync.ts +19 -18
  238. package/src/owner-grant-protocol.ts +547 -0
  239. package/src/owner-key-export.ts +348 -0
  240. package/src/owner-key-flows.ts +109 -0
  241. package/src/owner-key-store.ts +85 -0
  242. package/src/owner-keys.ts +178 -0
  243. package/src/owner-signer.ts +94 -0
  244. package/src/peer-addr-book.ts +4 -3
  245. package/src/peer-authorization.ts +558 -488
  246. package/src/peer-join-backfill.ts +971 -761
  247. package/src/pending-join-runner.ts +76 -53
  248. package/src/provider/rent-node.ts +1 -1
  249. package/src/seed-bootstrap.ts +343 -349
  250. package/src/seed-trust-policy.ts +4 -4
  251. package/src/strand-addr-protocol.ts +547 -538
  252. package/src/strand-cohort.ts +4 -0
  253. package/src/strand-database.ts +352 -319
  254. package/src/strand-first-sync-gate.ts +334 -133
  255. package/src/strand-formation-deadlines.ts +227 -227
  256. package/src/strand-formation-manager.ts +731 -725
  257. package/src/strand-formation-protocol.ts +122 -24
  258. package/src/strand-instance-manager.ts +2092 -2026
  259. package/src/strand-membership-reconciler.ts +33 -25
  260. package/src/strand-membership-writer.ts +2093 -1974
  261. package/src/strand-move.ts +50 -38
  262. package/src/strand-peer-redial.ts +2 -3
  263. package/src/strand-revocation-enforcer.ts +740 -654
  264. package/src/strand-solicitation.ts +61 -34
  265. package/src/strand-watcher.ts +175 -56
  266. package/src/table-change-watch.ts +285 -0
  267. package/src/timeout-scheduler.ts +29 -28
  268. package/src/types.ts +391 -152
@@ -0,0 +1,144 @@
1
+ /**
2
+ * An in-memory copy of one small control table's rows, kept until the table changes, so the
3
+ * membership, owner, peer-record and admission-chain reads that every flow repeats cost nothing
4
+ * after the first.
5
+ * `ControlDatabase` keeps one per cached table and drops it from its table-change subscription
6
+ * (`docs/architecture.md` → "Membership rows view"); this class holds only the caching rules, so
7
+ * they are testable without a database.
8
+ */
9
+ /**
10
+ * How long installed rows are served before the next read reloads them, change or no change.
11
+ * The reload is the only path for a change that reaches this node with no storage event: a
12
+ * machine outside the block's cohort (a cadre larger than its replication breadth), or one in
13
+ * the cohort that the writer could not reach when it committed (one side of a NAT pair; the
14
+ * cohort auto-connect scenarios). Longer than Optimystic's read-repair window
15
+ * ({@link OPTIMYSTIC_READ_REPAIR_WINDOW_MS}), so the reload's storage read starts the cohort
16
+ * consult that brings such a change in instead of being served from the local copy, and
17
+ * shorter than any reconcile backstop (`DEFAULT_CONTROL_COHORT_RECONCILE_MS`, 2 minutes), so
18
+ * the backstop pass, the only reader on an idle party, reloads rather than serving kept rows.
19
+ * The reload rate on an idle party is therefore the pass rate, and the staleness bound for
20
+ * such a change is the backstop, not this value.
21
+ *
22
+ * A machine that was offline when a sibling committed is covered sooner than either:
23
+ * `CadreNode` drops every view when a sibling becomes reachable (its identify on a new
24
+ * connection; `ControlDatabase.invalidateMembershipViews`), so the pass that starts then reads
25
+ * storage.
26
+ */
27
+ export const MEMBERSHIP_VIEW_MAX_AGE_MS = 15_000;
28
+
29
+ /**
30
+ * Optimystic's lazy read-repair window (`clusterPolicy.readRepairWindowMs`, which cadre does
31
+ * not set, so this is Optimystic's default): a read of a held block checked less than this
32
+ * long ago is served from the local copy without asking the cohort. A read after it is
33
+ * served locally too, but starts a cohort consult whose landing raises a table change.
34
+ *
35
+ * NOTE: a copy, since db-p2p exports no default for it. If cadre ever sets
36
+ * `readRepairWindowMs` in its cluster policy, derive this from that value.
37
+ */
38
+ const OPTIMYSTIC_READ_REPAIR_WINDOW_MS = 10_000;
39
+
40
+ /**
41
+ * How long after a sibling becomes reachable (its identify on a new connection) `CadreNode`
42
+ * drops the views a second time: one read-repair window, plus a second for timer slop. The
43
+ * drop at the identify is not enough by itself. A node's reads before the sibling arrived
44
+ * (its start pass, with no cohort to ask) stamp the window, so the reload the identify
45
+ * starts is served from the local copy without a consult and the view would keep the
46
+ * pre-connection rows until {@link MEMBERSHIP_VIEW_MAX_AGE_MS}. The reload past the window
47
+ * starts the consults that bring in what the sibling committed while this node was away.
48
+ */
49
+ export const MEMBERSHIP_VIEW_RECONNECT_RELOAD_MS = OPTIMYSTIC_READ_REPAIR_WINDOW_MS + 1_000;
50
+
51
+ /** One load's rows, and whether the view may keep them. */
52
+ export interface MembershipViewLoad<Row> {
53
+ rows: readonly Row[];
54
+ /**
55
+ * False when no later change event is guaranteed to reach the view for these rows (the
56
+ * read that produced them did not arm the table's change bridge), so they serve only the
57
+ * callers of this load.
58
+ */
59
+ installable: boolean;
60
+ }
61
+
62
+ /**
63
+ * Reads the whole table. `retry` is the caller's: false from a caller holding the control
64
+ * write lock, whose read must not sleep a retry backoff.
65
+ */
66
+ export type MembershipViewLoader<Row> = (retry: boolean) => Promise<MembershipViewLoad<Row>>;
67
+
68
+ export interface MembershipViewOptions {
69
+ /** Default {@link MEMBERSHIP_VIEW_MAX_AGE_MS}. */
70
+ maxAgeMs?: number;
71
+ /** Monotonic clock in milliseconds; default `performance.now`. */
72
+ now?: () => number;
73
+ }
74
+
75
+ export class MembershipView<Row> {
76
+ private rows: readonly Row[] | undefined;
77
+ /** When the load that produced {@link rows} started: the rows are no older than this. */
78
+ private loadedAt = 0;
79
+ /** Bumped by every {@link invalidate}; a load installs only if it is unchanged since the load began. */
80
+ private generation = 0;
81
+ /**
82
+ * The load each `retry` flag's callers share, current generation only. Separate per flag
83
+ * so a caller under the write lock never awaits a retrying load's backoff sleep.
84
+ */
85
+ private readonly inFlight = new Map<boolean, Promise<readonly Row[]>>();
86
+ private readonly maxAgeMs: number;
87
+ private readonly now: () => number;
88
+
89
+ constructor(private readonly loader: MembershipViewLoader<Row>, options: MembershipViewOptions = {}) {
90
+ this.maxAgeMs = options.maxAgeMs ?? MEMBERSHIP_VIEW_MAX_AGE_MS;
91
+ this.now = options.now ?? (() => performance.now());
92
+ }
93
+
94
+ /**
95
+ * The table's rows: the installed copy while it is younger than the maximum age, otherwise a
96
+ * load, shared with every caller of the same `retry` flag that arrives while it runs. A load
97
+ * that raced an {@link invalidate} answers its own callers with what it read, as an uncached
98
+ * read would have, and keeps nothing. A failed load keeps nothing and rejects.
99
+ */
100
+ read(retry: boolean): Promise<readonly Row[]> {
101
+ if (this.rows !== undefined && this.now() - this.loadedAt < this.maxAgeMs) {
102
+ return Promise.resolve(this.rows);
103
+ }
104
+ return this.inFlight.get(retry) ?? this.startLoad(retry);
105
+ }
106
+
107
+ /** Read the table without serving, joining or keeping anything. */
108
+ async readThrough(retry: boolean): Promise<readonly Row[]> {
109
+ return (await this.loader(retry)).rows;
110
+ }
111
+
112
+ /**
113
+ * Drop the installed rows and every load in flight, so the next read loads afresh and no
114
+ * earlier load installs. Synchronous and flag-setting only: the table-change handler calls
115
+ * it inside the committing call.
116
+ */
117
+ invalidate(): void {
118
+ this.generation++;
119
+ this.rows = undefined;
120
+ this.inFlight.clear();
121
+ }
122
+
123
+ private startLoad(retry: boolean): Promise<readonly Row[]> {
124
+ const load = this.load(retry, this.generation, this.now());
125
+ this.inFlight.set(retry, load);
126
+ const forget = (): void => {
127
+ if (this.inFlight.get(retry) === load) {
128
+ this.inFlight.delete(retry);
129
+ }
130
+ };
131
+ // Both arms handled, so a failed load rejects only for the callers awaiting it.
132
+ void load.then(forget, forget);
133
+ return load;
134
+ }
135
+
136
+ private async load(retry: boolean, generation: number, startedAt: number): Promise<readonly Row[]> {
137
+ const { rows, installable } = await this.loader(retry);
138
+ if (installable && generation === this.generation) {
139
+ this.rows = rows;
140
+ this.loadedAt = startedAt;
141
+ }
142
+ return rows;
143
+ }
144
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * How the node-local trusted-owner anchor follows the replicated `OwnerKey` table along
3
3
  * VERIFIABLE chains — the pure rule, with no I/O, so it can be tested without a database.
4
- * `CadreNode.syncOwnerAnchor` reads the table, the tombstones and the invitation chain,
4
+ * `CadreNode.syncOwnerAnchor` reads the table, the tombstones and the owner-grant chain,
5
5
  * calls {@link deriveOwnerAnchor}, and applies the difference to the store.
6
6
  *
7
7
  * Why not simply trust the table: an empty local copy can seat any key through the
@@ -19,9 +19,10 @@
19
19
  * retired, although nothing could re-derive it from the remaining base.
20
20
  * - **derivable from S**: a live row whose stored proof verifies against S — owner-signed
21
21
  * (`vouchSig` set): `vouchOwner` is in S and `verifyOwnerKeyVoucher` holds;
22
- * invitation-admitted (`vouchSig` null, `vouchUsage` set): `verifyInvitationOwnerAdmission`
23
- * holds with S as the anchor. The founding row (all three null) is never derivable:
24
- * founders enter anchors only out of band.
22
+ * grant-seated (`vouchSig` null, `vouchUsage` naming an `OwnerGrantUsage` row):
23
+ * `verifyOwnerGrantAdmission` holds with S as the anchor. The founding row (all three null)
24
+ * is never derivable: founders enter anchors only out of band. A machine invitation admits a
25
+ * machine and never seats an owner row, so no `CadreInviteUsage` row is read here.
25
26
  * - **derived**: the least fixpoint from base ∪ kept — add every key whose live row is
26
27
  * derivable from what is already in the set, until nothing changes. **chainDerived** is the
27
28
  * keys whose live row was derivable in this pass, base keys included.
@@ -45,9 +46,9 @@
45
46
  * two cannot be told apart from replicated state; keeping is the only rule under which a
46
47
  * sole owner can rotate at all.
47
48
  */
48
- import { verifyInvitationOwnerAdmission, verifyOwnerKeyVoucher, verifyRevocationSigner } from './peer-authorization.js';
49
+ import { verifyOwnerGrantAdmission, verifyOwnerKeyVoucher, verifyRevocationSigner } from './peer-authorization.js';
49
50
  import type { TrustSource } from './trusted-owner-store.js';
50
- import type { InvitationChain, OwnerKeyRow, RevocationRow } from './types.js';
51
+ import type { OwnerGrantChain, OwnerKeyRow, RevocationRow } from './types.js';
51
52
 
52
53
  export interface OwnerAnchorInputs {
53
54
  /** The party whose table is being read; every stored proof is judged for it, so a voucher or tombstone signed for another party neither seats nor removes a key. */
@@ -58,8 +59,8 @@ export interface OwnerAnchorInputs {
58
59
  rows: readonly OwnerKeyRow[];
59
60
  /** `Revocation` rows; only those with `tableName === 'OwnerKey'` are consulted. */
60
61
  tombstones: readonly RevocationRow[];
61
- /** The usage and invitation rows, when some owner row is invitation-admitted; null skips those rows. */
62
- chain: InvitationChain | null;
62
+ /** The usage and grant rows, when some owner row is grant-seated; null when none is, which skips every consent-seated row. */
63
+ grantChain: OwnerGrantChain | null;
63
64
  }
64
65
 
65
66
  export interface OwnerAnchorDerivation {
@@ -70,7 +71,7 @@ export interface OwnerAnchorDerivation {
70
71
  }
71
72
 
72
73
  /** The rule above, as one pure function. */
73
- export function deriveOwnerAnchor({ partyId, anchor, rows, tombstones, chain }: OwnerAnchorInputs): OwnerAnchorDerivation {
74
+ export function deriveOwnerAnchor({ partyId, anchor, rows, tombstones, grantChain }: OwnerAnchorInputs): OwnerAnchorDerivation {
74
75
  const ownerTombstones = tombstones.filter(tombstone => tombstone.tableName === 'OwnerKey');
75
76
  // NOTE: a stamp is retired by any tombstone that names it, verified or not — the same
76
77
  // reading `queryCadrePeers` and `getOwnerKeys` give the table. A forged tombstone can
@@ -80,7 +81,7 @@ export function deriveOwnerAnchor({ partyId, anchor, rows, tombstones, chain }:
80
81
  const liveRows = rows.filter(row => !retired.has(row.stampId));
81
82
 
82
83
  const derived = passStartSet(anchor, liveRows);
83
- const chainDerived = deriveFixpoint(partyId, derived, liveRows, chain);
84
+ const chainDerived = deriveFixpoint(partyId, derived, liveRows, grantChain);
84
85
 
85
86
  const removed = removedKeys(partyId, derived, chainDerived, ownerTombstones);
86
87
  if (removed.size > 0 && removed.size === derived.size) {
@@ -108,7 +109,7 @@ function passStartSet(anchor: ReadonlyMap<string, TrustSource>, liveRows: readon
108
109
  * trust only grows within a pass, and a proof that failed against a trusted voucher cannot
109
110
  * pass later, so no row is verified twice.
110
111
  */
111
- function deriveFixpoint(partyId: string, derived: Set<string>, liveRows: readonly OwnerKeyRow[], chain: InvitationChain | null): Set<string> {
112
+ function deriveFixpoint(partyId: string, derived: Set<string>, liveRows: readonly OwnerKeyRow[], grantChain: OwnerGrantChain | null): Set<string> {
112
113
  const chainDerived = new Set<string>();
113
114
  const pending = new Set(liveRows);
114
115
  let progress = true;
@@ -119,7 +120,7 @@ function deriveFixpoint(partyId: string, derived: Set<string>, liveRows: readonl
119
120
  continue;
120
121
  }
121
122
  pending.delete(row);
122
- if (proofVerifies(partyId, row, derived, chain)) {
123
+ if (proofVerifies(partyId, row, derived, grantChain)) {
123
124
  chainDerived.add(row.key);
124
125
  derived.add(row.key);
125
126
  progress = true;
@@ -130,22 +131,22 @@ function deriveFixpoint(partyId: string, derived: Set<string>, liveRows: readonl
130
131
  }
131
132
 
132
133
  /** Does `row`'s stored proof verify against `trusted`, for `partyId`, by the kind of proof it carries (see the module doc)? */
133
- function proofVerifies(partyId: string, row: OwnerKeyRow, trusted: ReadonlySet<string>, chain: InvitationChain | null): boolean {
134
+ function proofVerifies(partyId: string, row: OwnerKeyRow, trusted: ReadonlySet<string>, grantChain: OwnerGrantChain | null): boolean {
134
135
  if (row.vouchOwner === null) {
135
136
  return false;
136
137
  }
137
138
  if (row.vouchSig !== null) {
138
- return verifyOwnerKeyVoucher(partyId, row.key, row.stampId, row.vouchOwner, row.vouchSig);
139
+ return verifyOwnerKeyVoucher(partyId, row.key, row.label, row.stampId, row.vouchOwner, row.vouchSig);
139
140
  }
140
141
  if (row.vouchUsage === null) {
141
142
  return false;
142
143
  }
143
- const usage = chain?.usages.get(row.vouchUsage);
144
- const invite = usage === undefined ? undefined : chain?.invites.get(usage.inviteKey);
145
- if (usage === undefined || invite === undefined) {
144
+ const grantUsage = grantChain?.usages.get(row.vouchUsage);
145
+ const grant = grantUsage === undefined ? undefined : grantChain?.grants.get(grantUsage.grantKey);
146
+ if (grantUsage === undefined || grant === undefined) {
146
147
  return false;
147
148
  }
148
- return verifyInvitationOwnerAdmission(partyId, row, usage, invite, key => trusted.has(key));
149
+ return verifyOwnerGrantAdmission(partyId, row, grantUsage, grant, (key) => trusted.has(key));
149
150
  }
150
151
 
151
152
  /**