@@ -217,20 +217,43 @@ if (!existsSync(analysisNode)) {
217217 process . exit ( 1 ) ;
218218}
219219
220- copyFileSync ( hyperlightNode , join ( LIB_DIR , `js-host-api.${ napiTriple } .node` ) ) ;
221- copyFileSync (
222- analysisNode ,
223- join ( LIB_DIR , `hyperlight-analysis.${ napiTriple } .node` ) ,
224- ) ;
220+ // Copy .node files for ALL available platforms so the package is cross-platform.
221+ // The current platform's .node is guaranteed to exist (checked above).
222+ // Additional platform .node files are copied if present (e.g. from CI matrix builds).
223+ const ALL_TRIPLES = [ "linux-x64-gnu" , "linux-x64-musl" , "win32-x64-msvc" ] ;
224+ for ( const triple of ALL_TRIPLES ) {
225+ const hlNode = join ( ROOT , `deps/js-host-api/js-host-api.${ triple } .node` ) ;
226+ const anNode = join (
227+ ROOT ,
228+ `src/code-validator/guest/host/hyperlight-analysis.${ triple } .node` ,
229+ ) ;
230+ if ( existsSync ( hlNode ) ) {
231+ copyFileSync ( hlNode , join ( LIB_DIR , `js-host-api.${ triple } .node` ) ) ;
232+ console . log ( ` ✓ js-host-api.${ triple } .node` ) ;
233+ }
234+ if ( existsSync ( anNode ) ) {
235+ copyFileSync ( anNode , join ( LIB_DIR , `hyperlight-analysis.${ triple } .node` ) ) ;
236+ console . log ( ` ✓ hyperlight-analysis.${ triple } .node` ) ;
237+ }
238+ }
225239
226240// Create a proper node_modules package structure for hyperlight-analysis
227241// so both require() and import() can resolve it in the bundled binary.
228242const analysisPkgDir = join ( LIB_DIR , "node_modules" , "hyperlight-analysis" ) ;
229243mkdirSync ( analysisPkgDir , { recursive : true } ) ;
230- copyFileSync (
231- analysisNode ,
232- join ( analysisPkgDir , `hyperlight-analysis.${ napiTriple } .node` ) ,
233- ) ;
244+ // Copy all available platform .node files into the package dir
245+ for ( const triple of ALL_TRIPLES ) {
246+ const anNode = join (
247+ ROOT ,
248+ `src/code-validator/guest/host/hyperlight-analysis.${ triple } .node` ,
249+ ) ;
250+ if ( existsSync ( anNode ) ) {
251+ copyFileSync (
252+ anNode ,
253+ join ( analysisPkgDir , `hyperlight-analysis.${ triple } .node` ) ,
254+ ) ;
255+ }
256+ }
234257// Copy the index.js and index.d.ts from the source package
235258const analysisIndex = join ( ROOT , "src/code-validator/guest/index.js" ) ;
236259const analysisTypes = join ( ROOT , "src/code-validator/guest/index.d.ts" ) ;
@@ -250,24 +273,30 @@ if (existsSync(analysisPkg))
250273// Files are renamed to .cjs because the host package.json has "type": "module"
251274// which makes Node.js treat .js as ESM — but lib.js uses require().
252275const hyperlightLibJs = join ( ROOT , "deps/js-host-api/lib.js" ) ;
276+ const hyperlightIndexJs = join ( ROOT , "deps/js-host-api/index.js" ) ;
253277const hyperlightHostApiDir = join ( LIB_DIR , "js-host-api" ) ;
254278mkdirSync ( hyperlightHostApiDir , { recursive : true } ) ;
255- copyFileSync (
256- hyperlightNode ,
257- join ( hyperlightHostApiDir , `js-host-api.${ napiTriple } .node` ) ,
258- ) ;
279+ // Copy all available platform .node files
280+ for ( const triple of ALL_TRIPLES ) {
281+ const hlNode = join ( ROOT , `deps/js-host-api/js-host-api.${ triple } .node` ) ;
282+ if ( existsSync ( hlNode ) ) {
283+ copyFileSync (
284+ hlNode ,
285+ join ( hyperlightHostApiDir , `js-host-api.${ triple } .node` ) ,
286+ ) ;
287+ }
288+ }
259289// Copy lib.js as lib.cjs, patching the require('./index.js') to './index.cjs'
260290const libJsContent = readFileSync ( hyperlightLibJs , "utf-8" ) . replace (
261291 "require('./index.js')" ,
262292 "require('./index.cjs')" ,
263293) ;
264294writeFileSync ( join ( hyperlightHostApiDir , "lib.cjs" ) , libJsContent ) ;
265- // Create a minimal index.cjs shim that loads the .node addon from the
266- // same directory. Platform-specific .node file is resolved at build time.
267- writeFileSync (
268- join ( hyperlightHostApiDir , "index.cjs" ) ,
269- `'use strict';\nmodule.exports = require('./js-host-api.${ napiTriple } .node');\n` ,
270- ) ;
295+ // Copy the napi-rs generated index.js as index.cjs — it already has full
296+ // platform detection (musl vs glibc, win32, darwin) and tries local .node
297+ // files first, then falls back to optional @hyperlight/ scoped packages.
298+ const indexJsContent = readFileSync ( hyperlightIndexJs , "utf-8" ) ;
299+ writeFileSync ( join ( hyperlightHostApiDir , "index.cjs" ) , indexJsContent ) ;
271300
272301// ── Step 5: Copy runtime resources ─────────────────────────────────────
273302console . log ( "📁 Copying runtime resources..." ) ;
@@ -403,7 +432,9 @@ Module._load = function(request, parent, isMain) {
403432 return originalLoad.call(this, join(LIB_DIR, 'js-host-api', 'lib.cjs'), parent, isMain);
404433 }
405434 if (request === 'hyperlight-analysis') {
406- return originalLoad.call(this, join(LIB_DIR, 'hyperlight-analysis.${ napiTriple } .node'), parent, isMain);
435+ // The hyperlight-analysis index.js already has full napi-rs platform detection.
436+ // It's copied into the node_modules structure, so just load it from there.
437+ return originalLoad.call(this, join(LIB_DIR, 'node_modules', 'hyperlight-analysis', 'index.js'), parent, isMain);
407438 }
408439 return originalLoad.apply(this, arguments);
409440};
0 commit comments