/**
 * Phase 8 — auth.db column upgrades for per-user secret encryption.
 *
 * Two tables in `auth.db` carry per-user secrets:
 *
 *   1. `oauth_tokens.data_json` (TEXT NOT NULL) holds the full MCP OAuth
 *      payload (tokens + client info + code verifier) for a user+connector.
 *      Its value is a JSON blob containing the access/refresh tokens.
 *   2. `user_preferences.settings_json` (TEXT NOT NULL DEFAULT '{}') holds
 *      a free-form per-user key/value map. Today the only secret it
 *      carries is the Deepgram key (meeting capture); the rest is
 *      non-secret prefs (default folder, calendar config). Discrimination
 *      is registry-driven — any key whose registry entry is
 *      `user-secret` moves to the new ciphertext column.
 *
 * Strategy:
 *
 *   - `oauth_tokens`: SQLite cannot ALTER a TEXT NOT NULL column to be
 *     nullable. The standard pattern is a transactional table rebuild
 *     (CREATE NEW + INSERT...SELECT + DROP + RENAME). We do that, with
 *     the per-row encryption running in the Node loop between SELECT and
 *     INSERT.
 *   - `user_preferences`: column additions are easy (no constraints
 *     block us), so we just ALTER to add `settings_ciphertext` and
 *     `key_version`, then walk each row and partition keys by
 *     classification.
 *
 * Safety:
 *
 *   - Before any DDL, `auth.db` is copied to
 *     `auth.db.backup.<unix-ts-ms>`. If the backup write fails, the
 *     migration aborts before touching the source DB.
 *   - The rebuild runs inside a single transaction. SQLite atomic
 *     semantics give us rollback on any per-row encryption failure.
 *   - A row-count integrity check fires before COMMIT; mismatch
 *     triggers ROLLBACK and a thrown error.
 *   - Idempotent: completion is recorded in a new `meta` table.
 *     Re-running is a fast no-op.
 *   - Half-state guard: at boot we refuse to start if we find
 *     `data_json IS NOT NULL AND data_ciphertext IS NOT NULL` on any
 *     row — that means a previous run committed partial state.
 *
 * AAD binding for every encrypted blob:
 *
 *   `{ scope: 'user', scopeId: <user_id>, key: <column>, keyVersion: 'mk_v1' }`
 *
 * Swapping a ciphertext between users invalidates the AAD; tampering
 * with the row triggers AEAD failure on decrypt.
 */
import Database from 'better-sqlite3';
import { type EncryptedRow } from './encryption.js';
export interface AuthDbMigrationResult {
    /** True when the meta row already records prior completion. */
    skipped: boolean;
    /** Rows rewritten in oauth_tokens. */
    oauthRowsMigrated: number;
    /** Rows in user_preferences that had at least one secret key partitioned out. */
    prefsRowsMigrated: number;
    /** Path of the on-disk backup; absent when skipped. */
    backupPath?: string;
}
export interface AuthDbMigrationOptions {
    authDbPath: string;
    masterKey: Uint8Array;
    /** Defaults to 'mk_v1'. */
    keyVersion?: string;
}
/**
 * Run the Phase 8 auth.db migration. Idempotent; returns immediately
 * with `skipped: true` once the meta row is present.
 *
 * Caller MUST hold the only open handle to auth.db while this runs —
 * the migration opens its own Database connection internally so that
 * AuthService's WAL/foreign-keys configuration doesn't bleed in.
 * In `serve.ts` this runs before AuthService is constructed.
 */
export declare function migrateAuthDbPhase8(opts: AuthDbMigrationOptions): AuthDbMigrationResult;
/**
 * Public helper for AuthService to invoke at construction time once the
 * migration is known to be complete (or didn't need to run on a fresh
 * DB). On a freshly-created DB this writes the meta row so future
 * `migrateAuthDbPhase8` calls short-circuit.
 */
export declare function markAuthDbPhase8Migrated(db: Database.Database): void;
export declare function isAuthDbPhase8Migrated(db: Database.Database): boolean;
/**
 * Half-state detector for the live AuthService boot. Caller-friendly:
 * returns true when migration appears complete-and-consistent. Throws
 * on the corrupted shape (data_json non-null on a row that also has
 * data_ciphertext) — that's evidence a previous run committed partial
 * state and we'd rather refuse to start than serve corrupt OAuth data.
 */
export declare function assertAuthDbConsistent(db: Database.Database): void;
/**
 * Map legacy `user_preferences.settings_json` keys to canonical registry
 * names. The migration uses this to classify pre-existing rows; new
 * writes through the API will use canonical names directly (Phase 8
 * API update lands alongside the migration).
 */
export declare const LEGACY_PREFS_KEY_TO_REGISTRY: Record<string, string>;
/**
 * Helper used by AuthService when reading user_preferences. Given a
 * row's plaintext `settings_json` and optional `settings_ciphertext`,
 * return the merged object. Decryption errors throw — the caller
 * should let them propagate (corrupt or wrong-key data is a hard
 * fail, not a silent empty object).
 */
export declare function decryptUserPreferencesSettings(masterKey: Uint8Array, userId: number, settingsJson: string | null | undefined, settingsCiphertext: string | null | undefined, keyVersion: string | null | undefined): Record<string, unknown>;
/**
 * Encrypt the secret subset of a user_preferences object for storage.
 * Returns the pair (settings_json plaintext, settings_ciphertext) to
 * write into the row. The caller (AuthService.setUserSettings) is
 * responsible for the full merged write.
 */
export declare function encryptUserPreferencesSettings(masterKey: Uint8Array, userId: number, merged: Record<string, unknown>, keyVersion?: string): {
    settingsJson: string;
    settingsCiphertext: string | null;
    keyVersion: string | null;
};
/**
 * Encrypt an oauth_tokens row's data payload for storage. The AAD is
 * bound to the owning user_id so a row swap is detected on decrypt.
 */
export declare function encryptOAuthTokenData(masterKey: Uint8Array, userId: number, dataJson: string, keyVersion?: string): EncryptedRow;
/**
 * Decrypt an oauth_tokens row's ciphertext. Throws on AAD mismatch,
 * tampering, or wrong key — callers should let the error propagate.
 */
export declare function decryptOAuthTokenData(masterKey: Uint8Array, userId: number, ciphertext: string, keyVersion: string | null | undefined): string;
