export interface UserEntry {
    userId: string;
    pin: string;
}
export interface AdminEntry {
    userId: string;
    role: "owner" | "admin";
}
export interface AdminWriteInput {
    userId: string;
    pin: string;
    role: "owner" | "admin";
    usersFile: string;
    accountDir: string;
    caller: string;
}
export interface AdminWriteResult {
    usersJsonResult: "ok" | "fail" | "noop";
    accountJsonResult: "ok" | "fail" | "noop";
    usersError?: string;
    accountError?: string;
}
/**
 * Write a single admin entry across both auth stores (users.json + account.json admins[]).
 *
 * Idempotent on userId: if the userId already exists in users.json, the PIN
 * field is updated in place rather than duplicated; admins[] is checked for
 * presence before pushing.
 *
 * Always emits exactly one `[admins-write] caller=… userId=<prefix> usersJsonResult=… accountJsonResult=…`
 * line — success and failure paths both fire it. Operators grep for this single
 * predicate when reconstructing a partial-write incident.
 */
export declare function writeAdminEntry(input: AdminWriteInput): AdminWriteResult;
export interface AdminRemoveInput {
    userId: string;
    accountDir: string;
    caller: string;
}
export interface AdminRemoveResult {
    accountJsonResult: "ok" | "fail" | "noop";
    accountError?: string;
}
/**
 * Remove a single admin entry from account.json admins[] — does NOT touch
 * users.json (the device-level entry is preserved because the user may admin
 * other accounts). Single-file operation; the [admins-write] line records
 * `usersJsonResult=skip` so the grep-by-helper-call still picks it up.
 */
export declare function removeAdminFromAccount(input: AdminRemoveInput): AdminRemoveResult;
export interface InvariantCheckInput {
    /** Absolute path to users.json (persistent location). */
    usersFile: string;
    /** Absolute path to the accounts root (e.g. <INSTALL_DIR>/data/accounts). */
    accountsDir: string;
    /** Tag for the log prefix — `install-invariant` or `admin-invariant`. */
    tag: "install-invariant" | "admin-invariant";
}
export interface InvariantCheckResult {
    divergences: number;
    /** Userids in account.json admins[] that have no row in users.json. */
    accountWithoutUsers: Array<{
        userId: string;
        source: string;
    }>;
    /** Userids in users.json that no account.json admins[] references. */
    usersWithoutAccount: Array<{
        userId: string;
    }>;
}
/**
 * Walk every account.json under accountsDir and compare its admins[] to
 * users.json. Emits one log line per divergence and one summary line.
 *
 * Behaviour: log-only — does NOT throw, does NOT refuse boot or install.
 * Pre-Task-904 installs that already diverged would otherwise brick on the
 * first boot of a Task-904 device. The summary line `divergences=<n>` is
 * always emitted (wired-up assertion); per-divergence lines fire only when
 * divergences > 0. Operators grep `[install-invariant]` or `[admin-invariant]`
 * to detect the regression class without reading every install log.
 *
 * Promotion to refuse-or-degrade is a future sprint; capture as a TODO once
 * the deployed fleet has been audited clean.
 */
export declare function checkAdminAuthInvariant(input: InvariantCheckInput): InvariantCheckResult;
//# sourceMappingURL=index.d.ts.map