npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

corvid-js

v0.4.1

Published

Browser/Worker binding for the corvid embedded database — the engine compiled to wasm32: idiomatic synchronous OOP (in-memory) plus async OPFS persistence via a dedicated Worker

Readme

corvid-js

The browser / Web Worker binding for corvid — the embedded database with vector (HNSW), full-text (BM25 + CJK bigrams), hybrid RRF/MMR retrieval, graph edges, and geo — compiled to WebAssembly and exposed as idiomatic OOP: a synchronous in-memory surface (Db, Collection, a fluent Query builder, field() predicates) plus an async OPFS-persistent surface (openOpfs() / AsyncDb) hosted in a dedicated Worker. No SQL, no JSON, no serialization on the data path; values cross the boundary natively.

  • Engine pin: corvid-db git dep, exact release tags per the bindings program (the engine PACKAGE is corvid-db — lib ident corvid).
  • npm: livenpm install corvid-js (published via the repo's release workflow; the prebuilt wasm ships in the package).

Use (browsers / bundlers) — in-memory, synchronous

import { Db, field, init } from 'corvid-js';

await init(); // fetch + instantiate the wasm module (the only async part)

const db = new Db();            // in-memory per session
const docs = db.collection('docs');

docs.insert('s1', {
  kind: 'doc',
  body: 'rust embedded database',
  v: new Float32Array([1.0, 0.0]),      // the Vector kind
});

// Hybrid retrieval: filter + vector + BM25, RRF fusion, MMR rerank.
const rows = docs
  .query()
  .filter(field('kind').eq('doc'))
  .vector('v', new Float32Array([1.0, 0.0]), 2, 'cosine')
  .text('body', 'rust database', 2)
  .fuseRrf(60)
  .rerankMmr(1.0)
  .limit(2)
  .run(); // [{ key, doc, score }]

// Phrase search: consecutive in-order tokens, BM25 scores.
docs.phraseSearch('body', 'embedded database', 10);

Use (browsers) — persistent, async (OPFS)

import { openOpfs, field } from 'corvid-js';

const db = await openOpfs('notes');   // one OPFS file, one Worker
const docs = await db.collection('docs');

await docs.insert('k1', { body: 'survives reloads', n: 1 });

const rows = await docs
  .query()
  .filter(field('n').ge(1))
  .run();

await docs.close();
await db.close();   // the OPFS lock frees the moment this resolves

Every AsyncDb/AsyncCollection/AsyncQuery method returns a Promise and mirrors the sync surface (the three documented deviations: name is a sync getter, update(key, fn) composes get→fn→CAS — exact under OPFS single-writer — and scanEach streams in chunks). Also on the async surface: dump()/load()/loadWithRenames() (portable byte streams), backupTo(name) (physical copy), and the storage trio storageEstimate() / requestPersistentStorage() / isPersistentStorage().

Single writer, by design. OPFS grants the database file exclusively per origin: a second tab's openOpfs of an open name rejects with Busy (19). The lock frees the moment close() resolves.

Storage is evictable unless persisted. Browser storage under pressure is evicted whole-origin (LRU); Safari may additionally evict script-created data after 7 idle days. openOpfs requests persistent storage by default (best-effort — check isPersistentStorage()), and storageEstimate() monitors usage (deliberately imprecise, per platform design).

Use (Node — tests, tooling, CLIs)

import { Db, field } from 'corvid-js/node'; // synchronous init at import

const db = new Db();

The node entry loads the same wasm binary browsers do; every call is identical. The async OPFS surface is browser-only (no binding is exported under Node — OPFS and Web Workers do not exist there).

The value mapping

| JS | engine | | --- | --- | | null, boolean, string | Null / Bool / Text | | number (integer-valued, ≤ 2^53) | Int — 2 and 2.0 collapse; CorvidFloat(n) forces the Float kind | | number (0.5, inf, NaN, -0.0), bigint | Float / Int (full i64) | | Uint8Array (Buffer included) | Bytes | | Float32Array | Vector | | Array / plain object | Array / Map |

Reading back: Int → number (or bigint beyond ±2^53); Float → number — f64 bits preserved except NaN payloads, which canonicalize across the JS↔wasm Number boundary (-0.0, ±inf are exact; vector elements keep their f32 bits). Keys are strings (UTF-8) or Uint8Arrays. Object.keys() of a mapped document enumerates the engine's ascending key-byte order (the v0.3.0 map_keys surface). The async surface additionally rejects Map/Set/Date, functions, symbols, and cyclic values with InvalidArgument (12) before they cross the worker boundary.

Errors are CorvidError (e.code = the C ABI's frozen 0–19 table, e.message = the engine text). The sync surface is fully synchronous; the async surface is fully Promise-based.

Build from source

npm install            # wasm-pack wrapper deps + vitest + playwright (Rust >= 1.88 + wasm32 target)
npm run build          # wasm-pack build --release --target web  -> pkg/
npm test               # the golden suite (230 lines) + regressions + OPFS suites
npm run test:browser   # the golden suite in real Chromium, Firefox, and WebKit (await init())
npm run test:e2e       # async OPFS fixtures + reload/cross-tab (Playwright; chromium + firefox full, webkit where its build ships OPFS)
npm run size-gate      # gzipped wasm <= 1 MiB (engine reference: 2 MiB)
npm run surface-gate   # docs/SURFACE.tsv vs the pinned engine surface
npm run examples       # the six-example tour
npm run lint           # cargo fmt --check + clippy -D warnings

Correctness story

The binding replays the engine's golden suite — the same fixture files the C ABI smoke harness runs — against its public API on every CI run: 267/267 executable lines across all eight fixture files. The six in-memory files (values, mutations, queries, schema, graph, geo; 230 lines) run against the sync surface — in Node AND in real browsers (await init(), same spec, unchanged: Chromium, Firefox, and WebKit). The two file-backed files (persist.txt, admin.txt; 37 lines) run against the async OPFS surface in Chromium and Firefox end to end in CI (real Worker, real OPFS file, real postMessage), and in WebKit wherever the engine build ships OPFS — verified on macOS WebKit; ubuntu's GTK WebKit build has no Storage Manager API at all, so those six tests skip there on a capability probe carrying the failure (they re-enable automatically if the build gains the API). Browser-only contracts are pinned on the same split: persistence across a real page reload, and the cross-tab single-writer Busy with the lock freeing exactly when close() resolves (docs/OPFS-SPEC.md §8 records the exact enforced-vs-skipped matrix).

Six runnable examples (examples/) — quickstart, hybrid, vector index families, text+CJK+phrase, graph, geo — execute on every CI leg with deterministic output, and run identically in a browser (only the loader line differs).

The binding contract for persistence is docs/OPFS-SPEC.md (review-gated, like the C ABI's FFI.md); the architecture ruling, value contract, and size budget are in docs/PLAN.md, and every engine construct is resolved to a binding API or a documented N/A in docs/SURFACE.tsv.

License: MIT.