import { type CommandParser } from '../../client/parser';
import type { RedisClientType } from '../../client';
import type { RedisModules, RedisFunctions, RedisScripts, RespVersions, TypeMapping } from '../../RESP/types';
import type { KeySpec } from '../../commands/generic-transformers';
import type RedisClusterSlots from '../cluster-slots';
import { type ResponsePolicyWithDefaults } from '../../command-metadata/policies-constants';
type ClusterClient = RedisClientType<RedisModules, RedisFunctions, RedisScripts, RespVersions, TypeMapping>;
type ClusterSlots = RedisClusterSlots<RedisModules, RedisFunctions, RedisScripts, RespVersions, TypeMapping>;
/**
 * One unit of work a request policy schedules. Pass-through policies set only
 * `client` (run the original command on that node). `multi_shard` sets `parser`
 * (a per-slot sub-command, routed by its own `firstKey`) and `groupIndices`
 * (where its replies belong in the reassembled result).
 */
export type RoutedCommand = {
    client?: ClusterClient;
    getClient?: () => Promise<ClusterClient>;
    parser?: CommandParser;
    groupIndices?: Array<number>;
};
export type RequestRouter = (slots: ClusterSlots, parser: CommandParser, isReadonly: boolean | undefined, keySpecs: ReadonlyArray<KeySpec> | undefined) => Promise<Array<RoutedCommand>>;
export type ResponseReducer<T> = (responsePromises: Promise<T>[], parser: CommandParser, 
/**
 * For `multi_shard` commands, `positionHints[p]` is the original 0-based
 * group ordinals carried by the p-th sub-command (plan order == promise
 * order). Reducers that preserve order (e.g. default-keyed MGET) use it to
 * scatter each sub-reply back into the caller's key order. `undefined`
 * entries mean "not split"; the whole array is absent for non-split commands.
 */
positionHints?: Array<Array<number> | undefined>) => Promise<T>;
export declare const routeAllNodes: RequestRouter;
export declare const routeAllShards: RequestRouter;
/**
 * Splits the command into one sub-command per hash slot (using the COMMAND key
 * specs as the reconstruction recipe) and returns a plan entry per slot. Each
 * entry carries its own sub-parser, so core `_execute` routes it by that
 * slot's `firstKey` and handles MOVED/ASK with the sub-command's own key.
 */
export declare const routeMultiShard: RequestRouter;
export declare const routeDefaultKeyless: RequestRouter;
export declare const routeDefaultKeyed: RequestRouter;
/**
 * Special-request routers. Looked up by `COMMAND SUBCOMMAND` first, then bare
 * `COMMAND` — SCAN registers bare because its second argument is a cursor,
 * which the naive `commandIdentifier` mistakes for a subcommand.
 */
export declare const SPECIAL_REQUEST_ROUTERS: Record<string, RequestRouter>;
/**
 * Router for the `special` request policy. Commands with a dedicated handler
 * (e.g. FT.CURSOR sticky routing, cluster-wide SCAN) short-circuit into
 * `SPECIAL_REQUEST_ROUTERS` first. Everything else has non-trivial routing no
 * generic rule captures and no handler yet: route to a single (random) node
 * like a keyless command so it still works, but warn — the reply reflects
 * only that one node.
 */
export declare const routeSpecial: RequestRouter;
/**
 * `one_succeeded`: first fulfilled reply wins. When every node rejects the
 * policy requires surfacing one of the shard errors (e.g. SCRIPT KILL's
 * NOTBUSY), not the opaque `AggregateError` that `Promise.any` throws.
 */
export declare const reduceOneSucceeded: <T>(promises: Promise<T>[]) => Promise<T>;
export declare const reduceAllSucceeded: <T>(promises: Promise<T>[]) => Promise<T>;
export declare const reduceLogicalAnd: <T>(promises: Promise<T>[]) => Promise<T>;
export declare const reduceLogicalOr: <T>(promises: Promise<T>[]) => Promise<T>;
export declare const reduceMin: <T>(promises: Promise<T>[]) => Promise<T>;
export declare const reduceMax: <T>(promises: Promise<T>[]) => Promise<T>;
export declare const reduceSum: <T>(promises: Promise<T>[]) => Promise<T>;
/**
 * RANDOMKEY under `all_shards`: each master returns a random key from its own
 * keyspace (or nil when empty). Return one of the non-nil replies at random so
 * the result is a valid random key across the whole cluster and never a
 * false-nil when some shard is empty but others hold keys. All shards empty →
 * nil.
 */
export declare const reduceRandomKey: <T>(promises: Promise<T>[]) => Promise<T>;
/**
 * Per-command reducers for the `special` response policy, keyed like
 * `SPECIAL_REQUEST_ROUTERS` (`COMMAND SUBCOMMAND`, bare-command fallback). A
 * `special` response needs command-specific merging that no generic rule
 * captures; commands absent here hit `reduceSpecial`'s generic fallback. SCAN
 * (response also tipped `special`) needs no entry: its plan is single-node, so
 * the fallback passes the sole reply through and the cursor rewrite happens in
 * `finalizeScanCursor`.
 */
export declare const SPECIAL_RESPONSE_REDUCERS: Record<string, ResponseReducer<unknown>>;
/**
 * Entry point for the `special` response policy: dispatch to a per-command
 * reducer if one exists, else fall back to the default-keyless reduction (sole
 * reply as is, or a merge of a fan-out) so the command works instead of
 * throwing. Warn on the fallback because the merged shape is unlikely to be
 * what the command really wants.
 */
export declare const reduceSpecial: <T>(promises: Promise<T>[], parser: CommandParser) => Promise<T>;
export declare const reduceDefaultKeyless: <T>(promises: Promise<T>[]) => Promise<T>;
export declare const reduceDefaultKeyed: <T>(promises: Promise<T>[], _parser: CommandParser, positionHints?: Array<Array<number> | undefined>) => Promise<T>;
/**
 * Response policies whose reducers compute over raw numbers (scalars or
 * number arrays). Per-node replies for these plans are decoded *without* the
 * caller's type mapping — a `NUMBER: String` mapping would otherwise feed
 * strings into the numeric aggregators and throw — and the caller's mapping
 * is applied to the aggregated result instead (`remapAggregateReply`).
 */
export declare const NUMERIC_AGG_POLICIES: ReadonlySet<ResponsePolicyWithDefaults>;
/**
 * Applies the caller's NUMBER type mapping to a numeric aggregate (scalar, or
 * an array for the element-wise reducers like SCRIPT EXISTS), so aggregated
 * fan-out replies keep the same shape a standalone client would return.
 * Aggregation itself runs in JS number space, so — unlike standalone decode —
 * a `NUMBER: String` mapping does not preserve integer precision above 2^53
 * (see cluster-policy-caveats.md).
 */
export declare function remapAggregateReply<T>(reply: T, typeMapping: TypeMapping | undefined): T;
export declare const REQUEST_ROUTERS: {
    readonly all_nodes: RequestRouter;
    readonly all_shards: RequestRouter;
    readonly multi_shard: RequestRouter;
    readonly special: RequestRouter;
    readonly "default-keyless": RequestRouter;
    readonly "default-keyed": RequestRouter;
};
export declare const RESPONSE_REDUCERS: {
    readonly one_succeeded: <T>(promises: Promise<T>[]) => Promise<T>;
    readonly all_succeeded: <T_1>(promises: Promise<T_1>[]) => Promise<T_1>;
    readonly agg_logical_and: <T_2>(promises: Promise<T_2>[]) => Promise<T_2>;
    readonly agg_logical_or: <T_2>(promises: Promise<T_2>[]) => Promise<T_2>;
    readonly agg_min: <T_2>(promises: Promise<T_2>[]) => Promise<T_2>;
    readonly agg_max: <T_2>(promises: Promise<T_2>[]) => Promise<T_2>;
    readonly agg_sum: <T_2>(promises: Promise<T_2>[]) => Promise<T_2>;
    readonly special: <T_3>(promises: Promise<T_3>[], parser: CommandParser) => Promise<T_3>;
    readonly "default-keyless": <T_4>(promises: Promise<T_4>[]) => Promise<T_4>;
    readonly "default-keyed": <T_5>(promises: Promise<T_5>[], _parser: CommandParser, positionHints?: Array<Array<number> | undefined>) => Promise<T_5>;
};
export {};
//# sourceMappingURL=dispatch.d.ts.map