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.
- package/README.md +30 -2
- package/esm/keri/npm/src/acdc/authoring.js +195 -0
- package/esm/keri/npm/src/acdc/custody.js +187 -0
- package/esm/keri/npm/src/acdc/dhking.js +244 -32
- package/esm/keri/npm/src/acdc/regbasing.js +10 -0
- package/esm/keri/npm/src/acdc/salting.js +16 -1
- package/esm/keri/npm/src/acdc/scheming.js +93 -54
- package/esm/keri/npm/src/acdc/unblinding.js +118 -95
- package/esm/keri/npm/src/app/bootstrap/authenticating.js +4 -6
- package/esm/keri/npm/src/app/bootstrap/oobi-resolving.js +41 -0
- package/esm/keri/npm/src/app/bootstrap/oobiery.js +4 -6
- package/esm/keri/npm/src/app/credentials/credential-revoking.js +1 -0
- package/esm/keri/npm/src/app/credentials/credential-workflows.js +2 -0
- package/esm/keri/npm/src/app/credentials/registry-settling.js +44 -0
- package/esm/keri/npm/src/app/credentials/root-replicating.js +68 -60
- package/esm/keri/npm/src/app/credentials/root-replicator.js +198 -0
- package/esm/keri/npm/src/app/credentials/tel-completion.js +36 -0
- package/esm/keri/npm/src/app/delivery/forwarding.js +16 -3
- package/esm/keri/npm/src/app/exchanges/exchanging.js +14 -4
- package/esm/keri/npm/src/app/identity/challenging.js +50 -0
- package/esm/keri/npm/src/app/identity/delegating.js +77 -77
- package/esm/keri/npm/src/app/identity/delegation-approval.js +333 -0
- package/esm/keri/npm/src/app/identity/event-completion.js +154 -0
- package/esm/keri/npm/src/app/identity/habbing.js +129 -6
- package/esm/keri/npm/src/app/identity/keeping.js +77 -4
- package/esm/keri/npm/src/app/ipex/group-ipex.js +341 -0
- package/esm/keri/npm/src/app/ipex/group-issuance.js +905 -0
- package/esm/keri/npm/src/app/ipex/ipex-admitting.js +120 -0
- package/esm/keri/npm/src/app/ipex/ipex-conversation.js +197 -0
- package/esm/keri/npm/src/app/ipex/ipex-discloser.js +591 -0
- package/esm/keri/npm/src/app/ipex/ipex-granting.js +93 -0
- package/esm/keri/npm/src/app/ipex/ipex-grouping.js +50 -19
- package/esm/keri/npm/src/app/ipex/ipex-node-authentication.js +42 -18
- package/esm/keri/npm/src/app/ipex/issuance.js +896 -0
- package/esm/keri/npm/src/app/ipex/pending-presentations.js +46 -0
- package/esm/keri/npm/src/app/ipex/presentation-files.js +200 -0
- package/esm/keri/npm/src/app/ipex/presenting.js +408 -0
- package/esm/keri/npm/src/app/ipex/receive-issuance.js +86 -0
- package/esm/keri/npm/src/app/ipex/unblinding-workflow.js +667 -0
- package/esm/keri/npm/src/app/mailbox/ipex-arrival.js +103 -0
- package/esm/keri/npm/src/app/mailbox/kel-publisher.js +322 -0
- package/esm/keri/npm/src/app/mailbox/kel-publishing.js +65 -0
- package/esm/keri/npm/src/app/mailbox/kel-submission.js +24 -0
- package/esm/keri/npm/src/app/mailbox/mailbox-admin.js +208 -0
- package/esm/keri/npm/src/app/mailbox/mailbox-poller.js +212 -47
- package/esm/keri/npm/src/app/mailbox/mailboxing.js +10 -5
- package/esm/keri/npm/src/app/multisig/counseling.js +488 -0
- package/esm/keri/npm/src/app/multisig/group-members.js +18 -0
- package/esm/keri/npm/src/app/multisig/multisig-messaging.js +33 -6
- package/esm/keri/npm/src/app/multisig/multisig-workflows.js +98 -147
- package/esm/keri/npm/src/app/multisig/proposals.js +281 -0
- package/esm/keri/npm/src/app/multisig/proposing.js +122 -0
- package/esm/keri/npm/src/app/notifications/signaling.js +5 -5
- package/esm/keri/npm/src/app/protocol/parsering.js +26 -1
- package/esm/keri/npm/src/app/protocol/protocol-processing.js +9 -3
- package/esm/keri/npm/src/app/queries/query-workflows.js +98 -0
- package/esm/keri/npm/src/app/runtime/agent-runtime.js +106 -55
- package/esm/keri/npm/src/app/runtime/cue-runtime.js +3 -6
- package/esm/keri/npm/src/app/runtime/delivery-outbox.js +87 -0
- package/esm/keri/npm/src/app/runtime/doing.js +17 -0
- package/esm/keri/npm/src/app/runtime/ipex-auxiliaries.js +207 -0
- package/esm/keri/npm/src/app/runtime/operation-owners.js +151 -0
- package/esm/keri/npm/src/app/runtime/retry-backoff.js +93 -0
- package/esm/keri/npm/src/app/runtime/workflow-contract.js +80 -0
- package/esm/keri/npm/src/app/transport/http-client.js +25 -6
- package/esm/keri/npm/src/app/witness/http-endpoints.js +4 -4
- package/esm/keri/npm/src/cli/common/event-completion.js +49 -0
- package/esm/keri/npm/src/cli/common/runtime-workers.js +23 -0
- package/esm/keri/npm/src/cli/credentials/ipex.js +164 -191
- package/esm/keri/npm/src/cli/credentials/vc.js +53 -72
- package/esm/keri/npm/src/cli/endpoints/did.js +12 -3
- package/esm/keri/npm/src/cli/endpoints/oobi.js +10 -13
- package/esm/keri/npm/src/cli/identity/challenge.js +8 -34
- package/esm/keri/npm/src/cli/identity/delegate.js +81 -258
- package/esm/keri/npm/src/cli/identity/incept.js +15 -32
- package/esm/keri/npm/src/cli/identity/interact.js +5 -17
- package/esm/keri/npm/src/cli/identity/rotate.js +8 -36
- package/esm/keri/npm/src/cli/index.js +3 -1
- package/esm/keri/npm/src/cli/messaging/group-join.js +83 -0
- package/esm/keri/npm/src/cli/messaging/group-wait.js +88 -0
- package/esm/keri/npm/src/cli/messaging/multisig.js +190 -285
- package/esm/keri/npm/src/cli/messaging/root-copy-lines.js +31 -0
- package/esm/keri/npm/src/core/kel/eventing.js +66 -10
- package/esm/keri/npm/src/core/mailbox/kram-policy.js +39 -6
- package/esm/keri/npm/src/core/mailbox/kraming.js +2 -0
- package/esm/keri/npm/src/core/records.js +23 -0
- package/esm/keri/npm/src/core/routing.js +13 -0
- package/esm/keri/npm/src/db/basing.js +34 -2
- package/esm/keri/npm/src/db/core/indexeddb-persistence.js +221 -0
- package/esm/keri/npm/src/db/indexeddb.js +98 -0
- package/esm/keri/npm/src/db/keeping.js +11 -2
- package/esm/keri/npm/src/db/store-lock.js +150 -0
- package/esm/keri/npm/src/npm/db-indexeddb.browser.js +2 -0
- package/esm/keri/npm/src/npm/db-indexeddb.js +3 -0
- package/esm/keri/npm/src/npm/db.browser.js +2 -0
- package/esm/keri/npm/src/npm/index.browser.js +9 -0
- package/esm/keri/npm/src/npm/runtime-web.browser.js +2 -0
- package/esm/keri/npm/src/npm/runtime-web.js +3 -0
- package/esm/keri/npm/src/npm/runtime.browser.js +2 -0
- package/esm/keri/npm/src/runtime/index.js +51 -4
- package/esm/keri/npm/src/runtime/web/output-barrier.js +47 -0
- package/esm/keri/npm/src/runtime/web/persistent-storage.js +37 -0
- package/esm/keri/npm/src/runtime/web.js +10 -0
- package/esm/keri/npm/src/vdr/tel-publication.js +16 -0
- package/esm/keri/npm/src/version.js +2 -2
- package/package.json +15 -2
- package/types/acdc/authoring.d.ts +54 -0
- package/types/acdc/authoring.d.ts.map +1 -0
- package/types/acdc/custody.d.ts +84 -0
- package/types/acdc/custody.d.ts.map +1 -0
- package/types/acdc/dhking.d.ts +94 -3
- package/types/acdc/dhking.d.ts.map +1 -1
- package/types/acdc/regbasing.d.ts +4 -0
- package/types/acdc/regbasing.d.ts.map +1 -1
- package/types/acdc/salting.d.ts +6 -1
- package/types/acdc/salting.d.ts.map +1 -1
- package/types/acdc/scheming.d.ts +2 -0
- package/types/acdc/scheming.d.ts.map +1 -1
- package/types/acdc/unblinding.d.ts +58 -19
- package/types/acdc/unblinding.d.ts.map +1 -1
- package/types/app/bootstrap/authenticating.d.ts +3 -1
- package/types/app/bootstrap/authenticating.d.ts.map +1 -1
- package/types/app/bootstrap/oobi-resolving.d.ts +92 -0
- package/types/app/bootstrap/oobi-resolving.d.ts.map +1 -0
- package/types/app/bootstrap/oobiery.d.ts +3 -1
- package/types/app/bootstrap/oobiery.d.ts.map +1 -1
- package/types/app/credentials/credential-revoking.d.ts +3 -0
- package/types/app/credentials/credential-revoking.d.ts.map +1 -1
- package/types/app/credentials/credential-workflows.d.ts +5 -0
- package/types/app/credentials/credential-workflows.d.ts.map +1 -1
- package/types/app/credentials/registry-settling.d.ts +85 -0
- package/types/app/credentials/registry-settling.d.ts.map +1 -0
- package/types/app/credentials/root-replicating.d.ts +56 -44
- package/types/app/credentials/root-replicating.d.ts.map +1 -1
- package/types/app/credentials/root-replicator.d.ts +105 -0
- package/types/app/credentials/root-replicator.d.ts.map +1 -0
- package/types/app/credentials/tel-completion.d.ts +55 -0
- package/types/app/credentials/tel-completion.d.ts.map +1 -0
- package/types/app/delivery/forwarding.d.ts +6 -0
- package/types/app/delivery/forwarding.d.ts.map +1 -1
- package/types/app/exchanges/exchanging.d.ts.map +1 -1
- package/types/app/identity/challenging.d.ts +54 -0
- package/types/app/identity/challenging.d.ts.map +1 -1
- package/types/app/identity/delegating.d.ts +21 -4
- package/types/app/identity/delegating.d.ts.map +1 -1
- package/types/app/identity/delegation-approval.d.ts +228 -0
- package/types/app/identity/delegation-approval.d.ts.map +1 -0
- package/types/app/identity/event-completion.d.ts +151 -0
- package/types/app/identity/event-completion.d.ts.map +1 -0
- package/types/app/identity/habbing.d.ts +67 -2
- package/types/app/identity/habbing.d.ts.map +1 -1
- package/types/app/identity/keeping.d.ts +49 -3
- package/types/app/identity/keeping.d.ts.map +1 -1
- package/types/app/ipex/group-ipex.d.ts +254 -0
- package/types/app/ipex/group-ipex.d.ts.map +1 -0
- package/types/app/ipex/group-issuance.d.ts +281 -0
- package/types/app/ipex/group-issuance.d.ts.map +1 -0
- package/types/app/ipex/ipex-admitting.d.ts +47 -0
- package/types/app/ipex/ipex-admitting.d.ts.map +1 -0
- package/types/app/ipex/ipex-conversation.d.ts +195 -0
- package/types/app/ipex/ipex-conversation.d.ts.map +1 -0
- package/types/app/ipex/ipex-discloser.d.ts +156 -0
- package/types/app/ipex/ipex-discloser.d.ts.map +1 -0
- package/types/app/ipex/ipex-granting.d.ts +145 -0
- package/types/app/ipex/ipex-granting.d.ts.map +1 -0
- package/types/app/ipex/ipex-grouping.d.ts +18 -0
- package/types/app/ipex/ipex-grouping.d.ts.map +1 -1
- package/types/app/ipex/ipex-node-authentication.d.ts +9 -1
- package/types/app/ipex/ipex-node-authentication.d.ts.map +1 -1
- package/types/app/ipex/issuance.d.ts +445 -0
- package/types/app/ipex/issuance.d.ts.map +1 -0
- package/types/app/ipex/pending-presentations.d.ts +25 -0
- package/types/app/ipex/pending-presentations.d.ts.map +1 -0
- package/types/app/ipex/presentation-files.d.ts +47 -0
- package/types/app/ipex/presentation-files.d.ts.map +1 -0
- package/types/app/ipex/presenting.d.ts +300 -0
- package/types/app/ipex/presenting.d.ts.map +1 -0
- package/types/app/ipex/receive-issuance.d.ts +99 -0
- package/types/app/ipex/receive-issuance.d.ts.map +1 -0
- package/types/app/ipex/unblinding-workflow.d.ts +257 -0
- package/types/app/ipex/unblinding-workflow.d.ts.map +1 -0
- package/types/app/mailbox/ipex-arrival.d.ts +104 -0
- package/types/app/mailbox/ipex-arrival.d.ts.map +1 -0
- package/types/app/mailbox/kel-publisher.d.ts +141 -0
- package/types/app/mailbox/kel-publisher.d.ts.map +1 -0
- package/types/app/mailbox/kel-publishing.d.ts +70 -0
- package/types/app/mailbox/kel-publishing.d.ts.map +1 -0
- package/types/app/mailbox/kel-submission.d.ts +18 -0
- package/types/app/mailbox/kel-submission.d.ts.map +1 -0
- package/types/app/mailbox/mailbox-admin.d.ts +113 -0
- package/types/app/mailbox/mailbox-admin.d.ts.map +1 -0
- package/types/app/mailbox/mailbox-poller.d.ts +92 -3
- package/types/app/mailbox/mailbox-poller.d.ts.map +1 -1
- package/types/app/mailbox/mailboxing.d.ts +3 -0
- package/types/app/mailbox/mailboxing.d.ts.map +1 -1
- package/types/app/multisig/counseling.d.ts +196 -0
- package/types/app/multisig/counseling.d.ts.map +1 -0
- package/types/app/multisig/group-members.d.ts +11 -0
- package/types/app/multisig/group-members.d.ts.map +1 -1
- package/types/app/multisig/grouping.d.ts +39 -20
- package/types/app/multisig/grouping.d.ts.map +1 -1
- package/types/app/multisig/multisig-messaging.d.ts +23 -6
- package/types/app/multisig/multisig-messaging.d.ts.map +1 -1
- package/types/app/multisig/multisig-workflows.d.ts +91 -22
- package/types/app/multisig/multisig-workflows.d.ts.map +1 -1
- package/types/app/multisig/proposals.d.ts +129 -0
- package/types/app/multisig/proposals.d.ts.map +1 -0
- package/types/app/multisig/proposing.d.ts +125 -0
- package/types/app/multisig/proposing.d.ts.map +1 -0
- package/types/app/notifications/signaling.d.ts +3 -1
- package/types/app/notifications/signaling.d.ts.map +1 -1
- package/types/app/protocol/parsering.d.ts +13 -0
- package/types/app/protocol/parsering.d.ts.map +1 -1
- package/types/app/protocol/protocol-processing.d.ts +7 -1
- package/types/app/protocol/protocol-processing.d.ts.map +1 -1
- package/types/app/queries/query-workflows.d.ts +98 -0
- package/types/app/queries/query-workflows.d.ts.map +1 -0
- package/types/app/runtime/agent-runtime.d.ts +72 -25
- package/types/app/runtime/agent-runtime.d.ts.map +1 -1
- package/types/app/runtime/cue-runtime.d.ts +2 -1
- package/types/app/runtime/cue-runtime.d.ts.map +1 -1
- package/types/app/runtime/delivery-outbox.d.ts +68 -0
- package/types/app/runtime/delivery-outbox.d.ts.map +1 -0
- package/types/app/runtime/doing.d.ts +27 -0
- package/types/app/runtime/doing.d.ts.map +1 -0
- package/types/app/runtime/ipex-auxiliaries.d.ts +74 -0
- package/types/app/runtime/ipex-auxiliaries.d.ts.map +1 -0
- package/types/app/runtime/operation-owners.d.ts +137 -0
- package/types/app/runtime/operation-owners.d.ts.map +1 -0
- package/types/app/runtime/retry-backoff.d.ts +49 -0
- package/types/app/runtime/retry-backoff.d.ts.map +1 -0
- package/types/app/runtime/workflow-contract.d.ts +79 -0
- package/types/app/runtime/workflow-contract.d.ts.map +1 -0
- package/types/app/transport/http-client.d.ts.map +1 -1
- package/types/cli/common/event-completion.d.ts +26 -0
- package/types/cli/common/event-completion.d.ts.map +1 -0
- package/types/cli/common/runtime-workers.d.ts +23 -0
- package/types/cli/common/runtime-workers.d.ts.map +1 -0
- package/types/cli/credentials/ipex.d.ts.map +1 -1
- package/types/cli/credentials/vc.d.ts +1 -1
- package/types/cli/credentials/vc.d.ts.map +1 -1
- package/types/cli/endpoints/did.d.ts.map +1 -1
- package/types/cli/endpoints/oobi.d.ts +3 -1
- package/types/cli/endpoints/oobi.d.ts.map +1 -1
- package/types/cli/identity/challenge.d.ts +1 -1
- package/types/cli/identity/challenge.d.ts.map +1 -1
- package/types/cli/identity/delegate.d.ts +14 -1
- package/types/cli/identity/delegate.d.ts.map +1 -1
- package/types/cli/identity/incept.d.ts.map +1 -1
- package/types/cli/identity/interact.d.ts.map +1 -1
- package/types/cli/identity/rotate.d.ts.map +1 -1
- package/types/cli/index.d.ts +3 -1
- package/types/cli/index.d.ts.map +1 -1
- package/types/cli/messaging/group-join.d.ts +56 -0
- package/types/cli/messaging/group-join.d.ts.map +1 -0
- package/types/cli/messaging/group-wait.d.ts +34 -0
- package/types/cli/messaging/group-wait.d.ts.map +1 -0
- package/types/cli/messaging/multisig.d.ts +29 -5
- package/types/cli/messaging/multisig.d.ts.map +1 -1
- package/types/cli/messaging/root-copy-lines.d.ts +39 -0
- package/types/cli/messaging/root-copy-lines.d.ts.map +1 -0
- package/types/core/cues.d.ts +11 -0
- package/types/core/cues.d.ts.map +1 -1
- package/types/core/kel/eventing.d.ts.map +1 -1
- package/types/core/mailbox/kram-policy.d.ts +14 -0
- package/types/core/mailbox/kram-policy.d.ts.map +1 -1
- package/types/core/mailbox/kraming.d.ts +1 -1
- package/types/core/mailbox/kraming.d.ts.map +1 -1
- package/types/core/records.d.ts +61 -0
- package/types/core/records.d.ts.map +1 -1
- package/types/core/routing.d.ts +6 -0
- package/types/core/routing.d.ts.map +1 -1
- package/types/db/basing.d.ts +8 -2
- package/types/db/basing.d.ts.map +1 -1
- package/types/db/core/indexeddb-persistence.d.ts +59 -0
- package/types/db/core/indexeddb-persistence.d.ts.map +1 -0
- package/types/db/indexeddb.d.ts +37 -0
- package/types/db/indexeddb.d.ts.map +1 -0
- package/types/db/keeping.d.ts +5 -2
- package/types/db/keeping.d.ts.map +1 -1
- package/types/db/store-lock.d.ts +72 -0
- package/types/db/store-lock.d.ts.map +1 -0
- package/types/npm/db-indexeddb.d.ts +4 -0
- package/types/npm/db-indexeddb.d.ts.map +1 -0
- package/types/npm/runtime-web.d.ts +4 -0
- package/types/npm/runtime-web.d.ts.map +1 -0
- package/types/runtime/index.d.ts +42 -7
- package/types/runtime/index.d.ts.map +1 -1
- package/types/runtime/web/output-barrier.d.ts +30 -0
- package/types/runtime/web/output-barrier.d.ts.map +1 -0
- package/types/runtime/web/persistent-storage.d.ts +36 -0
- package/types/runtime/web/persistent-storage.d.ts.map +1 -0
- package/types/runtime/web.d.ts +11 -0
- package/types/runtime/web.d.ts.map +1 -0
- package/types/vdr/tel-publication.d.ts +6 -0
- package/types/vdr/tel-publication.d.ts.map +1 -1
- package/types/version.d.ts +2 -2
- package/esm/keri/npm/src/cli/common/tel-completion.js +0 -24
- package/types/cli/common/tel-completion.d.ts +0 -8
- package/types/cli/common/tel-completion.d.ts.map +0 -1
|
@@ -90,7 +90,7 @@ function escrowContext(keys, serder) {
|
|
|
90
90
|
return [keys, serder, pre, said, snh];
|
|
91
91
|
}
|
|
92
92
|
/** Persist the delegator event seal that authorizes one delegated event. */
|
|
93
|
-
function pinAuthorizingSeal(hby, delegated, delegating) {
|
|
93
|
+
export function pinAuthorizingSeal(hby, delegated, delegating) {
|
|
94
94
|
const pre = delegated.pre;
|
|
95
95
|
const said = delegated.said;
|
|
96
96
|
const sner = delegating.sner;
|
|
@@ -226,6 +226,72 @@ Object.defineProperty(DelegateRequestHandler, "resource", {
|
|
|
226
226
|
writable: true,
|
|
227
227
|
value: DELEGATE_REQUEST_ROUTE
|
|
228
228
|
});
|
|
229
|
+
/** Enqueue one anchor query to the delegator's first sorted witness, when its endpoint is known. */
|
|
230
|
+
function enqueueAnchorQuery(deps, serder, delpre, witness, communicationHab) {
|
|
231
|
+
deps.querying.enqueue({
|
|
232
|
+
pre: delpre,
|
|
233
|
+
route: "logs",
|
|
234
|
+
q: { fn: "0", s: "0", a: eventAnchor(serder) },
|
|
235
|
+
signer: communicationHab.pre,
|
|
236
|
+
wits: [witness],
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Publish the initial delegator-witness anchor query and seed the retry-pass
|
|
241
|
+
* bookkeeping so the first retry starts the backoff window instead of querying again.
|
|
242
|
+
*/
|
|
243
|
+
export function queueDelegatorWitnessQuery(deps, serder, communicationHab) {
|
|
244
|
+
const id = workflowId(serder);
|
|
245
|
+
const delpre = delegatedWorkflowDelpre(deps.hby, serder);
|
|
246
|
+
if (!delpre) {
|
|
247
|
+
throw new ValidationError(`Delegation workflow ${id} is missing a delegator prefix.`);
|
|
248
|
+
}
|
|
249
|
+
const delegator = deps.hby.db.getKever(delpre);
|
|
250
|
+
if (!delegator) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const witness = firstSorted(delegator.wits);
|
|
254
|
+
if (!witness || !preferredWitnessQueryUrl(communicationHab, witness)) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
enqueueAnchorQuery(deps, serder, delpre, witness, communicationHab);
|
|
258
|
+
deps.retryPasses.set(id, -1);
|
|
259
|
+
}
|
|
260
|
+
/** Retry bounded delegator-witness queries while waiting for the anchor; returns why the wait continues. */
|
|
261
|
+
export function retryDelegatorWitnessQuery(deps, serder, communicationHab) {
|
|
262
|
+
const id = workflowId(serder);
|
|
263
|
+
const delpre = delegatedWorkflowDelpre(deps.hby, serder);
|
|
264
|
+
if (!delpre) {
|
|
265
|
+
throw new ValidationError(`Delegation workflow ${id} is missing a delegator prefix.`);
|
|
266
|
+
}
|
|
267
|
+
const delegator = deps.hby.db.getKever(delpre);
|
|
268
|
+
if (!delegator) {
|
|
269
|
+
return "Delegator anchor has not been learned locally yet and the delegator KEL is not known locally.";
|
|
270
|
+
}
|
|
271
|
+
const witness = firstSorted(delegator.wits);
|
|
272
|
+
if (!witness) {
|
|
273
|
+
return "Delegator anchor has not been learned locally yet and no delegator witness is known locally.";
|
|
274
|
+
}
|
|
275
|
+
if (!preferredWitnessQueryUrl(communicationHab, witness)) {
|
|
276
|
+
return `Delegator anchor has not been learned locally yet and witness ${witness} has no HTTP endpoint known locally.`;
|
|
277
|
+
}
|
|
278
|
+
const pass = deps.retryPasses.get(id);
|
|
279
|
+
if (pass === undefined) {
|
|
280
|
+
enqueueAnchorQuery(deps, serder, delpre, witness, communicationHab);
|
|
281
|
+
deps.retryPasses.set(id, 0);
|
|
282
|
+
return `Delegator anchor has not been learned locally yet; queried delegator witness ${witness}.`;
|
|
283
|
+
}
|
|
284
|
+
const nextPass = pass + 1;
|
|
285
|
+
if (nextPass < DELEGATION_ANCHOR_QUERY_RETRY_PASSES) {
|
|
286
|
+
deps.retryPasses.set(id, nextPass);
|
|
287
|
+
const remaining = DELEGATION_ANCHOR_QUERY_RETRY_PASSES
|
|
288
|
+
- nextPass;
|
|
289
|
+
return `Delegator anchor has not been learned locally yet; next delegator witness query retry in ${remaining} pass(es).`;
|
|
290
|
+
}
|
|
291
|
+
enqueueAnchorQuery(deps, serder, delpre, witness, communicationHab);
|
|
292
|
+
deps.retryPasses.set(id, 0);
|
|
293
|
+
return `Delegator anchor has not been learned locally yet; queried delegator witness ${witness}.`;
|
|
294
|
+
}
|
|
229
295
|
/**
|
|
230
296
|
* Delegation workflow coordinator for delegated inception and rotation events.
|
|
231
297
|
*
|
|
@@ -329,6 +395,13 @@ export class Anchorer {
|
|
|
329
395
|
writable: true,
|
|
330
396
|
value: new Map()
|
|
331
397
|
});
|
|
398
|
+
/** Shared anchor-discovery inputs over this owner's collaborators and retry bookkeeping. */
|
|
399
|
+
Object.defineProperty(this, "anchorQuery", {
|
|
400
|
+
enumerable: true,
|
|
401
|
+
configurable: true,
|
|
402
|
+
writable: true,
|
|
403
|
+
value: void 0
|
|
404
|
+
});
|
|
332
405
|
if (protocol && protocol.kvy.db !== hby.db) {
|
|
333
406
|
throw new RangeError("Anchorer protocol processor must use the same database");
|
|
334
407
|
}
|
|
@@ -336,6 +409,7 @@ export class Anchorer {
|
|
|
336
409
|
this.protocol = protocol;
|
|
337
410
|
this.postman = postman;
|
|
338
411
|
this.querying = querying;
|
|
412
|
+
this.anchorQuery = { hby, querying, retryPasses: this.anchorQueryRetryPasses };
|
|
339
413
|
this.http = http;
|
|
340
414
|
this.clock = clock;
|
|
341
415
|
}
|
|
@@ -531,7 +605,7 @@ export class Anchorer {
|
|
|
531
605
|
// publish phase that forwards the delegation request and raw event bytes.
|
|
532
606
|
// Keep that ordering here so delegate-side approval discovery does not
|
|
533
607
|
// depend on a later escrow pass happening "soon enough" by accident.
|
|
534
|
-
this.
|
|
608
|
+
queueDelegatorWitnessQuery(this.anchorQuery, serder, communicationHab);
|
|
535
609
|
this.hby.db.dpwe.rem(keys);
|
|
536
610
|
this.hby.db.dune.pin(keys, serder);
|
|
537
611
|
return {
|
|
@@ -579,7 +653,7 @@ export class Anchorer {
|
|
|
579
653
|
pre,
|
|
580
654
|
said,
|
|
581
655
|
phase: "waitingDelegatorAnchor",
|
|
582
|
-
reason: this.
|
|
656
|
+
reason: retryDelegatorWitnessQuery(this.anchorQuery, serder, communicationHab),
|
|
583
657
|
};
|
|
584
658
|
}
|
|
585
659
|
// The approving event is authoritative only after the delegator's sealing
|
|
@@ -634,80 +708,6 @@ export class Anchorer {
|
|
|
634
708
|
}
|
|
635
709
|
throw new ValidationError(`Delegated inception for ${hab.pre} requires --proxy <alias> to send delegation requests.`);
|
|
636
710
|
}
|
|
637
|
-
/** Publish the initial anchor query after successful sending and seed the existing retry-pass bookkeeping. */
|
|
638
|
-
queueDelegatorWitnessQueryNow(serder, communicationHab) {
|
|
639
|
-
const id = workflowId(serder);
|
|
640
|
-
const delpre = delegatedWorkflowDelpre(this.hby, serder);
|
|
641
|
-
if (!delpre) {
|
|
642
|
-
throw new ValidationError(`Delegation workflow ${id} is missing a delegator prefix.`);
|
|
643
|
-
}
|
|
644
|
-
const delegator = this.hby.db.getKever(delpre);
|
|
645
|
-
if (!delegator) {
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
const witness = firstSorted(delegator.wits);
|
|
649
|
-
if (!witness || !preferredWitnessQueryUrl(communicationHab, witness)) {
|
|
650
|
-
return;
|
|
651
|
-
}
|
|
652
|
-
this.querying.enqueue({
|
|
653
|
-
pre: delpre,
|
|
654
|
-
route: "logs",
|
|
655
|
-
q: { fn: "0", s: "0", a: eventAnchor(serder) },
|
|
656
|
-
signer: communicationHab.pre,
|
|
657
|
-
wits: [witness],
|
|
658
|
-
});
|
|
659
|
-
// Mark that an immediate publication-time query was already sent so the
|
|
660
|
-
// first unanchored escrow retry pass starts the backoff window instead of
|
|
661
|
-
// immediately enqueueing the same query again.
|
|
662
|
-
this.anchorQueryRetryPasses.set(id, -1);
|
|
663
|
-
}
|
|
664
|
-
/** Retry bounded delegator-witness queries while waiting for the anchor. */
|
|
665
|
-
retryDelegatorWitnessQuery(serder, communicationHab) {
|
|
666
|
-
const id = workflowId(serder);
|
|
667
|
-
const delpre = delegatedWorkflowDelpre(this.hby, serder);
|
|
668
|
-
if (!delpre) {
|
|
669
|
-
throw new ValidationError(`Delegation workflow ${id} is missing a delegator prefix.`);
|
|
670
|
-
}
|
|
671
|
-
const delegator = this.hby.db.getKever(delpre);
|
|
672
|
-
if (!delegator) {
|
|
673
|
-
return "Delegator anchor has not been learned locally yet and the delegator KEL is not known locally.";
|
|
674
|
-
}
|
|
675
|
-
const witness = firstSorted(delegator.wits);
|
|
676
|
-
if (!witness) {
|
|
677
|
-
return "Delegator anchor has not been learned locally yet and no delegator witness is known locally.";
|
|
678
|
-
}
|
|
679
|
-
if (!preferredWitnessQueryUrl(communicationHab, witness)) {
|
|
680
|
-
return `Delegator anchor has not been learned locally yet and witness ${witness} has no HTTP endpoint known locally.`;
|
|
681
|
-
}
|
|
682
|
-
const pass = this.anchorQueryRetryPasses.get(id);
|
|
683
|
-
if (pass === undefined) {
|
|
684
|
-
this.querying.enqueue({
|
|
685
|
-
pre: delpre,
|
|
686
|
-
route: "logs",
|
|
687
|
-
q: { fn: "0", s: "0", a: eventAnchor(serder) },
|
|
688
|
-
signer: communicationHab.pre,
|
|
689
|
-
wits: [witness],
|
|
690
|
-
});
|
|
691
|
-
this.anchorQueryRetryPasses.set(id, 0);
|
|
692
|
-
return `Delegator anchor has not been learned locally yet; queried delegator witness ${witness}.`;
|
|
693
|
-
}
|
|
694
|
-
const nextPass = pass + 1;
|
|
695
|
-
if (nextPass < DELEGATION_ANCHOR_QUERY_RETRY_PASSES) {
|
|
696
|
-
this.anchorQueryRetryPasses.set(id, nextPass);
|
|
697
|
-
const remaining = DELEGATION_ANCHOR_QUERY_RETRY_PASSES
|
|
698
|
-
- nextPass;
|
|
699
|
-
return `Delegator anchor has not been learned locally yet; next delegator witness query retry in ${remaining} pass(es).`;
|
|
700
|
-
}
|
|
701
|
-
this.querying.enqueue({
|
|
702
|
-
pre: delpre,
|
|
703
|
-
route: "logs",
|
|
704
|
-
q: { fn: "0", s: "0", a: eventAnchor(serder) },
|
|
705
|
-
signer: communicationHab.pre,
|
|
706
|
-
wits: [witness],
|
|
707
|
-
});
|
|
708
|
-
this.anchorQueryRetryPasses.set(id, 0);
|
|
709
|
-
return `Delegator anchor has not been learned locally yet; queried delegator witness ${witness}.`;
|
|
710
|
-
}
|
|
711
711
|
/** Retire only this event's process-local signer and query bookkeeping. */
|
|
712
712
|
clearWorkflowPins(serder) {
|
|
713
713
|
const id = workflowId(serder);
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegator-side approval of pending delegated events, owned by the library so
|
|
3
|
+
* that every host (CLI, wallet, service) runs one implementation.
|
|
4
|
+
*
|
|
5
|
+
* A delegate's `dip` or `drt` reaches the delegator's `delegables.` escrow. The
|
|
6
|
+
* delegator approves it by anchoring the event seal in its own KEL, then lets
|
|
7
|
+
* the delegate's event reach local state. Operations follow the workflow
|
|
8
|
+
* contract (`app/runtime/workflow-contract.ts`):
|
|
9
|
+
* - `listPendingDelegations` and `delegationApprovalStatus` are pure reads of
|
|
10
|
+
* durable state.
|
|
11
|
+
* - `approveDelegation` is the only operation that signs. It returns after the
|
|
12
|
+
* anchor is committed locally and the follow-up requests are sent.
|
|
13
|
+
* - `waitForPendingDelegation`, `waitForDelegationAnchor` and `waitForDelegationApproval`
|
|
14
|
+
* only observe, each on the one thing asked for; the host's runtime workers make the
|
|
15
|
+
* request and the delegate's event arrive.
|
|
16
|
+
* - `dismissDelegation` removes the local controller notice only.
|
|
17
|
+
*
|
|
18
|
+
* Idempotence evidence: the anchor is the seal `{i, s, d}` of the delegated event
|
|
19
|
+
* inside the delegator's own KEL. That KEL entry is durable the moment signing
|
|
20
|
+
* commits, so a repeated approval after a crash finds it and never anchors twice.
|
|
21
|
+
* Witness receipts are not part of the test on purpose: the sealing-event lookup
|
|
22
|
+
* of `Baser` requires them, which would re-anchor in the window between signing
|
|
23
|
+
* and receipting.
|
|
24
|
+
*
|
|
25
|
+
* - A group delegator's anchor is a group interaction: `proposeGroupDelegationApproval`
|
|
26
|
+
* proposes it, the other members approve it with `approveGroupProposal`, and the
|
|
27
|
+
* Counselor receipts it. `requestDelegatedEvent` then asks for the delegate's event.
|
|
28
|
+
*
|
|
29
|
+
* Boundaries:
|
|
30
|
+
* - Dependencies are declared collaborators, not an AgentRuntime (ADR-0013).
|
|
31
|
+
* - `approveDelegation` serves single-signature delegators and rejects a group.
|
|
32
|
+
* - Witness authorization codes arrive resolved. Prompting is a host concern.
|
|
33
|
+
*/
|
|
34
|
+
import { Diger } from "cesr-ts";
|
|
35
|
+
import { ValidationError } from "../../core/errors.js";
|
|
36
|
+
import { dgKey } from "../../db/core/keys.js";
|
|
37
|
+
import { proposeGroupInteraction } from "../multisig/proposing.js";
|
|
38
|
+
import { observeUntil } from "../runtime/workflow-contract.js";
|
|
39
|
+
import { DELEGATE_REQUEST_ROUTE } from "./delegating.js";
|
|
40
|
+
import { isLocalGroupHab } from "./endpoint-roleing.js";
|
|
41
|
+
import { receiptEvent } from "./event-completion.js";
|
|
42
|
+
/** How long the CLI-compatible wait for the delegate's event lasts. */
|
|
43
|
+
export const DELEGATION_APPROVAL_TIMEOUT_MS = 30_000;
|
|
44
|
+
/** Delegator prefix for escrowed `dip` or `drt` material, if it is derivable. */
|
|
45
|
+
function delegationSourcePrefix(db, serder, pre) {
|
|
46
|
+
if (serder.delpre)
|
|
47
|
+
return serder.delpre;
|
|
48
|
+
if (serder.ilk !== "drt")
|
|
49
|
+
return undefined;
|
|
50
|
+
const delegatedPre = serder.pre ?? pre;
|
|
51
|
+
return db.getKever(delegatedPre)?.delpre ?? db.getState(delegatedPre)?.di;
|
|
52
|
+
}
|
|
53
|
+
/** Project a delegated event into the seal the approving event embeds. */
|
|
54
|
+
export function delegationSeal(serder) {
|
|
55
|
+
if (!serder.pre || !serder.snh || !serder.said) {
|
|
56
|
+
throw new ValidationError("Delegated event is missing pre, sn, or said.");
|
|
57
|
+
}
|
|
58
|
+
return { i: serder.pre, s: serder.snh, d: serder.said };
|
|
59
|
+
}
|
|
60
|
+
function requestFromEscrow(db, serder, pre) {
|
|
61
|
+
const delegator = delegationSourcePrefix(db, serder, pre);
|
|
62
|
+
if (!delegator)
|
|
63
|
+
return null;
|
|
64
|
+
const seal = delegationSeal(serder);
|
|
65
|
+
return {
|
|
66
|
+
delegate: seal.i,
|
|
67
|
+
sn: serder.sn ?? 0,
|
|
68
|
+
said: seal.d,
|
|
69
|
+
ilk: serder.ilk === "drt" ? "drt" : "dip",
|
|
70
|
+
delegator,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Find the delegator's KEL event that seals the request, whether or not it is receipted. */
|
|
74
|
+
function findAnchor(db, request) {
|
|
75
|
+
for (const [, said] of db.getKelItemIter(request.delegator)) {
|
|
76
|
+
const serder = db.getEvtSerder(request.delegator, said);
|
|
77
|
+
for (const seal of serder?.seals ?? []) {
|
|
78
|
+
const { i, s, d } = (seal ?? {});
|
|
79
|
+
if (i === request.delegate && d === request.said && typeof s === "string" && parseInt(s, 16) === request.sn) {
|
|
80
|
+
return serder;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
function anchorOf(serder) {
|
|
87
|
+
return { sn: serder.sn ?? 0, said: serder.said };
|
|
88
|
+
}
|
|
89
|
+
function inEscrow(db, request) {
|
|
90
|
+
return db.delegables.get([request.delegate]).includes(request.said);
|
|
91
|
+
}
|
|
92
|
+
/** True once the delegated event has left escrow and reached local state. */
|
|
93
|
+
export function delegateCommitted(db, delegate, sn) {
|
|
94
|
+
const kever = db.getKever(delegate);
|
|
95
|
+
return kever !== undefined && kever !== null && kever.sn >= sn;
|
|
96
|
+
}
|
|
97
|
+
/** Witnesses of the delegate after the delegated event: `backs` of a `dip`, current witnesses otherwise. */
|
|
98
|
+
export function delegateWitnesses(db, serder) {
|
|
99
|
+
if ((serder.sn ?? 0) === 0)
|
|
100
|
+
return [...serder.backs];
|
|
101
|
+
if (!serder.pre)
|
|
102
|
+
return [];
|
|
103
|
+
return [...(db.getKever(serder.pre)?.wits ?? [])];
|
|
104
|
+
}
|
|
105
|
+
/** Build the logs query that pulls the delegated event's replay from one delegate witness. */
|
|
106
|
+
export function delegateWitnessLogsQuery(signer, serder, witness) {
|
|
107
|
+
if (!serder.pre || !serder.snh) {
|
|
108
|
+
throw new ValidationError("Delegated event is missing pre or sn for query.");
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
pre: serder.pre,
|
|
112
|
+
signer,
|
|
113
|
+
src: witness,
|
|
114
|
+
route: "logs",
|
|
115
|
+
q: { fn: "0", s: serder.snh },
|
|
116
|
+
wits: [witness],
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/** Record the approving seal for the delegated event and let the delegator's escrow promote it. */
|
|
120
|
+
export function pinApprovalSeal(hby, hab, delegated, approving) {
|
|
121
|
+
if (!approving.sner || !approving.said || !delegated.pre || !delegated.said) {
|
|
122
|
+
throw new ValidationError("Approving event material is incomplete.");
|
|
123
|
+
}
|
|
124
|
+
hby.db.aess.pin(dgKey(delegated.pre, delegated.said), [approving.sner, new Diger({ qb64: approving.said })]);
|
|
125
|
+
hab.kvy.processEscrowDelegables();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* List delegated events awaiting approval, oldest sequence first. Reads every
|
|
129
|
+
* `delegables.` row, with no cap, and skips rows whose delegated event already
|
|
130
|
+
* reached local state. Pure.
|
|
131
|
+
*/
|
|
132
|
+
export function listPendingDelegations(deps, { delegator } = {}) {
|
|
133
|
+
const { db } = deps;
|
|
134
|
+
const pending = [];
|
|
135
|
+
for (const [keys, said] of db.delegables.getTopItemIter()) {
|
|
136
|
+
const pre = keys[0];
|
|
137
|
+
const serder = pre ? db.getEvtSerder(pre, said) : null;
|
|
138
|
+
const request = serder && pre ? requestFromEscrow(db, serder, pre) : null;
|
|
139
|
+
if (!request || (delegator !== undefined && request.delegator !== delegator))
|
|
140
|
+
continue;
|
|
141
|
+
if (delegateCommitted(db, request.delegate, request.sn))
|
|
142
|
+
continue;
|
|
143
|
+
pending.push({ ...request, anchored: findAnchor(db, request) !== null });
|
|
144
|
+
}
|
|
145
|
+
return pending.sort((left, right) => left.sn - right.sn);
|
|
146
|
+
}
|
|
147
|
+
/** Read the durable status of one request; mutates nothing. */
|
|
148
|
+
export function delegationApprovalStatus(deps, request) {
|
|
149
|
+
const { db } = deps;
|
|
150
|
+
const committed = delegateCommitted(db, request.delegate, request.sn);
|
|
151
|
+
if (!committed && !inEscrow(db, request))
|
|
152
|
+
return { state: "unknown", reason: "no-local-event" };
|
|
153
|
+
const anchor = findAnchor(db, request);
|
|
154
|
+
if (!anchor)
|
|
155
|
+
return { state: "awaiting-approval" };
|
|
156
|
+
if (committed)
|
|
157
|
+
return { state: "approved", anchor: anchorOf(anchor) };
|
|
158
|
+
return { state: "anchored", anchor: anchorOf(anchor), receipted: db.fullyWitnessed(anchor) };
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Local step after anchoring: record the approving seal and process the
|
|
162
|
+
* `delegables.` escrow. Idempotent, sends nothing and signs nothing. It does
|
|
163
|
+
* nothing until the anchor exists and, for a delegate with witnesses, until the
|
|
164
|
+
* delegate's event has arrived through the witness replay, because pinning
|
|
165
|
+
* earlier would make local state look approved while incomplete.
|
|
166
|
+
*/
|
|
167
|
+
export function settleDelegationApproval(deps, request) {
|
|
168
|
+
const { hby } = deps;
|
|
169
|
+
const hab = hby.habs.get(request.delegator);
|
|
170
|
+
const delegated = hby.db.getEvtSerder(request.delegate, request.said);
|
|
171
|
+
const anchor = findAnchor(hby.db, request);
|
|
172
|
+
if (!hab || !delegated || !anchor)
|
|
173
|
+
return;
|
|
174
|
+
const witnessed = delegateWitnesses(hby.db, delegated).length > 0;
|
|
175
|
+
if (witnessed && !delegateCommitted(hby.db, request.delegate, request.sn))
|
|
176
|
+
return;
|
|
177
|
+
pinApprovalSeal(hby, hab, delegated, anchor);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Approve one delegated event: anchor its seal in the delegator's KEL unless
|
|
181
|
+
* the KEL already holds it, obtain witness receipts for the anchoring event and
|
|
182
|
+
* ask the delegate's witness for the delegated event. Returns without waiting
|
|
183
|
+
* for the delegate; use {@link waitForDelegationApproval}.
|
|
184
|
+
*
|
|
185
|
+
* Repeating the call after a failure resumes at the first step not yet done.
|
|
186
|
+
*
|
|
187
|
+
* @throws ValidationError for a request not held locally, a delegator that is not a local single-signature identifier, or an anchor that cannot be read back.
|
|
188
|
+
*/
|
|
189
|
+
export function* approveDelegation(deps, request, { event, auths }) {
|
|
190
|
+
const { hby } = deps;
|
|
191
|
+
const delegated = hby.db.getEvtSerder(request.delegate, request.said);
|
|
192
|
+
const status = delegationApprovalStatus(hby, request);
|
|
193
|
+
if (status.state === "unknown" || !delegated) {
|
|
194
|
+
throw new ValidationError(`No delegated ${request.ilk} ${request.said} is held for ${request.delegate}.`);
|
|
195
|
+
}
|
|
196
|
+
const hab = hby.habs.get(request.delegator);
|
|
197
|
+
if (!hab || isLocalGroupHab(hby, hab)) {
|
|
198
|
+
throw new ValidationError(`${request.delegator} is not a local single-signature delegator.`);
|
|
199
|
+
}
|
|
200
|
+
if (!hab.kever)
|
|
201
|
+
throw new ValidationError(`Missing accepted key state for ${hab.pre}.`);
|
|
202
|
+
let anchor = findAnchor(hby.db, request);
|
|
203
|
+
if (!anchor) {
|
|
204
|
+
const data = [delegationSeal(delegated)];
|
|
205
|
+
if (event === "ixn")
|
|
206
|
+
hab.interact({ data });
|
|
207
|
+
else
|
|
208
|
+
hab.rotate({ data });
|
|
209
|
+
anchor = findAnchor(hby.db, request);
|
|
210
|
+
if (!anchor)
|
|
211
|
+
throw new ValidationError("Approving event material is incomplete.");
|
|
212
|
+
}
|
|
213
|
+
yield* receiptEvent(deps, hab.pre, { sn: anchorOf(anchor).sn, auths });
|
|
214
|
+
requestDelegatedEvent(deps, request, hab.pre);
|
|
215
|
+
return delegationApprovalStatus(hby, request);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* After the anchor exists: record the approving seal and ask the delegate's witness
|
|
219
|
+
* for the delegated event unless it already arrived. `signer` is the local identifier
|
|
220
|
+
* that sends the query: the delegator, or a group delegator's local member. Idempotent.
|
|
221
|
+
*/
|
|
222
|
+
export function requestDelegatedEvent(deps, request, signer) {
|
|
223
|
+
const { hby } = deps;
|
|
224
|
+
const delegated = hby.db.getEvtSerder(request.delegate, request.said);
|
|
225
|
+
if (!delegated) {
|
|
226
|
+
throw new ValidationError(`No delegated ${request.ilk} ${request.said} is held for ${request.delegate}.`);
|
|
227
|
+
}
|
|
228
|
+
settleDelegationApproval(deps, request);
|
|
229
|
+
const [witness] = delegateWitnesses(hby.db, delegated).sort();
|
|
230
|
+
if (!delegateCommitted(hby.db, request.delegate, request.sn)) {
|
|
231
|
+
// A delegate with no witness is asked through the same logs route with the usual attester choice.
|
|
232
|
+
deps.querying.enqueue(witness
|
|
233
|
+
? delegateWitnessLogsQuery(signer, delegated, witness)
|
|
234
|
+
: { pre: request.delegate, signer, route: "logs", q: { fn: "0", s: delegated.snh } });
|
|
235
|
+
}
|
|
236
|
+
deps.changes?.push({ kind: "delegation", id: `${request.delegate}:${request.sn}` });
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Propose a group delegator's anchoring interaction for one request: the group
|
|
240
|
+
* interaction that seals the delegated event, published to the other members.
|
|
241
|
+
* Returns without waiting; the other members approve it with `approveGroupProposal`
|
|
242
|
+
* and the Counselor receipts it, so read progress with `delegationApprovalStatus`
|
|
243
|
+
* and `counselor.status(result.event)`.
|
|
244
|
+
*
|
|
245
|
+
* Idempotent: null when the group's KEL already holds the anchor, so a repeat
|
|
246
|
+
* never anchors twice.
|
|
247
|
+
*
|
|
248
|
+
* @throws ValidationError for a request not held locally or a delegator that is not a local group.
|
|
249
|
+
*/
|
|
250
|
+
export function* proposeGroupDelegationApproval(deps, request, inputs) {
|
|
251
|
+
const { hby } = deps;
|
|
252
|
+
const delegated = hby.db.getEvtSerder(request.delegate, request.said);
|
|
253
|
+
if (delegationApprovalStatus(hby, request).state === "unknown" || !delegated) {
|
|
254
|
+
throw new ValidationError(`No delegated ${request.ilk} ${request.said} is held for ${request.delegate}.`);
|
|
255
|
+
}
|
|
256
|
+
const group = hby.habs.get(request.delegator);
|
|
257
|
+
if (!group || !isLocalGroupHab(hby, group)) {
|
|
258
|
+
throw new ValidationError(`${request.delegator} is not a local group delegator.`);
|
|
259
|
+
}
|
|
260
|
+
if (findAnchor(hby.db, request))
|
|
261
|
+
return null;
|
|
262
|
+
return yield* proposeGroupInteraction(deps, group, [delegationSeal(delegated)], inputs);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Observe until at least one delegated event awaits the delegator, or the budget
|
|
266
|
+
* expires. Waits on the delegator's own `delegables.` escrow only: unrelated
|
|
267
|
+
* group proposals, queries or OOBIs never hold it open. Starts no worker; the
|
|
268
|
+
* host's runtime brings the request in through its mailbox or witness polling.
|
|
269
|
+
*
|
|
270
|
+
* `timed-out` means no request reached local state in the budget, which is also
|
|
271
|
+
* what a request that was already approved and committed looks like.
|
|
272
|
+
*/
|
|
273
|
+
export function* waitForPendingDelegation(deps, filter = {}, { timeoutMs = DELEGATION_APPROVAL_TIMEOUT_MS } = {}) {
|
|
274
|
+
const done = yield* observeUntil(() => listPendingDelegations(deps, filter).length > 0, { timeoutMs });
|
|
275
|
+
const status = listPendingDelegations(deps, filter);
|
|
276
|
+
if (!done && status.length === 0)
|
|
277
|
+
return { outcome: "timed-out", status, timeoutMs };
|
|
278
|
+
for (const request of status)
|
|
279
|
+
deps.changes?.push({ kind: "delegation", id: `${request.delegate}:${request.sn}` });
|
|
280
|
+
return { outcome: "settled", status };
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Observe a group delegator's request until its anchor is in the group's KEL and
|
|
284
|
+
* receipted by witnesses, or the delegate's event is already accepted. This is
|
|
285
|
+
* the point where {@link requestDelegatedEvent} can ask for the delegate's event.
|
|
286
|
+
*/
|
|
287
|
+
export function* waitForDelegationAnchor(deps, request, { timeoutMs = DELEGATION_APPROVAL_TIMEOUT_MS } = {}) {
|
|
288
|
+
const ready = (status) => status.state === "approved" || (status.state === "anchored" && status.receipted);
|
|
289
|
+
const done = yield* observeUntil(() => ready(delegationApprovalStatus(deps, request)), { timeoutMs });
|
|
290
|
+
const status = delegationApprovalStatus(deps, request);
|
|
291
|
+
if (!done && !ready(status))
|
|
292
|
+
return { outcome: "timed-out", status, timeoutMs };
|
|
293
|
+
return { outcome: "settled", status };
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Observe the request until it is `approved` or the budget expires. Starts no
|
|
297
|
+
* worker; the host's runtime brings the delegate's event in.
|
|
298
|
+
*/
|
|
299
|
+
export function* waitForDelegationApproval(deps, request, { timeoutMs = DELEGATION_APPROVAL_TIMEOUT_MS } = {}) {
|
|
300
|
+
const read = () => {
|
|
301
|
+
deps.settle?.();
|
|
302
|
+
return delegationApprovalStatus(deps, request);
|
|
303
|
+
};
|
|
304
|
+
const done = yield* observeUntil(() => read().state === "approved", { timeoutMs });
|
|
305
|
+
const status = read();
|
|
306
|
+
if (!done || status.state !== "approved")
|
|
307
|
+
return { outcome: "timed-out", status, timeoutMs };
|
|
308
|
+
deps.changes?.push({ kind: "delegation", id: `${request.delegate}:${request.sn}` });
|
|
309
|
+
return { outcome: "settled", status };
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Remove the controller notices (`/delegate/request`) that announced this
|
|
313
|
+
* request. Local only: the delegated event stays in escrow and the delegate is
|
|
314
|
+
* told nothing, so the request can still be approved or listed later.
|
|
315
|
+
*
|
|
316
|
+
* @returns Number of notices removed.
|
|
317
|
+
*/
|
|
318
|
+
export function dismissDelegation(deps, request) {
|
|
319
|
+
const stale = [];
|
|
320
|
+
for (let start = 0;; start += 25) {
|
|
321
|
+
const page = deps.notifier.list(start, 25);
|
|
322
|
+
for (const note of page) {
|
|
323
|
+
const attrs = note.pad.a;
|
|
324
|
+
const evt = attrs["ked"];
|
|
325
|
+
if (attrs["r"] === DELEGATE_REQUEST_ROUTE && attrs["delpre"] === request.delegator && evt?.d === request.said) {
|
|
326
|
+
stale.push(note.pad.i);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (page.length < 25)
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
return stale.filter((rid) => deps.notifier.remove(rid)).length;
|
|
333
|
+
}
|