Releases: libredb/libredb-database
Release list
v0.2.2 — complete browser-entry documentation
Patch Changes
-
79559e8: Document the browser entry's full export surface.
The browser entry now declares its exports as documented local aliases instead of bare re-exports: a symbol exported by two entrypoints is emitted as an undocumented reference for the second one by the documentation tooling, which left the browser half of the API blank on JSR and in editors. Every symbol now carries browser-context documentation; runtime behavior and the exported API are unchanged.
v0.2.1 — complete API documentation and type exports
Patch Changes
-
6f5e953: Complete the API documentation surface and export the types it references.
Every exported symbol — including interface and class members — now carries JSDoc, and both entrypoints carry an explicit module doc, so generated documentation (JSR, editors) is complete. Types that public signatures reference are now exported instead of being reachable-but-unnamed:
Transaction,Entry,Key,Value,Open, and the lens seamStorefrom the main entry;Transaction,Entry,Key,Value, andStorefrom the browser entry. No runtime behavior changes.
v0.2.0 — durability, safety, and API-contract hardening
Minor Changes
-
69f7161: Durability, safety, and API-contract hardening across the kernel, adapters, lenses, and CLI (the pre-announcement audit wave).
On-disk format: new databases now begin with an 8-byte
LRDBmagic/version header, and each record header carries a checksum of its own length field. Files written by earlier releases (headerless) keep opening through a legacy read path, and keep their legacy record framing on later appends. The header is what letsopen()refuse a file that is not a LibreDB database with a clear error instead of destroying it; the record-header checksum is what lets recovery refuse a damaged length field instead of mistaking it for a torn tail.DOWNGRADE WARNING: a file written by this release must never be opened by 0.1.3 or older — the old recovery cannot parse the header, classifies the whole file as a torn tail, and silently truncates it to zero bytes. Back up before any downgrade. Three smaller legacy-behavior changes: a headerless file whose only record is torn/incomplete now refuses to open as
NOT_A_DATABASE(0.1.3 recovered it to an empty database; refusing is the safe reading, since such a file is indistinguishable from a foreign one); any file shorter than the 8-byte header is likewise refused untouched (a crash inside the first bytes of a brand-new database's first-ever commit therefore needs a manual delete — nothing in it was acknowledged); and a legacy length-field corruption still reads as a torn tail (the legacy format has no header checksum — the v1 format exists to close exactly that gap).Kernel:
open({ path })on a non-LibreDB file throwsNOT_A_DATABASEand leaves the file byte-for-byte untouched (previously the file was silently truncated to zero).- Recovery classifies failures: a torn tail truncates (reported through the new
onRecoveryopen option), while mid-log corruption throwsCORRUPT_WALand truncates nothing. Record payloads are structurally validated during replay. - A failed append/fsync latches the database: every later
transact()throwsFAILEDuntil reopen, so an IO error can never lead recovery to silently drop later acknowledged commits. transact()rejects async callbacks (ASYNC_TRANSACTION): writes after anawaitcould never reach the log.- Keys and values are copied at the transaction boundary in both directions — caller buffer reuse and mutation of returned buffers can no longer corrupt the store.
getRangesnapshots at first iteration, so delete-while-scanning visits every entry exactly once.close()inside a transaction throwsCLOSE_IN_TRANSACTIONinstead of surfacing a raw file error.open()takes an exclusive per-file lock (<path>.lock, pid/host/nonce): a second writer throwsLOCKEDinstead of silently diverging; locks from verifiably dead holders are reclaimed automatically.FileSystemgains an optionallock()seam method.- All kernel failures are now
LibreDbErrorinstances carrying a stablecode(exported, with theErrorCodeandRecoveryInfotypes).
Adapters:
- node-fs: creating a database fsyncs the parent directory (a fresh database can no longer vanish wholesale on power loss); a directory-fsync failure that is not a platform limitation (e.g. EIO) now surfaces as an error instead of being silently ignored; recovery truncation is fsync'd; reads are positional on the WAL's own file descriptor instead of re-reading the whole file per call.
- OPFS: reads loop until filled, so a legal short read can no longer masquerade as a torn tail; recovery treats an incomplete read as an IO fault (
INCOMPLETE_READ), never as license to truncate.
Lenses:
- Collection/table names may not be empty or contain
:(both broke namespace isolation); ids keep full freedom. - Strings that are not well-formed UTF-16 (lone surrogates) are rejected wherever they would become keys, ids, names, or kv values — distinct strings can no longer silently collide on one key.
- Relational
numbercolumns rejectNaNand the infinities (JSON would store them asnull). doc()refuses a name cataloged as a relational table (it would bypass schema validation);table()refuses a document collection's name.find()/where()reject a predicate field explicitly set toundefined, which previously matched documents missing the field.
CLI:
- Write commands rely on the kernel's exclusive lock;
--forceremoves a lock only when its holder is not verifiably alive, and never deletes a file that is not a libredb lock. Automatic reclaim is stricter still: only a lock whose holder is VERIFIABLY dead (same host, pid gone) is reclaimed without--force— anonymous locks (empty, or the sentinel-only 0.1.x format) carry no liveness information and now require--force. get/scanescape control characters (including tab and newline) by default so untrusted values cannot inject terminal escape sequences — scripts that consumed values verbatim should pass--raw.
New exports:
LibreDbError,ErrorCode,RecoveryInfo,nodeFileSystem, andreadonlyFileSystem(open a database for inspection with no lock and no writes — the supported way to read a file a live writer holds).Docker image now runs as a non-root user (distroless
:nonroot, uid 65532): bind-mounted directories must be writable by that uid, or pass--user "$(id -u):$(id -g)".
v0.1.3
First stable release of the distribution-channels work (issue #6). LibreDB now
ships through multiple channels:
- npm and JSR —
@libredb/libredb - CLI —
npx libredb(zero dependencies):inspect,stats,get,scan,
set,delete,import - Standalone binaries — Linux, macOS, Windows (x64 + arm64), attached below
with.sha256checksums - Docker — multi-arch image on GHCR and Docker Hub
(ghcr.io/libredb/libredb,libredb/libredb)
Under the hood: the kernel is now runtime-agnostic (node:fs moved to an
adapter), a new browser entry (@libredb/libredb/browser) ships with OPFS-backed
persistence, and writes are guarded (advisory lock, reserved-key protection).
See CHANGELOG.md for details.
v0.1.2 - distribution channels (npm, JSR, binaries, GHCR + Docker Hub)
Patch release validating the full pipeline including Docker Hub publishing (fixes the Docker Hub username being a repo variable, not a secret).
v0.1.1 - distribution channels (npm, JSR, binaries, GHCR + Docker Hub)
Patch release exercising the full pipeline including Docker Hub. Same distribution channels as v0.1.0, with the Docker image now also pushed to Docker Hub alongside GHCR.
v0.1.0 - distribution channels
First release carrying the full distribution-channels work (issue #6), published
end-to-end from the feat/distribution-channels branch:
- Runtime-agnostic core plus a browser entry (
@libredb/libredb/browser). - Published to JSR (
@libredb/libredb) alongside npm. - CLI
libredb(npx libredb): inspect, stats, get, scan, set, delete, import. - Standalone binaries for Linux, macOS, and Windows (x64 + arm64) attached below,
each with a.sha256checksum. - Multi-arch Docker image at
ghcr.io/libredb/libredb. - OPFS-backed browser persistence via
opfsFileSystem.
v0.0.4
First release published from the public LibreDB repository.
LibreDB is a small, readable, embeddable, multi-model database: one ordered
key-value core with thin key-value, document, and relational lenses on top, plus
a self-describing catalog. ESM-only, zero runtime dependencies, 100% line
coverage on the core, and crash recovery proven by deterministic simulation
testing.
Install:
bun add @libredb/libredb
# or: npm install @libredb/libredb
See the README and docs/ for the lens guides, architecture, and reliability model.