/**
 * Server assembly factory.
 *
 * Consumers provide a pre-initialized `AppBackend` and options (session,
 * origins, routes); `create_app_server()` handles middleware, bootstrap
 * status, surface generation, and Hono app assembly.
 *
 * @module
 */
import { Hono, type Context } from 'hono';
import type { UpgradeWebSocket } from 'hono/ws';
import { z } from 'zod';
import { type SessionOptions } from '../auth/session_cookie.js';
import type { BootstrapAccountSuccess } from '../auth/bootstrap_account.js';
import type { EventSpec } from '../realtime/sse.js';
import { type AuditLogSse } from '../realtime/sse_auth_guard.js';
import { type RateLimiter } from '../rate_limiter.js';
import type { DaemonTokenState } from '../auth/daemon_token.js';
import type { MigrationResult } from '../db/migrate.js';
import type { AppDeps } from '../auth/deps.js';
import type { AppBackend } from './app_backend.js';
import '../hono_context.js';
import { type ServeStaticFactory } from './static.js';
import { type AppSurfaceSpec, type RpcEndpointSpec } from '../http/surface.js';
import { type RouteSpec } from '../http/route_spec.js';
import type { MiddlewareSpec } from '../http/middleware_spec.js';
import { type BootstrapStatus } from '../auth/bootstrap_routes.js';
import type { WsEndpointSpec } from '../actions/ws_endpoint_spec.js';
import { BackendWebsocketTransport } from '../actions/transports_ws_backend.js';
/**
 * Context passed to `on_effect_error` when a pending effect rejects.
 */
export interface EffectErrorContext {
    /** HTTP method of the request that spawned the effect. */
    method: string;
    /** URL path of the request that spawned the effect. */
    path: string;
}
/**
 * Bootstrap configuration for `AppServerOptions.bootstrap`.
 *
 * Discriminated union over three deployment intents. Distinct from
 * `BootstrapRouteOptions` in `auth/bootstrap_routes.ts` — that one is
 * per-factory runtime state (mutable `bootstrap_status` ref, rate
 * limiter); this one is the consumer-facing server option that
 * `create_app_server` reads at startup to decide whether to mount the
 * routes and where.
 *
 * Three modes:
 * - `disabled` — no route mounted, nothing in `/api/surface`.
 *   Equivalent to omitting `bootstrap` entirely; the explicit mode is
 *   for documentation and reviewable intent at the wiring layer.
 * - `surface_only` — route present, permanent 403 via
 *   `check_bootstrap_status`. For tests asserting on the
 *   disabled-but-present wire shape.
 * - `live` — route mounted, real token verification. Success path
 *   reachable. `token_path` is required (non-nullable).
 */
export type BootstrapServerOptions = BootstrapDisabledOptions | BootstrapSurfaceOnlyOptions | BootstrapLiveOptions;
export interface BootstrapDisabledOptions {
    mode: 'disabled';
}
export interface BootstrapSurfaceOnlyOptions {
    mode: 'surface_only';
    /** Route prefix for surface generation. Default `'/api/account'`. */
    route_prefix?: string;
}
export interface BootstrapLiveOptions {
    mode: 'live';
    token_path: string;
    /** Route prefix for bootstrap routes. Default `'/api/account'`. */
    route_prefix?: string;
    /**
     * Called after successful bootstrap (account + session created).
     * Use for app-specific post-bootstrap work like generating API tokens.
     */
    on_bootstrap?: (result: BootstrapAccountSuccess, c: Context) => Promise<void>;
}
/**
 * Configuration for `create_app_server()`.
 *
 * Requires a pre-initialized `AppBackend` from `create_app_backend()`.
 * Two explicit steps: init backend then assemble server.
 */
export interface AppServerOptions {
    /** Pre-initialized backend from `create_app_backend()`. */
    backend: AppBackend;
    /** Session options for cookie-based auth. */
    session_options: SessionOptions<string>;
    /** Parsed allowed origin patterns. */
    allowed_origins: Array<RegExp>;
    /** Trusted proxy options. */
    proxy: {
        trusted_proxies: Array<string>;
        get_connection_ip: (c: Context) => string | undefined;
    };
    /**
     * Shared IP rate limiter for login, bootstrap, and bearer auth.
     * Omit or `undefined` to use a default limiter (5 attempts per 15 minutes).
     * Pass `null` to explicitly disable rate limiting.
     * Also available on `AppServerContext` for route factory callbacks.
     */
    ip_rate_limiter?: RateLimiter | null;
    /**
     * Per-account rate limiter for login attempts.
     * Omit or `undefined` to use a default limiter (10 attempts per 30 minutes).
     * Pass `null` to explicitly disable rate limiting.
     * Also available on `AppServerContext` for route factory callbacks.
     */
    login_account_rate_limiter?: RateLimiter | null;
    /**
     * Per-account rate limiter for signup attempts, keyed by submitted username.
     * Omit or `undefined` to use a default limiter (10 attempts per 30 minutes).
     * Pass `null` to explicitly disable rate limiting.
     * Also available on `AppServerContext` for route factory callbacks.
     */
    signup_account_rate_limiter?: RateLimiter | null;
    /**
     * Rate limiter for bearer token auth attempts (per-IP).
     * Omit or `undefined` to use a default limiter (5 attempts per 15 minutes).
     * Pass `null` to explicitly disable rate limiting.
     */
    bearer_ip_rate_limiter?: RateLimiter | null;
    /**
     * Per-IP rate limiter for the action dispatchers (HTTP RPC + WebSocket).
     * Consulted for actions whose spec declares `rate_limit: 'ip'` or `'both'`.
     * Same limiter applies across transports — one budget per action.
     * Omit or `undefined` to use a default limiter (600 attempts per
     * 15 minutes — permissive). Pass `null` to explicitly disable.
     * Also available on `AppServerContext` for consumers wiring
     * `register_action_ws`.
     */
    action_ip_rate_limiter?: RateLimiter | null;
    /**
     * Per-actor rate limiter for the action dispatchers (HTTP RPC + WebSocket).
     * Consulted for actions whose spec declares `rate_limit: 'account'` or
     * `'both'`. Keyed on `request_context.actor.id` (post-auth).
     * Omit or `undefined` to use a default limiter (1200 attempts per
     * 15 minutes — permissive). Pass `null` to explicitly disable.
     * Also available on `AppServerContext` for consumers wiring
     * `register_action_ws`.
     */
    action_account_rate_limiter?: RateLimiter | null;
    /**
     * Maximum allowed request body size in bytes.
     * Omit or `undefined` to use the default (1 MiB).
     * Pass `null` to explicitly disable body size limiting.
     */
    max_body_size?: number | null;
    /** Daemon token state for keeper auth. Omit to disable. */
    daemon_token_state?: DaemonTokenState;
    /** Bootstrap options. Omit to skip bootstrap status check and routes. */
    bootstrap?: BootstrapServerOptions;
    /**
     * Set to `false` to disable the auto-created surface route (`GET /api/surface`).
     * Default: auto-created (authenticated).
     */
    surface_route?: false;
    /**
     * Build route specs from the initialized backend.
     * Called after all middleware is ready.
     */
    create_route_specs: (context: AppServerContext) => Array<RouteSpec>;
    /** Optional: transform middleware specs before applying. */
    transform_middleware?: (specs: Array<MiddlewareSpec>) => Array<MiddlewareSpec>;
    /**
     * Enable factory-managed audit log SSE.
     *
     * When truthy, creates an `AuditLogSse` instance internally, appends the SSE
     * listener to `backend.deps.audit.on_event_chain` (composing with the
     * consumer's `on_audit_event` callback rather than rebuilding `AppDeps`), and
     * auto-includes `audit_log_event_specs` in the surface. The result is exposed
     * on `AppServerContext` (for route factories) and `AppServer` (for the caller),
     * always typed as `AuditLogSse | null` — when this option is set, the field
     * is non-null. Use `require_audit_sse(ctx)` to assert the invariant in
     * route factories that depend on it.
     *
     * Pass `true` for defaults (admin role), or `{role: 'custom'}` for a custom role.
     * Omit to wire audit SSE manually.
     */
    audit_log_sse?: true | {
        role?: string;
    };
    /** SSE event specs for surface generation. Defaults to `[]` (no SSE events). */
    event_specs?: Array<EventSpec>;
    /**
     * RPC endpoint specs — single source of truth for both surface generation
     * *and* live dispatch. Each entry is mounted via `create_rpc_endpoint`
     * against the assembled Hono app, so consumers no longer call
     * `create_rpc_endpoint` themselves inside `create_route_specs`.
     *
     * Accepts either an array (evaluated eagerly) or a factory
     * `(ctx: AppServerContext) => Array<RpcEndpointSpec>` (evaluated after the
     * server context is assembled). Use the factory form when action lists
     * depend on `ctx.deps` — e.g. `create_standard_rpc_actions(ctx.deps)`.
     */
    rpc_endpoints?: Array<RpcEndpointSpec> | ((context: AppServerContext) => Array<RpcEndpointSpec>);
    /**
     * Hono adapter's `upgradeWebSocket` helper. Required whenever
     * `ws_endpoints` resolves to a non-empty array — `create_app_server`
     * throws at assembly otherwise. Omit (along with `ws_endpoints`)
     * when the consumer doesn't mount any WS endpoints. The same
     * adapter helper services every `WsEndpointSpec` mounted from
     * `ws_endpoints` — one adapter per app.
     *
     * For Node, `import {upgradeWebSocket} from '@hono/node-ws'`. For
     * Deno, `import {upgradeWebSocket} from 'hono/deno'`. Test harnesses
     * use `create_stub_upgrade` from `$lib/testing/ws_round_trip.ts`.
     */
    upgradeWebSocket?: UpgradeWebSocket;
    /**
     * WebSocket endpoint specs — single source of truth for both surface
     * generation *and* live dispatch. Each entry is auto-mounted via
     * `register_ws_endpoint` against the assembled Hono app, so
     * consumers no longer call `register_ws_endpoint` themselves.
     *
     * Accepts either an array (evaluated eagerly) or a factory
     * `(ctx: AppServerContext) => ReadonlyArray<WsEndpointSpec>`
     * (evaluated after the server context is assembled). Use the factory
     * form when action lists depend on `ctx.deps` /
     * `ctx.action_*_rate_limiter` — e.g. when spreading
     * `create_standard_rpc_actions(ctx.deps, ...)` over WS.
     *
     * When non-empty, `upgradeWebSocket` must be supplied (throws
     * otherwise). A factory returning `[]` does NOT trip the check —
     * feature-flag gated WS surfaces stay safe.
     *
     * Duplicate `path` values across two `WsEndpointSpec`s throw at
     * mount time (Hono would silently shadow them otherwise).
     *
     * Each spec's `auth_guard?` defaults to `true` — the factory
     * composes `create_ws_auth_guard` + `create_ws_logout_closer`
     * against the mounted transport and appends them to
     * `deps.audit.on_event_chain`. Wiring is deduped by transport
     * **reference identity** so two specs sharing one
     * `BackendWebsocketTransport` instance get a single pair of
     * listeners; wrapped / proxied transports dedupe as separate
     * entries (set `auth_guard: false` on duplicates and compose
     * against the underlying transport once).
     */
    ws_endpoints?: ReadonlyArray<WsEndpointSpec> | ((context: AppServerContext) => ReadonlyArray<WsEndpointSpec>);
    /**
     * Env schema for surface generation. Defaults to `BaseServerEnv` —
     * pass an extended schema (typically `BaseServerEnv.extend({...})`)
     * when the consumer adds app-specific env vars.
     */
    env_schema?: z.ZodObject;
    /** Middleware applied after routes, before static serving. Included in surface. */
    post_route_middleware?: Array<MiddlewareSpec>;
    /** Static file serving. Omit if not serving static files. */
    static_serving?: {
        serve_static: ServeStaticFactory;
        /** Root directory for static files. Default `'./build'`. */
        root?: string;
        /** Optional SPA fallback path served for client-side routes. */
        spa_fallback?: string;
        /**
         * Predicate deciding which paths receive the SPA fallback.
         * Default: every path that is not under `/api/`. Only consulted
         * when `spa_fallback` is set.
         */
        is_spa_route?: (path: string) => boolean;
    };
    /**
     * Await all pending fire-and-forget effects before returning the response.
     * Use in tests so audit log assertions don't need polling.
     * Default `false` (production: true fire-and-forget).
     */
    await_pending_effects?: boolean;
    /**
     * Called when a pending effect rejects.
     * Use for monitoring, metrics, or alerting in production.
     * Only called when `await_pending_effects` is `false` (production mode).
     */
    on_effect_error?: (error: unknown, context: EffectErrorContext) => void;
    /** Env values for startup summary logging. */
    env_values?: Record<string, unknown>;
}
/** Context passed to `create_route_specs`. */
export interface AppServerContext {
    deps: AppDeps;
    backend: AppBackend;
    bootstrap_status: BootstrapStatus;
    session_options: SessionOptions<string>;
    /** Shared IP rate limiter (from options). `null` when not configured. */
    ip_rate_limiter: RateLimiter | null;
    /** Per-account login rate limiter (from options). `null` when not configured. */
    login_account_rate_limiter: RateLimiter | null;
    /** Per-account signup rate limiter (from options). `null` when not configured. */
    signup_account_rate_limiter: RateLimiter | null;
    /** Per-IP action-dispatcher rate limiter — shared across HTTP RPC + WS. `null` when not configured. */
    action_ip_rate_limiter: RateLimiter | null;
    /** Per-actor action-dispatcher rate limiter — shared across HTTP RPC + WS. `null` when not configured. */
    action_account_rate_limiter: RateLimiter | null;
    /**
     * Factory-managed audit log SSE. Non-null when the `audit_log_sse`
     * option was passed to `create_app_server`, `null` when omitted.
     * Use `require_audit_sse(ctx)` to assert the invariant.
     */
    audit_sse: AuditLogSse | null;
}
/** Result of `create_app_server()`. */
export interface AppServer {
    app: Hono;
    /** Surface spec — serializable surface + raw specs that produced it. */
    surface_spec: AppSurfaceSpec;
    bootstrap_status: BootstrapStatus;
    /** Migration results from `create_app_backend` (auth + any `migration_namespaces` passed there). */
    migration_results: ReadonlyArray<MigrationResult>;
    /**
     * Factory-managed audit log SSE. Non-null when the `audit_log_sse`
     * option was passed to `create_app_server`, `null` when omitted.
     * Use `require_audit_sse(server)` to assert the invariant.
     */
    audit_sse: AuditLogSse | null;
    /**
     * Path-keyed map of mounted WS endpoints. Each value is the
     * `BackendWebsocketTransport` `create_app_server` registered
     * connections against — supplied via `WsEndpointSpec.transport` or
     * auto-created when omitted. Retain for broadcast / fan-out:
     *
     * ```ts
     * app_server.ws_endpoints['/api/ws'].send_to_account(account_id, msg);
     * ```
     *
     * Empty when no `ws_endpoints` were mounted.
     */
    ws_endpoints: Readonly<Record<string, BackendWebsocketTransport>>;
    /** Close the database connection. Propagated from `AppBackend`. */
    close: () => Promise<void>;
}
/**
 * Assert that `audit_sse` was wired by `create_app_server` and return it
 * as a non-null `AuditLogSse`. Throws a labelled error when the
 * `audit_log_sse` option was not passed to `create_app_server`.
 *
 * Use in route factories that depend on factory-managed audit SSE:
 *
 * ```ts
 * create_route_specs: (ctx) => create_audit_log_route_specs({
 *   stream: require_audit_sse(ctx),
 * }),
 * ```
 *
 * Preferred over `ctx.audit_sse!` — `!` lies to the type system and
 * produces a downstream cannot-read-property crash if a consumer wires
 * the route without enabling the option.
 */
export declare const require_audit_sse: (source: {
    audit_sse: AuditLogSse | null;
}) => AuditLogSse;
/** Default maximum request body size: 1 MiB. */
export declare const DEFAULT_MAX_BODY_SIZE: number;
/**
 * Create a fully assembled Hono app with auth, middleware, and routes.
 *
 * Handles the assembly lifecycle: proxy middleware → auth middleware →
 * bootstrap status → route specs → surface generation → Hono app assembly →
 * static serving. Database migrations belong to the backend lifecycle —
 * pass `migration_namespaces` to `create_app_backend`.
 *
 * When `audit_log_sse` is set, the SSE registry's listener is appended to
 * `backend.deps.audit.on_event_chain` — no shallow-copy of `AppDeps`. The
 * `audit_sse` field on the returned `AppServer` (and the
 * `AppServerContext` passed to `create_route_specs`) is non-null in that
 * case; consumers can call `require_audit_sse(ctx)` / `require_audit_sse(server)`
 * to assert the invariant.
 *
 * @returns assembled Hono app, backend, surface build, and bootstrap status
 */
export declare const create_app_server: (options: AppServerOptions) => Promise<AppServer>;
//# sourceMappingURL=app_server.d.ts.map