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

@dikolab/vdb

v0.14.0

Published

A multi-partition vector database — lexical (BM25F), vector, and hybrid search plus a simple partitioned record store (list + CRUD with many-to-many partition attachment), for Node.js and Deno.

Readme

@dikolab/vdb

A multi-partition vector database: lexical (BM25F), vector (cosine), and hybrid (RRF) search over named partitions — each with its own indexes, field weights, and embedding provider — searchable one partition at a time or across a dynamic slice. Beyond ranked search it is also a simple partitioned record store: list + CRUD where a stable-id record is attached to a many-to-many selection of partitions. Runs the same on Node.js and Deno.

It is a thin TypeScript wrapper over a Rust core compiled to WebAssembly with wasm-pack — the WASM does the scoring and embedding, and the TypeScript owns the store layout, indexes, CLI, and daemon. The WASM loads locally on Node and offline on Deno (it ships in the module graph, so deno cache / deno install cover it — no per-process network fetch).

npm JSR Docs License: AGPL-3.0 Support

Documentation

Full documentation is published on the project docs site:

  • Overview — features, install, and a quick start.
  • Examples — end-to-end store, partition, record, and search usage.

A comprehensive reference ships in this package under docs/: partitions, records, search, storage, configuration, architecture (the Rust → WASM crates), CLI, API, integration, and embedding vdb.

Install

npm add @dikolab/vdb          # npm / Node.js / bundlers
deno add jsr:@dikolab/vdb     # Deno (JSR)

The package ships as ES modules only.

Requires Deno ≥ 2.6.0 (for source-phase WebAssembly imports, which let the WASM load offline). Node is unaffected — engines.node: >=18 is unchanged.

Quick start

Open a client against a store, declare a partition with a column schema, create records, and search:

import {
   createClient,
   ExecutionMode,
   AttributeType,
   SearchAlgo,
} from "@dikolab/vdb";

const vdb = createClient({ db: "./store", mode: ExecutionMode.InProcess });

// Declare a partition and the columns records may carry (full-text columns are searchable).
await vdb.createPartition("docs", {
   title: { type: AttributeType.String, fullTextSearch: true, weight: 2 },
   body: { type: AttributeType.String, fullTextSearch: true, weight: 1 },
});

// Create a record attached to one or more partitions.
const rec = await vdb.create({
   partitions: ["docs"],
   attributes: [
      { field: "title", value: "Install Guide" },
      { field: "body", value: "Run npm add @dikolab/vdb to get started." },
   ],
});

// Ingesting many at once? `createMany` reindexes the batch ONCE (O(N), not the
// O(N²) of N eager creates) and reports a per-record outcome. (Follow-up per-record
// update/delete each reindex again — defer them with `{ reindex: false }` and end
// the batch with one `rebuild()`. A deferred, un-settled write is detectable:
// `status().pendingRebuild` is true and `check()` fails with a `stale-index` error.)
await vdb.createMany([
   { partitions: ["docs"], attributes: [{ field: "body", value: "first" }] },
   { partitions: ["docs"], attributes: [{ field: "body", value: "second" }] },
]);

// Unranked list, filtered by partition.
await vdb.list({ partitions: ["docs"], limit: 20 });

// Ranked search — each partition ranks with its own config; a slice fuses.
const hits = await vdb.search({
   query: "install",
   partitions: ["docs"],
   algo: SearchAlgo.Hybrid,
});
for (const hit of hits.items) {
   console.log(hit.score.toFixed(3), hit.matchedTerms, hit.snippet);
}

Or from the CLI:

vdb db init --db ./store
vdb partition create docs --db ./store --column 'title:string:fulltext:2' --column 'body:string:fulltext:1'
vdb record create --db ./store --partition docs --attr 'title=Install Guide' --attr 'body=Run the installer.'
vdb search "install" --db ./store --partition docs --algo hybrid

Search capabilities

  • Lexical, vector & hybrid — BM25F full-text, cosine vector, and RRF-hybrid search per partition, with rank-fused cross-partition slices.
  • Approximate vector search (ANN) — opt in per partition to an HNSW index (ann.enabled) that generates candidates sub-linearly and then re-scores them exactly by cosine, so ranking is unchanged; off by default, with the exact scan the default and the fallback for small partitions.
  • Query grammar — a quoted "exact phrase" (positional), -term negation, and boolean AND / OR / (…); a plain bag-of-words query is unchanged and fully backward-compatible.
  • Recall expansion — curated synonyms (loginsignin, configconfiguration, …) and adjacent-word n-grams widen recall without perturbing base ranking; on by default, toggleable per partition (synonyms/ngrams, or --synonyms/--ngrams).
  • Relevance signals — each hit carries a top-relative confidence in [0, 1] beside the raw score, plus matchedTerms and matchedFields.
  • Deterministic ranking — a pure function of (corpus, query): exactly-tied scores break by ascending id, so ordering is reproducible across rebuilds, insertion orders, and runtimes.
  • Engine metrics, readiness & integritystats()/status() expose corpus, index, and daemon-cache figures (distinctTerms, termsIndexed, cacheStats, wasmMemoryBytes); status() is cheap (a record file count, with no embedding module loaded for a provider: "none" store); ready() is a cheap probe that forces the engine to load; hasPendingRebuild() is a WASM-free stat for a fast owed-rebuild poll; check() validates the store and surfaces best-effort semanticContradictions.
  • Fusion primitivefuseRankedSets fuses N externally-ranked sets (one primary) into a single deduped, ranked, paginated page — the engine's rank fusion, exported for reuse.
  • Diversity & rerank — opt-in SearchParams.diversity (MMR) cuts near-duplicate crowding using record vectors (exported as mmrSelect); opt-in SearchParams.rerank reorders the top with an injected RerankProvider (Node-only onnxCrossEncoder, or bring your own). Both are strict no-ops when absent.

Three entrypoints, one engine

  • @dikolab/vdb — the library (createClientVdb); what a host application imports.
  • @dikolab/vdb/cli — the thin vdb CLI (daemon, partitions, records, search).
  • @dikolab/vdb/worker — the detached daemon a daemon-mode client spawns.

Run the engine in-process (embed it, no IPC) or via a shared per-store daemon — see Embedding vdb.

Content-addressed ids

A record's id is a ULID by default, or you may bring your own — pass create({ id, … }) to store under a caller-supplied id, and re-creating the same id upserts in place (preserving createdAt). The exported contentId(text) helper turns any text into a stable, portable content hash you can use as that id, so identical content maps to the same record.

Support

If @dikolab/vdb is useful to you, you can support its development:

Support development

License

AGPL-3.0-only © 2026 Diko Consunji