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,122 @@
1
+ import { ValidationError } from "../../core/errors.js";
2
+ import { revokeCredential, } from "../credentials/credential-revoking.js";
3
+ import { createCredential, inceptCredentialRegistry, } from "../credentials/credential-workflows.js";
4
+ import { groupSigningMembers, localGroupMember, uniqueMembers } from "./group-members.js";
5
+ import { MULTISIG_ICP_ROUTE, MULTISIG_IXN_ROUTE, MULTISIG_ROT_ROUTE } from "./grouping.js";
6
+ import { remoteGroupMembers } from "./multisig-messaging.js";
7
+ import { approveAcdcV2Registry, commitAcceptedGroupMembers, publishAcdcV2Registry, publishProposal, } from "./multisig-workflows.js";
8
+ /** Propose a new group: create this member's inception and publish it. */
9
+ export function* proposeGroupInception(deps, member, alias, { smids, rmids = smids, ...args }, inputs) {
10
+ // Publishing needs a route to every other member. Refuse before the group habitat exists, so a call that could
11
+ // not be sent leaves nothing behind and the same alias can be used again.
12
+ for (const other of remoteGroupMembers(deps.hby, member, uniqueMembers([...smids, ...rmids]))) {
13
+ if (!deps.postman.canReach(member.pre, other)) {
14
+ throw new ValidationError(`Group member ${other} cannot be reached: no end role is known for it. Resolve its OOBI first.`);
15
+ }
16
+ }
17
+ const created = deps.hby.makeGroupHab(alias, member, [...smids], [...rmids], undefined, args);
18
+ const event = { pre: created.hab.pre, sn: created.serder.sn ?? 0, said: created.serder.said };
19
+ deps.counselor.start(event, inputs);
20
+ const sent = yield* publishProposal(deps.hby, deps.protocol, deps.postman, member, uniqueMembers([...smids, ...rmids]), {
21
+ route: MULTISIG_ICP_ROUTE,
22
+ attrs: { smids: [...smids], rmids: [...rmids], ...(args.delpre ? { delegator: args.delpre } : {}) },
23
+ }, created.message);
24
+ return { ...sent, route: MULTISIG_ICP_ROUTE, group: created.hab.pre, event, smids, rmids };
25
+ }
26
+ /** Propose a group rotation, including member add or remove through new `smids` / `rmids`. */
27
+ export function* proposeGroupRotation(deps, group, { smids: newSmids, rmids: newRmids, ...args } = {}, inputs) {
28
+ const { hby } = deps;
29
+ const rotated = hby.rotateGroupHab(group.name, newSmids && [...newSmids], newRmids && [...newRmids], args);
30
+ const smids = newSmids?.length ? newSmids : groupSigningMembers(hby, rotated.hab.pre);
31
+ const rmids = newRmids?.length ? newRmids : smids;
32
+ const event = { pre: rotated.hab.pre, sn: rotated.serder.sn, said: rotated.serder.said };
33
+ deps.counselor.start(event, inputs);
34
+ const sent = yield* publishProposal(hby, deps.protocol, deps.postman, localGroupMember(hby, rotated.hab.pre), uniqueMembers([...smids, ...rmids]), { route: MULTISIG_ROT_ROUTE, attrs: { gid: rotated.hab.pre, smids: [...smids], rmids: [...rmids] } }, rotated.message);
35
+ return { ...sent, route: MULTISIG_ROT_ROUTE, group: rotated.hab.pre, event, smids, rmids };
36
+ }
37
+ /** Propose a group interaction event carrying `data`. */
38
+ export function* proposeGroupInteraction(deps, group, data, inputs, version) {
39
+ const { hby } = deps;
40
+ const created = hby.interactGroupHab(group.name, undefined, { data, version });
41
+ const smids = groupSigningMembers(hby, created.hab.pre);
42
+ const event = { pre: created.hab.pre, sn: created.serder.sn, said: created.serder.said };
43
+ deps.counselor.start(event, inputs);
44
+ const sent = yield* publishProposal(hby, deps.protocol, deps.postman, localGroupMember(hby, created.hab.pre), smids, { route: MULTISIG_IXN_ROUTE, attrs: { gid: created.hab.pre, smids } }, created.message);
45
+ return { ...sent, route: MULTISIG_IXN_ROUTE, group: created.hab.pre, event, smids, rmids: [] };
46
+ }
47
+ /**
48
+ * Commit the members a proposed rotation named, once the rotation is accepted and
49
+ * is the group's latest establishment event. Idempotent; false until then, so a
50
+ * proposed newcomer is never adopted early. Other event kinds commit nothing.
51
+ *
52
+ * @throws ValidationError when the event is not an accepted event body held locally.
53
+ */
54
+ export function settleProposedRotation(deps, result) {
55
+ if (result.route !== MULTISIG_ROT_ROUTE)
56
+ return false;
57
+ const serder = deps.hby.db.getEvtSerder(result.event.pre, result.event.said);
58
+ if (!serder)
59
+ throw new ValidationError(`No rotation ${result.event.said} is held for ${result.event.pre}.`);
60
+ return commitAcceptedGroupMembers(deps.hby, serder, result.smids, result.rmids);
61
+ }
62
+ /**
63
+ * Propose an ACDC v2 registry event (`rip` or `bup`): author the group anchor
64
+ * that seals it, process this member's own contribution, hand the anchor to the
65
+ * Counselor and publish the proposal. The proposer's contribution is also its
66
+ * approval. Returns without waiting; the anchor's progress is
67
+ * `counselor.status(result.event)`. A `bup` needs its `opening`.
68
+ *
69
+ * @throws ValidationError for a group that is not joined and accepted, or a TEL event the group cannot propose.
70
+ */
71
+ export function* proposeRegistryEvent(deps, group, event, opening, inputs) {
72
+ const { hby } = deps;
73
+ const approval = yield* approveAcdcV2Registry(hby, deps.protocol, group, event, { opening, resume: true });
74
+ const anchorSaid = approval[0].sad?.a?.anc;
75
+ const anchor = anchorSaid ? hby.db.getEvtSerder(group.pre, anchorSaid) : null;
76
+ if (!anchor || anchor.sn === null)
77
+ throw new ValidationError("Registry proposal lost its group anchor.");
78
+ const anchorRef = { pre: group.pre, sn: anchor.sn, said: anchor.said };
79
+ deps.counselor.start(anchorRef, inputs);
80
+ const sent = yield* publishAcdcV2Registry(hby, deps.postman, group, approval);
81
+ const regid = event.ilk === "rip" ? event.said : event.regid;
82
+ const accepted = deps.registryStore?.seqEvent(regid, Number(BigInt(`0x${event.sad.n}`)))?.said === event.said;
83
+ return {
84
+ route: approval[0].route,
85
+ said: approval[0].said,
86
+ embedded: event.said,
87
+ group: group.pre,
88
+ accepted,
89
+ ...sent,
90
+ event: anchorRef,
91
+ };
92
+ }
93
+ function proposedGroup(result, what) {
94
+ if (!result.group)
95
+ throw new ValidationError(`${what} must be proposed by a local group.`);
96
+ return result;
97
+ }
98
+ /**
99
+ * Propose a group's legacy credential registry (`vcp`): author the anchoring group event,
100
+ * process this member's contribution, hand the anchor to the Counselor and publish the
101
+ * proposal. Returns without waiting; the anchor's progress is `counselor.status(result.group.event)`
102
+ * and the registry's is `waitForTelEvent`.
103
+ *
104
+ * @throws ValidationError when `group` is not a local group or the registry name is taken.
105
+ */
106
+ export function* proposeCredentialRegistry(deps, group, options, inputs) {
107
+ const result = proposedGroup(yield* inceptCredentialRegistry(deps.rgy, deps.input, deps.postman, group, options), "A group registry");
108
+ deps.counselor.start(result.group.event, inputs);
109
+ return result;
110
+ }
111
+ /** Propose a group credential issuance (`iss`) the way {@link proposeCredentialRegistry} proposes a registry. */
112
+ export function* proposeCredentialIssue(deps, options, inputs) {
113
+ const result = proposedGroup(yield* createCredential(deps.rgy, deps.input, deps.postman, options), "A group credential");
114
+ deps.counselor.start(result.group.event, inputs);
115
+ return result;
116
+ }
117
+ /** Propose a group credential revocation (`rev`) the way {@link proposeCredentialRegistry} proposes a registry. */
118
+ export function* proposeCredentialRevocation(deps, options, inputs) {
119
+ const result = proposedGroup(yield* revokeCredential(deps.rgy, deps.input, deps.postman, options), "A group revocation");
120
+ deps.counselor.start(result.group.event, inputs);
121
+ return result;
122
+ }
@@ -11,7 +11,8 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
11
11
  };
12
12
  var _Signal_raw, _Signal_pad, _Signal_ckey;
13
13
  import { MtrDex, Salter } from "cesr-ts";
14
- import { runtimeTurn } from "../runtime/runtime-turn.js";
14
+ import { doEvery, PROTOCOL_PACING } from "../runtime/doing.js";
15
+ import { systemClock } from "../runtime/runtime-clock.js";
15
16
  const textEncoder = new TextEncoder();
16
17
  const textDecoder = new TextDecoder();
17
18
  function randomNonce() {
@@ -162,11 +163,10 @@ export class Signaler {
162
163
  this.closed = true;
163
164
  this.clear();
164
165
  }
165
- *signalDo() {
166
- while (true) {
166
+ *signalDo(clock = systemClock, pacing = PROTOCOL_PACING) {
167
+ return yield* doEvery(clock, pacing.tockMs, function* () {
167
168
  this.processOnce();
168
- yield* runtimeTurn();
169
- }
169
+ }.bind(this));
170
170
  }
171
171
  }
172
172
  Object.defineProperty(Signaler, "SignalTimeoutMs", {
@@ -144,7 +144,7 @@ function* dispatchMessage(envelope, revery, kevery, exchanger, tevery, mailboxAi
144
144
  }
145
145
  }
146
146
  if (serder.ilk === "qry" && !["logs", "ksn", "mbx", "tels", "tsn"].includes(serder.route ?? "")
147
- && qvy?.resource !== serder.route) {
147
+ && !(qvy?.claims ? qvy.claims(serder) : qvy?.resource === serder.route)) {
148
148
  return { envelope, decision: { kind: "drop", reason: "missingProcessor" } };
149
149
  }
150
150
  const result = kevery.kramer?.intake(envelope);
@@ -487,6 +487,31 @@ export function copyAuxiliaryQuery(envelope) {
487
487
  copied.tsgs.splice(0, copied.tsgs.length, ...normalized.tsgs);
488
488
  return copied;
489
489
  }
490
+ /**
491
+ * Serialize an auxiliary query without nested evidence so a later process can rebuild it: its own frame with
492
+ * every attachment group (plus `children`, nested evidence already encoded as counted frames), then the
493
+ * normalized proof KRAM may have completed from earlier inputs.
494
+ */
495
+ export function auxiliaryQueryWire(envelope, children = []) {
496
+ const version = envelope.gvrsn ?? envelope.serder.gvrsn ?? envelope.serder.pvrsn;
497
+ const frame = concatBytes(Counter.makeGVC(version), envelope.serder.raw, Counter.enclose({
498
+ code: "AttachmentGroup",
499
+ version,
500
+ qb64: concatBytes(...envelope.attachmentGroups.map(group => group.raw), ...children),
501
+ }));
502
+ const proof = serializeMessage(envelope.serder, { tsgs: envelope.tsgs, gvrsn: version, genusify: true });
503
+ const size = new Uint8Array(4);
504
+ new DataView(size.buffer).setUint32(0, frame.length);
505
+ return concatBytes(size, frame, proof);
506
+ }
507
+ /** Rebuild the envelope {@link auxiliaryQueryWire} serialized. */
508
+ export function restoreAuxiliaryQuery(wire, local = false) {
509
+ const length = new DataView(wire.buffer, wire.byteOffset, 4).getUint32(0);
510
+ const restored = envelopeFromFrame(parseBytes(wire.slice(4, 4 + length))[0], local);
511
+ const normalized = envelopeFromFrame(parseBytes(wire.slice(4 + length))[0]);
512
+ restored.tsgs.splice(0, restored.tsgs.length, ...normalized.tsgs);
513
+ return restored;
514
+ }
490
515
  /** Normalize the actual query endorsements for ingress and per-request authorization. */
491
516
  export function queryEnvelopeFromDispatch(envelope) {
492
517
  const lastSsg = envelope.ssgs.at(-1);
@@ -6,8 +6,14 @@ import { consoleLogger } from "../../core/logger.js";
6
6
  import { BasicReplyRouteHandler, Revery } from "../../core/routing.js";
7
7
  import { Exchanger } from "../exchanges/exchanging.js";
8
8
  import { QueryReplies } from "../queries/query-replies.js";
9
- import { runtimeTurn } from "../runtime/runtime-turn.js";
9
+ import { systemClock } from "../runtime/runtime-clock.js";
10
+ import { waitOnClock } from "../runtime/workflow-contract.js";
10
11
  import { dispatchEnvelope, envelopeFromFrame, queryEnvelopeFromDispatch, } from "./parsering.js";
12
+ /**
13
+ * Wait after every escrow pass, as KERIpy's Doist cycle (`tock` 0.03125 s, app/directing.py) paces its `escrowDo`,
14
+ * which runs one full pass per cycle. A pass is never skipped or shortened; this is the time others get between passes.
15
+ */
16
+ export const ESCROW_TOCK_MS = 31.25;
11
17
  /**
12
18
  * Identify a refusal of one already-extracted message, which must not end its stream.
13
19
  *
@@ -255,10 +261,10 @@ export class ProtocolProcessor {
255
261
  * - mirrors the dedicated `escrowDo` loop rather than folding escrow
256
262
  * processing into parser ingress
257
263
  */
258
- *escrowDo() {
264
+ *escrowDo(clock = systemClock) {
259
265
  while (true) {
260
266
  yield* this.processEscrowsOnce();
261
- yield* runtimeTurn();
267
+ yield* waitOnClock(clock, ESCROW_TOCK_MS);
262
268
  }
263
269
  }
264
270
  }
@@ -0,0 +1,98 @@
1
+ import { call, race, sleep, spawn } from "effection";
2
+ import { ValidationError } from "../../core/errors.js";
3
+ import { isLocalGroupHab } from "../multisig/group-members.js";
4
+ import { AnchorQuerier, KeyStateNoticer } from "./querying.js";
5
+ /** One elapsed deadline covers query sending and independently received evidence. */
6
+ export const QUERY_TIMEOUT_MS = 10_000;
7
+ /** Reject group habs: a query must be signed by one member, not by a group needing more signatures. */
8
+ export function requireQueryRequester(hby, hab) {
9
+ if (isLocalGroupHab(hby, hab)) {
10
+ throw new ValidationError("Query --alias must select a member requester, not a group requiring additional signatures.");
11
+ }
12
+ }
13
+ /** Durable anchor status (`scope: "durable"`): the accepted KEL of `prefix` already holds the exact seal. */
14
+ export function anchorQueryStatus(deps, prefix, anchor) {
15
+ return deps.hby.db.fetchLastSealingEventByEventSeal(prefix, anchor)
16
+ ? { state: "completed", scope: "durable" }
17
+ : { state: "active", phase: "awaitingEvidence", scope: "durable" };
18
+ }
19
+ /** Start a key-state query in the caller's scope. */
20
+ export function* beginKeyStateQuery(deps, target) {
21
+ requireQueryRequester(deps.hby, target.hab);
22
+ const workflow = new KeyStateNoticer(deps.hby.db, deps.querying, target.prefix, deps.cues, {
23
+ signer: target.hab.pre,
24
+ });
25
+ return yield* startQuery(deps, target.prefix, workflow);
26
+ }
27
+ /** Start an anchor query in the caller's scope. */
28
+ export function* beginAnchorQuery(deps, target) {
29
+ requireQueryRequester(deps.hby, target.hab);
30
+ const workflow = new AnchorQuerier(deps.hby.db, deps.querying, target.prefix, target.anchor, {
31
+ signer: target.hab.pre,
32
+ });
33
+ return yield* startQuery(deps, target.prefix, workflow);
34
+ }
35
+ /**
36
+ * Query current key state for `prefix` and wait for accepted evidence.
37
+ *
38
+ * @returns `settled` (status `completed`), or `timed-out`; a timeout is not permission to treat
39
+ * stale local state as success. Workflow failures propagate.
40
+ */
41
+ export function* queryKeyState(deps, target, options = {}) {
42
+ return yield* beginThenWait(beginKeyStateQuery(deps, target), options);
43
+ }
44
+ /** Query for an accepted KEL event holding the exact seal `target.anchor`; see {@link queryKeyState}. */
45
+ export function* queryAnchor(deps, target, options = {}) {
46
+ return yield* beginThenWait(beginAnchorQuery(deps, target), options);
47
+ }
48
+ /** Spawn the workflow in the caller's scope. */
49
+ function* startQuery(deps, prefix, workflow) {
50
+ let completed = false;
51
+ const status = () => completed
52
+ ? { state: "completed", scope: "process" }
53
+ : { state: "active", phase: "awaitingEvidence", scope: "process" };
54
+ const observing = yield* spawn(function* () {
55
+ yield* workflow.queryDo();
56
+ completed = true;
57
+ });
58
+ deps.changes?.push({ kind: "query", id: prefix });
59
+ return {
60
+ prefix,
61
+ status,
62
+ *wait(options = {}) {
63
+ const outcome = yield* waitForQuery(observing, status, options.timeoutMs ?? QUERY_TIMEOUT_MS);
64
+ if (outcome.outcome === "settled")
65
+ deps.changes?.push({ kind: "query", id: prefix });
66
+ return outcome;
67
+ },
68
+ halt: () => observing.halt(),
69
+ };
70
+ }
71
+ /**
72
+ * Observe completion within the window without transferring task ownership.
73
+ * The race cancels only its observation when the timer wins; the run's `halt`
74
+ * joins the original task.
75
+ */
76
+ function* waitForQuery(observing, status, timeoutMs) {
77
+ const done = yield* race([
78
+ call(function* () {
79
+ yield* observing;
80
+ return true;
81
+ }),
82
+ call(function* () {
83
+ yield* sleep(timeoutMs);
84
+ return false;
85
+ }),
86
+ ]);
87
+ return done ? { outcome: "settled", status: status() } : { outcome: "timed-out", status: status(), timeoutMs };
88
+ }
89
+ /** begin + wait, halting the run on every exit path. */
90
+ function* beginThenWait(begin, options) {
91
+ const run = yield* begin;
92
+ try {
93
+ return yield* run.wait(options);
94
+ }
95
+ finally {
96
+ yield* run.halt();
97
+ }
98
+ }
@@ -1,15 +1,14 @@
1
1
  import { WireParseError } from "cesr-ts";
2
2
  import { call, resource, spawn, suspend } from "effection";
3
- import { Dhke } from "../../acdc/dhking.js";
4
3
  import { RegistryObserver } from "../../acdc/observing.js";
5
4
  import { createRegery as createAcdcRegery } from "../../acdc/registraring.js";
6
5
  import { RegistryRoot } from "../../acdc/salting.js";
7
- import { Unblind } from "../../acdc/unblinding.js";
8
6
  import { Deck } from "../../core/deck.js";
9
- import { DatabaseNotOpenError, ValidationError } from "../../core/errors.js";
7
+ import { DatabaseNotOpenError } from "../../core/errors.js";
10
8
  import { Kevery } from "../../core/kel/eventing.js";
11
9
  import { Kramer } from "../../core/mailbox/kraming.js";
12
10
  import { CREDENTIAL_MAILBOX_TOPIC, DELEGATE_MAILBOX_TOPIC, RECEIPT_MAILBOX_TOPIC, REPLAY_MAILBOX_TOPIC, REPLY_MAILBOX_TOPIC, } from "../../core/mailbox/mailbox-topics.js";
11
+ import { Roles } from "../../core/roles.js";
13
12
  import { Revery } from "../../core/routing.js";
14
13
  import { openOwner } from "../../db/core/store-owner.js";
15
14
  import { Mailboxer } from "../../db/mailbox/mailboxing.js";
@@ -28,10 +27,12 @@ import { loadChallengeHandlers } from "../identity/challenging.js";
28
27
  import { Anchorer, loadDelegationHandlers } from "../identity/delegating.js";
29
28
  import { loadIpexHandlers } from "../ipex/ipexing.js";
30
29
  import { ForwardHandler } from "../mailbox/forward-handler.js";
30
+ import { KEL_PUBLISHER_PACING, KelPublisher, kelPublisherDo } from "../mailbox/kel-publisher.js";
31
31
  import { MailboxDirector } from "../mailbox/mailbox-director.js";
32
- import { MailboxPoller } from "../mailbox/mailbox-poller.js";
32
+ import { MAILBOX_POLLER_PACING, MailboxPoller, } from "../mailbox/mailbox-poller.js";
33
33
  import { mailboxerOptionsForHabery } from "../mailbox/mailboxing.js";
34
34
  import { mailboxTopicForRoute } from "../mailbox/topic-routing.js";
35
+ import { Counselor } from "../multisig/counseling.js";
35
36
  import { loadMultisigHandlers } from "../multisig/grouping.js";
36
37
  import { noterOptionsForHabery, Notifier } from "../notifications/notifying.js";
37
38
  import { Signaler } from "../notifications/signaling.js";
@@ -41,7 +42,11 @@ import { QueryReplies } from "../queries/query-replies.js";
41
42
  import { WitnessInquisitor } from "../queries/witness-inquisitor.js";
42
43
  import { Receiptor } from "../witness/receipting.js";
43
44
  import { cueDo } from "./cue-runtime.js";
44
- import { runtimeTurn } from "./runtime-turn.js";
45
+ import { doEvery, PROTOCOL_PACING } from "./doing.js";
46
+ import { IpexAuxiliaries } from "./ipex-auxiliaries.js";
47
+ import { composeOwners, operationOwnersDo, OWNER_PACING, } from "./operation-owners.js";
48
+ import { signalerChangeSink } from "./workflow-contract.js";
49
+ import { observeUntil } from "./workflow-contract.js";
45
50
  /**
46
51
  * Create the shared runtime composition root used by CLI commands and
47
52
  * `tufa agent`.
@@ -59,15 +64,6 @@ import { runtimeTurn } from "./runtime-turn.js";
59
64
  * @throws Dependency mismatch/acquisition errors propagate after owned resource cleanup.
60
65
  */
61
66
  export function* createAgentRuntime(hby, http, clock, options = {}) {
62
- const selected = options.ipexAuxiliary;
63
- if (selected) {
64
- if (options.kram?.enabled !== true) {
65
- throw new ValidationError("IPEX auxiliary runtime requires explicitly enabled KRAM");
66
- }
67
- if (!selected.hab.pre || hby.habs.get(selected.hab.pre) !== selected.hab) {
68
- throw new ValidationError("IPEX auxiliary runtime requires its actual local habitat");
69
- }
70
- }
71
67
  const injectedSignaler = options.signaler ?? options.notifier?.signaler;
72
68
  if ((options.notifier && options.notifier.signator !== hby.signator)
73
69
  || (options.noter && options.notifier && options.noter !== options.notifier.noter)
@@ -102,8 +98,6 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
102
98
  const acdc = options.acdc ?? (!hby.readonly ? (yield* openAcdcRegeryForHabery(hby)) : null);
103
99
  const ownsAcdcRegery = options.acdc === undefined && acdc !== null;
104
100
  const acdcRegery = acdc;
105
- if (selected && !acdc)
106
- throw new ValidationError("IPEX auxiliary runtime requires a v2 registry");
107
101
  // Acquire after stores, before processors/consumers: reverse teardown joins consumers, clears cues, closes stores.
108
102
  const cues = yield* resource(function* (provide) {
109
103
  const owned = new Deck();
@@ -135,25 +129,21 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
135
129
  const kvy = new Kevery(hby.db, { cues: protocolCues, rvy: revery, messagePolicy: options.messagePolicy, kramer });
136
130
  const exc = new Exchanger(hby, { cues: protocolCues, now });
137
131
  const registry = acdc ? new RegistryObserver(hby.db, acdc.store) : null;
138
- const ipexAuxiliary = selected && registry
132
+ // Every runtime with a v2 registry store owns the per-identifier DH and Unblind owners: one dispatch path.
133
+ const ipex = registry
139
134
  ? yield* resource(function* (provide) {
140
- const auxiliary = selected.kind === "dhke"
141
- ? { kind: "dhke", owner: new Dhke({ hab: selected.hab, exc, registryStore: registry.store, rvy: revery, now }) }
142
- : {
143
- kind: "unblind",
144
- owner: new Unblind({ hab: selected.hab, exc, registry, states: selected.states, rvy: revery, now }),
145
- };
135
+ const owners = new IpexAuxiliaries(exc, registry, revery, now, options.kram?.enabled === true);
146
136
  try {
147
- revery.rtr.addRoute(auxiliary.kind === "dhke" ? Dhke.Route : Unblind.Route, auxiliary.owner);
148
- yield* provide(auxiliary);
137
+ owners.registerReplyRoutes(revery.rtr);
138
+ yield* provide(owners);
149
139
  }
150
140
  finally {
151
- auxiliary.owner.close();
141
+ owners.close();
152
142
  }
153
143
  })
154
144
  : null;
155
145
  const replies = new QueryReplies(cues);
156
- const protocol = new ProtocolProcessor(kvy, revery, exc, vdr?.tvy ?? null, vdr?.vry ?? null, registry, protocolCues, cues, replies, ipexAuxiliary?.owner);
146
+ const protocol = new ProtocolProcessor(kvy, revery, exc, vdr?.tvy ?? null, vdr?.vry ?? null, registry, protocolCues, cues, replies, ipex ?? undefined);
157
147
  const reactor = new Reactor(protocol);
158
148
  loadChallengeHandlers(hby.db, exc);
159
149
  loadDelegationHandlers(hby, exc, notifier);
@@ -165,7 +155,9 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
165
155
  grantWalk: options.grantWalk,
166
156
  });
167
157
  // Construction adopts stored copies an earlier handler-less Exchanger left unescrowed.
168
- const registryRoot = options.registryRoots !== "refuse" && acdc ? new RegistryRoot(hby, acdc, notifier) : null;
158
+ const registryRoot = options.registryRoots !== "refuse" && acdc
159
+ ? new RegistryRoot(hby, acdc, notifier, options.operationStores?.changes ?? (signaler ? signalerChangeSink(signaler) : undefined))
160
+ : null;
169
161
  if (registryRoot)
170
162
  exc.addHandler(registryRoot);
171
163
  const mailboxDirector = yield* resource(function* (provide) {
@@ -204,7 +196,25 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
204
196
  // Copies ride the credential topic; the refuser adds no mailbox topic of its own.
205
197
  if (options.registryRoots === "refuse")
206
198
  exc.addHandler(new RouteRefuser(RegistryRoot.Route));
207
- const mailboxPoller = new MailboxPoller(hby, mailboxDirector, http, clock, {});
199
+ const kelPublisher = new KelPublisher({
200
+ hby,
201
+ http,
202
+ clock,
203
+ changes: signaler ? signalerChangeSink(signaler) : undefined,
204
+ retry: options.kelPublishRetry,
205
+ });
206
+ const mailboxPoller = new MailboxPoller(hby, mailboxDirector, http, clock, {
207
+ onPolled: (pre, mailbox) => kelPublisher.prompt(pre, mailbox),
208
+ onUnauthorized: (pre, mailbox) => kelPublisher.repair(pre, mailbox),
209
+ timeouts: options.mailboxPolling,
210
+ });
211
+ // A mailbox role accepted from a reply (a group member's approved add, an OOBI) is acted on at the next tock.
212
+ revery.onEndRole = (cid, role) => {
213
+ if (role !== Roles.mailbox)
214
+ return;
215
+ kelPublisher.prompt(cid);
216
+ mailboxPoller.prompt(cid);
217
+ };
208
218
  for (const topic of [
209
219
  DELEGATE_MAILBOX_TOPIC,
210
220
  CREDENTIAL_MAILBOX_TOPIC,
@@ -224,6 +234,36 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
224
234
  }
225
235
  });
226
236
  const delegating = new Anchorer(hby, postman, querying, protocol, http, clock);
237
+ // Group receipting reaches TCP-only witnesses as `WitnessReceiptor` does, as KERIpy's Counselor does.
238
+ const groupReceiptor = new Receiptor(hby, protocol, http, clock);
239
+ const counselor = new Counselor(hby, {
240
+ receipt: (pre, options) => groupReceiptor.receipt(pre, { ...options, allowTcp: true }),
241
+ get: (pre, options) => groupReceiptor.get(pre, options),
242
+ }, clock, signaler ? signalerChangeSink(signaler) : undefined, { anchorer: delegating, querying }, {
243
+ rotated: (cue) => {
244
+ kelPublisher.rotated.push(cue);
245
+ owned?.rootReplicator?.prompt(cue.pre);
246
+ },
247
+ }, options.counselorReceiptRetry);
248
+ const owned = acdc && ipex
249
+ ? composeOwners({
250
+ hby,
251
+ acdc,
252
+ exc,
253
+ protocol,
254
+ reactor,
255
+ postman,
256
+ receiptor: new Receiptor(hby, protocol, http, clock),
257
+ ipex,
258
+ clock,
259
+ registryRoot,
260
+ mux,
261
+ counselor,
262
+ retry: options.operationRetry,
263
+ queryResendMs: options.issuanceQueryResendMs,
264
+ changes: signaler ? signalerChangeSink(signaler) : undefined,
265
+ }, options.operationStores)
266
+ : null;
227
267
  const oobiery = new Oobiery(hby, protocol, revery, http, cues);
228
268
  oobiery.registerReplyRoutes(revery.rtr);
229
269
  const authenticator = new Authenticator(hby, http);
@@ -239,7 +279,9 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
239
279
  replies,
240
280
  exc,
241
281
  mux,
242
- ipexAuxiliary,
282
+ ipex,
283
+ operations: owned?.operations ?? null,
284
+ rootReplicator: owned?.rootReplicator ?? null,
243
285
  oobiery,
244
286
  authenticator,
245
287
  mailboxDirector,
@@ -247,6 +289,12 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
247
289
  mailboxPoller,
248
290
  postman,
249
291
  delegating,
292
+ counselor,
293
+ kelPublisher,
294
+ ownerPacing: options.ownerPacing ?? OWNER_PACING,
295
+ publisherPacing: options.publisherPacing ?? KEL_PUBLISHER_PACING,
296
+ protocolPacing: options.protocolPacing ?? PROTOCOL_PACING,
297
+ pollerPacing: options.pollerPacing ?? MAILBOX_POLLER_PACING,
250
298
  querying,
251
299
  replyStreams,
252
300
  vdr,
@@ -264,7 +312,7 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
264
312
  const failures = [];
265
313
  const cleanup = [
266
314
  function* () {
267
- ipexAuxiliary?.owner.close();
315
+ ipex?.close();
268
316
  },
269
317
  function* () {
270
318
  yield* querying.close();
@@ -485,6 +533,7 @@ export function runtimePendingState(runtime) {
485
533
  delegationPending: runtime.hby.db.dpwe.cnt() > 0
486
534
  || runtime.hby.db.dune.cnt() > 0
487
535
  || runtime.hby.db.dpub.cnt() > 0,
536
+ groupPending: runtime.hby.db.gpse.cnt() > 0 || runtime.hby.db.gdee.cnt() > 0 || runtime.hby.db.gpwe.cnt() > 0,
488
537
  queriesPending: runtime.querying.hasPendingWork(),
489
538
  deliveriesPending: runtime.querying.hasPendingDelivery || runtime.postman.hasPending,
490
539
  };
@@ -506,6 +555,9 @@ export function runtimeHasPendingWork(runtime) {
506
555
  }
507
556
  /**
508
557
  * Return true once OOBI acceptance and its ingress/query dependencies settle.
558
+ * This is a whole-runtime drain predicate: any unrelated pending cue, query,
559
+ * delegation or OOBI keeps it false. A command or request that asked for one
560
+ * OOBI must wait with `waitForOobi` (`app/bootstrap/oobi-resolving.ts`) instead.
509
561
  * Background receipt delivery is not remote acknowledgement of OOBI acceptance;
510
562
  * static OOBI servers may refuse unsolicited posts. Runtime close still joins I/O.
511
563
  *
@@ -536,14 +588,10 @@ export function* runAgentRuntimeUntil(runtime, done, options) {
536
588
  if (done())
537
589
  return;
538
590
  const { timeoutMs, ...workerOptions } = options;
539
- const deadline = Date.now() + timeoutMs;
540
591
  const worker = yield* spawn(() => runAgentRuntime(runtime, workerOptions));
541
592
  try {
542
- while (!done()) {
543
- if (Date.now() >= deadline)
544
- throw new Error(`Runtime did not converge within ${timeoutMs}ms.`);
545
- yield* runtimeTurn();
546
- }
593
+ if (!(yield* observeUntil(done, { timeoutMs })))
594
+ throw new Error(`Runtime did not converge within ${timeoutMs}ms.`);
547
595
  }
548
596
  finally {
549
597
  yield* worker.halt();
@@ -572,52 +620,55 @@ export { runtimeTurn } from "./runtime-turn.js";
572
620
  */
573
621
  export function* runAgentRuntime(runtime, options = {}) {
574
622
  runtime.querying.configure({ hab: options.hab });
623
+ const pacing = runtime.protocolPacing;
575
624
  const telReceiptor = runtime.vdr ? new Receiptor(runtime.hby, runtime.protocol, runtime.http, runtime.clock) : null;
576
625
  const tasks = [
577
626
  yield* spawn(() => runtime.querying.deliverDo()),
578
627
  yield* spawn(() => runtime.postman.deliverDo()),
579
628
  ...(runtime.vdr && telReceiptor
580
629
  ? [
581
- yield* spawn(function* () {
582
- while (true) {
583
- yield* publishPendingTel(runtime.hby, runtime.vdr.publication, telReceiptor, runtime.http, runtime.clock);
584
- yield* runtimeTurn();
585
- }
586
- }),
630
+ yield* spawn(() => doEvery(runtime.clock, pacing.tockMs, () => publishPendingTel(runtime.hby, runtime.vdr.publication, telReceiptor, runtime.http, runtime.clock))),
587
631
  ]
588
632
  : []),
589
633
  yield* spawn(function* () {
590
- yield* cueDo(runtime, options);
634
+ yield* cueDo(runtime, options, pacing);
591
635
  }),
592
636
  yield* spawn(function* () {
593
- yield* runtime.protocol.escrowDo();
637
+ yield* runtime.protocol.escrowDo(runtime.clock);
594
638
  }),
595
639
  yield* spawn(function* () {
596
- yield* runtime.oobiery.oobiDo();
640
+ yield* runtime.oobiery.oobiDo(runtime.clock, pacing);
597
641
  }),
598
642
  yield* spawn(function* () {
599
- yield* runtime.authenticator.authDo();
643
+ yield* runtime.authenticator.authDo(runtime.clock, pacing);
600
644
  }),
601
645
  ...(runtime.signaler
602
646
  ? [
603
647
  yield* spawn(function* () {
604
- yield* runtime.signaler.signalDo();
648
+ yield* runtime.signaler.signalDo(runtime.clock, pacing);
605
649
  }),
606
650
  ]
607
651
  : []),
608
652
  ...(options.pollMailbox ?? true
609
653
  ? [
610
654
  yield* spawn(function* () {
611
- yield* runtime.mailboxPoller.pollDo((batch) => settleMailboxPollBatch(runtime, batch));
655
+ yield* runtime.mailboxPoller.pollDo((batch) => settleMailboxPollBatch(runtime, batch), runtime.pollerPacing);
612
656
  }),
613
657
  ]
614
658
  : []),
615
- yield* spawn(function* () {
616
- while (true) {
617
- yield* runtime.delegating.processAllOnce();
618
- yield* runtimeTurn();
619
- }
620
- }),
659
+ yield* spawn(() => doEvery(runtime.clock, pacing.tockMs, () => runtime.delegating.processAllOnce())),
660
+ yield* spawn(() => doEvery(runtime.clock, pacing.tockMs, () => runtime.counselor.processOnce())),
661
+ yield* spawn(() => kelPublisherDo(runtime.kelPublisher, runtime.clock, runtime.publisherPacing)),
662
+ ...(runtime.operations && runtime.ipex
663
+ ? [
664
+ yield* spawn(() => operationOwnersDo({
665
+ operations: runtime.operations,
666
+ rootReplicator: runtime.rootReplicator,
667
+ ipex: runtime.ipex,
668
+ clock: runtime.clock,
669
+ }, runtime.ownerPacing)),
670
+ ]
671
+ : []),
621
672
  ];
622
673
  try {
623
674
  return yield* suspend();
@@ -1,4 +1,4 @@
1
- import { runtimeTurn } from "./runtime-turn.js";
1
+ import { doEvery, PROTOCOL_PACING } from "./doing.js";
2
2
  /**
3
3
  * Use an explicitly selected or sole local habitat; never guess among hosted identities.
4
4
  *
@@ -53,9 +53,6 @@ export function* processCuesOnce(runtime, { hab, queryCues } = {}) {
53
53
  * @param runtime Borrowed composed runtime containing the actual cue consumers.
54
54
  * @param options Explicit signer and optional command-owned query cue destination.
55
55
  */
56
- export function* cueDo(runtime, options = {}) {
57
- while (true) {
58
- yield* processCuesOnce(runtime, options);
59
- yield* runtimeTurn();
60
- }
56
+ export function* cueDo(runtime, options = {}, pacing = PROTOCOL_PACING) {
57
+ return yield* doEvery(runtime.clock, pacing.tockMs, () => processCuesOnce(runtime, options));
61
58
  }