/**
 * Introspectable route spec system for Hono apps.
 *
 * Routes are defined as data (method, path, auth, input/output schemas, handler),
 * then applied to Hono. The attack surface is generated from the specs —
 * always accurate, always complete.
 *
 * Input/output schemas align with SAES `ActionSpec` conventions:
 * - `input`: Zod schema for the request body (`z.null()` for no body)
 * - `output`: Zod schema for the success response body
 * - `z.strictObject()` for inputs (reject unknown keys)
 *
 * @module
 */
import type { Context, Hono, MiddlewareHandler } from 'hono';
import type { z } from 'zod';
import type { Logger } from '@fuzdev/fuz_util/log.js';
import type { Db } from '../db/db.js';
import { type RouteErrorSchemas, type RateLimitKey } from './error_schemas.js';
import type { MiddlewareSpec } from './middleware_spec.js';
import { type RouteAuth } from './auth_shape.js';
/**
 * Two-phase auth guard set returned by `AuthGuardResolver`.
 *
 * `pre_validation` runs before input validation — 401 checks live here
 * so unauthenticated callers never see route-shape information from
 * input parsing failures. `post_authorization` runs after the
 * authorization phase has populated `RequestContext` — role / keeper
 * checks live here because they read `c.var.request_context.role_grants`.
 */
export interface AuthGuards {
    pre_validation: Array<MiddlewareHandler>;
    post_authorization: Array<MiddlewareHandler>;
}
/**
 * Resolves a `RouteAuth` to middleware guard handlers.
 *
 * Injected into `apply_route_specs` to decouple route registration
 * from auth-specific middleware. See `fuz_auth_guard_resolver` in
 * `auth/auth_guard_resolver.ts` for the standard implementation.
 */
export type AuthGuardResolver = (auth: RouteAuth) => AuthGuards;
/**
 * Per-route authorization phase. Runs after pre-validation auth guards
 * AND input validation; resolves the acting actor (when `auth.actor !== 'none'`)
 * by reading `c.var.validated_input.acting` and sets the request context on
 * the Hono context. Per-route order in `apply_route_specs`: params → query
 * → pre-validation auth (401) → input validation (400) → authorization
 * phase → post-authorization auth (403) → handler.
 *
 * Returns a `Response` to short-circuit (resolution failure → 400 / 500),
 * or `void` to continue. The http framework stays auth-agnostic — fuz_app
 * provides the implementation via `create_fuz_authorization_handler` in
 * `auth/request_context.ts`.
 */
export type AuthorizationHandler = (c: Context, spec: RouteSpec) => Promise<Response | void>;
/** HTTP methods supported by route specs. */
export type RouteMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
/**
 * Per-request deps provided by the framework to route handlers.
 *
 * Audit writes and other rollback-resilient fire-and-forget calls run
 * through `AppDeps.audit.emit(ctx, input)` (see `auth/audit_emitter.ts`),
 * which captures the pool inside its closure — handlers can never
 * accidentally write audits against the request transaction.
 *
 * Routes whose body manages its own transaction (signup, bootstrap)
 * declare `transaction: false` on the spec, which makes `route.db` the
 * pool — they reach for it directly.
 */
export interface RouteContext {
    /**
     * Transaction-scoped when `RouteSpec.transaction` is true (the default
     * for non-GET); pool-level otherwise.
     */
    db: Db;
    /**
     * Eager fire-and-forget queue — push the in-flight `Promise<void>` for
     * pool writes already running (audit emits, session touch, api-token
     * usage tracking). The flush middleware drains via
     * `flush_pending_effects` after the handler returns.
     */
    pending_effects: Array<Promise<void>>;
    /**
     * Deferred post-commit thunks — do not push directly; reach for
     * `emit_after_commit(ctx, fn)` from `pending_effects.ts`. The flush
     * middleware invokes each thunk after the handler (and any wrapping
     * `db.transaction`) returns, closing the microtask-ordering window
     * that an eager `Promise.resolve().then(fn)` leaves open inside the
     * transaction.
     */
    post_commit_effects: Array<() => void | Promise<void>>;
}
/**
 * Route handler function — receives the Hono context and a `RouteContext`
 * with per-request deps (db, pending_effects).
 *
 * TypeScript allows fewer params, so handlers that don't need `route`
 * can use `(c) => ...` without changes.
 */
export type RouteHandler = (c: Context, route: RouteContext) => Response | Promise<Response>;
/**
 * A single route definition — the unit of the surface map.
 *
 * `input` and `output` schemas align with SAES `ActionSpec` naming.
 * Use `z.null()` for routes with no request body (GET, DELETE without body).
 */
export interface RouteSpec {
    method: RouteMethod;
    path: string;
    auth: RouteAuth;
    handler: RouteHandler;
    description: string;
    /**
     * URL path parameter schema. Use `z.strictObject()` with string fields matching `:param` segments.
     *
     * REST-only — actions dispatch through a single JSON-RPC endpoint and encode
     * everything in `input`, so `params` doesn't appear on `ActionSpec`.
     */
    params?: z.ZodObject;
    /** URL query parameter schema. Use `z.strictObject()` with string fields. */
    query?: z.ZodObject;
    /** Request body schema. Use `z.null()` for routes with no body. */
    input: z.ZodType;
    /** Success response body schema. */
    output: z.ZodType;
    /**
     * Rate limit key type — declares what this route's rate limiter is keyed on.
     *
     * When set, 429 (`RateLimitError`) is auto-derived in `derive_error_schemas`.
     * The actual `RateLimiter` instance is still wired imperatively in the handler —
     * this field is metadata for surface introspection and policy invariants.
     */
    rate_limit?: RateLimitKey;
    /**
     * Handler-specific error response schemas keyed by HTTP status code.
     *
     * Middleware errors (auth 401/403, validation 400, rate limit 429) are
     * auto-derived from `auth`, `input`, and `rate_limit`. Declare handler-specific
     * errors here (e.g., 404 for not-found, 409 for conflicts).
     *
     * Explicit entries override auto-derived ones for the same status code.
     */
    errors?: RouteErrorSchemas;
    /**
     * Whether to wrap the handler in a database transaction.
     *
     * When omitted, defaults are derived from the HTTP method:
     * - `GET` → `false` (read-only, no transaction)
     * - All others (`POST`, `PUT`, `DELETE`, `PATCH`) → `true`
     *
     * Set explicitly to override the default (e.g., `false` for a POST
     * that manages its own transaction like signup).
     */
    transaction?: boolean;
}
/**
 * Get validated input from the Hono context.
 *
 * Call after the input validation middleware has run. Pass the route's
 * `input` Zod schema to infer the typed shape directly:
 *
 * ```ts
 * const input = get_route_input(c, my_route_spec.input);
 * ```
 *
 * Or pass an explicit type argument when the schema isn't in scope:
 *
 * ```ts
 * const input = get_route_input<MyInput>(c);
 * ```
 */
export declare function get_route_input<S extends z.ZodType>(c: Context, schema: S): z.infer<S>;
export declare function get_route_input<T = unknown>(c: Context): T;
/**
 * Get validated URL path params from the Hono context.
 *
 * Call after the params validation middleware has run. Pass the route's
 * `params` schema to infer the typed shape, or supply an explicit type
 * argument. See `get_route_input` for the two call shapes.
 */
export declare function get_route_params<S extends z.ZodType>(c: Context, schema: S): z.infer<S>;
export declare function get_route_params<T = unknown>(c: Context): T;
/**
 * Get validated URL query params from the Hono context.
 *
 * Call after the query validation middleware has run. Pass the route's
 * `query` schema to infer the typed shape, or supply an explicit type
 * argument. See `get_route_input` for the two call shapes.
 */
export declare function get_route_query<S extends z.ZodType>(c: Context, schema: S): z.infer<S>;
export declare function get_route_query<T = unknown>(c: Context): T;
/**
 * Apply named middleware specs to a Hono app.
 *
 * @mutates `app`
 */
export declare const apply_middleware_specs: (app: Hono, specs: Array<MiddlewareSpec>) => void;
/**
 * Apply route specs to a Hono app.
 *
 * For each spec: resolves auth to guards via the provided resolver,
 * adds input validation middleware (for routes with non-null input schemas),
 * runs the optional authorization phase to resolve the acting actor + build
 * the request context, wraps handler with DEV-only output and error
 * validation, wraps with error catch layer (catches `ThrownJsonrpcError`
 * and generic errors), and registers the route.
 *
 * Per-route middleware order: params → query → pre-validation auth
 * guards (401) → input validation (400) → authorization phase →
 * post-authorization auth guards (403) → handler. The 401 check runs
 * before any body parsing so unauthenticated callers never see
 * route-shape information from parse failures. Input validation runs
 * before the authorization phase (validate first, authorize after) so
 * the authorization phase reads `c.var.validated_input.acting` as a
 * typed Zod field instead of pre-parsing the raw body. Role /
 * credential-type denials still surface 403 last; trade-off is that
 * authenticated-but-unauthorized callers can distinguish 400
 * (validation) from 403 (authorization), a defense-in-depth concession
 * deemed acceptable because the route surface is public via
 * spec/codegen JSON.
 *
 * Each handler receives a `RouteContext` with:
 * - `db`: transaction-scoped when `RouteSpec.transaction` is true; pool-level otherwise
 * - `pending_effects`: eager fire-and-forget pool-write queue
 * - `post_commit_effects`: deferred-thunk queue (push via `emit_after_commit`)
 *
 * Also enforces registry-time invariant 2 from the auth-shape design:
 * `auth.actor !== 'none' ⟺ input or query declares acting?: ActingActor`.
 * REST is bi-located (GETs declare `acting` on `query`, mutations on
 * `input`), so the check passes both slots; the action-dispatcher
 * registries (`compile_action_registry`) share the same helper with
 * `input` only — `ActionSpec` has no `query` shape.
 *
 * @param resolve_auth_guards - maps `RouteAuth` to middleware — use `fuz_auth_guard_resolver` from `auth/auth_guard_resolver.ts`
 * @param authorize - optional authorization phase; runs after input validation
 * @param db - used for transaction wrapping and `RouteContext`
 * @mutates `app`
 * @throws Error if two specs share the same `method` + `path` (each combination must be unique), or if any spec violates the actor-acting biconditional
 */
export declare const apply_route_specs: (app: Hono, specs: Array<RouteSpec>, resolve_auth_guards: AuthGuardResolver, log: Logger, db: Db, authorize?: AuthorizationHandler) => void;
/**
 * Prepend a prefix to all route spec paths.
 *
 * @param prefix - the path prefix (e.g. `/api/account`)
 * @returns a new array — the input specs are not mutated
 */
export declare const prefix_route_specs: (prefix: string, specs: Array<RouteSpec>) => Array<RouteSpec>;
//# sourceMappingURL=route_spec.d.ts.map