/**
 * Remote Substrate — Reconnect Engine
 *
 * Implements reconnect with handshake tokens, epoch tracking,
 * replay from last acknowledged offset, and idempotent command submission.
 *
 * The reconnect engine drives the transport state machine:
 *   disconnected → initializing → authenticating → connected → syncing → degraded
 *   → reconnecting → ... (retry loop)
 *   → terminal_failure (max attempts exceeded or non-retryable error)
 */
import type { HandshakeToken, ReplayConfig, DurableIdentity, RetryPolicy, TransportErrorCategory, NegotiatedProtocol } from './types.js';
/** Outcome of a connect/reconnect attempt. */
export type ConnectOutcome = {
    readonly success: true;
    readonly token: HandshakeToken;
    readonly epoch: number;
    readonly replayFromOffset: number;
    /** Negotiated protocol agreed during handshake. */
    readonly negotiatedProtocol: NegotiatedProtocol;
} | {
    readonly success: false;
    readonly category: TransportErrorCategory;
    readonly error: string;
    readonly retryable: boolean;
    /**
     * Incompatibility code when the failure is due to version mismatch.
     * Absent for auth/network failures.
     */
    readonly incompatibilityCode?: 'major_version_mismatch' | 'peer_version_too_old' | 'peer_version_unsupported';
};
/**
 * Adapter interface — callers implement the actual transport operations.
 *
 * The reconnect engine delegates real I/O to this adapter, keeping itself
 * transport-agnostic (WebSocket, HTTP, stdio all implement the same adapter).
 */
export interface TransportAdapter {
    /**
     * Attempt to establish a connection and perform the handshake.
     *
     * Implementations must:
     * 1. Open the transport channel
     * 2. Send HANDSHAKE_INIT with identity, epoch, lastAckedOffset, authToken,
     *    and the local `protocolVersion` from CURRENT_PROTOCOL_VERSION
     * 3. Wait for HANDSHAKE_ACCEPT or HANDSHAKE_REJECT
     * 4. On HANDSHAKE_ACCEPT, extract `negotiatedProtocol` and return it in the outcome
     * 5. On HANDSHAKE_REJECT with an `incompatibilityCode`, return success=false with
     *    that code — the engine will treat it as a terminal (non-retryable) failure
     *
     * @param identity - Stable durable identity to present.
     * @param lastAckedOffset - Offset to replay from.
     * @param authToken - Bearer token from the AuthProvider.
     * @returns ConnectOutcome — success with token+negotiatedProtocol or failure with category.
     */
    connect(identity: DurableIdentity, lastAckedOffset: number, authToken: string): Promise<ConnectOutcome>;
    /** Disconnect the transport cleanly. */
    disconnect(): Promise<void>;
    /**
     * Called after a successful handshake to replay messages since lastAckedOffset.
     * The adapter fetches and delivers replayed messages via its normal receive path.
     */
    requestReplay(fromOffset: number, maxCount: number): Promise<void>;
}
/** Lifecycle event callbacks fired by the reconnect engine. */
export interface ReconnectEngineCallbacks {
    /** Called when version negotiation produces a downgrade. Incompatible = terminal failure. */
    onVersionNegotiated?(protocol: NegotiatedProtocol): void;
    /** Called when the transport enters 'initializing'. */
    onInitializing?(attempt: number): void;
    /** Called when authentication is in progress. */
    onAuthenticating?(): void;
    /** Called when the connection is successfully established. */
    onConnected(token: HandshakeToken, epoch: number): void;
    /** Called when state sync is in progress after connect. */
    onSyncing?(): void;
    /** Called when a reconnect attempt is scheduled. */
    onReconnecting?(attempt: number, maxAttempts: number, delayMs: number): void;
    /** Called when the transport is disconnected (willRetry indicates intent). */
    onDisconnected?(reason?: string, willRetry?: boolean): void;
    /** Called when all retries are exhausted — terminal failure. */
    onTerminalFailure(error: string): void;
}
/**
 * ReconnectEngine — manages the full reconnect lifecycle with backoff and replay.
 *
 * Usage:
 * ```ts
 * const engine = new ReconnectEngine(adapter, identity, replayConfig, callbacks);
 * await engine.connect(); // blocks until connected or terminal failure
 * // After a failure detected externally:
 * await engine.reconnect(); // drives the retry loop
 * engine.dispose(); // cancel any pending reconnect
 * ```
 */
export declare class ReconnectEngine {
    private readonly adapter;
    private readonly identity;
    private readonly callbacks?;
    private readonly _policy;
    private readonly _replay;
    private _handshakeToken;
    private _epoch;
    private _lastAckedOffset;
    private _attempts;
    private _disposed;
    private _pendingTimer;
    /** Negotiated protocol from the last successful handshake. */
    private _negotiatedProtocol;
    constructor(adapter: TransportAdapter, identity: DurableIdentity, replayConfig?: Partial<ReplayConfig>, callbacks?: ReconnectEngineCallbacks | undefined, reconnectPolicy?: Partial<RetryPolicy>);
    /** Current handshake token (undefined until first successful connect). */
    get handshakeToken(): HandshakeToken | undefined;
    /** Current server epoch. */
    get epoch(): number;
    /** Offset of the last acknowledged message. */
    get lastAckedOffset(): number;
    /** Number of reconnect attempts since last successful connect. */
    get attempts(): number;
    /**
     * The negotiated protocol from the last successful handshake.
     * Undefined until the first successful connect.
     */
    get negotiatedProtocol(): NegotiatedProtocol | undefined;
    /**
     * Update the last acknowledged offset.
     * Call this whenever an ack is sent or a message is durably processed.
     *
     * @param offset - The offset to record as acknowledged.
     */
    ackOffset(offset: number): void;
    /**
     * Perform the initial connect attempt.
     *
     * @param authToken - Bearer token from the AuthProvider.
     * @returns True on success, false on terminal failure.
     */
    connect(authToken: string): Promise<boolean>;
    /**
     * Drive the reconnect retry loop.
     *
     * Attempts reconnection up to `policy.maxAttempts` times using
     * exponential backoff with jitter. Calls callbacks at each state transition.
     *
     * @param getAuthToken - Called before each attempt to get a fresh token.
     * @returns True if eventually connected, false on terminal failure.
     */
    reconnect(getAuthToken: () => Promise<string>): Promise<boolean>;
    /** Cancel any pending reconnect timer and mark engine as disposed. */
    dispose(): void;
    private _attemptConnect;
    private _sleep;
}
/**
 * Generate an idempotent submission key for a command.
 *
 * The key combines the session ID with a random UUID so that retried
 * submissions with the same key can be deduplicated by the server.
 *
 * @param sessionId - Durable session ID.
 * @returns A stable key string for use as `idempotencyKey`.
 */
export declare function generateIdempotencyKey(sessionId: string): string;
//# sourceMappingURL=reconnect.d.ts.map