ix(native-host): use host-specific tt-native resolution so Linux binary loads addon
CI / Build & Test (push) Successful in 3m49s

When building with --all, the bundle used a single addon resolution (darwin-arm64),
so the Linux binary tried to load the wrong prebuild and tt-native failed. Patch
tt-native binding with a nested resolution map (addon → bare → node → platform →
arch) so the runtime selects the correct prebuild per platform; SSH PTY then works
on Linux.
This commit is contained in:
Raven Scott
2026-03-04 01:31:47 -05:00
parent f9976559bf
commit 4165179ae3
+16 -16
View File
@@ -135,9 +135,9 @@ module.exports = async function sign() {}
* 1. tt-native addon detection:
* bare-pack cannot detect `require('load-addon')(__dirname)` as an addon
* import. We replace tt-native/binding.js with `module.exports = require.addon()`
* and set its resolutions map to the prebuild path — the same structure that
* bare-pack generates for addons using the standard `require.addon()` pattern.
* bare-unpack will then extract the prebuild to a temp dir and remap the URL.
* and set its resolutions map to a host-specific nested map (addon → bare →
* node → platform → arch) so the runtime selects the correct prebuild per
* platform. bare-unpack then extracts the right prebuild for the current host.
*
* 2. node-rdpjs-2 EventEmitter compatibility:
* node-rdpjs-2 uses `util.inherits(Class, EventEmitter)` which calls
@@ -151,8 +151,10 @@ function patchBundle(bundle, hosts) {
const ttNativePkgKey = '/node_modules/tt-native/package.json'
if (bundle.read(ttNativeBindingKey) !== null) {
// Find the prebuild for each target host
const addedPrebuilds = []
// Build host-specific resolution map so the runtime picks the correct prebuild
// per platform (addon → bare → node → platform → arch). Same format as
// bare-pack/bare-module-traverse so require.addon() resolves on Linux, etc.
const addonResolutions = { addon: { bare: { node: {} } } }
for (const host of hosts) {
const prebuiltKey = `/node_modules/tt-native/prebuilds/${host}/tt-native.bare`
@@ -160,27 +162,25 @@ function patchBundle(bundle, hosts) {
if (!fs.existsSync(diskPath)) continue
// Write the prebuild binary into the bundle
bundle.write(prebuiltKey, fs.readFileSync(diskPath), { addon: true })
addedPrebuilds.push(prebuiltKey)
const [platform, arch] = host.split('-')
if (!addonResolutions.addon.bare.node[platform]) addonResolutions.addon.bare.node[platform] = {}
addonResolutions.addon.bare.node[platform][arch] = prebuiltKey
}
if (addedPrebuilds.length > 0) {
// Replace binding.js with the standard require.addon() pattern.
// The resolutions map tells bare-unpack which prebuild to extract.
// We use the first matching host's prebuild as the "." resolution.
const primaryPrebuild = addedPrebuilds[0]
if (Object.keys(addonResolutions.addon.bare.node).length > 0) {
bundle.write(
ttNativeBindingKey,
Buffer.from('module.exports = require.addon()\n'),
{
imports: {
'#package': ttNativePkgKey,
'.': primaryPrebuild
'.': addonResolutions
}
}
)
console.log(` Patched tt-native binding ${primaryPrebuild}`)
console.log(' Patched tt-native binding (host-specific resolutions)')
}
}
@@ -300,8 +300,8 @@ async function build(hosts, doPackage) {
// statically detect this pattern, so the addon prebuild is never added to
// bundle.addons and bare-unpack never extracts it to disk.
// Fix: replace tt-native/binding.js with `module.exports = require.addon()`
// (same pattern as bare-tcp/binding.js) and set its resolutions map to point
// to the prebuild — exactly what bare-pack would do for a normal addon.
// and set its resolutions map to a host-specific nested map (addon → bare →
// node → platform → arch) so the runtime selects the correct prebuild per platform.
//
// 2. node-rdpjs-2 uses `util.inherits(Class, EventEmitter)` which calls
// EventEmitter.call(this) — this fails on bare-events' ES6 class.