import { cp, mkdir, rm, writeFile, chmod } from "node:fs/promises";import { existsSync } from "node:fs";import { createRequire } from "node:module";import { resolve, join, dirname } from "node:path";import { fileURLToPath } from "node:url";import { parseArgs } from "node:util";import { $ } from "bun"; const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../..");const cliRoot = resolve(repoRoot, "apps/cli");const webRoot = resolve(repoRoot, "apps/local");const distDir = resolve(cliRoot, "dist"); const resolveQuickJsWasmPath = (): string => { const req = createRequire(join(repoRoot, "packages/kernel/runtime-quickjs/package.json")); const quickJsPkg = req.resolve("quickjs-emscripten/package.json"); const wasmPath = resolve( dirname(quickJsPkg), "../@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.wasm", ); if (!existsSync(wasmPath)) throw new Error(`QuickJS WASM not found at ${wasmPath}`); return wasmPath;}; // ---------------------------------------------------------------------------// Metadata// --------------------------------------------------------------------------- const readMetadata = async () => { const rootPkg = await Bun.file(join(repoRoot, "package.json")).json(); const cliPkg = await Bun.file(join(cliRoot, "package.json")).json(); return { name: "executor", version: process.env.EXECUTOR_VERSION ?? cliPkg.version ?? rootPkg.version ?? "0.0.0", description: rootPkg.description ?? "Local AI executor with a CLI, local API server, and web UI.", keywords: rootPkg.keywords ?? [], homepage: rootPkg.homepage, bugs: rootPkg.bugs, repository: rootPkg.repository, license: rootPkg.license ?? "MIT", };}; // ---------------------------------------------------------------------------// Targets// --------------------------------------------------------------------------- type Target = { os: "linux" | "darwin" | "win32"; arch: "x64" | "arm64"; abi?: "musl";}; const ALL_TARGETS: Target[] = [ { os: "linux", arch: "x64" }, { os: "linux", arch: "arm64" }, { os: "linux", arch: "x64", abi: "musl" }, { os: "linux", arch: "arm64", abi: "musl" }, { os: "darwin", arch: "x64" }, { os: "darwin", arch: "arm64" }, { os: "win32", arch: "x64" }, { os: "win32", arch: "arm64" },]; const platformName = (t: Target) => (t.os === "win32" ? "windows" : t.os); const targetPackageName = (t: Target) => ["executor", platformName(t), t.arch, t.abi].filter(Boolean).join("-"); const bunTarget = (t: Target) => ["bun", platformName(t), t.arch, t.abi].filter(Boolean).join("-"); const binaryName = (t: Target) => (t.os === "win32" ? "executor.exe" : "executor"); const isCurrentPlatform = (t: Target) => t.os === process.platform && t.arch === process.arch && !t.abi; /** Resolve the platform-specific secure-exec-v8 binary for a given target. */const resolveSecureExecV8 = (t: Target): string | null => { const platformMap: Record<string, string> = { "darwin-arm64": "@secure-exec/v8-darwin-arm64", "darwin-x64": "@secure-exec/v8-darwin-x64", "linux-arm64": "@secure-exec/v8-linux-arm64-gnu", "linux-x64": "@secure-exec/v8-linux-x64-gnu", }; const key = `${t.os}-${t.arch}`; const pkg = platformMap[key]; if (!pkg) return null; try { // Resolve from @secure-exec/v8 which has these as optional deps const req = createRequire(join(repoRoot, "node_modules", "secure-exec", "package.json")); const pkgJson = req.resolve(`${pkg}/package.json`); return join(dirname(pkgJson), "secure-exec-v8"); } catch { // Try bun's flat node_modules layout const bunPath = join( repoRoot, `node_modules/.bun/${pkg.replace("/", "+")}@0.2.1/node_modules/${pkg}/secure-exec-v8`, ); if (existsSync(bunPath)) return bunPath; return null; }}; // ---------------------------------------------------------------------------// Build mode// --------------------------------------------------------------------------- type BuildMode = "production" | "development"; // ---------------------------------------------------------------------------// Build web app// --------------------------------------------------------------------------- const buildWeb = async (mode: BuildMode) => { const webDist = join(webRoot, "dist"); await rm(webDist, { recursive: true, force: true }); console.log(`Building web app (${mode})...`); const proc = Bun.spawn(["bun", "run", "build", "--mode", mode], { cwd: webRoot, stdio: ["ignore", "inherit", "inherit"], env: { ...process.env, NODE_ENV: mode }, }); if ((await proc.exited) !== 0) throw new Error("Web build failed"); return webDist;}; // ---------------------------------------------------------------------------// Embedded web UI — generates a virtual module that imports all web assets// using `with { type: "file" }` so Bun bakes them into the compiled binary.// --------------------------------------------------------------------------- const createEmbeddedWebUISource = async (mode: BuildMode) => { const webDist = await buildWeb(mode); const files = (await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: webDist }))) .map((f) => f.replaceAll("\\", "/")) .sort(); const imports = files.map((file, i) => { const spec = join(webDist, file).replaceAll("\\", "/"); return `import file_${i} from ${JSON.stringify(spec)} with { type: "file" };`; }); const entries = files.map((file, i) => ` ${JSON.stringify(file)}: file_${i},`); return [ "// Auto-generated — maps web UI paths to embedded file references", ...imports, "export default {", ...entries, "} as Record<string, string>;", ].join("\n");}; // ---------------------------------------------------------------------------// Embedded drizzle migrations — inlined as text imports so drizzle's// `migrate()` (which reads a folder from disk) can be given a tmpdir// populated from the inlined contents at runtime.// --------------------------------------------------------------------------- const createEmbeddedMigrationsSource = async () => { const migrationsDir = resolve(webRoot, "drizzle"); const files = (await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: migrationsDir }))) .map((f) => f.replaceAll("\\", "/")) .sort(); const imports = files.map((file, i) => { const spec = join(migrationsDir, file).replaceAll("\\", "/"); return `import file_${i} from ${JSON.stringify(spec)} with { type: "text" };`; }); const entries = files.map((file, i) => ` ${JSON.stringify(file)}: file_${i},`); return [ "// Auto-generated — maps migration paths to inlined file contents", ...imports, "export default {", ...entries, "} as Record<string, string>;", ].join("\n");}; // ---------------------------------------------------------------------------// Bun.build plugin for @secure-exec bundling issues// --------------------------------------------------------------------------- /** * Plugin that fixes two issues with @secure-exec in compiled binaries: * * 1. node-stdlib-browser / web-streams-polyfill eagerly call require.resolve() * at import time, which fails in bunfs. We stub these out since our code * never uses the polyfill functions. * * 2. bridge-loader.js reads bridge.js from disk via fs.readFileSync using * __dirname. In a compiled binary __dirname points into bunfs where the * file doesn't exist. We replace bridge-loader with a version that embeds * bridge.js content directly. */const secureExecBundlePlugin = async (): Promise<import("bun").BunPlugin> => { // Read files at build time so we can inline them into the compiled binary. // bridge.js is loaded via fs.readFileSync at runtime, which fails in bunfs. // bridgeAttach comes from @secure-exec/core's generated isolate-runtime. const secureExecNodejs = join( repoRoot, "node_modules/.bun/@secure-exec+nodejs@0.2.1/node_modules/@secure-exec/nodejs", ); const secureExecCore = join( repoRoot, "node_modules/.bun/@secure-exec+core@0.2.1/node_modules/@secure-exec/core", ); const bridgeCode = await Bun.file(join(secureExecNodejs, "dist/bridge.js")).text(); const isolateRuntime = await import(join(secureExecCore, "dist/generated/isolate-runtime.js")); const bridgeAttachCode = isolateRuntime.ISOLATE_RUNTIME_SOURCES.bridgeAttach; const polyfillCodeMap = (await import(join(secureExecCore, "dist/generated/polyfills.js"))) .POLYFILL_CODE_MAP as Record<string, string>; return { name: "secure-exec-bundle-fixes", setup(build) { // Stub polyfill modules that fail at import time in compiled binaries const stubTargets = /node-stdlib-browser|web-streams-polyfill/; build.onResolve({ filter: stubTargets }, (args) => ({ path: args.path, namespace: "stub", })); // Replace @secure-exec/nodejs polyfills (which use node-stdlib-browser + esbuild // at runtime) with a shim that serves from pre-bundled POLYFILL_CODE_MAP. build.onResolve({ filter: /polyfills/ }, (args) => { if ( args.importer.includes("@secure-exec/nodejs") || args.importer.includes("@secure-exec+nodejs") ) { return { path: args.path, namespace: "polyfills-shim" }; } }); build.onLoad({ filter: /.*/, namespace: "polyfills-shim" }, () => ({ contents: `const POLYFILL_CODE_MAP = ${JSON.stringify(polyfillCodeMap)};const polyfillCache = new Map();export default {};export async function bundlePolyfill(moduleName) { const cached = polyfillCache.get(moduleName); if (cached) return cached; const code = POLYFILL_CODE_MAP[moduleName]; if (!code) throw new Error("No polyfill available for module: " + moduleName); polyfillCache.set(moduleName, code); return code;}export function getAvailableStdlib() { return Object.keys(POLYFILL_CODE_MAP); }export function hasPolyfill(name) { return name.replace(/^node:/, "") in POLYFILL_CODE_MAP; }export async function prebundleAllPolyfills() { return { ...POLYFILL_CODE_MAP }; } `, loader: "js", })); build.onLoad({ filter: /.*/, namespace: "stub" }, () => ({ contents: "export default {};", loader: "js", })); // Replace bridge-loader with pre-read content build.onResolve({ filter: /bridge-loader/ }, (args) => { if (args.importer.includes("secure-exec")) { return { path: args.path, namespace: "bridge" }; } }); build.onLoad({ filter: /.*/, namespace: "bridge" }, () => ({ contents: `const bridgeCode = ${JSON.stringify(bridgeCode)};const bridgeAttachCode = ${JSON.stringify(bridgeAttachCode)};export function getRawBridgeCode() { return bridgeCode; }export function getBridgeAttachCode() { return bridgeAttachCode; } `, loader: "js", })); }, };}; // ---------------------------------------------------------------------------// Build platform binaries// --------------------------------------------------------------------------- const EMBEDDED_WEB_UI_STUB = `const files: Record<string, string> | null = null;\n\nexport default files;\n`;const EMBEDDED_MIGRATIONS_STUB = `const migrations: Record<string, string> | null = null;\n\nexport default migrations;\n`; const buildBinaries = async (targets: Target[], mode: BuildMode) => { const meta = await readMetadata(); const binaries: Record<string, string> = {}; const embeddedWebUIPath = join(cliRoot, "src/embedded-web-ui.gen.ts"); const embeddedMigrationsPath = join(webRoot, "src/server/embedded-migrations.gen.ts"); await rm(distDir, { recursive: true, force: true }); console.log(`Generating embedded web UI bundle (${mode})...`); const embeddedWebUI = await createEmbeddedWebUISource(mode); await writeFile(embeddedWebUIPath, `${embeddedWebUI}\n`); console.log("Generating embedded drizzle migrations..."); const embeddedMigrations = await createEmbeddedMigrationsSource(); await writeFile(embeddedMigrationsPath, `${embeddedMigrations}\n`); const quickJsWasmPath = resolveQuickJsWasmPath(); try { for (const target of targets) { const name = targetPackageName(target); const outDir = join(distDir, name); const binDir = join(outDir, "bin"); await mkdir(binDir, { recursive: true }); console.log(`Building ${name}...`); await Bun.build({ entrypoints: [join(cliRoot, "src/main.ts")], minify: mode === "production", compile: { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Bun compile target string is dynamically constructed target: bunTarget(target) as any, outfile: join(binDir, binaryName(target)), }, plugins: [await secureExecBundlePlugin()], }); // Copy QuickJS WASM next to binary — loaded at runtime by the server await cp(quickJsWasmPath, join(binDir, "emscripten-module.wasm")); // Copy secure-exec-v8 binary next to executor — needed for code execution const secureExecBin = resolveSecureExecV8(target); if (secureExecBin && existsSync(secureExecBin)) { const destName = target.os === "win32" ? "secure-exec-v8.exe" : "secure-exec-v8"; await cp(secureExecBin, join(binDir, destName)); await chmod(join(binDir, destName), 0o755); } // Smoke test on current platform if (isCurrentPlatform(target)) { const bin = join(binDir, binaryName(target)); console.log(` Smoke test: ${bin} --version`); const version = await $`${bin} --version`.text(); console.log(` OK: ${version.trim()}`); } // Platform package.json await writeFile( join(outDir, "package.json"), JSON.stringify( { name, version: meta.version, os: [target.os], cpu: [target.arch], bin: { executor: `bin/${binaryName(target)}` }, }, null, 2, ) + "\n", ); binaries[name] = meta.version; } return binaries; } finally { await writeFile(embeddedWebUIPath, EMBEDDED_WEB_UI_STUB); await writeFile(embeddedMigrationsPath, EMBEDDED_MIGRATIONS_STUB); }}; // ---------------------------------------------------------------------------// Build wrapper npm package// --------------------------------------------------------------------------- const buildWrapperPackage = async (binaries: Record<string, string>) => { const meta = await readMetadata(); const wrapperDir = join(distDir, meta.name); const binDir = join(wrapperDir, "bin"); await mkdir(binDir, { recursive: true }); // Node.js shim that spawns the downloaded platform binary await writeFile(join(binDir, "executor"), NODE_SHIM); await chmod(join(binDir, "executor"), 0o755); // Postinstall downloads the matching release asset from GitHub Releases await writeFile(join(wrapperDir, "postinstall.cjs"), POSTINSTALL_SCRIPT); // Package.json await writeFile( join(wrapperDir, "package.json"), JSON.stringify( { name: meta.name, version: meta.version, description: meta.description, keywords: meta.keywords, homepage: meta.homepage, bugs: meta.bugs, repository: meta.repository, license: meta.license, bin: { executor: "bin/executor" }, scripts: { postinstall: "node ./postinstall.cjs", }, engines: { node: ">=20", }, }, null, 2, ) + "\n", ); // README const readmePath = join(repoRoot, "README.md"); if (existsSync(readmePath)) { await cp(readmePath, join(wrapperDir, "README.md")); } console.log(`\nWrapper package: ${wrapperDir}`); console.log(` ${meta.name}@${meta.version}`); console.log(` release assets: ${Object.keys(binaries).join(", ")}`);}; // ---------------------------------------------------------------------------// Preview wrapper — a slim npm package for pkg.pr.new previews that fetches// the platform binary from our R2 bucket at install time.//// The release wrapper points postinstall at GitHub Releases. For previews// there's no release, so we upload per-PR tarballs to R2 (keyed by commit// SHA) and have a dedicated postinstall download from there.//// CI splits this in two:// 1. A matrix job per platform runs `buildPreviewTarballs` to produce// dist/previews/<platform>.tar.gz, which it uploads to R2.// 2. A single publish job runs `buildPreviewWrapperPackage` with an// explicit list of platforms and hands the wrapper to pkg.pr.new.//// Both paths require EXECUTOR_PREVIEW_CDN_URL and EXECUTOR_PREVIEW_SHA so// the postinstall URL embeds the right commit.// --------------------------------------------------------------------------- const buildPreviewTarballs = async (binaries: Record<string, string>) => { const previewDir = join(distDir, "previews"); await mkdir(previewDir, { recursive: true }); for (const platformPkg of Object.keys(binaries)) { const srcBinDir = join(distDir, platformPkg, "bin"); const tarPath = join(previewDir, `${platformPkg}.tar.gz`); await $`tar -czf ${tarPath} .`.cwd(srcBinDir).quiet(); console.log(`Preview tarball: ${tarPath}`); }}; const resolveTargetsFromEnv = (env: string | undefined): Target[] => { if (!env) throw new Error("EXECUTOR_PREVIEW_TARGETS must be set (comma-separated package names)"); const names = env.split(",").map((s) => s.trim()).filter(Boolean); const resolved = names.map((name) => { const match = ALL_TARGETS.find((t) => targetPackageName(t) === name); if (!match) throw new Error(`Unknown preview target: ${name}`); return match; }); if (resolved.length === 0) throw new Error("EXECUTOR_PREVIEW_TARGETS resolved to an empty list"); return resolved;}; const buildPreviewWrapperPackage = async (targets: Target[]) => { const meta = await readMetadata(); const cdnUrl = process.env.EXECUTOR_PREVIEW_CDN_URL?.replace(/\/+$/, ""); const sha = process.env.EXECUTOR_PREVIEW_SHA; if (!cdnUrl || !sha) { throw new Error( "preview build requires EXECUTOR_PREVIEW_CDN_URL and EXECUTOR_PREVIEW_SHA to be set", ); } const wrapperDir = join(distDir, meta.name); const binDir = join(wrapperDir, "bin"); await mkdir(binDir, { recursive: true }); await writeFile(join(binDir, "executor"), NODE_SHIM); await chmod(join(binDir, "executor"), 0o755); const postinstall = PREVIEW_POSTINSTALL_SCRIPT.replaceAll( "__CDN_BASE_URL__", `${cdnUrl}/${sha}`, ); await writeFile(join(wrapperDir, "postinstall.cjs"), postinstall); // Restrict os/cpu to platforms we actually built this run so npm refuses // the install on anything else — a clear error beats a cryptic 404 from // postinstall on an unbuilt platform. const osList = Array.from(new Set(targets.map((t) => t.os))); const cpuList = Array.from(new Set(targets.map((t) => t.arch))); await writeFile( join(wrapperDir, "package.json"), JSON.stringify( { name: meta.name, version: meta.version,Lines 1–500 of 933. Load more
import { cp, mkdir, rm, writeFile, chmod } from "node:fs/promises"; import { existsSync } from "node:fs"; import { createRequire } from "node:module"; import { resolve, join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { parseArgs } from "node:util"; import { $ } from "bun"; const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../.."); const cliRoot = resolve(repoRoot, "apps/cli"); const webRoot = resolve(repoRoot, "apps/local"); const distDir = resolve(cliRoot, "dist"); const resolveQuickJsWasmPath = (): string => { const req = createRequire(join(repoRoot, "packages/kernel/runtime-quickjs/package.json")); const quickJsPkg = req.resolve("quickjs-emscripten/package.json"); const wasmPath = resolve( dirname(quickJsPkg), "../@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.wasm", ); if (!existsSync(wasmPath)) throw new Error(`QuickJS WASM not found at ${wasmPath}`); return wasmPath; }; // --------------------------------------------------------------------------- // Metadata // --------------------------------------------------------------------------- const readMetadata = async () => { const rootPkg = await Bun.file(join(repoRoot, "package.json")).json(); const cliPkg = await Bun.file(join(cliRoot, "package.json")).json(); return { name: "executor", version: process.env.EXECUTOR_VERSION ?? cliPkg.version ?? rootPkg.version ?? "0.0.0", description: rootPkg.description ?? "Local AI executor with a CLI, local API server, and web UI.", keywords: rootPkg.keywords ?? [], homepage: rootPkg.homepage, bugs: rootPkg.bugs, repository: rootPkg.repository, license: rootPkg.license ?? "MIT", }; }; // --------------------------------------------------------------------------- // Targets // --------------------------------------------------------------------------- type Target = { os: "linux" | "darwin" | "win32"; arch: "x64" | "arm64"; abi?: "musl"; }; const ALL_TARGETS: Target[] = [ { os: "linux", arch: "x64" }, { os: "linux", arch: "arm64" }, { os: "linux", arch: "x64", abi: "musl" }, { os: "linux", arch: "arm64", abi: "musl" }, { os: "darwin", arch: "x64" }, { os: "darwin", arch: "arm64" }, { os: "win32", arch: "x64" }, { os: "win32", arch: "arm64" }, ]; const platformName = (t: Target) => (t.os === "win32" ? "windows" : t.os); const targetPackageName = (t: Target) => ["executor", platformName(t), t.arch, t.abi].filter(Boolean).join("-"); const bunTarget = (t: Target) => ["bun", platformName(t), t.arch, t.abi].filter(Boolean).join("-"); const binaryName = (t: Target) => (t.os === "win32" ? "executor.exe" : "executor"); const isCurrentPlatform = (t: Target) => t.os === process.platform && t.arch === process.arch && !t.abi; /** Resolve the platform-specific secure-exec-v8 binary for a given target. */ const resolveSecureExecV8 = (t: Target): string | null => { const platformMap: Record<string, string> = { "darwin-arm64": "@secure-exec/v8-darwin-arm64", "darwin-x64": "@secure-exec/v8-darwin-x64", "linux-arm64": "@secure-exec/v8-linux-arm64-gnu", "linux-x64": "@secure-exec/v8-linux-x64-gnu", }; const key = `${t.os}-${t.arch}`; const pkg = platformMap[key]; if (!pkg) return null; try { // Resolve from @secure-exec/v8 which has these as optional deps const req = createRequire(join(repoRoot, "node_modules", "secure-exec", "package.json")); const pkgJson = req.resolve(`${pkg}/package.json`); return join(dirname(pkgJson), "secure-exec-v8"); } catch { // Try bun's flat node_modules layout const bunPath = join( repoRoot, `node_modules/.bun/${pkg.replace("/", "+")}@0.2.1/node_modules/${pkg}/secure-exec-v8`, ); if (existsSync(bunPath)) return bunPath; return null; } }; // --------------------------------------------------------------------------- // Build mode // --------------------------------------------------------------------------- type BuildMode = "production" | "development"; // --------------------------------------------------------------------------- // Build web app // --------------------------------------------------------------------------- const buildWeb = async (mode: BuildMode) => { const webDist = join(webRoot, "dist"); await rm(webDist, { recursive: true, force: true }); console.log(`Building web app (${mode})...`); const proc = Bun.spawn(["bun", "run", "build", "--mode", mode], { cwd: webRoot, stdio: ["ignore", "inherit", "inherit"], env: { ...process.env, NODE_ENV: mode }, }); if ((await proc.exited) !== 0) throw new Error("Web build failed"); return webDist; }; // --------------------------------------------------------------------------- // Embedded web UI — generates a virtual module that imports all web assets // using `with { type: "file" }` so Bun bakes them into the compiled binary. // --------------------------------------------------------------------------- const createEmbeddedWebUISource = async (mode: BuildMode) => { const webDist = await buildWeb(mode); const files = (await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: webDist }))) .map((f) => f.replaceAll("\\", "/")) .sort(); const imports = files.map((file, i) => { const spec = join(webDist, file).replaceAll("\\", "/"); return `import file_${i} from ${JSON.stringify(spec)} with { type: "file" };`; }); const entries = files.map((file, i) => ` ${JSON.stringify(file)}: file_${i},`); return [ "// Auto-generated — maps web UI paths to embedded file references", ...imports, "export default {", ...entries, "} as Record<string, string>;", ].join("\n"); }; // --------------------------------------------------------------------------- // Embedded drizzle migrations — inlined as text imports so drizzle's // `migrate()` (which reads a folder from disk) can be given a tmpdir // populated from the inlined contents at runtime. // --------------------------------------------------------------------------- const createEmbeddedMigrationsSource = async () => { const migrationsDir = resolve(webRoot, "drizzle"); const files = (await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: migrationsDir }))) .map((f) => f.replaceAll("\\", "/")) .sort(); const imports = files.map((file, i) => { const spec = join(migrationsDir, file).replaceAll("\\", "/"); return `import file_${i} from ${JSON.stringify(spec)} with { type: "text" };`; }); const entries = files.map((file, i) => ` ${JSON.stringify(file)}: file_${i},`); return [ "// Auto-generated — maps migration paths to inlined file contents", ...imports, "export default {", ...entries, "} as Record<string, string>;", ].join("\n"); }; // --------------------------------------------------------------------------- // Bun.build plugin for @secure-exec bundling issues // --------------------------------------------------------------------------- /** * Plugin that fixes two issues with @secure-exec in compiled binaries: * * 1. node-stdlib-browser / web-streams-polyfill eagerly call require.resolve() * at import time, which fails in bunfs. We stub these out since our code * never uses the polyfill functions. * * 2. bridge-loader.js reads bridge.js from disk via fs.readFileSync using * __dirname. In a compiled binary __dirname points into bunfs where the * file doesn't exist. We replace bridge-loader with a version that embeds * bridge.js content directly. */ const secureExecBundlePlugin = async (): Promise<import("bun").BunPlugin> => { // Read files at build time so we can inline them into the compiled binary. // bridge.js is loaded via fs.readFileSync at runtime, which fails in bunfs. // bridgeAttach comes from @secure-exec/core's generated isolate-runtime. const secureExecNodejs = join( repoRoot, "node_modules/.bun/@secure-exec+nodejs@0.2.1/node_modules/@secure-exec/nodejs", ); const secureExecCore = join( repoRoot, "node_modules/.bun/@secure-exec+core@0.2.1/node_modules/@secure-exec/core", ); const bridgeCode = await Bun.file(join(secureExecNodejs, "dist/bridge.js")).text(); const isolateRuntime = await import(join(secureExecCore, "dist/generated/isolate-runtime.js")); const bridgeAttachCode = isolateRuntime.ISOLATE_RUNTIME_SOURCES.bridgeAttach; const polyfillCodeMap = (await import(join(secureExecCore, "dist/generated/polyfills.js"))) .POLYFILL_CODE_MAP as Record<string, string>; return { name: "secure-exec-bundle-fixes", setup(build) { // Stub polyfill modules that fail at import time in compiled binaries const stubTargets = /node-stdlib-browser|web-streams-polyfill/; build.onResolve({ filter: stubTargets }, (args) => ({ path: args.path, namespace: "stub", })); // Replace @secure-exec/nodejs polyfills (which use node-stdlib-browser + esbuild // at runtime) with a shim that serves from pre-bundled POLYFILL_CODE_MAP. build.onResolve({ filter: /polyfills/ }, (args) => { if ( args.importer.includes("@secure-exec/nodejs") || args.importer.includes("@secure-exec+nodejs") ) { return { path: args.path, namespace: "polyfills-shim" }; } }); build.onLoad({ filter: /.*/, namespace: "polyfills-shim" }, () => ({ contents: ` const POLYFILL_CODE_MAP = ${JSON.stringify(polyfillCodeMap)}; const polyfillCache = new Map(); export default {}; export async function bundlePolyfill(moduleName) { const cached = polyfillCache.get(moduleName); if (cached) return cached; const code = POLYFILL_CODE_MAP[moduleName]; if (!code) throw new Error("No polyfill available for module: " + moduleName); polyfillCache.set(moduleName, code); return code; } export function getAvailableStdlib() { return Object.keys(POLYFILL_CODE_MAP); } export function hasPolyfill(name) { return name.replace(/^node:/, "") in POLYFILL_CODE_MAP; } export async function prebundleAllPolyfills() { return { ...POLYFILL_CODE_MAP }; } `, loader: "js", })); build.onLoad({ filter: /.*/, namespace: "stub" }, () => ({ contents: "export default {};", loader: "js", })); // Replace bridge-loader with pre-read content build.onResolve({ filter: /bridge-loader/ }, (args) => { if (args.importer.includes("secure-exec")) { return { path: args.path, namespace: "bridge" }; } }); build.onLoad({ filter: /.*/, namespace: "bridge" }, () => ({ contents: ` const bridgeCode = ${JSON.stringify(bridgeCode)}; const bridgeAttachCode = ${JSON.stringify(bridgeAttachCode)}; export function getRawBridgeCode() { return bridgeCode; } export function getBridgeAttachCode() { return bridgeAttachCode; } `, loader: "js", })); }, }; }; // --------------------------------------------------------------------------- // Build platform binaries // --------------------------------------------------------------------------- const EMBEDDED_WEB_UI_STUB = `const files: Record<string, string> | null = null;\n\nexport default files;\n`; const EMBEDDED_MIGRATIONS_STUB = `const migrations: Record<string, string> | null = null;\n\nexport default migrations;\n`; const buildBinaries = async (targets: Target[], mode: BuildMode) => { const meta = await readMetadata(); const binaries: Record<string, string> = {}; const embeddedWebUIPath = join(cliRoot, "src/embedded-web-ui.gen.ts"); const embeddedMigrationsPath = join(webRoot, "src/server/embedded-migrations.gen.ts"); await rm(distDir, { recursive: true, force: true }); console.log(`Generating embedded web UI bundle (${mode})...`); const embeddedWebUI = await createEmbeddedWebUISource(mode); await writeFile(embeddedWebUIPath, `${embeddedWebUI}\n`); console.log("Generating embedded drizzle migrations..."); const embeddedMigrations = await createEmbeddedMigrationsSource(); await writeFile(embeddedMigrationsPath, `${embeddedMigrations}\n`); const quickJsWasmPath = resolveQuickJsWasmPath(); try { for (const target of targets) { const name = targetPackageName(target); const outDir = join(distDir, name); const binDir = join(outDir, "bin"); await mkdir(binDir, { recursive: true }); console.log(`Building ${name}...`); await Bun.build({ entrypoints: [join(cliRoot, "src/main.ts")], minify: mode === "production", compile: { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Bun compile target string is dynamically constructed target: bunTarget(target) as any, outfile: join(binDir, binaryName(target)), }, plugins: [await secureExecBundlePlugin()], }); // Copy QuickJS WASM next to binary — loaded at runtime by the server await cp(quickJsWasmPath, join(binDir, "emscripten-module.wasm")); // Copy secure-exec-v8 binary next to executor — needed for code execution const secureExecBin = resolveSecureExecV8(target); if (secureExecBin && existsSync(secureExecBin)) { const destName = target.os === "win32" ? "secure-exec-v8.exe" : "secure-exec-v8"; await cp(secureExecBin, join(binDir, destName)); await chmod(join(binDir, destName), 0o755); } // Smoke test on current platform if (isCurrentPlatform(target)) { const bin = join(binDir, binaryName(target)); console.log(` Smoke test: ${bin} --version`); const version = await $`${bin} --version`.text(); console.log(` OK: ${version.trim()}`); } // Platform package.json await writeFile( join(outDir, "package.json"), JSON.stringify( { name, version: meta.version, os: [target.os], cpu: [target.arch], bin: { executor: `bin/${binaryName(target)}` }, }, null, 2, ) + "\n", ); binaries[name] = meta.version; } return binaries; } finally { await writeFile(embeddedWebUIPath, EMBEDDED_WEB_UI_STUB); await writeFile(embeddedMigrationsPath, EMBEDDED_MIGRATIONS_STUB); } }; // --------------------------------------------------------------------------- // Build wrapper npm package // --------------------------------------------------------------------------- const buildWrapperPackage = async (binaries: Record<string, string>) => { const meta = await readMetadata(); const wrapperDir = join(distDir, meta.name); const binDir = join(wrapperDir, "bin"); await mkdir(binDir, { recursive: true }); // Node.js shim that spawns the downloaded platform binary await writeFile(join(binDir, "executor"), NODE_SHIM); await chmod(join(binDir, "executor"), 0o755); // Postinstall downloads the matching release asset from GitHub Releases await writeFile(join(wrapperDir, "postinstall.cjs"), POSTINSTALL_SCRIPT); // Package.json await writeFile( join(wrapperDir, "package.json"), JSON.stringify( { name: meta.name, version: meta.version, description: meta.description, keywords: meta.keywords, homepage: meta.homepage, bugs: meta.bugs, repository: meta.repository, license: meta.license, bin: { executor: "bin/executor" }, scripts: { postinstall: "node ./postinstall.cjs", }, engines: { node: ">=20", }, }, null, 2, ) + "\n", ); // README const readmePath = join(repoRoot, "README.md"); if (existsSync(readmePath)) { await cp(readmePath, join(wrapperDir, "README.md")); } console.log(`\nWrapper package: ${wrapperDir}`); console.log(` ${meta.name}@${meta.version}`); console.log(` release assets: ${Object.keys(binaries).join(", ")}`); }; // --------------------------------------------------------------------------- // Preview wrapper — a slim npm package for pkg.pr.new previews that fetches // the platform binary from our R2 bucket at install time. // // The release wrapper points postinstall at GitHub Releases. For previews // there's no release, so we upload per-PR tarballs to R2 (keyed by commit // SHA) and have a dedicated postinstall download from there. // // CI splits this in two: // 1. A matrix job per platform runs `buildPreviewTarballs` to produce // dist/previews/<platform>.tar.gz, which it uploads to R2. // 2. A single publish job runs `buildPreviewWrapperPackage` with an // explicit list of platforms and hands the wrapper to pkg.pr.new. // // Both paths require EXECUTOR_PREVIEW_CDN_URL and EXECUTOR_PREVIEW_SHA so // the postinstall URL embeds the right commit. // --------------------------------------------------------------------------- const buildPreviewTarballs = async (binaries: Record<string, string>) => { const previewDir = join(distDir, "previews"); await mkdir(previewDir, { recursive: true }); for (const platformPkg of Object.keys(binaries)) { const srcBinDir = join(distDir, platformPkg, "bin"); const tarPath = join(previewDir, `${platformPkg}.tar.gz`); await $`tar -czf ${tarPath} .`.cwd(srcBinDir).quiet(); console.log(`Preview tarball: ${tarPath}`); } }; const resolveTargetsFromEnv = (env: string | undefined): Target[] => { if (!env) throw new Error("EXECUTOR_PREVIEW_TARGETS must be set (comma-separated package names)"); const names = env.split(",").map((s) => s.trim()).filter(Boolean); const resolved = names.map((name) => { const match = ALL_TARGETS.find((t) => targetPackageName(t) === name); if (!match) throw new Error(`Unknown preview target: ${name}`); return match; }); if (resolved.length === 0) throw new Error("EXECUTOR_PREVIEW_TARGETS resolved to an empty list"); return resolved; }; const buildPreviewWrapperPackage = async (targets: Target[]) => { const meta = await readMetadata(); const cdnUrl = process.env.EXECUTOR_PREVIEW_CDN_URL?.replace(/\/+$/, ""); const sha = process.env.EXECUTOR_PREVIEW_SHA; if (!cdnUrl || !sha) { throw new Error( "preview build requires EXECUTOR_PREVIEW_CDN_URL and EXECUTOR_PREVIEW_SHA to be set", ); } const wrapperDir = join(distDir, meta.name); const binDir = join(wrapperDir, "bin"); await mkdir(binDir, { recursive: true }); await writeFile(join(binDir, "executor"), NODE_SHIM); await chmod(join(binDir, "executor"), 0o755); const postinstall = PREVIEW_POSTINSTALL_SCRIPT.replaceAll( "__CDN_BASE_URL__", `${cdnUrl}/${sha}`, ); await writeFile(join(wrapperDir, "postinstall.cjs"), postinstall); // Restrict os/cpu to platforms we actually built this run so npm refuses // the install on anything else — a clear error beats a cryptic 404 from // postinstall on an unbuilt platform. const osList = Array.from(new Set(targets.map((t) => t.os))); const cpuList = Array.from(new Set(targets.map((t) => t.arch))); await writeFile( join(wrapperDir, "package.json"), JSON.stringify( { name: meta.name, version: meta.version,