/**
 * `RepackedSyncBroker` — the single owner of one `RepackedVfs`, answering synchronous file requests
 * that arrive over `SharedArrayBuffer` channels.
 *
 * The broker is meant to be the only thing on its thread. A backend running wasm parks in futexes and
 * cannot await anything, so it publishes a request and blocks; the broker must therefore never block on
 * a promise between reading a request and writing its answer. Every handler here is synchronous, and
 * the store's own API is synchronous end to end.
 *
 * Three loop shapes are offered:
 *
 * - `serveForever()` parks the thread in `Atomics.wait` between requests. It is the shape for a
 *   dedicated coordinator worker, and while it runs the thread never reaches its event loop — so
 *   `postMessage` cannot reach it and every channel must be attached BEFORE entering it. Ask it to
 *   return with `doorbell.requestStop()` from any thread holding the doorbell.
 * - `serve()` is the same loop built on `Atomics.waitAsync`, for a host that must keep its event loop
 *   alive. Channels may be attached and detached at any time.
 * - `serveOnce()` scans every attached channel once and returns without waiting, for a host that
 *   drives its own loop.
 *
 * Failure separation is the point of the class. A file rejection (`FsError`) becomes an errno in the
 * reply header and nothing else happens. A store failure becomes `FAULT_STORE` in the reply, and the
 * loop keeps running because every later request will fail the same way and the client decides what to
 * do. A protocol violation detaches only the offending client, with a logged reason.
 */
import type { RepackedFileSystem } from "../core/repacked-vfs";
import type { RepackedChannel, RepackedDoorbell } from "./protocol";
export interface RepackedSyncBrokerOptions {
    /**
     * The store this broker owns. Nothing else may hold it. A `RepackedVfs` is the one-store form; a
     * `MountedRepackedVfs` serves several stores as one tree, and the broker cannot tell them apart.
     */
    readonly vfs: RepackedFileSystem;
    /** The shared doorbell every attached channel rings. */
    readonly doorbell: RepackedDoorbell;
    /** The timestamp the broker supplies to every core call. Defaults to the wall clock. */
    readonly now?: () => bigint;
    /** Where a detach reason goes. Defaults to `console.warn`. */
    readonly log?: (message: string) => void;
    /**
     * How long one blocking iteration parks before re-scanning anyway. Defaults to 250 ms. The protocol
     * has no missed-wakeup window — the server observes the doorbell ticket BEFORE it scans, so a
     * request published during the scan makes the wait return `not-equal` at once — so this is purely a
     * heartbeat: it costs four idle wakeups a second and turns any future slip into a latency blip
     * instead of a permanently parked backend. `Infinity` makes the loop a pure park.
     */
    readonly pollIntervalMs?: number;
}
export declare class RepackedSyncBroker {
    #private;
    readonly doorbell: RepackedDoorbell;
    constructor(options: RepackedSyncBrokerOptions);
    /** Channel ids the broker currently serves. */
    attachedIds(): number[];
    /** Descriptors the broker currently holds for one client — the leak check after a detach. */
    openFdCount(channelId?: number): number;
    attach(channel: RepackedChannel): void;
    /**
     * Drop a client and close every descriptor it still holds. A backend that dies mid-query never leaks
     * a descriptor into the store, and the store's exclusive handles are released the moment the LAST
     * owner goes away rather than whenever a stale fd happens to be noticed.
     */
    detach(channel: RepackedChannel | number, reason?: string): void;
    /** Detach every client, closing all descriptors. The store itself is NOT closed. */
    detachAll(reason?: string): void;
    /**
     * Scan every attached channel once and answer whatever is pending. Never blocks, never throws for a
     * file or store error. Returns how many requests were answered.
     */
    serveOnce(): number;
    /**
     * The blocking coordinator loop. Parks the thread in `Atomics.wait` on the doorbell between
     * requests, so this thread's event loop never runs: attach every channel before calling it, and stop
     * it with `doorbell.requestStop()` from another thread.
     */
    serveForever(): void;
    /**
     * The same loop on `Atomics.waitAsync`, for a host that must not park its thread — the tab's main
     * thread, or a worker that also has to receive `postMessage`. Channels may be attached and detached
     * while it runs. Resolves when `doorbell.requestStop()` is called.
     */
    serve(): Promise<void>;
}
//# sourceMappingURL=server.d.ts.map