import type { CollectionEncryption, WasClient } from '@interop/was-client'; import type { EncryptionDescriptorStore } from '@interop/was-client/edv/core'; import type { IKeyAgreementKey } from '@interop/data-integrity-core'; import { type ClientWebvhUpdateKeys, type ICapabilityAgent, type KmsAuthenticationBinding, type PublishedWebvhLog, type WebvhIdStore } from '../webvh/index.js'; import { type UserKey, type WalletSpaceEpochsResult } from '../keys/index.js'; import { type StageNotifier } from '../log.js'; /** * The complete key set a brand-new account mints locally before anything * touches the network: the data Space id, this founding client's identity * seed, the account's user key, and the client-held did:webvh update-key * seeds. Persisting the set client-local (under the app's unlock layer) is * the caller's job, and for the update keys it must happen BEFORE * {@link ensureAccountGenesis} publishes anything -- the seeds are the only * update authority the log will ever accept. */ export interface AccountKeySet { spaceId: string; clientSeed: Uint8Array; userKey: UserKey; updateKeys: ClientWebvhUpdateKeys; } /** * Mints a fresh data-Space id: 32 random bytes, base64url without padding. * Random rather than controller-derived on purpose: the Space's controller is * promoted to a did:webvh whose id embeds this Space id, so a * controller-derived id would be circular. * * @returns {string} */ export declare function mintSpaceId(): string; /** * Mints the complete key set of a brand-new account: a fresh Space id, a * 32-byte client identity seed (expanded to the founding client's agents via * `agentsFromSeed`), the account's user key, and the did:webvh update-key * pair. Pure minting -- nothing here touches the network or any store. * * @returns {Promise} */ export declare function mintAccountKeySet(): Promise; /** * What the promotion stage found and did: `promoted` (the Space Description * named another controller -- on a fresh signup, this founding client's * did:key -- and the ceremony moved it to the account DID), `confirmed` (the * Space already names the account DID; nothing written), or `healed` (the * Description was unreadable under the session's signing identity -- the torn * state where the controller PUT never landed -- and the re-PUT signed as the * stored did:key controller landed it). */ export type SpaceControllerPromotion = 'promoted' | 'confirmed' | 'healed'; /** * Promotes the data Space's controller to the account's did:webvh, as a state * machine over the Space Description so every state a torn earlier run can * leave behind converges: * * - The Description reads and already names `did`: nothing to do. * - The Description reads and names another controller (a fresh signup: this * founding client's did:key, which `was` is then signing as): one configure * PUT moves it to `did`. * - The Description is unreadable (`null` covers both absent and * unauthorized): the torn case, where the session already signs under the * did:webvh but the controller PUT never landed, so the server still * authorizes only the stored did:key controller. The re-PUT goes through * `wasAsClient`, the handle signing under this client's plain did:key. * * The PUT always carries the full `{ name, controller }` description, so the * unreadable-Description merge guard in was-client's `configure` never * defaults anything from a state this ceremony cannot see. * * @param options {object} * @param options.was {WasClient} signing as the session currently signs * (this client's did:key on a fresh signup; the promoted did:webvh keyId on * a heal re-run) * @param [options.wasAsClient] {WasClient} signing under this client's * plain did:key, for the torn-promotion heal; omitted, that branch refuses * instead of healing * @param options.spaceId {string} * @param options.did {string} the account's did:webvh DID * @returns {Promise} */ export declare function ensurePromotedSpaceController({ was, wasAsClient, spaceId, did }: { was: WasClient; wasAsClient?: WasClient; spaceId: string; did: string; }): Promise; /** * The Space-provisioning stage of {@link ensureAccountGenesis} failed: the * Space (or part of its collection roster) could not be ensured, so nothing * downstream ran. Raised as its own class with a stable `name`, so a caller * that treats the later stages as non-fatal can still let a missing Space * propagate -- match it on `err.name === 'AccountGenesisSpaceError'`, never * `instanceof` (the error can be raised by a linked or duplicated copy of * this package). */ export declare class AccountGenesisSpaceError extends Error { constructor(options: { spaceId: string; cause: unknown; }); } /** * The stages whose failures the ceremony collects instead of throwing (see * the module doc for the split). */ export type AccountGenesisStage = 'kmsAuthentication' | 'roster' | 'epochs' | 'promotion'; /** * What a completed ceremony reports: the account DID, each collected stage's * outcome where it ran (the roster descriptor, the per-collection epoch * install -- whose own `failed` list stays inside it -- and what the * promotion found), and the stages that failed on this run. A result with * `failed` entries is a resumable success: the account exists and is * identified, and a naive re-run of the whole ceremony finishes the rest. */ export interface AccountGenesisResult { did: string; /** * The account log's verified head as the did:webvh stage left it -- the * served head it adopted, or the one it minted paired with its create PUT's * ETag -- for the stage after the ceremony to build on rather than re-read. * Set by the credential-anchored ceremony alone; the plain genesis's * did:webvh stage hands no head back. */ published?: PublishedWebvhLog; /** * Whether the did:webvh stage MINTED that head (a fresh signup) rather than * adopting a served one (a heal re-run). A later stage may reuse a minted * head freely -- the account did not exist a moment ago, so no other writer * holds it -- but an adopted head is only a snapshot: its document's * completion tests are unprotected by any ETag and another client may have * moved past them by the time a later stage reads them. */ logMinted?: boolean; rosterDescriptor?: CollectionEncryption; epochs?: WalletSpaceEpochsResult; /** * Set when the epochs stage was refused by `ensureWalletSpaceEpochs`'s * mint gate: the adopted user-key roster's current epoch is not the * `userKey` the ceremony was handed, so nothing was installed (`epochs` is * then absent). The caller that recovers the roster's real key is the one * installer (the credential-anchored establishment's adopted-roster arm * does this). Absent, like `epochs`, when the roster stage did not land: * no roster means no epochs, and a re-run installs both. */ epochsSkipped?: WalletSpaceEpochsResult['skipped']; promotion?: SpaceControllerPromotion; failed: Array<{ stage: AccountGenesisStage; error: unknown; }>; } /** * Runs the account-genesis ceremony against an already-minted * {@link AccountKeySet} (whose update-key seeds the caller has already * persisted client-local). Idempotent end to end: every stage adopts what an * earlier run landed, so a torn run -- and a lost create race against a * concurrent provisioner -- heals by re-running. * * Stage order (the module doc has the why): Space provisioning, the optional * KMS key-map acquisition, did:webvh genesis, user-key roster genesis, the * encrypted collections' epoch[0] install, Space-controller promotion. * * @param options {object} * @param options.was {WasClient} signing as the session currently signs: * this client's did:key on a fresh signup, the promoted did:webvh keyId on * a heal re-run over an already-promoted account * @param [options.wasAsClient] {WasClient} signing under this client's * plain did:key, for the torn-promotion heal (see * {@link ensurePromotedSpaceController}) * @param options.wasServerUrl {string} the storage server the account * lives on; the did:webvh id embeds its host * @param options.spaceId {string} * @param options.keyAgent {ICapabilityAgent} this founding client's signing * key agent (`agentsFromSeed` over the key set's `clientSeed`); its did:key * id is the Space's controller at creation * @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own * (identity) key-agreement key -- its published `keyAgreement` verification * method, and the roster's first recipient * @param options.userKey {UserKey} the account's user key, recipient zero * of every encrypted collection and the roster's first epoch * @param options.updateKeys {ClientWebvhUpdateKeys} the client-held * did:webvh update-key seeds, already persisted client-local * @param options.idStore {WebvhIdStore} the account's `id` collection * store the did:webvh ceremony reads and publishes through * @param options.rosterStoreFor {Function} `({ did }) => * EncryptionDescriptorStore` -- builds the user-key roster's descriptor * store once the account DID is known (the log-governed store's controller * view and chain-head pin are the app's wiring) * @param options.collectionStoreFor {Function} `({ did }) => * (collectionId: string) => EncryptionDescriptorStore` -- builds each * encrypted collection's descriptor store once the account DID is known, * the same wiring the roster's builder takes. It is handed `did` alone, * since this ceremony's did:webvh stage returns only that: an app whose * store resolves a controller view builds it from the published log it * fetches itself (`webvhResourceLogController` over a `verifyAccountLog` * result), unlike the credential-anchored genesis, which hands its own * head through * @param [options.provideKmsAuthentication] {Function} `({ spaceReady }) => * Promise` -- the KMS authentication * binding's acquisition; absent or resolving `undefined`, the genesis is * client-keys-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 client-keys-only, 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's did:webvh from the * caller's stored account pointer, when it already names one; the genesis * read then refuses a published log resolving to any other account. That * read and the publish run under the `idStore`'s own chain-head pin * @param [options.onDidPublished] {Function} `({ did }) => Promise` * -- runs between the DID publication and the roster genesis, so the app * can adopt the DID (and drop any verified-log memo) before the roster * store's controller view resolves against the published document * @param [options.promoteController] {boolean} whether to run the * promotion stage (default `true`). An app whose account pointer must * durably name the DID BEFORE the controller PUT lands -- and whose * pointer write lives outside this call (freewallet's keyring re-bind) -- * passes `false` and runs {@link ensurePromotedSpaceController} itself * after that write * @param [options.onStage] {StageNotifier} observational: called at the * KMS-authentication join, with {@link KMS_AUTHENTICATION_STAGE} -- the one * boundary this ceremony names, and the same token the credential-anchored * genesis emits at the same point * @returns {Promise} */ export declare function ensureAccountGenesis({ was, wasAsClient, wasServerUrl, spaceId, keyAgent, clientKeyAgreementKey, userKey, updateKeys, idStore, rosterStoreFor, collectionStoreFor, provideKmsAuthentication, expectedDid, onDidPublished, promoteController, onStage }: { was: WasClient; wasAsClient?: WasClient; wasServerUrl: string; spaceId: string; keyAgent: ICapabilityAgent; clientKeyAgreementKey: IKeyAgreementKey; userKey: UserKey; updateKeys: ClientWebvhUpdateKeys; idStore: WebvhIdStore; rosterStoreFor: (options: { did: string; }) => EncryptionDescriptorStore; collectionStoreFor: (options: { did: string; }) => (collectionId: string) => EncryptionDescriptorStore; provideKmsAuthentication?: (options: { spaceReady: Promise; }) => Promise; expectedDid?: string; onDidPublished?: (published: { did: string; }) => Promise; promoteController?: boolean; onStage?: StageNotifier; }): Promise; //# sourceMappingURL=accountGenesis.d.ts.map