/*! * Copyright (c) 2026 Interop Alliance. All rights reserved. */ /** * The enrolled-client listing: enumerates the wallet clients a verified * did:webvh log currently enrolls, for a "your wallets" management surface. * * The document is the roster, so the listing is a pure read over it, keyed on * `capabilityInvocation`: every enrolled client publishes its Ed25519 signing * key there, while a recovery code's key appears only under `keyAgreement` * (deliberately unmarked) and the KMS-held convenience key only under * `authentication` -- so neither can ever surface in the listing, * structurally rather than by filtering. * * Two members are not readable off the current document alone and come from * the log: * * - `updateKeyMultibase` -- the client's ACTIVE update key, which * {@link RevokedClientKeys} needs to disconnect the client. `updateKeys` is * a flat set with no per-client grouping, so the key is recovered by * attribution: the entry that published the client's verification methods * also revealed its initial update key, and each later entry that retired * the attributed key while revealing exactly one replacement is that * client's self-rotation. An attribution that cannot isolate a single key * leaves the member `undefined` (the caller disables disconnect for that * row) rather than guessing -- removing a wrong update key would revoke a * different client's authority. * - `addedAt` -- the `versionTime` of the entry that published the client's * verification methods (its enrollment moment, as the log states it). * * The X25519 `keyAgreementKeyMultibases` set is READ from the document, not * derived: it is every `keyAgreement` method published under the client's * controller marker (`controller: did:key:`, the write-side * convention every enrollment follows). The marker is what tells a client's * key-agreement methods apart from the deliberately unmarked ones a recovery * continuation publishes beside them. It is hard-required -- a client with no * marked method reports an EMPTY set, the same refuse-not-guess rule the * update-key attribution follows, since a guessed key-agreement key would make * a revocation report success over a method that never left the document. The * whole set is built in a single pass over the document's resolved * key-agreement methods, grouped by controller once and looked up per client, * rather than a per-client rescan. * * Verification is the CALLER's job: pass a log that was resolved and checked * against the account pointer (the wallet's ordinary * verify-the-published-log step); this module only enumerates it. * * Beside the listing lives the current-key-set rule as one predicate, * `delegationKeyInDocument`: given a recorded delegation's key id, does the * document still list that key under `capabilityDelegation`? The relation is * the whole question -- a delegation proof verifies only against a method the * document publishes for that purpose now -- so a key surviving under * `authentication` or `keyAgreement` alone does not keep a grant chaining. It * is the same read the listing performs, reduced to a yes/no about one * recorded grant, so every surface that has to decide "does this delegation * still chain" decides it in one place. */ import type { DIDLog } from '@interop/did-method-webvh'; import type { KeyAgreementDocument } from '../resourceLog/document.js'; /** * One enrolled wallet client as the log states it. `keyAgreementKeyMultibases` * is REQUIRED and set-valued: every key-agreement method the client's * controller marker claims, in document order, deduplicated. An EMPTY array is * the refuse-not-guess state -- the document carries no marked method for the * client. `updateKeyMultibase` and `addedAt` are absent when the log * attribution cannot recover them (see the module doc). * * A client that published several marked key-agreement methods surfaces the * full set here; revoking it removes them all regardless, because the removal * filters the document by the marker rather than by this member. */ export interface EnrolledWebvhClient { signingKeyMultibase: string; keyAgreementKeyMultibases: string[]; updateKeyMultibase?: string; addedAt?: string; } /** * A locally verified did:webvh document, read only for the key multibases it * publishes. Structural on purpose: a resolved `DIDDoc` satisfies it, and so * does any narrower document shape a wallet already holds. */ export interface PublishedKeyDocument { verificationMethod?: Array<{ id?: string; publicKeyMultibase?: string; }>; capabilityDelegation?: Array; } /** * The key multibases the document currently publishes: every verification * method's `publicKeyMultibase`, plus the fragment of its id (for a did:webvh * document the two agree, and taking both is what makes the did:key and * did:webvh forms of one key match). * * @param options {object} * @param options.doc {PublishedKeyDocument} a locally verified document * @returns {Set} */ export declare function documentKeyMultibases({ doc }: { doc: PublishedKeyDocument; }): Set; /** * The current-key-set rule for a recorded delegation: does the document still * list the verification method that signed it under `capabilityDelegation`? * That relation is the test rather than mere membership in the document, * because a delegation proof verifies only against a method published for the * delegation purpose as the document resolves NOW. A key kept under * `authentication` or `keyAgreement` but dropped from `capabilityDelegation` * signs nothing the server will accept, so it must read as rotted here too. * A `false` is exactly "this recorded grant has rotted" -- the signal behind a * re-mint or a health nudge. * * Matching is on the key multibase, not the whole id, so the did:key and * did:webvh forms of one key agree (a delegation signed before the account's * controller was promoted names the same key under a different DID). * * An ABSENT `delegationKeyId` reports `false`: a record that does not say * which key signed it cannot be checked against the document, and the * conservative reading of an uncheckable grant is that it does not stand. * That is the one decision here, taken once so no caller re-decides it -- a * record predating the field is flagged rather than assumed healthy. * * @param options {object} * @param options.doc {PublishedKeyDocument} a locally verified document * @param [options.delegationKeyId] {string} the recorded delegation's * verification-method id, in either DID form * @returns {boolean} */ export declare function delegationKeyInDocument({ doc, delegationKeyId }: { doc: PublishedKeyDocument; delegationKeyId?: string; }): boolean; /** * The `keyAgreement` verification methods one client's controller marker * claims: the document's resolved key-agreement methods * ({@link resolvedKeyAgreementMethods}) filtered to those whose `controller` is * the client's did:key (see `clientKeyAgreementController`). * * The marker is HARD-REQUIRED here, and that is where this predicate parts * company with the user key roster's recipient resolver, which filters the same * reader's result by nothing more than "carries a public key multibase". * Listing and revocation are refuse-not-guess surfaces: an unmarked method * matched by proximity would make a revocation report success over a method * that never left the document. The roster resolver's job is the opposite -- * it must keep wrapping the user key to the deliberately unmarked * key-agreement methods a recovery code publishes, so it matches them too. * * The ordinary shape is exactly one method, but the result is a SET rather * than a first match on purpose: a revocation has to remove every method the * marker claims, or a client with a second published key-agreement key would * keep a standing wrap target after a revocation reported success. * * @param options {object} * @param options.doc {KeyAgreementDocument} a locally verified document * @param options.signingKeyMultibase {string} the client's Ed25519 signing * key, as the document publishes it * @returns {Array<{ id?: string, publicKeyMultibase?: string }>} */ export declare function markedKeyAgreementMethods({ doc, signingKeyMultibase }: { doc: KeyAgreementDocument; signingKeyMultibase: string; }): Array<{ id?: string; publicKeyMultibase?: string; }>; /** * The key multibases of the `keyAgreement` methods one client's controller * marker claims -- {@link markedKeyAgreementMethods}, reduced to the * multibases a roster wrap and a listing row speak in. A method carrying no * `publicKeyMultibase` falls back to the fragment of its id (for a did:webvh * document the two agree). * * @param options {object} * @param options.doc {KeyAgreementDocument} a locally verified document * @param options.signingKeyMultibase {string} * @returns {string[]} */ export declare function markedKeyAgreementMultibases({ doc, signingKeyMultibase }: { doc: KeyAgreementDocument; signingKeyMultibase: string; }): string[]; /** * One enrolled client's ACTIVE update key as the log states it, keyed on the * signing key the document publishes for it -- the same attribution the * listing performs, for a caller that already knows which client it means (the * revocation edit, re-deriving a target whose key rotated since the listing). * `undefined` when the log never published the client's verification methods, * or when the attribution cannot isolate a single key (see the module doc: a * wrong update key would revoke a different client's authority). * * @param options {object} * @param options.log {DIDLog} a resolved, caller-verified log * @param options.signingKeyMultibase {string} the client's Ed25519 signing * key, as the document publishes it * @returns {string | undefined} */ export declare function attributeClientUpdateKey({ log, signingKeyMultibase }: { log: DIDLog; signingKeyMultibase: string; }): string | undefined; /** * The enrolled clients' signing verification-method ids, in document order: * the one read of "which methods are enrolled clients" the listing and the * last-client rule share. The convention is `capabilityInvocation` * membership (see the module doc) -- an enrolled client publishes its * signing key there, while a credential's key-agreement key, its ladder VM, * a transient annex VM, and the KMS convenience key never appear under it. * A future convention that put a non-client key under `capabilityInvocation` * would be corrected here, once, instead of at each decider: a plain forget * counting that key would strand an account, and the last-client transition * would refuse an account it should transition. * * @param options {object} * @param options.doc {object} a locally verified account document * @returns {string[]} */ export declare function enrolledClientVmIds({ doc }: { doc: { capabilityInvocation?: Array; }; }): string[]; /** * Whether a verification method is the account's LAST enrolled client: the * document lists this method as an enrolled client * ({@link enrolledClientVmIds}) and no other. A document that does not list * it at all is not this client standing alone, which is why membership is * asked alongside exclusivity. The plain forget refuses on `true` (removing * the client would strand the account), and the last-client transition * refuses on `false` (another client remains, so the ordinary forget * applies) -- opposite failures decided by one predicate. * * @param options {object} * @param options.doc {object} a locally verified account document * @param options.signingVmId {string} the client's signing * verification-method id * @returns {boolean} */ export declare function isLastEnrolledClient({ doc, signingVmId }: { doc: { capabilityInvocation?: Array; }; signingVmId: string; }): boolean; /** * Lists the enrolled wallet clients of a VERIFIED did:webvh log (see the * module doc: enumeration keyed on the final document's * `capabilityInvocation`, update keys and enrollment times recovered by log * attribution). Order follows the document's `capabilityInvocation` array -- * enrollment order, since every roster edit appends. * * @param options {object} * @param options.log {DIDLog} a resolved, caller-verified log * @returns {EnrolledWebvhClient[]} */ export declare function listEnrolledWebvhClients({ log }: { log: DIDLog; }): EnrolledWebvhClient[]; //# sourceMappingURL=listClients.d.ts.map