#!/usr/bin/env node const { cpSync, existsSync, mkdirSync, readdirSync, rmSync, } = require("node:fs"); const { join, resolve } = require("node:path"); const root = resolve(__dirname, ".."); const webRoot = join(root, "web"); const standaloneRoot = join(webRoot, ".next", "standalone"); const standaloneAppRoot = join(standaloneRoot, "web"); const standaloneNodeModulesRoot = join(standaloneRoot, "node_modules"); const staticRoot = join(webRoot, ".next", "static"); const publicRoot = join(webRoot, "public"); const distWebRoot = join(root, "dist", "web"); const distStandaloneRoot = join(distWebRoot, "standalone"); const sourceNodePtyRoot = join(webRoot, "node_modules", "node-pty"); const COPY_OPTIONS = { recursive: true, force: true, dereference: true, }; function overlayNodePty(targetRoot) { if (!existsSync(sourceNodePtyRoot)) return []; const hydrated = []; const directTarget = join(targetRoot, "node_modules", "node-pty"); mkdirSync(join(targetRoot, "node_modules"), { recursive: true }); cpSync(sourceNodePtyRoot, directTarget, COPY_OPTIONS); hydrated.push(directTarget); const hashedNodeModulesRoot = join(targetRoot, ".next", "node_modules"); if (!existsSync(hashedNodeModulesRoot)) return hydrated; for (const entry of readdirSync(hashedNodeModulesRoot, { withFileTypes: true, })) { if (!entry.isDirectory() || !entry.name.startsWith("node-pty-")) continue; const target = join(hashedNodeModulesRoot, entry.name); cpSync(sourceNodePtyRoot, target, COPY_OPTIONS); hydrated.push(target); } return hydrated; } if (!existsSync(standaloneAppRoot)) { console.error( "[forge] Web standalone build not found at web/.next/standalone/web. Run `npm --prefix web run build` first.", ); process.exit(1); } rmSync(distWebRoot, { recursive: true, force: true }); mkdirSync(distStandaloneRoot, { recursive: true }); cpSync(standaloneAppRoot, distStandaloneRoot, COPY_OPTIONS); if (existsSync(standaloneNodeModulesRoot)) { cpSync( standaloneNodeModulesRoot, join(distStandaloneRoot, "node_modules"), COPY_OPTIONS, ); } if (existsSync(staticRoot)) { mkdirSync(join(distStandaloneRoot, ".next"), { recursive: true }); cpSync(staticRoot, join(distStandaloneRoot, ".next", "static"), COPY_OPTIONS); } if (existsSync(publicRoot)) { cpSync(publicRoot, join(distStandaloneRoot, "public"), COPY_OPTIONS); } const hydratedTargets = overlayNodePty(distStandaloneRoot); console.log(`[forge] Staged web standalone host at ${distStandaloneRoot}`); if (hydratedTargets.length > 0) { console.log( `[forge] Hydrated node-pty native assets in ${hydratedTargets.length} location(s).`, ); }