Skip to content

Releases: libredb/libredb-database

v0.2.2 — complete browser-entry documentation

Choose a tag to compare

@cevheri cevheri released this 03 Jul 12:12

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

Choose a tag to compare

@cevheri cevheri released this 03 Jul 12:03

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 seam Store from the main entry; Transaction, Entry, Key, Value, and Store from the browser entry. No runtime behavior changes.

v0.2.0 — durability, safety, and API-contract hardening

Choose a tag to compare

@cevheri cevheri released this 03 Jul 07:38

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 LRDB magic/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 lets open() 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 throws NOT_A_DATABASE and 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 onRecovery open option), while mid-log corruption throws CORRUPT_WAL and truncates nothing. Record payloads are structurally validated during replay.
    • A failed append/fsync latches the database: every later transact() throws FAILED until reopen, so an IO error can never lead recovery to silently drop later acknowledged commits.
    • transact() rejects async callbacks (ASYNC_TRANSACTION): writes after an await could 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.
    • getRange snapshots at first iteration, so delete-while-scanning visits every entry exactly once.
    • close() inside a transaction throws CLOSE_IN_TRANSACTION instead of surfacing a raw file error.
    • open() takes an exclusive per-file lock (<path>.lock, pid/host/nonce): a second writer throws LOCKED instead of silently diverging; locks from verifiably dead holders are reclaimed automatically. FileSystem gains an optional lock() seam method.
    • All kernel failures are now LibreDbError instances carrying a stable code (exported, with the ErrorCode and RecoveryInfo types).

    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 number columns reject NaN and the infinities (JSON would store them as null).
    • 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 to undefined, which previously matched documents missing the field.

    CLI:

    • Write commands rely on the kernel's exclusive lock; --force removes 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/scan escape 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, and readonlyFileSystem (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

Choose a tag to compare

@cevheri cevheri released this 29 Jun 15:20

First stable release of the distribution-channels work (issue #6). LibreDB now
ships through multiple channels:

  • npm and JSR@libredb/libredb
  • CLInpx libredb (zero dependencies): inspect, stats, get, scan,
    set, delete, import
  • Standalone binaries — Linux, macOS, Windows (x64 + arm64), attached below
    with .sha256 checksums
  • 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)

Choose a tag to compare

@cevheri cevheri released this 29 Jun 13:30

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)

Choose a tag to compare

@cevheri cevheri released this 29 Jun 13:26

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

Pre-release

Choose a tag to compare

@cevheri cevheri released this 29 Jun 13:17

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 .sha256 checksum.
  • Multi-arch Docker image at ghcr.io/libredb/libredb.
  • OPFS-backed browser persistence via opfsFileSystem.

v0.0.4

Choose a tag to compare

@cevheri cevheri released this 26 Jun 10:22
f609bb2

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.