98 lines · 4.2 KB · TypeScript
RawDownload
/** * Build the production sidecar binary using `bun build --compile`. * * Produces a fully self-contained executable that includes the Bun runtime * plus the entire @executor-js/local server graph (including bun:sqlite, * drizzle, MCP, etc.). The Electron main process exec's this binary at * runtime instead of relying on a `bun` install on the user's machine. * * Also stages the apps/local Vite build output as `resources/web-ui/` so * electron-builder picks it up via extraResources. * * Like apps/cli/src/build.ts, this script generates * apps/local/src/server/embedded-migrations.gen.ts with drizzle migration * files inlined via `with { type: "text" }` before compiling, then restores * the stub afterwards. The compiled binary unpacks migrations to a tmpdir * at boot so drizzle's `migrate()` (which only accepts folder paths) works. */import { mkdir, rm, cp, writeFile } from "node:fs/promises";import { existsSync } from "node:fs";import { join, resolve } from "node:path";import { $ } from "bun"; const ROOT = resolve(import.meta.dir, "..");const REPO_ROOT = resolve(ROOT, "../..");const APPS_LOCAL = resolve(REPO_ROOT, "apps/local");const SIDECAR_ENTRY = resolve(ROOT, "src/sidecar/server.ts");const SIDECAR_OUT_DIR = resolve(ROOT, "resources/sidecar");const WEB_UI_OUT_DIR = resolve(ROOT, "resources/web-ui");const APPS_LOCAL_DIST = resolve(APPS_LOCAL, "dist"); const EMBEDDED_MIGRATIONS_PATH = join(APPS_LOCAL, "src/server/embedded-migrations.gen.ts");const EMBEDDED_MIGRATIONS_STUB = `const migrations: Record<string, string> | null = null;\n\nexport default migrations;\n`; /** * Cross-compile target for `bun build --compile`. When unset we use Bun's * default `bun` target (the runner's own platform). CI passes a specific * value like `bun-darwin-x64` to produce binaries for other platforms from * a single matrix entry. */const BUN_TARGET = process.env.BUN_TARGET ?? "bun";const targetIsWindows = BUN_TARGET.includes("windows") || process.platform === "win32";const binaryName = targetIsWindows ? "executor-sidecar.exe" : "executor-sidecar";const sidecarBinary = resolve(SIDECAR_OUT_DIR, binaryName); const createEmbeddedMigrationsSource = async (): Promise<string> => {  const migrationsDir = resolve(APPS_LOCAL, "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");}; if (!existsSync(APPS_LOCAL_DIST)) {  // oxlint-disable-next-line executor/no-try-catch-or-throw, executor/no-error-constructor -- boundary: build-time fatal  throw new Error(    `apps/local/dist not found. Run \`bun run --filter @executor-js/local build\` first.`,  );} await rm(SIDECAR_OUT_DIR, { recursive: true, force: true });await rm(WEB_UI_OUT_DIR, { recursive: true, force: true });await mkdir(SIDECAR_OUT_DIR, { recursive: true });await mkdir(WEB_UI_OUT_DIR, { recursive: true }); console.log("[build-sidecar] inlining drizzle migrations...");const embeddedMigrations = await createEmbeddedMigrationsSource();await writeFile(EMBEDDED_MIGRATIONS_PATH, `${embeddedMigrations}\n`); // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: ensure the gen stub is restored even if compile failstry {  console.log(    `[build-sidecar] bun build --compile --target=${BUN_TARGET} ${SIDECAR_ENTRY} → ${sidecarBinary}`,  );  await $`bun build --compile --minify --sourcemap --target=${BUN_TARGET} --outfile ${sidecarBinary} ${SIDECAR_ENTRY}`.cwd(    REPO_ROOT,  );} finally {  await writeFile(EMBEDDED_MIGRATIONS_PATH, EMBEDDED_MIGRATIONS_STUB);} console.log(`[build-sidecar] staging web UI → ${WEB_UI_OUT_DIR}`);await cp(APPS_LOCAL_DIST, WEB_UI_OUT_DIR, { recursive: true }); console.log("[build-sidecar] done");