import { z } from 'zod';
/**
 * Per-device runtime state — cap-keyed. Mutable signals discovered
 * after boot live here, separate from `DeviceConfig` (operator
 * intent) and from `deviceCache` (immutable autodetect / abilities).
 *
 * Shape: `Record<capName, capStateSlice>`. Each slice's schema is
 * declared by the capability itself (`CapabilityDefinition.runtimeState`)
 * so that any provider implementing the cap inherits the same shape —
 * the BatteryStatus shape a Reolink cam emits is the same a Frigate or
 * ONVIF cam emits, no driver-specific re-declaration.
 *
 * Schemas are registered DYNAMICALLY as the device's caps are
 * installed (see `BaseDevice.registerNativeCap`). A slice without a
 * registered schema is rejected on write — the cap must be wired
 * first. Reads return `undefined` for unknown slices.
 *
 * Persistence: only registered slices round-trip to disk. The kernel
 * layer debounces writes; explicit `flush()` awaits in-flight saves
 * (used by the shutdown hook).
 */
export interface IDeviceRuntimeState {
    /**
     * Read the slice for `capName`. Three overloads, picked by
     * argument shape:
     *
     *   1. Pass a known cap-name literal (`'battery'`, `'motion'`, …)
     *      → return type is auto-inferred from
     *      `CapNameToRuntimeStateMap` (codegen output). No generic
     *      argument, no `as`-cast.
     *   2. Pass a cap-name with an explicit generic
     *      (`getCapState<MyShape>('custom-cap')`) → return that
     *      shape. Used for caps the codegen doesn't see (test-only,
     *      addon-private).
     *   3. Pass a cap-name with no generic (default `Record<string,
     *      unknown>`) → permissive untyped fallback.
     *
     * Returns `undefined` if no slice has been written yet.
     */
    getCapState<K extends keyof import('../generated/device-local-state.js').CapNameToRuntimeStateMap>(capName: K): Readonly<import('../generated/device-local-state.js').CapNameToRuntimeStateMap[K]> | undefined;
    getCapState<T extends Record<string, unknown> = Record<string, unknown>>(capName: string): Readonly<T> | undefined;
    /** Read a single key inside a slice. Convenience for the common
     *  case of reading a primitive (`battery.percentage`). */
    getCapField(capName: string, key: string): unknown;
    /**
     * Replace the slice for `capName`. The schema bound to `capName`
     * (via `installCapSchema`) validates `value`; throws on mismatch.
     * Listeners fire synchronously after the write applies.
     */
    setCapState(capName: string, value: Record<string, unknown>): void;
    /**
     * Shallow-merge `partial` into the current slice for `capName`.
     * Re-validates the merged result against the cap's schema.
     */
    patchCapState(capName: string, partial: Record<string, unknown>): void;
    /** Subscribe to ALL state changes. Receives the cap names whose
     *  slices changed and the full snapshot. */
    subscribe(cb: (changedCaps: ReadonlyArray<string>, snapshot: Snapshot) => void): () => void;
    /** Subscribe to a single cap's slice changes. Fires only when that
     *  cap's slice is touched; ignores writes against other caps. */
    subscribeCap<T extends Record<string, unknown> = Record<string, unknown>>(capName: string, cb: (slice: Readonly<T> | undefined) => void): () => void;
    /** Frozen snapshot of every cap's slice. Cap names without a
     *  written slice are omitted (sparse). */
    snapshot(): Snapshot;
    /** Flush any pending debounced disk writes. */
    flush(): Promise<void>;
    /**
     * Register a cap's runtime-state schema. Called by the kernel
     * when `ctx.registerNativeCap(cap, …)` runs and `cap.runtimeState`
     * is defined. Idempotent — repeat installs with the same schema
     * are no-ops; mismatched schemas throw to surface a config bug.
     *
     * Lazily validates any existing in-memory slice for `capName` so
     * a slice loaded from disk before the cap was wired is checked
     * the moment the cap shows up.
     */
    installCapSchema(capName: string, schema: z.ZodObject<z.core.$ZodLooseShape>): void;
}
export type Snapshot = Readonly<Record<string, Readonly<Record<string, unknown>>>>;
/**
 * Concrete implementation. Routes every successful write through
 * `writer(capName, slice)` — the kernel hooks this up to
 * `device-state.setCapSlice`, the canonical cross-layer write
 * entrypoint, which handles disk persistence (debounced on the hub)
 * and mirror updates.
 *
 * Schema validation runs in-process before the writer is called —
 * the round-trip should never carry an invalid slice. `flush()`
 * awaits any in-flight writer promises so shutdown is lossless.
 *
 * `initial` is the persisted blob loaded at boot. Slices for caps
 * whose schema hasn't been installed yet are kept in-memory verbatim
 * and validated when the cap registers later.
 */
export declare class DeviceRuntimeState implements IDeviceRuntimeState {
    private readonly writer;
    /** In-flight writer promises tracked so `flush()` can await them. */
    private readonly pendingWrites;
    /** Per-cap committed slice — after schema validation when known. */
    private slices;
    /** Per-cap registered schema (set by `installCapSchema`). */
    private readonly schemas;
    private readonly listeners;
    private readonly capListeners;
    private constructor();
    static fromInitial(initial: Record<string, unknown>, writer: (capName: string, slice: Record<string, unknown>) => Promise<void>): DeviceRuntimeState;
    installCapSchema(capName: string, schema: z.ZodObject<z.core.$ZodLooseShape>): void;
    getCapState<T extends Record<string, unknown> = Record<string, unknown>>(capName: string): Readonly<T> | undefined;
    getCapField(capName: string, key: string): unknown;
    setCapState(capName: string, value: Record<string, unknown>): void;
    patchCapState(capName: string, partial: Record<string, unknown>): void;
    /**
     * Internal worker. `merge` controls whether `value` replaces or
     * shallow-merges into the existing slice. Schema validation runs
     * on the FINAL composed object regardless.
     */
    private applyCapWrite;
    private fireListeners;
    subscribe(cb: (changed: ReadonlyArray<string>, snap: Snapshot) => void): () => void;
    subscribeCap<T extends Record<string, unknown> = Record<string, unknown>>(capName: string, cb: (slice: Readonly<T> | undefined) => void): () => void;
    snapshot(): Snapshot;
    flush(): Promise<void>;
}
//# sourceMappingURL=device-runtime-state.d.ts.map