@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,110 @@
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 = 15000;
28
+ /**
29
+ * Optimystic's lazy read-repair window (`clusterPolicy.readRepairWindowMs`, which cadre does
30
+ * not set, so this is Optimystic's default): a read of a held block checked less than this
31
+ * long ago is served from the local copy without asking the cohort. A read after it is
32
+ * served locally too, but starts a cohort consult whose landing raises a table change.
33
+ *
34
+ * NOTE: a copy, since db-p2p exports no default for it. If cadre ever sets
35
+ * `readRepairWindowMs` in its cluster policy, derive this from that value.
36
+ */
37
+ const OPTIMYSTIC_READ_REPAIR_WINDOW_MS = 10000;
38
+ /**
39
+ * How long after a sibling becomes reachable (its identify on a new connection) `CadreNode`
40
+ * drops the views a second time: one read-repair window, plus a second for timer slop. The
41
+ * drop at the identify is not enough by itself. A node's reads before the sibling arrived
42
+ * (its start pass, with no cohort to ask) stamp the window, so the reload the identify
43
+ * starts is served from the local copy without a consult and the view would keep the
44
+ * pre-connection rows until {@link MEMBERSHIP_VIEW_MAX_AGE_MS}. The reload past the window
45
+ * starts the consults that bring in what the sibling committed while this node was away.
46
+ */
47
+ export const MEMBERSHIP_VIEW_RECONNECT_RELOAD_MS = OPTIMYSTIC_READ_REPAIR_WINDOW_MS + 1000;
48
+ export class MembershipView {
49
+ constructor(loader, options = {}) {
50
+ this.loader = loader;
51
+ /** When the load that produced {@link rows} started: the rows are no older than this. */
52
+ this.loadedAt = 0;
53
+ /** Bumped by every {@link invalidate}; a load installs only if it is unchanged since the load began. */
54
+ this.generation = 0;
55
+ /**
56
+ * The load each `retry` flag's callers share, current generation only. Separate per flag
57
+ * so a caller under the write lock never awaits a retrying load's backoff sleep.
58
+ */
59
+ this.inFlight = new Map();
60
+ this.maxAgeMs = options.maxAgeMs ?? MEMBERSHIP_VIEW_MAX_AGE_MS;
61
+ this.now = options.now ?? (() => performance.now());
62
+ }
63
+ /**
64
+ * The table's rows: the installed copy while it is younger than the maximum age, otherwise a
65
+ * load, shared with every caller of the same `retry` flag that arrives while it runs. A load
66
+ * that raced an {@link invalidate} answers its own callers with what it read, as an uncached
67
+ * read would have, and keeps nothing. A failed load keeps nothing and rejects.
68
+ */
69
+ read(retry) {
70
+ if (this.rows !== undefined && this.now() - this.loadedAt < this.maxAgeMs) {
71
+ return Promise.resolve(this.rows);
72
+ }
73
+ return this.inFlight.get(retry) ?? this.startLoad(retry);
74
+ }
75
+ /** Read the table without serving, joining or keeping anything. */
76
+ async readThrough(retry) {
77
+ return (await this.loader(retry)).rows;
78
+ }
79
+ /**
80
+ * Drop the installed rows and every load in flight, so the next read loads afresh and no
81
+ * earlier load installs. Synchronous and flag-setting only: the table-change handler calls
82
+ * it inside the committing call.
83
+ */
84
+ invalidate() {
85
+ this.generation++;
86
+ this.rows = undefined;
87
+ this.inFlight.clear();
88
+ }
89
+ startLoad(retry) {
90
+ const load = this.load(retry, this.generation, this.now());
91
+ this.inFlight.set(retry, load);
92
+ const forget = () => {
93
+ if (this.inFlight.get(retry) === load) {
94
+ this.inFlight.delete(retry);
95
+ }
96
+ };
97
+ // Both arms handled, so a failed load rejects only for the callers awaiting it.
98
+ void load.then(forget, forget);
99
+ return load;
100
+ }
101
+ async load(retry, generation, startedAt) {
102
+ const { rows, installable } = await this.loader(retry);
103
+ if (installable && generation === this.generation) {
104
+ this.rows = rows;
105
+ this.loadedAt = startedAt;
106
+ }
107
+ return rows;
108
+ }
109
+ }
110
+ //# sourceMappingURL=membership-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"membership-view.js","sourceRoot":"","sources":["../src/membership-view.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,KAAM,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,gCAAgC,GAAG,KAAM,CAAC;AAEhD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAAG,gCAAgC,GAAG,IAAK,CAAC;AA0B5F,MAAM,OAAO,cAAc;IAc1B,YAA6B,MAAiC,EAAE,UAAiC,EAAE;QAAtE,WAAM,GAAN,MAAM,CAA2B;QAZ9D,yFAAyF;QACjF,aAAQ,GAAG,CAAC,CAAC;QACrB,wGAAwG;QAChG,eAAU,GAAG,CAAC,CAAC;QACvB;;;WAGG;QACc,aAAQ,GAAG,IAAI,GAAG,EAAoC,CAAC;QAKvE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,0BAA0B,CAAC;QAC/D,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;IACrD,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,KAAc;QAClB,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC3E,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC;IAED,mEAAmE;IACnE,KAAK,CAAC,WAAW,CAAC,KAAc;QAC/B,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACxC,CAAC;IAED;;;;OAIG;IACH,UAAU;QACT,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAEO,SAAS,CAAC,KAAc;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,GAAS,EAAE;YACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;gBACvC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC;QACF,CAAC,CAAC;QACF,gFAAgF;QAChF,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,KAAc,EAAE,UAAkB,EAAE,SAAiB;QACvE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvD,IAAI,WAAW,IAAI,UAAU,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YACnD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CACD"}
@@ -1,5 +1,5 @@
1
1
  import type { TrustSource } from './trusted-owner-store.js';
2
- import type { InvitationChain, OwnerKeyRow, RevocationRow } from './types.js';
2
+ import type { OwnerGrantChain, OwnerKeyRow, RevocationRow } from './types.js';
3
3
  export interface OwnerAnchorInputs {
4
4
  /** 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. */
5
5
  partyId: string;
@@ -9,8 +9,8 @@ export interface OwnerAnchorInputs {
9
9
  rows: readonly OwnerKeyRow[];
10
10
  /** `Revocation` rows; only those with `tableName === 'OwnerKey'` are consulted. */
11
11
  tombstones: readonly RevocationRow[];
12
- /** The usage and invitation rows, when some owner row is invitation-admitted; null skips those rows. */
13
- chain: InvitationChain | null;
12
+ /** The usage and grant rows, when some owner row is grant-seated; null when none is, which skips every consent-seated row. */
13
+ grantChain: OwnerGrantChain | null;
14
14
  }
15
15
  export interface OwnerAnchorDerivation {
16
16
  /** The keys the anchor should hold after this pass. */
@@ -19,4 +19,4 @@ export interface OwnerAnchorDerivation {
19
19
  refusedRemovals: readonly string[];
20
20
  }
21
21
  /** The rule above, as one pure function. */
22
- export declare function deriveOwnerAnchor({ partyId, anchor, rows, tombstones, chain }: OwnerAnchorInputs): OwnerAnchorDerivation;
22
+ export declare function deriveOwnerAnchor({ partyId, anchor, rows, tombstones, grantChain }: OwnerAnchorInputs): OwnerAnchorDerivation;
@@ -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
  /** The rule above, as one pure function. */
50
- export function deriveOwnerAnchor({ partyId, anchor, rows, tombstones, chain }) {
51
+ export function deriveOwnerAnchor({ partyId, anchor, rows, tombstones, grantChain }) {
51
52
  const ownerTombstones = tombstones.filter(tombstone => tombstone.tableName === 'OwnerKey');
52
53
  // NOTE: a stamp is retired by any tombstone that names it, verified or not — the same
53
54
  // reading `queryCadrePeers` and `getOwnerKeys` give the table. A forged tombstone can
@@ -56,7 +57,7 @@ export function deriveOwnerAnchor({ partyId, anchor, rows, tombstones, chain })
56
57
  const retired = new Set(ownerTombstones.map(tombstone => tombstone.stampId));
57
58
  const liveRows = rows.filter(row => !retired.has(row.stampId));
58
59
  const derived = passStartSet(anchor, liveRows);
59
- const chainDerived = deriveFixpoint(partyId, derived, liveRows, chain);
60
+ const chainDerived = deriveFixpoint(partyId, derived, liveRows, grantChain);
60
61
  const removed = removedKeys(partyId, derived, chainDerived, ownerTombstones);
61
62
  if (removed.size > 0 && removed.size === derived.size) {
62
63
  return { target: derived, refusedRemovals: Array.from(removed) };
@@ -81,7 +82,7 @@ function passStartSet(anchor, liveRows) {
81
82
  * trust only grows within a pass, and a proof that failed against a trusted voucher cannot
82
83
  * pass later, so no row is verified twice.
83
84
  */
84
- function deriveFixpoint(partyId, derived, liveRows, chain) {
85
+ function deriveFixpoint(partyId, derived, liveRows, grantChain) {
85
86
  const chainDerived = new Set();
86
87
  const pending = new Set(liveRows);
87
88
  let progress = true;
@@ -92,7 +93,7 @@ function deriveFixpoint(partyId, derived, liveRows, chain) {
92
93
  continue;
93
94
  }
94
95
  pending.delete(row);
95
- if (proofVerifies(partyId, row, derived, chain)) {
96
+ if (proofVerifies(partyId, row, derived, grantChain)) {
96
97
  chainDerived.add(row.key);
97
98
  derived.add(row.key);
98
99
  progress = true;
@@ -102,22 +103,22 @@ function deriveFixpoint(partyId, derived, liveRows, chain) {
102
103
  return chainDerived;
103
104
  }
104
105
  /** Does `row`'s stored proof verify against `trusted`, for `partyId`, by the kind of proof it carries (see the module doc)? */
105
- function proofVerifies(partyId, row, trusted, chain) {
106
+ function proofVerifies(partyId, row, trusted, grantChain) {
106
107
  if (row.vouchOwner === null) {
107
108
  return false;
108
109
  }
109
110
  if (row.vouchSig !== null) {
110
- return verifyOwnerKeyVoucher(partyId, row.key, row.stampId, row.vouchOwner, row.vouchSig);
111
+ return verifyOwnerKeyVoucher(partyId, row.key, row.label, row.stampId, row.vouchOwner, row.vouchSig);
111
112
  }
112
113
  if (row.vouchUsage === null) {
113
114
  return false;
114
115
  }
115
- const usage = chain?.usages.get(row.vouchUsage);
116
- const invite = usage === undefined ? undefined : chain?.invites.get(usage.inviteKey);
117
- if (usage === undefined || invite === undefined) {
116
+ const grantUsage = grantChain?.usages.get(row.vouchUsage);
117
+ const grant = grantUsage === undefined ? undefined : grantChain?.grants.get(grantUsage.grantKey);
118
+ if (grantUsage === undefined || grant === undefined) {
118
119
  return false;
119
120
  }
120
- return verifyInvitationOwnerAdmission(partyId, row, usage, invite, key => trusted.has(key));
121
+ return verifyOwnerGrantAdmission(partyId, row, grantUsage, grant, (key) => trusted.has(key));
121
122
  }
122
123
  /**
123
124
  * The keys of `derived` that a verifiable tombstone removes (see the module doc), every
@@ -1 +1 @@
1
- {"version":3,"file":"owner-anchor-sync.js","sourceRoot":"","sources":["../src/owner-anchor-sync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"owner-anchor-sync.js","sourceRoot":"","sources":["../src/owner-anchor-sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Owner grant redemption transport: `/sereus/owner-grant/1.0.0`.
3
+ *
4
+ * A holder of an owner grant (an owner-signed `OwnerGrant` row plus the private half of the
5
+ * grant keypair, see {@link OwnerGrantBundle}) dials ANY member machine the grant names and
6
+ * proves possession of the grant and of the key it wants seated; the member seats the row if
7
+ * it does not hold it yet and writes the holder's `OwnerKey` row through
8
+ * `ControlDatabase.redeemOwnerGrant`. No machine is admitted and no peer id is named: the
9
+ * holder's network identity has nothing to do with the key it seats, so unlike the invitation
10
+ * protocol there is no connecting-identity check — both signatures already bind the grant, the
11
+ * nonce and the key. The owner that minted the grant need not be online.
12
+ *
13
+ * The exchange shape — one frame each way, the member's hardening and admission of the
14
+ * holder, the holder's address-by-address dialing in passes — is `member-redemption.ts`'s,
15
+ * shared with the invitation protocol; this module supplies the grant's bundle, request,
16
+ * checks, writes and refusal codes. Stranger-facing by design, classed `stranger-open` in
17
+ * `control-protocol-guard.ts`; the handler's own trust decision is the two signatures.
18
+ */
19
+ import type { Libp2p } from '@libp2p/interface';
20
+ import { type ControlDatabase } from './control-database.js';
21
+ import { MemberRedemptionHandler, type MemberRedemption, type MemberRedemptionHandlerOptions, type RedemptionAddressOutcome, type RedemptionRejection } from './member-redemption.js';
22
+ import type { OwnerSign } from './owner-signer.js';
23
+ import type { CadreJoinProgress, OwnerGrantRow } from './types.js';
24
+ /** Protocol id for owner grant redemption (parallel to `/sereus/cadre-invite/1.0.0`). */
25
+ export declare const OWNER_GRANT_PROTOCOL = "/sereus/owner-grant/1.0.0";
26
+ /**
27
+ * What an owner hands out (QR, paste, file) and a holder redeems. A grant is an ed25519
28
+ * keypair: the row holds the public half, `grantPrivateKey` is the proof of possession, and
29
+ * whoever holds this bundle can become an owner of the party — a bearer credential for admin
30
+ * rights for the row's lifetime (15 minutes by default; a backup grant has no expiry and is
31
+ * kept as carefully as an owner key).
32
+ *
33
+ * Carrying the signed row is what makes redemption work at a member that has not received
34
+ * the row by replication: the member seats it from the bundle under its stored issuer
35
+ * signature. The row's own signature covers every column, so a bundle whose row was altered
36
+ * cannot be seated anywhere. `members` are the party's addresses at mint time, so a backup
37
+ * grant can go stale if every member's address changes.
38
+ */
39
+ export interface OwnerGrantBundle {
40
+ v: 1;
41
+ /** The cadre the grant makes an owner of; a holder refuses one for another party. */
42
+ partyId: string;
43
+ /** The grant's ed25519 seed, base64url: the proof of possession. */
44
+ grantPrivateKey: string;
45
+ /** The owner-signed row exactly as issued (`ControlDatabase.insertOwnerGrant`). */
46
+ grant: OwnerGrantRow;
47
+ /**
48
+ * The issuer's anchored owner keys. The holder pins them before it dials
49
+ * (`CadreNode.trustOwnerKeys`) and checks the member's reply against them. Sourced from the
50
+ * issuer's node-local anchor only, never the replicated `OwnerKey` table, for the reason the
51
+ * invitation gives: the holder anchors whatever arrives here.
52
+ */
53
+ ownerKeys: string[];
54
+ /** As `CadreInvitation.members`: multiaddrs ending in `/p2p/<peerId>`, the issuer's first, at most six in all. */
55
+ members: string[];
56
+ }
57
+ /**
58
+ * Encode a bundle for out-of-band delivery: {@link OWNER_GRANT_PREFIX}, then base64url over
59
+ * JSON. The prefix lets an app tell a grant from an invitation, a join request or an owner key
60
+ * and name the mistake when one is pasted for the other.
61
+ */
62
+ export declare function encodeOwnerGrant(bundle: OwnerGrantBundle): string;
63
+ /**
64
+ * Decode a bundle, refusing anything that is not a well-formed version-1
65
+ * {@link OwnerGrantBundle} behind {@link OWNER_GRANT_PREFIX}. Standalone, like
66
+ * `decodeCadreInvitation`, so a client without a node can decode one.
67
+ *
68
+ * @throws on an owner key, a cadre invitation or a join request, a string without the prefix
69
+ * or that is not base64url JSON after it, or one that decodes to another shape or version.
70
+ */
71
+ export declare function decodeOwnerGrant(encoded: string): OwnerGrantBundle;
72
+ /** Is `value` an {@link OwnerGrantRow} with every column in its stored form and bounded? */
73
+ export declare function isWellFormedOwnerGrantRow(value: unknown): value is OwnerGrantRow;
74
+ /** Holder → member: one frame, the whole redemption. */
75
+ export interface OwnerGrantRedeemRequest {
76
+ v: 1;
77
+ /** The cadre the holder believes it is becoming an owner of; a machine serving another party refuses by name. */
78
+ partyId: string;
79
+ /** The owner-signed row from the bundle. */
80
+ grant: OwnerGrantRow;
81
+ /** The ed25519 public key to seat as an owner, base64url: the holder's, fresh or already held. */
82
+ ownerKey: string;
83
+ /** Single-use nonce the holder minted (`generateStampId`); both signatures cover it. */
84
+ usageStampId: string;
85
+ /** By `grantPrivateKey` over the `'redeem'` digest. */
86
+ grantSig: string;
87
+ /** By `ownerKey` over the `'consent'` digest. */
88
+ ownerSig: string;
89
+ }
90
+ /**
91
+ * Why a member refused a redemption: the invitation's codes with grant wording. Retryability
92
+ * is {@link OWNER_GRANT_REJECTION_RETRYABLE}'s; a retryable code moves the holder to the next
93
+ * address the bundle names.
94
+ */
95
+ export type OwnerGrantRejectionCode =
96
+ /** The issuer's `OwnerKey` row is not on this member (not replicated yet), or the issuer was removed; the member cannot tell which. */
97
+ 'issuer-unknown'
98
+ /** A signature does not verify, or the request or the row is malformed. */
99
+ | 'grant-invalid'
100
+ /** Expired, withdrawn, exhausted, or issued by a key that is no longer an owner here. */
101
+ | 'grant-spent'
102
+ /** This machine serves another cadre than the one the grant names. */
103
+ | 'party-mismatch'
104
+ /** The member is at its cap on concurrent redemptions. */
105
+ | 'busy'
106
+ /** The write failed transiently (the write retry gave up), or the member has not synced the grant row the cadre holds; nothing was recorded. */
107
+ | 'conflict'
108
+ /** An unexpected member-side failure, or a request frame the member could not read: nothing was proved either way. */
109
+ | 'internal';
110
+ /** Which refusals are worth repeating at the next address — the one place that says so. */
111
+ export declare const OWNER_GRANT_REJECTION_RETRYABLE: Readonly<Record<OwnerGrantRejectionCode, boolean>>;
112
+ /** Is `value` a code this build knows? Own keys only, so a peer's `'constructor'` does not pass. */
113
+ export declare function isOwnerGrantRejectionCode(value: unknown): value is OwnerGrantRejectionCode;
114
+ /** Member → holder. No dial hints: the holder is not joining the cadre's network, only seating a key. */
115
+ export interface OwnerGrantRedeemReply {
116
+ accepted: boolean;
117
+ /** Present iff `!accepted`. */
118
+ code?: OwnerGrantRejectionCode;
119
+ /** Human-facing text; present iff `!accepted`. */
120
+ reason?: string;
121
+ /** The member's party id; present iff `accepted`. */
122
+ partyId?: string;
123
+ /** The grant row as this member holds it; present iff `accepted`. */
124
+ grant?: OwnerGrantRow;
125
+ /** The key was already a live owner here, so nothing was written and no use was spent; present iff `accepted`. */
126
+ alreadyOwner?: boolean;
127
+ }
128
+ /** An accepting reply, every optional field present. */
129
+ export interface OwnerGrantAccepted extends OwnerGrantRedeemReply {
130
+ accepted: true;
131
+ partyId: string;
132
+ grant: OwnerGrantRow;
133
+ alreadyOwner: boolean;
134
+ }
135
+ type OwnerGrantRejection = RedemptionRejection<OwnerGrantRejectionCode>;
136
+ /**
137
+ * A member answered and refused (on `CadreNode.redeemOwnerGrant`'s local path, the member is
138
+ * this node). `code` is `'unrecognized'` when the frame carried none this build knows, and such
139
+ * a refusal counts as retryable, as the invitation's does.
140
+ */
141
+ export declare class OwnerGrantRejectedError extends Error {
142
+ readonly code: OwnerGrantRejectionCode | 'unrecognized';
143
+ readonly reason: string;
144
+ readonly retryable: boolean;
145
+ /** Both arguments come straight off the wire, so neither is trusted to have its declared type. */
146
+ constructor(code: unknown, reason: unknown);
147
+ }
148
+ /** Every address the bundle names was tried and none accepted. Always retryable; `outcomes` says what each address did. */
149
+ export declare class OwnerGrantUnreachableError extends Error {
150
+ readonly outcomes: readonly RedemptionAddressOutcome[];
151
+ readonly retryable = true;
152
+ constructor(outcomes: readonly RedemptionAddressOutcome[]);
153
+ }
154
+ /**
155
+ * A member accepted but its reply does not check out: another party id, another grant key, or
156
+ * a row not signed by one of the pinned owner keys. Final, for the invitation's reason: such a
157
+ * machine is not a member of the cadre the grant names.
158
+ */
159
+ export declare class OwnerGrantReplyInvalidError extends Error {
160
+ readonly retryable = false;
161
+ constructor(message: string);
162
+ }
163
+ /**
164
+ * Build and sign the request for `bundle`: the holder's `'redeem'` signature with the grant's
165
+ * private key (held in memory for the length of this call) and the seated key's `'consent'`
166
+ * signature through `signConsent`, the `sign` of an open owner approval on the signer that
167
+ * holds `ownerKey`; both over (grant key, `usageStampId`, `ownerKey`) for the grant's party. The
168
+ * same bytes the schema verifies at the member (`ownerGrantRedeemMessage` /
169
+ * `ownerGrantConsentMessage`), and the same request goes to every member and every pass.
170
+ */
171
+ export declare function signOwnerGrantRequest(bundle: OwnerGrantBundle, ownerKey: string, signConsent: OwnerSign, usageStampId: string): Promise<OwnerGrantRedeemRequest>;
172
+ /**
173
+ * The holder's check on an acceptance: the same party, the same grant key, and a row signed by
174
+ * an issuer the holder pinned from the bundle. Throws {@link OwnerGrantReplyInvalidError} naming
175
+ * the first failure. Bounded as `verifyRedeemReply` is: it catches a wrong-party or wrong-row
176
+ * answer, not a forged member, which the holder's anchor settles once its store syncs.
177
+ */
178
+ export declare function verifyOwnerGrantReply(reply: OwnerGrantAccepted, bundle: OwnerGrantBundle, isTrustedIssuer: (ownerKey: string) => boolean): void;
179
+ /** The control-database surface a redemption needs; a `ControlDatabase` satisfies it. */
180
+ export type OwnerGrantStore = Pick<ControlDatabase, 'queryOwnerGrant' | 'seatOwnerGrant' | 'isOwnerGrantLive' | 'redeemOwnerGrant'>;
181
+ export interface OwnerGrantHandlerOptions extends MemberRedemptionHandlerOptions {
182
+ store: OwnerGrantStore;
183
+ }
184
+ /**
185
+ * Member side of the grant protocol (`MemberRedemptionHandler` has the shape): after the
186
+ * request's shape, it checks the party and both signatures — nothing about the connecting
187
+ * peer, whose identity is unrelated to the key it seats — then seats the row from the bundle
188
+ * when this member holds none and redeems. An issuer this member does not know as an owner is
189
+ * the one retryable refusal left: the holder tries the next address, which may hold the
190
+ * issuer's row.
191
+ */
192
+ export declare class OwnerGrantHandler extends MemberRedemptionHandler<OwnerGrantRedeemRequest, OwnerGrantRedeemReply, OwnerGrantRow> {
193
+ private readonly store;
194
+ protected readonly busyRefusal: RedemptionRejection<"busy">;
195
+ protected readonly internalRefusal: RedemptionRejection<"internal">;
196
+ protected readonly malformedRefusal: RedemptionRejection<"grant-invalid">;
197
+ constructor(options: OwnerGrantHandlerOptions);
198
+ protected isWellFormedRequest(value: unknown): value is OwnerGrantRedeemRequest;
199
+ protected checkRequest(request: OwnerGrantRedeemRequest): OwnerGrantRejection | null;
200
+ protected readHeld(request: OwnerGrantRedeemRequest): Promise<OwnerGrantRow | null>;
201
+ protected isLive(request: OwnerGrantRedeemRequest, held: OwnerGrantRow | null): Promise<boolean>;
202
+ /** The two writes — the seat only when this member holds no row, and the redemption, carrying the held row — as `CadreInviteHandler.redeemAdmitted`. */
203
+ protected redeemAdmitted(request: OwnerGrantRedeemRequest, remotePeerId: string, held: OwnerGrantRow | null): Promise<OwnerGrantRedeemReply>;
204
+ /** Seat the bundle's copy of the row; a refusal answered by name, or null once it is held. */
205
+ private seat;
206
+ }
207
+ export interface RedeemOwnerGrantAtMembersOptions {
208
+ /** The bundle: its `members` are dialed in order. */
209
+ bundle: OwnerGrantBundle;
210
+ /** The signed request ({@link signOwnerGrantRequest}); the same one goes to every address. */
211
+ request: OwnerGrantRedeemRequest;
212
+ /** Is this owner key one the holder pinned from the bundle? The reply check's input. */
213
+ isTrustedIssuer: (ownerKey: string) => boolean;
214
+ /** See `MemberRedemptionOptions.linkRoundTripMs`. */
215
+ linkRoundTripMs?: number;
216
+ /** Per-address deadline override; default derived from `linkRoundTripMs`. */
217
+ addressBudgetMs?: number;
218
+ protocolId?: string;
219
+ /** Cancels the dial or stream in flight and ends the pass; the call throws the signal's reason. */
220
+ signal?: AbortSignal;
221
+ }
222
+ /** What a successful redemption yields the holder. */
223
+ export type OwnerGrantRedemption = MemberRedemption<OwnerGrantAccepted>;
224
+ /**
225
+ * Holder side: try the bundle's addresses one at a time and stop at the first acceptance or
226
+ * the first final refusal (`dialRedemption` in `member-redemption.ts`). Every address gets the
227
+ * SAME request, with one `usageStampId`: `OwnerGrantUsage` is keyed by it, so a member the
228
+ * holder gave up on that was still committing cannot spend a second use, and a retry after a
229
+ * dropped reply is answered `alreadyOwner`.
230
+ *
231
+ * @throws {OwnerGrantRejectedError} on a final refusal (its `retryable` is false).
232
+ * @throws {OwnerGrantReplyInvalidError} on an acceptance that fails {@link verifyOwnerGrantReply}.
233
+ * @throws {OwnerGrantUnreachableError} when every address was tried and none accepted.
234
+ * @throws the reason of `options.signal` once it aborts.
235
+ */
236
+ export declare function redeemOwnerGrantAtMembers(node: Libp2p, options: RedeemOwnerGrantAtMembersOptions): Promise<OwnerGrantRedemption>;
237
+ export interface RedeemOwnerGrantInPassesOptions extends RedeemOwnerGrantAtMembersOptions {
238
+ /** Keep making passes while every answer is retryable; false makes exactly one. */
239
+ waitForMember: boolean;
240
+ /** Called at each pass and each pause; an exception it throws is logged and ignored. */
241
+ onProgress?: (progress: CadreJoinProgress) => void;
242
+ }
243
+ /**
244
+ * Holder side, in passes (`dialRedemptionInPasses` in `member-redemption.ts`): one
245
+ * {@link redeemOwnerGrantAtMembers} pass, or, with `waitForMember`, as many as it takes,
246
+ * pausing between them and never past the grant's expiry, which by this holder's clock is
247
+ * thrown as the `grant-spent` refusal a member would give. A backup grant has no expiry, so a
248
+ * wait on one ends only by acceptance, a final refusal, the signal or the node stopping.
249
+ */
250
+ export declare function redeemOwnerGrantInPasses(node: Libp2p, options: RedeemOwnerGrantInPassesOptions): Promise<OwnerGrantRedemption>;
251
+ export {};