import { type CommandParser } from '../../client/parser';
import type { RequestRouter, RoutedCommand } from './dispatch';
type ClusterSlots = Parameters<RequestRouter>[0];
/**
 * Cluster-wide SCAN (server `request_policy: special` + `response_policy:
 * special`). SCAN cursors are per-node state, so the cluster iteration walks
 * the masters one at a time behind a *virtual* cursor:
 *
 *  - `SCAN 0` starts a chain on the first master.
 *  - Each reply's server cursor is swapped for a client-minted token that maps
 *    back to (serving node, real cursor, masters already exhausted). The
 *    caller keeps its usual `cursor !== "0"` loop; the token is opaque.
 *  - When a node's cursor returns 0 the chain advances to the next unvisited
 *    master (fresh cursor 0); when every master is exhausted the caller
 *    finally sees "0".
 *
 * The visited set is tracked by node address, so a topology change mid-scan
 * neither rescans a surviving node nor gets stuck on a departed one. The usual
 * SCAN guarantees apply per node; keys migrating between nodes mid-iteration
 * may be missed or duplicated — same caveat as every cluster-wide scan.
 */
export declare const routeScan: RequestRouter;
/**
 * Post-reply hook for SCAN (invoked from `_executeWithPolicies` after the
 * reducer, like `finalizeFtCursor`): advances the chain state and swaps
 * the server cursor in the reply for the chain's virtual token. No-op for any
 * other command or a non-single-target plan. Returns the (possibly rewritten)
 * reply.
 */
export declare function finalizeScanCursor(slots: ClusterSlots, parser: CommandParser, plan: ReadonlyArray<RoutedCommand>, reply: unknown): unknown;
export {};
//# sourceMappingURL=scan-cursor.d.ts.map