/**
 * `GET /api/facts/:hash` — content-addressed fact serving.
 *
 * Resolves a fact hash to the bytes referenced by at least one viewable
 * cell. Embedded facts stream from the `facts.bytes` PG column;
 * external facts (filesystem-backed `file:<shard>/<rest>` URLs) either
 * return an `X-Accel-Redirect` header pointing into nginx's internal
 * facts location (production) or stream from disk via the filesystem
 * `FactExternalFetcher` (dev / tests). The runtime mode is selected by
 * the optional `x_accel_redirect_prefix` factory option — set in prod,
 * unset in dev.
 *
 * REST, not RPC: binary responses don't fit the JSON-RPC envelope.
 *
 * ## Authorization
 *
 * Auth is `{account: 'none', actor: 'none'}` — the dispatcher's
 * authorization phase is skipped for pure-public routes, so this handler
 * builds the `RequestContext` itself from `c.var.account_id` (populated
 * by the `/api/*` session middleware) by resolving the caller's single
 * actor and loading their role_grants. Unauthed callers pass through
 * with `req_ctx: null`. Viewers are admitted via `can_view_cell` over
 * **every** active cell that references the hash. Multi-actor accounts
 * fall through with `req_ctx: null` — there's no `acting?` slot on a
 * pure-public route, so multi-actor callers are treated as anonymous
 * (admitted only by the public-visibility branch). A fact is viewable iff
 * at least one referencing cell admits the caller; unauthenticated callers
 * are admitted only via a referencing cell with `cell.visibility ===
 * 'public'`. Facts with no referencing active cell are unreachable here —
 * orphan-fact GC reaps them separately.
 *
 * 404 is the universal "not viewable" response: missing fact, missing
 * referencing cell, all referencing cells private to other actors. We
 * deliberately don't distinguish 403 from 404 — the existence of a
 * private hash should not leak through the public surface.
 *
 * ## Defense-in-depth
 *
 * The `external_url` regex is re-validated before issuing
 * `X-Accel-Redirect` even though `PgFactStore.put_ref` only writes
 * `file:<shard>/<rest>`-shaped URLs. A future row-injection bug
 * upstream would otherwise hand nginx an attacker-controlled path.
 *
 * @module
 */
import type { Logger } from '@fuzdev/fuz_util/log.js';
import { type RouteSpec } from '../http/route_spec.js';
import type { AppDeps } from '../auth/deps.js';
export interface CreateServeFactRouteSpecOptions {
    /**
     * App deps reference. Currently unused at handler time (cell + fact
     * tables are read via `RouteContext.db`); kept on the factory
     * signature for symmetry with sibling route factories and to give
     * future role_grant-scoped viewer extensions somewhere to read other
     * deps without changing the public shape.
     */
    deps: AppDeps;
    /** Absolute path of the facts directory. Used for the dev/test streaming path. */
    facts_dir: string;
    /**
     * When set, external facts return an `X-Accel-Redirect` pointing at
     * `${prefix}<shard>/<rest>` — nginx's internal facts location serves
     * the bytes. When unset, external facts stream from
     * `<facts_dir>/<shard>/<rest>` directly. Production sets this (e.g.
     * `/_facts/`); tests + dev leave it unset.
     */
    x_accel_redirect_prefix?: string;
    log: Logger;
}
/**
 * Build the `GET /api/facts/:hash` `RouteSpec`.
 *
 * Pure-public auth — the handler builds the per-request `RequestContext`
 * from `c.var.account_id` and enforces visibility per-fact via the
 * cell-walk above.
 */
export declare const create_serve_fact_route_spec: (options: CreateServeFactRouteSpecOptions) => RouteSpec;
//# sourceMappingURL=serve_fact_route.d.ts.map