@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
@@ -2,15 +2,14 @@ import debug from 'debug';
2
2
  import { FormationAbortedError, InvitationExhaustedError } from './control-database.js';
3
3
  import { mintStrandId } from './strand-id.js';
4
4
  import { createHttpFormationApprover, verifyFormationApproval, FormationApprovalError } from './formation-approval.js';
5
+ import { isInviteExpired } from './formation-token.js';
5
6
  const log = debug('sereus:cadre:formation-recorder');
6
- /** Far-future sentinel for an invitation that never expires (max valid JS Date). */
7
- const NEVER_EXPIRES = new Date(8640000000000000);
8
7
  /**
9
8
  * {@link FormationUsageRecorder} backed by the real `CadreControl` tables.
10
9
  *
11
- * It reads `FormationInvite` / `FormationUsage` to answer token-validity and
12
- * usage questions, and writes the consent row that records a redemption. Two
13
- * provisioning shapes are supported, keyed on whether the invite binds a host strand:
10
+ * It reads a session's token once ({@link readToken}: the `FormationInvite` row and its
11
+ * `FormationUsage` count), and writes the consent row that records a redemption from that
12
+ * read. Two provisioning shapes are supported, keyed on whether the invite binds a host strand:
14
13
  *
15
14
  * - **Bound (provision-then-record):** the host strand already exists (owner-signed
16
15
  * up front and named by the invite's `StrandId`), so {@link resolveStrand} reports it
@@ -48,38 +47,21 @@ export class ControlFormationUsageRecorder {
48
47
  this.controlDatabase = controlDatabase;
49
48
  this.approver = options?.approver ?? createHttpFormationApprover();
50
49
  }
51
- /** A token is valid when a matching, unexpired `FormationInvite` exists. */
52
- async isTokenValid(token) {
53
- const invite = await this.controlDatabase.queryFormationInvite(token);
54
- if (!invite) {
55
- return { valid: false, reason: 'unknown' };
56
- }
57
- if (invite.expiresAtMs !== null && invite.expiresAtMs <= Date.now()) {
58
- log('Token expired: %s', token);
59
- return { valid: false, reason: 'expired' };
60
- }
61
- return {
62
- valid: true,
63
- invitation: {
64
- token: invite.token,
65
- sAppId: invite.sAppId,
66
- expiration: invite.expiresAtMs !== null ? new Date(invite.expiresAtMs) : NEVER_EXPIRES,
67
- bootstrap: [],
68
- },
69
- };
70
- }
71
50
  /**
72
- * A token is "used" when its recorded usage count has reached the invite's
73
- * `TotalUses`. A null `TotalUses` (unlimited) is never used up; an unknown
74
- * token is reported not-used (validity is handled by {@link isTokenValid}).
51
+ * One `FormationInvite` read, then one `FormationUsage` count only when the invite is
52
+ * metered (`TotalUses` set) and unexpired: an unknown, expired or unlimited token has no
53
+ * seat to count. This early count refuses a spent token before anything costly (the outside
54
+ * approval call, the strand-database write that issues the membership invite); the count
55
+ * inside the write lock decides.
75
56
  */
76
- async isTokenUsed(token) {
57
+ async readToken(token) {
77
58
  const invite = await this.controlDatabase.queryFormationInvite(token);
78
- if (!invite || invite.totalUses === null) {
79
- return false;
80
- }
81
- const uses = await this.controlDatabase.countFormationUsage(token);
82
- return uses >= invite.totalUses;
59
+ const metered = invite !== null && invite.totalUses !== null && !isInviteExpired(invite, Date.now());
60
+ return {
61
+ token,
62
+ invite,
63
+ usesRecorded: metered ? await this.controlDatabase.countFormationUsage(token) : null,
64
+ };
83
65
  }
84
66
  /**
85
67
  * Any `FormationInvite` row still unexpired and not fully consumed — the
@@ -157,66 +139,79 @@ export class ControlFormationUsageRecorder {
157
139
  * spent on AND provably the joiner that agreed. Use
158
140
  * {@link ControlDatabase.redeemInvitation} for the consent-creates-strand path instead.
159
141
  *
160
- * Authorizes ({@link authorizeUsage}) and writes in one step, for callers with nothing to do
161
- * in between.
142
+ * Reads the invite for itself (it is handed no session read) and the strand's stamp inside
143
+ * `recordFormationUsage`; otherwise authorizes as {@link authorizeUsage} does and writes in
144
+ * one step, for callers with nothing to do in between.
162
145
  */
163
146
  async recordUsage(params) {
164
- await (await this.authorizeUsage(params)).record();
147
+ if (params.signal?.aborted) {
148
+ throw new FormationAbortedError(params.token, 'usage recording');
149
+ }
150
+ const invite = await this.controlDatabase.queryFormationInvite(params.token);
151
+ await (await this.authorize(params, invite, undefined)).record();
165
152
  }
166
153
  /**
167
154
  * Everything {@link recordUsage} does before its write, so the manager can issue the
168
155
  * joiner's membership pass into the host strand only once the redemption is cleared, and
169
- * spend the token only after that.
170
- *
171
- * Reads the invite first (one extra read per redemption) to learn its `ValidationUrl` and
172
- * seat budget, obtains the approval through {@link obtainApproval} when one is demanded,
173
- * re-checks the abort (the approval call may have been long), and pre-checks the seat
174
- * budget ({@link assertSeatFree}). The returned `record()` closes over the captured fields
175
- * and approval, so the nonce the approver signed is the nonce inserted without the caller
176
- * ever passing it back.
156
+ * spend the token only after that. Takes the invite's `ValidationUrl` and seat budget from
157
+ * the session's `read`, and the host strand's stamp from `host`, so it reads neither again.
177
158
  */
178
- async authorizeUsage(params) {
159
+ async authorizeUsage(params, read, host) {
160
+ return await this.authorize(params, read.invite, host.strandStampId);
161
+ }
162
+ /**
163
+ * Obtain the approval through {@link obtainApproval} when `invite` demands one, re-check the
164
+ * abort (the approval call may have been long), and after an obtained approval re-check the
165
+ * seat budget ({@link assertSeatFree}). The returned `record()` closes over the captured
166
+ * fields and approval, so the nonce the approver signed is the nonce inserted without the
167
+ * caller ever passing it back. `strandStampId` undefined makes `recordFormationUsage` read it.
168
+ */
169
+ async authorize(params, invite, strandStampId) {
179
170
  const { token, peerKey, peerSignature, usageStampId, strandId, disclosure, signal } = params;
180
171
  if (signal?.aborted) {
181
172
  throw new FormationAbortedError(token, 'usage recording');
182
173
  }
183
- const invite = await this.controlDatabase.queryFormationInvite(token);
184
174
  // NOTE: a missing invite row reads as "no approval required" here and in
185
- // `provisionAndRecord`, so an invite that vanished between `resolveStrand` and this read
186
- // would be written unapproved. Safe only because the database's `FormationUsage.Authorized`
187
- // CHECK demands a matching `FormationInvite` and rolls the write back regardless; if that
188
- // CHECK ever loosens, reject on `invite === null` instead of defaulting to null.
175
+ // `provisionAndRecord`, so an invite that was absent from the session's read (or vanished
176
+ // before `recordUsage`'s) would be written unapproved. Safe only because the database's
177
+ // `FormationUsage.Authorized` CHECK demands a matching `FormationInvite` and rolls the write
178
+ // back regardless; if that CHECK ever loosens, reject on `invite === null` instead of
179
+ // defaulting to null.
180
+ const validationUrl = invite?.validationUrl ?? null;
189
181
  const approval = await this.obtainApproval({
190
- token, usageStampId, strandId, peerKey, disclosure,
191
- validationUrl: invite?.validationUrl ?? null,
182
+ token, usageStampId, strandId, peerKey, disclosure, validationUrl,
192
183
  }, signal);
193
184
  if (signal?.aborted) {
194
185
  throw new FormationAbortedError(token, 'usage recording');
195
186
  }
196
187
  const totalUses = invite?.totalUses ?? null;
197
- await this.assertSeatFree(token, totalUses);
188
+ if (validationUrl !== null) {
189
+ await this.assertSeatFree(token, totalUses);
190
+ }
198
191
  return {
199
192
  record: async () => {
200
193
  await this.controlDatabase.recordFormationUsage({
201
194
  token, strandId, peerKey, peerSignature, usageStampId, disclosure, signal,
202
- totalUses, ...approval,
195
+ totalUses, strandStampId, ...approval,
203
196
  });
204
197
  log('Recorded formation usage: token=%s strand=%s', token, strandId);
205
198
  }
206
199
  };
207
200
  }
208
201
  /**
209
- * Refuse a redemption whose invite has no seat left, BEFORE anything is written — the
210
- * authoritative check is the one `recordFormationUsage` repeats inside its write lock.
211
- * Catches a same-node rival that took the last seat while this redemption waited on the
212
- * approval hook, which `runSession`'s up-front `isTokenUsed` check could not see.
202
+ * Refuse a redemption whose invite lost its last seat while this redemption waited on its
203
+ * outside approval, BEFORE anything is written — the authoritative check is the one
204
+ * `recordFormationUsage` repeats inside its write lock. Runs only after an obtained approval:
205
+ * that call is the one long wait between the session's early count (`readToken`) and the
206
+ * membership pass, in which a same-node rival could take the seat unseen.
213
207
  *
214
- * NOTE: two redemptions that both pass this check within the time one of them takes to
215
- * issue its membership pass still both issue one, and the loser's pass is orphaned
216
- * (expiry-bounded, never handed out). Holding the control write lock across issuance would
217
- * close it, but `lockedWithRetry` re-runs locked bodies on transient failures (a re-run
218
- * would double-issue) and every control write would stall behind a strand-database write.
219
- * If orphaned passes from same-node races ever matter, reserve the seat before issuance.
208
+ * NOTE: two redemptions that both pass the last count before issuance (this one after an
209
+ * approval, `readToken`'s without one) within the time one of them takes to issue its
210
+ * membership pass still both issue one, and the loser's pass is orphaned (expiry-bounded,
211
+ * never handed out). Holding the control write lock across issuance would close it, but
212
+ * `lockedWithRetry` re-runs locked bodies on transient failures (a re-run would double-issue)
213
+ * and every control write would stall behind a strand-database write. If orphaned passes from
214
+ * same-node races ever matter, reserve the seat before issuance.
220
215
  */
221
216
  async assertSeatFree(token, totalUses) {
222
217
  if (totalUses === null) {
@@ -228,29 +223,32 @@ export class ControlFormationUsageRecorder {
228
223
  }
229
224
  }
230
225
  /**
231
- * Classify the host strand this invite binds to (see {@link ResolvedHostStrand}):
226
+ * Classify the host strand the read invite binds to (see {@link ResolvedHostStrand}), with
227
+ * one `Strand` read and no invite read:
232
228
  *
233
229
  * - no invite / no `StrandId` → `unbound` (responder-provisions path).
234
- * - `StrandId` set AND the strand row is present → `bound`, carrying its
235
- * `MemberPrivateKey` (the closed-strand read-gating secret) for delivery to a
236
- * validated invitee.
230
+ * - `StrandId` set AND the strand row is present → `bound`, carrying its type, its
231
+ * `StampId` (which the consent row names) and its `MemberPrivateKey` (the closed-strand
232
+ * read-gating secret) for delivery to a validated invitee.
237
233
  * - `StrandId` set but the strand row is absent → `missing` (the host strand has not
238
234
  * converged on this responder yet); the manager rejects cleanly instead of recording
239
235
  * usage against a non-existent strand, which would fail the deferred `StrandExists`
240
236
  * CHECK at commit and drop the result frame.
241
237
  */
242
- async resolveStrand(token) {
243
- const invite = await this.controlDatabase.queryFormationInvite(token);
244
- if (!invite || !invite.strandId) {
238
+ async resolveStrand(read) {
239
+ const strandId = read.invite?.strandId;
240
+ if (!strandId) {
245
241
  return { kind: 'unbound' };
246
242
  }
247
- const strand = await this.controlDatabase.queryStrand(invite.strandId);
243
+ const strand = await this.controlDatabase.queryStrandWithStamp(strandId);
248
244
  if (!strand) {
249
- return { kind: 'missing', strandId: invite.strandId };
245
+ return { kind: 'missing', strandId };
250
246
  }
251
247
  return {
252
248
  kind: 'bound',
253
- strandId: invite.strandId,
249
+ strandId,
250
+ strandType: strand.Type,
251
+ strandStampId: strand.StampId,
254
252
  memberPrivateKey: strand.MemberPrivateKey ?? null,
255
253
  };
256
254
  }
@@ -269,7 +267,8 @@ export class ControlFormationUsageRecorder {
269
267
  *
270
268
  * The strand is open (`'o'`) — an unbound responder-provisioned strand has no membership
271
269
  * key — so the returned `memberPrivateKey` is null. `sAppId` is accepted for parity/future
272
- * use; `redeemInvitation` does not currently thread it into the `Strand` row.
270
+ * use; `redeemInvitation` does not currently thread it into the `Strand` row. The invite's
271
+ * `ValidationUrl` and seat budget come from the session's `read`.
273
272
  *
274
273
  * A concurrent redemption of the same single-use invite still THROWS for the loser — the
275
274
  * manager maps that to a clean protocol rejection (it never lets the dropped insert close
@@ -282,13 +281,13 @@ export class ControlFormationUsageRecorder {
282
281
  * removal), chosen over a fought-over shared key whose failure mode was the silent loss of
283
282
  * a consented join.
284
283
  */
285
- async provisionAndRecord(params) {
284
+ async provisionAndRecord(params, read) {
286
285
  const { token, peerKey, peerSignature, usageStampId, disclosure, signal } = params;
287
286
  if (signal?.aborted) {
288
287
  throw new FormationAbortedError(token, 'redemption');
289
288
  }
290
289
  const strandId = mintStrandId();
291
- const invite = await this.controlDatabase.queryFormationInvite(token);
290
+ const invite = read.invite;
292
291
  const approval = await this.obtainApproval({
293
292
  token, usageStampId, strandId, peerKey, disclosure,
294
293
  validationUrl: invite?.validationUrl ?? null,
@@ -1 +1 @@
1
- {"version":3,"file":"control-formation-recorder.js","sourceRoot":"","sources":["../src/control-formation-recorder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"control-formation-recorder.js","sourceRoot":"","sources":["../src/control-formation-recorder.ts"],"names":[],"mappings":"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"}
@@ -14,9 +14,10 @@
14
14
  *
15
15
  * ## The classes
16
16
  *
17
- * - `stranger-open` — seed delivery, strand formation, cadre-invitation redemption. Any peer;
18
- * each handler makes its own trust decision in-protocol (a seed signature against the
19
- * anchored trust policy, a formation token, an invitation's possession proof).
17
+ * - `stranger-open` — seed delivery, strand formation, cadre-invitation redemption, owner-grant
18
+ * redemption. Any peer; each handler makes its own trust decision in-protocol (a seed
19
+ * signature against the anchored trust policy, a formation token, an invitation's or a
20
+ * grant's possession proof).
20
21
  * - `transport` — libp2p plumbing (identify, ping, hole punching, AutoNAT, the circuit-relay
21
22
  * stop and hop protocols, WebRTC signaling). Every connection runs these, the redeeming
22
23
  * device's own included: refusing identify would make that device treat the member as
@@ -78,7 +79,7 @@
78
79
  import type { Libp2p } from '@libp2p/interface';
79
80
  /** What a peer must be to open a stream on a control-node protocol (see the module doc). */
80
81
  export type ControlProtocolClass =
81
- /** Any peer. The handler makes its own trust decision in-protocol (seed, formation, cadre-invite). */
82
+ /** Any peer. The handler makes its own trust decision in-protocol (seed, formation, cadre-invite, owner-grant). */
82
83
  'stranger-open'
83
84
  /** libp2p plumbing that a stranger's connection needs or that carries no party data. */
84
85
  | 'transport'
@@ -111,6 +112,12 @@ export declare class ControlStreamRefusedError extends Error {
111
112
  * storage scope key already does.
112
113
  */
113
114
  export declare function controlNetworkName(partyId: string): string;
115
+ /**
116
+ * Whether a peer whose protocol list is `protocols` serves the control database. Optimystic
117
+ * counts a peer into a control block's cohort by the same test (`servesThisNetwork` in db-p2p's
118
+ * `libp2p-key-network.ts`), before its membership check.
119
+ */
120
+ export declare function servesControlDatabase(partyId: string, protocols: readonly string[]): boolean;
114
121
  /**
115
122
  * The class of every protocol a control node serves, by exact protocol id: the single
116
123
  * declaration the guard enforces. See the module doc for what each class admits and why each
@@ -14,9 +14,10 @@
14
14
  *
15
15
  * ## The classes
16
16
  *
17
- * - `stranger-open` — seed delivery, strand formation, cadre-invitation redemption. Any peer;
18
- * each handler makes its own trust decision in-protocol (a seed signature against the
19
- * anchored trust policy, a formation token, an invitation's possession proof).
17
+ * - `stranger-open` — seed delivery, strand formation, cadre-invitation redemption, owner-grant
18
+ * redemption. Any peer; each handler makes its own trust decision in-protocol (a seed
19
+ * signature against the anchored trust policy, a formation token, an invitation's or a
20
+ * grant's possession proof).
20
21
  * - `transport` — libp2p plumbing (identify, ping, hole punching, AutoNAT, the circuit-relay
21
22
  * stop and hop protocols, WebRTC signaling). Every connection runs these, the redeeming
22
23
  * device's own included: refusing identify would make that device treat the member as
@@ -79,6 +80,7 @@ import debug from 'debug';
79
80
  import { SEED_PROTOCOL } from './seed-bootstrap.js';
80
81
  import { FORMATION_PROTOCOL } from './strand-formation-protocol.js';
81
82
  import { CADRE_INVITE_PROTOCOL } from './cadre-invite-protocol.js';
83
+ import { OWNER_GRANT_PROTOCOL } from './owner-grant-protocol.js';
82
84
  import { WAKE_PROTOCOL } from './strand-wake-protocol.js';
83
85
  import { STRAND_ADDR_PROTOCOL } from './strand-addr-protocol.js';
84
86
  import { withTimeout } from './control-stream.js';
@@ -113,6 +115,19 @@ export class ControlStreamRefusedError extends Error {
113
115
  export function controlNetworkName(partyId) {
114
116
  return `control-${partyId}`;
115
117
  }
118
+ /** The control database's two storage protocols, `repo` and `cluster`. */
119
+ function controlDatabaseProtocols(partyId) {
120
+ const prefix = `/optimystic/${controlNetworkName(partyId)}`;
121
+ return [`${prefix}/repo/1.0.0`, `${prefix}/cluster/1.0.0`];
122
+ }
123
+ /**
124
+ * Whether a peer whose protocol list is `protocols` serves the control database. Optimystic
125
+ * counts a peer into a control block's cohort by the same test (`servesThisNetwork` in db-p2p's
126
+ * `libp2p-key-network.ts`), before its membership check.
127
+ */
128
+ export function servesControlDatabase(partyId, protocols) {
129
+ return controlDatabaseProtocols(partyId).some((protocol) => protocols.includes(protocol));
130
+ }
116
131
  /**
117
132
  * The class of every protocol a control node serves, by exact protocol id: the single
118
133
  * declaration the guard enforces. See the module doc for what each class admits and why each
@@ -125,10 +140,10 @@ export function controlProtocolClasses(partyId) {
125
140
  [SEED_PROTOCOL, 'stranger-open'],
126
141
  [FORMATION_PROTOCOL, 'stranger-open'],
127
142
  [CADRE_INVITE_PROTOCOL, 'stranger-open'],
143
+ [OWNER_GRANT_PROTOCOL, 'stranger-open'],
128
144
  [WAKE_PROTOCOL, 'members'],
129
145
  [STRAND_ADDR_PROTOCOL, 'members'],
130
- [`${prefix}/repo/1.0.0`, 'members-snapshot'],
131
- [`${prefix}/cluster/1.0.0`, 'members-snapshot'],
146
+ ...controlDatabaseProtocols(partyId).map((protocol) => [protocol, 'members-snapshot']),
132
147
  [`${prefix}/db-p2p/sync/1.0.0`, 'members-snapshot'],
133
148
  [`${prefix}/db-p2p/block-transfer/1.0.0`, 'members-snapshot'],
134
149
  [`${fret}/neighbors`, 'members-snapshot'],
@@ -1 +1 @@
1
- {"version":3,"file":"control-protocol-guard.js","sourceRoot":"","sources":["../src/control-protocol-guard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"control-protocol-guard.js","sourceRoot":"","sources":["../src/control-protocol-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * control-schema-version.ts — the check `ControlDatabase.loadSchema` runs on a warm control
3
+ * store after declaring the control schema and before applying it.
4
+ *
5
+ * `apply schema CadreControl` runs whatever DDL makes the hydrated catalog equal the declared
6
+ * schema, and that apply is how a store written under an older control schema version is
7
+ * migrated in place: between consecutive versions the difference is limited to statements the
8
+ * optimystic module applies to a table's catalog record without rewriting a row, so running the
9
+ * diff from a store at version K to this build's declaration runs each version's changes from
10
+ * K+1 up to the build's, in order. This module decides, from the stored version and the pending
11
+ * DDL and before any of it runs, whether the apply may go ahead, and throws one typed error
12
+ * naming the reason when it may not.
13
+ *
14
+ * The same change classifier ({@link classifyControlSchemaChange}) is what
15
+ * `control-schema-versions.spec.ts` runs over each pair of consecutive control schema versions,
16
+ * so a schema edit that no store could be migrated across fails when it is made. Where the
17
+ * version lives, when it changes and what a new version may change: docs/architecture.md →
18
+ * "Control schema versions and migrations".
19
+ *
20
+ * The stored tag is the version of the last start that applied the schema to the store: the
21
+ * apply's `alter table OwnerKey set tags (…)` persists since Optimystic 1.16.0, so after a
22
+ * migrating start the store records this build's version. A store additively upgraded by a build
23
+ * from before that still reads the version it was created under, which is harmless: the diff is
24
+ * computed from the catalog, not from the number, and the number only has to tell a store that
25
+ * a newer release migrated from one this build can migrate.
26
+ */
27
+ import { type Database } from '@quereus/quereus';
28
+ /**
29
+ * Why a warm control store is refused, in the order the check decides them:
30
+ * - `newer-release`: the store records a version above this build's, so a newer release has
31
+ * migrated it (this machine before a downgrade, or another machine sharing its catalog
32
+ * lineage); this machine is the one to update.
33
+ * - `before-migrations`: the store records a version below {@link CONTROL_SCHEMA_BASELINE_VERSION}
34
+ * (written by 1.16.0 or earlier); it cannot be migrated and must be recreated.
35
+ * - `not-migratable`: a pending statement would rewrite or discard rows. Reachable only from a
36
+ * development or hand-made store, since the edit-time check refuses such a version.
37
+ */
38
+ export type ControlStoreIncompatibility = 'newer-release' | 'before-migrations' | 'not-migratable';
39
+ /** A warm control store this build cannot apply its control schema to. */
40
+ export declare class ControlStoreIncompatibleError extends Error {
41
+ readonly reason: ControlStoreIncompatibility;
42
+ readonly partyId: string;
43
+ /** The version the store records: the one its last migrating start declared; 0 = before versions were recorded. */
44
+ readonly storeVersion: number;
45
+ /** The version this build declares. */
46
+ readonly buildVersion: number;
47
+ /** The DDL the apply would have run, from `diff schema`; for diagnostics, not for parsing. */
48
+ readonly pendingDdl: readonly string[];
49
+ /** `controlStorageScope(partyId)`: the storage the embedder deletes to recreate (docs/architecture.md). */
50
+ readonly storageScope: string;
51
+ constructor(reason: ControlStoreIncompatibility, partyId: string, storeVersion: number, buildVersion: number, pendingDdl: readonly string[]);
52
+ }
53
+ /**
54
+ * Throw {@link ControlStoreIncompatibleError} when the declared control schema must not be applied
55
+ * to the hydrated store; return having run nothing otherwise, and the apply then migrates the
56
+ * store. Needs `declare schema CadreControl` to have run, and runs only `diff schema`, which
57
+ * executes no DDL.
58
+ *
59
+ * A cold store (the hydrated catalog lists no control table) passes without a diff: the apply
60
+ * creates everything. A warm store is refused for the first of these that holds
61
+ * ({@link ControlStoreIncompatibility}):
62
+ * - its version is above the build's: even a diff that only adds (the newer release no longer
63
+ * declares something this build does) would put back what that release removed, and the newer
64
+ * release would then refuse its own store;
65
+ * - its version is below the baseline, whatever the diff: a store written by 1.16.0 or earlier,
66
+ * which the baseline paragraph of docs/architecture.md explains cannot be migrated;
67
+ * - any pending statement is `unmigratable` ({@link classifyControlSchemaChange}).
68
+ *
69
+ * Every `additive` and `catalog-only` change passes, so a store from an older migratable
70
+ * release warm-starts and the apply brings it to this build's version. A store that is both
71
+ * older than the baseline and not migratable reports `before-migrations`, whose message gives the
72
+ * recreate advice and points at the explanation.
73
+ */
74
+ export declare function refuseIncompatibleControlStore(db: Database, partyId: string): Promise<void>;
75
+ /** The version the declared control schema carries on its version table; 0 when it carries none. */
76
+ export declare function declaredSchemaVersion(db: Database): number;
77
+ /**
78
+ * How applying one `diff schema` statement to a warm store treats its rows, from most to least
79
+ * migratable (docs/architecture.md → "Control schema versions and migrations"):
80
+ * - `additive`: a new table, a new index, or a table tag change, which the optimystic module
81
+ * applies without touching a row;
82
+ * - `catalog-only`: a change the optimystic module applies to the table's catalog record without
83
+ * rewriting a row (since Optimystic 1.16.0);
84
+ * - `unmigratable`: everything else, which rewrites or discards rows.
85
+ */
86
+ export type ControlSchemaChangeKind = 'additive' | 'catalog-only' | 'unmigratable';
87
+ /** One row of `diff schema CadreControl`, classified. */
88
+ export interface PendingControlSchemaChange {
89
+ readonly ddl: string;
90
+ /** The least migratable kind among the row's statements. */
91
+ readonly kind: ControlSchemaChangeKind;
92
+ }
93
+ /**
94
+ * The DDL `apply schema CadreControl` would run now, one entry per `diff schema` row, each
95
+ * classified against the catalog `db` holds. Needs `declare schema CadreControl` to have run.
96
+ */
97
+ export declare function pendingControlSchemaChanges(db: Database): Promise<PendingControlSchemaChange[]>;