import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const electrobunDir = path.join(rootDir, "node_modules/electrobun"); const sharedSrcDir = path.join(electrobunDir, "src/shared"); const sharedDistDir = path.join(electrobunDir, "dist/api/shared"); if (!existsSync(sharedDistDir)) { console.error("patch-electrobun-src: electrobun dist/api/shared not found"); process.exit(1); } mkdirSync(sharedSrcDir, { recursive: true }); for (const fileName of [ "cef-version.ts", "bun-version.ts", "electrobun-version.ts", "naming.ts", "rpc.ts", ]) { const source = path.join(sharedDistDir, fileName); const destination = path.join(sharedSrcDir, fileName); if (existsSync(source)) { cpSync(source, destination); } } const platformPatch = `import { platform, arch } from "os"; export type SupportedOS = "macos" | "win" | "linux"; export type SupportedArch = "arm64" | "x64"; const platformName = platform(); const archName = arch(); export const OS: SupportedOS = (() => { switch (platformName) { case "win32": return "win"; case "darwin": return "macos"; case "linux": return "linux"; default: throw new Error(\`Unsupported platform: \${platformName}\`); } })(); function normalizeForcedArch(value) { if (value === "arm64" || value === "aarch64") { return "arm64"; } if (value === "x64" || value === "amd64") { return "x64"; } return null; } export const ARCH: SupportedArch = (() => { const forcedArch = normalizeForcedArch( process.env.ELECTROBUN_FORCE_ARCH || process.env.ELECTROBUN_TARGET_ARCH, ); if (forcedArch) { return forcedArch; } if (OS === "win") { return "x64"; } switch (archName) { case "arm64": return "arm64"; case "x64": return "x64"; default: throw new Error(\`Unsupported architecture: \${archName}\`); } })(); export const HOST_ARCH: SupportedArch = (() => { if (OS === "win") { return "x64"; } switch (archName) { case "arm64": return "arm64"; case "x64": return "x64"; default: throw new Error(\`Unsupported architecture: \${archName}\`); } })(); export function getPlatformOS(): SupportedOS { return OS; } export function getPlatformArch(): SupportedArch { return ARCH; } `; writeFileSync(path.join(sharedSrcDir, "platform.ts"), platformPatch); const templatesDir = path.join(electrobunDir, "src/cli/templates"); mkdirSync(templatesDir, { recursive: true }); writeFileSync( path.join(templatesDir, "embedded.ts"), `export function getTemplateNames() { return []; } export function getTemplate(name: string) { throw new Error(\`Template not available in patched electrobun CLI: \${name}\`); } `, ); const cliPath = path.join(electrobunDir, "src/cli/index.ts"); let cliSource = readFileSync(cliPath, "utf8"); if (!cliSource.includes("HOST_ARCH")) { cliSource = cliSource.replace( 'import { OS, ARCH } from "../shared/platform";', 'import { OS, ARCH, HOST_ARCH } from "../shared/platform";', ); cliSource = cliSource.replace( "const hostPaths = getPlatformPaths(OS, ARCH);", "const hostPaths = getPlatformPaths(OS, HOST_ARCH);", ); } if (!cliSource.includes("toolPaths")) { cliSource = cliSource.replace( "const targetPaths = getPlatformPaths(currentTarget.os, currentTarget.arch);", "const targetPaths = getPlatformPaths(currentTarget.os, currentTarget.arch);\n\t\tconst toolPaths = getPlatformPaths(currentTarget.os, ARCH !== HOST_ARCH ? HOST_ARCH : ARCH);", ); cliSource = cliSource.replaceAll("const zstdPath = targetPaths.ZSTD;", "const zstdPath = toolPaths.ZSTD;"); cliSource = cliSource.replaceAll("const bsdiffpath = targetPaths.BSDIFF;", "const bsdiffpath = toolPaths.BSDIFF;"); cliSource = cliSource.replace( "zigAsarCli = join(targetPaths.BSPATCH).replace(\"bspatch\", \"zig-asar\");", "zigAsarCli = join(toolPaths.BSPATCH).replace(\"bspatch\", \"zig-asar\");", ); writeFileSync(cliPath, cliSource); cliSource = readFileSync(cliPath, "utf8"); } if (!cliSource.includes("hookBunBinary")) { cliSource = cliSource.replace( `const hostPaths = getPlatformPaths(OS, HOST_ARCH); const result = Bun.spawnSync([hostPaths.BUN_BINARY, hookScript],`, `const hostPaths = getPlatformPaths(OS, HOST_ARCH); const hookBunBinary = existsSync(hostPaths.BUN_BINARY) ? hostPaths.BUN_BINARY : process.execPath; const result = Bun.spawnSync([hookBunBinary, hookScript],`, ); cliSource = cliSource.replace( "console.error(\"Tried to run with bun at:\", hostPaths.BUN_BINARY);", "console.error(\"Tried to run with bun at:\", hookBunBinary);", ); writeFileSync(cliPath, cliSource); } const markerPath = path.join(electrobunDir, ".farmcontrol-electrobun-patched"); writeFileSync(markerPath, `patched-at=${new Date().toISOString()}\n`); console.log("patch-electrobun-src: electrobun src/shared ready for cross-arch builds");