diff --git a/.gitignore b/.gitignore index a00b96ef47..a0142644e0 100644 --- a/.gitignore +++ b/.gitignore @@ -101,14 +101,10 @@ app.__qa_backup/ .app-build-backup-*/ backup/ -# Production standalone build (created by scripts/prepublish.mjs) -# Conflicts with Next.js App Router detection in dev (root app/ shadows src/app/) -# npm publish still includes it via package.json "files" field -/app/ - # Build intermediates (.build/) and shippable standalone (dist/). # These are fully reproducible from source; never committed. # Layer 1: Next.js now writes to .build/next (was .next); assembled bundle โ†’ dist/ +# (Previously /app/ was the standalone output; renamed to /dist/ in Layer 1.) /.build/ /dist/ /.next/ @@ -126,9 +122,6 @@ vscode-extension/ *.sqlite-wal *.sqlite-journal -# Compiled npm-package build artifact (not source, should not be in git) -/app - # IDEA .idea/ diff --git a/bin/cli/commands/serve.mjs b/bin/cli/commands/serve.mjs index 6b3e22b2e5..de0a5c826f 100644 --- a/bin/cli/commands/serve.mjs +++ b/bin/cli/commands/serve.mjs @@ -10,7 +10,7 @@ import { isTermux } from "../../../scripts/build/postinstallSupport.mjs"; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = join(__dirname, "..", "..", ".."); -const APP_DIR = join(ROOT, "app"); +const APP_DIR = join(ROOT, "dist"); function parsePort(value, fallback) { const parsed = parseInt(String(value), 10); diff --git a/package.json b/package.json index 57215ed479..d0940c86a6 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ }, "files": [ "bin/", - "app/", + "dist/", "src/lib/cli-helper/", "@omniroute/", "open-sse/mcp-server/index.ts", diff --git a/scripts/build/assembleStandalone.mjs b/scripts/build/assembleStandalone.mjs index afa4c09845..275cf0219b 100644 --- a/scripts/build/assembleStandalone.mjs +++ b/scripts/build/assembleStandalone.mjs @@ -406,6 +406,25 @@ export function assembleStandalone({ fsSync.cpSync(standaloneDir, resolvedOutDir, { recursive: true }); } + // 1.5. Fix package.json in outDir: Next.js standalone's server.js is CommonJS (uses require()), + // but the root package.json (which Next copies into the standalone) has "type":"module". + // Remove "type" from the outDir's package.json so Node.js treats .js files as CJS in this dir. + // Without this, `node server.js` (or `import("./server.js")`) fails with + // ReferenceError: require is not defined in ES module scope + const outDirPkgJson = path.join(resolvedOutDir, "package.json"); + if (fsSync.existsSync(outDirPkgJson)) { + try { + const pkg = JSON.parse(fsSync.readFileSync(outDirPkgJson, "utf8")); + if (pkg.type === "module") { + delete pkg.type; + fsSync.writeFileSync(outDirPkgJson, JSON.stringify(pkg, null, 2) + "\n"); + console.log("[assembleStandalone] Removed 'type':'module' from standalone package.json (server.js is CJS)"); + } + } catch (err) { + console.warn(`[assembleStandalone] Could not patch standalone package.json: ${err.message}`); + } + } + // 2. Copy /static -> resolvedOutDir/.next/static const staticSrc = path.join(distDir, "static"); const staticDest = path.join(resolvedOutDir, ".next", "static"); diff --git a/scripts/build/build-next-isolated.mjs b/scripts/build/build-next-isolated.mjs index f7b1521f6c..5660ab8e99 100644 --- a/scripts/build/build-next-isolated.mjs +++ b/scripts/build/build-next-isolated.mjs @@ -12,10 +12,9 @@ import { } from "./assembleStandalone.mjs"; /** - * This repository contains a legacy `app/` snapshot (packaging/runtime artifacts) - * alongside the active Next.js source in `src/app/`. Next.js route discovery scans - * both and fails the build on legacy files. We temporarily move the legacy folder - * out of the project root during `next build`, then restore it in all outcomes. + * Layer 1: `app/` has been renamed to `dist/` and the App-Router collision is gone. + * The only transient paths remaining are `.tmp/wine32` (Wine prefix used by some + * older build tools) and `_tasks` (planning workspace). */ const projectRoot = process.cwd(); @@ -24,11 +23,6 @@ const backupRoot = path.join(os.tmpdir(), `omniroute-build-isolated-${process.pi export function getTransientBuildPaths(rootDir = projectRoot, env = process.env) { const paths = [ - { - label: "legacy app snapshot", - sourcePath: path.join(rootDir, "app"), - backupPath: path.join(backupRoot, "app"), - }, { label: "local Wine prefix", sourcePath: path.join(rootDir, ".tmp", "wine32"), diff --git a/scripts/build/pack-artifact-policy.ts b/scripts/build/pack-artifact-policy.ts index 5a7c768d4f..c166d3482c 100644 --- a/scripts/build/pack-artifact-policy.ts +++ b/scripts/build/pack-artifact-policy.ts @@ -1,9 +1,9 @@ /** * Shared policy for OmniRoute npm publish artifact hygiene. * - * The package currently publishes the standalone runtime under app/. + * The package publishes the standalone runtime under dist/ (Layer 1: renamed from app/). * This policy keeps local backups, QA scratch files, and development-only - * directories out of the staged app/ tree and out of the final tarball. + * directories out of the staged dist/ tree and out of the final tarball. */ const STAGING_FORBIDDEN_DIRECTORIES = [ @@ -40,6 +40,9 @@ export const APP_STAGING_ALLOWED_EXACT_PATHS: string[] = [ ]; export const APP_STAGING_ALLOWED_PATH_PREFIXES: string[] = [ + // Layer 1: Next.js distDir changed from ".next" to ".build/next"; the server + // bundle now lives under .build/next/ inside the standalone output. + ".build/next/", ".next/", "data/", "node_modules/", @@ -51,11 +54,11 @@ export const APP_STAGING_ALLOWED_PATH_PREFIXES: string[] = [ ]; export const PACK_ARTIFACT_ALLOWED_EXACT_PATHS: string[] = APP_STAGING_ALLOWED_EXACT_PATHS.map( - (filePath: string) => `app/${filePath}` + (filePath: string) => `dist/${filePath}` ); export const PACK_ARTIFACT_ALLOWED_PATH_PREFIXES: string[] = APP_STAGING_ALLOWED_PATH_PREFIXES.map( - (directoryPath: string) => `app/${directoryPath}` + (directoryPath: string) => `dist/${directoryPath}` ); export const PACK_ARTIFACT_ROOT_ALLOWED_EXACT_PATHS: string[] = [ @@ -100,12 +103,12 @@ export const PACK_ARTIFACT_ROOT_ALLOWED_PATH_PREFIXES: string[] = [ ]; export const PACK_ARTIFACT_REQUIRED_PATHS: string[] = [ - "app/open-sse/services/compression/engines/rtk/filters/generic-output.json", - "app/open-sse/services/compression/rules/en/filler.json", - "app/server.js", - "app/server-ws.mjs", - "app/responses-ws-proxy.mjs", - "app/peer-stamp.mjs", + "dist/open-sse/services/compression/engines/rtk/filters/generic-output.json", + "dist/open-sse/services/compression/rules/en/filler.json", + "dist/server.js", + "dist/server-ws.mjs", + "dist/responses-ws-proxy.mjs", + "dist/peer-stamp.mjs", "bin/cli/program.mjs", "bin/mcp-server.mjs", "bin/nodeRuntimeSupport.mjs", diff --git a/scripts/build/postinstall.mjs b/scripts/build/postinstall.mjs index 5e83b4883a..deecca2a12 100644 --- a/scripts/build/postinstall.mjs +++ b/scripts/build/postinstall.mjs @@ -5,12 +5,12 @@ * * The npm package ships with a Next.js standalone build that includes * native modules compiled for the build platform (Linux x64) inside - * app/node_modules/. However, npm also installs these as top-level + * dist/node_modules/. However, npm also installs these as top-level * dependencies (in the root node_modules/), correctly compiled for * the user's platform. * * This script copies the correctly-built native binaries from the root - * into the standalone app directory โ€” no rebuild or build tools needed. + * into the standalone dist directory โ€” no rebuild or build tools needed. * * Modules repaired: * - better-sqlite3 (SQLite bindings) @@ -35,7 +35,7 @@ const ROOT = join(__dirname, "..", ".."); const appBinary = join( ROOT, - "app", + "dist", "node_modules", "better-sqlite3", "build", @@ -52,7 +52,7 @@ const rootBinary = join( ); async function fixBetterSqliteBinary() { - if (!existsSync(join(ROOT, "app", "node_modules", "better-sqlite3"))) { + if (!existsSync(join(ROOT, "dist", "node_modules", "better-sqlite3"))) { return; } @@ -92,14 +92,14 @@ async function fixBetterSqliteBinary() { const { execSync } = await import("node:child_process"); const preGypBin = join( ROOT, - "app", + "dist", "node_modules", ".bin", process.platform === "win32" ? "node-pre-gyp.cmd" : "node-pre-gyp" ); const preGypFallback = join( ROOT, - "app", + "dist", "node_modules", "@mapbox", "node-pre-gyp", @@ -110,7 +110,7 @@ async function fixBetterSqliteBinary() { if (existsSync(preGypCmd)) { execSync(`"${process.execPath}" "${preGypCmd}" install --fallback-to-build=false`, { - cwd: join(ROOT, "app", "node_modules", "better-sqlite3"), + cwd: join(ROOT, "dist", "node_modules", "better-sqlite3"), stdio: "inherit", timeout: 60_000, }); @@ -147,7 +147,7 @@ async function fixBetterSqliteBinary() { } execSync(rebuildCmd, { - cwd: join(ROOT, "app"), + cwd: join(ROOT, "dist"), stdio: "inherit", timeout: isAndroid ? 600_000 : 300_000, // ARM compilation is slower env, @@ -171,23 +171,23 @@ async function fixBetterSqliteBinary() { console.warn(" Manual fix options:"); if (process.platform === "win32") { console.warn(" Option A (easiest โ€” no build tools needed):"); - console.warn(` cd "${join(ROOT, "app", "node_modules", "better-sqlite3")}"`); + console.warn(` cd "${join(ROOT, "dist", "node_modules", "better-sqlite3")}"`); console.warn(" npx @mapbox/node-pre-gyp install --fallback-to-build=false"); console.warn(" Option B (requires Build Tools for Visual Studio):"); - console.warn(` cd "${join(ROOT, "app")}" && npm rebuild better-sqlite3`); + console.warn(` cd "${join(ROOT, "dist")}" && npm rebuild better-sqlite3`); console.warn(" Install from: https://visualstudio.microsoft.com/visual-cpp-build-tools/"); console.warn(" Also ensure Python is installed: https://python.org"); } else if (process.platform === "darwin") { - console.warn(` cd ${join(ROOT, "app")} && npm rebuild better-sqlite3`); + console.warn(` cd ${join(ROOT, "dist")} && npm rebuild better-sqlite3`); console.warn(" If build tools are missing: xcode-select --install"); } else { - console.warn(` cd ${join(ROOT, "app")} && npm rebuild better-sqlite3`); + console.warn(` cd ${join(ROOT, "dist")} && npm rebuild better-sqlite3`); } console.warn(""); } /** - * Fix wreq-js native binary for the standalone app directory. + * Fix wreq-js native binary for the standalone dist directory. * * wreq-js ships platform-specific .node binaries under rust/. * The standalone build may only contain Linux binaries from the CI. @@ -206,10 +206,10 @@ async function fixWreqJsBinary() { return; } - const appWreqDir = join(ROOT, "app", "node_modules", "wreq-js", "rust"); + const appWreqDir = join(ROOT, "dist", "node_modules", "wreq-js", "rust"); const rootWreqDir = join(ROOT, "node_modules", "wreq-js", "rust"); - if (!existsSync(join(ROOT, "app", "node_modules", "wreq-js"))) { + if (!existsSync(join(ROOT, "dist", "node_modules", "wreq-js"))) { return; } @@ -262,12 +262,12 @@ async function fixWreqJsBinary() { } } - // Strategy 3: Rebuild wreq-js inside app/ + // Strategy 3: Rebuild wreq-js inside dist/ console.log(" ๐Ÿ“ฅ Attempting npm rebuild wreq-js..."); try { const { execSync } = await import("node:child_process"); execSync("npm rebuild wreq-js", { - cwd: join(ROOT, "app"), + cwd: join(ROOT, "dist"), stdio: "inherit", timeout: 120_000, }); @@ -284,7 +284,7 @@ async function fixWreqJsBinary() { `\n โš ๏ธ Could not fix wreq-js native module for ${process.platform}-${process.arch}.` ); console.warn(" OAuth-based providers (Codex, Cursor, etc.) may not work."); - console.warn(` Manual fix: cd ${join(ROOT, "app")} && npm install wreq-js --no-save\n`); + console.warn(` Manual fix: cd ${join(ROOT, "dist")} && npm install wreq-js --no-save\n`); } async function ensureSwcHelpers() { @@ -292,7 +292,7 @@ async function ensureSwcHelpers() { return; } - const swcHelpersApp = join(ROOT, "app", "node_modules", "@swc", "helpers"); + const swcHelpersApp = join(ROOT, "dist", "node_modules", "@swc", "helpers"); const swcHelpersRoot = join(ROOT, "node_modules", "@swc", "helpers"); if (existsSync(swcHelpersApp)) { @@ -302,13 +302,13 @@ async function ensureSwcHelpers() { if (existsSync(swcHelpersRoot)) { try { const { cpSync } = await import("node:fs"); - mkdirSync(join(ROOT, "app", "node_modules", "@swc"), { recursive: true }); + mkdirSync(join(ROOT, "dist", "node_modules", "@swc"), { recursive: true }); cpSync(swcHelpersRoot, swcHelpersApp, { recursive: true }); - console.log(" โœ… @swc/helpers copied to standalone app/node_modules.\n"); + console.log(" โœ… @swc/helpers copied to standalone dist/node_modules.\n"); } catch (err) { console.warn(` โš ๏ธ Could not copy @swc/helpers: ${err.message}`); console.warn( - " Try manually: cp -r node_modules/@swc/helpers app/node_modules/@swc/helpers\n" + " Try manually: cp -r node_modules/@swc/helpers dist/node_modules/@swc/helpers\n" ); } return; diff --git a/scripts/build/postinstallSupport.mjs b/scripts/build/postinstallSupport.mjs index 9bd399aa5c..53e66b8ea3 100644 --- a/scripts/build/postinstallSupport.mjs +++ b/scripts/build/postinstallSupport.mjs @@ -4,15 +4,16 @@ import { existsSync } from "node:fs"; import { join } from "node:path"; /** - * Detect whether the current install tree contains the published standalone app bundle. - * Source checkouts should not create `app/` during postinstall because Next.js would - * mis-detect it as a competing App Router root and serve 404s for the real `src/app` routes. + * Detect whether the current install tree contains the published standalone bundle. + * Checks for dist/server.js (Layer 1: renamed from app/server.js). + * Source checkouts will not have dist/ so postinstall skips platform-specific + * native repairs (which only apply to the shipped pre-built bundle). * * @param {string} rootDir * @returns {boolean} */ export function hasStandaloneAppBundle(rootDir) { - return existsSync(join(rootDir, "app", "server.js")); + return existsSync(join(rootDir, "dist", "server.js")); } /** diff --git a/scripts/build/prepublish.ts b/scripts/build/prepublish.ts index f8792cacde..7b81c0417a 100644 --- a/scripts/build/prepublish.ts +++ b/scripts/build/prepublish.ts @@ -4,7 +4,7 @@ * OmniRoute โ€” Prepublish Build Script * * Consumes the .build/next/standalone artifact produced by `npm run build` - * (build-next-isolated.mjs) and assembles the npm staging `app/` directory. + * (build-next-isolated.mjs) and assembles the npm staging `dist/` directory. * Does NOT run a second `next build` โ€” the caller must run `npm run build` first, * or this script will invoke it exactly once if the artifact is absent. * @@ -39,7 +39,7 @@ const __dirname = dirname(__filename); const ROOT = join(__dirname, "..", ".."); const NPX_BIN = process.platform === "win32" ? "npx.cmd" : "npx"; -const APP_DIR = join(ROOT, "app"); +const DIST_DIR = join(ROOT, "dist"); function walkFiles(dir: string, rootDir: string = dir, files: string[] = []): string[] { let entries: string[] = []; @@ -110,11 +110,10 @@ function removeEmptyDirectories(dir: string): boolean { console.log("๐Ÿ”จ OmniRoute โ€” Building for npm publish...\n"); -// โ”€โ”€ Step 1: Clean previous app/ directory โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// KEEP for now (deleted in Layer 1 rename hack removal). -if (existsSync(APP_DIR)) { - console.log(" ๐Ÿงน Cleaning previous app/ directory..."); - rmSync(APP_DIR, { recursive: true, force: true }); +// โ”€โ”€ Step 1: Clean previous dist/ directory โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +if (existsSync(DIST_DIR)) { + console.log(" ๐Ÿงน Cleaning previous dist/ directory..."); + rmSync(DIST_DIR, { recursive: true, force: true }); } // โ”€โ”€ Step 2: Assert / trigger the Next.js standalone build โ”€โ”€ @@ -137,33 +136,23 @@ if (!existsSync(standaloneServerJs)) { } console.log(" โœ… Standalone artifact present:", standaloneServerJs); -// โ”€โ”€ Step 2.5: Remove app/ before assembly โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// CRITICAL: The postinstall script may create app/node_modules/@swc/helpers/, -// which causes Next.js 16 to interpret app/ as an App Router directory -// (competing with src/app/). We keep this guard in case postinstall re-runs -// between the clean above and here. (Removed in Layer 1.) -if (existsSync(APP_DIR)) { - console.log(" ๐Ÿงน Removing app/ created by postinstall (App Router conflict fix)..."); - rmSync(APP_DIR, { recursive: true, force: true }); -} - -// โ”€โ”€ Step 3โ€“7: Assemble standalone into app/ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// โ”€โ”€ Step 3โ€“7: Assemble standalone into dist/ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // All shared copy/sync/sanitize/chunk-patch operations are delegated to // assembleStandalone. npm-UNIQUE steps (MITM, MCP, CLI, sidecars) follow. -console.log(" ๐Ÿ“‹ Assembling standalone bundle into app/..."); +console.log(" ๐Ÿ“‹ Assembling standalone bundle into dist/..."); assembleStandalone({ distDir: join(ROOT, NEXT_DIST), - outDir: APP_DIR, + outDir: DIST_DIR, projectRoot: ROOT, sanitizePaths: true, patchTurbopackChunks: true, copyNatives: true, }); -console.log(" โœ… Standalone bundle assembled to app/"); +console.log(" โœ… Standalone bundle assembled to dist/"); // โ”€โ”€ Step 8: Compile + copy MITM cert utilities โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const mitmSrc = join(ROOT, "src", "mitm"); -const mitmDest = join(APP_DIR, "src", "mitm"); +const mitmDest = join(DIST_DIR, "src", "mitm"); if (existsSync(mitmSrc)) { console.log(" ๐Ÿ”จ Compiling MITM utilities (TypeScript โ†’ JavaScript)..."); mkdirSync(mitmDest, { recursive: true }); @@ -206,7 +195,7 @@ if (existsSync(mitmSrc)) { if (existsSync(mitmServerSrc)) { cpSync(mitmServerSrc, join(mitmDest, "server.cjs")); } - console.log(" โœ… MITM utilities compiled to app/src/mitm/"); + console.log(" โœ… MITM utilities compiled to dist/src/mitm/"); } catch (err: any) { console.warn(" โš ๏ธ MITM compile warning (non-fatal):", err.message); // Fallback: copy source files so at least they are present @@ -221,7 +210,7 @@ if (existsSync(mitmSrc)) { // โ”€โ”€ Step 8.5: Bundle MCP server โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const mcpSrcFile = join(ROOT, "open-sse", "mcp-server", "server.ts"); -const mcpDestDir = join(APP_DIR, "open-sse", "mcp-server"); +const mcpDestDir = join(DIST_DIR, "open-sse", "mcp-server"); const mcpDestFile = join(mcpDestDir, "server.js"); if (existsSync(mcpSrcFile)) { @@ -237,11 +226,11 @@ if (existsSync(mcpSrcFile)) { "--platform=node", "--packages=external", "--format=esm", - "--outfile=app/open-sse/mcp-server/server.js", + "--outfile=dist/open-sse/mcp-server/server.js", ], { cwd: ROOT, stdio: "inherit" } ); - console.log(" โœ… MCP Server bundled to app/open-sse/mcp-server/server.js"); + console.log(" โœ… MCP Server bundled to dist/open-sse/mcp-server/server.js"); } catch (err: any) { console.warn(" โš ๏ธ MCP Server bundle error:", err.message); } @@ -276,7 +265,7 @@ if (existsSync(cliSrcFile)) { // โ”€โ”€ Step 9: Copy shared utilities needed at runtime โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const sharedApiKey = join(ROOT, "src", "shared", "utils", "apiKey.js"); -const sharedApiKeyDest = join(APP_DIR, "src", "shared", "utils"); +const sharedApiKeyDest = join(DIST_DIR, "src", "shared", "utils"); if (existsSync(sharedApiKey)) { console.log(" ๐Ÿ“‹ Copying shared utilities..."); mkdirSync(sharedApiKeyDest, { recursive: true }); @@ -286,19 +275,19 @@ if (existsSync(sharedApiKey)) { // โ”€โ”€ Step 9.5: Copy minimal runtime sidecars required outside .next โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const envExampleSrc = join(ROOT, ".env.example"); if (existsSync(envExampleSrc)) { - cpSync(envExampleSrc, join(APP_DIR, ".env.example")); + cpSync(envExampleSrc, join(DIST_DIR, ".env.example")); } const openapiSpecSrc = join(ROOT, "docs", "openapi.yaml"); if (existsSync(openapiSpecSrc)) { - const docsDest = join(APP_DIR, "docs"); + const docsDest = join(DIST_DIR, "docs"); mkdirSync(docsDest, { recursive: true }); cpSync(openapiSpecSrc, join(docsDest, "openapi.yaml")); } const docsMarkdownSrc = join(ROOT, "docs"); if (existsSync(docsMarkdownSrc)) { - const docsDest = join(APP_DIR, "docs"); + const docsDest = join(DIST_DIR, "docs"); mkdirSync(docsDest, { recursive: true }); const mdFiles = readdirSync(docsMarkdownSrc).filter( (f) => f.endsWith(".md") || f.endsWith(".mdx") @@ -313,26 +302,26 @@ if (existsSync(docsMarkdownSrc)) { const syncEnvSrc = join(ROOT, "scripts", "sync-env.mjs"); if (existsSync(syncEnvSrc)) { - const scriptsDest = join(APP_DIR, "scripts"); + const scriptsDest = join(DIST_DIR, "scripts"); mkdirSync(scriptsDest, { recursive: true }); cpSync(syncEnvSrc, join(scriptsDest, "sync-env.mjs")); } const migrationsSrc = join(ROOT, "src", "lib", "db", "migrations"); if (existsSync(migrationsSrc)) { - const migrationsDest = join(APP_DIR, "src", "lib", "db", "migrations"); - mkdirSync(join(APP_DIR, "src", "lib", "db"), { recursive: true }); + const migrationsDest = join(DIST_DIR, "src", "lib", "db", "migrations"); + mkdirSync(join(DIST_DIR, "src", "lib", "db"), { recursive: true }); cpSync(migrationsSrc, migrationsDest, { recursive: true, force: true }); } const runtimeAssetDirs = [ { source: join(ROOT, "open-sse", "services", "compression", "engines", "rtk", "filters"), - destination: join(APP_DIR, "open-sse", "services", "compression", "engines", "rtk", "filters"), + destination: join(DIST_DIR, "open-sse", "services", "compression", "engines", "rtk", "filters"), }, { source: join(ROOT, "open-sse", "services", "compression", "rules"), - destination: join(APP_DIR, "open-sse", "services", "compression", "rules"), + destination: join(DIST_DIR, "open-sse", "services", "compression", "rules"), }, ]; for (const assetDir of runtimeAssetDirs) { @@ -343,66 +332,66 @@ for (const assetDir of runtimeAssetDirs) { } // โ”€โ”€ Step 10: Ensure data/ directory exists โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -mkdirSync(join(APP_DIR, "data"), { recursive: true }); +mkdirSync(join(DIST_DIR, "data"), { recursive: true }); // โ”€โ”€ Step 10.5: Copy @swc/helpers into standalone โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -// Next.js standalone tracer sometimes omits @swc/helpers from app/node_modules/, +// Next.js standalone tracer sometimes omits @swc/helpers from dist/node_modules/, // causing MODULE_NOT_FOUND at runtime. Always copy it explicitly. const swcHelpersSrc = join(ROOT, "node_modules", "@swc", "helpers"); -const swcHelpersDst = join(APP_DIR, "node_modules", "@swc", "helpers"); +const swcHelpersDst = join(DIST_DIR, "node_modules", "@swc", "helpers"); if (existsSync(swcHelpersSrc) && !existsSync(swcHelpersDst)) { - console.log(" ๐Ÿ“‹ Copying @swc/helpers to standalone app/node_modules..."); - mkdirSync(join(APP_DIR, "node_modules", "@swc"), { recursive: true }); + console.log(" ๐Ÿ“‹ Copying @swc/helpers to standalone dist/node_modules..."); + mkdirSync(join(DIST_DIR, "node_modules", "@swc"), { recursive: true }); cpSync(swcHelpersSrc, swcHelpersDst, { recursive: true }); console.log(" โœ… @swc/helpers included in standalone build."); } -// โ”€โ”€ Step 10.6: Remove development-only residue from staged app/ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// โ”€โ”€ Step 10.6: Remove development-only residue from staged dist/ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ for (const relativePath of APP_STAGING_REMOVAL_PATHS) { - const targetPath = join(APP_DIR, relativePath); + const targetPath = join(DIST_DIR, relativePath); if (existsSync(targetPath)) { - console.log(` ๐Ÿงน Removing app/${relativePath} (not needed in npm package)...`); + console.log(` ๐Ÿงน Removing dist/${relativePath} (not needed in npm package)...`); rmSync(targetPath, { recursive: true, force: true }); - console.log(` โœ… app/${relativePath} removed.`); + console.log(` โœ… dist/${relativePath} removed.`); } } -// โ”€โ”€ Step 10.7: Prune any staged app/ file outside the allowed runtime set โ”€โ”€โ”€ -const stagedFiles = walkFiles(APP_DIR); +// โ”€โ”€ Step 10.7: Prune any staged dist/ file outside the allowed runtime set โ”€โ”€ +const stagedFiles = walkFiles(DIST_DIR); const unexpectedStagedFiles = findUnexpectedArtifactPaths(stagedFiles, { exactPaths: APP_STAGING_ALLOWED_EXACT_PATHS, prefixPaths: APP_STAGING_ALLOWED_PATH_PREFIXES, }); if (unexpectedStagedFiles.length > 0) { - console.log(" ๐Ÿงน Pruning unexpected files from staged app/..."); + console.log(" ๐Ÿงน Pruning unexpected files from staged dist/..."); unexpectedStagedFiles.forEach((unexpectedPath: string) => { - rmSync(join(APP_DIR, unexpectedPath), { force: true }); - console.log(` โœ… Removed app/${unexpectedPath}`); + rmSync(join(DIST_DIR, unexpectedPath), { force: true }); + console.log(` โœ… Removed dist/${unexpectedPath}`); }); - removeEmptyDirectories(APP_DIR); + removeEmptyDirectories(DIST_DIR); } -const remainingUnexpectedFiles = findUnexpectedArtifactPaths(walkFiles(APP_DIR), { +const remainingUnexpectedFiles = findUnexpectedArtifactPaths(walkFiles(DIST_DIR), { exactPaths: APP_STAGING_ALLOWED_EXACT_PATHS, prefixPaths: APP_STAGING_ALLOWED_PATH_PREFIXES, }); if (remainingUnexpectedFiles.length > 0) { - console.error("\n โŒ Staged app/ still contains unexpected publish artifacts:"); - remainingUnexpectedFiles.forEach((violation: string) => console.error(` - app/${violation}`)); + console.error("\n โŒ Staged dist/ still contains unexpected publish artifacts:"); + remainingUnexpectedFiles.forEach((violation: string) => console.error(` - dist/${violation}`)); process.exit(1); } // โ”€โ”€ Done โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -const appPkg = join(APP_DIR, "package.json"); -if (existsSync(appPkg)) { - const pkg = JSON.parse(readFileSync(appPkg, "utf8")); +const distPkg = join(DIST_DIR, "package.json"); +if (existsSync(distPkg)) { + JSON.parse(readFileSync(distPkg, "utf8")); console.log(`\n โœ… Build complete!`); - console.log(` App directory: app/`); - console.log(` Server entry: app/server.js`); + console.log(` Dist directory: dist/`); + console.log(` Server entry: dist/server.js`); } else { - console.log(`\n โœ… Build complete! (app/ ready for publish)`); + console.log(`\n โœ… Build complete! (dist/ ready for publish)`); } console.log(""); diff --git a/scripts/build/validate-pack-artifact.ts b/scripts/build/validate-pack-artifact.ts index e208c4b6eb..95a97c55db 100644 --- a/scripts/build/validate-pack-artifact.ts +++ b/scripts/build/validate-pack-artifact.ts @@ -30,12 +30,12 @@ function runNpm(args: string[], stdio: "inherit" | "pipe" = "pipe"): string { function ensureAppStagingReady(): void { const missingAppRequiredPaths = PACK_ARTIFACT_REQUIRED_PATHS.filter((requiredPath) => - requiredPath.startsWith("app/") + requiredPath.startsWith("dist/") ).filter((requiredPath) => !existsSync(join(ROOT, requiredPath))); if (missingAppRequiredPaths.length === 0) return; - console.log("๐Ÿ“ฆ app/ staging is missing required runtime files; running npm run build:cli..."); + console.log("๐Ÿ“ฆ dist/ staging is missing required runtime files; running npm run build:cli..."); runNpm(["run", "build:cli"], "inherit"); }