// scripts/check-nix-deps.ts — Keep .nix/bun.nix in sync with bun.lock // // Handy uses bun2nix to generate per-package Nix fetchurl expressions from // bun.lock. This replaces the old FOD (Fixed-Output Derivation) approach // where a single hash covered the entire node_modules — that hash would // break whenever the bun version in nixpkgs changed, even without any // dependency updates. // // How it works: // 1. Computes sha256 of bun.lock // 2. Compares with stored hash in .nix/bun-lock-hash // 3. If they match — nothing to do (~2ms) // 4. If they differ — runs `bunx bun2nix` to regenerate .nix/bun.nix // // When it runs: // - Automatically via "postinstall" in package.json — triggers after every // bun install / bun add / bun remove / bun update // - Can also be run manually: bun scripts/check-nix-deps.ts // // What to commit: // If the script regenerated .nix/bun.nix, commit it together with bun.lock: // git add bun.lock .nix/bun.nix .nix/bun-lock-hash import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; import { join, resolve } from "path"; const root = resolve(import.meta.dirname, ".."); const nixDir = join(root, ".nix"); const lockFile = join(root, "bun.lock"); const hashFile = join(nixDir, "bun-lock-hash"); const nixFile = join(nixDir, "bun.nix"); // Skip on Windows — bun2nix is Nix-only and hangs on Windows CI if (process.platform === "win32") process.exit(0); // No bun.lock — nothing to do if (!existsSync(lockFile)) process.exit(0); // Ensure .nix directory exists mkdirSync(nixDir, { recursive: true }); // Compute sha256 of the current bun.lock const currentHash = new Bun.CryptoHasher("sha256") .update(readFileSync(lockFile)) .digest("hex"); // Read the previously stored hash (empty if first run) const storedHash = existsSync(hashFile) ? readFileSync(hashFile, "utf-8").trim() : ""; // If hashes match, bun.nix is up to date — nothing to do if (currentHash === storedHash) process.exit(0); // bun.lock has changed — regenerate the Nix dependency file console.log( `[check-nix-deps] bun.lock has changed, regenerating ${nixFile}...`, ); const result = Bun.spawnSync(["bunx", "bun2nix", "-o", nixFile], { cwd: root, stdio: ["inherit", "inherit", "inherit"], }); if (result.exitCode !== 0) { console.warn( "[check-nix-deps] Warning: bunx bun2nix failed. .nix/bun.nix may be outdated.", ); console.warn( "[check-nix-deps] Nix users: run `bunx bun2nix -o .nix/bun.nix` manually.", ); console.warn( "[check-nix-deps] Non-Nix users: this is safe to ignore, CI will catch it.", ); // Exit 0 so that `bun install` is not blocked for non-Nix developers. // CI validates bun.nix independently. process.exit(0); } writeFileSync(hashFile, currentHash + "\n"); console.log(`[check-nix-deps] Updated ${nixFile}`); console.log( "[check-nix-deps] Don't forget to commit: .nix/bun.nix .nix/bun-lock-hash", );