/** * Habitat and shared-environment primitives for local KERI operation. * * KERIpy correspondence: * - this module is the closest analogue to `keri.app.habbing` * - `Hab` owns local identifier behavior while `Habery` owns the shared * keeper/database/router/parser environment * * `keri-ts` difference: * - parser ingress uses the CESR frame/envelope pipeline instead of KERIpy's * monolithic `Parser` * - local bootstrap replies and events still flow through the same accepted * state machinery instead of being written directly to persistent state */ import { type Operation } from "effection"; import { Cigar, SerderKERI, Siger, type ThresholdSith, type Tier, Verfer, type Versionage } from "../../../cesr/mod.js"; import type { AgentCue, CueEmission } from "../core/cues.js"; import { Deck } from "../core/deck.js"; import { Kevery } from "../core/eventing.js"; import { Kever } from "../core/kever.js"; import { type Role } from "../core/roles.js"; import { BasicReplyRouteHandler, Revery, Router } from "../core/routing.js"; import { type Scheme } from "../core/schemes.js"; import { Baser } from "../db/basing.js"; import { Keeper } from "../db/keeping.js"; import { type OutboxerLike } from "../db/outboxing.js"; import { type CesrBodyMode } from "./cesr-http.js"; import { Configer } from "./configing.js"; import { Algos, Manager } from "./keeping.js"; /** Reserved alias for the local signatory habitat record. */ export declare const SIGNER = "__signatory__"; /** Arguments for constructing and reopening a `Habery`. */ export interface HaberyArgs { name: string; base?: string; temp?: boolean; headDirPath?: string; compat?: boolean; readonly?: boolean; cf?: Configer; skipConfig?: boolean; skipSignator?: boolean; bran?: string; seed?: string; aeid?: string; salt?: string; algo?: Algos; tier?: Tier; outboxer?: "disabled" | "open" | "create"; cesrBodyMode?: CesrBodyMode; } /** Habitat inception options consumed by the local bootstrap `Hab.make()` flow. */ export interface MakeHabArgs { code?: string; transferable?: boolean; isith?: ThresholdSith; icount?: number; icode?: string; nsith?: ThresholdSith; ncount?: number; ncode?: string; toad?: number; wits?: string[]; delpre?: string; estOnly?: boolean; DnD?: boolean; hidden?: boolean; data?: unknown[]; algo?: Algos; salt?: string; tier?: Tier; } /** Group habitat inception options for local member-collected group creation. */ export interface MakeGroupHabArgs { isith?: ThresholdSith; nsith?: ThresholdSith; toad?: number; wits?: string[]; delpre?: string; data?: unknown[]; hidden?: boolean; } /** Result of creating one local group inception event. */ export interface GroupHabCreation { hab: Hab; serder: SerderKERI; sigers: Siger[]; /** Initial controller-signed creation bytes; use event replay for later cross-implementation publication. */ message: Uint8Array; } /** Result of rotating one locally membered group habitat. */ export interface GroupHabRotation { hab: Hab; serder: SerderKERI; sigers: Siger[]; message: Uint8Array; } /** Result of creating one locally signed group interaction event. */ export interface GroupHabInteraction { hab: Hab; serder: SerderKERI; sigers: Siger[]; message: Uint8Array; } /** * Return KERIpy-shaped replay bytes for one accepted KEL event. * * The replay payload is event body plus durable attachments from first-seen * storage: controller indexed signatures, witness indexed signatures, * authorizing seals, and receipts in KERIpy `cloneEvtMsg` order. */ export declare function eventReplayMessage(hby: Habery, serder: SerderKERI): Uint8Array; /** * Return a stored KEL event payload with KERIpy `cloneEvtMsg` attachment order. * * Accepted events use their first-seen ordinal. Locally generated events that * are still in delegated escrow do not have a first-seen ordinal yet, so they * use their own event sequence number for the stored clone lookup. */ export declare function eventPayloadMessage(hby: Habery, serder: SerderKERI): Uint8Array; /** Return the exact accepted event replay message at `(pre, sn)`. */ export declare function acceptedEventReplayMessage(hby: Habery, pre: string, sn: number): { serder: SerderKERI; message: Uint8Array; }; /** * Build one inception/delgated-inception serder from generated keys and config. * * Current scope: * - supports local `icp` and delegated `dip` bootstrap events * - relies on simple numeric threshold defaults * - keeps SAID code resolution centralized for prefix derivation consistency */ /** Represents a local identifier habitat and its current key state. */ export declare class Hab { readonly name: string; readonly ns?: string; readonly db: Baser; readonly ks: Keeper; readonly mgr: Manager; readonly cf?: Configer; readonly rtr: Router; readonly rvy: Revery; readonly kvy: Kevery; pre: string; /** Create one habitat wrapper over shared DB/keeper/manager infrastructure. */ constructor(name: string, db: Baser, ks: Keeper, mgr: Manager, cf: Configer | undefined, rtr: Router, rvy: Revery, kvy: Kevery, ns?: string, pre?: string); /** Backward-compatible alias for the injected local `Kevery`. */ get kevery(): Kevery; /** Return true when this habitat has accepted local key state. */ get accepted(): boolean; /** Return the live accepted-state `Kever` for this habitat when available. */ get kever(): Kever | null; /** * Accept one locally generated event through the same `Kevery`/`Kever` path * used by remote processing. * * This keeps local habitat inception and later state transitions aligned with * the main accepted-state machine instead of duplicating direct DB writes in * the habitat layer. */ private acceptLocally; /** * Parse and dispatch locally generated CESR bytes through the real * `CesrParser` architecture. * * This mirrors the KERIpy shape where locally generated bootstrap replies may * still flow through the same parser-driven reply acceptance machinery as * remotely received wire messages. */ private ingestLocalCesr; /** Return the alias-scoped config section for this habitat when present. */ configuredSection(): Record | null; /** Return true when this habitat has alias-scoped config preload material. */ hasConfigSection(): boolean; /** * Apply alias-scoped controller endpoint config through the real CESR parser path. * * KERIpy correspondence: * - `Hab` owns per-alias config lookup and reply ingestion * - config remains immutable bootstrap input, not mutable database state */ reconfigure(): boolean; /** * Incept this habitat through the shared accepted-state path. * * KERIpy correspondence: * - mirrors the pattern where local inception is signed in the habitat layer * and then fed through `Kevery.processEvent()` rather than hand-writing * `states.`/`kels.` directly */ make(args?: MakeHabArgs): void; /** * Rotate this habitat through the shared accepted-state path. * * KERIpy correspondence: * - advances keeper state first via `Manager.replay()` or `Manager.rotate()` * - rolls keeper state back if local `Kevery` acceptance rejects the event * - erases stale old private keys only after successful acceptance */ rotate(args?: { isith?: ThresholdSith; nsith?: ThresholdSith; ncount?: number; toad?: number; cuts?: string[]; adds?: string[]; data?: unknown[]; }): Uint8Array; /** * Create and locally accept one interaction event for this habitat. * * KERIpy correspondence: * - author one `ixn` from current accepted state * - sign with the current controller keys * - feed the event back through local `Kevery` acceptance * * `keri-ts` difference: * - local acceptance still flows through the explicit decision architecture, * and non-accept outcomes surface as local validation failures */ interact(args?: { data?: unknown[]; }): Uint8Array; /** Produces signatures with this habitat's current signing keys. */ sign(ser: Uint8Array, indexed: true): Siger[]; sign(ser: Uint8Array, indexed?: false): Cigar[]; /** * Endorse one already-built KERI message body with this habitat's current * establishment keys. * * Current supported endorsement shapes: * - transferable indexed signature groups anchored to the latest accepted * establishment event * - non-transferable detached signature cigars with attached verifier * context for local replay/reload flows * * Current `keri-ts` limitation: * - the Gate E bootstrap path only actively uses the transferable branch for * locally generated replies and queries */ endorse(serder: SerderKERI, options?: { pipelined?: boolean; gvrsn?: Versionage; nested?: boolean; genusify?: boolean; }): Uint8Array; /** * Create and sign one reply event with this habitat's current establishment keys. * * The returned bytes are a complete wire message. Transferable reply * attachments are anchored to the habitat's latest accepted establishment * event, matching the KERI reply-endorsement model. */ reply(route: string, data: Record, stamp?: string): Uint8Array; /** * Create and sign one query message from this habitat. * * This mirrors the intent of KERIpy's `BaseHab.query()` while staying within * the current Gate E bootstrap message surface. */ query(pre: string, src: string, query?: Record, route?: string, stamp?: string): Uint8Array; /** * Create and locally accept one controller receipt for `serder`. * * KERI semantics: * - receipt signatures cover the receipted event bytes, not the `rct` * message body * - transferable receiptors emit transferable indexed-signature groups * - non-transferable receiptors emit receipt couples */ receipt(serder: SerderKERI): Uint8Array; /** * Create and locally accept one witness receipt for `serder`. * * The current habitat must be a non-transferable witness listed on the * receipted event's witness state. */ witness(serder: SerderKERI): Uint8Array; /** * Create one signed endpoint-role authorization reply for this habitat. * * This is the local helper behind `tufa ends add` and endpoint-role OOBI * dissemination. */ makeEndRole(eid: string, role?: Role | string, allow?: boolean, stamp?: string): Uint8Array; /** * Create one signed endpoint-location reply for this habitat. * * The endpoint AID defaults to the habitat's own prefix because the most * common bootstrap case is self-advertised controller/agent/mailbox hosting. */ makeLocScheme(url: string, eid?: string, scheme?: Scheme | string, stamp?: string): Uint8Array; /** * Return stored non-empty location URLs keyed by scheme for one endpoint AID. * * This is a pure projection over `locs.`; it does not synthesize default * schemes or perform any lookup beyond local state. */ fetchUrls(eid: string, scheme?: string): Record; /** * Project authorized endpoint URLs for one controller AID. * * Output shape: * - role -> endpoint AID -> scheme-keyed URL map * * Witnesses are derived from current key state as well as stored location * replies because witness membership is partly a KEL concern, not just an * endpoint-authorization concern. */ endsFor(pre: string): Record>>; /** * Reload one stored `/end/role/*` reply message from reply-state DBs. * * Returns an empty message when the requested authorization is not presently * enabled or allowed. */ loadEndRole(cid: string, eid: string, role?: Role | string): Uint8Array; /** * Reload stored `/loc/scheme` reply messages for one endpoint and optional scheme. * * Without a scheme filter this may concatenate multiple stored scheme replies * into one outbound byte stream. */ loadLocScheme(eid: string, scheme?: string): Uint8Array; /** * Generate fresh `/loc/scheme` replies from local location state. * * This is used when the local habitat is the authoritative speaker for the * endpoint, so a newly signed reply is preferred over replaying an older * stored reply. */ replyLocScheme(eid: string, scheme?: string): Uint8Array; /** * Generate the reply/message stream used for role-based OOBI discovery. * * Current composition order: * 1. cloned KEL messages for the controller AID * 2. witness location/auth material when serving witness OOBIs * 3. endpoint location/auth replies from `locs.` and `ends.` * * This mirrors the shape of KERIpy's `replyEndRole()` output while remaining * limited to the Gate E bootstrap role families. */ replyEndRole(cid: string, role?: Role | string, eids?: string[], scheme?: string): Uint8Array; /** * Entry point used by OOBI HTTP resource serving. * * The current bootstrap implementation delegates directly to `replyEndRole()` * so the recognizable KERIpy seam exists before broader discovery policy is * implemented. */ replyToOobi(aid: string, role?: Role | string, eids?: string[]): Uint8Array; /** * Resolve the witness list that governs receipts for one event. * * Preference order: * - the durable event-level `wits.` projection when present * - the event body's own backer list for inception events * - the current accepted kever witness list as a last resort */ private receiptedWitnesses; /** * Process KERI-style cues and yield structured runtime cue emissions. * * KERIpy correspondence: * - this is the `keri-ts` equivalent of `BaseHab.processCuesIter()` * * `keri-ts` difference: * - the cue identity is preserved in the yielded `CueEmission` instead of * collapsing everything immediately to raw bytes * * Current support: * - `receipt`, `witness`, `replay`, `reply`, and complete `query` cues emit * wire messages * - `stream` emits transport requests without flattening them into bytes * - observer/runtime cues remain visible as notify emissions */ processCuesIter(cues: Deck | Iterable): Generator; } /** * Internal signatory habitat wrapper used for habery-scoped signatures. * * KERIpy correspondence: * - mirrors the idea of a persisted `__signatory__` habitat owned by the * enclosing habery * - verifies through the live signatory habitat verifier instead of * reconstructing one ad hoc from the prefix * * Current `keri-ts` differences: * - signing/verification are deterministic local-hab wrappers, not a full * parity implementation of KERIpy signatory lifecycle and reopen logic */ export declare class Signator { readonly db: Baser; readonly hab: Hab; pre: string; /** Reopen or create the habery-owned `__signatory__` habitat wrapper. */ constructor(args: { db: Baser; ks: Keeper; mgr: Manager; cf?: Configer; rtr: Router; rvy: Revery; kvy: Kevery; }); /** * Sign arbitrary serialized bytes with the habery-owned signatory habitat. * * KERIpy parity: * - delegates to the underlying hab with `indexed=false` * - returns the first hydrated detached `Cigar` */ sign(ser: Uint8Array): Cigar; /** Return the current verifier from the signatory habitat's accepted key state. */ get verfer(): Verfer; /** Verify one detached `Cigar` through the signatory habitat's live verifier. */ verify(ser: Uint8Array, cigar: Cigar): boolean; } /** * Top-level controller container for databases, key manager, config, and local * habitats. * * Responsibilities: * - compose `Baser`, `Keeper`, `Manager`, optional config, and loaded habitats * - own the habery-local `Kevery` used by `Hab` for local KEL/receipt * acceptance outside the runtime host * - eagerly reconstruct persisted habitat visibility on open * - provide app-layer alias lookup and habitat creation boundaries * * State model: * - `habs` is an in-memory cache of reconstructed `Hab` instances * - durable habitat metadata lives in `habs.` * - durable current key state lives in `states.` with supporting `evts.`, * `kels.`, `fels.`, and `dtss.` data in `Baser` * - accepted current key state is owned by live `Kever` instances reloaded into * `Baser.kevers` * - `Hab.kever` resolves that accepted-state cache instead of reconstructing a * thin projection ad hoc * - `Habery.kevery` owns a separate local cue deck from the runtime-owned cue * deck created by `createAgentRuntime()` * * Current `keri-ts` differences: * - readonly compatibility opens may intentionally skip config processing and * signator creation for visibility-only commands * - config-driven OOBI processing and broader KEL/state orchestration are not * yet at KERIpy parity */ export declare class Habery { readonly name: string; readonly base: string; readonly temp: boolean; readonly headDirPath?: string; readonly compat: boolean; readonly readonly: boolean; readonly db: Baser; readonly ks: Keeper; readonly obx: OutboxerLike; readonly cesrBodyMode: CesrBodyMode; readonly mgr: Manager; readonly cf?: Configer; readonly habs: Map; readonly rtr: Router; readonly rvy: Revery; readonly kevery: Kevery; readonly replyRoutes: BasicReplyRouteHandler; readonly signator: Signator | null; /** Compose one habery from already-opened storage, manager, and config surfaces. */ constructor(name: string, base: string, temp: boolean, headDirPath: string | undefined, compat: boolean, readonly: boolean, db: Baser, ks: Keeper, obx: OutboxerLike, cesrBodyMode: CesrBodyMode, mgr: Manager, cf?: Configer, skipSignator?: boolean); /** Live config snapshot from the optional config file surface. */ get config(): Record; /** * Populate the in-memory habitat cache from durable `habs.` + `states.` data. * * Bare metadata records without corresponding accepted key state are skipped * so `Habery.habs` only contains reopenable local habitats. */ private loadHabs; /** Local AID prefixes currently managed by this habery. */ get prefixes(): string[]; /** * Seed OOBI queues from config-file preload material. * * Config is treated as immutable bootstrap input, matching KERIpy's * "preload the database, do not use config as a mutable database" rule. * * Stores touched: * - `oobis.` for controller/delegate bootstrap URLs * - `woobi.` for witness bootstrap URLs */ reconfigure(): void; /** Creates and caches a new habitat under this habery. */ makeHab(name: string, ns?: string, args?: MakeHabArgs): Hab; /** * Create a locally signed group inception event from member habitat state. * * KERIpy correspondence: * - mirrors the narrow `Habery.makeGroupHab()` inception path * - extracts one current verifier per signing member and one next digest per * rotation member, matching KERIpy's `extractMerfersMigers()` * * Current scope: * - at least one signing member must be local to this `Habery` * - delegated groups may remain escrowed until the delegator anchor arrives * - rotation/counselor orchestration is intentionally outside this method */ makeGroupHab(group: string, mhab: Hab, smids: string[], rmids?: string[], ns?: string, args?: MakeGroupHabArgs): GroupHabCreation; /** * Bind local metadata for a remotely proposed group event. * * KERIpy correspondence: * - this is the TypeScript analogue of `Habery.joinGroupHab()` * - it does not fabricate key state; accepted KEL state must still arrive * through `Kevery.processEvent()` */ joinGroupHab(pre: string, group: string, mhab: Hab, smids: string[], rmids?: string[], ns?: string): Hab; /** * Rotate a locally membered group identifier from member habitat state. * * Current scope: * - all signing members must be local habitats in this `Habery` * - member AIDs should already be in the key state intended for the new * group key list, matching KLI's operator workflow of rotating members * before rotating the group */ rotateGroupHab(group: string, smids?: string[], rmids?: string[], args?: { isith?: ThresholdSith; nsith?: ThresholdSith; toad?: number; cuts?: string[]; adds?: string[]; data?: unknown[]; }): GroupHabRotation; /** Create a locally signed group interaction event. */ interactGroupHab(group: string, smids?: string[], args?: { data?: unknown[]; }): GroupHabInteraction; /** Extract the single current verifier from each group signing member. */ private extractGroupMemberKeys; /** Extract one next-key digest from each transferable rotation member. */ private extractGroupMemberNextDigests; /** Sign a group event with every listed member that is local to this habery. */ private signGroupEventWithLocalMembers; /** Persist group habitat metadata and member ordinals. */ private persistGroupHabRecord; /** Mark an accepted group habitat as locally managed/membered. */ private markAcceptedGroupHab; /** Remove group metadata when local event validation rejects the inception. */ private removeGroupHabRecord; /** Encode group member prefixes with durable ordinal metadata. */ private groupMemberTuples; /** * Resolve a habitat by alias (and optional namespace) using DB-backed state. * * This uses `names.` for alias lookup, `habs.` for metadata, and accepted * `Kever` state for reopenable current state before materializing a cached * `Hab`. */ habByName(name: string, ns?: string): Hab | null; /** Closes backing databases and optionally clears temp storage. */ close(clear?: boolean): Operation; } /** * Derive deterministic seed/AEID material from one passcode string. * * KERIpy correspondence: * - mirrors the `bran` -> `seed`/`aeid` derivation used for encrypted habery * reopen flows */ export declare function branToSeedAeid(bran: string): { seed: string; aeid: string; }; /** * Create a `Habery` with reopened database/keystore surfaces and manager state. * * The returned `Habery` immediately reconstructs its local habitat cache from * durable DB state rather than depending on process-local creation history. */ export declare function createHabery(args: HaberyArgs): Operation; //# sourceMappingURL=habbing.d.ts.map