/**
 * Graceful shutdown helper for `spectral serve`.
 *
 * Why a separate module:
 *  - The shutdown flag (`shutdownState.isShuttingDown`) is read by the relay
 *    dispatcher to reject new `client_message` envelopes. Putting it on
 *    `serve.ts` would create a circular import (dispatcher → serve → relay
 *    client → …); pulling it out keeps the dependency graph linear.
 *  - The orchestration is small but has enough edge cases (idempotent on a
 *    second SIGTERM, bounded wait for in-flight streams, best-effort store
 *    close) that it's worth one focused unit test.
 *
 * Behaviour summary (matches the contract in the Batch 6 brief):
 *  1. First SIGINT/SIGTERM:
 *     - Log "Shutting down…" to stderr.
 *     - Flip `shutdownState.isShuttingDown = true`. From this point on the
 *       dispatcher refuses new `client_message` frames with an error
 *       wrapped as a `ws_event` (so the browser sees the rejection on the
 *       same stream it was using).
 *     - Wait up to `gracePeriodMs` (default 5_000 ms) for the in-flight
 *       stream count reported by `inFlightCount()` to drain to 0. Polled
 *       every 100 ms — any non-zero value indicates an active turn.
 *     - Close the relay (code 1000, reason "shutdown") and dispose the
 *       manager. The dispose order matters: relay first so the backend
 *       sees a clean close before our local state goes; manager second so
 *       any spectral processes get torn down deterministically.
 *     - Close the SQLite store (best-effort — a failure here just gets
 *       logged; the process is exiting anyway).
 *     - Exit with the supplied code (default 0).
 *  2. Second SIGINT/SIGTERM during the grace period: skip the wait, force
 *     immediate exit with code 1. We don't want a hung spectral process to
 *     prevent operators from killing the server with a second Ctrl-C.
 *
 * The function is intentionally framework-free — it takes plain callbacks
 * for everything I/O-shaped so the unit test can exercise the orchestration
 * without spawning a real relay or sqlite handle.
 */
/**
 * Process-wide shutdown flag. Read by the dispatcher to gate new
 * `client_message` envelopes; written by `gracefulShutdown` (and by tests
 * via `resetShutdownState`).
 *
 * Module-level singleton because there is exactly one server process per
 * `spectral serve` invocation; co-locating with serve.ts would require
 * threading the flag through the dispatcher's deps (already a small
 * object) and risks dispatcher tests carrying serve.ts state.
 */
export declare const shutdownState: {
    isShuttingDown: boolean;
};
/**
 * Reset the singleton flag. Tests use this in `beforeEach` so a previous
 * test's shutdown doesn't bleed into the next. Production code must NOT
 * call this — once the process is shutting down, it's shutting down.
 */
export declare function resetShutdownState(): void;
export interface GracefulShutdownOptions {
    /** Logger; defaults to `console`. Tests inject a noop or a recorder. */
    logger?: Pick<Console, "log" | "warn" | "error">;
    /**
     * Reports in-flight stream count (e.g. `() => manager.activeTurnCount()`).
     * Polled every 100 ms until it returns 0 or `gracePeriodMs` elapses.
     * If omitted we skip the wait entirely (treated as "nothing in flight").
     */
    inFlightCount?: () => number;
    /** Close the relay with code 1000 / reason "shutdown". */
    closeRelay?: () => void | Promise<void>;
    /** Dispose the SessionStreamManager (kills spectral processes). */
    disposeManager?: () => void | Promise<void>;
    /** Close the SQLite store. Failures are logged, not rethrown. */
    closeStore?: () => void;
    /** Bound on how long to wait for in-flight streams. Default 5_000 ms. */
    gracePeriodMs?: number;
    /** Polling interval for the in-flight wait. Default 100 ms. */
    pollIntervalMs?: number;
    /** Exit code on a clean first-signal shutdown. Default 0. */
    exitCode?: number;
    /**
     * Override `process.exit` for tests. Not called as a function reference
     * directly so the test can assert on what was requested without actually
     * killing vitest.
     */
    exitFn?: (code: number) => void;
    /**
     * Sleep helper. Tests inject a mock clock; production uses real
     * `setTimeout`. Resolves after `ms` milliseconds.
     */
    sleep?: (ms: number) => Promise<void>;
}
/** Test-only: reset the entry counter alongside `shutdownState`. */
export declare function resetShutdownEntryCount(): void;
/**
 * Run the graceful shutdown sequence. Idempotent on the entry-count
 * dimension: the second concurrent call resolves immediately after
 * triggering an immediate exit.
 *
 * Returns once the supplied `exitFn` has been invoked (or would have been
 * invoked in production where `process.exit` does not return). Tests can
 * await it to assert ordering.
 */
export declare function gracefulShutdown(opts?: GracefulShutdownOptions): Promise<void>;
//# sourceMappingURL=shutdown.d.ts.map