`open` derives its own directory from import.meta.url at module scope. Webpack replaces that with the build machine's absolute path as a string literal, so a release built on macOS ships a file:///Users/... URL that fileURLToPath rejects on Windows (no drive letter), throwing on import. refreshXaiToken dynamic-imports the xAI OAuth service, which imports open eagerly, so every Grok token refresh silently failed and was swallowed by a catch that only logs a warning. Add open to serverExternalPackages so it keeps its real import.meta.url at runtime, and bundle it into the CLI package via ensureModuleInBundle (same guard already used for sql.js) since externalizing it means webpack no longer traces/copies it automatically.
99 lines
3.2 KiB
JavaScript
99 lines
3.2 KiB
JavaScript
import { fileURLToPath } from "node:url";
|
|
import { dirname, join } from "node:path";
|
|
|
|
const projectRoot = dirname(fileURLToPath(import.meta.url));
|
|
// CLI bundling needs workspace root so tracing includes hoisted node_modules (slim ~50MB).
|
|
// Docker / default uses projectRoot so server.js lands at /app/server.js (not nested).
|
|
const tracingRoot = process.env.NEXT_TRACING_ROOT_MODE === "workspace"
|
|
? join(projectRoot, "..")
|
|
: projectRoot;
|
|
const proxyClientMaxBodySize = process.env.NINEROUTER_PROXY_CLIENT_MAX_BODY_SIZE || "128mb";
|
|
|
|
/** @type {import('next').NextConfig} */
|
|
const nextConfig = {
|
|
distDir: process.env.NEXT_DIST_DIR || ".next",
|
|
output: "standalone",
|
|
// `open` must stay external. It derives its own directory from `import.meta.url`, and
|
|
// webpack replaces that with the absolute path of the BUILD machine as a string literal.
|
|
// A release built on macOS therefore ships `file:///Users/.../open/index.js`, which
|
|
// `fileURLToPath` rejects on Windows ("File URL path must be absolute" — no drive
|
|
// letter). That throw happens at module scope, so every consumer of `open` dies on
|
|
// import — including xAI/Grok token refresh, which loads the OAuth service that imports
|
|
// it. Keeping it external preserves the real `import.meta.url` at runtime.
|
|
serverExternalPackages: ["better-sqlite3", "sql.js", "node:sqlite", "bun:sqlite", "open"],
|
|
turbopack: {
|
|
root: tracingRoot
|
|
},
|
|
outputFileTracingRoot: tracingRoot,
|
|
outputFileTracingExcludes: {
|
|
"*": ["./gitbook/**/*"]
|
|
},
|
|
images: {
|
|
unoptimized: true
|
|
},
|
|
env: {},
|
|
experimental: {
|
|
// #1529/#1572: LLM clients can send long context or base64 image payloads through /v1 rewrites.
|
|
proxyClientMaxBodySize,
|
|
// Cache fetch responses across HMR refreshes for faster dev reloads.
|
|
serverComponentsHmrCache: true,
|
|
// Tree-shake heavy barrel imports to cut compile + bundle size
|
|
optimizePackageImports: ["@xyflow/react", "@dnd-kit/core", "@dnd-kit/sortable", "material-symbols", "marked"],
|
|
},
|
|
webpack: (config, { isServer }) => {
|
|
// Ignore fs/path modules in browser bundle
|
|
if (!isServer) {
|
|
config.resolve.fallback = {
|
|
...config.resolve.fallback,
|
|
fs: false,
|
|
path: false,
|
|
};
|
|
}
|
|
// Exclude non-source dirs from watcher to reduce inotify load
|
|
config.watchOptions = {
|
|
...config.watchOptions,
|
|
aggregateTimeout: 300,
|
|
ignored: /[\\/](node_modules|\.git|logs|\.next|\.next-cli-build|gitbook|cli|open-sse\.old|tests|docs)[\\/]/,
|
|
};
|
|
return config;
|
|
},
|
|
async rewrites() {
|
|
return [
|
|
{
|
|
source: "/v1/v1/:path*",
|
|
destination: "/api/v1/:path*"
|
|
},
|
|
{
|
|
source: "/v1/v1",
|
|
destination: "/api/v1"
|
|
},
|
|
{
|
|
source: "/codex/:path*",
|
|
destination: "/api/v1/responses"
|
|
},
|
|
{
|
|
source: "/responses",
|
|
destination: "/api/v1/responses"
|
|
},
|
|
{
|
|
source: "/v1beta/:path*",
|
|
destination: "/api/v1beta/:path*"
|
|
},
|
|
{
|
|
source: "/v1beta",
|
|
destination: "/api/v1beta"
|
|
},
|
|
{
|
|
source: "/v1/:path*",
|
|
destination: "/api/v1/:path*"
|
|
},
|
|
{
|
|
source: "/v1",
|
|
destination: "/api/v1"
|
|
}
|
|
];
|
|
}
|
|
};
|
|
|
|
export default nextConfig;
|