keri-ts 2.1.0 → 2.2.1

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 (300) 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 +187 -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 +341 -0
  27. package/esm/keri/npm/src/app/ipex/group-issuance.js +905 -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 +50 -19
  33. package/esm/keri/npm/src/app/ipex/ipex-node-authentication.js +42 -18
  34. package/esm/keri/npm/src/app/ipex/issuance.js +896 -0
  35. package/esm/keri/npm/src/app/ipex/pending-presentations.js +46 -0
  36. package/esm/keri/npm/src/app/ipex/presentation-files.js +200 -0
  37. package/esm/keri/npm/src/app/ipex/presenting.js +408 -0
  38. package/esm/keri/npm/src/app/ipex/receive-issuance.js +86 -0
  39. package/esm/keri/npm/src/app/ipex/unblinding-workflow.js +667 -0
  40. package/esm/keri/npm/src/app/mailbox/ipex-arrival.js +103 -0
  41. package/esm/keri/npm/src/app/mailbox/kel-publisher.js +322 -0
  42. package/esm/keri/npm/src/app/mailbox/kel-publishing.js +65 -0
  43. package/esm/keri/npm/src/app/mailbox/kel-submission.js +24 -0
  44. package/esm/keri/npm/src/app/mailbox/mailbox-admin.js +208 -0
  45. package/esm/keri/npm/src/app/mailbox/mailbox-poller.js +212 -47
  46. package/esm/keri/npm/src/app/mailbox/mailboxing.js +10 -5
  47. package/esm/keri/npm/src/app/multisig/counseling.js +488 -0
  48. package/esm/keri/npm/src/app/multisig/group-members.js +18 -0
  49. package/esm/keri/npm/src/app/multisig/multisig-messaging.js +33 -6
  50. package/esm/keri/npm/src/app/multisig/multisig-workflows.js +98 -147
  51. package/esm/keri/npm/src/app/multisig/proposals.js +281 -0
  52. package/esm/keri/npm/src/app/multisig/proposing.js +122 -0
  53. package/esm/keri/npm/src/app/notifications/signaling.js +5 -5
  54. package/esm/keri/npm/src/app/protocol/parsering.js +26 -1
  55. package/esm/keri/npm/src/app/protocol/protocol-processing.js +9 -3
  56. package/esm/keri/npm/src/app/queries/query-workflows.js +98 -0
  57. package/esm/keri/npm/src/app/runtime/agent-runtime.js +106 -55
  58. package/esm/keri/npm/src/app/runtime/cue-runtime.js +3 -6
  59. package/esm/keri/npm/src/app/runtime/delivery-outbox.js +87 -0
  60. package/esm/keri/npm/src/app/runtime/doing.js +17 -0
  61. package/esm/keri/npm/src/app/runtime/ipex-auxiliaries.js +207 -0
  62. package/esm/keri/npm/src/app/runtime/operation-owners.js +151 -0
  63. package/esm/keri/npm/src/app/runtime/retry-backoff.js +93 -0
  64. package/esm/keri/npm/src/app/runtime/workflow-contract.js +80 -0
  65. package/esm/keri/npm/src/app/transport/http-client.js +25 -6
  66. package/esm/keri/npm/src/app/witness/http-endpoints.js +4 -4
  67. package/esm/keri/npm/src/cli/common/event-completion.js +49 -0
  68. package/esm/keri/npm/src/cli/common/runtime-workers.js +23 -0
  69. package/esm/keri/npm/src/cli/credentials/ipex.js +164 -191
  70. package/esm/keri/npm/src/cli/credentials/vc.js +53 -72
  71. package/esm/keri/npm/src/cli/endpoints/did.js +12 -3
  72. package/esm/keri/npm/src/cli/endpoints/oobi.js +10 -13
  73. package/esm/keri/npm/src/cli/identity/challenge.js +8 -34
  74. package/esm/keri/npm/src/cli/identity/delegate.js +81 -258
  75. package/esm/keri/npm/src/cli/identity/incept.js +15 -32
  76. package/esm/keri/npm/src/cli/identity/interact.js +5 -17
  77. package/esm/keri/npm/src/cli/identity/rotate.js +8 -36
  78. package/esm/keri/npm/src/cli/index.js +3 -1
  79. package/esm/keri/npm/src/cli/messaging/group-join.js +83 -0
  80. package/esm/keri/npm/src/cli/messaging/group-wait.js +88 -0
  81. package/esm/keri/npm/src/cli/messaging/multisig.js +190 -285
  82. package/esm/keri/npm/src/cli/messaging/root-copy-lines.js +31 -0
  83. package/esm/keri/npm/src/core/kel/eventing.js +66 -10
  84. package/esm/keri/npm/src/core/mailbox/kram-policy.js +39 -6
  85. package/esm/keri/npm/src/core/mailbox/kraming.js +2 -0
  86. package/esm/keri/npm/src/core/records.js +23 -0
  87. package/esm/keri/npm/src/core/routing.js +13 -0
  88. package/esm/keri/npm/src/db/basing.js +34 -2
  89. package/esm/keri/npm/src/db/core/indexeddb-persistence.js +221 -0
  90. package/esm/keri/npm/src/db/indexeddb.js +98 -0
  91. package/esm/keri/npm/src/db/keeping.js +11 -2
  92. package/esm/keri/npm/src/db/store-lock.js +150 -0
  93. package/esm/keri/npm/src/npm/db-indexeddb.browser.js +2 -0
  94. package/esm/keri/npm/src/npm/db-indexeddb.js +3 -0
  95. package/esm/keri/npm/src/npm/db.browser.js +2 -0
  96. package/esm/keri/npm/src/npm/index.browser.js +9 -0
  97. package/esm/keri/npm/src/npm/runtime-web.browser.js +2 -0
  98. package/esm/keri/npm/src/npm/runtime-web.js +3 -0
  99. package/esm/keri/npm/src/npm/runtime.browser.js +2 -0
  100. package/esm/keri/npm/src/runtime/index.js +51 -4
  101. package/esm/keri/npm/src/runtime/web/output-barrier.js +47 -0
  102. package/esm/keri/npm/src/runtime/web/persistent-storage.js +37 -0
  103. package/esm/keri/npm/src/runtime/web.js +10 -0
  104. package/esm/keri/npm/src/vdr/tel-publication.js +16 -0
  105. package/esm/keri/npm/src/version.js +2 -2
  106. package/package.json +15 -2
  107. package/types/acdc/authoring.d.ts +54 -0
  108. package/types/acdc/authoring.d.ts.map +1 -0
  109. package/types/acdc/custody.d.ts +84 -0
  110. package/types/acdc/custody.d.ts.map +1 -0
  111. package/types/acdc/dhking.d.ts +94 -3
  112. package/types/acdc/dhking.d.ts.map +1 -1
  113. package/types/acdc/regbasing.d.ts +4 -0
  114. package/types/acdc/regbasing.d.ts.map +1 -1
  115. package/types/acdc/salting.d.ts +6 -1
  116. package/types/acdc/salting.d.ts.map +1 -1
  117. package/types/acdc/scheming.d.ts +2 -0
  118. package/types/acdc/scheming.d.ts.map +1 -1
  119. package/types/acdc/unblinding.d.ts +58 -19
  120. package/types/acdc/unblinding.d.ts.map +1 -1
  121. package/types/app/bootstrap/authenticating.d.ts +3 -1
  122. package/types/app/bootstrap/authenticating.d.ts.map +1 -1
  123. package/types/app/bootstrap/oobi-resolving.d.ts +92 -0
  124. package/types/app/bootstrap/oobi-resolving.d.ts.map +1 -0
  125. package/types/app/bootstrap/oobiery.d.ts +3 -1
  126. package/types/app/bootstrap/oobiery.d.ts.map +1 -1
  127. package/types/app/credentials/credential-revoking.d.ts +3 -0
  128. package/types/app/credentials/credential-revoking.d.ts.map +1 -1
  129. package/types/app/credentials/credential-workflows.d.ts +5 -0
  130. package/types/app/credentials/credential-workflows.d.ts.map +1 -1
  131. package/types/app/credentials/registry-settling.d.ts +85 -0
  132. package/types/app/credentials/registry-settling.d.ts.map +1 -0
  133. package/types/app/credentials/root-replicating.d.ts +56 -44
  134. package/types/app/credentials/root-replicating.d.ts.map +1 -1
  135. package/types/app/credentials/root-replicator.d.ts +105 -0
  136. package/types/app/credentials/root-replicator.d.ts.map +1 -0
  137. package/types/app/credentials/tel-completion.d.ts +55 -0
  138. package/types/app/credentials/tel-completion.d.ts.map +1 -0
  139. package/types/app/delivery/forwarding.d.ts +6 -0
  140. package/types/app/delivery/forwarding.d.ts.map +1 -1
  141. package/types/app/exchanges/exchanging.d.ts.map +1 -1
  142. package/types/app/identity/challenging.d.ts +54 -0
  143. package/types/app/identity/challenging.d.ts.map +1 -1
  144. package/types/app/identity/delegating.d.ts +21 -4
  145. package/types/app/identity/delegating.d.ts.map +1 -1
  146. package/types/app/identity/delegation-approval.d.ts +228 -0
  147. package/types/app/identity/delegation-approval.d.ts.map +1 -0
  148. package/types/app/identity/event-completion.d.ts +151 -0
  149. package/types/app/identity/event-completion.d.ts.map +1 -0
  150. package/types/app/identity/habbing.d.ts +67 -2
  151. package/types/app/identity/habbing.d.ts.map +1 -1
  152. package/types/app/identity/keeping.d.ts +49 -3
  153. package/types/app/identity/keeping.d.ts.map +1 -1
  154. package/types/app/ipex/group-ipex.d.ts +254 -0
  155. package/types/app/ipex/group-ipex.d.ts.map +1 -0
  156. package/types/app/ipex/group-issuance.d.ts +281 -0
  157. package/types/app/ipex/group-issuance.d.ts.map +1 -0
  158. package/types/app/ipex/ipex-admitting.d.ts +47 -0
  159. package/types/app/ipex/ipex-admitting.d.ts.map +1 -0
  160. package/types/app/ipex/ipex-conversation.d.ts +195 -0
  161. package/types/app/ipex/ipex-conversation.d.ts.map +1 -0
  162. package/types/app/ipex/ipex-discloser.d.ts +156 -0
  163. package/types/app/ipex/ipex-discloser.d.ts.map +1 -0
  164. package/types/app/ipex/ipex-granting.d.ts +145 -0
  165. package/types/app/ipex/ipex-granting.d.ts.map +1 -0
  166. package/types/app/ipex/ipex-grouping.d.ts +18 -0
  167. package/types/app/ipex/ipex-grouping.d.ts.map +1 -1
  168. package/types/app/ipex/ipex-node-authentication.d.ts +9 -1
  169. package/types/app/ipex/ipex-node-authentication.d.ts.map +1 -1
  170. package/types/app/ipex/issuance.d.ts +445 -0
  171. package/types/app/ipex/issuance.d.ts.map +1 -0
  172. package/types/app/ipex/pending-presentations.d.ts +25 -0
  173. package/types/app/ipex/pending-presentations.d.ts.map +1 -0
  174. package/types/app/ipex/presentation-files.d.ts +47 -0
  175. package/types/app/ipex/presentation-files.d.ts.map +1 -0
  176. package/types/app/ipex/presenting.d.ts +300 -0
  177. package/types/app/ipex/presenting.d.ts.map +1 -0
  178. package/types/app/ipex/receive-issuance.d.ts +99 -0
  179. package/types/app/ipex/receive-issuance.d.ts.map +1 -0
  180. package/types/app/ipex/unblinding-workflow.d.ts +257 -0
  181. package/types/app/ipex/unblinding-workflow.d.ts.map +1 -0
  182. package/types/app/mailbox/ipex-arrival.d.ts +104 -0
  183. package/types/app/mailbox/ipex-arrival.d.ts.map +1 -0
  184. package/types/app/mailbox/kel-publisher.d.ts +141 -0
  185. package/types/app/mailbox/kel-publisher.d.ts.map +1 -0
  186. package/types/app/mailbox/kel-publishing.d.ts +70 -0
  187. package/types/app/mailbox/kel-publishing.d.ts.map +1 -0
  188. package/types/app/mailbox/kel-submission.d.ts +18 -0
  189. package/types/app/mailbox/kel-submission.d.ts.map +1 -0
  190. package/types/app/mailbox/mailbox-admin.d.ts +113 -0
  191. package/types/app/mailbox/mailbox-admin.d.ts.map +1 -0
  192. package/types/app/mailbox/mailbox-poller.d.ts +92 -3
  193. package/types/app/mailbox/mailbox-poller.d.ts.map +1 -1
  194. package/types/app/mailbox/mailboxing.d.ts +3 -0
  195. package/types/app/mailbox/mailboxing.d.ts.map +1 -1
  196. package/types/app/multisig/counseling.d.ts +196 -0
  197. package/types/app/multisig/counseling.d.ts.map +1 -0
  198. package/types/app/multisig/group-members.d.ts +11 -0
  199. package/types/app/multisig/group-members.d.ts.map +1 -1
  200. package/types/app/multisig/grouping.d.ts +39 -20
  201. package/types/app/multisig/grouping.d.ts.map +1 -1
  202. package/types/app/multisig/multisig-messaging.d.ts +23 -6
  203. package/types/app/multisig/multisig-messaging.d.ts.map +1 -1
  204. package/types/app/multisig/multisig-workflows.d.ts +91 -22
  205. package/types/app/multisig/multisig-workflows.d.ts.map +1 -1
  206. package/types/app/multisig/proposals.d.ts +129 -0
  207. package/types/app/multisig/proposals.d.ts.map +1 -0
  208. package/types/app/multisig/proposing.d.ts +125 -0
  209. package/types/app/multisig/proposing.d.ts.map +1 -0
  210. package/types/app/notifications/signaling.d.ts +3 -1
  211. package/types/app/notifications/signaling.d.ts.map +1 -1
  212. package/types/app/protocol/parsering.d.ts +13 -0
  213. package/types/app/protocol/parsering.d.ts.map +1 -1
  214. package/types/app/protocol/protocol-processing.d.ts +7 -1
  215. package/types/app/protocol/protocol-processing.d.ts.map +1 -1
  216. package/types/app/queries/query-workflows.d.ts +98 -0
  217. package/types/app/queries/query-workflows.d.ts.map +1 -0
  218. package/types/app/runtime/agent-runtime.d.ts +72 -25
  219. package/types/app/runtime/agent-runtime.d.ts.map +1 -1
  220. package/types/app/runtime/cue-runtime.d.ts +2 -1
  221. package/types/app/runtime/cue-runtime.d.ts.map +1 -1
  222. package/types/app/runtime/delivery-outbox.d.ts +68 -0
  223. package/types/app/runtime/delivery-outbox.d.ts.map +1 -0
  224. package/types/app/runtime/doing.d.ts +27 -0
  225. package/types/app/runtime/doing.d.ts.map +1 -0
  226. package/types/app/runtime/ipex-auxiliaries.d.ts +74 -0
  227. package/types/app/runtime/ipex-auxiliaries.d.ts.map +1 -0
  228. package/types/app/runtime/operation-owners.d.ts +137 -0
  229. package/types/app/runtime/operation-owners.d.ts.map +1 -0
  230. package/types/app/runtime/retry-backoff.d.ts +49 -0
  231. package/types/app/runtime/retry-backoff.d.ts.map +1 -0
  232. package/types/app/runtime/workflow-contract.d.ts +79 -0
  233. package/types/app/runtime/workflow-contract.d.ts.map +1 -0
  234. package/types/app/transport/http-client.d.ts.map +1 -1
  235. package/types/cli/common/event-completion.d.ts +26 -0
  236. package/types/cli/common/event-completion.d.ts.map +1 -0
  237. package/types/cli/common/runtime-workers.d.ts +23 -0
  238. package/types/cli/common/runtime-workers.d.ts.map +1 -0
  239. package/types/cli/credentials/ipex.d.ts.map +1 -1
  240. package/types/cli/credentials/vc.d.ts +1 -1
  241. package/types/cli/credentials/vc.d.ts.map +1 -1
  242. package/types/cli/endpoints/did.d.ts.map +1 -1
  243. package/types/cli/endpoints/oobi.d.ts +3 -1
  244. package/types/cli/endpoints/oobi.d.ts.map +1 -1
  245. package/types/cli/identity/challenge.d.ts +1 -1
  246. package/types/cli/identity/challenge.d.ts.map +1 -1
  247. package/types/cli/identity/delegate.d.ts +14 -1
  248. package/types/cli/identity/delegate.d.ts.map +1 -1
  249. package/types/cli/identity/incept.d.ts.map +1 -1
  250. package/types/cli/identity/interact.d.ts.map +1 -1
  251. package/types/cli/identity/rotate.d.ts.map +1 -1
  252. package/types/cli/index.d.ts +3 -1
  253. package/types/cli/index.d.ts.map +1 -1
  254. package/types/cli/messaging/group-join.d.ts +56 -0
  255. package/types/cli/messaging/group-join.d.ts.map +1 -0
  256. package/types/cli/messaging/group-wait.d.ts +34 -0
  257. package/types/cli/messaging/group-wait.d.ts.map +1 -0
  258. package/types/cli/messaging/multisig.d.ts +29 -5
  259. package/types/cli/messaging/multisig.d.ts.map +1 -1
  260. package/types/cli/messaging/root-copy-lines.d.ts +39 -0
  261. package/types/cli/messaging/root-copy-lines.d.ts.map +1 -0
  262. package/types/core/cues.d.ts +11 -0
  263. package/types/core/cues.d.ts.map +1 -1
  264. package/types/core/kel/eventing.d.ts.map +1 -1
  265. package/types/core/mailbox/kram-policy.d.ts +14 -0
  266. package/types/core/mailbox/kram-policy.d.ts.map +1 -1
  267. package/types/core/mailbox/kraming.d.ts +1 -1
  268. package/types/core/mailbox/kraming.d.ts.map +1 -1
  269. package/types/core/records.d.ts +61 -0
  270. package/types/core/records.d.ts.map +1 -1
  271. package/types/core/routing.d.ts +6 -0
  272. package/types/core/routing.d.ts.map +1 -1
  273. package/types/db/basing.d.ts +8 -2
  274. package/types/db/basing.d.ts.map +1 -1
  275. package/types/db/core/indexeddb-persistence.d.ts +59 -0
  276. package/types/db/core/indexeddb-persistence.d.ts.map +1 -0
  277. package/types/db/indexeddb.d.ts +37 -0
  278. package/types/db/indexeddb.d.ts.map +1 -0
  279. package/types/db/keeping.d.ts +5 -2
  280. package/types/db/keeping.d.ts.map +1 -1
  281. package/types/db/store-lock.d.ts +72 -0
  282. package/types/db/store-lock.d.ts.map +1 -0
  283. package/types/npm/db-indexeddb.d.ts +4 -0
  284. package/types/npm/db-indexeddb.d.ts.map +1 -0
  285. package/types/npm/runtime-web.d.ts +4 -0
  286. package/types/npm/runtime-web.d.ts.map +1 -0
  287. package/types/runtime/index.d.ts +42 -7
  288. package/types/runtime/index.d.ts.map +1 -1
  289. package/types/runtime/web/output-barrier.d.ts +30 -0
  290. package/types/runtime/web/output-barrier.d.ts.map +1 -0
  291. package/types/runtime/web/persistent-storage.d.ts +36 -0
  292. package/types/runtime/web/persistent-storage.d.ts.map +1 -0
  293. package/types/runtime/web.d.ts +11 -0
  294. package/types/runtime/web.d.ts.map +1 -0
  295. package/types/vdr/tel-publication.d.ts +6 -0
  296. package/types/vdr/tel-publication.d.ts.map +1 -1
  297. package/types/version.d.ts +2 -2
  298. package/esm/keri/npm/src/cli/common/tel-completion.js +0 -24
  299. package/types/cli/common/tel-completion.d.ts +0 -8
  300. package/types/cli/common/tel-completion.d.ts.map +0 -1
@@ -2,9 +2,13 @@ import * as dntShim from "../../_dnt.shims.js";
2
2
  import { concatBytes, Counter, parse, SerderKERI } from "cesr-ts";
3
3
  import { action, spawn } from "effection";
4
4
  import { Organizer } from "../../app/identity/organizing.js";
5
- import { credentialSaidFromGrant, ipexCredentialAdmit, ipexCredentialGrant, processCredentialPresentationArtifacts, storedGrantArtifacts, validateAdmitGrant, } from "../../app/ipex/ipex-credentialing.js";
5
+ import { approveGroupIpex, waitForGroupIpex } from "../../app/ipex/group-ipex.js";
6
+ import { requireIpexPrior, sendIpexAgree, sendIpexApply, sendIpexOffer, sendIpexSpurn, waitForIpexExchange, } from "../../app/ipex/ipex-conversation.js";
7
+ import { ipexCredentialAdmit, ipexCredentialGrant, } from "../../app/ipex/ipex-credentialing.js";
8
+ import { requireAdmittableGrant, sendIpexAdmit, sendIpexGrant, settleGrantCredential, } from "../../app/ipex/ipex-granting.js";
6
9
  import { approveMultisigIpex, approveStoredMultisigIpexWrappers, findPendingMultisigIpex, groupIpexPartial, publishInitialGroupIpex, requireStoredExchange, sendCompletedGroupIpex, sendCredentialStream, storedExchangeMessage, storedMultisigIpexBody, } from "../../app/ipex/ipex-grouping.js";
7
- import { IPEX_ADMIT_ROUTE, IPEX_AGREE_ROUTE, IPEX_APPLY_ROUTE, IPEX_GRANT_ROUTE, IPEX_OFFER_ROUTE, IPEX_SPURN_ROUTE, validateIpexReply, } from "../../app/ipex/ipexing.js";
10
+ import { IPEX_ADMIT_ROUTE, IPEX_AGREE_ROUTE, IPEX_APPLY_ROUTE, IPEX_GRANT_ROUTE, IPEX_OFFER_ROUTE, IPEX_SPURN_ROUTE, } from "../../app/ipex/ipexing.js";
11
+ import { ipexBaseline, MailboxIntakeTally, settleStoredGrants, waitForIpexArrival, } from "../../app/mailbox/ipex-arrival.js";
8
12
  import { isLocalGroupHab, localGroupMember } from "../../app/multisig/group-members.js";
9
13
  import { MULTISIG_EXN_ROUTE } from "../../app/multisig/grouping.js";
10
14
  import { abortable } from "../../app/runtime/abortable.js";
@@ -14,9 +18,9 @@ import { fileBytes } from "../../app/transport/file-bytes.js";
14
18
  import { parseGvrsn } from "../../core/attachment-countering.js";
15
19
  import { ValidationError } from "../../core/errors.js";
16
20
  import { exchange } from "../../core/exchange/protocol-exchanging.js";
17
- import { CREDENTIAL_MAILBOX_TOPIC } from "../../core/mailbox/mailbox-topics.js";
18
21
  import { withAgentRuntime } from "../common/context.js";
19
22
  import { parseBooleanOption, parseNumberOption, parseStringOption } from "../common/parsing.js";
23
+ import { withRuntimeWorkers } from "../common/runtime-workers.js";
20
24
  /**
21
25
  * Implement `tufa ipex apply` by sending a schema/attribute request EXN.
22
26
  *
@@ -31,13 +35,22 @@ export function* ipexApplyCommand(args) {
31
35
  return yield* withIpexRuntime(ipexArgs, function* ({ hby, runtime }) {
32
36
  const hab = requireHab(hby, ipexArgs.alias);
33
37
  const recipient = new Organizer(hby.db, hby.signator).resolveRecipient(requireString(ipexArgs.recipient, "Recipient"));
34
- const prepared = exchange(IPEX_APPLY_ROUTE, {
35
- m: ipexArgs.message ?? "",
36
- s: schema,
37
- a: attrs,
38
- i: recipient,
39
- }, { sender: hab.pre, recipient });
40
- return yield* sendConversation(hby, runtime, hab, recipient, prepared, timeout);
38
+ if (isLocalGroupHab(hby, hab)) {
39
+ // TODO(group proposal API): replace with the multisig proposal API from app/multisig/counseling.ts.
40
+ const prepared = exchange(IPEX_APPLY_ROUTE, {
41
+ m: ipexArgs.message ?? "",
42
+ s: schema,
43
+ a: attrs,
44
+ i: recipient,
45
+ }, { sender: hab.pre, recipient });
46
+ return yield* sendGroupConversation(hby, runtime, hab, recipient, prepared, timeout);
47
+ }
48
+ return yield* withRuntimeWorkers(runtime, { hab }, () => sendIpexApply(ipexSendDeps(hby, runtime), hab, {
49
+ recipient,
50
+ schema: schema,
51
+ attrs,
52
+ message: ipexArgs.message,
53
+ }));
41
54
  });
42
55
  }
43
56
  /**
@@ -54,15 +67,21 @@ export function* ipexOfferCommand(args) {
54
67
  return yield* withIpexRuntime(ipexArgs, function* ({ hby, runtime }) {
55
68
  const hab = requireHab(hby, ipexArgs.alias);
56
69
  const recipient = new Organizer(hby.db, hby.signator).resolveRecipient(requireString(ipexArgs.recipient, "Recipient"));
70
+ // A bad prior is reported before an unreadable ACDC file.
57
71
  if (apply)
58
- requireConversationPrior(hby, hab, recipient, apply, "offer");
59
- const prepared = exchange(IPEX_OFFER_ROUTE, { m: ipexArgs.message ?? "" }, {
60
- sender: hab.pre,
61
- recipient,
62
- dig: apply,
63
- embeds: { acdc: dntShim.Deno.readFileSync(acdcFile) },
64
- });
65
- return yield* sendConversation(hby, runtime, hab, recipient, prepared, timeout);
72
+ requireIpexPrior(hby, hab.pre, recipient, apply, "offer");
73
+ const acdc = dntShim.Deno.readFileSync(acdcFile);
74
+ if (isLocalGroupHab(hby, hab)) {
75
+ // TODO(group proposal API): replace with the multisig proposal API from app/multisig/counseling.ts.
76
+ const prepared = exchange(IPEX_OFFER_ROUTE, { m: ipexArgs.message ?? "" }, {
77
+ sender: hab.pre,
78
+ recipient,
79
+ dig: apply,
80
+ embeds: { acdc },
81
+ });
82
+ return yield* sendGroupConversation(hby, runtime, hab, recipient, prepared, timeout);
83
+ }
84
+ return yield* withRuntimeWorkers(runtime, { hab }, () => sendIpexOffer(ipexSendDeps(hby, runtime), hab, { recipient, acdc, apply, message: ipexArgs.message }));
66
85
  });
67
86
  }
68
87
  /** Implement `tufa ipex agree` as a response to an accepted offer EXN. */
@@ -80,13 +99,17 @@ export function* ipexSpurnCommand(args) {
80
99
  return yield* withIpexRuntime(ipexArgs, function* ({ hby, runtime }) {
81
100
  const hab = requireHab(hby, ipexArgs.alias);
82
101
  const dest = new Organizer(hby.db, hby.signator).resolveRecipient(requireString(ipexArgs.recipient, "Recipient"));
83
- requireConversationPrior(hby, hab, dest, prior, "spurn");
84
- const prepared = exchange(IPEX_SPURN_ROUTE, { m: ipexArgs.message ?? "" }, {
85
- sender: hab.pre,
86
- recipient: dest,
87
- dig: prior,
88
- });
89
- return yield* sendConversation(hby, runtime, hab, dest, prepared, timeout);
102
+ if (isLocalGroupHab(hby, hab)) {
103
+ requireIpexPrior(hby, hab.pre, dest, prior, "spurn");
104
+ // TODO(group proposal API): replace with the multisig proposal API from app/multisig/counseling.ts.
105
+ const prepared = exchange(IPEX_SPURN_ROUTE, { m: ipexArgs.message ?? "" }, {
106
+ sender: hab.pre,
107
+ recipient: dest,
108
+ dig: prior,
109
+ });
110
+ return yield* sendGroupConversation(hby, runtime, hab, dest, prepared, timeout);
111
+ }
112
+ return yield* withRuntimeWorkers(runtime, { hab }, () => sendIpexSpurn(ipexSendDeps(hby, runtime), hab, { recipient: dest, prior, message: ipexArgs.message }));
90
113
  });
91
114
  }
92
115
  /**
@@ -113,9 +136,29 @@ export function* ipexGrantCommand(args) {
113
136
  else {
114
137
  recipient = new Organizer(hby.db, hby.signator).resolveRecipient(selectedRecipient);
115
138
  }
139
+ if (!isLocalGroupHab(hby, hab)) {
140
+ return yield* withRuntimeWorkers(runtime, { hab }, function* () {
141
+ const sent = yield* sendIpexGrant({ ...ipexSendDeps(hby, runtime), reger }, hab, {
142
+ recipient,
143
+ credential: ipexArgs.said,
144
+ message: ipexArgs.message,
145
+ agree: ipexArgs.agree,
146
+ gvrsn: ipexArgs.gvrsn,
147
+ deliver: !ipexArgs.out,
148
+ });
149
+ if (ipexArgs.out)
150
+ dntShim.Deno.writeFileSync(ipexArgs.out, concatBytes(...sent.support, sent.wire));
151
+ return {
152
+ grant: sent.grant,
153
+ credential: ipexArgs.said,
154
+ support: sent.support.length,
155
+ deliveries: sent.deliveries,
156
+ };
157
+ });
158
+ }
159
+ // TODO(group proposal API): replace the group branch with the multisig proposal API from app/multisig/counseling.ts.
116
160
  if (ipexArgs.agree)
117
161
  requireConversationPrior(hby, hab, recipient, ipexArgs.agree, "grant");
118
- const group = isLocalGroupHab(hby, hab);
119
162
  const grant = ipexCredentialGrant({
120
163
  hby,
121
164
  hab,
@@ -127,26 +170,14 @@ export function* ipexGrantCommand(args) {
127
170
  agree: ipexArgs.agree ? hby.db.exns.get([ipexArgs.agree]) : null,
128
171
  gvrsn: ipexArgs.gvrsn,
129
172
  },
130
- sign: !group,
173
+ sign: false,
131
174
  });
132
175
  const genus = grant.grant.gvrsn ?? ipexArgs.gvrsn ?? grant.grant.pvrsn;
133
- const wire = group ? groupIpexPartial(hby, hab, grant.grant, grant.attachments, genus) : grant.wire;
134
- const signer = group ? localGroupMember(hby, hab.pre) : hab;
135
- const host = yield* spawn(() => runAgentRuntime(runtime, { hab: signer, pollMailbox: group }));
136
- try {
176
+ const wire = groupIpexPartial(hby, hab, grant.grant, grant.attachments, genus);
177
+ const signer = localGroupMember(hby, hab.pre);
178
+ return yield* withRuntimeWorkers(runtime, { hab: signer, pollMailbox: true }, function* () {
137
179
  yield* runtime.reactor.processBytes(concatBytes(Counter.makeGVC(genus), wire), { local: true });
138
180
  yield* runtime.protocol.processEscrowsOnce();
139
- if (!group) {
140
- if (!runtime.exc.complete(grant.grant.said))
141
- throw new ValidationError("Local IPEX grant was not accepted.");
142
- const deliveries = [];
143
- if (!ipexArgs.out) {
144
- deliveries.push(...yield* sendCredentialStream(runtime.postman, hab, recipient, [...grant.support, wire]));
145
- }
146
- if (ipexArgs.out)
147
- dntShim.Deno.writeFileSync(ipexArgs.out, concatBytes(...grant.support, wire));
148
- return { grant: grant.grant, credential: ipexArgs.said, support: grant.support.length, deliveries };
149
- }
150
181
  const publication = yield* publishInitialGroupIpex(hby, runtime.protocol, runtime.postman, hab, wire, genus);
151
182
  const complete = yield* waitForGroupIpexApproval(hby, runtime.protocol, grant.grant.said, ipexArgs.approvalTimeoutSeconds, reger);
152
183
  const deliveries = [...publication.deliveries];
@@ -174,10 +205,7 @@ export function* ipexGrantCommand(args) {
174
205
  deliveries,
175
206
  group: { ...publication, complete: true, lead },
176
207
  };
177
- }
178
- finally {
179
- yield* host.halt();
180
- }
208
+ });
181
209
  });
182
210
  }
183
211
  /**
@@ -202,18 +230,26 @@ export function* ipexAdmitCommand(args) {
202
230
  const selected = yield* loadGrant(hby, ipexArgs);
203
231
  const group = isLocalGroupHab(hby, hab);
204
232
  const signer = group ? localGroupMember(hby, hab.pre) : hab;
205
- const host = yield* spawn(() => runAgentRuntime(runtime, { hab: signer, pollMailbox: group }));
206
- try {
233
+ return yield* withRuntimeWorkers(runtime, { hab: signer, pollMailbox: group }, function* () {
207
234
  if (selected.wire)
208
235
  yield* runtime.reactor.processBytes(selected.wire);
209
- const grant = requireStoredExchange(hby, selected.grant.said);
210
- const recipient = grantSender(grant);
211
- requireConversationPrior(hby, hab, recipient, grant.said, "admit");
212
- const credential = validateAdmitGrant(grant, hab.pre, reger, false);
236
+ const { grant, recipient, credential } = requireAdmittableGrant({ hby, reger }, hab, selected.grant.said);
213
237
  if (!ipexArgs.noWait
214
- && !(yield* settleGrantCredential(hby, runtime.protocol, reger, grant, hab.pre, ipexArgs.gvrsn, ipexArgs.timeout))) {
238
+ && !(yield* settleAndWaitForCredential(hby, runtime.protocol, reger, grant, hab.pre, ipexArgs.gvrsn, ipexArgs.timeout))) {
215
239
  return { admit: null, grant, credential, saved: false, deliveries: [] };
216
240
  }
241
+ if (!group) {
242
+ const sent = yield* sendIpexAdmit({ ...ipexSendDeps(hby, runtime), reger }, hab, grant.said, {
243
+ message: ipexArgs.message,
244
+ gvrsn: ipexArgs.gvrsn,
245
+ requireSaved: !ipexArgs.noWait,
246
+ deliver: !ipexArgs.out,
247
+ });
248
+ if (ipexArgs.out)
249
+ dntShim.Deno.writeFileSync(ipexArgs.out, sent.wire);
250
+ return { admit: sent.admit, grant, credential, saved: sent.saved, deliveries: sent.deliveries };
251
+ }
252
+ // TODO(group proposal API): replace the group branch with the multisig proposal API from app/multisig/counseling.ts.
217
253
  const saved = !!reger.saved.get([credential]);
218
254
  const prepared = ipexCredentialAdmit({
219
255
  hab,
@@ -221,23 +257,13 @@ export function* ipexAdmitCommand(args) {
221
257
  grant,
222
258
  message: ipexArgs.message ?? "",
223
259
  options: { requireSaved: !ipexArgs.noWait, gvrsn: ipexArgs.gvrsn },
224
- sign: !group,
260
+ sign: false,
225
261
  });
226
262
  const genus = prepared.admit.gvrsn ?? ipexArgs.gvrsn ?? prepared.admit.pvrsn;
227
- const wire = group ? groupIpexPartial(hby, hab, prepared.admit, prepared.attachments, genus) : prepared.wire;
263
+ const wire = groupIpexPartial(hby, hab, prepared.admit, prepared.attachments, genus);
228
264
  yield* runtime.reactor.processBytes(concatBytes(Counter.makeGVC(genus), wire), { local: true });
229
265
  yield* runtime.protocol.processEscrowsOnce();
230
266
  const deliveries = [];
231
- if (!group) {
232
- if (!runtime.exc.complete(prepared.admit.said)) {
233
- throw new ValidationError("Local IPEX admit was not accepted.");
234
- }
235
- if (ipexArgs.out)
236
- dntShim.Deno.writeFileSync(ipexArgs.out, wire);
237
- else
238
- deliveries.push(...yield* sendCredentialStream(runtime.postman, signer, recipient, [wire]));
239
- return { admit: prepared.admit, grant, credential, saved, deliveries };
240
- }
241
267
  const publication = yield* publishInitialGroupIpex(hby, runtime.protocol, runtime.postman, hab, wire, genus);
242
268
  deliveries.push(...publication.deliveries);
243
269
  const complete = yield* waitForGroupIpexApproval(hby, runtime.protocol, prepared.admit.said, ipexArgs.approvalTimeoutSeconds, reger);
@@ -251,10 +277,7 @@ export function* ipexAdmitCommand(args) {
251
277
  }
252
278
  }
253
279
  return { admit: prepared.admit, grant, credential, saved, deliveries, group: { ...publication, complete, lead } };
254
- }
255
- finally {
256
- yield* host.halt();
257
- }
280
+ });
258
281
  });
259
282
  }
260
283
  /** Implement `tufa ipex list` by printing locally accepted IPEX EXNs. */
@@ -281,55 +304,30 @@ export function* ipexPollCommand(args) {
281
304
  const timeoutMs = nonNegativeNumber(args.timeout, 40, "poll timeout seconds") * 1000;
282
305
  return yield* withIpexRuntime(ipexArgs, function* ({ hby, runtime, reger }) {
283
306
  const hab = ipexArgs.alias ? requireHab(hby, ipexArgs.alias) : undefined;
284
- const beforeExns = new Set([...hby.db.exns.getTopItemIter()]
285
- .map(([, exn]) => exn.said)
286
- .filter((said) => typeof said === "string"));
287
- const beforeSaved = savedCredentials(reger);
288
- let batchesSeen = 0;
289
- let messagesSeen = 0;
307
+ const arrivals = { hby, reger };
308
+ const baseline = ipexBaseline(arrivals);
309
+ const tally = new MailboxIntakeTally();
290
310
  const signer = hab && isLocalGroupHab(hby, hab) ? localGroupMember(hby, hab.pre) : hab;
291
- const deadline = Date.now() + timeoutMs;
292
- let receiving = 0;
293
- const host = yield* spawn(() => runAgentRuntime(runtime, { hab: signer, pollMailbox: false }));
294
- try {
311
+ // The CLI has no running runtime: it runs the workers and a mailbox poller around the library wait.
312
+ const result = yield* withRuntimeWorkers(runtime, { hab: signer, pollMailbox: false }, function* () {
295
313
  const mailbox = yield* spawn(function* () {
296
- yield* runtime.mailboxPoller.pollDo(function* (batch) {
297
- receiving++;
298
- try {
299
- yield* settleMailboxPollBatch(runtime, batch);
300
- batchesSeen++;
301
- messagesSeen += batch.messages.length;
302
- }
303
- finally {
304
- receiving--;
305
- }
306
- });
314
+ yield* runtime.mailboxPoller.pollDo((batch) => tally.track(batch, () => settleMailboxPollBatch(runtime, batch)));
307
315
  });
308
316
  try {
309
- while (true) {
310
- yield* processStoredCredentialGrants(hby, runtime, reger, ipexArgs.gvrsn);
311
- // State may become visible before the rest of a delivered batch settles.
312
- if (receiving === 0
313
- && (newIpexMessages(hby, beforeExns).length > 0 || newSavedCredentials(reger, beforeSaved).length > 0)) {
314
- break;
315
- }
316
- if (Date.now() >= deadline)
317
- break;
318
- yield* sleep(Math.min(250, deadline - Date.now()));
319
- }
317
+ return yield* waitForIpexArrival({
318
+ ...arrivals,
319
+ settle: () => settleStoredGrants({ ...arrivals, hby, protocol: runtime.protocol }, ipexArgs.gvrsn),
320
+ }, baseline, { timeoutMs, tally });
320
321
  }
321
322
  finally {
322
323
  yield* mailbox.halt();
323
324
  }
324
- }
325
- finally {
326
- yield* host.halt();
327
- }
325
+ });
328
326
  return {
329
- batches: batchesSeen,
330
- messages: messagesSeen,
331
- ipex: newIpexMessages(hby, beforeExns),
332
- saved: newSavedCredentials(reger, beforeSaved),
327
+ batches: tally.batches,
328
+ messages: tally.messages,
329
+ ipex: result.status.ipex,
330
+ saved: result.status.saved,
333
331
  };
334
332
  });
335
333
  }
@@ -374,7 +372,33 @@ export function* joinIpexProposal(hby, runtime, reger, ipexArgs) {
374
372
  throw new ValidationError(`Multisig IPEX sender ${group ?? "<missing>"} is not a local group AID.`);
375
373
  }
376
374
  if (!ipexArgs.auto) {
377
- return { exn, group: { embedded, accepted: null, approved: null, lead: null, messages: [], deliveries: [] } };
375
+ return {
376
+ exn,
377
+ group: { embedded, accepted: null, approved: null, lead: null, messages: [], deliveries: [], members: [] },
378
+ };
379
+ }
380
+ if (embedded.pvrsn.major === 2) {
381
+ // ACDC v2: the runtime's group IPEX owner approves, publishes, collects and lets the lead deliver.
382
+ const ops = runtime.operations?.groupIpex;
383
+ if (!ops)
384
+ throw new ValidationError("ACDC v2 group IPEX requires the runtime's operation owners.");
385
+ const said = embedded.said;
386
+ if (!ops.live.has(said))
387
+ yield* approveGroupIpex(ops, said);
388
+ yield* withRuntimeWorkers(runtime, { hab: localGroupMember(hby, group), pollMailbox: true }, () => waitForGroupIpex(ops, said, { timeoutMs: ipexArgs.approvalTimeoutSeconds * 1000 }));
389
+ const outcome = ops.outcomes.get(said);
390
+ return {
391
+ exn,
392
+ group: {
393
+ embedded,
394
+ accepted: runtime.exc.complete(said),
395
+ approved: true,
396
+ lead: runtime.exc.lead(hby.habs.get(group), said),
397
+ messages: outcome?.messages ?? [],
398
+ deliveries: [...(outcome?.deliveries ?? []), ...(outcome?.sent ?? [])],
399
+ members: outcome?.members ?? [],
400
+ },
401
+ };
378
402
  }
379
403
  const host = yield* spawn(() => runAgentRuntime(runtime, { hab: localGroupMember(hby, group) }));
380
404
  let credentialSaved;
@@ -384,7 +408,7 @@ export function* joinIpexProposal(hby, runtime, reger, ipexArgs) {
384
408
  throw new ValidationError("VDR runtime did not open Reger.");
385
409
  const prior = embedded.ked?.p;
386
410
  const grant = typeof prior === "string" && prior.length > 0 ? hby.db.exns.get([prior]) : null;
387
- credentialSaved = !!grant && (yield* settleGrantCredential(hby, runtime.protocol, reger, grant, group, ipexArgs.gvrsn, ipexArgs.approvalTimeoutSeconds));
411
+ credentialSaved = !!grant && (yield* settleAndWaitForCredential(hby, runtime.protocol, reger, grant, group, ipexArgs.gvrsn, ipexArgs.approvalTimeoutSeconds));
388
412
  if (!credentialSaved) {
389
413
  return {
390
414
  exn,
@@ -396,6 +420,7 @@ export function* joinIpexProposal(hby, runtime, reger, ipexArgs) {
396
420
  credentialSaved,
397
421
  messages: [],
398
422
  deliveries: [],
423
+ members: [],
399
424
  },
400
425
  };
401
426
  }
@@ -417,6 +442,7 @@ export function* joinIpexProposal(hby, runtime, reger, ipexArgs) {
417
442
  credentialSaved,
418
443
  messages: approval.messages,
419
444
  deliveries: approval.deliveries,
445
+ members: approval.members,
420
446
  },
421
447
  };
422
448
  }
@@ -441,54 +467,37 @@ function* sendPriorResponse(args, route, priorLabel) {
441
467
  return yield* withIpexRuntime(ipexArgs, function* ({ hby, runtime }) {
442
468
  const hab = requireHab(hby, ipexArgs.alias);
443
469
  const recipient = new Organizer(hby.db, hby.signator).resolveRecipient(requireString(ipexArgs.recipient, "Recipient"));
444
- requireConversationPrior(hby, hab, recipient, prior, "agree");
445
- const prepared = exchange(route, { m: ipexArgs.message ?? "" }, { sender: hab.pre, recipient, dig: prior });
446
- return yield* sendConversation(hby, runtime, hab, recipient, prepared, timeout);
470
+ if (isLocalGroupHab(hby, hab)) {
471
+ requireIpexPrior(hby, hab.pre, recipient, prior, "agree");
472
+ // TODO(group proposal API): replace with the multisig proposal API from app/multisig/counseling.ts.
473
+ const prepared = exchange(route, { m: ipexArgs.message ?? "" }, { sender: hab.pre, recipient, dig: prior });
474
+ return yield* sendGroupConversation(hby, runtime, hab, recipient, prepared, timeout);
475
+ }
476
+ return yield* withRuntimeWorkers(runtime, { hab }, () => sendIpexAgree(ipexSendDeps(hby, runtime), hab, { recipient, offer: prior, message: ipexArgs.message }));
447
477
  });
448
478
  }
449
479
  /** Validate an accepted predecessor and its known parties before any local signing. */
450
480
  function requireConversationPrior(hby, hab, recipient, said, verb) {
451
- const prior = hby.db.exns.get([said]);
452
- if (!prior)
453
- throw new ValidationError("Prior IPEX exchange is not accepted.");
454
- validateIpexReply(prior, verb, hab.pre, recipient);
455
- if (hby.db.erpy.get([said])) {
456
- throw new ValidationError("Prior IPEX exchange already has an accepted response; resume the existing exchange.");
457
- }
481
+ requireIpexPrior(hby, hab.pre, recipient, said, verb);
482
+ }
483
+ /** Collaborators for the library send operations, adapted once from the command runtime. */
484
+ function ipexSendDeps(hby, runtime) {
485
+ return { hby, reactor: runtime.reactor, protocol: runtime.protocol, postman: runtime.postman };
458
486
  }
459
487
  /**
460
- * Run one command host through local intake, member approval and concrete delivery.
461
- * Local conversation state survives transport failure. Group publication and business
462
- * acceptance are separate facts; only an accepted child's elected member sends it
463
- * externally. The caller's resource scope closes stores after this host joins.
488
+ * Run one group command host through local intake, member approval and concrete delivery.
489
+ * Group publication and business acceptance are separate facts; only an accepted
490
+ * child's elected member sends it externally. The caller's resource scope closes
491
+ * stores after this host joins. Single-signature sends use `sendIpex*`.
464
492
  */
465
- function* sendConversation(hby, runtime, hab, recipient, [exn, attachments], timeout) {
466
- const group = isLocalGroupHab(hby, hab);
493
+ function* sendGroupConversation(hby, runtime, hab, recipient, [exn, attachments], timeout) {
467
494
  const genus = exn.gvrsn ?? exn.pvrsn;
468
- const wire = group
469
- ? groupIpexPartial(hby, hab, exn, attachments, genus)
470
- : concatBytes(hab.endorse(exn, { pipelined: false, gvrsn: genus }), attachments);
471
- const signer = group ? localGroupMember(hby, hab.pre) : hab;
472
- const host = yield* spawn(() => runAgentRuntime(runtime, { hab: signer, pollMailbox: group }));
495
+ const wire = groupIpexPartial(hby, hab, exn, attachments, genus);
496
+ const signer = localGroupMember(hby, hab.pre);
497
+ const host = yield* spawn(() => runAgentRuntime(runtime, { hab: signer, pollMailbox: true }));
473
498
  try {
474
499
  yield* runtime.reactor.processBytes(concatBytes(Counter.makeGVC(genus), wire), { local: true });
475
500
  yield* runtime.protocol.processEscrowsOnce();
476
- if (!group) {
477
- if (!runtime.exc.complete(exn.said))
478
- throw new ValidationError("Local IPEX exchange was not accepted.");
479
- let deliveries;
480
- if (exn.route === IPEX_SPURN_ROUTE) {
481
- deliveries = yield* sendCredentialStream(runtime.postman, hab, recipient, [wire]);
482
- }
483
- else {
484
- const evt = runtime.postman.send({ src: hab.pre, dest: recipient, topic: CREDENTIAL_MAILBOX_TOPIC, msg: wire }, { notify: true });
485
- const outcome = yield* runtime.postman.wait(evt);
486
- if (outcome.kin === "failed")
487
- throw outcome.error;
488
- deliveries = outcome.deliveries;
489
- }
490
- return { exn, deliveries };
491
- }
492
501
  const publication = yield* publishInitialGroupIpex(hby, runtime.protocol, runtime.postman, hab, wire, genus);
493
502
  const complete = yield* waitForGroupIpexApproval(hby, runtime.protocol, exn.said, timeout, null);
494
503
  const lead = complete ? runtime.exc.lead(hab, exn.said) : null;
@@ -554,37 +563,6 @@ function requireNonEmpty(value, label) {
554
563
  throw new ValidationError(`${label} is required and cannot be empty.`);
555
564
  }
556
565
  }
557
- function newIpexMessages(hby, before) {
558
- const messages = [];
559
- for (const [, exn] of hby.db.exns.getTopItemIter()) {
560
- const said = exn.said;
561
- const route = exn.route ?? "";
562
- if (!said || before.has(said) || !route.startsWith("/ipex/")) {
563
- continue;
564
- }
565
- messages.push(exn);
566
- }
567
- return messages;
568
- }
569
- function savedCredentials(reger) {
570
- return new Set([...reger.saved.getTopItemIter()].map(([keys]) => keys[0]).filter((key) => !!key));
571
- }
572
- function newSavedCredentials(reger, before) {
573
- return [...savedCredentials(reger)].filter((said) => !before.has(said));
574
- }
575
- /** Settle accepted grant artifacts before the poll command reports newly saved credentials. */
576
- function* processStoredCredentialGrants(hby, runtime, reger, gvrsn) {
577
- for (const [, grant] of hby.db.exns.getTopItemIter()) {
578
- if (grant.route !== IPEX_GRANT_ROUTE) {
579
- continue;
580
- }
581
- const credentialSaid = credentialSaidFromGrant(grant);
582
- if (!credentialSaid || reger.saved.get([credentialSaid])) {
583
- continue;
584
- }
585
- yield* processCredentialPresentationArtifacts(runtime.protocol, storedGrantArtifacts(hby, grant, gvrsn));
586
- }
587
- }
588
566
  function parseJsonArg(value) {
589
567
  if (!value) {
590
568
  return undefined;
@@ -643,18 +621,13 @@ function grantSender(grant) {
643
621
  * escrow progress. The caller runs the host and selects the elapsed wait; no
644
622
  * admit signature is produced here. Missing evidence remains pending on expiry.
645
623
  */
646
- function* settleGrantCredential(hby, protocol, reger, grant, recipient, genus, timeout) {
647
- const said = validateAdmitGrant(grant, recipient, reger, false);
648
- if (reger.saved.get([said]))
649
- return true;
650
- const deadline = Date.now() + timeout * 1000;
651
- yield* processCredentialPresentationArtifacts(protocol, storedGrantArtifacts(hby, grant, genus));
652
- while (!reger.saved.get([said])) {
653
- if (Date.now() >= deadline)
654
- return false;
655
- yield* sleep(Math.min(250, deadline - Date.now()));
656
- }
657
- return true;
624
+ function* settleAndWaitForCredential(hby, protocol, reger, grant, recipient, genus, timeout) {
625
+ yield* settleGrantCredential({ hby, reger, protocol }, recipient, grant.said, { gvrsn: genus });
626
+ const waited = yield* waitForIpexExchange({ hby, reger }, grant.said, {
627
+ timeoutMs: timeout * 1000,
628
+ until: "credential-saved",
629
+ });
630
+ return waited.outcome === "settled";
658
631
  }
659
632
  /**
660
633
  * Observe one child's approvals under an elapsed deadline. The command's existing