Summary
Six CLI commands fail end-to-end on a database produced by npx ruvector create, and npx ruvector embed text fails immediately on
a fresh npm install. Both are reproducible on ruvector@0.2.25
straight from npm.
Reproduction (~30 seconds)
npx ruvector create /tmp/x.db -d 384 -m cosine
echo '[{"id":"a","vector":[…384 floats…]}]' > /tmp/v.json
npx ruvector insert /tmp/x.db /tmp/v.json
# → SyntaxError: Unexpected token 'r', "redb…" is not valid JSON
npx ruvector stats /tmp/x.db # same crash
npx ruvector search /tmp/x.db -v '[…]' -k 5 # same crash
npx ruvector embed text "hello"
# → Error: ONNX WASM files not bundled. The onnx/ directory is
missing.
benchmark runs to completion but its rates are unreliable (Promise
leak — see below). export and import fail with "method does not
exist" errors.
Root causes
1. bin/cli.js insert / search / stats / export / import
handlers
const dbData = fs.readFileSync(dbPath, 'utf8');
const parsed = JSON.parse(dbData); // ← bin/cli.js:191,
241, 288, 1968, 2010
const dimension = parsed.dimension || 384;
create writes a redb (Rust binary) file via the native binding's
storagePath. JSON.parse of that file crashes on the magic bytes
"redb…". The same handlers also call methods that do not exist on
VectorDBWrapper: db.load, db.save, db.stats, db.getStats.
Verified API surface (dist/index.js):
constructor, insert, insertBatch, search, get, delete, len, isEmpty
(all async)
Same handlers also pass dimension (singular) where the wrapper
expects dimensions, pass topK where the wrapper passes k to
native, and don't await the async wrapper methods.
2. benchmark (bin/cli.js:380-440)
db.insertBatch(vectors) and db.search(query) are never awaited;
the action handler isn't async. Benchmark numbers reflect spinner
timing, not actual ingest/search completion.
3. ONNX WASM not bundled (package.json build script)
"build": "tsc && cp src/core/onnx/pkg/package.json
dist/core/onnx/pkg/"
This copies one package.json. The actual WASM payload —
loader.js, ruvector_onnx_embeddings_wasm.{js,_bg.js,_bg.wasm} —
never reaches dist/. At runtime onnx-embedder.js:184 looks for
dist/core/onnx/pkg/ruvector_onnx_embeddings_wasm.js and throws
"ONNX WASM files not bundled. The onnx/ directory is missing." The
package.json files array also doesn't include src/core/onnx/,
so even raw-source fallback is impossible.
Proposed fix (already implemented locally; happy to PR)
I have a working fix on fix/cli-sidecar-and-onnx-bundling (228
lines in bin/cli.js, 1 line in package.json, 36 lines in
scripts/verify-dist.js). Architecture summary:
- CLI handlers — write a
<dbPath>.meta.json sidecar in create
carrying {dimensions, metric, version}.
insert/search/stats/export/import read the sidecar instead
of JSON.parse-ing the redb. All handlers become async, await every
wrapper call, use canonical constructor keys, coerce numeric ids to
strings in place, and pass k not topK.
- Defensive guards — error clearly if sidecar exists but DB
doesn't (and vice versa), so the native binding can't silently
fabricate a fresh empty DB.
- Build script — copy the full
src/core/onnx/ tree into
dist/core/onnx/ so the loader can find its WASM at runtime.
verify-dist.js — assert all 5 ONNX runtime assets exist
before publish, so this regression cannot ship silently again.
- Honest disclosures —
VectorDBWrapper has no
list/iter/keys, so export is metadata-only and the success
message + import warning say so.
Question before I send a PR
The sidecar pattern is one of two reasonable architectures. The other
is to add an enumeration / metadata-read method to VectorDBWrapper
(e.g. db.metadata() returning {dimensions, metric, count}) so
the CLI can recover dimensions from the redb itself.
The wrapper-API approach is cleaner long-term but a bigger change.
The sidecar is a small CLI-only patch that ships today. Which would
you prefer for the PR? Happy to align before opening it.
I can post the diff for review here as a comment if helpful, or open
the PR directly once you confirm direction.
Summary
Six CLI commands fail end-to-end on a database produced by
npx ruvector create, andnpx ruvector embed textfails immediately ona fresh
npm install. Both are reproducible onruvector@0.2.25straight from npm.
Reproduction (~30 seconds)
benchmarkruns to completion but its rates are unreliable (Promiseleak — see below).
exportandimportfail with "method does notexist" errors.
Root causes
1.
bin/cli.jsinsert / search / stats / export / importhandlers
createwrites a redb (Rust binary) file via the native binding'sstoragePath.JSON.parseof that file crashes on the magic bytes"redb…". The same handlers also call methods that do not exist on
VectorDBWrapper:db.load,db.save,db.stats,db.getStats.Verified API surface (dist/index.js):
Same handlers also pass
dimension(singular) where the wrapperexpects
dimensions, passtopKwhere the wrapper passesktonative, and don't
awaitthe async wrapper methods.2.
benchmark(bin/cli.js:380-440)db.insertBatch(vectors)anddb.search(query)are never awaited;the action handler isn't
async. Benchmark numbers reflect spinnertiming, not actual ingest/search completion.
3. ONNX WASM not bundled (
package.jsonbuild script)This copies one
package.json. The actual WASM payload —loader.js,ruvector_onnx_embeddings_wasm.{js,_bg.js,_bg.wasm}—never reaches
dist/. At runtimeonnx-embedder.js:184looks fordist/core/onnx/pkg/ruvector_onnx_embeddings_wasm.jsand throws"ONNX WASM files not bundled. The onnx/ directory is missing." The
package.jsonfilesarray also doesn't includesrc/core/onnx/,so even raw-source fallback is impossible.
Proposed fix (already implemented locally; happy to PR)
I have a working fix on
fix/cli-sidecar-and-onnx-bundling(228lines in
bin/cli.js, 1 line inpackage.json, 36 lines inscripts/verify-dist.js). Architecture summary:<dbPath>.meta.jsonsidecar increatecarrying
{dimensions, metric, version}.insert/search/stats/export/importread the sidecar insteadof
JSON.parse-ing the redb. All handlers become async, await everywrapper call, use canonical constructor keys, coerce numeric ids to
strings in place, and pass
knottopK.doesn't (and vice versa), so the native binding can't silently
fabricate a fresh empty DB.
src/core/onnx/tree intodist/core/onnx/so the loader can find its WASM at runtime.verify-dist.js— assert all 5 ONNX runtime assets existbefore publish, so this regression cannot ship silently again.
VectorDBWrapperhas nolist/iter/keys, soexportis metadata-only and the successmessage +
importwarning say so.Question before I send a PR
The sidecar pattern is one of two reasonable architectures. The other
is to add an enumeration / metadata-read method to
VectorDBWrapper(e.g.
db.metadata()returning{dimensions, metric, count}) sothe CLI can recover dimensions from the redb itself.
The wrapper-API approach is cleaner long-term but a bigger change.
The sidecar is a small CLI-only patch that ships today. Which would
you prefer for the PR? Happy to align before opening it.
I can post the diff for review here as a comment if helpful, or open
the PR directly once you confirm direction.