Summary
@ruvector/[email protected] (published to npm) is unloadable in any Node.js consumer. Every entry point — CJS require(), ESM await import(), and the import condition pointing to pkg/rvf_wasm.mjs — transitively loads pkg/rvf_wasm.js, which contains both import.meta.url and a top-level export default while the package has no "type": "module" set. Node parses it as CJS and throws a SyntaxError before any runtime guard can execute.
This breaks every downstream agentdb / @claude-flow/memory / ruflo operation that touches the RVF backend (memory init, hooks pretrain, status, etc.). Encountered via [email protected] → @claude-flow/memory → [email protected] → @ruvector/[email protected].
Reproduction
npm install -g ruflo@latest # 3.6.12, ships @ruvector/[email protected]
mkdir /tmp/repro && cd /tmp/repro
ruflo init --full
ruflo memory init
Result:
/.../@ruvector/rvf-wasm/pkg/rvf_wasm.js:47
var thisDir = path.default.dirname(url.default.fileURLToPath(import.meta.url));
^^^^
SyntaxError: Cannot use 'import.meta' outside a module
at wrapSafe (node:internal/modules/cjs/loader:1378:20)
at Module._compile (node:internal/modules/cjs/loader:1428:41)
...
at async detectBackends (.../agentdb/dist/src/backends/factory.js:86:13)
ruflo status, ruflo hooks pretrain, and any other call path through agentdb's detectBackends() fails identically.
Root cause analysis
Three independent issues compound in the published artifact:
1. pkg/rvf_wasm.js mixes ESM-only syntax into a CJS-classified file
package.json has no "type" field, so Node treats .js files as CJS by default. But pkg/rvf_wasm.js contains:
- Line 47:
import.meta.url (inside a _isNode else branch)
- Line 53:
import.meta.url (inside the browser branch)
- Line 72: top-level
export default init;
These are all ESM-only. The author guards line 47 behind typeof __dirname !== 'undefined' — but that's runtime, not parse time. The file fails to parse before any guard runs. Same for line 53 (only relevant in browsers, but parser doesn't know that). Line 72 is unconditional ESM syntax in a CJS file.
2. pkg/rvf_wasm.mjs re-imports the broken .js
// pkg/rvf_wasm.mjs
import init from './rvf_wasm.js';
export default init;
So the import condition (which routes ESM consumers to .mjs) doesn't actually escape the bug — it just reaches the same broken file via a re-export, and Node still loads .js through the CJS translator because the package isn't marked as a module.
3. Two distinct kinds of consumers all hit the same crash
In ruflo's installed tree:
await import('@ruvector/rvf-wasm') from ESM (agentdb): picks the import condition → .mjs → re-imports .js → CJS parse → crash.
__importStar(require('@ruvector/rvf-wasm')) from CJS (@ruvector/rvf/dist/backend.js): picks the require condition → .js directly → CJS parse → crash.
There is no working code path.
Suggested fix (recommended)
Add "type": "module" to package.json and route require through a thin CJS shim, or drop CJS support entirely.
Option A — ESM-only (simplest, matches the file's actual syntax):
"name": "@ruvector/rvf-wasm",
"version": "0.1.7",
+ "type": "module",
"main": "pkg/rvf_wasm.js",
"exports": {
".": {
"types": "./pkg/rvf_wasm.d.ts",
- "import": "./pkg/rvf_wasm.mjs",
- "require": "./pkg/rvf_wasm.js",
- "default": "./pkg/rvf_wasm.js"
+ "default": "./pkg/rvf_wasm.mjs"
}
},
Tradeoff: CJS callers (currently only @ruvector/rvf/dist/backend.js in your stack) would get ERR_REQUIRE_ESM. They already crash today, so this is strictly better — and @ruvector/rvf should switch to dynamic import() anyway.
Option B — true dual package: keep .js as a real CJS file (replace import.meta.url with __dirname-only logic, replace export default with module.exports, replace await import('node:fs/promises') with require('node:fs/promises')), and have .mjs re-export from a separate ESM source that uses import.meta.url. More work but doesn't break require() consumers.
Option C — minimal patch keeping everything else the same: add "type": "module" and let the existing .js parse as ESM. The if (typeof module !== 'undefined') module.exports = init; line on row 71 silently no-ops in ESM, the import.meta.url and export default then parse correctly. CJS require() still breaks.
Pre-publish CI suggestion: add node -e "import('@ruvector/rvf-wasm').then(m => m.default())" and node -e "require('@ruvector/rvf-wasm')()" smoke tests on the packed tarball before publishing.
Workaround for end users (verified)
Single-line patch on the installed copy:
NODE_ROOT=$(npm root -g)
sed -i 's/"main": "pkg\/rvf_wasm.js",/"type": "module",\n "main": "pkg\/rvf_wasm.js",/' \
$NODE_ROOT/ruflo/node_modules/@ruvector/rvf-wasm/package.json
After patch, ruflo memory init --force and ruflo hooks pretrain complete successfully (727 files analyzed, 69 patterns extracted in my repro on [email protected]).
Environment
- ruflo: 3.6.12
- @ruvector/rvf-wasm: 0.1.6
- agentdb: 3.0.0-alpha.11
- Node: v20.18.0
- npm: 10.8.2
- OS: Linux 6.12.74 (Debian 13)
Impact
This blocks:
ruflo memory init (any backend that probes RVF)
ruflo hooks pretrain (fails at EMBED/HYPERBOLIC stage)
ruflo status (fails before output)
- Any consumer of
[email protected] doing detectBackends()
- Any consumer of
@ruvector/rvf that probes the WASM backend
Since the published tarball is unusable in any Node version, a prompt patch release (0.1.7) would be valuable.
Summary
@ruvector/[email protected](published to npm) is unloadable in any Node.js consumer. Every entry point — CJSrequire(), ESMawait import(), and theimportcondition pointing topkg/rvf_wasm.mjs— transitively loadspkg/rvf_wasm.js, which contains bothimport.meta.urland a top-levelexport defaultwhile the package has no"type": "module"set. Node parses it as CJS and throws aSyntaxErrorbefore any runtime guard can execute.This breaks every downstream
agentdb/@claude-flow/memory/ruflooperation that touches the RVF backend (memory init,hooks pretrain,status, etc.). Encountered via[email protected]→@claude-flow/memory→[email protected]→@ruvector/[email protected].Reproduction
Result:
ruflo status,ruflo hooks pretrain, and any other call path throughagentdb'sdetectBackends()fails identically.Root cause analysis
Three independent issues compound in the published artifact:
1.
pkg/rvf_wasm.jsmixes ESM-only syntax into a CJS-classified filepackage.jsonhas no"type"field, so Node treats.jsfiles as CJS by default. Butpkg/rvf_wasm.jscontains:import.meta.url(inside a_isNodeelse branch)import.meta.url(inside the browser branch)export default init;These are all ESM-only. The author guards line 47 behind
typeof __dirname !== 'undefined'— but that's runtime, not parse time. The file fails to parse before any guard runs. Same for line 53 (only relevant in browsers, but parser doesn't know that). Line 72 is unconditional ESM syntax in a CJS file.2.
pkg/rvf_wasm.mjsre-imports the broken.jsSo the
importcondition (which routes ESM consumers to.mjs) doesn't actually escape the bug — it just reaches the same broken file via a re-export, and Node still loads.jsthrough the CJS translator because the package isn't marked as a module.3. Two distinct kinds of consumers all hit the same crash
In
ruflo's installed tree:await import('@ruvector/rvf-wasm')from ESM (agentdb): picks theimportcondition →.mjs→ re-imports.js→ CJS parse → crash.__importStar(require('@ruvector/rvf-wasm'))from CJS (@ruvector/rvf/dist/backend.js): picks therequirecondition →.jsdirectly → CJS parse → crash.There is no working code path.
Suggested fix (recommended)
Add
"type": "module"topackage.jsonand routerequirethrough a thin CJS shim, or drop CJS support entirely.Option A — ESM-only (simplest, matches the file's actual syntax):
Tradeoff: CJS callers (currently only
@ruvector/rvf/dist/backend.jsin your stack) would getERR_REQUIRE_ESM. They already crash today, so this is strictly better — and@ruvector/rvfshould switch to dynamicimport()anyway.Option B — true dual package: keep
.jsas a real CJS file (replaceimport.meta.urlwith__dirname-only logic, replaceexport defaultwithmodule.exports, replaceawait import('node:fs/promises')withrequire('node:fs/promises')), and have.mjsre-export from a separate ESM source that usesimport.meta.url. More work but doesn't breakrequire()consumers.Option C — minimal patch keeping everything else the same: add
"type": "module"and let the existing.jsparse as ESM. Theif (typeof module !== 'undefined') module.exports = init;line on row 71 silently no-ops in ESM, theimport.meta.urlandexport defaultthen parse correctly. CJSrequire()still breaks.Pre-publish CI suggestion: add
node -e "import('@ruvector/rvf-wasm').then(m => m.default())"andnode -e "require('@ruvector/rvf-wasm')()"smoke tests on the packed tarball before publishing.Workaround for end users (verified)
Single-line patch on the installed copy:
After patch,
ruflo memory init --forceandruflo hooks pretraincomplete successfully (727 files analyzed, 69 patterns extracted in my repro on[email protected]).Environment
Impact
This blocks:
ruflo memory init(any backend that probes RVF)ruflo hooks pretrain(fails at EMBED/HYPERBOLIC stage)ruflo status(fails before output)[email protected]doingdetectBackends()@ruvector/rvfthat probes the WASM backendSince the published tarball is unusable in any Node version, a prompt patch release (0.1.7) would be valuable.