/**
 * PG-backed `FactStore` implementation.
 *
 * Wraps the raw queries in `db/fact_queries.ts` with the lifecycle the
 * `FactStore` interface promises:
 *
 * - sync hash on `put`, stream hash on `put_ref` (counting bytes against
 *   the caller-supplied `size`)
 * - idempotent insert (`ON CONFLICT DO NOTHING` in the queries layer)
 * - JSON ref auto-extraction when `content_type` signals JSON and the
 *   caller didn't pass an explicit `refs` array
 * - verify-on-read for external content; embedded reads skip verify
 *   because PG storage IS the hash table
 * - mismatched external bytes return `null` + log warning (treat as
 *   unavailable; GC / repair is a separate concern)
 *
 * Embedded vs referenced split: callers route by size. `put` rejects
 * `bytes.length > embedded_threshold` so oversized content takes the
 * `put_ref` path explicitly. Auto-split inside `put` is a future option.
 *
 * Wired with a filesystem `file:`-URL fetcher (`create_file_fact_fetcher`)
 * at server assembly: bytes ≤ threshold embed via `put`, larger bytes go
 * through atomic temp+rename onto disk then `put_ref('file:<shard>/<rest>',
 * size)` for verified registration.
 *
 * @module
 */
import type { QueryDeps } from './query_deps.js';
import type { Logger } from '@fuzdev/fuz_util/log.js';
import { type FactHash } from '@fuzdev/fuz_util/fact_hash.js';
import type { FactMeta, FactPutOptions, FactStore } from '@fuzdev/fuz_util/fact_store.js';
/** Default embedded-vs-referenced cutoff (1 MiB). */
export declare const FACT_EMBEDDED_THRESHOLD_DEFAULT: number;
/** Fetcher abstraction so tests can stub external URL retrieval. */
export interface FactExternalFetcher {
    fetch_stream: (url: string) => Promise<ReadableStream<Uint8Array>>;
    fetch_bytes: (url: string) => Promise<Uint8Array>;
}
/** Default fetcher backed by `globalThis.fetch`. */
export declare const create_default_fetcher: () => FactExternalFetcher;
/**
 * Construction-time deps for `PgFactStore`.
 *
 * `embedded_threshold` (bytes) is the inline-vs-external cutoff: payloads
 * at or under it store embedded in the `fact` row, larger ones route to
 * the external fetcher. Defaults to `FACT_EMBEDDED_THRESHOLD_DEFAULT`
 * (1 MiB). Consumers tune it per workload — e.g. a much lower bound
 * (~16 KiB) keeps only small JSON inline and routes image originals +
 * thumbnails external. `fetcher` defaults to a `globalThis.fetch`-backed
 * implementation; tests inject a stub. `log` is optional — the only call
 * site is the verify-mismatch warning path.
 */
export interface PgFactStoreDeps {
    deps: QueryDeps;
    embedded_threshold?: number;
    fetcher?: FactExternalFetcher;
    log?: Logger;
}
/**
 * PG-backed `FactStore`. Delegates to `db/fact_queries.ts` for I/O and adds
 * the lifecycle layer described in the module doc.
 */
export declare class PgFactStore implements FactStore {
    #private;
    constructor(options: PgFactStoreDeps);
    /**
     * Store small bytes embedded in PG. Rejects oversized content so the
     * caller routes it through `put_ref` explicitly — implicit splitting
     * hides the size decision from the caller.
     */
    put(bytes: Uint8Array, options?: FactPutOptions): Promise<FactHash>;
    /**
     * Stream-hash external content and record `(hash, external_url, size)`.
     * Throws when the streamed byte count disagrees with the caller's
     * declared `size` — a size mismatch usually means the upload was
     * truncated or the URL points at the wrong content.
     */
    put_ref(url: string, size: number, options?: FactPutOptions): Promise<FactHash>;
    /**
     * Retrieve bytes. Embedded reads return PG bytes directly; external
     * reads fetch + verify and return `null` (with a warning log) when
     * the bytes don't match the stored hash.
     */
    get(hash: FactHash): Promise<Uint8Array | null>;
    has(hash: FactHash): Promise<boolean>;
    get_meta(hash: FactHash): Promise<FactMeta | null>;
    get_refs(hash: FactHash): Promise<Array<FactHash>>;
    /**
     * Drop a fact row. `fact_ref` rows referencing this hash as a source
     * cascade via the FK; `fact_ref` targeting this hash do **not** —
     * they remain as dangling pointers, consistent with the federation
     * model where `target_hash` is intentionally not a FK.
     *
     * Idempotent: deleting an absent fact returns `null`. The store does
     * NOT verify the fact is unreferenced — that policy lives one layer
     * up (the orphan-fact admin surface in the consumer; a future GC walker).
     *
     * External-URL unlink is the caller's responsibility — the store
     * doesn't know how to resolve `file:` / `s3:` / etc. URLs to a
     * deletable handle. Caller iterates the returned `external_url`
     * (when non-null) and dispatches to the appropriate cleanup
     * routine. Mirrors the read-side `FactExternalFetcher` split.
     *
     * @returns `{size, external_url}` for the deleted row, or `null` if
     *   no row matched the hash.
     */
    delete(hash: FactHash): Promise<{
        size: number;
        external_url: string | null;
    } | null>;
}
//# sourceMappingURL=fact_store.d.ts.map