import { existsSync, openSync, readSync, closeSync } from "node:fs"; export const PUBLISHED_BUILD_PLATFORM = "linux"; export const PUBLISHED_BUILD_ARCH = "x64"; const HEADER_SIZE = 4096; const MAX_FAT_ARCH_COUNT = 30; function mapElfMachine(machine) { switch (machine) { case 62: return "x64"; case 183: return "arm64"; default: return null; } } function mapMachCpuType(cpuType) { switch (cpuType) { case 0x01000007: return "x64"; case 0x0100000c: return "arm64"; default: return null; } } function mapPeMachine(machine) { switch (machine) { case 0x8664: return "x64"; case 0xaa64: return "arm64"; default: return null; } } function readUInt16(buffer, offset, littleEndian) { return littleEndian ? buffer.readUInt16LE(offset) : buffer.readUInt16BE(offset); } function readUInt32(buffer, offset, littleEndian) { return littleEndian ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); } const ELF_MAGIC = 0x7f454c46; function detectElfTarget(buffer) { if (buffer.length < 20) return null; if (buffer.readUInt32BE(0) !== ELF_MAGIC) return null; const littleEndian = buffer[5] !== 2; const arch = mapElfMachine(readUInt16(buffer, 18, littleEndian)); if (!arch) return null; return { platform: "linux", architectures: [arch] }; } const THIN_MACH_MAGIC = new Map([ [0xfeedface, false], [0xfeedfacf, false], [0xcefaedfe, true], [0xcffaedfe, true], ]); const FAT_MACH_MAGIC = new Map([ [0xcafebabe, false], [0xcafebabf, false], [0xbebafeca, true], [0xbfbafeca, true], ]); function detectMachTarget(buffer) { if (buffer.length < 8) return null; const magic = buffer.readUInt32BE(0); if (THIN_MACH_MAGIC.has(magic)) { const littleEndian = THIN_MACH_MAGIC.get(magic); const arch = mapMachCpuType(readUInt32(buffer, 4, littleEndian)); if (!arch) return null; return { platform: "darwin", architectures: [arch] }; } if (!FAT_MACH_MAGIC.has(magic)) return null; const littleEndian = FAT_MACH_MAGIC.get(magic); const isFat64 = magic === 0xcafebabf || magic === 0xbfbafeca; const archCount = readUInt32(buffer, 4, littleEndian); if (archCount > MAX_FAT_ARCH_COUNT) return null; const entrySize = isFat64 ? 32 : 20; const architectures = new Set(); for (let index = 0; index < archCount; index += 1) { const offset = 8 + index * entrySize; if (offset + 4 > buffer.length) break; const arch = mapMachCpuType(readUInt32(buffer, offset, littleEndian)); if (arch) architectures.add(arch); } if (architectures.size === 0) return null; return { platform: "darwin", architectures: [...architectures] }; } function detectPeTarget(buffer) { if (buffer.length < 0x40) return null; if (buffer.readUInt16LE(0) !== 0x5a4d) return null; const peHeaderOffset = buffer.readUInt32LE(0x3c); if (peHeaderOffset + 6 > buffer.length) return null; if (buffer.readUInt32LE(peHeaderOffset) !== 0x00004550) return null; const arch = mapPeMachine(buffer.readUInt16LE(peHeaderOffset + 4)); if (!arch) return null; return { platform: "win32", architectures: [arch] }; } export function detectNativeBinaryTarget(buffer) { return detectElfTarget(buffer) ?? detectMachTarget(buffer) ?? detectPeTarget(buffer); } export function readNativeBinaryTarget(binaryPath) { if (!existsSync(binaryPath)) return null; let fd; try { fd = openSync(binaryPath, "r"); const buffer = Buffer.alloc(HEADER_SIZE); const bytesRead = readSync(fd, buffer, 0, HEADER_SIZE, 0); return detectNativeBinaryTarget(buffer.subarray(0, bytesRead)); } catch (err) { console.warn(` ⚠️ Could not read native binary at ${binaryPath}: ${err.message}`); return null; } finally { if (fd !== undefined) closeSync(fd); } } export function isNativeBinaryCompatible( binaryPath, { runtimePlatform = process.platform, runtimeArch = process.arch, dlopen = process.dlopen } = {} ) { const target = readNativeBinaryTarget(binaryPath); if (target) { if ( (target.platform !== runtimePlatform && !(target.platform === "linux" && runtimePlatform === "android")) || !target.architectures.includes(runtimeArch) ) { return false; } } else if (runtimePlatform !== PUBLISHED_BUILD_PLATFORM || runtimeArch !== PUBLISHED_BUILD_ARCH) { return false; } try { dlopen({ exports: {} }, binaryPath); return true; } catch (err) { console.warn(` ⚠️ Native binary dlopen failed: ${err.message}`); return false; } }