import type { Client } from "../kernel.js";
import { VAULT_MIRROR_KEYSTORE_STILL_REQUIRED_STATEMENT, VAULT_MIRROR_VALIDITY_NOT_FRESHNESS_STATEMENT } from "../namespaces/vault.crypto.js";
import { VaultKeystore } from "./vault-keystore.js";
import { type VaultMirrorBackend } from "./vault-mirror-backend.js";
/**
 * REPO-RELATIVE — the `source/<repo_id>/` prefix has already been stripped
 * (see the module doc's mirror-layout mapping). This is the shape every
 * OTHER function in this module, `vault-recover.ts`, and the mirror
 * backend interface all consume; nothing here ever sees the raw wire key
 * except `listVaultObjectsAll` itself.
 *
 * `size_bytes` is an exact decimal string for EVERY kind, including the two
 * generation-addressed chain kinds (`head`/`vault_genesis` at generation
 * zero, `admission_record`) — never `null`.
 */
export interface VaultObjectEntry {
    key: string;
    object_kind: string;
    sha256: string;
    size_bytes: string;
}
/** Page through `GET /vaults/v1/:vault_id/objects`, collecting every entry, stripped to repo-relative keys. Store-and-echo cursor per D3a — never parsed here either. */
export declare function listVaultObjectsAll(client: Client, repoId: string): Promise<VaultObjectEntry[]>;
/** Read one object's bytes by key, using the same wire identity every stored kind already carries (§3 layout). `null` when the gateway reports the object absent. */
export declare function readVaultObjectBytes(client: Client, repoId: string, entry: VaultObjectEntry): Promise<Uint8Array | null>;
/** Exported for the key-shape conformance test (`vault-mirror-recover.test.ts`) — never called for its own sake outside this module. */
export declare function generationRouteForKey(key: string): {
    route: "heads" | "admissions";
    generation: string;
} | null;
/**
 * `key_envelope` is path-addressed by `(epoch, recipient_fingerprint)`, not a
 * plain object_id — every other kind uses its object_id, read straight from
 * the key's own filename via an ANCHORED, kind-specific pattern (never a
 * loose, unanchored fallback — see {@link NON_GENERATION_KEY_SPECS}).
 * Exported for the key-shape conformance test.
 */
export declare function objectReadRequestForEntry(entry: VaultObjectEntry): {
    object_kind: string;
    object_id?: string;
    epoch?: string;
    recipient_fingerprint?: string;
};
export interface VaultMirrorWritePlan {
    /** Every non-head, non-admission entry, in listing order — write these FIRST, in any order among themselves. */
    objects: VaultObjectEntry[];
    /** Then admission records and heads, interleaved, strictly ascending by generation (admission before its own head). */
    admissionsAndHeads: VaultObjectEntry[];
}
/** Sort a flat listing into the admission-order write plan (module doc above). */
export declare function planMirrorWrite(entries: readonly VaultObjectEntry[]): VaultMirrorWritePlan;
export interface VaultMirrorCopyResult {
    key: string;
    outcome: "copied" | "already_present" | "skipped_foreign_recipient" | "failed";
    size_bytes?: string;
    error?: string;
}
export interface VaultMirrorSyncSummary {
    repo_id: string;
    destination: string;
    /** Faithful counts of what ACTUALLY happened this call — never an estimate (design D3a rider (e)). */
    objects_listed: number;
    objects_copied: number;
    objects_already_present: number;
    /**
     * Task 5.3 follow-up: a `key_envelope` wrapped for a DIFFERENT recipient
     * than this machine's own identity — EXPECTED, not a problem. The
     * recipient-only read gate means a mirror can only ever hold envelopes
     * addressed to the local identity; a multi-recipient vault
     * (vault-human-envelopes) makes this the norm. Never counted toward
     * `objects_failed`, and never causes `mirror sync` to report anything but
     * success — named per-key in `skipped_foreign_recipient_keys` so a reader
     * can tell "expected skip" from "silent gap" without cross-referencing.
     */
    objects_skipped_foreign_recipient: number;
    skipped_foreign_recipient_keys: string[];
    objects_failed: number;
    bytes_copied: string;
    errors: Array<{
        key: string;
        error: string;
    }>;
    validity_not_freshness: typeof VAULT_MIRROR_VALIDITY_NOT_FRESHNESS_STATEMENT;
    keystore_still_required: typeof VAULT_MIRROR_KEYSTORE_STILL_REQUIRED_STATEMENT;
}
export interface VaultMirrorSyncOptions {
    keystore?: VaultKeystore;
    /** Test/advanced hook: an already-opened backend, bypassing config resolution. */
    backend?: VaultMirrorBackend;
}
/**
 * `run402 repos mirror sync` (task 2.3): list the vault's stored objects,
 * diff against the mirror by key+size, fetch and hash-verify what's missing,
 * write it in admission order. Resumable and idempotent — running it twice in
 * a row with nothing new copies nothing the second time.
 */
export declare function mirrorSync(client: Client, repoId: string, options?: VaultMirrorSyncOptions): Promise<VaultMirrorSyncSummary>;
export interface VaultMirrorPushResult {
    attempted: boolean;
    outcome: "pushed" | "skipped_no_mirror" | "failed";
    summary?: VaultMirrorSyncSummary;
    error?: string;
}
/**
 * Fires after an ordinary vault push/deploy produces a new generation. NEVER
 * throws and NEVER alters the caller's deploy/push outcome (design D6) — a
 * mirror is strictly extra durability, and its failure is reported BESIDE the
 * vault result as a distinct line, not folded into it. Fires only when a
 * mirror is configured for this vault; a vault with no mirror gets
 * `skipped_no_mirror` (not an error) so callers can log it uniformly without
 * branching on whether mirroring was ever opted into.
 *
 * Implemented as a full (but INCREMENTAL, idempotent) sync rather than a
 * push-scoped upload: the objects listing + diff-by-size machinery already
 * makes an all-caught-up sync cheap (one listing page, zero copies), and this
 * keeps the admission-order write discipline in exactly one place instead of
 * a second, push-scoped code path that could drift from it.
 */
export declare function mirrorPushForGeneration(client: Client, repoId: string, options?: VaultMirrorSyncOptions): Promise<VaultMirrorPushResult>;
/**
 * `run402 repos create --byo`'s every-push dual-write (task 3.3, design
 * D1): list the vault's stored objects, restrict to the signed CHAIN
 * (never the payload kinds, which THIS SAME push already wrote directly to
 * the destination — task 3.2), diff against the destination by key+size,
 * fetch (from run402 — the chain stays run402-authoritative) and
 * hash-verify what's missing, write it in admission order. Resumable and
 * idempotent, reusing the SAME `reconcileOne` copy primitive and
 * admission-order discipline the opt-in mirror uses — one implementation,
 * not a second ordering to prove.
 */
export declare function byoChainCopySync(client: Client, repoId: string, options?: VaultMirrorSyncOptions): Promise<VaultMirrorSyncSummary>;
/**
 * Fires after an ordinary vault push produces a new generation, mirroring
 * {@link mirrorPushForGeneration}'s exact contract (NEVER throws, NEVER
 * alters the caller's push outcome — the chain-copy is reported BESIDE it).
 * Gated on a LOCAL BYO write config existing for this repo — a managed
 * vault (the common case) pays zero extra network calls, `skipped_no_byo`.
 */
export declare function byoChainCopyPushForGeneration(client: Client, repoId: string, options?: VaultMirrorSyncOptions): Promise<VaultMirrorPushResult>;
export interface VaultByoMissingObject {
    key: string;
    object_kind: string;
}
export interface VaultByoPresenceReport {
    repo_id: string;
    destination: string;
    checked: number;
    missing: VaultByoMissingObject[];
}
/**
 * Adjudicates the BYO destination against run402's signed chain (task 3.3's
 * read half, D6): HEAD-checks (cheap, no data transfer) every object the
 * vault's OWN listing names — payload AND chain alike, since for a BYO
 * vault the destination is supposed to hold BOTH (payload via task 3.2's
 * direct write, chain via this file's dual-write above) — against the
 * destination, by key + size. Never throws on an absence; it REPORTS every
 * missing object by name so the caller (`repos fsck`) can refuse with
 * `VAULT_BYO_OBJECT_MISSING` naming exactly what the chain says should
 * exist and does not.
 */
export declare function verifyByoObjectsPresent(client: Client, repoId: string, options?: VaultMirrorSyncOptions): Promise<VaultByoPresenceReport>;
//# sourceMappingURL=vault-mirror.d.ts.map