/**
 * watchFileWhenAvailable — single-owner watcher that survives
 * mount/unmount races.
 *
 * Several screens (LogViewer, ReportViewer) share the same file-watch
 * pattern: try `fs.watch(path)` immediately; if the file doesn't exist
 * yet, fall back to polling `fs.accessSync` until it appears, then swap
 * the polling interval out for a real `fs.watch` handle. The naive
 * version of that pattern stored the watcher and the interval in two
 * separate closure variables, so unmount cleanup could fire BETWEEN
 * `clearInterval` and the new `eventPlanWatcher = fs.watch(...)`
 * assignment — leaking the watcher (the closed-over reference is still
 * `undefined` when cleanup runs) and double-firing `onAvailable`.
 *
 * This helper takes ownership of both handles inside a single closure
 * and exposes one `dispose()`. Cleanup reads-and-clears each handle
 * atomically inside the synchronous dispose call, so a mid-poll race
 * either:
 *   - hasn't attached the watcher yet (interval is cleared, never
 *     attaches), or
 *   - has already attached the watcher (close fires), or
 *   - is mid-attach but the `disposed` flag short-circuits before
 *     storing the handle (the local watcher returned from `fs.watch` is
 *     closed inline).
 *
 * Always returns a `dispose` function. Call it from the cleanup return
 * of the owning `useEffect`.
 */
import * as fs from 'node:fs';
export interface WatchFileWhenAvailableOptions {
    /** Path to watch. May not exist yet. */
    filePath: string;
    /**
     * Called once the watcher is attached AND on each subsequent change
     * event. Also called immediately when polling discovers the file for
     * the first time so the caller can read initial contents.
     */
    onChange: () => void;
    /** Poll cadence in ms while the file is missing. Defaults to 1000. */
    pollMs?: number;
    /**
     * Test injection points. Defaults are the real Node APIs.
     * Returning `undefined` from `watch` means "watch attempt failed —
     * fall back to polling".
     */
    watch?: (target: string, listener: () => void) => fs.FSWatcher | undefined;
    accessSync?: (target: string) => void;
    setIntervalFn?: (handler: () => void, ms: number) => ReturnType<typeof setInterval>;
    clearIntervalFn?: (handle: ReturnType<typeof setInterval>) => void;
}
export interface WatchFileWhenAvailableHandle {
    /** Test-only inspection — true while a real watcher is attached. */
    isWatching: () => boolean;
    /** Idempotent. Closes watcher, clears poll, and prevents future attaches. */
    dispose: () => void;
}
export declare function watchFileWhenAvailable(opts: WatchFileWhenAvailableOptions): WatchFileWhenAvailableHandle;
