/**
 * Generic account subscription manager using Solana programNotifications.
 * Framework-agnostic — consumers provide error/log callbacks for observability.
 *
 * Features:
 * - Ref-counted: first listener starts the WS, last unsubscribe tears it down.
 * - Slot-based ordering + buffer dedup (skips unchanged data, updates slot only).
 * - Auto-reconnect via {@link runReconnectLoop}.
 * - Decode/listener throws are reported but DO NOT trigger reconnect.
 * - Per-listener `onReconnect` for state refresh after WS recovery; cleaned
 *   up on unsubscribe so departed listeners' hooks cannot fire later.
 */
import { type Address, type Base58EncodedBytes, type Commitment, type RpcSubscriptions, type Slot, type SolanaRpcSubscriptionsApi } from '@solana/kit';
import { type SubscriptionHandle } from './subscriptionHandle';
import type { UpdateScheduler } from './wsUpdateScheduler';
export type SubscriptionCallback = (address: Address, buffer: Uint8Array, slot: Slot) => void;
export type SubscriptionMode = 'ws' | 'idle';
export type SubscriptionErrorHandler = (error: unknown) => void;
export type SubscriptionLogger = (...args: unknown[]) => void;
export type ProgramFilter = Readonly<{
    dataSize: bigint;
}> | Readonly<{
    memcmp: Readonly<{
        offset: bigint;
        bytes: Base58EncodedBytes;
        encoding: 'base58';
    }>;
}>;
export interface AccountSubscriptionManagerConfig {
    wsRpc: RpcSubscriptions<SolanaRpcSubscriptionsApi>;
    onError?: SubscriptionErrorHandler;
    onLog?: SubscriptionLogger;
    reconnectDelayMs?: number;
}
export interface SubscribeProgramAccountsOptions {
    commitment?: Commitment;
    /** Called after WS reconnects, before resuming the notification loop.
     *  Use to refresh state that may have drifted during downtime.
     *
     *  Per-listener: each subscriber's hook is tracked independently and
     *  cleaned up on `unsubscribe()`. The hook invoked on each reconnect is
     *  the most recently registered one still attached (latest wins), so a
     *  subscriber whose hook is currently in use can leave without leaving
     *  a dangling reference.
     *
     *  The manager wraps the call in retry-with-exponential-backoff (capped
     *  at 30s, 5 attempts). A throwing hook is reported through `onError`
     *  per attempt; after the max, we give up and proceed with cached state.
     *  Aborts cleanly on `unsubscribe()`. */
    onReconnect?: () => void | Promise<void>;
    /** Request a delivery cadence of at most one per N ms. The actual cadence
     *  is the minimum of all subscribers' demands (**shortest wins**) — your
     *  callback may fire faster than your own `throttleMs` if another
     *  subscriber asked for less.
     *
     *  - A subscriber that omits `throttleMs` adds no demand and inherits the
     *    existing cadence. To guarantee strictly immediate delivery, ensure
     *    no other subscriber on the same `(programId, commitment, filters)`
     *    key sets a `throttleMs` — otherwise their throttle wins.
     *  - A throttled subscriber joining an unthrottled key silently throttles
     *    the original subscriber (intentional — fast wins, no data loss).
     *
     *  Required when `scheduler` is set (sets the group cadence). */
    throttleMs?: number;
    /** Cross-stream flush scheduler — registers an updater under `throttleMs`
     *  in the scheduler's group map. Drains the buffer on each scheduler tick
     *  instead of running an own setTimeout.
     *
     *  Per-listener tracking: each subscriber's scheduler is recorded, and
     *  the **active** scheduler is the FIRST one passed (insertion order).
     *  Subscribers that omit `scheduler` don't contribute, so a no-scheduler
     *  subscriber doesn't block a later one from establishing the active
     *  scheduler. If a subscriber passes a scheduler DIFFERENT from the
     *  active one, the manager logs (via `onLog`) and records the demand
     *  anyway — that scheduler will take over only if every listener owning
     *  the currently-active scheduler unsubscribes.
     *
     *  On unsubscribe, the active scheduler is recomputed and the buffered-
     *  drain registration moves to the next scheduler in line (or falls back
     *  to a self-managed timer if none remain). This prevents holding a dead
     *  reference to a scheduler whose owner has departed.
     *
     *  Note: this subscription's scheduler-group cadence follows the
     *  shortest-wins effective `throttleMs`. If a later subscriber to the
     *  same key passes a shorter `throttleMs` (with or without scheduler),
     *  the scheduler-group registration moves to the faster cadence — your
     *  other subscriptions registered under the original cadence will no
     *  longer flush together with this one. */
    scheduler?: UpdateScheduler;
}
export declare class AccountSubscriptionManager {
    private subscriptions;
    private nextListenerId;
    private wsRpc;
    private onError;
    private onLog;
    private reconnectDelayMs;
    constructor(config: AccountSubscriptionManagerConfig);
    /**
     * Subscribe to program account changes. First subscriber for a key starts
     * the WS; last unsubscribe tears it down. Late subscribers replay any
     * cached account data immediately.
     */
    subscribeProgramAccounts(programId: Address, filters: readonly ProgramFilter[], callback: SubscriptionCallback, options?: SubscribeProgramAccountsOptions): SubscriptionHandle;
    /**
     * Drain any buffered notifications immediately. With `commitment`, flushes
     * just that subscription; without, flushes all matching programId+filters
     * across all commitments.
     *
     * No-op if unbuffered or empty. Cadence timers keep ticking — next firing
     * may be a no-op since the buffer was just cleared.
     */
    flushPending(programId: Address, filters: readonly ProgramFilter[], commitment?: Commitment): void;
    getMode(programId: Address, filters: readonly ProgramFilter[], commitment?: Commitment): SubscriptionMode;
    destroy(): void;
    /** Resolves when the WS subscription is established.
     *
     *  Throws if no subscription matches `(programId, filters, commitment)` —
     *  silently resolving used to make caller typos (wrong commitment, missing
     *  prior `subscribeProgramAccounts`, stale filter array) look like a
     *  successful wait. Failing loudly surfaces the sequencing bug at the
     *  call site. */
    waitForConnection(programId: Address, filters: readonly ProgramFilter[], commitment?: Commitment): Promise<void>;
    private buildKey;
    /** Direct lookup with `commitment`; fan-out scan without. */
    private findSubscription;
    /** Re-wire cadence machinery after a demands change. Fast no-op if effective throttle didn't change. */
    private recomputeEffectiveThrottle;
    /** Re-pick the active scheduler from current demands and re-wire the
     *  group registration if the choice changed. */
    private recomputeActiveScheduler;
    private tearDownActiveCadence;
    private attachToSchedulerGroup;
    private flushOrphanedBuffer;
    private rearmTimerForBufferedData;
    /** No-op if a timer is already armed. */
    private armThrottleDrainTimer;
    private flushSubscription;
    private createSubscription;
    private startWs;
    private handleNotification;
    private deliverByCadence;
    private drainBufferedNotifications;
    private fireListeners;
    private teardown;
    /** Sleep `ms`, but resolve immediately on abort — mirrors the pattern in
     *  runReconnectLoop so teardown cancels in-flight reconnect-hook retries. */
    private static abortableSleep;
    /** Calls the latest registered `onReconnect` hook with bounded retry-with-
     *  backoff. The manager is the documented wrapper for runReconnectLoop's
     *  best-effort `onBeforeReconnect` contract — failing the hook silently
     *  would let listeners resume with stale state (e.g. borrowOrderFills
     *  misclassifying new fills against pre-downtime obligations).
     *
     *  After {@link RECONNECT_HOOK_MAX_RETRIES} consecutive failures we give
     *  up and proceed anyway: an indefinitely failing hook would block the
     *  WS forever, which is worse than stale state. The error reporter sees
     *  every failure regardless. */
    private runReconnectHookWithRetry;
}
//# sourceMappingURL=accountSubscriptionManager.d.ts.map