/**
 * vault — the six-stage crash-safe creation journal (protocol rev 41 §5.2;
 * task 5.3).
 *
 *   LOCAL_KEYS_PREPARED   identity + client_creation_id            (no ciphertext yet —
 *   ALLOCATED             verified allocation: repo_id, nonce, gen   repo_id is a KDF input)
 *   OBJECTS_PREPARED      exact object ids, nonces, framed bytes, hashes, sizes — fsynced BEFORE any PUT
 *   OBJECTS_FINALIZED     server receipts, compared to the local manifest
 *   GENESIS_PREPARED      exact genesis stored bytes + hash
 *   ACTIVE                admitted; pin + recovery receipt recorded
 *
 * The ordering is the round-3 H5 invariant made structural: `K_repo` is
 * generated and the creator's `key_envelope` is sealed ONLY in the
 * OBJECTS_PREPARED step, which cannot run until ALLOCATED has journaled a
 * `repo_id` — because `repo_id` is an HKDF input and an HPKE AAD member, no
 * ciphertext can exist before allocation. Each stage is written to
 * `journal/<client_creation_id>.json` with the keystore's atomic+fsync write
 * before the next step starts.
 *
 * Restart reconciliation (`resume`) dispatches on the durable stage:
 *   - OBJECTS_PREPARED with a PUT possibly in flight → read-and-compare the
 *     object against the journaled bytes; equal → finalized; present-but-
 *     different → `VAULT_CREATION_CONFLICT`; absent → PUT the SAME bytes.
 *     Never re-encrypt under the same id (a fresh seal would be a second
 *     ciphertext under a single-use key label).
 *   - GENESIS_PREPARED → read the admitted genesis back; equal → ACTIVE;
 *     foreign → `VAULT_CREATION_CONFLICT`, never overwritten.
 *   - a `superseded` allocation anywhere → `ALLOCATION_SUPERSEDED`; the client
 *     does not publish.
 *   - anything the journal cannot explain → refuse the destructive retry.
 *
 * The control-plane calls ride an injectable {@link VaultCreationTransport}
 * — task 5.4 wires the HTTP one; tests supply an in-memory bucket.
 */
import { VAULT_TERMINAL_LOSS_DOCTOR_TEXT, VAULT_TERMINAL_LOSS_STATEMENT } from "../namespaces/vault.crypto.js";
import type { VaultAllocation, VaultKeyEnvelopeReceipt, VaultRecoveryReceipt, VaultGenesis } from "../namespaces/vault.types.js";
import { VaultKeystore } from "./vault-keystore.js";
export declare const VAULT_CREATION_STAGES: readonly ["LOCAL_KEYS_PREPARED", "ALLOCATED", "OBJECTS_PREPARED", "OBJECTS_FINALIZED", "GENESIS_PREPARED", "ACTIVE"];
export type VaultCreationStage = (typeof VAULT_CREATION_STAGES)[number];
/** One prepared object: exact bytes + identity, durable before any PUT. */
export interface VaultJournaledObject {
    object_kind: "key_envelope";
    /** Storage path relative to the vault root (`envelopes/<epoch>/<recipient_fingerprint>`). */
    path: string;
    /** The exact stored bytes, base64url (the §1 "base64url-jcs" convention). */
    stored_bytes_b64u: string;
    stored_bytes_sha256: string;
    size_bytes: string;
    /** The genesis receipt for this object. */
    receipt: VaultKeyEnvelopeReceipt;
    /** Set once the server receipt was compared equal to the local manifest. */
    finalized: boolean;
}
/**
 * Push-to-create addressing (repo-first-onramp task 4.5; design D6). A journal
 * opened this way does not know its `org_id`/`project_id` until the ALLOCATED
 * stage's response tells it (the gateway resolves `org_slug` and creates the
 * project atomically inside the SAME allocate call — see routes/repos.ts's
 * `resolveAllocationAuthz` in run402-private) — see `VaultCreationJournal`'s
 * doc comment on why `org_id`/`project_id` are nullable.
 */
export interface VaultPushToCreateAddress {
    org_slug: string;
    repo_name: string;
}
/**
 * `journal/<client_creation_id>.json`. Stage-monotonic; every field from an
 * earlier stage survives.
 *
 * `org_id` / `project_id` are `string | null` because of push-to-create
 * (repo-first-onramp task 4.5, design D6): a journal opened with
 * `push_to_create` set does not know either value until the ALLOCATED stage's
 * response names them (trust-on-first-use — `checkAllocation` skips those two
 * comparisons while they are `null` and this module pins them from the
 * allocation the FIRST time, then treats the pin as authoritative on every
 * later call for this same journal, same as an ordinary `project_id`-addressed
 * journal always has been). Exactly one of `project_id` or `push_to_create` is
 * set at open time; `push_to_create` itself never changes across the journal's
 * life — it is the RESUMABILITY KEY for a push-to-create attempt, the way
 * `(org_id, project_id)` is for the ordinary path.
 */
export interface VaultCreationJournal {
    version: 1;
    stage: VaultCreationStage;
    client_creation_id: string;
    org_id: string | null;
    project_id: string | null;
    /** Set only for a push-to-create journal (task 4.5); `null` otherwise. */
    push_to_create: VaultPushToCreateAddress | null;
    /** vault-byo-primary-bucket task 3.1 — `"byo"` when this journal requested a BYO vault at open time; `null` (managed, byte-identical to today) otherwise. Set once at open, never changes across the journal's life (mirrors `push_to_create`'s own resumability-key discipline). */
    storage_profile: "byo" | null;
    /** Set iff `storage_profile === "byo"`; `null` otherwise. */
    byo_destination: string | null;
    creator_signing_fingerprint: string;
    creator_encryption_fingerprint: string;
    created_at: string;
    updated_at: string;
    /** ALLOCATED — the verified allocation verbatim. */
    allocation: VaultAllocation | null;
    /** OBJECTS_PREPARED — K_repo (hex) lives ONLY here until ACTIVE moves it to the repo file. */
    k_repo_hex: string | null;
    objects: VaultJournaledObject[];
    /** GENESIS_PREPARED — the exact signed genesis and its stored-bytes hash. */
    genesis: VaultGenesis | null;
    genesis_sha256: string | null;
    /** ACTIVE — the emitted recovery receipt. */
    recovery_receipt: VaultRecoveryReceipt | null;
    /**
     * A terminal refusal, if reconciliation hit one (the journal is kept for
     * diagnosis, never retried destructively). `REPO_CREATION_CONFLICT` (task
     * 4.5) marks a push-to-create journal that lost the atomic name-claim race
     * — `details.project_id` names the winner, exactly what
     * `pushToCreateVault` needs to resolve to it and proceed as an ordinary
     * push (design D6: "the loser's work is not lost — it just wasn't the
     * creator").
     */
    refusal: {
        code: "VAULT_CREATION_CONFLICT" | "ALLOCATION_SUPERSEDED" | "REPO_CREATION_CONFLICT";
        at: string;
        details?: Record<string, unknown>;
    } | null;
}
/**
 * `POST /vaults/v1` — the allocate REQUEST.
 *
 * READ THIS BEFORE CHANGING THESE FIELD NAMES. The request carries the raw
 * PUBLIC KEYS; the signed `allocation` RECORD the gateway returns carries the
 * FINGERPRINTS derived from them. The two shapes differ on exactly these two
 * fields, so building the request from `schemas/allocation.json` — the obvious
 * thing to do — produces a body the gateway ignores, and it answers
 * `400 VALIDATION_FAILED field=creator_signing_pubkey` as if the field were
 * simply missing. That is the production failure this comment exists to stop
 * from recurring.
 *
 * Pubkeys, not fingerprints, because a fingerprint is one-way: every later head
 * signature is verified against the stored creator signing key, and a hash
 * cannot verify a signature. The gateway derives the fingerprints itself, and
 * `checkAllocation` compares the record's fingerprints back against this
 * principal's — which is what proves the keys we sent are the keys it stored.
 */
export type VaultAllocateRequest = {
    client_creation_id: string;
    org_id: string;
    project_id: string;
    /** Raw Ed25519 public key, canonical base64url (43 chars, decodes to 32 bytes). */
    creator_signing_pubkey: string;
    /** Raw X25519 public key, canonical base64url (43 chars, decodes to 32 bytes). */
    creator_encryption_pubkey: string;
    /** vault-byo-primary-bucket task 3.1/3.5 — omitted/absent is byte-identical to today ("managed"). Present only to request a BYO vault; `byo_destination` is the address only, never credential material (D2). */
    storage_profile?: "byo";
    byo_destination?: string;
} | {
    /**
     * Push-to-create (repo-first-onramp task 4.4/4.5, design D6):
     * `{org_slug, repo_name}` in place of `{org_id, project_id}`. The
     * gateway resolves the slug, atomically claims the name, creates the
     * project, and allocates the vault — all inside this one call
     * (`POST /vaults/v1`, same route, alternate body shape).
     */
    client_creation_id: string;
    org_slug: string;
    repo_name: string;
    creator_signing_pubkey: string;
    creator_encryption_pubkey: string;
    storage_profile?: "byo";
    byo_destination?: string;
};
export interface VaultPutObjectRequest {
    repo_id: string;
    path: string;
    bytes: Uint8Array;
    /** What the client expects the server to acknowledge — the server's receipt is compared against it. */
    expected_sha256: string;
    expected_size_bytes: string;
    /** vault-byo-primary-bucket task 3.2 — present iff this vault is `storage_profile: "byo"`; the object is written directly to `byo.destination` (never run402's own bucket). Omitted is byte-identical to today. */
    byo?: {
        destination: import("./vault-mirror-config.js").VaultMirrorDestination;
        credential?: import("./vault-mirror-config.js").VaultMirrorCredential;
    };
}
export interface VaultObjectReceipt {
    stored_bytes_sha256: string;
    size_bytes: string;
}
export interface VaultAdmitGenesisRequest {
    repo_id: string;
    allocation_generation: string;
    stored_bytes: Uint8Array;
    stored_bytes_sha256: string;
}
export type VaultAdmitGenesisResult = {
    outcome: "admitted";
    admitted_sha256: string;
}
/** Someone already canonized generation zero — the resume path decides whether it is ours (read-back) or foreign. */
 | {
    outcome: "already_admitted";
    admitted_sha256: string;
} | {
    outcome: "allocation_superseded";
};
/**
 * The control-plane + bucket operations creation needs. Every method is
 * idempotent from the journal's point of view; the journal never relies on a
 * call having NOT happened.
 */
export interface VaultCreationTransport {
    /** Idempotent on `client_creation_id`; returns the current representation (which may be `superseded`). */
    allocate(request: VaultAllocateRequest): Promise<VaultAllocation>;
    /** Create-only PUT; on a pre-existing object the server MAY return its receipt instead of overwriting. */
    putObject(request: VaultPutObjectRequest): Promise<VaultObjectReceipt>;
    /**
     * Read an object back (`null` when absent) — the read-and-compare primitive.
     *
     * `expected_sha256` (vault-small-object-inline design D3) is OPTIONAL,
     * client-internal plumbing: an `object-reads`-backed implementation MAY
     * use it to verify a gateway-supplied `inline` reply before trusting it,
     * falling back to the ordinary fetch on a mismatch — never a NEW
     * verification obligation, since every real caller already hash-checks
     * the returned bytes itself before use. Omitted, this is byte-identical
     * to before that change.
     */
    getObject(request: {
        repo_id: string;
        path: string;
        expected_sha256?: string;
    }): Promise<Uint8Array | null>;
    /** Generation-zero admission (the §5A machine at generation zero). */
    admitGenesis(request: VaultAdmitGenesisRequest): Promise<VaultAdmitGenesisResult>;
    /** Read the admitted genesis bytes back (`null` when none). */
    getGenesis(request: {
        repo_id: string;
    }): Promise<Uint8Array | null>;
}
export interface VaultCreationOptions {
    keystore: VaultKeystore;
    transport: VaultCreationTransport;
    /**
     * Exactly ONE addressing form: either `{org_id, project_id}` (the ordinary
     * path — a project already exists) or `push_to_create` (task 4.5 — the
     * project does not exist yet; the gateway creates it atomically alongside
     * the vault). Passing both, or neither, is a local validation error.
     */
    org_id?: string;
    project_id?: string;
    /** Push-to-create addressing (repo-first-onramp task 4.5, design D6) — mutually exclusive with `{org_id, project_id}`. */
    push_to_create?: VaultPushToCreateAddress;
    /** Resume an existing journal, or pin the idempotency key (tests). Fresh CSPRNG when omitted. */
    client_creation_id?: string;
    /**
     * vault-byo-primary-bucket task 3.1/3.5 — request a BYO vault at
     * allocation. Omitted (the default) is byte-identical to today. The
     * caller MUST have already run the allocation-time bucket probe
     * ({@link ../node/vault-byo-probe.js probeVaultByoDestination})
     * against `byo_destination` BEFORE reaching here — this option only
     * threads the already-validated request through; it does not probe.
     */
    storage_profile?: "byo";
    /** Required iff `storage_profile === "byo"` — the destination ADDRESS only (never credential material, D2). */
    byo_destination?: string;
    /**
     * vault-byo-primary-bucket task 3.1/3.2 — the LOCAL write target that
     * drives the genesis `key_envelope`'s own PUT (the one object every
     * vault creates, and the one this class's own `run()` writes directly,
     * bypassing `Vault.uploadAll`'s resolver since no `Vault`
     * exists yet at creation time). Deliberately NOT persisted into the
     * journal file (unlike `storage_profile`/`byo_destination` above) — a
     * credential name is a local, per-invocation fact the caller resupplies
     * on every call, exactly like `service_public_key` already is. Required
     * when `storage_profile === "byo"` and this call needs to reach
     * OBJECTS_PREPARED/OBJECTS_FINALIZED; a resume that omits it fails
     * closed at the object-PUT step rather than silently writing to
     * run402's own bucket.
     */
    byo_write_target?: {
        destination: import("./vault-mirror-config.js").VaultMirrorDestination;
        credential?: import("./vault-mirror-config.js").VaultMirrorCredential;
    };
    /** Clock injection. */
    now?: () => Date;
    /** Optional pinned service public key for allocation-signature verification (5.4 supplies it from the registry). */
    service_public_key?: Uint8Array | string;
    /** Test hook: called after each stage is durable, BEFORE the next step — throw to simulate a crash. */
    onStage?: (stage: VaultCreationStage, journal: VaultCreationJournal) => void | Promise<void>;
}
export interface VaultCreationResult {
    repo_id: string;
    /** The owning org/project, resolved by ACTIVE either way — trust-on-first-use for a push-to-create journal (task 4.5). */
    org_id: string;
    project_id: string;
    genesis_sha256: string;
    recovery_receipt: VaultRecoveryReceipt;
    journal: VaultCreationJournal;
    /** `created` on the first pass; `reconciled` when a restart completed an earlier attempt. */
    how: "created" | "reconciled";
}
/** Journal file for one creation attempt. */
export declare function vaultJournalPath(keystore: VaultKeystore, clientCreationId: string): string;
export declare function readVaultJournal(keystore: VaultKeystore, clientCreationId: string): VaultCreationJournal | null;
/** Every journal on disk that has not reached ACTIVE (what `doctor` lists as "creation in progress"). */
export declare function listIncompleteVaultJournals(keystore: VaultKeystore): VaultCreationJournal[];
/**
 * The client-side half of D2's resumability guarantee (repo-first-onramp
 * task 2.2): find an in-progress LOCAL creation attempt for this exact
 * (org, project) pair, so a second lazy-create call after a crash RESUMES
 * that attempt's `client_creation_id` instead of starting a fresh one.
 *
 * A fresh random id every call would still converge on one vault in
 * practice (the gateway's own allocate route is idempotent per project),
 * but only this local check makes it provable client-side, with no
 * dependency on that server behavior: interrupt a creation mid-flight,
 * call this again, and the SAME journal — not a second competing one —
 * drives to ACTIVE.
 *
 * Refused journals (`VAULT_CREATION_CONFLICT` / `ALLOCATION_SUPERSEDED`) are
 * skipped: `VaultCreation.run()` refuses to retry a refused journal
 * destructively, so resuming one here would only reproduce the refusal.
 * When more than one live candidate exists (should not happen in practice —
 * this function is what prevents it — but a manually-edited keystore or a
 * pre-D2 stray journal could produce one), the most recently updated one is
 * preferred, on the theory that it is the attempt most likely still moving.
 */
export declare function findResumableVaultJournal(keystore: VaultKeystore, orgId: string, projectId: string): VaultCreationJournal | null;
/**
 * The push-to-create sibling of {@link findResumableVaultJournal} (task
 * 4.5): find an in-progress LOCAL push-to-create attempt for this exact
 * `(org_slug, repo_name)` address, so a retry after a crash resumes it rather
 * than starting a second competing attempt. A journal that already lost the
 * name-claim race (`REPO_CREATION_CONFLICT`) is excluded — resuming it would
 * only reproduce the same refusal; `pushToCreateVault` starts a fresh
 * attempt in that case (and typically does not even reach here, since its
 * own fast-path read resolves the winner's repo directly).
 */
export declare function findResumablePushToCreateJournal(keystore: VaultKeystore, orgSlug: string, repoName: string): VaultCreationJournal | null;
export declare class VaultCreation {
    private readonly keystore;
    private readonly transport;
    private readonly now;
    private readonly options;
    private journal;
    private resumed;
    private constructor();
    /**
     * Open a creation: resume the journal for `client_creation_id` when one
     * exists, else write stage 1 (LOCAL_KEYS_PREPARED). Nothing here touches the
     * network; no ciphertext exists yet.
     */
    static open(options: VaultCreationOptions): VaultCreation;
    get current(): VaultCreationJournal;
    private persist;
    private advance;
    private refuse;
    /**
     * Init idempotence. Reached only from a FRESH
     * attempt's `allocate()` call (never a resumed one — that path is
     * `verifyAllocation`/the mid-journal refusals below), so nothing has been
     * journaled past LOCAL_KEYS_PREPARED and no ciphertext or K_repo exists to
     * protect: this method either returns the SAME result a resumed journal
     * would have produced, or throws, and mints nothing either way.
     *
     * `details.repo_id` names the vault the gateway says already exists.
     * Holding a local repo file for it is necessary but not sufficient —
     * `assess()` re-verifies the pinned genesis hash against the ADMITTED
     * genesis this same 409 implies exists (read via the ordinary
     * `transport.getGenesis` path, not trusted blind), so a stale or
     * corrupted local pin still falls through to the non-holder refusal
     * rather than a false "reconciled".
     */
    private reconcileAllocateConflict;
    /**
     * Drive the journal to ACTIVE from whatever stage is durable. Safe to call
     * again after any crash; a refused journal stays refused.
     */
    run(): Promise<VaultCreationResult>;
    private verifyAllocation;
}
/** Convenience: open + run in one call. */
export declare function createVault(options: VaultCreationOptions): Promise<VaultCreationResult>;
/** What `doctor`/`status` print about V0-A recovery — the verbatim statement plus the pointers it must carry. */
export interface VaultDoctorRecoveryText {
    statement: typeof VAULT_TERMINAL_LOSS_STATEMENT;
    doctor_text: typeof VAULT_TERMINAL_LOSS_DOCTOR_TEXT;
    /** The platform's custodial restore of deployed artifacts (the deploy lane's CAS) — the support path when every principal envelope is lost. */
    cas_restore_pointer: string;
}
export declare function vaultDoctorRecoveryText(): VaultDoctorRecoveryText;
//# sourceMappingURL=vault-creation-journal.d.ts.map