import './assert_dev_env.js';
import type { AppSurface } from '../http/surface.js';
/**
 * Every protected route has 401 in `error_schemas`.
 */
export declare const assert_protected_routes_declare_401: (surface: AppSurface) => void;
/**
 * Every role/keeper route has 403 in `error_schemas`.
 */
export declare const assert_role_routes_declare_403: (surface: AppSurface) => void;
/**
 * Every route with non-null `input_schema` has 400 in `error_schemas`.
 */
export declare const assert_input_routes_declare_400: (surface: AppSurface) => void;
/**
 * Every route with non-null `params_schema` has 400 in `error_schemas`.
 */
export declare const assert_params_routes_declare_400: (surface: AppSurface) => void;
/**
 * Every route with non-null `query_schema` has 400 in `error_schemas`.
 */
export declare const assert_query_routes_declare_400: (surface: AppSurface) => void;
/**
 * Every route has a non-empty description.
 */
export declare const assert_descriptions_present: (surface: AppSurface) => void;
/**
 * No duplicate method+path pairs.
 */
export declare const assert_no_duplicate_routes: (surface: AppSurface) => void;
/**
 * Every applicable middleware that declares errors must have those status codes
 * present in the route's `error_schemas`.
 */
export declare const assert_middleware_errors_propagated: (surface: AppSurface) => void;
/**
 * Every route's declared error schemas must have an `error` field at the top level
 * (conforming to the `ApiError` base shape `{error: string}`).
 *
 * Walks union branches (`anyOf` from `z.union`, `oneOf` from
 * `z.discriminatedUnion`) so every emit shape inside a merged 400 / 404
 * is checked, not just the top-level wrapper.
 *
 * Catches typos in error schema definitions and ensures consumers can always
 * read `.error` from error responses.
 */
export declare const assert_error_schemas_structurally_valid: (surface: AppSurface) => void;
/**
 * The same `z.literal()` error code should not appear at different HTTP status codes
 * across routes.
 *
 * Extracts `const` values from error schema `error` properties (which correspond to
 * `z.literal()` in the Zod source). Walks union branches (`anyOf` from `z.union`,
 * `oneOf` from `z.discriminatedUnion`) so literal codes nested inside merged unions
 * (e.g. validation 400 + actor-resolution 400) are still tracked. Flags when the
 * same literal appears at different status codes — e.g., `ERROR_INVALID_CREDENTIALS`
 * at both 401 and 403 would be a bug.
 *
 * Only checks `const` values (literal schemas). Generic `z.string()` schemas
 * (which produce `{type: 'string'}`) and `z.enum()` schemas are ignored — the
 * literal-only narrow keeps the check unambiguous.
 */
export declare const assert_error_code_status_consistency: (surface: AppSurface) => void;
/**
 * Routes declaring 404 error schemas should use specific `z.literal()` or `z.enum()`
 * error codes, not generic `z.string()`.
 *
 * A generic 404 schema (`ApiError` with `z.string()`) means the error code is
 * unconstrained — the handler could return any string, making client error handling
 * fragile. Routes with params (`:id`) are the primary 404 producers; their error
 * schemas should use specific constants like `ERROR_ACCOUNT_NOT_FOUND`.
 *
 * Only flags routes that have `params_schema` (param-driven resource lookup) — routes
 * declaring 404 for other reasons (e.g., bootstrap not configured) may legitimately
 * use generic schemas.
 */
export declare const assert_404_schemas_use_specific_errors: (surface: AppSurface) => void;
/** Specificity level of an error schema's `error` field. */
export type ErrorSchemaSpecificity = 'literal' | 'enum' | 'generic';
/** A single entry in the error schema tightness audit report. */
export interface ErrorSchemaAuditEntry {
    method: string;
    route_path: string;
    status: string;
    specificity: ErrorSchemaSpecificity;
    /** The literal value or enum values, if specific. */
    error_codes: Array<string> | null;
}
/**
 * Audit error schema tightness across all routes in a surface.
 *
 * Reports which route x status code combinations use generic `ApiError`
 * (`z.string()`) vs specific `z.literal()` or `z.enum()` error codes.
 * Use the output to prioritize progressive tightening of error schemas.
 *
 * @returns audit entries for every route x status combination
 */
export declare const audit_error_schema_tightness: (surface: AppSurface) => Array<ErrorSchemaAuditEntry>;
/**
 * Every RPC method on every endpoint has a non-empty `description`.
 *
 * Parallel of `assert_descriptions_present` over `surface.rpc_endpoints`.
 * Empty descriptions on RPC methods leak through `library.json` codegen and
 * consumer-facing docs without the route-level check catching them.
 */
export declare const assert_rpc_method_descriptions_present: (surface: AppSurface) => void;
/**
 * Every WS method on every endpoint has a non-empty `description`.
 *
 * Parallel of `assert_descriptions_present` over `surface.ws_endpoints`.
 * Same rationale as `assert_rpc_method_descriptions_present` — codegen +
 * surface explorer consume the description, blank values surface as `''`.
 */
export declare const assert_ws_method_descriptions_present: (surface: AppSurface) => void;
/**
 * Every WS endpoint's `methods` includes every protocol action method
 * (`heartbeat`, `cancel`).
 *
 * Consumers register WS endpoints by spreading `protocol_actions` from
 * `actions/protocol.ts` before their own actions:
 *
 * ```ts
 * ws_endpoints: [{path: '/api/ws', actions: [...protocol_actions, ...consumer_actions], ...}]
 * ```
 *
 * Forgetting the spread compiles cleanly but breaks at runtime: client-side
 * heartbeats and `cancel` notifications get `method_not_found` from the
 * dispatcher, so disconnect detection silently regresses and per-request
 * cancel never aborts the matching handler. Catch the mistake at the
 * surface layer rather than at runtime.
 */
export declare const assert_ws_endpoints_include_protocol_actions: (surface: AppSurface) => void;
/**
 * WS methods follow the kind ⇔ auth biconditional emitted by surface
 * generation: `kind === 'remote_notification' ⟺ auth === null`.
 *
 * `generate_app_surface` produces this shape directly from the action
 * spec union (notifications carry `auth: null` per `ActionSpecUnion`;
 * `request_response` carries a `RouteAuth`). The assertion guards against
 * drift if a future surface emitter, transform, or test fixture violates
 * it — and gives consumers a clear failure message when a hand-built
 * surface mocks the shape incorrectly.
 */
export declare const assert_ws_notifications_have_null_auth: (surface: AppSurface) => void;
/**
 * Configuration for security policy invariants.
 *
 * All fields have sensible defaults. Pass overrides for project-specific needs.
 */
export interface SurfaceSecurityPolicyOptions {
    /**
     * Path patterns for routes that should be rate-limited.
     * Default: common sensitive REST patterns (login, password, bootstrap).
     * `account_token_create` lives on the RPC surface; per-method RPC rate
     * limiting is a separate invariant if consumers want it.
     */
    sensitive_route_patterns?: Array<string | RegExp>;
    /**
     * Routes explicitly allowed to be public mutations (e.g., webhooks, bootstrap).
     * Format: `'METHOD /path'` (e.g., `'POST /api/account/login'`).
     */
    public_mutation_allowlist?: Array<string>;
    /**
     * Allowed path prefixes for keeper-protected routes.
     * Default: `['/api/']`. Catches keeper routes outside expected namespaces.
     */
    keeper_route_prefixes?: Array<string>;
}
/**
 * Sensitive routes must declare rate limiting (`rate_limit_key` is non-null)
 * or have 429 in their error schemas.
 *
 * Matches routes against sensitive patterns and flags any that lack rate limit
 * declarations. Catches forgotten rate limiting on credential-handling routes.
 */
export declare const assert_sensitive_routes_rate_limited: (surface: AppSurface, sensitive_patterns?: Array<string | RegExp>) => void;
/**
 * Public mutation routes (auth: none + is_mutation) must be in the allowlist.
 *
 * Catches accidentally unprotected POST/PUT/DELETE routes. Routes like login
 * and bootstrap are public mutations by design — they go in the allowlist.
 */
export declare const assert_no_unexpected_public_mutations: (surface: AppSurface, allowlist?: Array<string>) => void;
/**
 * Routes with non-null input schemas should use POST (or other mutation methods),
 * not GET.
 *
 * GET routes with request bodies are technically allowed by HTTP but semantically
 * suspicious — they bypass browser security assumptions about GET being idempotent.
 * Query-string-driven filtering (audit log, list endpoints) should use params schemas
 * or query string parsing, not input schemas.
 *
 * Note: RPC endpoints (`create_rpc_endpoint`) use `input: z.null()` on their
 * route specs — the dispatcher handles body/query parsing internally. Real input
 * schemas live in `rpc_endpoints` surface, not on routes; see
 * `assert_rpc_ws_surface_invariants` for the parallel checks over RPC/WS
 * method shapes.
 */
export declare const assert_mutation_routes_use_post: (surface: AppSurface) => void;
/**
 * Keeper-protected routes must be under expected path prefixes.
 *
 * Catches keeper routes accidentally placed outside the API namespace
 * (e.g., a keeper route at `/health` or `/admin/` instead of `/api/...`).
 */
export declare const assert_keeper_routes_under_prefix: (surface: AppSurface, prefixes?: Array<string>) => void;
/** Options for `assert_error_schema_tightness`. */
export interface ErrorSchemaTightnessOptions {
    /** Minimum specificity level. Error schemas below this threshold fail. Default: `'enum'`. */
    min_specificity?: ErrorSchemaSpecificity;
    /** HTTP status codes to skip (e.g., middleware-injected codes). */
    ignore_statuses?: Array<number>;
    /** Routes to skip, in `'METHOD /path'` format. */
    allowlist?: Array<string>;
}
/**
 * Routes shipped by fuz_app whose error schemas require a tightness exemption.
 *
 * Currently empty — every fuz_app-shipped route (account login/password/
 * bootstrap/signup, db health/tables/:name/tables/:name/rows/:id) was tightened
 * in place to `z.enum([...])` / `z.literal(...)` against every emit-site error
 * code.
 *
 * Kept as a forward-compatibility hook: when new stock routes ship with
 * heterogeneous error surfaces that need an interim generic schema, add
 * them here instead of forcing every consumer to hand-maintain the entry.
 *
 * Paths assume the standard `/api/account` + `/api/db` prefixes used by every
 * fuz_app consumer. Merged into `default_error_schema_tightness.allowlist` so
 * consumers calling `assert_error_schema_tightness` directly inherit the
 * exemptions; the standard attack-surface suite also prepends these entries
 * underneath any consumer-supplied allowlist so project-specific entries are
 * additive.
 */
export declare const fuz_app_stock_route_tightness_allowlist: ReadonlyArray<string>;
/**
 * Baseline error schema tightness applied by
 * `describe_standard_attack_surface_tests` when no config is passed.
 *
 * Uses `min_specificity: 'enum'` (the assertion default) with `ignore_statuses`
 * for middleware-derived status codes that are commonly generic (auth middleware
 * produces multiple error codes at 401/403, and 429 comes from rate limiters),
 * and `allowlist` seeded with `fuz_app_stock_route_tightness_allowlist` so
 * fuz_app-shipped routes with heterogeneous generic schemas don't force every
 * consumer to hand-maintain an identical allowlist. Consumers can pass a
 * narrower config with project-specific `allowlist` entries, or pass `null`
 * to skip the assertion entirely.
 */
export declare const default_error_schema_tightness: ErrorSchemaTightnessOptions;
/**
 * Assert that all error schemas meet a minimum specificity threshold.
 *
 * Calls `audit_error_schema_tightness` and fails on any entry below
 * the configured threshold. Use `allowlist` and `ignore_statuses` to exclude
 * known exceptions during progressive tightening.
 *
 * @throws AssertionError listing every route × status combination whose error
 *   schema specificity is below `min_specificity` (default `'enum'`) and is
 *   not in `allowlist` or `ignore_statuses`.
 */
export declare const assert_error_schema_tightness: (surface: AppSurface, options?: ErrorSchemaTightnessOptions) => void;
/**
 * Run all structural invariants. Options-free — applies universally.
 *
 * Catches schema/surface generation bugs: missing 401/403/400 declarations,
 * empty descriptions, duplicate routes, middleware-injected error codes
 * unpropagated to routes, structurally invalid error schemas, error codes
 * appearing at multiple statuses, and generic 404 schemas on param routes.
 *
 * @throws AssertionError on the first invariant violation; the message names
 *   the offending route and the missing/inconsistent field.
 */
export declare const assert_surface_invariants: (surface: AppSurface) => void;
/**
 * Run all RPC / WS structural invariants. Options-free — applies
 * universally to the `surface.rpc_endpoints` and `surface.ws_endpoints`
 * slots produced by `generate_app_surface`.
 *
 * Parallel of `assert_surface_invariants` for the non-REST surfaces.
 * Within-endpoint duplicate method names and the auth-shape biconditional
 * are already enforced at startup by `compile_action_registry` (see
 * `actions/CLAUDE.md` §Registry compile) — these assertions cover only
 * the contract-surface concerns that a runtime registration check
 * cannot: empty descriptions, missing protocol-action spread on WS
 * endpoints, and kind ⇔ auth drift on WS methods.
 *
 * @throws AssertionError on the first invariant violation; the message
 *   names the offending endpoint, method, and field.
 */
export declare const assert_rpc_ws_surface_invariants: (surface: AppSurface) => void;
/**
 * Run security policy invariants. Configurable with sensible defaults.
 *
 * Checks:
 * - Sensitive routes are rate-limited
 * - No unexpected public mutation routes
 * - Input schemas use mutation methods (not GET)
 * - Keeper routes under expected prefixes
 *
 * @throws AssertionError on the first policy violation; the message names
 *   the offending route.
 */
export declare const assert_surface_security_policy: (surface: AppSurface, options?: SurfaceSecurityPolicyOptions) => void;
//# sourceMappingURL=surface_invariants.d.ts.map