import type { Constructable, FilterType, FindOptions, PhysicalStore } from '@furystack/core';
import { EventHub, type ListenerErrorPayload } from '@furystack/utils';
import { promises } from 'fs';
/**
 * {@link PhysicalStore} backed by a JSON file on disk.
 *
 * Reads on construction, holds entities in an {@link InMemoryStore}, and flushes
 * pending writes on a `tickMs` interval (default 3000 ms). External edits to the
 * file are picked up via an `fs.watch` watcher that triggers {@link reloadData}.
 *
 * Disposal is async — `[Symbol.asyncDispose]` flushes pending changes, closes
 * the watcher, and clears the interval. Owners must `await` disposal or rely on
 * `await using` / {@link defineStore}'s `onDispose` hook to avoid lost writes.
 *
 * **Init race:** the constructor schedules the initial reload in the
 * background. Calls to `get` / `find` / `count` issued before the reload
 * resolves see an empty cache. Failures during the background reload (other
 * than `ENOENT`) are surfaced via `onLoadError` rather than thrown.
 *
 * Re-emits `onEntityAdded` / `onEntityUpdated` / `onEntityRemoved` from the
 * underlying in-memory store, plus `onWatcherError` (sync watcher setup
 * failure) and `onLoadError` (async file-load failure) for diagnostics.
 */
export declare class FileSystemStore<T, TPrimaryKey extends keyof T> extends EventHub<{
    onEntityAdded: {
        entity: T;
    };
    onEntityUpdated: {
        id: T[TPrimaryKey];
        change: Partial<T>;
    };
    onEntityRemoved: {
        key: T[TPrimaryKey];
    };
    onWatcherError: {
        error: unknown;
    };
    onLoadError: {
        error: unknown;
    };
    onListenerError: ListenerErrorPayload;
}> implements PhysicalStore<T, TPrimaryKey, T> {
    private readonly options;
    private readonly watcher?;
    readonly model: Constructable<T>;
    readonly primaryKey: TPrimaryKey;
    private readonly inMemoryStore;
    private get cache();
    remove(...keys: Array<T[TPrimaryKey]>): Promise<void>;
    private tick;
    private _hasChanges;
    /** Whether the in-memory cache has unflushed mutations. Read-only externally. */
    get hasChanges(): boolean;
    get(key: T[TPrimaryKey], select?: Array<keyof T>): Promise<T | undefined>;
    add(...entries: T[]): Promise<import("@furystack/core").CreateResult<T>>;
    find<TFields extends Array<keyof T>>(filter: FindOptions<T, TFields>): Promise<import("@furystack/core").PartialResult<T, TFields>[]>;
    count(filter?: FilterType<T>): Promise<number>;
    /**
     * Writes the in-memory cache to disk if {@link hasChanges} is set. No-op
     * otherwise — the periodic tick calls this on every interval but only the
     * first call after a mutation actually touches the filesystem.
     */
    saveChanges(): Promise<void>;
    /**
     * Flushes pending changes, closes the FS watcher and clears the tick interval.
     * Must be awaited — skipping `await` risks losing the final write.
     */
    [Symbol.asyncDispose](): Promise<void>;
    /**
     * Replaces the in-memory cache with the contents of the backing file. Called
     * on construction and on every FS watcher event. Missing file (`ENOENT`) is
     * silently ignored so first-run writes succeed against a fresh path.
     */
    reloadData(): Promise<void>;
    update(id: T[TPrimaryKey], data: T): Promise<void>;
    /**
     * Test seam — overridable to fault-inject the read path. Defaults to
     * `fs.promises.readFile`. Production code should not reassign.
     */
    readFile: typeof promises.readFile;
    /**
     * Test seam — overridable to fault-inject the write path. Defaults to
     * `fs.promises.writeFile`. Production code should not reassign.
     */
    writeFile: typeof promises.writeFile;
    constructor(options: {
        fileName: string;
        primaryKey: TPrimaryKey;
        tickMs?: number;
        model: Constructable<T>;
    });
}
//# sourceMappingURL=filesystem-store.d.ts.map