keri-ts 2.2.3 → 2.2.5
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/registering.js +19 -0
- package/esm/keri/npm/src/acdc/salting.js +4 -0
- package/esm/keri/npm/src/app/bootstrap/authenticating.js +34 -12
- package/esm/keri/npm/src/app/bootstrap/oobiery.js +365 -32
- 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 +188 -47
- 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 +109 -23
- package/esm/keri/npm/src/app/ipex/ipex-discloser.js +36 -22
- 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 +131 -35
- 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 +16 -3
- 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 +75 -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 +62 -27
- 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 +190 -40
- package/esm/keri/npm/src/app/runtime/agent-runtime.js +46 -73
- package/esm/keri/npm/src/app/runtime/cue-runtime.js +45 -5
- package/esm/keri/npm/src/app/runtime/doing.js +25 -0
- 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 +8 -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/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/lmdber.js +25 -6
- package/esm/keri/npm/src/db/core/memstore.js +4 -0
- package/esm/keri/npm/src/db/core/store-owner.js +4 -0
- 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 +28 -19
- 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/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/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 +75 -7
- 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 +48 -6
- package/types/app/ipex/group-issuance.d.ts.map +1 -1
- package/types/app/ipex/ipex-discloser.d.ts +14 -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 +35 -11
- 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 +4 -1
- 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 +34 -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 +31 -6
- 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 +57 -6
- 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/doing.d.ts +17 -0
- package/types/app/runtime/doing.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 +6 -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/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/dber.d.ts +5 -0
- package/types/db/core/dber.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/lmdber.d.ts +6 -0
- package/types/db/core/lmdber.d.ts.map +1 -1
- package/types/db/core/memstore.d.ts +2 -0
- package/types/db/core/memstore.d.ts.map +1 -1
- package/types/db/core/store-owner.d.ts +2 -0
- package/types/db/core/store-owner.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.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,25 +7,56 @@
|
|
|
7
7
|
* do not select a stored framing preference or acquire workers, stores or queues.
|
|
8
8
|
*/
|
|
9
9
|
import { ValidationError } from "../../core/errors.js";
|
|
10
|
+
import { readUrl } from "../../core/wire-fields.js";
|
|
11
|
+
import { isRequestableHttpUrl } from "./http-client.js";
|
|
10
12
|
import { HTTPMessenger } from "./http-messenger.js";
|
|
11
13
|
import { HTTPStreamMessenger } from "./http-stream-messenger.js";
|
|
12
14
|
import { requireTcpDialer } from "./tcp-dialer.js";
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Choose HTTPS, HTTP, then TCP, refusing before I/O what no messenger can use: an unparseable URL, a scheme other than
|
|
17
|
+
* the advertised one, an HTTP(S) URL the HTTP client refuses ({@link isRequestableHttpUrl}: embedded credentials), or
|
|
18
|
+
* a TCP URL without a valid port. A refused higher-priority URL does not fall through to another transport.
|
|
19
|
+
*
|
|
20
|
+
* @param urls Resolved endpoints, keyed by their advertised scheme.
|
|
21
|
+
* @returns The selection, never a throw.
|
|
22
|
+
*/
|
|
23
|
+
function selectEndpoint(urls) {
|
|
15
24
|
for (const scheme of ["https", "http", "tcp"]) {
|
|
16
25
|
const value = urls[scheme];
|
|
17
26
|
if (value === undefined)
|
|
18
27
|
continue;
|
|
19
|
-
const endpoint =
|
|
20
|
-
if (endpoint
|
|
21
|
-
|
|
28
|
+
const endpoint = readUrl(value);
|
|
29
|
+
if (!endpoint)
|
|
30
|
+
return { kind: "refused", reason: `Invalid ${scheme} messenger endpoint: ${value}` };
|
|
31
|
+
const usable = scheme === "tcp" ? !endpoint.username && !endpoint.password : isRequestableHttpUrl(value);
|
|
32
|
+
if (endpoint.protocol !== `${scheme}:` || !usable) {
|
|
33
|
+
return { kind: "refused", reason: `Invalid ${scheme} messenger endpoint: ${value}` };
|
|
22
34
|
}
|
|
23
35
|
if (scheme === "tcp" && (!endpoint.port || Number(endpoint.port) < 1 || Number(endpoint.port) > 65535)) {
|
|
24
|
-
|
|
36
|
+
return { kind: "refused", reason: `TCP messenger endpoint requires a valid port: ${value}` };
|
|
25
37
|
}
|
|
26
|
-
return endpoint;
|
|
38
|
+
return { kind: "usable", value, endpoint };
|
|
27
39
|
}
|
|
28
|
-
|
|
40
|
+
return { kind: "refused", reason: "No supported messenger endpoint is available." };
|
|
41
|
+
}
|
|
42
|
+
/** Select the factories' endpoint, refusing an unusable one as a caller error. */
|
|
43
|
+
function endpointFrom(urls) {
|
|
44
|
+
const selection = selectEndpoint(urls);
|
|
45
|
+
if (selection.kind === "refused")
|
|
46
|
+
throw new ValidationError(selection.reason);
|
|
47
|
+
return selection.endpoint;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The URL the messenger factories would use for these endpoints, or null when they would refuse it. A caller holding
|
|
51
|
+
* a location another party advertised reads a refused one as no location, so it fails one delivery as unroutable
|
|
52
|
+
* instead of throwing out of the factory.
|
|
53
|
+
*
|
|
54
|
+
* @param urls Resolved endpoints, keyed by their advertised scheme.
|
|
55
|
+
* @returns The selected URL exactly as advertised, or null.
|
|
56
|
+
*/
|
|
57
|
+
export function messengerUrl(urls) {
|
|
58
|
+
const selection = selectEndpoint(urls);
|
|
59
|
+
return selection.kind === "usable" ? selection.value : null;
|
|
29
60
|
}
|
|
30
61
|
/**
|
|
31
62
|
* Bind ordinary signed-message delivery to the first present HTTPS/HTTP/TCP URL.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { parse } from "cesr-ts";
|
|
3
3
|
import { call, ensure } from "effection";
|
|
4
4
|
import { rethrowCleanupFailure } from "../runtime/abortable.js";
|
|
5
|
+
import { promptForEndRole } from "../runtime/cue-runtime.js";
|
|
5
6
|
import { chunkBytes } from "../transport/byte-source.js";
|
|
6
7
|
/** Return the active wire-message habitat or `null` when selection is ambiguous. */
|
|
7
8
|
function cueHab(runtime, serviceHab) {
|
|
@@ -15,6 +16,7 @@ function cueHab(runtime, serviceHab) {
|
|
|
15
16
|
/**
|
|
16
17
|
* Route one initial witness cue batch, leaving saved key-state facts for the
|
|
17
18
|
* application cue worker and its optional command-owned noticer destination.
|
|
19
|
+
* An accepted mailbox end role prompts the KEL publisher and poller as the cue worker does.
|
|
18
20
|
* Respondant publishes Poster work; this ingress helper never drains Poster
|
|
19
21
|
* network delivery. Query network I/O stays with the independent sender.
|
|
20
22
|
*
|
|
@@ -39,6 +41,11 @@ export function* drainWitnessCues(runtime, serviceHab, cues, { deliver = true }
|
|
|
39
41
|
cues.append(cue);
|
|
40
42
|
continue;
|
|
41
43
|
}
|
|
44
|
+
if (cue.kin === "endRoleSaved") {
|
|
45
|
+
cues.pull();
|
|
46
|
+
promptForEndRole(runtime, cue);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
42
49
|
if (deliver) {
|
|
43
50
|
if (cue.kin === "query") {
|
|
44
51
|
runtime.querying.enqueueCue(cue, hab);
|
|
@@ -8,6 +8,7 @@ import { collectBytes } from "../transport/byte-source.js";
|
|
|
8
8
|
import { buildCesrRequest, CESR_CONTENT_TYPE, KERIPY_CESR_JSON_CONTENT_TYPE } from "../transport/cesr-http.js";
|
|
9
9
|
import { HTTPMessenger } from "../transport/http-messenger.js";
|
|
10
10
|
import { requireTcpDialer } from "../transport/tcp-dialer.js";
|
|
11
|
+
import { TransportError } from "../transport/transport-error.js";
|
|
11
12
|
import { inspectReceiptMessage } from "./receipt-messages.js";
|
|
12
13
|
const WitnessReceiptPollAttempts = 20;
|
|
13
14
|
const WitnessReceiptPollDelayMs = 100;
|
|
@@ -51,6 +52,8 @@ function preferredWitnessTransportUrl(hab, witness) {
|
|
|
51
52
|
return witnessHttpUrl(hab, witness) ?? witnessTcpUrl(hab, witness);
|
|
52
53
|
}
|
|
53
54
|
/**
|
|
55
|
+
* Deliver one message to a witness, reporting remote failure as data.
|
|
56
|
+
*
|
|
54
57
|
* Send via HTTP first; an explicit protocol processor processes same-socket TCP replies.
|
|
55
58
|
* Without a protocol processor TCP reports local transmission only. Actual socket/parser
|
|
56
59
|
* cleanup finishes before this borrowed protocol processor can be released.
|
|
@@ -62,27 +65,51 @@ function preferredWitnessTransportUrl(hab, witness) {
|
|
|
62
65
|
* @param clock Borrowed clock with epoch-millisecond now and millisecond timer delays.
|
|
63
66
|
* @param protocol Optional same-socket reply processor; null selects transmit-only TCP.
|
|
64
67
|
* @param auth Optional HTTP Authorization header value.
|
|
65
|
-
* @
|
|
68
|
+
* @returns `unreachable` when the witness advertises no endpoint, refuses over HTTP, or the connection fails
|
|
69
|
+
* (`TransportError`); the caller decides whether to retry later. Parser, storage, programmer and cleanup
|
|
70
|
+
* failures still throw.
|
|
66
71
|
*/
|
|
67
|
-
export function*
|
|
72
|
+
export function* deliverWitnessMessage(hab, witness, bytes, http, clock, protocol, auth) {
|
|
68
73
|
const url = preferredWitnessTransportUrl(hab, witness);
|
|
69
74
|
if (!url) {
|
|
70
|
-
|
|
75
|
+
return {
|
|
76
|
+
kind: "unreachable",
|
|
77
|
+
witness,
|
|
78
|
+
error: new ValidationError(`Unable to find a valid endpoint for witness ${witness}.`),
|
|
79
|
+
};
|
|
71
80
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
try {
|
|
82
|
+
const parsed = new URL(url);
|
|
83
|
+
if (parsed.protocol === "tcp:") {
|
|
84
|
+
yield* requireTcpDialer(http).messenger(url, clock, protocol).send(bytes, {
|
|
85
|
+
replies: Boolean(protocol),
|
|
86
|
+
local: true,
|
|
87
|
+
});
|
|
88
|
+
return { kind: "delivered" };
|
|
89
|
+
}
|
|
90
|
+
const outcome = yield* new HTTPMessenger(url, http, {
|
|
91
|
+
destination: witness,
|
|
92
|
+
headers: auth ? { Authorization: auth } : undefined,
|
|
93
|
+
}).send(bytes);
|
|
94
|
+
if (outcome.kind === "refuse")
|
|
95
|
+
return { kind: "unreachable", witness, error: outcome.error };
|
|
96
|
+
return { kind: "delivered" };
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (!(error instanceof TransportError))
|
|
100
|
+
throw error;
|
|
101
|
+
return { kind: "unreachable", witness, error };
|
|
79
102
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Send one message to a witness for callers that require delivery.
|
|
106
|
+
*
|
|
107
|
+
* @throws The delivery's remote failure (missing endpoint, peer refusal, transport) and any local failure.
|
|
108
|
+
*/
|
|
109
|
+
export function* sendWitnessMessage(hab, witness, bytes, http, clock, protocol, auth) {
|
|
110
|
+
const delivery = yield* deliverWitnessMessage(hab, witness, bytes, http, clock, protocol, auth);
|
|
111
|
+
if (delivery.kind === "unreachable")
|
|
112
|
+
throw delivery.error;
|
|
86
113
|
}
|
|
87
114
|
function isKeripyContentTypeRejection(status, contentType, responseText) {
|
|
88
115
|
return status === 406
|
|
@@ -8,8 +8,12 @@ import { dgKey } from "../../db/core/keys.js";
|
|
|
8
8
|
import { acceptedEventReplayMessage } from "../identity/habbing.js";
|
|
9
9
|
import { chunkBytes } from "../transport/byte-source.js";
|
|
10
10
|
import { processMessages } from "../transport/message-source.js";
|
|
11
|
-
import {
|
|
11
|
+
import { TransportError } from "../transport/transport-error.js";
|
|
12
|
+
import { deliverWitnessMessage, getWitnessReceiptEndpoint, pollWitnessReceipt, postWitnessReceiptEndpoint, witnessHttpUrl, witnessTcpUrl, } from "./receipt-client.js";
|
|
12
13
|
import { buildDetachedReceiptMessage } from "./receipt-messages.js";
|
|
14
|
+
function incomplete(witness, error) {
|
|
15
|
+
return { kind: "incomplete", witness, error };
|
|
16
|
+
}
|
|
13
17
|
/** Build one `loc/scheme` replay bundle for witness introductions. */
|
|
14
18
|
function* witnessSchemeReplies(hab, eids, gvrsn) {
|
|
15
19
|
const replies = eids
|
|
@@ -94,7 +98,17 @@ export class Receiptor {
|
|
|
94
98
|
this.gvrsn = gvrsn;
|
|
95
99
|
}
|
|
96
100
|
/** Submit the latest or specified event to all witnesses and gather receipts. */
|
|
97
|
-
*receipt(pre,
|
|
101
|
+
*receipt(pre, options = {}) {
|
|
102
|
+
const outcome = yield* this.attempt(pre, options);
|
|
103
|
+
if (outcome.kind === "incomplete")
|
|
104
|
+
throw outcome.error;
|
|
105
|
+
return outcome.result;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Submit like `receipt`, but report a witness that is unreachable, refuses, or does not receipt as
|
|
109
|
+
* `incomplete` data. Local faults (unknown local AID, missing key state, storage) still throw.
|
|
110
|
+
*/
|
|
111
|
+
*attempt(pre, { sn, auths = {}, allowTcp = false } = {}) {
|
|
98
112
|
return yield* call(() => this.receiptOnce(pre, { sn, auths }, allowTcp));
|
|
99
113
|
}
|
|
100
114
|
/**
|
|
@@ -118,11 +132,13 @@ export class Receiptor {
|
|
|
118
132
|
const { serder, message } = acceptedEventReplayMessage(this.hby, pre, eventSn, this.gvrsn);
|
|
119
133
|
const witnesses = this.hby.db.acceptedEventWitnesses(serder);
|
|
120
134
|
if (witnesses.length === 0) {
|
|
121
|
-
return { witnesses: [], statuses: {} };
|
|
135
|
+
return { kind: "receipted", result: { witnesses: [], statuses: {} } };
|
|
122
136
|
}
|
|
123
137
|
if (serder.ilk === Ilks.rot || serder.ilk === Ilks.drt) {
|
|
124
138
|
for (const witness of serder.adds) {
|
|
125
|
-
yield* this.
|
|
139
|
+
const caughtUp = yield* this.replayHistory(hab, witness);
|
|
140
|
+
if (caughtUp.kind === "unreachable")
|
|
141
|
+
return incomplete(witness, caughtUp.error);
|
|
126
142
|
}
|
|
127
143
|
}
|
|
128
144
|
const receiptGroups = new Map();
|
|
@@ -134,23 +150,35 @@ export class Receiptor {
|
|
|
134
150
|
for (const witness of witnesses) {
|
|
135
151
|
if (kever.delegated) {
|
|
136
152
|
for (const dmsg of this.hby.db.cloneDelegation(kever, this.gvrsn)) {
|
|
137
|
-
yield*
|
|
153
|
+
const delivery = yield* deliverWitnessMessage(hab, witness, this.selected(dmsg), this.http, this.clock, this.protocol);
|
|
154
|
+
if (delivery.kind === "unreachable")
|
|
155
|
+
return incomplete(witness, delivery.error);
|
|
138
156
|
}
|
|
139
157
|
}
|
|
140
158
|
if (allowTcp && !witnessHttpUrl(hab, witness) && witnessTcpUrl(hab, witness)) {
|
|
141
|
-
yield*
|
|
159
|
+
const delivery = yield* deliverWitnessMessage(hab, witness, this.selected(message), this.http, this.clock, this.protocol);
|
|
160
|
+
if (delivery.kind === "unreachable")
|
|
161
|
+
return incomplete(witness, delivery.error);
|
|
142
162
|
statuses[witness] = 200;
|
|
143
163
|
}
|
|
144
164
|
else {
|
|
145
165
|
// A single receipt attempt owns its response until parsing and collection finish.
|
|
146
|
-
let response
|
|
147
|
-
|
|
148
|
-
response = yield*
|
|
166
|
+
let response;
|
|
167
|
+
try {
|
|
168
|
+
response = yield* call(() => postWitnessReceiptEndpoint(hab, witness, message, this.http, auths[witness], this.gvrsn));
|
|
169
|
+
if (response.kind === "escrow") {
|
|
170
|
+
response = yield* pollWitnessReceipt(hab, witness, pre, eventSn, said, this.http, this.gvrsn);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
if (!(error instanceof TransportError))
|
|
175
|
+
throw error;
|
|
176
|
+
return incomplete(witness, error);
|
|
149
177
|
}
|
|
150
178
|
statuses[witness] = response.status;
|
|
151
179
|
if (response.kind !== "accepted") {
|
|
152
180
|
const detail = response.kind === "reject" ? response.message : "receipt remained escrowed";
|
|
153
|
-
|
|
181
|
+
return incomplete(witness, new ValidationError(`Witness ${witness} failed to receipt ${pre}:${eventSn.toString(16)}: ${detail}`));
|
|
154
182
|
}
|
|
155
183
|
yield* processMessages((signal) => chunkBytes(response.body, { signal }), this.protocol, this.kvy, {
|
|
156
184
|
local: false,
|
|
@@ -161,7 +189,7 @@ export class Receiptor {
|
|
|
161
189
|
const index = witnesses.indexOf(witness);
|
|
162
190
|
const wigers = this.hby.db.wigs.get(dgKey(pre, said)).filter((siger) => siger.index === index);
|
|
163
191
|
if (wigers.length === 0) {
|
|
164
|
-
|
|
192
|
+
return incomplete(witness, new ValidationError(`Witness ${witness} did not receipt ${pre}:${eventSn.toString(16)}.`));
|
|
165
193
|
}
|
|
166
194
|
receiptGroups.set(witness, wigers);
|
|
167
195
|
}
|
|
@@ -190,9 +218,11 @@ export class Receiptor {
|
|
|
190
218
|
pipelined: true,
|
|
191
219
|
genusify: true,
|
|
192
220
|
}));
|
|
193
|
-
yield*
|
|
221
|
+
const delivery = yield* deliverWitnessMessage(hab, witness, concatBytes(...parts), this.http, this.clock, this.protocol);
|
|
222
|
+
if (delivery.kind === "unreachable")
|
|
223
|
+
return incomplete(witness, delivery.error);
|
|
194
224
|
}
|
|
195
|
-
return { witnesses, statuses };
|
|
225
|
+
return { kind: "receipted", result: { witnesses, statuses } };
|
|
196
226
|
}
|
|
197
227
|
/**
|
|
198
228
|
* Query a stored witness receipt and apply it to local state when found.
|
|
@@ -243,15 +273,27 @@ export class Receiptor {
|
|
|
243
273
|
if (!hab) {
|
|
244
274
|
throw new ValidationError(`${pre} not a valid local AID.`);
|
|
245
275
|
}
|
|
276
|
+
const delivery = yield* this.replayHistory(hab, witness);
|
|
277
|
+
if (delivery.kind === "unreachable")
|
|
278
|
+
throw delivery.error;
|
|
279
|
+
}
|
|
280
|
+
/** Replay a delegated inception's delegation chain and the KEL to one witness, stopping at the first failure. */
|
|
281
|
+
*replayHistory(hab, witness) {
|
|
246
282
|
const kever = hab.kever;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
yield*
|
|
283
|
+
const db = this.hby.db;
|
|
284
|
+
const gvrsn = this.gvrsn;
|
|
285
|
+
const pre = hab.pre;
|
|
286
|
+
const messages = (function* () {
|
|
287
|
+
if (kever?.delegated)
|
|
288
|
+
yield* db.cloneDelegation(kever, gvrsn);
|
|
289
|
+
yield* db.clonePreIter(pre, 0, gvrsn);
|
|
290
|
+
})();
|
|
291
|
+
for (const msg of messages) {
|
|
292
|
+
const delivery = yield* deliverWitnessMessage(hab, witness, this.selected(msg), this.http, this.clock, this.protocol);
|
|
293
|
+
if (delivery.kind === "unreachable")
|
|
294
|
+
return delivery;
|
|
254
295
|
}
|
|
296
|
+
return { kind: "delivered" };
|
|
255
297
|
}
|
|
256
298
|
/** Complete streams select their framing before the body; detached receipt headers retain their existing enclosure. */
|
|
257
299
|
selected(message) {
|
|
@@ -16,7 +16,7 @@ import { telEventStatus, waitForIssuedCredential, waitForTelEvent, } from "../..
|
|
|
16
16
|
import { endpointRoleAccepted, isLocalGroupHab, localGroupMember, proposeGroupEndpointRole, } from "../../app/identity/endpoint-roleing.js";
|
|
17
17
|
import { MULTISIG_REV_ROUTE, MULTISIG_ROT_ROUTE, MULTISIG_VCP_ROUTE } from "../../app/multisig/grouping.js";
|
|
18
18
|
import { routeForKelEvent } from "../../app/multisig/multisig-workflows.js";
|
|
19
|
-
import { proposeGroupInception, proposeGroupInteraction, proposeGroupRotation,
|
|
19
|
+
import { proposeGroupInception, proposeGroupInteraction, proposeGroupRotation, } from "../../app/multisig/proposing.js";
|
|
20
20
|
import { observeUntil } from "../../app/runtime/workflow-contract.js";
|
|
21
21
|
import { ValidationError } from "../../core/errors.js";
|
|
22
22
|
import { isV2RegistryRoute } from "../../core/exchange/protocol-exchanging.js";
|
|
@@ -272,8 +272,9 @@ export function* multisigRotateCommand(args) {
|
|
|
272
272
|
let delegationPhase = null;
|
|
273
273
|
let rootCopies = [];
|
|
274
274
|
if (accepted) {
|
|
275
|
-
//
|
|
276
|
-
|
|
275
|
+
// Acceptance was read straight from the KEL, possibly before the Counselor's pass: follow it now, since the
|
|
276
|
+
// root copies below go to the rotated members.
|
|
277
|
+
hby.alignGroupMembers(sent.group);
|
|
277
278
|
delegationPhase = yield* finishAcceptedEvent(hby, runtime, sent.event, commandArgs);
|
|
278
279
|
rootCopies = yield* resealAfterRotation(hby, runtime, sent.group, sent.event.said, since);
|
|
279
280
|
}
|
|
@@ -32,6 +32,34 @@ export class ValidationError extends AppError {
|
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* A caller asked to treat a KRAM refusal as a failure. Carries the refused message SAID and the refusal decision;
|
|
37
|
+
* the message names the reason and, when the refusal has one, the last instant the message was acceptable.
|
|
38
|
+
*/
|
|
39
|
+
export class KramRefusedError extends ValidationError {
|
|
40
|
+
constructor(said, refusal) {
|
|
41
|
+
super(`KRAM refused message ${said}: ${refusal.reason}`
|
|
42
|
+
+ (refusal.deadline ? ` (acceptable until ${refusal.deadline})` : ""));
|
|
43
|
+
Object.defineProperty(this, "said", {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true,
|
|
46
|
+
writable: true,
|
|
47
|
+
value: said
|
|
48
|
+
});
|
|
49
|
+
Object.defineProperty(this, "refusal", {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
configurable: true,
|
|
52
|
+
writable: true,
|
|
53
|
+
value: refusal
|
|
54
|
+
});
|
|
55
|
+
Object.defineProperty(this, "name", {
|
|
56
|
+
enumerable: true,
|
|
57
|
+
configurable: true,
|
|
58
|
+
writable: true,
|
|
59
|
+
value: "KramRefusedError"
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
35
63
|
/** Filesystem or path-resolution failure from path-managed resources. */
|
|
36
64
|
export class PathError extends AppError {
|
|
37
65
|
constructor() {
|
|
@@ -120,3 +148,48 @@ export class DatabaseOperationError extends DatabaseError {
|
|
|
120
148
|
});
|
|
121
149
|
}
|
|
122
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Local durable state that the store's own records say must exist is missing or contradicts itself: a local group
|
|
153
|
+
* names a member habitat the store does not hold, for example. Never a remote outcome: no peer message removes a
|
|
154
|
+
* local record, so a long-running loop does not survive it and lets it end the runtime. Recovery is repairing or
|
|
155
|
+
* replacing the store, not retrying.
|
|
156
|
+
*/
|
|
157
|
+
export class MissingDurableStateError extends DatabaseError {
|
|
158
|
+
constructor() {
|
|
159
|
+
super(...arguments);
|
|
160
|
+
Object.defineProperty(this, "name", {
|
|
161
|
+
enumerable: true,
|
|
162
|
+
configurable: true,
|
|
163
|
+
writable: true,
|
|
164
|
+
value: "MissingDurableStateError"
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* A browser composition's persistence queue gave up on a write after its retries (ADR-0015 rule 3), so it accepts
|
|
170
|
+
* no more commits and reports this from every later commit, flush and close. The cause is the write's first failure.
|
|
171
|
+
* The latch is terminal for that composition; recovery is closing it and opening a new one.
|
|
172
|
+
*/
|
|
173
|
+
export class PersistenceLatchedError extends DatabaseOperationError {
|
|
174
|
+
constructor() {
|
|
175
|
+
super(...arguments);
|
|
176
|
+
Object.defineProperty(this, "name", {
|
|
177
|
+
enumerable: true,
|
|
178
|
+
configurable: true,
|
|
179
|
+
writable: true,
|
|
180
|
+
value: "PersistenceLatchedError"
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** A task passed to `PersistenceQueue.read` failed. Only its caller sees it; the queue does not latch. */
|
|
185
|
+
export class PersistenceReadError extends DatabaseOperationError {
|
|
186
|
+
constructor() {
|
|
187
|
+
super(...arguments);
|
|
188
|
+
Object.defineProperty(this, "name", {
|
|
189
|
+
enumerable: true,
|
|
190
|
+
configurable: true,
|
|
191
|
+
writable: true,
|
|
192
|
+
value: "PersistenceReadError"
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { dgKey } from "../../db/core/keys.js";
|
|
2
2
|
import { ValidationError } from "../errors.js";
|
|
3
|
-
|
|
3
|
+
import { readEventSeal } from "../wire-fields.js";
|
|
4
|
+
/**
|
|
5
|
+
* Whether one accepted delegator event carries the exact `{i,s,d}` seal of a delegated inception.
|
|
6
|
+
*
|
|
7
|
+
* The delegator's seals are remote-authored and unchecked at acceptance; other shapes and undecodable values are
|
|
8
|
+
* skipped (`readEventSeal`), never thrown.
|
|
9
|
+
*/
|
|
4
10
|
function approves(event, dip) {
|
|
5
|
-
return event.
|
|
11
|
+
return event.seals.some((raw) => {
|
|
12
|
+
const seal = readEventSeal(raw);
|
|
13
|
+
return seal !== null && seal.i.qb64 === dip.pre && seal.s.numh === dip.snh && seal.d.qb64 === dip.said;
|
|
14
|
+
});
|
|
6
15
|
}
|
|
7
16
|
/**
|
|
8
17
|
* Find the delegator's accepted approval of `dip`.
|
|
@@ -8,6 +8,7 @@ import { normalizeMbxTopicCursor } from "../mailbox/mailbox-topics.js";
|
|
|
8
8
|
import { reply as replyEvent } from "../protocol-eventing.js";
|
|
9
9
|
import { KeyStateRecord, ObservedRecord } from "../records.js";
|
|
10
10
|
import { acceptReplyDecision, unverifiedReplyDecision } from "../routing.js";
|
|
11
|
+
import { kelEventFieldDefect, readDater, readDiger, readOrdinal, readPrefixer, readSequenceNumber, } from "../wire-fields.js";
|
|
11
12
|
import { acceptEscrow, acceptQuery, acceptReceipt, dropEscrow, dropQuery, dropReceipt, escrowQuery, escrowReceipt, ignoreReceipt, keepEscrow, logEscrowDecision, } from "./kever-decisions.js";
|
|
12
13
|
import { Kever } from "./kever.js";
|
|
13
14
|
import { deriveRotatedWitnessSet, hasUniqueWitnesses } from "./witnesses.js";
|
|
@@ -365,14 +366,15 @@ export class Kevery {
|
|
|
365
366
|
processReceipt(envelope) {
|
|
366
367
|
const serder = envelope.serder;
|
|
367
368
|
const pre = serder.pre;
|
|
368
|
-
|
|
369
|
+
// Decided before any escrow: a remote receipt's sn and prefix are read through the guarded readers.
|
|
370
|
+
const sn = readSequenceNumber(serder);
|
|
369
371
|
const said = serder.said;
|
|
370
372
|
const local = envelope.local ?? this.local;
|
|
371
|
-
if (!pre || sn === null || !said) {
|
|
373
|
+
if (!pre || !readPrefixer(pre) || sn === null || !said) {
|
|
372
374
|
this.cues.push({
|
|
373
375
|
kin: "invalid",
|
|
374
376
|
serder,
|
|
375
|
-
reason: "Receipt message is missing receipted pre, sn, or said.",
|
|
377
|
+
reason: "Receipt message is missing a valid receipted pre, hex sn, or said.",
|
|
376
378
|
});
|
|
377
379
|
return;
|
|
378
380
|
}
|
|
@@ -611,23 +613,22 @@ export class Kevery {
|
|
|
611
613
|
const pre = serder.pre;
|
|
612
614
|
const ilk = serder.ilk;
|
|
613
615
|
const said = serder.said;
|
|
614
|
-
|
|
616
|
+
// Every remote field value is decided here, before any escrow or store write: escrow replay re-enters through
|
|
617
|
+
// this method, so a row stored with a malformed value is rejected and removed instead of failing every pass.
|
|
618
|
+
const sn = readSequenceNumber(serder);
|
|
615
619
|
if (!pre || !ilk || !said || sn === null) {
|
|
616
620
|
return {
|
|
617
621
|
kind: "reject",
|
|
618
622
|
code: !pre ? "invalidPre" : !ilk ? "invalidIlk" : "invalidSn",
|
|
619
|
-
message:
|
|
623
|
+
message: `KEL event must include pre, ilk, said, and a hex sn of at most ${Number.MAX_SAFE_INTEGER}.`,
|
|
620
624
|
};
|
|
621
625
|
}
|
|
622
|
-
|
|
623
|
-
|
|
626
|
+
if (!readPrefixer(pre)) {
|
|
627
|
+
return { kind: "reject", code: "invalidPre", message: `Invalid pre=${pre} for event ${said}.` };
|
|
624
628
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
code: "invalidPre",
|
|
629
|
-
message: `Invalid pre=${pre} for event ${said}: ${error instanceof Error ? error.message : String(error)}`,
|
|
630
|
-
};
|
|
629
|
+
const defect = kelEventFieldDefect(serder);
|
|
630
|
+
if (defect) {
|
|
631
|
+
return { kind: "reject", code: "malformedField", message: `Malformed ${defect} in event ${said} for ${pre}.` };
|
|
631
632
|
}
|
|
632
633
|
const local = envelope.local ?? this.local;
|
|
633
634
|
const init = this.makeKeverEventInit(envelope, local);
|
|
@@ -939,16 +940,18 @@ export class Kevery {
|
|
|
939
940
|
throw new ValidationError(`Unsupported route=${args.route} in ${Ilks.rpy} reply.`);
|
|
940
941
|
}
|
|
941
942
|
const ksn = KeyStateRecord.fromDict(args.serder.ked?.a);
|
|
942
|
-
|
|
943
|
-
const
|
|
944
|
-
const
|
|
945
|
-
const
|
|
946
|
-
|
|
943
|
+
// Decide the notice's field values before decideReply can escrow it.
|
|
944
|
+
const pre = readPrefixer(ksn.i)?.qb64 ?? null;
|
|
945
|
+
const sn = typeof ksn.s === "string" ? readOrdinal(ksn.s) : null;
|
|
946
|
+
const saider = readDiger(ksn.d);
|
|
947
|
+
const dater = readDater(ksn.dt);
|
|
948
|
+
if (!pre || sn === null || !saider || !dater) {
|
|
947
949
|
throw new ValidationError("Malformed key state notice reply body.");
|
|
948
950
|
}
|
|
951
|
+
const said = saider.qb64;
|
|
949
952
|
if (!this.lax) {
|
|
950
953
|
const watchers = this.configuredWatchers();
|
|
951
|
-
const backers = ksn.b
|
|
954
|
+
const backers = Array.isArray(ksn.b) ? ksn.b : [];
|
|
952
955
|
// In non-lax mode, only the controller, a reported KSN backer, or a
|
|
953
956
|
// locally configured watcher may advance saved key state.
|
|
954
957
|
const trusted = args.aid === pre
|
|
@@ -986,8 +989,6 @@ export class Kevery {
|
|
|
986
989
|
if (ldig && ldig !== said) {
|
|
987
990
|
throw new ValidationError(`Mismatch key state at sn=${sn} with accepted event log for ${pre}.`);
|
|
988
991
|
}
|
|
989
|
-
const saider = new Diger({ qb64: said });
|
|
990
|
-
const dater = new Dater({ qb64: encodeDateTimeToDater(dt) });
|
|
991
992
|
const cues = [{ kin: "keyStateSaved", ksn }];
|
|
992
993
|
this.rvy.writeReply(reply);
|
|
993
994
|
this.updateKeyState(args.aid, ksn, saider, dater);
|
|
@@ -1025,15 +1026,11 @@ export class Kevery {
|
|
|
1025
1026
|
throw new ValidationError(`Unsupported route=${args.route} in ${Ilks.rpy} reply.`);
|
|
1026
1027
|
}
|
|
1027
1028
|
const data = args.serder.ked?.a;
|
|
1028
|
-
const cid =
|
|
1029
|
-
|
|
1030
|
-
: null;
|
|
1031
|
-
const oid = typeof data?.oid === "string"
|
|
1032
|
-
? new Prefixer({ qb64: data.oid }).qb64
|
|
1033
|
-
: null;
|
|
1029
|
+
const cid = readPrefixer(data?.cid)?.qb64 ?? null;
|
|
1030
|
+
const oid = readPrefixer(data?.oid)?.qb64 ?? null;
|
|
1034
1031
|
const oobi = typeof data?.oobi === "string" ? data.oobi : null;
|
|
1035
1032
|
if (!cid || !oid) {
|
|
1036
|
-
throw new ValidationError("Missing one of cid/oid in /watcher reply.");
|
|
1033
|
+
throw new ValidationError("Missing or malformed one of cid/oid in /watcher reply.");
|
|
1037
1034
|
}
|
|
1038
1035
|
const keys = [cid, args.aid, oid];
|
|
1039
1036
|
let osaider = this.db.wwas.get(keys);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Dater, Diger, Ilks, NumberPrimitive, Prefixer, SealSource, Siger, Tholder, Verfer, } from "cesr-ts";
|
|
1
|
+
import { Dater, Diger, Ilks, NumberPrimitive, Prefixer, SealEvent, SealSource, Siger, Tholder, Verfer, } from "cesr-ts";
|
|
2
2
|
import { dgKey } from "../../db/core/keys.js";
|
|
3
3
|
import { encodeDateTimeToDater, makeNowIso8601 } from "../../time/mod.js";
|
|
4
4
|
import { ValidationError } from "../errors.js";
|
|
5
5
|
import { KeyStateRecord } from "../records.js";
|
|
6
|
+
import { readEventSeal } from "../wire-fields.js";
|
|
6
7
|
import { deriveRotatedWitnessSet } from "./witnesses.js";
|
|
7
8
|
/**
|
|
8
9
|
* Convert one integer into the Huge-number CESR family used for durable replay
|
|
@@ -1434,16 +1435,21 @@ export class Kever {
|
|
|
1434
1435
|
}
|
|
1435
1436
|
return this.db.getState(pre)?.di || null;
|
|
1436
1437
|
}
|
|
1437
|
-
/**
|
|
1438
|
+
/**
|
|
1439
|
+
* Return the zero-based index of the matching event seal among the candidate's event-shaped seals, or `-1`.
|
|
1440
|
+
*
|
|
1441
|
+
* The candidate is an accepted delegator event, which is remote-authored: its `a` may hold any seal shape and
|
|
1442
|
+
* undecodable values. Like KERIpy, the index counts entries with the `{i, s, d}` field shape; other shapes and
|
|
1443
|
+
* malformed values never match (`readEventSeal`).
|
|
1444
|
+
*/
|
|
1438
1445
|
eventAnchorSealIndex(candidate, serder) {
|
|
1439
|
-
|
|
1440
|
-
|
|
1446
|
+
return candidate.seals.filter((raw) => SealEvent.isSad(raw)).findIndex((raw) => {
|
|
1447
|
+
const seal = readEventSeal(raw);
|
|
1448
|
+
return seal !== null
|
|
1449
|
+
&& seal.i.qb64 === serder.pre
|
|
1441
1450
|
&& seal.s.numh === serder.snh
|
|
1442
|
-
&& seal.d.qb64 === serder.said
|
|
1443
|
-
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
return -1;
|
|
1451
|
+
&& seal.d.qb64 === serder.said;
|
|
1452
|
+
});
|
|
1447
1453
|
}
|
|
1448
1454
|
/**
|
|
1449
1455
|
* Verify one indexed-signature set against a given verifier list.
|
|
@@ -29,6 +29,14 @@ function storedCacheType(db, ilk, route) {
|
|
|
29
29
|
export function singleKeyQueryWindow(db, route) {
|
|
30
30
|
return storedCacheType(db, "qry", route)?.sl ?? null;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* How long an exchange of a message of `ilk` on `route` stays open after its opener under the windows this store
|
|
34
|
+
* is configured with now, in milliseconds: the exchange lag `xl`. Null when this store has no KRAM cache types
|
|
35
|
+
* (KRAM never ran on it).
|
|
36
|
+
*/
|
|
37
|
+
export function exchangeWindow(db, ilk, route) {
|
|
38
|
+
return storedCacheType(db, ilk, route)?.xl ?? null;
|
|
39
|
+
}
|
|
32
40
|
/** Validate caller configuration before any durable policy mutation. */
|
|
33
41
|
function windows(value, transitional = false) {
|
|
34
42
|
if (!Array.isArray(value) || value.length !== 7 || value.some((v) => !Number.isSafeInteger(v) || v < 0)) {
|