/**
 * Minimal Raft leader election implementation.
 *
 * Implements only leader election (no log replication) for cluster coordination.
 * State machine: follower -> candidate -> leader. State is persisted to Postgres
 * via RaftStateStore for crash recovery. Election timeout is 5-10s with randomized
 * jitter (WAN-appropriate per research). Leader sends heartbeats every 2s.
 *
 * Dormant mode: When peerRegistry has 0 connected peers, the node self-elects
 * immediately (single-orchestrator deployment). If peers connect later, normal
 * election resumes.
 *
 * Raft heartbeat (raft.append.entries every 2s) is separate from peer inventory
 * heartbeat (peer.heartbeat every 30s). Raft heartbeat is purely for leader
 * liveness detection.
 */
import type { RaftVoteRequest, RaftVoteResponse, RaftAppendEntries } from '@kici-dev/engine';
import type { PeerRegistry } from './peer-registry.js';
import type { RaftStateStore } from './raft-state.js';
export type RaftRole = 'follower' | 'candidate' | 'leader';
interface RaftNodeDeps {
    instanceId: string;
    stateStore: RaftStateStore;
    peerRegistry: PeerRegistry;
    broadcastToPeers: (msg: RaftVoteRequest | RaftAppendEntries) => void;
    onBecomeLeader: () => void;
    onLoseLeadership: () => void;
    electionTimeoutMinMs?: number;
    electionTimeoutMaxMs?: number;
    leaderHeartbeatMs?: number;
    /** Grace period in ms before dormant-mode self-election. Default: 0 (no grace period). */
    gracePeriodMs?: number;
}
export declare class RaftNode {
    private readonly instanceId;
    private readonly stateStore;
    private readonly peerRegistry;
    private readonly broadcastToPeers;
    private readonly onBecomeLeader;
    private readonly onLoseLeadership;
    private readonly electionTimeoutMinMs;
    private readonly electionTimeoutMaxMs;
    private readonly leaderHeartbeatMs;
    private readonly gracePeriodMs;
    private startedAt;
    private currentTerm;
    private votedFor;
    private leaderId;
    private role;
    private electionTimer;
    private leaderHeartbeatTimer;
    /** Votes received during the current election as candidate. */
    private votesReceived;
    /**
     * Consecutive elections where no peer responded with a vote.
     * When this exceeds the threshold, the node force-self-elects as a safety
     * valve against delayed WebSocket close detection (peer appears "connected"
     * but is actually dead).
     */
    private consecutiveUnansweredElections;
    constructor(deps: RaftNodeDeps);
    /**
     * Start the Raft node. Loads persisted state from DB and starts
     * as follower with election timer.
     */
    start(): Promise<void>;
    /**
     * Stop the Raft node. Clears all timers and persists state.
     */
    stop(): Promise<void>;
    /** Whether this node is the current leader. */
    isLeader(): boolean;
    /** Get the current known leader's instance ID. */
    getLeaderId(): string | null;
    /** Get the current Raft term. */
    getCurrentTerm(): number;
    /** Get the current role (for testing/diagnostics). */
    getRole(): RaftRole;
    /**
     * Handle a peer.leaving announcement from a gracefully shutting down peer.
     * If the leaving peer is the current leader, immediately clear leaderId and
     * start a new election. Otherwise, no election action (peer registry update
     * is done by the caller before calling this method).
     */
    handlePeerLeaving(instanceId: string): void;
    /**
     * Reset the election timer with a randomized timeout.
     * On expiry, starts an election.
     */
    resetElectionTimer(): void;
    private clearElectionTimer;
    /**
     * Notify Raft that a peer disconnected. If this node is a follower or
     * candidate, reset the election timer to a short value so Raft quickly
     * re-evaluates whether it should self-elect (dormant mode).
     * Without this, the node waits for the full election timeout (3-5s)
     * before discovering all peers are gone.
     */
    onPeerDisconnected(): void;
    /**
     * Start a new election. Increment term, vote for self, request votes
     * from peers. If no peers are connected, self-elect immediately
     * (dormant mode for single-orchestrator deployments).
     */
    private startElection;
    /**
     * Handle an incoming vote request from another candidate.
     */
    handleVoteRequest(msg: RaftVoteRequest): RaftVoteResponse;
    /**
     * Handle a vote response from a peer.
     */
    handleVoteResponse(msg: RaftVoteResponse): void;
    /**
     * Check if we have a majority of votes to become leader.
     * Cluster size = connected peers + self.
     */
    private checkMajority;
    /**
     * Transition to leader role. Start heartbeat timer, persist state,
     * call onBecomeLeader callback.
     */
    private becomeLeader;
    /**
     * Step down from leader/candidate to follower.
     */
    private stepDown;
    /**
     * Start sending periodic leader heartbeats (raft.append.entries).
     */
    private startLeaderHeartbeat;
    private sendHeartbeat;
    private clearLeaderHeartbeat;
    /**
     * Handle an incoming append entries (heartbeat) from a leader.
     */
    handleAppendEntries(msg: RaftAppendEntries): void;
}
export {};
//# sourceMappingURL=raft.d.ts.map