/// <reference types="node" />
export interface TelemetryConfig {
    enabled?: boolean;
    heartbeatIntervalMs?: number;
    samplingRate?: number;
    errorMaxCount?: number;
    /** Pins telemetry identity across process restarts. */
    clientId?: string;
}
export interface TelemetryMetric {
    request_count: number;
    success_count: number;
    error_count: number;
    avg_latency_ms: number;
    p99_latency_ms: number;
    max_latency_ms: number;
}
export interface TelemetryOperationMetrics {
    operation: string;
    global: TelemetryMetric;
    collection_metrics: Record<string, TelemetryMetric>;
}
export interface TelemetrySnapshot {
    timestamp: number;
    end_time: number;
    metrics: TelemetryOperationMetrics[];
}
export interface TelemetryError {
    timestamp: number;
    operation: string;
    error_msg: string;
    collection?: string;
    request_id?: string;
}
export interface ClientCommand {
    command_id: string;
    command_type: string;
    payload?: Uint8Array | Buffer | string;
    create_time?: number | string;
    persistent?: boolean;
    target_scope?: string;
}
export interface CommandReply {
    command_id: string;
    success: boolean;
    error_message?: string;
    payload?: Buffer;
}
export type CommandHandler = (command: ClientCommand) => CommandReply | Promise<CommandReply>;
export interface OperationRecord {
    operation: string;
    collection: string;
    startTime: number;
    error?: unknown;
    requestId?: string;
}
type HeartbeatSender = (request: Record<string, unknown>) => Promise<any>;
export declare class ClientTelemetryManager {
    readonly clientId: string;
    readonly stableClientId: boolean;
    ready: boolean;
    configHash: string;
    lastCommandTimestamp: number;
    lastHeartbeatError: unknown;
    private readonly sender;
    private sdkVersion;
    private readonly userProvider;
    private readonly databaseProvider;
    private readonly configProvider;
    private readonly senderEpochProvider;
    private readonly collectors;
    private readonly errors;
    private readonly snapshots;
    private readonly snapshotLatencySamples;
    private readonly pendingReplies;
    private readonly executedCommands;
    private readonly handlers;
    private readonly enabledCollections;
    private allCollectionsEnabled;
    private enabled;
    private heartbeatIntervalMs;
    private samplingRate;
    private readonly errorMaxCount;
    private samplingAccum;
    private unsupportedStreak;
    private timer?;
    private stopped;
    private lastSnapshotEnd;
    private commandQueue;
    private readonly commandHandlerScope;
    constructor(options: {
        sender: HeartbeatSender;
        config?: TelemetryConfig;
        sdkVersion?: string;
        userProvider?: () => string;
        databaseProvider?: () => string;
        configProvider?: () => Record<string, unknown>;
        senderEpochProvider?: () => number;
    });
    start(): void;
    setSdkVersion(version: string): void;
    stop(): void;
    isSupported(): boolean;
    getConfig(): Required<TelemetryConfig>;
    registerCommandHandler(type: string, handler: CommandHandler): void;
    recordOperation(record: OperationRecord): void;
    getRecentErrors(maxCount?: number): TelemetryError[];
    getMetricsSnapshots(): TelemetrySnapshot[];
    processCommands(commands: ClientCommand[]): Promise<void>;
    private enqueueCommandBatch;
    private processCommandBatch;
    static calculateConfigHash(commands: ClientCommand[]): string;
    private heartbeatLoop;
    private scheduleNextHeartbeat;
    private nextHeartbeatDelay;
    private sendHeartbeat;
    /**
     * Decide whether this operation is recorded, spreading the sampled ones evenly rather
     * than in runs.
     *
     * Each call adds the rate to an accumulator and samples on the call that carries it
     * across a whole unit: at 0.25 that is every fourth operation. The ratio has to hold
     * over any stretch of calls, not only over a long one -- metrics are reported per
     * heartbeat window, and a window is tens or hundreds of operations, so sampling a
     * contiguous run would make each window either complete or empty.
     */
    private shouldSample;
    private createSnapshot;
    private pruneSnapshots;
    private filterMetricsForWire;
    private handleCommand;
    private registerDefaultHandlers;
}
export declare function newClientRequestId(): string;
export {};
