(): FactExternalFetcher import {create_default_fetcher} from '@fuzdev/fuz_app/db/fact_store.js'; Default fetcher backed by globalThis.fetch.
returns
FactExternalFetcher PG-backed FactStore implementation.
Wraps the raw queries in db/fact_queries.ts with the lifecycle the
FactStore interface promises:
put, stream hash on put_ref (counting bytes against
the caller-supplied size)ON CONFLICT DO NOTHING in the queries layer)content_type signals JSON and the
caller didn't pass an explicit refs arraynull + log warning (treat as
unavailable; GC / repair is a separate concern)Embedded vs disk split: writes route by size. Bytes <= embedded_threshold
land in the PG bytes column; larger bytes go to the disk CAS at
<facts_dir>/<shard>/<rest> (db/fact_disk_storage.ts) and the row records a
file:<shard>/<rest> external_url. put takes fully-buffered bytes;
put_stream is the bounded-memory streaming twin (hash BLAKE3 + SHA-256 in
one pass, spill past the threshold, enforce max_bytes / ENOSPC). Both need
disk_root + fs (the runtime/*Deps) configured for the over-threshold
path; without them, an oversize put throws and the caller must put_ref
against an externally-managed URL (federation / stub-fetcher tests).
5 declarations
(): FactExternalFetcher import {create_default_fetcher} from '@fuzdev/fuz_app/db/fact_store.js'; Default fetcher backed by globalThis.fetch.
FactExternalFetcher number import {FACT_EMBEDDED_THRESHOLD_DEFAULT} from '@fuzdev/fuz_app/db/fact_store.js'; Default embedded-vs-referenced cutoff (1 MiB).
FactExternalFetcher import type {FactExternalFetcher} from '@fuzdev/fuz_app/db/fact_store.js'; Fetcher abstraction so tests can stub external URL retrieval.
fetch_streamtype (url: string) => Promise<ReadableStream<Uint8Array>>
fetch_bytestype (url: string) => Promise<Uint8Array>
import {PgFactStore} from '@fuzdev/fuz_app/db/fact_store.js'; PG-backed FactStore. Delegates to db/fact_queries.ts for I/O and adds
the lifecycle layer described in the module doc.
FactStoreconstructortype new (options: PgFactStoreDeps): PgFactStore
optionsputStore fully-buffered bytes, routing by size: <= embedded_threshold into
the PG bytes column; larger into the disk CAS (when disk_root + fs
are configured) at <facts_dir>/<shard>/<rest> with a file: URL. Oversize
without a disk root throws so the caller routes it through put_ref
explicitly. Idempotent — ON CONFLICT DO NOTHING + content-addressed disk
filenames make a re-write a no-op.
type (bytes: Uint8Array<ArrayBufferLike>, options?: FactPutOptions | undefined): Promise<string & $brand<"FactHash">>
bytesUint8Array<ArrayBufferLike>options?FactPutOptions | undefinedPromise<string & $brand<"FactHash">>put_streamStream bytes into the store with bounded memory, returning the finalized
digests + size. Delegates the byte path to stream_fact_to_disk (hash
BLAKE3 + SHA-256 in one pass, buffer to the embedded threshold, spill to the
disk CAS), then inserts the fact row by placement — embedded bytes go to
the PG bytes column, disk-spilled bytes record the file: external_url.
The cap is enforced mid-stream (PayloadTooLargeError); a disk-full mid-
stream throws StorageFullError.
Refs: explicit options.refs are recorded; JSON auto-extraction is NOT
attempted (it would need a buffered re-read, defeating the bounded-memory
contract) — streamed uploads are opaque blobs.
Requires fs (and, for the over-threshold spill, disk_root) to be
configured. The streaming twin of put; mirrors the Rust
FactStore::put_stream.
type (stream: ReadableStream<Uint8Array<ArrayBufferLike>>, max_bytes: number, options?: FactPutOptions | undefined): Promise<...>
streamReadableStream<Uint8Array<ArrayBufferLike>>max_bytesnumberoptions?FactPutOptions | undefinedPromise<PutStreamOutcome>put_refStream-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.
type (url: string, size: number, options?: FactPutOptions | undefined): Promise<string & $brand<"FactHash">>
urlstringsizenumberoptions?FactPutOptions | undefinedPromise<string & $brand<"FactHash">>getRetrieve 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.
type (hash: string & $brand<"FactHash">): Promise<Uint8Array<ArrayBufferLike> | null>
hashstring & $brand<"FactHash">Promise<Uint8Array<ArrayBufferLike> | null>hastype (hash: string & $brand<"FactHash">): Promise<boolean>
hashstring & $brand<"FactHash">Promise<boolean>get_metatype (hash: string & $brand<"FactHash">): Promise<FactMeta | null>
hashstring & $brand<"FactHash">Promise<FactMeta | null>get_refstype (hash: string & $brand<"FactHash">): Promise<(string & $brand<"FactHash">)[]>
hashstring & $brand<"FactHash">Promise<(string & $brand<"FactHash">)[]>deleteDrop 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.
type (hash: string & $brand<"FactHash">): Promise<{ size: number; external_url: string | null; } | null>
hashstring & $brand<"FactHash">Promise<{ size: number; external_url: string | null; } | null>{size, external_url} for the deleted row, or null if
no row matched the hash.
PgFactStoreDeps import type {PgFactStoreDeps} from '@fuzdev/fuz_app/db/fact_store.js'; 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 disk CAS. 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 to disk.
disk_root is the facts directory backing the <shard>/<rest> disk CAS;
fs supplies the filesystem capabilities (a RuntimeDeps satisfies it).
When both are set, oversize put + put_stream write to disk and the
default fetcher reads from it. When unset, oversize put/put_stream
spill throws and reads fall back to the globalThis.fetch-backed default
fetcher (or an injected stub). log is optional — the only call site is the
verify-mismatch warning path.
depstype QueryDeps
embedded_threshold?type number
disk_root?type string
fs?type FactDiskStorageDeps
fetcher?type FactExternalFetcher
log?type Logger