keri-ts 2.1.0 → 2.2.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 (294) hide show
  1. package/README.md +30 -2
  2. package/esm/keri/npm/src/acdc/authoring.js +195 -0
  3. package/esm/keri/npm/src/acdc/custody.js +164 -0
  4. package/esm/keri/npm/src/acdc/dhking.js +244 -32
  5. package/esm/keri/npm/src/acdc/regbasing.js +10 -0
  6. package/esm/keri/npm/src/acdc/salting.js +16 -1
  7. package/esm/keri/npm/src/acdc/scheming.js +93 -54
  8. package/esm/keri/npm/src/acdc/unblinding.js +118 -95
  9. package/esm/keri/npm/src/app/bootstrap/authenticating.js +4 -6
  10. package/esm/keri/npm/src/app/bootstrap/oobi-resolving.js +41 -0
  11. package/esm/keri/npm/src/app/bootstrap/oobiery.js +4 -6
  12. package/esm/keri/npm/src/app/credentials/credential-revoking.js +1 -0
  13. package/esm/keri/npm/src/app/credentials/credential-workflows.js +2 -0
  14. package/esm/keri/npm/src/app/credentials/registry-settling.js +44 -0
  15. package/esm/keri/npm/src/app/credentials/root-replicating.js +68 -60
  16. package/esm/keri/npm/src/app/credentials/root-replicator.js +198 -0
  17. package/esm/keri/npm/src/app/credentials/tel-completion.js +36 -0
  18. package/esm/keri/npm/src/app/delivery/forwarding.js +16 -3
  19. package/esm/keri/npm/src/app/exchanges/exchanging.js +14 -4
  20. package/esm/keri/npm/src/app/identity/challenging.js +50 -0
  21. package/esm/keri/npm/src/app/identity/delegating.js +77 -77
  22. package/esm/keri/npm/src/app/identity/delegation-approval.js +333 -0
  23. package/esm/keri/npm/src/app/identity/event-completion.js +154 -0
  24. package/esm/keri/npm/src/app/identity/habbing.js +129 -6
  25. package/esm/keri/npm/src/app/identity/keeping.js +77 -4
  26. package/esm/keri/npm/src/app/ipex/group-ipex.js +327 -0
  27. package/esm/keri/npm/src/app/ipex/group-issuance.js +902 -0
  28. package/esm/keri/npm/src/app/ipex/ipex-admitting.js +120 -0
  29. package/esm/keri/npm/src/app/ipex/ipex-conversation.js +197 -0
  30. package/esm/keri/npm/src/app/ipex/ipex-discloser.js +591 -0
  31. package/esm/keri/npm/src/app/ipex/ipex-granting.js +93 -0
  32. package/esm/keri/npm/src/app/ipex/ipex-grouping.js +34 -11
  33. package/esm/keri/npm/src/app/ipex/issuance.js +888 -0
  34. package/esm/keri/npm/src/app/ipex/pending-presentations.js +46 -0
  35. package/esm/keri/npm/src/app/ipex/presentation-files.js +200 -0
  36. package/esm/keri/npm/src/app/ipex/presenting.js +401 -0
  37. package/esm/keri/npm/src/app/ipex/receive-issuance.js +86 -0
  38. package/esm/keri/npm/src/app/ipex/unblinding-workflow.js +660 -0
  39. package/esm/keri/npm/src/app/mailbox/ipex-arrival.js +103 -0
  40. package/esm/keri/npm/src/app/mailbox/kel-publisher.js +322 -0
  41. package/esm/keri/npm/src/app/mailbox/kel-publishing.js +65 -0
  42. package/esm/keri/npm/src/app/mailbox/kel-submission.js +24 -0
  43. package/esm/keri/npm/src/app/mailbox/mailbox-admin.js +208 -0
  44. package/esm/keri/npm/src/app/mailbox/mailbox-poller.js +212 -47
  45. package/esm/keri/npm/src/app/mailbox/mailboxing.js +10 -5
  46. package/esm/keri/npm/src/app/multisig/counseling.js +482 -0
  47. package/esm/keri/npm/src/app/multisig/group-members.js +18 -0
  48. package/esm/keri/npm/src/app/multisig/multisig-workflows.js +94 -139
  49. package/esm/keri/npm/src/app/multisig/proposals.js +281 -0
  50. package/esm/keri/npm/src/app/multisig/proposing.js +122 -0
  51. package/esm/keri/npm/src/app/notifications/signaling.js +5 -5
  52. package/esm/keri/npm/src/app/protocol/parsering.js +26 -1
  53. package/esm/keri/npm/src/app/protocol/protocol-processing.js +9 -3
  54. package/esm/keri/npm/src/app/queries/query-workflows.js +98 -0
  55. package/esm/keri/npm/src/app/runtime/agent-runtime.js +106 -55
  56. package/esm/keri/npm/src/app/runtime/cue-runtime.js +3 -6
  57. package/esm/keri/npm/src/app/runtime/delivery-outbox.js +87 -0
  58. package/esm/keri/npm/src/app/runtime/doing.js +17 -0
  59. package/esm/keri/npm/src/app/runtime/ipex-auxiliaries.js +207 -0
  60. package/esm/keri/npm/src/app/runtime/operation-owners.js +151 -0
  61. package/esm/keri/npm/src/app/runtime/retry-backoff.js +93 -0
  62. package/esm/keri/npm/src/app/runtime/workflow-contract.js +80 -0
  63. package/esm/keri/npm/src/app/transport/http-client.js +25 -6
  64. package/esm/keri/npm/src/app/witness/http-endpoints.js +4 -4
  65. package/esm/keri/npm/src/cli/common/event-completion.js +49 -0
  66. package/esm/keri/npm/src/cli/common/runtime-workers.js +23 -0
  67. package/esm/keri/npm/src/cli/credentials/ipex.js +157 -190
  68. package/esm/keri/npm/src/cli/credentials/vc.js +53 -72
  69. package/esm/keri/npm/src/cli/endpoints/did.js +12 -3
  70. package/esm/keri/npm/src/cli/endpoints/oobi.js +10 -13
  71. package/esm/keri/npm/src/cli/identity/challenge.js +8 -34
  72. package/esm/keri/npm/src/cli/identity/delegate.js +81 -258
  73. package/esm/keri/npm/src/cli/identity/incept.js +15 -32
  74. package/esm/keri/npm/src/cli/identity/interact.js +5 -17
  75. package/esm/keri/npm/src/cli/identity/rotate.js +8 -36
  76. package/esm/keri/npm/src/cli/index.js +3 -1
  77. package/esm/keri/npm/src/cli/messaging/group-join.js +79 -0
  78. package/esm/keri/npm/src/cli/messaging/group-wait.js +88 -0
  79. package/esm/keri/npm/src/cli/messaging/multisig.js +163 -284
  80. package/esm/keri/npm/src/cli/messaging/root-copy-lines.js +31 -0
  81. package/esm/keri/npm/src/core/kel/eventing.js +66 -10
  82. package/esm/keri/npm/src/core/mailbox/kram-policy.js +39 -6
  83. package/esm/keri/npm/src/core/mailbox/kraming.js +2 -0
  84. package/esm/keri/npm/src/core/records.js +23 -0
  85. package/esm/keri/npm/src/core/routing.js +13 -0
  86. package/esm/keri/npm/src/db/basing.js +34 -2
  87. package/esm/keri/npm/src/db/core/indexeddb-persistence.js +221 -0
  88. package/esm/keri/npm/src/db/indexeddb.js +98 -0
  89. package/esm/keri/npm/src/db/keeping.js +11 -2
  90. package/esm/keri/npm/src/db/store-lock.js +150 -0
  91. package/esm/keri/npm/src/npm/db-indexeddb.browser.js +2 -0
  92. package/esm/keri/npm/src/npm/db-indexeddb.js +3 -0
  93. package/esm/keri/npm/src/npm/db.browser.js +2 -0
  94. package/esm/keri/npm/src/npm/index.browser.js +9 -0
  95. package/esm/keri/npm/src/npm/runtime-web.browser.js +2 -0
  96. package/esm/keri/npm/src/npm/runtime-web.js +3 -0
  97. package/esm/keri/npm/src/npm/runtime.browser.js +2 -0
  98. package/esm/keri/npm/src/runtime/index.js +51 -4
  99. package/esm/keri/npm/src/runtime/web/output-barrier.js +47 -0
  100. package/esm/keri/npm/src/runtime/web/persistent-storage.js +37 -0
  101. package/esm/keri/npm/src/runtime/web.js +10 -0
  102. package/esm/keri/npm/src/vdr/tel-publication.js +16 -0
  103. package/esm/keri/npm/src/version.js +2 -2
  104. package/package.json +15 -2
  105. package/types/acdc/authoring.d.ts +54 -0
  106. package/types/acdc/authoring.d.ts.map +1 -0
  107. package/types/acdc/custody.d.ts +77 -0
  108. package/types/acdc/custody.d.ts.map +1 -0
  109. package/types/acdc/dhking.d.ts +94 -3
  110. package/types/acdc/dhking.d.ts.map +1 -1
  111. package/types/acdc/regbasing.d.ts +4 -0
  112. package/types/acdc/regbasing.d.ts.map +1 -1
  113. package/types/acdc/salting.d.ts +6 -1
  114. package/types/acdc/salting.d.ts.map +1 -1
  115. package/types/acdc/scheming.d.ts +2 -0
  116. package/types/acdc/scheming.d.ts.map +1 -1
  117. package/types/acdc/unblinding.d.ts +58 -19
  118. package/types/acdc/unblinding.d.ts.map +1 -1
  119. package/types/app/bootstrap/authenticating.d.ts +3 -1
  120. package/types/app/bootstrap/authenticating.d.ts.map +1 -1
  121. package/types/app/bootstrap/oobi-resolving.d.ts +92 -0
  122. package/types/app/bootstrap/oobi-resolving.d.ts.map +1 -0
  123. package/types/app/bootstrap/oobiery.d.ts +3 -1
  124. package/types/app/bootstrap/oobiery.d.ts.map +1 -1
  125. package/types/app/credentials/credential-revoking.d.ts +3 -0
  126. package/types/app/credentials/credential-revoking.d.ts.map +1 -1
  127. package/types/app/credentials/credential-workflows.d.ts +5 -0
  128. package/types/app/credentials/credential-workflows.d.ts.map +1 -1
  129. package/types/app/credentials/registry-settling.d.ts +85 -0
  130. package/types/app/credentials/registry-settling.d.ts.map +1 -0
  131. package/types/app/credentials/root-replicating.d.ts +56 -44
  132. package/types/app/credentials/root-replicating.d.ts.map +1 -1
  133. package/types/app/credentials/root-replicator.d.ts +105 -0
  134. package/types/app/credentials/root-replicator.d.ts.map +1 -0
  135. package/types/app/credentials/tel-completion.d.ts +55 -0
  136. package/types/app/credentials/tel-completion.d.ts.map +1 -0
  137. package/types/app/delivery/forwarding.d.ts +6 -0
  138. package/types/app/delivery/forwarding.d.ts.map +1 -1
  139. package/types/app/exchanges/exchanging.d.ts.map +1 -1
  140. package/types/app/identity/challenging.d.ts +54 -0
  141. package/types/app/identity/challenging.d.ts.map +1 -1
  142. package/types/app/identity/delegating.d.ts +21 -4
  143. package/types/app/identity/delegating.d.ts.map +1 -1
  144. package/types/app/identity/delegation-approval.d.ts +228 -0
  145. package/types/app/identity/delegation-approval.d.ts.map +1 -0
  146. package/types/app/identity/event-completion.d.ts +151 -0
  147. package/types/app/identity/event-completion.d.ts.map +1 -0
  148. package/types/app/identity/habbing.d.ts +67 -2
  149. package/types/app/identity/habbing.d.ts.map +1 -1
  150. package/types/app/identity/keeping.d.ts +49 -3
  151. package/types/app/identity/keeping.d.ts.map +1 -1
  152. package/types/app/ipex/group-ipex.d.ts +247 -0
  153. package/types/app/ipex/group-ipex.d.ts.map +1 -0
  154. package/types/app/ipex/group-issuance.d.ts +281 -0
  155. package/types/app/ipex/group-issuance.d.ts.map +1 -0
  156. package/types/app/ipex/ipex-admitting.d.ts +47 -0
  157. package/types/app/ipex/ipex-admitting.d.ts.map +1 -0
  158. package/types/app/ipex/ipex-conversation.d.ts +195 -0
  159. package/types/app/ipex/ipex-conversation.d.ts.map +1 -0
  160. package/types/app/ipex/ipex-discloser.d.ts +156 -0
  161. package/types/app/ipex/ipex-discloser.d.ts.map +1 -0
  162. package/types/app/ipex/ipex-granting.d.ts +145 -0
  163. package/types/app/ipex/ipex-granting.d.ts.map +1 -0
  164. package/types/app/ipex/ipex-grouping.d.ts +18 -0
  165. package/types/app/ipex/ipex-grouping.d.ts.map +1 -1
  166. package/types/app/ipex/issuance.d.ts +443 -0
  167. package/types/app/ipex/issuance.d.ts.map +1 -0
  168. package/types/app/ipex/pending-presentations.d.ts +25 -0
  169. package/types/app/ipex/pending-presentations.d.ts.map +1 -0
  170. package/types/app/ipex/presentation-files.d.ts +47 -0
  171. package/types/app/ipex/presentation-files.d.ts.map +1 -0
  172. package/types/app/ipex/presenting.d.ts +298 -0
  173. package/types/app/ipex/presenting.d.ts.map +1 -0
  174. package/types/app/ipex/receive-issuance.d.ts +99 -0
  175. package/types/app/ipex/receive-issuance.d.ts.map +1 -0
  176. package/types/app/ipex/unblinding-workflow.d.ts +255 -0
  177. package/types/app/ipex/unblinding-workflow.d.ts.map +1 -0
  178. package/types/app/mailbox/ipex-arrival.d.ts +104 -0
  179. package/types/app/mailbox/ipex-arrival.d.ts.map +1 -0
  180. package/types/app/mailbox/kel-publisher.d.ts +141 -0
  181. package/types/app/mailbox/kel-publisher.d.ts.map +1 -0
  182. package/types/app/mailbox/kel-publishing.d.ts +70 -0
  183. package/types/app/mailbox/kel-publishing.d.ts.map +1 -0
  184. package/types/app/mailbox/kel-submission.d.ts +18 -0
  185. package/types/app/mailbox/kel-submission.d.ts.map +1 -0
  186. package/types/app/mailbox/mailbox-admin.d.ts +113 -0
  187. package/types/app/mailbox/mailbox-admin.d.ts.map +1 -0
  188. package/types/app/mailbox/mailbox-poller.d.ts +92 -3
  189. package/types/app/mailbox/mailbox-poller.d.ts.map +1 -1
  190. package/types/app/mailbox/mailboxing.d.ts +3 -0
  191. package/types/app/mailbox/mailboxing.d.ts.map +1 -1
  192. package/types/app/multisig/counseling.d.ts +196 -0
  193. package/types/app/multisig/counseling.d.ts.map +1 -0
  194. package/types/app/multisig/group-members.d.ts +11 -0
  195. package/types/app/multisig/group-members.d.ts.map +1 -1
  196. package/types/app/multisig/grouping.d.ts +39 -20
  197. package/types/app/multisig/grouping.d.ts.map +1 -1
  198. package/types/app/multisig/multisig-workflows.d.ts +91 -22
  199. package/types/app/multisig/multisig-workflows.d.ts.map +1 -1
  200. package/types/app/multisig/proposals.d.ts +129 -0
  201. package/types/app/multisig/proposals.d.ts.map +1 -0
  202. package/types/app/multisig/proposing.d.ts +125 -0
  203. package/types/app/multisig/proposing.d.ts.map +1 -0
  204. package/types/app/notifications/signaling.d.ts +3 -1
  205. package/types/app/notifications/signaling.d.ts.map +1 -1
  206. package/types/app/protocol/parsering.d.ts +13 -0
  207. package/types/app/protocol/parsering.d.ts.map +1 -1
  208. package/types/app/protocol/protocol-processing.d.ts +7 -1
  209. package/types/app/protocol/protocol-processing.d.ts.map +1 -1
  210. package/types/app/queries/query-workflows.d.ts +98 -0
  211. package/types/app/queries/query-workflows.d.ts.map +1 -0
  212. package/types/app/runtime/agent-runtime.d.ts +72 -25
  213. package/types/app/runtime/agent-runtime.d.ts.map +1 -1
  214. package/types/app/runtime/cue-runtime.d.ts +2 -1
  215. package/types/app/runtime/cue-runtime.d.ts.map +1 -1
  216. package/types/app/runtime/delivery-outbox.d.ts +68 -0
  217. package/types/app/runtime/delivery-outbox.d.ts.map +1 -0
  218. package/types/app/runtime/doing.d.ts +27 -0
  219. package/types/app/runtime/doing.d.ts.map +1 -0
  220. package/types/app/runtime/ipex-auxiliaries.d.ts +74 -0
  221. package/types/app/runtime/ipex-auxiliaries.d.ts.map +1 -0
  222. package/types/app/runtime/operation-owners.d.ts +137 -0
  223. package/types/app/runtime/operation-owners.d.ts.map +1 -0
  224. package/types/app/runtime/retry-backoff.d.ts +49 -0
  225. package/types/app/runtime/retry-backoff.d.ts.map +1 -0
  226. package/types/app/runtime/workflow-contract.d.ts +79 -0
  227. package/types/app/runtime/workflow-contract.d.ts.map +1 -0
  228. package/types/app/transport/http-client.d.ts.map +1 -1
  229. package/types/cli/common/event-completion.d.ts +26 -0
  230. package/types/cli/common/event-completion.d.ts.map +1 -0
  231. package/types/cli/common/runtime-workers.d.ts +23 -0
  232. package/types/cli/common/runtime-workers.d.ts.map +1 -0
  233. package/types/cli/credentials/ipex.d.ts.map +1 -1
  234. package/types/cli/credentials/vc.d.ts +1 -1
  235. package/types/cli/credentials/vc.d.ts.map +1 -1
  236. package/types/cli/endpoints/did.d.ts.map +1 -1
  237. package/types/cli/endpoints/oobi.d.ts +3 -1
  238. package/types/cli/endpoints/oobi.d.ts.map +1 -1
  239. package/types/cli/identity/challenge.d.ts +1 -1
  240. package/types/cli/identity/challenge.d.ts.map +1 -1
  241. package/types/cli/identity/delegate.d.ts +14 -1
  242. package/types/cli/identity/delegate.d.ts.map +1 -1
  243. package/types/cli/identity/incept.d.ts.map +1 -1
  244. package/types/cli/identity/interact.d.ts.map +1 -1
  245. package/types/cli/identity/rotate.d.ts.map +1 -1
  246. package/types/cli/index.d.ts +3 -1
  247. package/types/cli/index.d.ts.map +1 -1
  248. package/types/cli/messaging/group-join.d.ts +53 -0
  249. package/types/cli/messaging/group-join.d.ts.map +1 -0
  250. package/types/cli/messaging/group-wait.d.ts +34 -0
  251. package/types/cli/messaging/group-wait.d.ts.map +1 -0
  252. package/types/cli/messaging/multisig.d.ts +28 -5
  253. package/types/cli/messaging/multisig.d.ts.map +1 -1
  254. package/types/cli/messaging/root-copy-lines.d.ts +39 -0
  255. package/types/cli/messaging/root-copy-lines.d.ts.map +1 -0
  256. package/types/core/cues.d.ts +11 -0
  257. package/types/core/cues.d.ts.map +1 -1
  258. package/types/core/kel/eventing.d.ts.map +1 -1
  259. package/types/core/mailbox/kram-policy.d.ts +14 -0
  260. package/types/core/mailbox/kram-policy.d.ts.map +1 -1
  261. package/types/core/mailbox/kraming.d.ts +1 -1
  262. package/types/core/mailbox/kraming.d.ts.map +1 -1
  263. package/types/core/records.d.ts +61 -0
  264. package/types/core/records.d.ts.map +1 -1
  265. package/types/core/routing.d.ts +6 -0
  266. package/types/core/routing.d.ts.map +1 -1
  267. package/types/db/basing.d.ts +8 -2
  268. package/types/db/basing.d.ts.map +1 -1
  269. package/types/db/core/indexeddb-persistence.d.ts +59 -0
  270. package/types/db/core/indexeddb-persistence.d.ts.map +1 -0
  271. package/types/db/indexeddb.d.ts +37 -0
  272. package/types/db/indexeddb.d.ts.map +1 -0
  273. package/types/db/keeping.d.ts +5 -2
  274. package/types/db/keeping.d.ts.map +1 -1
  275. package/types/db/store-lock.d.ts +72 -0
  276. package/types/db/store-lock.d.ts.map +1 -0
  277. package/types/npm/db-indexeddb.d.ts +4 -0
  278. package/types/npm/db-indexeddb.d.ts.map +1 -0
  279. package/types/npm/runtime-web.d.ts +4 -0
  280. package/types/npm/runtime-web.d.ts.map +1 -0
  281. package/types/runtime/index.d.ts +41 -6
  282. package/types/runtime/index.d.ts.map +1 -1
  283. package/types/runtime/web/output-barrier.d.ts +30 -0
  284. package/types/runtime/web/output-barrier.d.ts.map +1 -0
  285. package/types/runtime/web/persistent-storage.d.ts +36 -0
  286. package/types/runtime/web/persistent-storage.d.ts.map +1 -0
  287. package/types/runtime/web.d.ts +11 -0
  288. package/types/runtime/web.d.ts.map +1 -0
  289. package/types/vdr/tel-publication.d.ts +6 -0
  290. package/types/vdr/tel-publication.d.ts.map +1 -1
  291. package/types/version.d.ts +2 -2
  292. package/esm/keri/npm/src/cli/common/tel-completion.js +0 -24
  293. package/types/cli/common/tel-completion.d.ts +0 -8
  294. package/types/cli/common/tel-completion.d.ts.map +0 -1
@@ -0,0 +1,591 @@
1
+ /**
2
+ * IPEX discloser core: Grant preparation over borrowed protocol owners.
3
+ *
4
+ * Holds the parts of disclosure that read no credential inventory: exchange
5
+ * wires, source anchoring, fresh-issuance Grant bodies and public proof
6
+ * support, plus graph authorization, registry proofs, Apply and Reply bodies.
7
+ * Selecting issued or held credentials stays with the embedder
8
+ * (`WalletDiscloser` extends this class).
9
+ * No constructor opens a store, starts a worker or loads registry secrets.
10
+ */
11
+ import { collectPayload, Compactor, concatBytes, Counter, Diger, framePayload, nestedPayload, NumberPrimitive, parseBytes, Prefixer, SealSource, SerderACDC, SerderKERI, unblindBlindState, unblindBoundState, Vrsn_2_0, } from "cesr-ts";
12
+ import { call } from "effection";
13
+ import { evaluateChain } from "../../acdc/chaining.js";
14
+ import { matchesRegistrySeal, vet, vetBinds, vetBlind, vetBound, } from "../../acdc/regeventing.js";
15
+ import { publicOpeningAttachment } from "../../acdc/registering.js";
16
+ import { validateSchema as validateAcdcSchema } from "../../acdc/scheming.js";
17
+ import { ValidationError } from "../../core/errors.js";
18
+ import { verifyExchangeProofs } from "../../core/exchange/exchange-proofing.js";
19
+ import { Kever } from "../../core/kel/kever.js";
20
+ import { messagize } from "../../core/protocol-serialization.js";
21
+ import { acceptedEventReplayMessage } from "../identity/habbing.js";
22
+ import { isLocalGroupHab } from "../multisig/group-members.js";
23
+ import { envelopeFromFrame } from "../protocol/parsering.js";
24
+ import { ipexExnBody, prepareIpexExn } from "./ipex-building.js";
25
+ import { walkIpexGraph } from "./ipex-graph.js";
26
+ import { acceptedRegistryEvidence, authenticateIpexNode, issuedNodeVerdict } from "./ipex-node-authentication.js";
27
+ import { ipexGrantWalk } from "./ipex-v2.js";
28
+ /** Reuse a matching accepted KEL seal, or author once and gather real witness receipts. */
29
+ export function* anchorExchange(hby, receiptor, hab, body, auths) {
30
+ if (receiptor.hby !== hby)
31
+ throw new ValidationError("Receipt owner must share this wallet's Habery.");
32
+ let anchor = null, event = hab.kever.serder;
33
+ while (event) {
34
+ if (event.seals.some((seal) => body instanceof SerderACDC
35
+ ? matchesRegistrySeal(seal, body)
36
+ : seal && typeof seal === "object" && "d" in seal && seal.d === body.said)) {
37
+ anchor = event;
38
+ }
39
+ event = event.prior ? hab.db.getEvtSerder(hab.pre, event.prior) : null;
40
+ }
41
+ if (!anchor) {
42
+ const data = body instanceof SerderACDC
43
+ ? [{ i: body.regid ?? body.said, s: body.sad.n, d: body.said }]
44
+ : [{ d: body.said }];
45
+ if (hab.kever.estOnly)
46
+ hab.rotate({ data });
47
+ else
48
+ hab.interact({ data });
49
+ anchor = hab.kever.serder;
50
+ }
51
+ yield* receiptor.receipt(hab.pre, { sn: anchor.sn, allowTcp: true, auths });
52
+ if (!hab.db.fullyWitnessed(anchor))
53
+ throw new ValidationError("Source anchor remains pending witness receipts.");
54
+ return { s: NumberPrimitive.fromNum(BigInt(anchor.sn)), d: new Diger({ qb64: anchor.said }) };
55
+ }
56
+ /** Encode one frozen body and its existing prepared nests; source proofs do not alter its SAID. */
57
+ export function exchangeWire(hab, exn, nested = new Uint8Array(), source, gvrsn = Vrsn_2_0) {
58
+ const proof = source
59
+ ? Counter.enclose({ code: "SealSourceCouples", qb64: SealSource.qb64b(source), version: gvrsn })
60
+ : concatBytes(...parseBytes(hab.endorse(exn, { gvrsn, pipelined: false, genusify: true }))[0].attachments.map((g) => g.raw));
61
+ return concatBytes(Counter.makeGVC(gvrsn), exn.raw, Counter.enclose({ qb64: concatBytes(proof, nested), version: gvrsn }));
62
+ }
63
+ /**
64
+ * Re-encode a signed exchange from its retained, authenticated factors: the wire its signer sent, rebuilt
65
+ * from the stored signatures or source seal and the stored nests. Signs nothing, so it needs no keys.
66
+ */
67
+ export function* storedExchangeWire(retained, gvrsn = Vrsn_2_0) {
68
+ const nests = [...retained.nests ?? []];
69
+ const seal = retained.sourceSeals?.[0];
70
+ if (seal) {
71
+ const nested = concatBytes(...yield* call(() => Promise.all(nests.map((nest) => collectPayload(framePayload(nest))))));
72
+ const proof = Counter.enclose({
73
+ code: "SealSourceCouples",
74
+ qb64: SealSource.qb64b({ s: seal.s, d: seal.d }),
75
+ version: gvrsn,
76
+ });
77
+ return concatBytes(Counter.makeGVC(gvrsn), retained.serder.raw, Counter.enclose({ qb64: concatBytes(proof, nested), version: gvrsn }));
78
+ }
79
+ const frame = parseBytes(messagize(retained.serder, { tsgs: retained.tsgs, cigars: retained.cigars, gvrsn }))[0];
80
+ frame.nests = nests;
81
+ return yield* call(() => collectPayload(framePayload(frame)));
82
+ }
83
+ /** Borrow concrete owners only. No constructor opens a store, starts a worker or loads registry secrets. */
84
+ export class IpexDiscloser {
85
+ constructor(hby, registry, exc, receiptor, custody, views) {
86
+ Object.defineProperty(this, "hby", {
87
+ enumerable: true,
88
+ configurable: true,
89
+ writable: true,
90
+ value: hby
91
+ });
92
+ Object.defineProperty(this, "registry", {
93
+ enumerable: true,
94
+ configurable: true,
95
+ writable: true,
96
+ value: registry
97
+ });
98
+ Object.defineProperty(this, "exc", {
99
+ enumerable: true,
100
+ configurable: true,
101
+ writable: true,
102
+ value: exc
103
+ });
104
+ Object.defineProperty(this, "receiptor", {
105
+ enumerable: true,
106
+ configurable: true,
107
+ writable: true,
108
+ value: receiptor
109
+ });
110
+ Object.defineProperty(this, "custody", {
111
+ enumerable: true,
112
+ configurable: true,
113
+ writable: true,
114
+ value: custody
115
+ });
116
+ Object.defineProperty(this, "views", {
117
+ enumerable: true,
118
+ configurable: true,
119
+ writable: true,
120
+ value: views
121
+ });
122
+ if (receiptor.hby !== hby)
123
+ throw new ValidationError("Disclosure receipt owner must share the Habery.");
124
+ if (custody && (custody.options.hby !== hby || custody.options.registry !== registry)) {
125
+ throw new ValidationError("Disclosure custody must use this discloser's actual owners.");
126
+ }
127
+ }
128
+ /** Selection needs the embedder's credential views; fresh issuance and replies do not. */
129
+ credentials() {
130
+ if (!this.views)
131
+ throw new ValidationError("Credential selection requires the embedder's credential views.");
132
+ return this.views;
133
+ }
134
+ /** Resolve only a local individual signer; group approval composes this body in the group workflow. */
135
+ signer(sender, gvrsn = Vrsn_2_0) {
136
+ if (gvrsn.major < 2)
137
+ throw new ValidationError("ACDC v2 disclosure requires attachment genus 2 or later.");
138
+ const hab = this.hby.habs.get(sender);
139
+ if (!hab || isLocalGroupHab(this.hby, hab)) {
140
+ throw new ValidationError("ACDC v2 disclosure requires a local individual signer.");
141
+ }
142
+ return hab;
143
+ }
144
+ /** Revalidate exact accepted prior bytes without treating notification or salt possession as acceptance. */
145
+ *prior(said) {
146
+ if (!said)
147
+ return undefined;
148
+ const body = this.hby.db.exns.get(said);
149
+ if (!body || !this.exc.complete(said) || !this.exc.verifyAccepted(said, body.route)) {
150
+ throw new ValidationError("Prior ACDC v2 IPEX exchange must be accepted and authenticated.");
151
+ }
152
+ yield* call(async () => {
153
+ for await (const _ of this.exc.replay(said)) { /* authenticated retained outer proof */ }
154
+ });
155
+ return body;
156
+ }
157
+ /** Prepare one fresh issuer origin with explicit authenticated far nodes, without changing disclosure authority. */
158
+ *prepareIssuanceGrantBody(sender, credential, options) {
159
+ const hab = this.hby.habs.get(sender), origin = new SerderACDC({ raw: credential.raw.slice() });
160
+ if (!hab?.kever || (options.gvrsn ?? Vrsn_2_0).major < 2 || origin.pvrsn.major !== 2
161
+ || !origin.verify() || !["acm", "act", "acg"].includes(origin.ilk) || origin.issuer !== sender
162
+ || !options.recipient || options.recipient === sender || origin.issuee !== options.recipient || !origin.regid) {
163
+ throw new ValidationError("Fresh issuance requires an exact v2 credential from the local issuer to its selected issuee.");
164
+ }
165
+ const chain = acceptedRegistryEvidence(this.registry, origin.regid);
166
+ if (!chain || chain.updates.length || chain.rip.issuer !== sender
167
+ || vet({ ...chain, db: this.hby.db }).kind !== "verified") {
168
+ throw new ValidationError("Fresh issuance requires the issuer's accepted anchored RIP without updates.");
169
+ }
170
+ const raw = concatBytes(Counter.makeGVC(Vrsn_2_0), origin.raw, Counter.enclose({ qb64: new Uint8Array(), version: Vrsn_2_0 }), ...(options.artifacts ?? []).map(artifact => artifact.slice()));
171
+ const graph = walkIpexGraph(origin.said, parseBytes(raw), ipexGrantWalk(this.exc));
172
+ if (!graph) {
173
+ throw new ValidationError("Fresh issuance requires its complete explicitly disclosed credential graph.");
174
+ }
175
+ for (const [said, node] of graph.nodes) {
176
+ const schema = validateAcdcSchema(node.body, this.hby.db);
177
+ if (schema.kind !== "valid") {
178
+ throw new ValidationError(schema.kind === "missing" ? `Missing ACDC schema: ${schema.said}` : schema.reason);
179
+ }
180
+ if (said !== origin.said
181
+ && authenticateIpexNode(node.body, envelopeFromFrame(node), this.hby.db, this.registry).kind
182
+ !== "authenticated") {
183
+ throw new ValidationError("Fresh issuance supports one new origin; every far node requires authenticated issuer proof.");
184
+ }
185
+ }
186
+ const prior = yield* this.prior(options.priorSaid);
187
+ if (options.anchor || prior && (!["/ipex/apply", "/ipex/agree"].includes(prior.route)
188
+ || prior.sad.a.ax?.[0])) {
189
+ throw new ValidationError("Fresh issuance requires an unanchored Grant and an accepted Apply or Agree when linked.");
190
+ }
191
+ const [exn, nests] = yield* prepareIpexExn(sender, "/ipex/grant", raw, { ...options, prior });
192
+ return { exn, raw, nests };
193
+ }
194
+ /** Carry selected public evidence and root-first delegation ancestry; receiver intake still verifies every approval. */
195
+ proofSupport(raw, hab) {
196
+ const aids = new Set([hab.pre]), registries = new Set();
197
+ for (const frame of parseBytes(raw)) {
198
+ if (!(frame.body instanceof SerderACDC))
199
+ continue;
200
+ const node = frame.body, envelope = envelopeFromFrame(frame);
201
+ if (node.issuer)
202
+ aids.add(node.issuer);
203
+ if (node.issuee)
204
+ aids.add(node.issuee);
205
+ if (node.regid)
206
+ registries.add(node.regid);
207
+ const a = node.sad.a;
208
+ if (a && typeof a === "object" && typeof a.rd === "string")
209
+ registries.add(a.rd);
210
+ for (const seal of envelope.ssts) {
211
+ if (this.registry.seqEvent(seal.i.qb64, 0))
212
+ registries.add(seal.i.qb64);
213
+ else
214
+ aids.add(seal.i.qb64);
215
+ }
216
+ }
217
+ const messages = [Counter.makeGVC(Vrsn_2_0)];
218
+ const db = this.hby.db, ordered = new Set();
219
+ // An ancestry claim selects supporting KELs; it does not establish delegation authority.
220
+ for (const aid of aids) {
221
+ const ancestors = [], seen = new Set();
222
+ let current = aid;
223
+ while (current && !ordered.has(current)) {
224
+ if (seen.has(current))
225
+ throw new ValidationError(`Cyclic disclosure delegation ancestry at ${current}.`);
226
+ seen.add(current);
227
+ const state = db.getKever(current);
228
+ if (!state)
229
+ break;
230
+ ancestors.push(current);
231
+ current = state.delpre;
232
+ }
233
+ for (const ancestor of ancestors.reverse())
234
+ ordered.add(ancestor);
235
+ }
236
+ // Keep first-seen authorizers and exact stored attachments, including superseded history.
237
+ // clonePreIter skips broken rows; finite disclosure must instead fail if an accepted row cannot be replayed.
238
+ for (const aid of ordered) {
239
+ for (const [, fn, said] of db.fels.getAllItemIter(aid))
240
+ messages.push(db.cloneEvtMsg(aid, fn, said, Vrsn_2_0));
241
+ }
242
+ for (const regid of registries)
243
+ messages.push(this.registry.cloneTel(regid));
244
+ return concatBytes(...messages);
245
+ }
246
+ /** Public replay includes actual stored witness receipts; it grants no new consent. */
247
+ kel(hab) {
248
+ return concatBytes(Counter.makeGVC(Vrsn_2_0), ...Array.from({ length: hab.kever.sn + 1 }, (_, sn) => acceptedEventReplayMessage(this.hby, hab.pre, sn, Vrsn_2_0).message));
249
+ }
250
+ /** Reduce only the selected attribute view using the existing commitment-preserving Compactor. */
251
+ partial(credential, paths) {
252
+ if (!paths?.length)
253
+ return credential;
254
+ if (!credential.sad.a || typeof credential.sad.a !== "object" || Array.isArray(credential.sad.a)) {
255
+ throw new ValidationError("Attribute disclosure requires an expanded selected attribute map.");
256
+ }
257
+ const block = new Compactor({
258
+ mad: structuredClone(credential.sad.a),
259
+ kind: credential.kind,
260
+ verify: false,
261
+ });
262
+ block.compact([...paths], "a");
263
+ const partial = new SerderACDC({
264
+ sad: { ...credential.sad, a: block.partials[paths.join("|")].mad },
265
+ kind: credential.kind,
266
+ makify: true,
267
+ });
268
+ if (partial.said !== credential.said) {
269
+ throw new ValidationError("Disclosure changed the selected credential commitment.");
270
+ }
271
+ return partial;
272
+ }
273
+ /** Authenticate every selected node, then authorize only the shared complete-root expression. */
274
+ requireGraph(origin, raw, pendingPresentation = false) {
275
+ const graph = walkIpexGraph(origin, parseBytes(raw), ipexGrantWalk(this.exc));
276
+ if (!graph)
277
+ throw new ValidationError("Selected credential graph is incomplete.");
278
+ const verdicts = new Map();
279
+ for (const [said, node] of graph.nodes) {
280
+ if (pendingPresentation) {
281
+ const schema = validateAcdcSchema(node.body, this.hby.db);
282
+ if (schema.kind !== "valid") {
283
+ throw new ValidationError(schema.kind === "missing" ? `Missing ACDC schema: ${schema.said}` : schema.reason);
284
+ }
285
+ }
286
+ const envelope = envelopeFromFrame(node);
287
+ const auth = authenticateIpexNode(node.body, envelope, this.hby.db, this.registry);
288
+ let verdict = issuedNodeVerdict(auth);
289
+ if (pendingPresentation && auth.kind === "reject" && node.body.regid) {
290
+ // Ordinary node authentication deliberately rejects absent current openings.
291
+ // File consent may wait for that specific evidence, never for a known invalid state.
292
+ const chain = acceptedRegistryEvidence(this.registry, node.body.regid);
293
+ const binding = chain && vetBinds({
294
+ ...chain,
295
+ db: this.hby.db,
296
+ acdc: node.body,
297
+ target: said,
298
+ blinders: [...envelope.bsqs, ...envelope.bsss],
299
+ });
300
+ const historical = authenticateIpexNode(node.body, envelope, this.hby.db, this.registry, true);
301
+ if (binding?.kind === "missing" && binding.reason === "disclosure"
302
+ && historical.kind === "authenticated" && historical.registration?.state === "issued") {
303
+ verdict = { kind: "unknown", retryable: true, reason: "Missing current registry opening.", schemas: [] };
304
+ }
305
+ }
306
+ verdicts.set(said, verdict);
307
+ }
308
+ const current = evaluateChain(graph, verdicts, this.hby.db);
309
+ if (current?.kind === "valid")
310
+ return;
311
+ if (pendingPresentation && current?.kind === "unknown" && current.retryable) {
312
+ const historical = new Map();
313
+ for (const [said, node] of graph.nodes) {
314
+ historical.set(said, issuedNodeVerdict(authenticateIpexNode(node.body, envelopeFromFrame(node), this.hby.db, this.registry, true)));
315
+ }
316
+ if (evaluateChain(graph, historical, this.hby.db)?.kind === "valid")
317
+ return;
318
+ }
319
+ throw new ValidationError("Current authenticated graph truth is required before use.");
320
+ }
321
+ /** Recover a candidate using an explicitly possessed UUID; this neither derives a salt nor grants authority. */
322
+ unblind(opening, credential, states, bounds = []) {
323
+ if (!opening.u.nonce)
324
+ throw new ValidationError("Unblinding requires an explicitly possessed disclosure UUID.");
325
+ const options = { said: opening.d.nonce, uuid: opening.u.nonce, acdc: credential, states: [...states] };
326
+ return "bn" in opening
327
+ ? unblindBoundState({ ...options, bounds: [[opening.bn.num, opening.bd.nonce], ...bounds] })
328
+ : unblindBlindState(options);
329
+ }
330
+ /** Attach exact accepted issuer openings from head through vacuous suffix to this credential's binding. */
331
+ registryProof(credential, registry, retained = [], options = {}) {
332
+ const chain = acceptedRegistryEvidence(this.registry, registry);
333
+ if (!chain || chain.updates.some((update) => update.ilk !== "bup")) {
334
+ throw new ValidationError("Accepted ACDC v2 registry history is required.");
335
+ }
336
+ if (options.derive && !this.custody)
337
+ throw new ValidationError("Explicit derivation requires provisioned custody.");
338
+ const proofs = [];
339
+ let binding = null;
340
+ for (const event of [...chain.updates].reverse()) {
341
+ const blid = event.sad.b;
342
+ let opening = retained.find((proof) => proof.d.nonce === blid) ?? this.registry.publicOpening(event.said);
343
+ if (!opening && options.derive) {
344
+ // Exact retained coordinates are required; missing local material is a refusal.
345
+ opening = this.custody.derivedOpening(event);
346
+ }
347
+ if (!opening || !vetBlind(opening, blid) || (opening.td.nonce && opening.td.nonce !== credential.said)
348
+ || vetBound(opening, credential, this.hby.db)) {
349
+ throw new ValidationError("Current exact registry opening is unavailable or binds different evidence.");
350
+ }
351
+ proofs.push(publicOpeningAttachment(opening));
352
+ if (opening.td.nonce) {
353
+ binding = event;
354
+ break;
355
+ }
356
+ }
357
+ if (!binding)
358
+ throw new ValidationError("Registry has no disclosed credential binding.");
359
+ if (!credential.regid) {
360
+ proofs.push(Counter.enclose({
361
+ code: "SealSourceTriples",
362
+ version: Vrsn_2_0,
363
+ qb64: concatBytes(new Prefixer({ qb64: registry }).qb64b, NumberPrimitive.fromNum(BigInt(`0x${binding.sad.n}`)).qb64b, new Diger({ qb64: binding.said }).qb64b),
364
+ }));
365
+ }
366
+ return concatBytes(Counter.makeGVC(Vrsn_2_0), credential.raw, Counter.enclose({ qb64: concatBytes(...proofs), version: Vrsn_2_0 }));
367
+ }
368
+ /** Create an application request; no credential-use approval is invented for negotiation. */
369
+ *prepareApply(sender, options) {
370
+ const hab = this.signer(sender, options.gvrsn ?? Vrsn_2_0), exn = ipexExnBody(sender, "/ipex/apply", [], options);
371
+ return {
372
+ exn,
373
+ wire: exchangeWire(hab, exn, undefined, undefined, options.gvrsn ?? Vrsn_2_0),
374
+ support: new Uint8Array(),
375
+ };
376
+ }
377
+ /** Accept or decline the exact authenticated predecessor and its negotiated anchoring choice. */
378
+ *prepareReply(sender, verb, priorSaid, message = "", recipient, auths) {
379
+ const hab = this.signer(sender), prior = yield* this.prior(priorSaid);
380
+ const exn = ipexExnBody(sender, `/ipex/${verb}`, [], { message, prior, recipient });
381
+ const source = verb === "agree" && exn.sad.a.ax?.[0]
382
+ ? yield* anchorExchange(this.hby, this.receiptor, hab, exn, auths)
383
+ : undefined;
384
+ return { exn, wire: exchangeWire(hab, exn, undefined, source), support: source ? this.kel(hab) : new Uint8Array() };
385
+ }
386
+ /** Extend the frozen Grant's exact origin proof; ordinary intake still authenticates the supplied presentation evidence. */
387
+ *attachPresentationProof(prepared, opening, source) {
388
+ const frames = parseBytes(prepared.raw), node = frames[0].body;
389
+ if (!node.issuee || opening.td.nonce !== prepared.exn.said || opening.ts.label !== "presented") {
390
+ throw new ValidationError("Presentation proof must target this exact Grant and disclosed Issuee.");
391
+ }
392
+ const seal = Counter.enclose({
393
+ code: "SealSourceTriples",
394
+ qb64: concatBytes(new Prefixer({ qb64: node.issuee }).qb64b, source.s.qb64b, source.d.qb64b),
395
+ version: Vrsn_2_0,
396
+ });
397
+ const first = concatBytes(node.raw, Counter.enclose({
398
+ qb64: concatBytes(...frames[0].attachments.map(group => group.raw), publicOpeningAttachment(opening), seal),
399
+ version: Vrsn_2_0,
400
+ }));
401
+ const rest = yield* call(() => Promise.all(frames.slice(1).map(frame => collectPayload(nestedPayload(frame, Vrsn_2_0)))));
402
+ const raw = concatBytes(Counter.makeGVC(Vrsn_2_0), first, ...rest);
403
+ const payloads = yield* call(() => Promise.all(parseBytes(raw).map(frame => collectPayload(nestedPayload(frame, Vrsn_2_0)))));
404
+ return { exn: prepared.exn, raw, nests: concatBytes(...payloads) };
405
+ }
406
+ /** Select immutable admitted/transferred nests; proof refresh changes attachments only when explicitly requested. */
407
+ *selected(selection, offer = false) {
408
+ if ([selection.said, selection.fromGrant, selection.transferred].filter(value => value !== undefined).length !== 1) {
409
+ throw new ValidationError("Select exactly one issued credential, retained Grant or transferred view.");
410
+ }
411
+ const retained = Boolean(selection.fromGrant || selection.transferred);
412
+ if (selection.refresh && !retained)
413
+ throw new ValidationError("Refresh requires a retained view.");
414
+ if (retained && selection.artifacts) {
415
+ throw new ValidationError("A retained Grant keeps its exact original artifacts.");
416
+ }
417
+ if (retained && !selection.refresh
418
+ && (selection.derive || selection.openings?.length)) {
419
+ throw new ValidationError("New held-Grant proof requires explicit refresh.");
420
+ }
421
+ let held = selection.fromGrant
422
+ ? yield* call(() => this.credentials().held(selection.fromGrant, { presenterAuthorized: selection.presenterAuthorized }))
423
+ : null;
424
+ if (selection.transferred) {
425
+ if (selection.presenterAuthorized !== true) {
426
+ throw new ValidationError("Transferred view requires explicit presenter authorization.");
427
+ }
428
+ const frames = parseBytes(concatBytes(Counter.makeGVC(Vrsn_2_0), selection.transferred.slice()));
429
+ if (!frames.length || frames.some(frame => !(frame.body instanceof SerderACDC) || frame.nests?.length)) {
430
+ throw new ValidationError("Transferred view must contain direct credential node frames.");
431
+ }
432
+ const streams = yield* call(() => Promise.all(frames.map(frame => collectPayload(nestedPayload(frame, Vrsn_2_0)))));
433
+ held = { credential: frames[0].body, proof: streams[0], artifacts: streams.slice(1) };
434
+ }
435
+ const credential = this.partial(held?.credential ?? this.credentials().issued(selection.said), selection.disclose);
436
+ const original = held ? parseBytes(concatBytes(Counter.makeGVC(Vrsn_2_0), held.proof))[0] : null;
437
+ let origin;
438
+ if (offer)
439
+ origin = concatBytes(credential.raw, Counter.enclose({ qb64: new Uint8Array() }));
440
+ else if (held && !selection.refresh) {
441
+ origin = concatBytes(credential.raw, Counter.enclose({ qb64: concatBytes(...original.attachments.map((group) => group.raw)) }));
442
+ }
443
+ else {
444
+ const envelope = original ? envelopeFromFrame(original) : null;
445
+ const candidates = [
446
+ ...new Set(envelope?.ssts.filter((seal) => this.registry.seqEvent(seal.i.qb64, 0)).map((seal) => seal.i.qb64)),
447
+ ];
448
+ const regid = credential.regid
449
+ ?? (selection.said ? this.credentials().issuedRegistry(selection.said) : undefined)
450
+ ?? (candidates.length === 1 ? candidates[0] : undefined);
451
+ if (!regid)
452
+ throw new ValidationError("Selected issuer registry proof is unavailable.");
453
+ origin = this.registryProof(credential, regid, [
454
+ ...(envelope?.bsqs ?? []),
455
+ ...(envelope?.bsss ?? []),
456
+ ...(selection.openings ?? []),
457
+ ], selection);
458
+ }
459
+ const artifacts = selection.artifacts ?? held?.artifacts ?? [];
460
+ return concatBytes(Counter.makeGVC(Vrsn_2_0), origin, ...artifacts.map((raw) => offer
461
+ ? concatBytes(parseBytes(concatBytes(Counter.makeGVC(Vrsn_2_0), raw))[0].body.raw, Counter.enclose({ qb64: new Uint8Array() }))
462
+ : raw));
463
+ }
464
+ /** Offer only the selected commitment/view without issuer proof attachments. */
465
+ *prepareOffer(sender, selection, options) {
466
+ const hab = this.signer(sender, options.gvrsn ?? Vrsn_2_0), prior = yield* this.prior(options.priorSaid);
467
+ const raw = yield* this.selected(selection, true);
468
+ const [exn, nests] = yield* prepareIpexExn(sender, "/ipex/offer", raw, { ...options, prior });
469
+ return {
470
+ exn,
471
+ wire: exchangeWire(hab, exn, nests, undefined, options.gvrsn ?? Vrsn_2_0),
472
+ support: new Uint8Array(),
473
+ };
474
+ }
475
+ /** Select and authorize once before freezing a Grant body, without signing or committing group approval. */
476
+ *prepareGrantBody(sender, selection, options) {
477
+ return yield* this.grantBody(sender, selection, options, false);
478
+ }
479
+ /** Freeze an endorsement file from issued evidence, allowing only retryable current-opening absence. */
480
+ *prepareGrantFileBody(sender, selection, options) {
481
+ return yield* this.grantBody(sender, selection, options, true);
482
+ }
483
+ /** Both public preparation profiles preserve the same selected view and body construction. */
484
+ *grantBody(sender, selection, options, pendingPresentation) {
485
+ const hab = this.hby.habs.get(sender);
486
+ if (!hab?.kever || (options.gvrsn ?? Vrsn_2_0).major < 2) {
487
+ throw new ValidationError("ACDC v2 Grant preparation requires an accepted local sender and attachment genus 2.");
488
+ }
489
+ if (selection.derive && this.custody?.options.hab !== hab) {
490
+ throw new ValidationError("Derived disclosure requires the actual sender habitat's custody.");
491
+ }
492
+ const prior = yield* this.prior(options.priorSaid), raw = yield* this.selected(selection);
493
+ this.requireGraph(parseBytes(raw)[0].body.said, raw, pendingPresentation);
494
+ const [exn, nests] = yield* prepareIpexExn(sender, "/ipex/grant", raw, { ...options, prior });
495
+ return { exn, raw, nests };
496
+ }
497
+ /** Authenticate and authorize the selected graph before the Grant builder and after receipt waits. */
498
+ *prepareGrant(sender, selection, options) {
499
+ const hab = this.signer(sender, options.gvrsn ?? Vrsn_2_0);
500
+ const prepared = yield* this.prepareGrantBody(sender, selection, options);
501
+ let raw = prepared.raw;
502
+ const origin = parseBytes(raw)[0].body.said;
503
+ const exn = prepared.exn;
504
+ let nests = prepared.nests;
505
+ if (options.presentation) {
506
+ const reg = options.presentation, frames = parseBytes(raw), node = frames[0].body;
507
+ const attribute = node.sad.a;
508
+ if (reg.hab.pre !== sender || reg.store.baser !== this.registry.baser
509
+ || attribute?.rd !== reg.regk || attribute?.i !== sender || isLocalGroupHab(this.hby, reg.hab)) {
510
+ throw new ValidationError("Presentation registry must match the selected disclosed local Issuee declaration.");
511
+ }
512
+ // The Grant SAID is frozen before the BUP/KEL commitment. Only its nested proof is extended.
513
+ const [proof, update] = reg.present(exn, "presented", { stamp: options.stamp });
514
+ const seal = yield* anchorExchange(this.hby, this.receiptor, hab, update, options.auths);
515
+ reg.processEscrows();
516
+ if (reg.store.seqEvent(reg.regk, Number(BigInt(`0x${update.sad.n}`)))?.said !== update.said) {
517
+ throw new ValidationError("Presentation BUP remains pending authenticated acceptance.");
518
+ }
519
+ ({ raw, nests } = yield* this.attachPresentationProof({ exn, raw, nests }, proof, seal));
520
+ }
521
+ const source = exn.sad.a.ax?.[0]
522
+ ? yield* anchorExchange(this.hby, this.receiptor, hab, exn, options.auths)
523
+ : undefined;
524
+ this.requireGraph(origin, raw);
525
+ return {
526
+ exn,
527
+ wire: exchangeWire(hab, exn, nests, source, options.gvrsn ?? Vrsn_2_0),
528
+ support: this.proofSupport(raw, hab),
529
+ };
530
+ }
531
+ /** Inspect one exact unanchored Grant without dropping invalid signatures or publishing any evidence. */
532
+ inspectGrantFile(raw, selection) {
533
+ const frames = parseBytes(raw), frame = frames[0], message = frame?.body;
534
+ if (frames.length !== 1 || !(message instanceof SerderKERI) || !message.verify()
535
+ || message.pvrsn.major !== 2 || message.pvrsn.minor !== 0 || !["xip", "exn"].includes(message.ilk ?? "")
536
+ || message.route !== "/ipex/grant" || message.sad.a.ax?.[0]
537
+ || frame.essrs?.length || !frame.nests?.length
538
+ || frame.nests.some(node => !(node.body instanceof SerderACDC) || node.nests?.length || node.essrs?.length)
539
+ || selection && (message.said !== selection.said || message.pre !== selection.sender
540
+ || message.sad.ri !== selection.recipient)) {
541
+ throw new ValidationError("Select one exact unanchored v2 Grant, its disclosed nodes and declared parties.");
542
+ }
543
+ const factors = envelopeFromFrame(frame);
544
+ if (factors.attachmentGroups.some(group => ![
545
+ "TransIdxSigGroups",
546
+ "NonTransReceiptCouples",
547
+ "SealSourceTriples",
548
+ ].includes(group.name.replace(/^Big/, "")))) {
549
+ throw new ValidationError("Grant file permits only named authentication and exact nested evidence.");
550
+ }
551
+ const other = verifyExchangeProofs(this.hby.db, message, {
552
+ cigars: factors.cigars,
553
+ sourceSeals: factors.ssts,
554
+ });
555
+ if (other.invalid || other.missing.length) {
556
+ throw new ValidationError("Invalid or unavailable Grant authentication.");
557
+ }
558
+ const complete = new Set([
559
+ ...other.cigars.map(proof => proof.verfer.qb64),
560
+ ...other.sourceSeals.map(seal => seal.i.qb64),
561
+ ]);
562
+ const groups = new Map();
563
+ for (const group of factors.tsgs) {
564
+ const accepted = group.sn <= BigInt(Number.MAX_SAFE_INTEGER)
565
+ ? this.hby.db.kels.getLast(group.pre, Number(group.sn))
566
+ : null;
567
+ const event = accepted ? this.hby.db.getEvtSerder(group.pre, accepted) : null;
568
+ if (!group.prefixer.transferable || !event?.estive || !event.tholder || accepted !== group.said
569
+ || !group.sigers.length) {
570
+ throw new ValidationError("Grant contribution requires an accepted establishment event.");
571
+ }
572
+ const verified = Kever.verifyIndexedSignatures(message.raw, group.sigers, event.verfers);
573
+ if (new Set(verified.sigers.map(sig => sig.qb64)).size !== new Set(group.sigers.map(sig => sig.qb64)).size) {
574
+ throw new ValidationError("Invalid supplied Grant signature.");
575
+ }
576
+ const key = `${group.pre}:${group.sn}:${group.said}`;
577
+ const aggregate = groups.get(key) ?? { pre: group.pre, event, indices: new Set() };
578
+ for (const index of verified.indices)
579
+ aggregate.indices.add(index);
580
+ groups.set(key, aggregate);
581
+ }
582
+ const partial = new Set();
583
+ for (const { pre, event, indices } of groups.values()) {
584
+ if (event.tholder.satisfy([...indices]))
585
+ complete.add(pre);
586
+ else
587
+ partial.add(pre);
588
+ }
589
+ return { frame, completeSigners: [...complete], partialSigners: [...partial] };
590
+ }
591
+ }