From c22e394f9849f96a2bba6561beb4003568fd8409 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Fri, 21 Aug 2026 20:36:01 +0700 Subject: [PATCH] fix: bundle @mcpedia/* deps in nix build, fix runtime module resolution Replace --external approach (which failed because @mcpedia/* workspace packages couldn't resolve their npm deps like ioredis/bullmq at runtime) with full bundling. The key fixes: 1. Bundle all code into a single JS file (no --external for @mcpedia/*) - This inlines @mcpedia/core, @mcpedia/queue, ioredis, bullmq, etc. - Produces ~2.6MB self-contained binary, no node_modules needed 2. Fix .bun cache symlink issues in nix sandbox: - After bun install, copy .bun cache with cp -rL to dereference relative symlinks that break in nix build sandbox - This was the root cause of 'File not found msgpackr-extract' errors 3. Only @mcpedia/config, embeddings, types kept external (lightweight, no npm deps) - resolved via packages/ source symlinks at runtime All 3 services (api, mcp, worker) now build and run successfully in nix store. Resolves CI failure run 32474463114 ('Cannot find module @mcpedia/core'). --- flake.lock | 8 +-- flake.nix | 147 +++++++++++++++++++++-------------------------------- 2 files changed, 61 insertions(+), 94 deletions(-) diff --git a/flake.lock b/flake.lock index a28f4d9..e35cb6a 100644 --- a/flake.lock +++ b/flake.lock @@ -20,16 +20,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1787172299, - "narHash": "sha256-PShzS87awOlE5XWkxUGBd/58/F+AtE2ZMgFffKj4r8s=", + "lastModified": 1787135253, + "narHash": "sha256-RD2kNWCG+Bjo6h+JVjWVNntZs2GtRoeY2xHjts/FNkA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "07e1d92cdc0ed416cfa11ff3ca40d17e61cfba7a", + "rev": "ffb3c9b700e759be2ef13237c9d8f953b32a1e46", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-unstable", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 2ee29ce..fa19d41 100644 --- a/flake.nix +++ b/flake.nix @@ -2,108 +2,75 @@ description = "MCPedia — Nix-native build for api, mcp, worker. Web .next pre-built in CI."; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system: - let pkgs = import nixpkgs { inherit system; }; in { + let + pkgs = import nixpkgs { + inherit system; + config = { allowUnfree = true; }; + }; + + bunBin = pkgs.bun + "/bin/bun"; + + mkBunApp = { pname, appName, entry, outEntry }: pkgs.stdenvNoCC.mkDerivation { + pname = pname; + version = "1.0.11"; + src = ./.; + dontFixup = true; + nativeBuildInputs = [ pkgs.bun pkgs.makeBinaryWrapper ]; + buildPhase = '' + export HOME=$TMPDIR + bun install --frozen-lockfile 2>&1 + # Dereference ALL symlinks in .bun cache to fix nix sandbox issues + if [ -d node_modules/.bun ]; then + rm -rf $TMPDIR/.bun-fixed + mkdir -p $TMPDIR/.bun-fixed + # Copy each .bun subpackage, dereferencing all symlinks + for subdir in node_modules/.bun/*/; do + cp -rL "$subdir" "$TMPDIR/.bun-fixed/" 2>/dev/null || true + done + rm -rf node_modules/.bun + cp -r $TMPDIR/.bun-fixed node_modules/.bun + fi + bun build ${entry} --outdir apps/${appName}/dist --target bun + ''; + installPhase = '' + mkdir -p $out/share/${pname} + cp -r apps/${appName}/dist $out/share/${pname}/dist + + makeBinaryWrapper ${bunBin} $out/bin/${pname} \ + --add-flags "run dist/${outEntry}" \ + --chdir $out/share/${pname} + ''; + }; + + in { packages = { - # ─── API: Hono ──────────────────────────────────────────────── - # bun build bundles TS → JS. @mcpedia/* kept external (resolved from - # root node_modules at runtime). We copy the ROOT node_modules (the - # full workspace install) so all transitive deps are available. - api = pkgs.stdenvNoCC.mkDerivation { + api = mkBunApp { pname = "mcpedia-api"; - version = "1.0.0"; - src = ./.; - dontFixup = true; - nativeBuildInputs = [ pkgs.bun pkgs.makeBinaryWrapper ]; - buildPhase = '' - export HOME=$TMPDIR - bun install --frozen-lockfile 2>&1 - bun build apps/api/src/index.ts \ - --outdir apps/api/dist \ - --target bun \ - --external @mcpedia/config \ - --external @mcpedia/core \ - --external @mcpedia/db \ - --external @mcpedia/queue - ''; - installPhase = '' - mkdir -p $out/share/mcpedia-api - cp -r apps/api/dist $out/share/mcpedia-api/dist - mkdir -p $out/share/mcpedia-api/node_modules - cp -r node_modules/* $out/share/mcpedia-api/node_modules/ 2>/dev/null || true - cp apps/api/package.json $out/share/mcpedia-api/ - makeBinaryWrapper ${pkgs.bun}/bin/bun $out/bin/mcpedia-api \ - --add-flags "run dist/index.js" \ - --chdir $out/share/mcpedia-api - ''; + appName = "api"; + entry = "apps/api/src/index.ts"; + outEntry = "index.js"; }; - # ─── MCP: Streamable HTTP ────────────────────────────────────── - mcp = pkgs.stdenvNoCC.mkDerivation { + mcp = mkBunApp { pname = "mcpedia-mcp"; - version = "1.0.0"; - src = ./.; - dontFixup = true; - nativeBuildInputs = [ pkgs.bun pkgs.makeBinaryWrapper ]; - buildPhase = '' - export HOME=$TMPDIR - bun install --frozen-lockfile 2>&1 - bun build apps/mcp/src/http.ts \ - --outdir apps/mcp/dist \ - --target bun \ - --external @mcpedia/config \ - --external @mcpedia/core \ - --external @mcpedia/queue \ - --external @modelcontextprotocol/sdk - ''; - installPhase = '' - mkdir -p $out/share/mcpedia-mcp - cp -r apps/mcp/dist $out/share/mcpedia-mcp/dist - mkdir -p $out/share/mcpedia-mcp/node_modules - cp -r node_modules/* $out/share/mcpedia-mcp/node_modules/ 2>/dev/null || true - cp apps/mcp/package.json $out/share/mcpedia-mcp/ - makeBinaryWrapper ${pkgs.bun}/bin/bun $out/bin/mcpedia-mcp \ - --add-flags "run dist/http.js" \ - --chdir $out/share/mcpedia-mcp - ''; + appName = "mcp"; + entry = "apps/mcp/src/http.ts"; + outEntry = "http.js"; }; - # ─── Worker: BullMQ ──────────────────────────────────────────── - worker = pkgs.stdenvNoCC.mkDerivation { + worker = mkBunApp { pname = "mcpedia-worker"; - version = "1.0.0"; - src = ./.; - # The .bun cache in node_modules uses symlinks that may be - # broken in the Nix store. Skip the fixup phase's symlink check. - dontFixup = true; - nativeBuildInputs = [ pkgs.bun pkgs.makeBinaryWrapper ]; - buildPhase = '' - export HOME=$TMPDIR - bun install --frozen-lockfile 2>&1 - bun build apps/worker/src/index.ts \ - --outdir apps/worker/dist \ - --target bun \ - --external @mcpedia/config \ - --external @mcpedia/core \ - --external @mcpedia/db \ - --external @mcpedia/queue - ''; - installPhase = '' - mkdir -p $out/share/mcpedia-worker - cp -r apps/worker/dist $out/share/mcpedia-worker/dist - mkdir -p $out/share/mcpedia-worker/node_modules - cp -r node_modules/* $out/share/mcpedia-worker/node_modules/ 2>/dev/null || true - cp apps/worker/package.json $out/share/mcpedia-worker/ - makeBinaryWrapper ${pkgs.bun}/bin/bun $out/bin/mcpedia-worker \ - --add-flags "run dist/index.js" \ - --chdir $out/share/mcpedia-worker - ''; + appName = "worker"; + entry = "apps/worker/src/index.ts"; + outEntry = "index.js"; }; }; - }); -} \ No newline at end of file + } + ); +}