/*! * Copyright (c) 2026 Interop Alliance. All rights reserved. */ /** * The account-genesis ceremony's CREDENTIAL-ANCHORED variant: such a * signup mints no enrolled client, so the ceremony is anchored on the unlock * credential's ladder alone. The stage order mirrors `ensureAccountGenesis` * with the enrolled-client members swapped for their ladder analogs: * * 1. Space provisioning under the ladder VM's bare did:key -- the bootstrap * controller (wallet-core decision 0004, freewallet decision 0002's * resolution of the orphan-Space tear): re-derivable from the unlock * record's ladder seed, so a tab death here strands nothing a later * login cannot finish or unwind. * 2. The optional KMS authentication binding (`provideKmsAuthentication`), * started BEFORE stage 1 is awaited and joined before stage 3 -- the * keystore and the key mint need no Space, so only the thunk's own * `keys.json` write waits on the `spaceReady` promise this ceremony hands * it. Best-effort: a throw is collected and the genesis proceeds * keystore-less, publishing a document with no `authentication` relation, * which no later entry adds the key to. * 3. The ladder-anchored did:webvh genesis * (`ensureLadderAnchoredDidWebvh`): the entry signed by ladder rung 0, * `updateKeys` = [rung 0], `nextKeyHashes` = [hash(rung 0), hash(rung 1)], * the ladder VM and the credential's `keyAgreement` inventory folded in -- * plus, when stage 2 delivered a key map, the KMS-held authentication VM * under `authentication` only -- `portable` unchanged. * 4. The user-key roster genesis, wrapped to the CREDENTIAL's standing * key-agreement key -- the only recipient a ladder-anchored account has * -- with the entry proof signed by the ladder VM (the ceremony-tail * license's first-entry shape). The account is credential-recoverable * from the moment this lands. * 5. Epoch[0] on every encrypted roster collection -- gated twice, unlike the * enrolled-client flow. The roster stage must have landed, AND the roster's * current epoch must BE the `userKey` this run was handed: the user key * here exists only in this tab's memory, so installing collection epochs * under a key the roster does not deliver would strand the collections on a * key that dies with the tab. The second gate is what a re-run over an * earlier run's roster hits: `read()` adopts a roster keyed to that run's * user key, and this run's candidate key is a throwaway nobody holds -- * installing epoch[0] under it on a collection the earlier run never * reached would key that collection to nothing, permanently, since the * install is create-if-absent and every later ensure adopts it. So the * stage is refused whole by `ensureWalletSpaceEpochs`'s mint gate (the * roster descriptor is handed to it) and reported on `epochsSkipped`; * the caller that recovers the roster's real key is the one installer. * With both gates the tear heal is always clean: no roster means no * epochs, and a fresh user key re-runs both. * 6. Space-controller promotion, last -- every earlier stage ran under the * bootstrap did:key the Space's stored controller authorizes. * * Idempotent end to end on the enrolled-client flow's convention; the did:webvh * stage adopts a published log iff the ladder attributes it (a naive re-run * would mint a different SCID, so adoption IS the torn-signup convergence). */ import { type RecipientPublicKey } from '@interop/was-client/edv/core'; import type { WasClient } from '@interop/was-client'; import type { EncryptionDescriptorStore } from '@interop/was-client/edv/core'; import type { DIDLog } from '@interop/did-method-webvh'; import type { KmsAuthenticationBinding, PublishedWebvhLog, WebvhIdStore } from '../webvh/didWebvh.js'; import type { UnlockKeyAgreementPublication } from '../unlock/standingWebvh.js'; import { type UserKey } from '../keys/index.js'; import { type AccountGenesisResult } from '../genesis/accountGenesis.js'; import { type StageNotifier } from '../log.js'; /** * The key set a credential-anchored signup mints locally before anything * touches the network: the data Space id and the account's user key -- nothing else. * No client seed and no client update-key seeds exist (that is the point); * the ladder seed is minted by the unlock layer beside the record that * carries it, and every other key derives from it. * * @returns {Promise<{ spaceId: string, userKey: UserKey }>} */ export declare function mintCredentialAnchoredAccountKeySet(): Promise<{ spaceId: string; userKey: UserKey; }>; /** * Runs the credential-anchored account-genesis ceremony (see the module doc * for the stage order and its whys). The caller has already durably written the * unlock record carrying the ladder seed -- the transposed * persist-before-publish rule: rung 0 must never publish before the seed * that derives it is recoverable. * * @param options {object} * @param options.was {WasClient} signing as the ladder VM's bare did:key * (the bootstrap controller; build it over `ladderVmAgent`) * @param options.wasServerUrl {string} * @param options.spaceId {string} * @param options.ladderSeed {Uint8Array} the credential's ladder seed, * already sealed into the durably written unlock record * @param options.keyAgreement {UnlockKeyAgreementPublication} the * credential's key-agreement publication (commitment or verbatim), folded * into the genesis document * @param options.standingRecipient {RecipientPublicKey} the credential's * standing key-agreement key as a roster recipient (`id` its roster kid) * @param options.userKey {UserKey} the account's user key, epoch[0] of the * roster and recipient zero of every encrypted collection * @param options.idStore {WebvhIdStore} the account's `id` collection * store, signing as the same bootstrap did:key * @param options.rosterStoreFor {Function} `({ did, log }) => * EncryptionDescriptorStore` -- the user-key roster's store once the DID is * known, with a LADDER-signed `ResourceLogSigner` (the first-entry shape). * `log` is the account log the did:webvh stage just adopted or published, * so a store resolving its controller view can read it out of this run's * own head instead of fetching `did.jsonl` again * @param options.collectionStoreFor {Function} `({ did, log }) => * (collectionId: string) => EncryptionDescriptorStore` -- each encrypted * collection's descriptor store, with the same LADDER-signed * `ResourceLogSigner` and the same bootstrap invocation the roster's * builder takes, and the same account log to resolve a controller view * from. On a governed collection the epoch install through it is that * collection's governing-log genesis * @param [options.provideKmsAuthentication] {Function} `({ spaceReady }) => * Promise` -- the KMS authentication * binding's acquisition (a wallet that keeps a KMS mints the key under the * ladder VM's bare did:key and writes `keys.json` here); absent or * resolving `undefined`, the genesis is ladder-and-credential-only and no * `keys.json` is ever written. It is STARTED before the Space is awaited * and joined before the genesis entry, so its `spaceReady` argument is what * its own `keys.json` write waits on. A throw is collected, not fatal: the * genesis proceeds keystore-less, and the document it publishes never gains * the key. The thunk's own obligation, since this ceremony takes * `authentication.vmId` VERBATIM into the world-readable genesis entry: a * served `keys.json` may be adopted only after the multibase in its `vmId` * is checked against the session's own keystore listing; on a mismatch, or * when the keystore cannot be listed, the thunk mints instead of adopting * @param [options.expectedDid] {string} the account DID, when the caller * holds a pointer that already names one (a heal re-run); a fresh signup * and a fresh-terminal heal legitimately hold none * @param [options.onDidPublished] {Function} `({ did }) => Promise` * @param [options.promoteController] {boolean} default `true`; an app whose * account pointer must durably name the DID first (freewallet's record * re-bind) passes `false` and promotes after that write * @param [options.onStage] {StageNotifier} observational: called as each * stage finishes, with the names in `CREDENTIAL_ANCHORED_GENESIS_STAGES` * (`clientAnnex/stages.ts`) and, only when this ceremony promotes, * `CONTROLLER_PROMOTION_STAGE`. `kms-authentication` fires at the JOIN * rather than inside the thunk: stage 2 overlaps stage 1, so a thunk that * finishes first would otherwise mark out of order * @returns {Promise} with `published` and * `logMinted` always set: the account log's verified head the did:webvh * stage adopted or minted, and which of the two it was -- the head is only * safely reusable downstream when this run minted it */ export declare function ensureCredentialAnchoredAccountGenesis({ was, wasServerUrl, spaceId, ladderSeed, keyAgreement, standingRecipient, userKey, idStore, rosterStoreFor, collectionStoreFor, provideKmsAuthentication, expectedDid, onDidPublished, promoteController, onStage }: { was: WasClient; wasServerUrl: string; spaceId: string; ladderSeed: Uint8Array; keyAgreement: UnlockKeyAgreementPublication; standingRecipient: RecipientPublicKey; userKey: UserKey; idStore: WebvhIdStore; rosterStoreFor: (options: { did: string; log: DIDLog; }) => EncryptionDescriptorStore; collectionStoreFor: (options: { did: string; log: DIDLog; }) => (collectionId: string) => EncryptionDescriptorStore; provideKmsAuthentication?: (options: { spaceReady: Promise; }) => Promise; expectedDid?: string; onDidPublished?: (published: { did: string; }) => Promise; promoteController?: boolean; onStage?: StageNotifier; }): Promise; //# sourceMappingURL=credentialAnchoredGenesis.d.ts.map