/**
 * Cluster identity validation for split-brain prevention.
 *
 * In geo-distributed setups, orchestrators may use different connection strings
 * for the same logical DB and S3. URL comparison would falsely flag them as
 * different resources. cluster_id validates that orchestrators share the same
 * logical DB, and the S3 sentinel validates they share the same logical bucket.
 */
import type { Kysely } from 'kysely';
interface ClusterIdentityS3Client {
    getObject(bucket: string, key: string): Promise<string | null>;
    putObject(bucket: string, key: string, body: string): Promise<void>;
}
export interface ClusterIdentityDeps {
    db: Kysely<any>;
    s3Client?: ClusterIdentityS3Client;
    storageBucket?: string;
    /**
     * Optional storage prefix (mirrors `KICI_STORAGE_PREFIX`). When set, the
     * sentinel lives under that prefix (`<prefix>/.kici-cluster-id`) so multiple
     * clusters can share the same physical bucket as long as they use distinct
     * prefixes. When empty, the sentinel is at the bucket root.
     */
    storagePrefix?: string;
    /**
     * E2E escape hatch — when true, validateS3Sentinel logs a warning and
     * returns early. Mirrors the orchestrator's
     * `config.skipS3SentinelValidation` (KICI_SKIP_S3_SENTINEL_VALIDATION).
     */
    skipSentinelValidation?: boolean;
}
/**
 * Build the S3 key for the cluster identity sentinel under an optional prefix.
 * Strips any trailing slash from the prefix so callers can pass either form.
 */
export declare function clusterSentinelKey(prefix?: string): string;
export declare class ClusterIdentity {
    private readonly deps;
    constructor(deps: ClusterIdentityDeps);
    /** Read cluster_id from DB. Throws if not found (migration not run). */
    getClusterId(): Promise<string>;
    /**
     * Validate S3 sentinel file matches DB cluster_id.
     * - If no S3 configured, skip (filesystem-only deployment).
     * - If sentinel doesn't exist, write it (first orch to use this bucket).
     * - If sentinel exists and matches, success.
     * - If sentinel exists and doesn't match, throw error (different DB/bucket mismatch).
     */
    validateS3Sentinel(): Promise<void>;
    /**
     * Validate cluster identity at startup.
     * Logs cluster_id and instance_id for operational visibility, then runs
     * S3 sentinel check. Throws on misconfiguration (e.g., different cluster
     * using same DB/S3).
     */
    validateAtStartup(instanceId: string): Promise<string>;
}
export {};
//# sourceMappingURL=cluster-identity.d.ts.map