import { spawn } from "node:child_process";
import { existsSync } from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const require = createRequire(import.meta.url);
const PLATFORM_PACKAGE_BY_TARGET = {
"x86_64-unknown-linux-gnu": "asfml-linux-x64",
"aarch64-unknown-linux-gnu": "asfml-linux-arm64",
"x86_64-apple-darwin": "asfml-darwin-x64",
"aarch64-apple-darwin": "asfml-darwin-arm64",
"x86_64-pc-windows-msvc": "asfml-win32-x64",
"aarch64-pc-windows-msvc": "asfml-win32-arm64",
};
function detectTargetTriple(platformName, archName) {
switch (platformName) {
case "linux":
if (archName === "x64") {
return "x86_64-unknown-linux-gnu";
}
if (archName === "arm64") {
return "aarch64-unknown-linux-gnu";
}
break;
case "darwin":
if (archName === "x64") {
return "x86_64-apple-darwin";
}
if (archName === "arm64") {
return "aarch64-apple-darwin";
}
break;
case "win32":
if (archName === "x64") {
return "x86_64-pc-windows-msvc";
}
if (archName === "arm64") {
return "aarch64-pc-windows-msvc";
}
break;
default:
break;
}
return null;
}
function detectPackageManager() {
const userAgent = process.env.npm_config_user_agent || "";
if (/\bbun\//.test(userAgent)) {
return "bun";
}
return userAgent ? "npm" : null;
}
const targetTriple = detectTargetTriple(process.platform, process.arch);
if (!targetTriple) {
throw new Error(`Unsupported platform: ${process.platform} (${process.arch})`);
}
const platformPackage = PLATFORM_PACKAGE_BY_TARGET[targetTriple];
if (!platformPackage) {
throw new Error(`Unsupported target triple: ${targetTriple}`);
}
const binaryName = process.platform === "win32" ? "asfml.exe" : "asfml";
const localVendorRoot = path.join(__dirname, "..", "vendor");
const localBinaryPath = path.join(localVendorRoot, targetTriple, "asfml", binaryName);
let vendorRoot;
try {
const packageJsonPath = require.resolve(`${platformPackage}/package.json`);
vendorRoot = path.join(path.dirname(packageJsonPath), "vendor");
} catch {
if (existsSync(localBinaryPath)) {
vendorRoot = localVendorRoot;
} else {
const manager = detectPackageManager();
const updateCommand =
manager === "bun" ? "bun install -g asfml@latest" : "npm install -g asfml@latest";
throw new Error(`Missing optional dependency ${platformPackage}. Reinstall asfml: ${updateCommand}`);
}
}
const binaryPath = path.join(vendorRoot, targetTriple, "asfml", binaryName);
const env = { ...process.env };
env[detectPackageManager() === "bun" ? "ASFML_MANAGED_BY_BUN" : "ASFML_MANAGED_BY_NPM"] = "1";
const child = spawn(binaryPath, process.argv.slice(2), {
stdio: "inherit",
env,
});
child.on("error", (err) => {
console.error(err);
process.exit(1);
});
const forwardSignal = (signal) => {
if (child.killed) {
return;
}
try {
child.kill(signal);
} catch {
}
};
for (const signal of ["SIGINT", "SIGTERM"]) {
process.on(signal, () => forwardSignal(signal));
}
child.on("exit", (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 1);
});