keri-ts 2.2.4 → 2.2.6
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/esm/keri/npm/src/_dnt.polyfills.js +14 -14
- package/esm/keri/npm/src/acdc/dhking.js +29 -2
- package/esm/keri/npm/src/acdc/observing.js +10 -3
- package/esm/keri/npm/src/acdc/query-resend.js +74 -0
- package/esm/keri/npm/src/acdc/regengine.js +39 -9
- package/esm/keri/npm/src/acdc/regeventing.js +5 -3
- package/esm/keri/npm/src/acdc/registering.js +19 -0
- package/esm/keri/npm/src/acdc/salting.js +4 -0
- package/esm/keri/npm/src/acdc/unblinding.js +38 -3
- package/esm/keri/npm/src/app/bootstrap/authenticating.js +32 -10
- package/esm/keri/npm/src/app/bootstrap/oobiery.js +363 -30
- package/esm/keri/npm/src/app/credentials/credential-importing.js +33 -4
- package/esm/keri/npm/src/app/credentials/root-replicator.js +27 -15
- package/esm/keri/npm/src/app/credentials/schema-resolving.js +5 -1
- package/esm/keri/npm/src/app/credentials/tel-publishing.js +16 -7
- package/esm/keri/npm/src/app/delivery/forwarding.js +205 -44
- package/esm/keri/npm/src/app/delivery/relaying.js +232 -0
- package/esm/keri/npm/src/app/delivery/respondant.js +8 -5
- package/esm/keri/npm/src/app/exchanges/exchange-messaging.js +1 -1
- package/esm/keri/npm/src/app/exchanges/exchanging.js +65 -9
- package/esm/keri/npm/src/app/identity/delegating.js +66 -9
- package/esm/keri/npm/src/app/identity/habbing.js +190 -71
- package/esm/keri/npm/src/app/identity/keeping.js +111 -39
- package/esm/keri/npm/src/app/identity/retire-identifier.js +98 -0
- package/esm/keri/npm/src/app/ipex/disclosure-replaying.js +116 -0
- package/esm/keri/npm/src/app/ipex/group-ipex.js +122 -25
- package/esm/keri/npm/src/app/ipex/group-issuance.js +137 -37
- package/esm/keri/npm/src/app/ipex/ipex-discloser.js +94 -31
- package/esm/keri/npm/src/app/ipex/ipex-grouping.js +53 -3
- package/esm/keri/npm/src/app/ipex/ipex-v2.js +7 -2
- package/esm/keri/npm/src/app/ipex/issuance.js +147 -44
- package/esm/keri/npm/src/app/ipex/pending-presentations.js +4 -2
- package/esm/keri/npm/src/app/ipex/presenting.js +3 -18
- package/esm/keri/npm/src/app/ipex/receive-issuance.js +2 -1
- package/esm/keri/npm/src/app/ipex/unblinding-workflow.js +39 -11
- package/esm/keri/npm/src/app/mailbox/agent-inbox.js +292 -0
- package/esm/keri/npm/src/app/mailbox/forward-handler.js +298 -52
- package/esm/keri/npm/src/app/mailbox/kel-publisher.js +26 -31
- package/esm/keri/npm/src/app/mailbox/mailbox-poller.js +70 -62
- package/esm/keri/npm/src/app/mailbox/mailboxing.js +20 -4
- package/esm/keri/npm/src/app/multisig/counseling.js +71 -27
- package/esm/keri/npm/src/app/multisig/group-members.js +41 -5
- package/esm/keri/npm/src/app/multisig/grouping.js +50 -2
- package/esm/keri/npm/src/app/multisig/multisig-workflows.js +3 -18
- package/esm/keri/npm/src/app/multisig/proposing.js +1 -16
- package/esm/keri/npm/src/app/multisig/rejoin-group.js +99 -0
- package/esm/keri/npm/src/app/multisig/replace-member.js +29 -8
- package/esm/keri/npm/src/app/protocol/parsering.js +45 -17
- package/esm/keri/npm/src/app/protocol/protocol-processing.js +47 -21
- package/esm/keri/npm/src/app/queries/query-replies.js +0 -22
- package/esm/keri/npm/src/app/queries/relay-refresh.js +81 -0
- package/esm/keri/npm/src/app/queries/witness-inquisitor.js +180 -34
- package/esm/keri/npm/src/app/runtime/agent-runtime.js +42 -73
- package/esm/keri/npm/src/app/runtime/cue-runtime.js +45 -5
- package/esm/keri/npm/src/app/runtime/ipex-auxiliaries.js +8 -1
- package/esm/keri/npm/src/app/runtime/operation-owners.js +26 -56
- package/esm/keri/npm/src/app/runtime/workflow-contract.js +7 -4
- package/esm/keri/npm/src/app/transport/http-client.js +20 -2
- package/esm/keri/npm/src/app/transport/message-source.js +2 -1
- package/esm/keri/npm/src/app/transport/messengering.js +39 -8
- package/esm/keri/npm/src/app/witness/ingress.js +7 -0
- package/esm/keri/npm/src/app/witness/receipt-client.js +43 -16
- package/esm/keri/npm/src/app/witness/receipting.js +62 -20
- package/esm/keri/npm/src/cli/messaging/multisig.js +4 -3
- package/esm/keri/npm/src/core/errors.js +73 -0
- package/esm/keri/npm/src/core/kel/delegation-ancestry.js +11 -2
- package/esm/keri/npm/src/core/kel/eventing.js +25 -28
- package/esm/keri/npm/src/core/kel/kever.js +15 -9
- package/esm/keri/npm/src/core/mailbox/kram-policy.js +16 -0
- package/esm/keri/npm/src/core/mailbox/kram-pruning.js +25 -6
- package/esm/keri/npm/src/core/mailbox/kram-time.js +34 -6
- package/esm/keri/npm/src/core/mailbox/kraming.js +58 -2
- package/esm/keri/npm/src/core/missing-anchor-query.js +20 -0
- package/esm/keri/npm/src/core/routing.js +18 -25
- package/esm/keri/npm/src/core/scheming.js +12 -5
- package/esm/keri/npm/src/core/wire-fields.js +126 -0
- package/esm/keri/npm/src/db/basing.js +4 -13
- package/esm/keri/npm/src/db/core/indexeddb-persistence.js +3 -2
- package/esm/keri/npm/src/db/core/webdber.js +85 -27
- package/esm/keri/npm/src/db/mailbox/mailboxing.js +13 -0
- package/esm/keri/npm/src/db/subing.js +4 -0
- package/esm/keri/npm/src/runtime/index.js +11 -5
- package/esm/keri/npm/src/time/mod.js +5 -0
- package/esm/keri/npm/src/vdr/credential-tsn-record.js +2 -7
- package/esm/keri/npm/src/vdr/eventing.js +71 -28
- package/esm/keri/npm/src/vdr/registry-tsn-record.js +3 -13
- package/esm/keri/npm/src/version.js +2 -2
- package/package.json +1 -1
- package/types/_dnt.polyfills.d.ts +9 -9
- package/types/_dnt.polyfills.d.ts.map +1 -1
- package/types/acdc/dhking.d.ts +8 -0
- package/types/acdc/dhking.d.ts.map +1 -1
- package/types/acdc/observing.d.ts +5 -1
- package/types/acdc/observing.d.ts.map +1 -1
- package/types/acdc/query-resend.d.ts +24 -0
- package/types/acdc/query-resend.d.ts.map +1 -0
- package/types/acdc/regengine.d.ts +19 -1
- package/types/acdc/regengine.d.ts.map +1 -1
- package/types/acdc/regeventing.d.ts.map +1 -1
- package/types/acdc/registering.d.ts +6 -0
- package/types/acdc/registering.d.ts.map +1 -1
- package/types/acdc/salting.d.ts.map +1 -1
- package/types/acdc/unblinding.d.ts +13 -1
- package/types/acdc/unblinding.d.ts.map +1 -1
- package/types/app/bootstrap/authenticating.d.ts +12 -2
- package/types/app/bootstrap/authenticating.d.ts.map +1 -1
- package/types/app/bootstrap/oobiery.d.ts +144 -7
- package/types/app/bootstrap/oobiery.d.ts.map +1 -1
- package/types/app/credentials/credential-importing.d.ts +8 -0
- package/types/app/credentials/credential-importing.d.ts.map +1 -1
- package/types/app/credentials/root-replicator.d.ts +19 -8
- package/types/app/credentials/root-replicator.d.ts.map +1 -1
- package/types/app/credentials/schema-resolving.d.ts.map +1 -1
- package/types/app/credentials/tel-publishing.d.ts +4 -2
- package/types/app/credentials/tel-publishing.d.ts.map +1 -1
- package/types/app/delivery/forwarding.d.ts +90 -5
- package/types/app/delivery/forwarding.d.ts.map +1 -1
- package/types/app/delivery/relaying.d.ts +144 -0
- package/types/app/delivery/relaying.d.ts.map +1 -0
- package/types/app/delivery/respondant.d.ts +9 -2
- package/types/app/delivery/respondant.d.ts.map +1 -1
- package/types/app/exchanges/exchanging.d.ts +36 -0
- package/types/app/exchanges/exchanging.d.ts.map +1 -1
- package/types/app/identity/delegating.d.ts +6 -0
- package/types/app/identity/delegating.d.ts.map +1 -1
- package/types/app/identity/habbing.d.ts +106 -19
- package/types/app/identity/habbing.d.ts.map +1 -1
- package/types/app/identity/keeping.d.ts +54 -19
- package/types/app/identity/keeping.d.ts.map +1 -1
- package/types/app/identity/retire-identifier.d.ts +24 -0
- package/types/app/identity/retire-identifier.d.ts.map +1 -0
- package/types/app/ipex/disclosure-replaying.d.ts +61 -0
- package/types/app/ipex/disclosure-replaying.d.ts.map +1 -0
- package/types/app/ipex/group-ipex.d.ts +60 -14
- package/types/app/ipex/group-ipex.d.ts.map +1 -1
- package/types/app/ipex/group-issuance.d.ts +54 -8
- package/types/app/ipex/group-issuance.d.ts.map +1 -1
- package/types/app/ipex/ipex-discloser.d.ts +39 -2
- package/types/app/ipex/ipex-discloser.d.ts.map +1 -1
- package/types/app/ipex/ipex-grouping.d.ts +23 -2
- package/types/app/ipex/ipex-grouping.d.ts.map +1 -1
- package/types/app/ipex/ipex-v2.d.ts +5 -2
- package/types/app/ipex/ipex-v2.d.ts.map +1 -1
- package/types/app/ipex/issuance.d.ts +46 -16
- package/types/app/ipex/issuance.d.ts.map +1 -1
- package/types/app/ipex/pending-presentations.d.ts +4 -2
- package/types/app/ipex/pending-presentations.d.ts.map +1 -1
- package/types/app/ipex/presenting.d.ts.map +1 -1
- package/types/app/ipex/receive-issuance.d.ts +2 -1
- package/types/app/ipex/receive-issuance.d.ts.map +1 -1
- package/types/app/ipex/unblinding-workflow.d.ts +13 -2
- package/types/app/ipex/unblinding-workflow.d.ts.map +1 -1
- package/types/app/mailbox/agent-inbox.d.ts +126 -0
- package/types/app/mailbox/agent-inbox.d.ts.map +1 -0
- package/types/app/mailbox/forward-handler.d.ts +114 -14
- package/types/app/mailbox/forward-handler.d.ts.map +1 -1
- package/types/app/mailbox/kel-publisher.d.ts +12 -22
- package/types/app/mailbox/kel-publisher.d.ts.map +1 -1
- package/types/app/mailbox/mailbox-poller.d.ts +40 -24
- package/types/app/mailbox/mailbox-poller.d.ts.map +1 -1
- package/types/app/mailbox/mailboxing.d.ts +19 -5
- package/types/app/mailbox/mailboxing.d.ts.map +1 -1
- package/types/app/multisig/counseling.d.ts +32 -11
- package/types/app/multisig/counseling.d.ts.map +1 -1
- package/types/app/multisig/group-members.d.ts +17 -1
- package/types/app/multisig/group-members.d.ts.map +1 -1
- package/types/app/multisig/grouping.d.ts +17 -1
- package/types/app/multisig/grouping.d.ts.map +1 -1
- package/types/app/multisig/multisig-workflows.d.ts +0 -8
- package/types/app/multisig/multisig-workflows.d.ts.map +1 -1
- package/types/app/multisig/proposing.d.ts +4 -19
- package/types/app/multisig/proposing.d.ts.map +1 -1
- package/types/app/multisig/rejoin-group.d.ts +119 -0
- package/types/app/multisig/rejoin-group.d.ts.map +1 -0
- package/types/app/multisig/replace-member.d.ts +15 -1
- package/types/app/multisig/replace-member.d.ts.map +1 -1
- package/types/app/protocol/parsering.d.ts +21 -2
- package/types/app/protocol/parsering.d.ts.map +1 -1
- package/types/app/protocol/protocol-processing.d.ts +25 -5
- package/types/app/protocol/protocol-processing.d.ts.map +1 -1
- package/types/app/queries/query-replies.d.ts +4 -8
- package/types/app/queries/query-replies.d.ts.map +1 -1
- package/types/app/queries/relay-refresh.d.ts +26 -0
- package/types/app/queries/relay-refresh.d.ts.map +1 -0
- package/types/app/queries/witness-inquisitor.d.ts +56 -5
- package/types/app/queries/witness-inquisitor.d.ts.map +1 -1
- package/types/app/runtime/agent-runtime.d.ts +34 -3
- package/types/app/runtime/agent-runtime.d.ts.map +1 -1
- package/types/app/runtime/cue-runtime.d.ts +15 -3
- package/types/app/runtime/cue-runtime.d.ts.map +1 -1
- package/types/app/runtime/ipex-auxiliaries.d.ts.map +1 -1
- package/types/app/runtime/operation-owners.d.ts +16 -26
- package/types/app/runtime/operation-owners.d.ts.map +1 -1
- package/types/app/runtime/workflow-contract.d.ts +21 -6
- package/types/app/runtime/workflow-contract.d.ts.map +1 -1
- package/types/app/transport/http-client.d.ts +9 -0
- package/types/app/transport/http-client.d.ts.map +1 -1
- package/types/app/transport/message-source.d.ts +6 -3
- package/types/app/transport/message-source.d.ts.map +1 -1
- package/types/app/transport/messengering.d.ts +10 -1
- package/types/app/transport/messengering.d.ts.map +1 -1
- package/types/app/witness/ingress.d.ts +1 -0
- package/types/app/witness/ingress.d.ts.map +1 -1
- package/types/app/witness/receipt-client.d.ts +19 -1
- package/types/app/witness/receipt-client.d.ts.map +1 -1
- package/types/app/witness/receipting.d.ts +24 -1
- package/types/app/witness/receipting.d.ts.map +1 -1
- package/types/cli/messaging/multisig.d.ts.map +1 -1
- package/types/core/cues.d.ts +53 -1
- package/types/core/cues.d.ts.map +1 -1
- package/types/core/errors.d.ts +32 -0
- package/types/core/errors.d.ts.map +1 -1
- package/types/core/kel/delegation-ancestry.d.ts.map +1 -1
- package/types/core/kel/eventing.d.ts.map +1 -1
- package/types/core/kel/kever-decisions.d.ts +3 -1
- package/types/core/kel/kever-decisions.d.ts.map +1 -1
- package/types/core/kel/kever.d.ts +7 -1
- package/types/core/kel/kever.d.ts.map +1 -1
- package/types/core/mailbox/kram-policy.d.ts +12 -0
- package/types/core/mailbox/kram-policy.d.ts.map +1 -1
- package/types/core/mailbox/kram-pruning.d.ts +5 -1
- package/types/core/mailbox/kram-pruning.d.ts.map +1 -1
- package/types/core/mailbox/kram-time.d.ts +26 -2
- package/types/core/mailbox/kram-time.d.ts.map +1 -1
- package/types/core/mailbox/kraming.d.ts +14 -1
- package/types/core/mailbox/kraming.d.ts.map +1 -1
- package/types/core/missing-anchor-query.d.ts +34 -0
- package/types/core/missing-anchor-query.d.ts.map +1 -0
- package/types/core/routing.d.ts +3 -7
- package/types/core/routing.d.ts.map +1 -1
- package/types/core/scheming.d.ts.map +1 -1
- package/types/core/wire-fields.d.ts +56 -0
- package/types/core/wire-fields.d.ts.map +1 -0
- package/types/db/basing.d.ts.map +1 -1
- package/types/db/core/indexeddb-persistence.d.ts +3 -2
- package/types/db/core/indexeddb-persistence.d.ts.map +1 -1
- package/types/db/core/webdber.d.ts +32 -6
- package/types/db/core/webdber.d.ts.map +1 -1
- package/types/db/exchange/exchange-records.d.ts +4 -0
- package/types/db/exchange/exchange-records.d.ts.map +1 -1
- package/types/db/mailbox/mailboxing.d.ts +10 -1
- package/types/db/mailbox/mailboxing.d.ts.map +1 -1
- package/types/db/subing.d.ts +2 -0
- package/types/db/subing.d.ts.map +1 -1
- package/types/runtime/index.d.ts +20 -14
- package/types/runtime/index.d.ts.map +1 -1
- package/types/time/mod.d.ts +2 -0
- package/types/time/mod.d.ts.map +1 -1
- package/types/vdr/credential-tsn-record.d.ts.map +1 -1
- package/types/vdr/eventing.d.ts +32 -1
- package/types/vdr/eventing.d.ts.map +1 -1
- package/types/vdr/registry-tsn-record.d.ts.map +1 -1
- package/types/version.d.ts +2 -2
- package/esm/keri/npm/src/app/runtime/signer-conditions.js +0 -51
- package/types/app/runtime/signer-conditions.d.ts +0 -32
- package/types/app/runtime/signer-conditions.d.ts.map +0 -1
|
@@ -7,23 +7,36 @@
|
|
|
7
7
|
* is an explicitly selected remote attester. Resolve/sign just before sending,
|
|
8
8
|
* using accepted endpoint evidence. One worker owns the unsigned request Deck
|
|
9
9
|
* and current network attempt; there is no retained signed retry backlog.
|
|
10
|
+
*
|
|
11
|
+
* With a relay (an edge runtime) every query is addressed and sent to the relay,
|
|
12
|
+
* which is the attester: it answers from its own store through its Respondant
|
|
13
|
+
* and Poster into the edge's mailbox, which it hosts. No query goes to a witness
|
|
14
|
+
* or controller, whatever `src` or `wits` the request names.
|
|
10
15
|
*/
|
|
11
16
|
import { concatBytes } from "cesr-ts";
|
|
12
17
|
import { call, resource } from "effection";
|
|
13
18
|
import { Deck } from "../../core/deck.js";
|
|
14
|
-
import { ValidationError } from "../../core/errors.js";
|
|
15
19
|
import { consoleLogger } from "../../core/logger.js";
|
|
16
20
|
import { Roles } from "../../core/roles.js";
|
|
17
21
|
import { Schemes } from "../../core/schemes.js";
|
|
18
22
|
import { introduce } from "../delivery/introducing.js";
|
|
23
|
+
import { relayEndpoint, relayRefusal } from "../delivery/relaying.js";
|
|
19
24
|
import { PROTOCOL_TOCK_MS } from "../runtime/doing.js";
|
|
20
25
|
import { waitOnClock } from "../runtime/workflow-contract.js";
|
|
21
26
|
import { CesrHttpRefusal } from "../transport/cesr-egress.js";
|
|
27
|
+
import { isRequestableHttpUrl } from "../transport/http-client.js";
|
|
22
28
|
import { HTTPMessenger } from "../transport/http-messenger.js";
|
|
29
|
+
import { messengerUrl } from "../transport/messengering.js";
|
|
23
30
|
import { requireTcpDialer } from "../transport/tcp-dialer.js";
|
|
24
31
|
import { TransportError } from "../transport/transport-error.js";
|
|
25
32
|
/** First eligible role used by KERIpy WitnessInquisitor before random endpoint selection. */
|
|
26
33
|
const QUERY_ROLE_PRIORITY = [Roles.controller, Roles.agent, Roles.witness];
|
|
34
|
+
/**
|
|
35
|
+
* Delivery passes an ordinary request may rotate with a ready signer but no reachable attester before it is dropped:
|
|
36
|
+
* about five minutes at the protocol tock. Any remote party can cause such requests (every unverified reply signed by
|
|
37
|
+
* an unknown prefix yields a `query` cue), so without a bound they would rotate in the queue forever.
|
|
38
|
+
*/
|
|
39
|
+
export const UNADDRESSED_QUERY_PASS_LIMIT = 9_600;
|
|
27
40
|
/**
|
|
28
41
|
* Copy only the owned query-body level without erasing its route/payload relationship.
|
|
29
42
|
*
|
|
@@ -41,6 +54,22 @@ function copyQuery(instruction) {
|
|
|
41
54
|
return { route: instruction.route, q: { ...instruction.q } };
|
|
42
55
|
}
|
|
43
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Identity of one unsigned request for duplicate detection: every field that changes what is signed or where it goes.
|
|
59
|
+
*
|
|
60
|
+
* @param request Queued or candidate request; query filters are strings and string-valued seal SADs.
|
|
61
|
+
* @returns A canonical string equal for two requests exactly when they would produce the same query.
|
|
62
|
+
*/
|
|
63
|
+
function requestKey(request) {
|
|
64
|
+
return JSON.stringify([
|
|
65
|
+
request.route,
|
|
66
|
+
request.pre,
|
|
67
|
+
request.signer ?? null,
|
|
68
|
+
request.src ?? null,
|
|
69
|
+
request.wits ?? null,
|
|
70
|
+
request.q,
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
44
73
|
/**
|
|
45
74
|
* Return the sole local habitat when exactly one exists.
|
|
46
75
|
*
|
|
@@ -56,12 +85,47 @@ function soleHab(hby) {
|
|
|
56
85
|
const first = habitats.next();
|
|
57
86
|
return first.done || !habitats.next().done ? null : first.value;
|
|
58
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* The attesters an ordinary (non-relay) query for `pre` may go to: the AIDs of the first role among controller,
|
|
90
|
+
* agent and witness that has any accepted endpoint for the subject. Mailbox providers are not query attesters.
|
|
91
|
+
*
|
|
92
|
+
* @param hab Local habitat whose accepted-state store is read.
|
|
93
|
+
* @param pre Subject AID whose accepted endpoint roles are consulted.
|
|
94
|
+
* @returns Eligible attester AIDs, or an empty array for an unknown subject or a subject with no such endpoint.
|
|
95
|
+
*/
|
|
96
|
+
function queryAttesters(hab, pre) {
|
|
97
|
+
if (!hab.db.getKever(pre))
|
|
98
|
+
return [];
|
|
99
|
+
const ends = hab.endsFor(pre);
|
|
100
|
+
for (const role of QUERY_ROLE_PRIORITY) {
|
|
101
|
+
const eids = Object.keys(ends[role] ?? {});
|
|
102
|
+
if (eids.length > 0)
|
|
103
|
+
return eids;
|
|
104
|
+
}
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The location a query can be sent to, preferring HTTPS, then HTTP, then TCP. An accepted location comes from a remote
|
|
109
|
+
* `/loc/scheme` reply, so one the HTTP client refuses by construction (embedded credentials) is no location: sending
|
|
110
|
+
* to it would throw a refusal that is not a send outcome.
|
|
111
|
+
*
|
|
112
|
+
* @param urls Accepted locations of one endpoint, by scheme.
|
|
113
|
+
* @returns The preferred usable location, or null when none is usable.
|
|
114
|
+
*/
|
|
115
|
+
function preferredLocation(urls) {
|
|
116
|
+
for (const url of [urls[Schemes.https], urls[Schemes.http]])
|
|
117
|
+
if (url && isRequestableHttpUrl(url))
|
|
118
|
+
return url;
|
|
119
|
+
// A TCP location without a valid port is refused by the TCP messenger; it is no location here.
|
|
120
|
+
const tcp = urls[Schemes.tcp];
|
|
121
|
+
return tcp && messengerUrl({ tcp }) ? tcp : null;
|
|
122
|
+
}
|
|
59
123
|
/**
|
|
60
124
|
* Resolve the actual transport URL for one query destination AID.
|
|
61
125
|
*
|
|
62
126
|
* An explicit witness uses its own location records. Ordinary queries use only
|
|
63
127
|
* the selected controller, agent or witness endpoint; mailbox providers are not
|
|
64
|
-
* query attesters. Missing
|
|
128
|
+
* query attesters. Missing, unsupported or unusable locations do not promote another endpoint.
|
|
65
129
|
*
|
|
66
130
|
* @param hab Local habitat used to construct/sign this output; stores remain borrowed.
|
|
67
131
|
* @param queriedPre Subject AID whose state is requested.
|
|
@@ -70,18 +134,27 @@ function soleHab(hby) {
|
|
|
70
134
|
* @returns Preferred endpoint URL, or null if no permitted route exists.
|
|
71
135
|
*/
|
|
72
136
|
function resolveQueryDestinationUrl(hab, queriedPre, destination, { explicitWitness = false, } = {}) {
|
|
73
|
-
if (explicitWitness)
|
|
74
|
-
|
|
75
|
-
return urls[Schemes.https] ?? urls[Schemes.http] ?? urls[Schemes.tcp] ?? null;
|
|
76
|
-
}
|
|
137
|
+
if (explicitWitness)
|
|
138
|
+
return preferredLocation(hab.fetchUrls(destination));
|
|
77
139
|
const ends = hab.endsFor(queriedPre);
|
|
78
140
|
for (const role of [Roles.controller, Roles.agent, Roles.witness]) {
|
|
79
141
|
const urls = ends[role]?.[destination];
|
|
80
142
|
if (urls)
|
|
81
|
-
return urls
|
|
143
|
+
return preferredLocation(urls);
|
|
82
144
|
}
|
|
83
145
|
return null;
|
|
84
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* The attesters of an ordinary query for `pre` that can be sent to now: those {@link queryAttesters} selects that also
|
|
149
|
+
* have an accepted location.
|
|
150
|
+
*
|
|
151
|
+
* @param hab Local habitat whose accepted-state store is read.
|
|
152
|
+
* @param pre Subject AID whose accepted endpoint roles and locations are consulted.
|
|
153
|
+
* @returns Addressable attester AIDs of the first eligible role; empty when none can be reached now.
|
|
154
|
+
*/
|
|
155
|
+
export function addressableAttesters(hab, pre) {
|
|
156
|
+
return queryAttesters(hab, pre).filter((aid) => resolveQueryDestinationUrl(hab, pre, aid) !== null);
|
|
157
|
+
}
|
|
85
158
|
/**
|
|
86
159
|
* KERIpy-shaped query sender, independent from semantic query completion.
|
|
87
160
|
*
|
|
@@ -109,9 +182,10 @@ export class WitnessInquisitor {
|
|
|
109
182
|
* @param protocol Borrowed same-database processor for incoming query replies.
|
|
110
183
|
* @param http Borrowed HTTP implementation selected by composition.
|
|
111
184
|
* @param clock Borrowed clock for transport deadlines; times are milliseconds.
|
|
185
|
+
* @param relay The agent every query goes to; null selects attesters from accepted endpoint roles.
|
|
112
186
|
* @param hab Optional default local signer; null requires an unambiguous sole habitat.
|
|
113
187
|
*/
|
|
114
|
-
constructor(hby, protocol, http, clock, hab = null) {
|
|
188
|
+
constructor(hby, protocol, http, clock, relay, hab = null) {
|
|
115
189
|
/** Borrowed local signers and accepted-state stores. */
|
|
116
190
|
Object.defineProperty(this, "hby", {
|
|
117
191
|
enumerable: true,
|
|
@@ -182,12 +256,20 @@ export class WitnessInquisitor {
|
|
|
182
256
|
writable: true,
|
|
183
257
|
value: void 0
|
|
184
258
|
});
|
|
259
|
+
/** The agent every query is addressed and sent to (an edge); null selects ordinary attesters. */
|
|
260
|
+
Object.defineProperty(this, "relay", {
|
|
261
|
+
enumerable: true,
|
|
262
|
+
configurable: true,
|
|
263
|
+
writable: true,
|
|
264
|
+
value: void 0
|
|
265
|
+
});
|
|
185
266
|
if (protocol.kvy.db !== hby.db)
|
|
186
267
|
throw new RangeError("Query protocol must use the same database");
|
|
187
268
|
this.hby = hby;
|
|
188
269
|
this.protocol = protocol;
|
|
189
270
|
this.http = http;
|
|
190
271
|
this.clock = clock;
|
|
272
|
+
this.relay = relay;
|
|
191
273
|
this.hab = hab;
|
|
192
274
|
}
|
|
193
275
|
/**
|
|
@@ -198,6 +280,17 @@ export class WitnessInquisitor {
|
|
|
198
280
|
configure({ hab = null } = {}) {
|
|
199
281
|
this.hab = hab;
|
|
200
282
|
}
|
|
283
|
+
/** The explicitly configured default signer, or null when the sole local habitat is used. */
|
|
284
|
+
get defaultSigner() {
|
|
285
|
+
return this.hab?.pre ?? null;
|
|
286
|
+
}
|
|
287
|
+
/** Whether a queued request names `signer` as its explicit signer. */
|
|
288
|
+
hasRequestsSignedBy(signer) {
|
|
289
|
+
for (const request of this.requests)
|
|
290
|
+
if (request.signer === signer)
|
|
291
|
+
return true;
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
201
294
|
/** Deferred instructions and active sends are this sender's only pending work. */
|
|
202
295
|
hasPendingWork() {
|
|
203
296
|
return !this.requests.empty || this.hasPendingDelivery;
|
|
@@ -215,6 +308,7 @@ export class WitnessInquisitor {
|
|
|
215
308
|
...request,
|
|
216
309
|
...copyQuery(request),
|
|
217
310
|
wits: request.wits ? [...request.wits] : undefined,
|
|
311
|
+
unaddressedPasses: 0,
|
|
218
312
|
});
|
|
219
313
|
}
|
|
220
314
|
/**
|
|
@@ -232,6 +326,27 @@ export class WitnessInquisitor {
|
|
|
232
326
|
const selected = { ...request, signer: request.signer ?? hab?.pre };
|
|
233
327
|
this.enqueue(selected);
|
|
234
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* Admit a routed query cue unless an identical request is already queued: same subject, route, filters, signer,
|
|
331
|
+
* attester and witness overrides, with the signer resolved as {@link enqueueCue} resolves it. A relaying host's cue
|
|
332
|
+
* router uses this, so the queries of the many edges it serves about one subject leave one request queued; a request
|
|
333
|
+
* already taken for delivery is no longer queued, so a later cue queues the next one.
|
|
334
|
+
*
|
|
335
|
+
* @param cue Typed query cue; missing route/subject produces no request.
|
|
336
|
+
* @param hab Optional local signer hint when the cue has no explicit signer.
|
|
337
|
+
*/
|
|
338
|
+
enqueueCueOnce(cue, hab) {
|
|
339
|
+
if (this.closed)
|
|
340
|
+
throw new Error("Query sender is closed");
|
|
341
|
+
if (!cue.route || !cue.pre)
|
|
342
|
+
return;
|
|
343
|
+
const { kin: _, ...request } = cue;
|
|
344
|
+
const key = requestKey({ ...request, signer: request.signer ?? hab?.pre });
|
|
345
|
+
for (const queued of this.requests)
|
|
346
|
+
if (requestKey(queued) === key)
|
|
347
|
+
return;
|
|
348
|
+
this.enqueueCue(cue, hab);
|
|
349
|
+
}
|
|
235
350
|
/** Include actual query I/O in convergence; pending instructions have their own queue. */
|
|
236
351
|
get hasPendingDelivery() {
|
|
237
352
|
return this.delivering;
|
|
@@ -282,7 +397,16 @@ export class WitnessInquisitor {
|
|
|
282
397
|
const packet = self.prepareRequest(request);
|
|
283
398
|
self.requests.pull();
|
|
284
399
|
if (!packet) {
|
|
285
|
-
|
|
400
|
+
// A signer that cannot sign yet, or a relay not yet usable, is local state that waits; a ready signer with no
|
|
401
|
+
// reachable attester counts toward the bound.
|
|
402
|
+
if (!self.relay && self.configuredHab(request.signer)?.canSign())
|
|
403
|
+
request.unaddressedPasses++;
|
|
404
|
+
if (request.unaddressedPasses >= UNADDRESSED_QUERY_PASS_LIMIT) {
|
|
405
|
+
consoleLogger.warn(`Dropping ${request.route} query for ${request.pre}: no reachable attester after ${request.unaddressedPasses} passes.`);
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
self.requests.append(request);
|
|
409
|
+
}
|
|
286
410
|
continue;
|
|
287
411
|
}
|
|
288
412
|
active.signal.throwIfAborted();
|
|
@@ -369,51 +493,73 @@ export class WitnessInquisitor {
|
|
|
369
493
|
* Resolve/sign one selected query and introduction immediately before its attempt.
|
|
370
494
|
*
|
|
371
495
|
* @param request Deferred unsigned request; nested query values must remain immutable.
|
|
372
|
-
*
|
|
373
|
-
*
|
|
496
|
+
* The attester is chosen at random among the eligible ones (the explicit `src`, the `wits` overrides, or the first
|
|
497
|
+
* eligible endpoint role) that have an accepted location. An attester without one is never promoted to another
|
|
498
|
+
* role; when none of the eligible attesters can be reached the request is unresolved, like a signer that cannot sign
|
|
499
|
+
* yet, so no endpoint condition ends the delivery loop or fails a caller's pass.
|
|
500
|
+
*
|
|
501
|
+
* @param request Deferred unsigned request; nested query values must remain immutable.
|
|
502
|
+
* @returns Prepared packet, or null when signer/attester evidence is unresolved, no eligible attester has an
|
|
503
|
+
* accepted location, or the signer cannot sign yet.
|
|
374
504
|
*/
|
|
375
505
|
prepareRequest(request) {
|
|
376
506
|
const hab = this.configuredHab(request.signer);
|
|
377
|
-
|
|
507
|
+
// A signer that cannot sign yet leaves the request unresolved: it goes to the tail, and the next pass tries again.
|
|
508
|
+
if (!hab || !hab.canSign())
|
|
378
509
|
return null;
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
510
|
+
if (this.relay)
|
|
511
|
+
return this.prepareRelayRequest(hab, request, this.relay);
|
|
512
|
+
const eligible = request.src
|
|
513
|
+
? [request.src]
|
|
514
|
+
: this.attestersFor(request.pre, { signer: hab.pre, wits: request.wits });
|
|
515
|
+
const reachable = eligible.flatMap((destination) => {
|
|
516
|
+
const url = resolveQueryDestinationUrl(hab, request.pre, destination, {
|
|
517
|
+
explicitWitness: request.wits?.includes(destination) ?? false,
|
|
518
|
+
});
|
|
519
|
+
// A TCP location on a host without a TCP dialer cannot be sent to: it is unreachable, not a fault.
|
|
520
|
+
return url && (this.http.tcp || !url.startsWith("tcp:")) ? [{ destination, url }] : [];
|
|
385
521
|
});
|
|
386
|
-
|
|
387
|
-
|
|
522
|
+
const selected = reachable[Math.floor(Math.random() * reachable.length)];
|
|
523
|
+
if (!selected)
|
|
524
|
+
return null;
|
|
525
|
+
const { destination, url } = selected;
|
|
388
526
|
const message = hab.query(request.pre, destination, copyQuery(request));
|
|
389
527
|
const intro = introduce(hab, destination);
|
|
390
528
|
return { url, body: concatBytes(intro, message), destination };
|
|
391
529
|
}
|
|
392
530
|
/**
|
|
393
|
-
*
|
|
531
|
+
* Address one query to the relay and sign it for the relay's location. The relay must have an accepted location
|
|
532
|
+
* and the signer must have authorized it as mailbox (where the answer is stored); until then the request stays
|
|
533
|
+
* unresolved and is tried again on a later pass, as for a signer that cannot sign yet.
|
|
534
|
+
*
|
|
535
|
+
* @param hab Local signing habitat.
|
|
536
|
+
* @param request Deferred unsigned request; its `src` and `wits` are not consulted.
|
|
537
|
+
* @param relay The configured relay agent, which is the attester.
|
|
538
|
+
* @returns Prepared packet for the relay, or null while {@link relayRefusal} refuses the relay for this signer.
|
|
539
|
+
*/
|
|
540
|
+
prepareRelayRequest(hab, request, relay) {
|
|
541
|
+
if (relayRefusal(this.hby, relay, hab.pre))
|
|
542
|
+
return null;
|
|
543
|
+
const endpoint = relayEndpoint(this.hby, relay);
|
|
544
|
+
const message = hab.query(request.pre, relay.aid, copyQuery(request));
|
|
545
|
+
return { url: endpoint.url, body: concatBytes(introduce(hab, relay.aid), message), destination: relay.aid };
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Return the first eligible role’s attester IDs; preparation chooses one randomly. With a relay, the relay is the
|
|
549
|
+
* only attester.
|
|
394
550
|
*
|
|
395
551
|
* @param pre Subject AID whose accepted endpoint roles are consulted.
|
|
396
552
|
* @param options Optional local signer AID and remote witness/attester overrides; neither selects a transport implementation.
|
|
397
553
|
* @returns Eligible attester AIDs, or an empty array for an unknown subject or unresolved signer/role.
|
|
398
554
|
*/
|
|
399
555
|
attestersFor(pre, { signer, wits } = {}) {
|
|
556
|
+
if (this.relay)
|
|
557
|
+
return [this.relay.aid];
|
|
400
558
|
if (wits && wits.length > 0) {
|
|
401
559
|
// Explicit watcher/witness overrides outrank endpoint-role lookup.
|
|
402
560
|
return [...wits];
|
|
403
561
|
}
|
|
404
562
|
const hab = this.configuredHab(signer);
|
|
405
|
-
|
|
406
|
-
return [];
|
|
407
|
-
const ends = hab.endsFor(pre);
|
|
408
|
-
for (const role of QUERY_ROLE_PRIORITY) {
|
|
409
|
-
const roleEnds = ends[role];
|
|
410
|
-
if (!roleEnds) {
|
|
411
|
-
continue;
|
|
412
|
-
}
|
|
413
|
-
const eids = Object.keys(roleEnds);
|
|
414
|
-
if (eids.length > 0)
|
|
415
|
-
return eids;
|
|
416
|
-
}
|
|
417
|
-
return [];
|
|
563
|
+
return hab ? queryAttesters(hab, pre) : [];
|
|
418
564
|
}
|
|
419
565
|
}
|
|
@@ -8,7 +8,6 @@ import { DatabaseNotOpenError } from "../../core/errors.js";
|
|
|
8
8
|
import { Kevery } from "../../core/kel/eventing.js";
|
|
9
9
|
import { Kramer } from "../../core/mailbox/kraming.js";
|
|
10
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";
|
|
12
11
|
import { Revery } from "../../core/routing.js";
|
|
13
12
|
import { openOwner } from "../../db/core/store-owner.js";
|
|
14
13
|
import { Mailboxer } from "../../db/mailbox/mailboxing.js";
|
|
@@ -20,12 +19,12 @@ import { Authenticator } from "../bootstrap/authenticating.js";
|
|
|
20
19
|
import { loadOobiHandlers, Oobiery, oobiTerminalState } from "../bootstrap/oobiery.js";
|
|
21
20
|
import { publishPendingTel } from "../credentials/tel-publishing.js";
|
|
22
21
|
import { Poster } from "../delivery/forwarding.js";
|
|
22
|
+
import { relayEndpoint, relayOnlyHttpClient } from "../delivery/relaying.js";
|
|
23
23
|
import { ReplyStreams } from "../delivery/reply-streams.js";
|
|
24
24
|
import { Respondant } from "../delivery/respondant.js";
|
|
25
25
|
import { Exchanger, RouteRefuser } from "../exchanges/exchanging.js";
|
|
26
26
|
import { loadChallengeHandlers } from "../identity/challenging.js";
|
|
27
27
|
import { Anchorer, loadDelegationHandlers } from "../identity/delegating.js";
|
|
28
|
-
import { SignerNotHeldError } from "../identity/keeping.js";
|
|
29
28
|
import { loadIpexHandlers } from "../ipex/ipexing.js";
|
|
30
29
|
import { ForwardHandler } from "../mailbox/forward-handler.js";
|
|
31
30
|
import { KEL_PUBLISHER_PACING, KelPublisher, kelPublisherDo } from "../mailbox/kel-publisher.js";
|
|
@@ -47,7 +46,6 @@ import { cueDo } from "./cue-runtime.js";
|
|
|
47
46
|
import { doEveryOnWrite, PROTOCOL_PACING } from "./doing.js";
|
|
48
47
|
import { IpexAuxiliaries } from "./ipex-auxiliaries.js";
|
|
49
48
|
import { composeOwners, operationOwnersDo, OWNER_PACING, } from "./operation-owners.js";
|
|
50
|
-
import { SignerConditions } from "./signer-conditions.js";
|
|
51
49
|
import { signalerChangeSink } from "./workflow-contract.js";
|
|
52
50
|
import { observeUntil } from "./workflow-contract.js";
|
|
53
51
|
/**
|
|
@@ -67,12 +65,18 @@ import { observeUntil } from "./workflow-contract.js";
|
|
|
67
65
|
* @throws Dependency mismatch/acquisition errors propagate after owned resource cleanup.
|
|
68
66
|
*/
|
|
69
67
|
export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
68
|
+
// An edge reaches only its relay: every component below, and `runtime.http`, gets the guarded client.
|
|
69
|
+
if (options.relay)
|
|
70
|
+
http = relayOnlyHttpClient(http, hby, options.relay);
|
|
70
71
|
const injectedSignaler = options.signaler ?? options.notifier?.signaler;
|
|
71
72
|
if ((options.notifier && options.notifier.signator !== hby.signator)
|
|
72
73
|
|| (options.noter && options.notifier && options.noter !== options.notifier.noter)
|
|
73
74
|
|| (options.signaler && options.notifier && options.signaler !== options.notifier.signaler)) {
|
|
74
75
|
throw new RangeError("AgentRuntime notification services require its exact Signator, Noter and Signaler");
|
|
75
76
|
}
|
|
77
|
+
if (options.relaying && !options.mailboxer && !options.enableMailboxStore) {
|
|
78
|
+
throw new RangeError("Relaying requires a mailbox store for /fwd intake");
|
|
79
|
+
}
|
|
76
80
|
const mailboxer = options.mailboxer
|
|
77
81
|
?? (options.enableMailboxStore ? (yield* openRuntimeMailboxer(hby)) : null);
|
|
78
82
|
const ownsMailboxer = options.mailboxer === undefined && mailboxer !== null;
|
|
@@ -131,7 +135,7 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
|
131
135
|
const kramer = options.kram ? new Kramer(hby.db, { config: options.kram, cues: protocolCues, now }) : undefined;
|
|
132
136
|
const kvy = new Kevery(hby.db, { cues: protocolCues, rvy: revery, messagePolicy: options.messagePolicy, kramer });
|
|
133
137
|
const exc = new Exchanger(hby, { cues: protocolCues, now });
|
|
134
|
-
const registry = acdc ? new RegistryObserver(hby.db, acdc.store) : null;
|
|
138
|
+
const registry = acdc ? new RegistryObserver(hby.db, acdc.store, protocolCues) : null;
|
|
135
139
|
// Every runtime with a v2 registry store owns the per-identifier DH and Unblind owners: one dispatch path.
|
|
136
140
|
const ipex = registry
|
|
137
141
|
? yield* resource(function* (provide) {
|
|
@@ -146,11 +150,11 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
|
146
150
|
})
|
|
147
151
|
: null;
|
|
148
152
|
const replies = new QueryReplies(cues);
|
|
149
|
-
const protocol = new ProtocolProcessor(kvy, revery, exc, vdr?.tvy ?? null, vdr?.vry ?? null, registry, protocolCues, cues, replies, ipex ?? undefined);
|
|
153
|
+
const protocol = new ProtocolProcessor(kvy, revery, exc, vdr?.tvy ?? null, vdr?.vry ?? null, registry, protocolCues, cues, replies, ipex ?? undefined, options.relaying === true);
|
|
150
154
|
const reactor = new Reactor(protocol);
|
|
151
155
|
loadChallengeHandlers(hby.db, exc);
|
|
152
156
|
loadDelegationHandlers(hby, exc, notifier);
|
|
153
|
-
loadOobiHandlers(hby, exc, notifier);
|
|
157
|
+
loadOobiHandlers(hby, exc, notifier, options.relaying === true);
|
|
154
158
|
const mux = loadMultisigHandlers(hby, exc, { notifier, registry: protocol.registry, messageKevery: protocol.kvy });
|
|
155
159
|
loadIpexHandlers(hby, exc, {
|
|
156
160
|
notifier,
|
|
@@ -158,8 +162,9 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
|
158
162
|
grantWalk: options.grantWalk,
|
|
159
163
|
});
|
|
160
164
|
// Construction adopts stored copies an earlier handler-less Exchanger left unescrowed.
|
|
165
|
+
const changes = options.operationStores?.changes ?? (signaler ? signalerChangeSink(signaler) : undefined);
|
|
161
166
|
const registryRoot = options.registryRoots !== "refuse" && acdc
|
|
162
|
-
? new RegistryRoot(hby, acdc, notifier,
|
|
167
|
+
? new RegistryRoot(hby, acdc, notifier, changes)
|
|
163
168
|
: null;
|
|
164
169
|
if (registryRoot)
|
|
165
170
|
exc.addHandler(registryRoot);
|
|
@@ -175,7 +180,7 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
|
175
180
|
}
|
|
176
181
|
});
|
|
177
182
|
const postman = yield* resource(function* (provide) {
|
|
178
|
-
const postman = new Poster(hby, mailboxer, protocol, http, clock);
|
|
183
|
+
const postman = new Poster(hby, mailboxer, protocol, http, clock, options.relay ?? null);
|
|
179
184
|
try {
|
|
180
185
|
yield* provide(postman);
|
|
181
186
|
}
|
|
@@ -185,7 +190,7 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
|
185
190
|
});
|
|
186
191
|
const respondant = new Respondant(hby, postman);
|
|
187
192
|
if (mailboxer) {
|
|
188
|
-
exc.addHandler(new ForwardHandler(mailboxDirector));
|
|
193
|
+
exc.addHandler(new ForwardHandler(mailboxDirector, reactor, options.relaying ? postman : null));
|
|
189
194
|
}
|
|
190
195
|
for (const route of exc.routes.keys()) {
|
|
191
196
|
if (route === ForwardHandler.resource) {
|
|
@@ -206,20 +211,7 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
|
206
211
|
changes: signaler ? signalerChangeSink(signaler) : undefined,
|
|
207
212
|
retry: options.kelPublishRetry,
|
|
208
213
|
});
|
|
209
|
-
const
|
|
210
|
-
const mailboxPoller = new MailboxPoller(hby, mailboxDirector, http, clock, {
|
|
211
|
-
signerConditions,
|
|
212
|
-
onPolled: (pre, mailbox) => kelPublisher.prompt(pre, mailbox),
|
|
213
|
-
onUnauthorized: (pre, mailbox) => kelPublisher.repair(pre, mailbox),
|
|
214
|
-
timeouts: options.mailboxPolling,
|
|
215
|
-
});
|
|
216
|
-
// A mailbox role accepted from a reply (a group member's approved add, an OOBI) is acted on at the next tock.
|
|
217
|
-
revery.onEndRole = (cid, role) => {
|
|
218
|
-
if (role !== Roles.mailbox)
|
|
219
|
-
return;
|
|
220
|
-
kelPublisher.prompt(cid);
|
|
221
|
-
mailboxPoller.prompt(cid);
|
|
222
|
-
};
|
|
214
|
+
const mailboxPoller = new MailboxPoller(hby, mailboxDirector, http, clock, options.relay ?? null, { polls: kelPublisher.polls, timeouts: options.mailboxPolling });
|
|
223
215
|
for (const topic of [
|
|
224
216
|
DELEGATE_MAILBOX_TOPIC,
|
|
225
217
|
CREDENTIAL_MAILBOX_TOPIC,
|
|
@@ -230,7 +222,7 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
|
230
222
|
mailboxDirector.registerTopic(topic);
|
|
231
223
|
}
|
|
232
224
|
const querying = yield* resource(function* (provide) {
|
|
233
|
-
const inquisitor = new WitnessInquisitor(hby, protocol, http, clock);
|
|
225
|
+
const inquisitor = new WitnessInquisitor(hby, protocol, http, clock, options.relay ?? null);
|
|
234
226
|
try {
|
|
235
227
|
yield* provide(inquisitor);
|
|
236
228
|
}
|
|
@@ -239,17 +231,9 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
|
239
231
|
}
|
|
240
232
|
});
|
|
241
233
|
const delegating = new Anchorer(hby, postman, querying, protocol, http, clock);
|
|
242
|
-
//
|
|
243
|
-
const
|
|
244
|
-
const counselor = new Counselor(hby, {
|
|
245
|
-
receipt: (pre, options) => groupReceiptor.receipt(pre, { ...options, allowTcp: true }),
|
|
246
|
-
get: (pre, options) => groupReceiptor.get(pre, options),
|
|
247
|
-
}, clock, signaler ? signalerChangeSink(signaler) : undefined, { anchorer: delegating, querying }, {
|
|
248
|
-
rotated: (cue) => {
|
|
249
|
-
kelPublisher.rotated.push(cue);
|
|
250
|
-
owned?.rootReplicator?.prompt(cue.pre);
|
|
251
|
-
},
|
|
252
|
-
}, options.counselorReceiptRetry, groupEventForwarding(hby, postman));
|
|
234
|
+
// Only a runtime with operations owners and a registry root has a root replicator to drain this deck.
|
|
235
|
+
const groupChanges = registryRoot && ipex ? new Deck() : undefined;
|
|
236
|
+
const counselor = new Counselor(hby, new Receiptor(hby, protocol, http, clock), clock, signaler ? signalerChangeSink(signaler) : undefined, { anchorer: delegating, querying }, kelPublisher.rotated, groupChanges, options.counselorReceiptRetry, groupEventForwarding(hby, postman));
|
|
253
237
|
const owned = acdc && ipex
|
|
254
238
|
? composeOwners({
|
|
255
239
|
hby,
|
|
@@ -264,21 +248,26 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
|
264
248
|
registryRoot,
|
|
265
249
|
mux,
|
|
266
250
|
counselor,
|
|
251
|
+
groupChanges,
|
|
267
252
|
retry: options.operationRetry,
|
|
268
253
|
queryResendMs: options.issuanceQueryResendMs,
|
|
269
254
|
changes: signaler ? signalerChangeSink(signaler) : undefined,
|
|
270
255
|
}, options.operationStores)
|
|
271
256
|
: null;
|
|
272
|
-
const oobiery = new Oobiery(hby, protocol, revery, http, cues);
|
|
257
|
+
const oobiery = new Oobiery(hby, protocol, revery, http, cues, options.relay ? { relay: options.relay, postman, clock } : null);
|
|
273
258
|
oobiery.registerReplyRoutes(revery.rtr);
|
|
259
|
+
if (options.relay && !relayEndpoint(hby, options.relay))
|
|
260
|
+
oobiery.resolve(options.relay.oobi);
|
|
274
261
|
const authenticator = new Authenticator(hby, http);
|
|
275
262
|
return {
|
|
276
263
|
hby,
|
|
277
264
|
mailboxer,
|
|
265
|
+
relaying: options.relaying === true,
|
|
278
266
|
noter,
|
|
279
267
|
notifier,
|
|
280
268
|
signaler,
|
|
281
269
|
cues,
|
|
270
|
+
changes: changes ?? null,
|
|
282
271
|
reactor,
|
|
283
272
|
protocol,
|
|
284
273
|
replies,
|
|
@@ -296,7 +285,6 @@ export function* createAgentRuntime(hby, http, clock, options = {}) {
|
|
|
296
285
|
delegating,
|
|
297
286
|
counselor,
|
|
298
287
|
kelPublisher,
|
|
299
|
-
signerConditions,
|
|
300
288
|
ownerPacing: options.ownerPacing ?? OWNER_PACING,
|
|
301
289
|
publisherPacing: options.publisherPacing ?? KEL_PUBLISHER_PACING,
|
|
302
290
|
protocolPacing: options.protocolPacing ?? PROTOCOL_PACING,
|
|
@@ -618,6 +606,11 @@ export { runtimeTurn } from "./runtime-turn.js";
|
|
|
618
606
|
* delegation and ordinary query sending. The finalizer halts children in reverse
|
|
619
607
|
* order; store ownership remains with the composition scope.
|
|
620
608
|
*
|
|
609
|
+
* Each loop is a plain spawned fixed-tock doer. A loop that signs for a local habitat reads `Hab.canSign()` on its
|
|
610
|
+
* tock and skips a habitat that cannot sign yet (a store opened without its signer); a later `Manager.hold` lets
|
|
611
|
+
* that habitat act on the next tock. A `SignerNotHeldError` that still escapes a loop is a fault: the loop ends
|
|
612
|
+
* and the failure ends this operation.
|
|
613
|
+
*
|
|
621
614
|
* @param runtime Borrowed composed runtime; caller owns its worker and store lifetime.
|
|
622
615
|
* @param options Optional default query/cue signer, remote pollMailbox switch
|
|
623
616
|
* (default true) and command-owned queryCues Deck. Wire queryCues before starting
|
|
@@ -628,28 +621,25 @@ export function* runAgentRuntime(runtime, options = {}) {
|
|
|
628
621
|
runtime.querying.configure({ hab: options.hab });
|
|
629
622
|
const pacing = runtime.protocolPacing;
|
|
630
623
|
const telReceiptor = runtime.vdr ? new Receiptor(runtime.hby, runtime.protocol, runtime.http, runtime.clock) : null;
|
|
631
|
-
// A loop that needs a signer the host released waits for it; it never ends the runtime (see `surviving`).
|
|
632
|
-
const alive = (loop, make) => spawn(() => surviving(runtime, loop, make));
|
|
633
|
-
const stopHoldWatch = runtime.hby.mgr.onHold(() => runtime.signerConditions.held());
|
|
634
624
|
const tasks = [
|
|
635
|
-
yield*
|
|
636
|
-
yield*
|
|
625
|
+
yield* spawn(() => runtime.querying.deliverDo(pacing.tockMs)),
|
|
626
|
+
yield* spawn(() => runtime.postman.deliverDo(pacing.tockMs)),
|
|
637
627
|
...(runtime.vdr && telReceiptor
|
|
638
628
|
? [
|
|
639
|
-
yield*
|
|
629
|
+
yield* spawn(() => doEveryOnWrite(runtime.clock, pacing, {
|
|
640
630
|
get writeActivity() {
|
|
641
631
|
return runtime.hby.db.writeActivity + runtime.vdr.publication.reger.writeActivity;
|
|
642
632
|
},
|
|
643
633
|
}, () => publishPendingTel(runtime.hby, runtime.vdr.publication, telReceiptor, runtime.http, runtime.clock))),
|
|
644
634
|
]
|
|
645
635
|
: []),
|
|
646
|
-
yield*
|
|
647
|
-
yield*
|
|
648
|
-
yield*
|
|
649
|
-
yield*
|
|
636
|
+
yield* spawn(() => cueDo(runtime, options, pacing)),
|
|
637
|
+
yield* spawn(() => runtime.protocol.escrowDo(runtime.clock, pacing)),
|
|
638
|
+
yield* spawn(() => runtime.oobiery.oobiDo(runtime.clock, pacing)),
|
|
639
|
+
yield* spawn(() => runtime.authenticator.authDo(runtime.clock, pacing)),
|
|
650
640
|
...(runtime.signaler
|
|
651
641
|
? [
|
|
652
|
-
yield*
|
|
642
|
+
yield* spawn(() => runtime.signaler.signalDo(runtime.clock, pacing)),
|
|
653
643
|
]
|
|
654
644
|
: []),
|
|
655
645
|
...(options.pollMailbox ?? true
|
|
@@ -659,12 +649,12 @@ export function* runAgentRuntime(runtime, options = {}) {
|
|
|
659
649
|
}),
|
|
660
650
|
]
|
|
661
651
|
: []),
|
|
662
|
-
yield*
|
|
663
|
-
yield*
|
|
664
|
-
yield*
|
|
652
|
+
yield* spawn(() => doEveryOnWrite(runtime.clock, pacing, runtime.hby.db, () => runtime.delegating.processAllOnce())),
|
|
653
|
+
yield* spawn(() => doEveryOnWrite(runtime.clock, pacing, runtime.hby.db, () => runtime.counselor.processOnce(), () => runtime.counselor.holdsForwards)),
|
|
654
|
+
yield* spawn(() => kelPublisherDo(runtime.kelPublisher, runtime.clock, runtime.publisherPacing)),
|
|
665
655
|
...(runtime.operations && runtime.ipex
|
|
666
656
|
? [
|
|
667
|
-
yield*
|
|
657
|
+
yield* spawn(() => operationOwnersDo({
|
|
668
658
|
operations: runtime.operations,
|
|
669
659
|
rootReplicator: runtime.rootReplicator,
|
|
670
660
|
ipex: runtime.ipex,
|
|
@@ -677,29 +667,8 @@ export function* runAgentRuntime(runtime, options = {}) {
|
|
|
677
667
|
return yield* suspend();
|
|
678
668
|
}
|
|
679
669
|
finally {
|
|
680
|
-
stopHoldWatch();
|
|
681
670
|
for (const task of tasks.reverse()) {
|
|
682
671
|
yield* task.halt();
|
|
683
672
|
}
|
|
684
673
|
}
|
|
685
674
|
}
|
|
686
|
-
/** How long a loop waits for a held signer before trying again, in milliseconds. */
|
|
687
|
-
const SIGNER_RETRY_MS = 1_000;
|
|
688
|
-
/**
|
|
689
|
-
* Run a background loop so that a signer the host released does not end the runtime: the loop's
|
|
690
|
-
* `SignerNotHeldError` is recorded in `runtime.signerConditions`, the loop waits for a signer to be held (or a
|
|
691
|
-
* second) and starts again. Every other failure still ends it.
|
|
692
|
-
*/
|
|
693
|
-
function* surviving(runtime, loop, make) {
|
|
694
|
-
while (true) {
|
|
695
|
-
try {
|
|
696
|
-
return yield* make();
|
|
697
|
-
}
|
|
698
|
-
catch (error) {
|
|
699
|
-
if (!(error instanceof SignerNotHeldError))
|
|
700
|
-
throw error;
|
|
701
|
-
runtime.signerConditions.report(`runtime:${loop}`, error.pub, runtime.clock.now());
|
|
702
|
-
yield* runtime.signerConditions.waitForHold(runtime.clock, SIGNER_RETRY_MS);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
}
|