Spaces:
Paused
Paused
| import createNextIntlPlugin from "next-intl/plugin"; | |
| import { dirname } from "node:path"; | |
| import { fileURLToPath } from "node:url"; | |
| const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts"); | |
| const distDir = process.env.NEXT_DIST_DIR || ".next"; | |
| const projectRoot = dirname(fileURLToPath(import.meta.url)); | |
| const scriptSrc = | |
| process.env.NODE_ENV === "development" | |
| ? "script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:" | |
| : "script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:"; | |
| const contentSecurityPolicy = [ | |
| "default-src 'self'", | |
| "base-uri 'self'", | |
| "object-src 'none'", | |
| "frame-ancestors 'none'", | |
| "form-action 'self'", | |
| scriptSrc, | |
| "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com", | |
| "font-src 'self' https://fonts.gstatic.com data:", | |
| "img-src 'self' data: blob: https:", | |
| "media-src 'self' data: blob:", | |
| "connect-src 'self' http://localhost:* http://127.0.0.1:* ws://localhost:* ws://127.0.0.1:* https: wss:", | |
| "worker-src 'self' blob:", | |
| "manifest-src 'self'", | |
| ].join("; "); | |
| const securityHeaders = [ | |
| { | |
| key: "Content-Security-Policy", | |
| value: contentSecurityPolicy, | |
| }, | |
| { | |
| key: "X-Frame-Options", | |
| value: "DENY", | |
| }, | |
| { | |
| key: "X-Content-Type-Options", | |
| value: "nosniff", | |
| }, | |
| { | |
| key: "Referrer-Policy", | |
| value: "strict-origin-when-cross-origin", | |
| }, | |
| { | |
| key: "Permissions-Policy", | |
| value: "camera=(), microphone=(), geolocation=(), payment=(), usb=(), serial=()", | |
| }, | |
| { | |
| key: "Strict-Transport-Security", | |
| value: "max-age=63072000; includeSubDomains; preload", | |
| }, | |
| ]; | |
| /** @type {import('next').NextConfig} */ | |
| const nextConfig = { | |
| distDir, | |
| // Turbopack config: redirect native modules to stubs at build time | |
| turbopack: { | |
| root: projectRoot, | |
| resolveAlias: { | |
| // Point mitm/manager to a stub during build (native child_process/fs can't be bundled) | |
| "@/mitm/manager": "./src/mitm/manager.stub.ts", | |
| }, | |
| }, | |
| output: "standalone", | |
| // OmniRoute is a proxy for AI APIs — request bodies routinely include | |
| // multi-MB payloads (vision models, image edits, base64-encoded files, | |
| // long chat histories with embedded images). Next.js's Server Action | |
| // handler intercepts POSTs with multipart/form-data or | |
| // x-www-form-urlencoded content-types and enforces a 1 MB cap that | |
| // surfaces as a 413 with a confusing "Server Actions" hint, even on | |
| // pure route handlers. 50 MB matches what most upstream LLM providers | |
| // accept for image-bearing requests; tune via env if a deployment needs | |
| // more. | |
| experimental: { | |
| serverActions: { | |
| bodySizeLimit: process.env.OMNIROUTE_SERVER_ACTIONS_BODY_LIMIT || "50mb", | |
| }, | |
| }, | |
| outputFileTracingRoot: projectRoot, | |
| outputFileTracingIncludes: { | |
| // Migration SQL and compression rule/filter JSON files are read via fs at | |
| // runtime and are NOT always auto-traced by webpack/turbopack. | |
| "/*": [ | |
| "./src/lib/db/migrations/**/*", | |
| "./open-sse/services/compression/engines/rtk/filters/**/*.json", | |
| "./open-sse/services/compression/rules/**/*.json", | |
| ], | |
| }, | |
| outputFileTracingExcludes: { | |
| // Planning/task docs are not runtime assets and can break standalone copies | |
| // when broad fs/path tracing pulls the whole repository into the NFT graph. | |
| "/*": [ | |
| "./.git/**/*", | |
| "./_tasks/**/*", | |
| "./_references/**/*", | |
| "./_ideia/**/*", | |
| "./_mono_repo/**/*", | |
| "./coverage/**/*", | |
| "./test-results/**/*", | |
| "./playwright-report/**/*", | |
| "./app.__qa_backup/**/*", | |
| "./tests/**/*", | |
| "./logs/**/*", | |
| ], | |
| }, | |
| serverExternalPackages: [ | |
| "pino", | |
| "pino-pretty", | |
| "thread-stream", | |
| "pino-abstract-transport", | |
| "better-sqlite3", | |
| "keytar", | |
| "wreq-js", | |
| "zod", | |
| "tls-client-node", | |
| "koffi", | |
| "tough-cookie", | |
| "@ngrok/ngrok", | |
| "child_process", | |
| "fs", | |
| "path", | |
| "os", | |
| "crypto", | |
| "net", | |
| "tls", | |
| "http", | |
| "https", | |
| "stream", | |
| "buffer", | |
| "util", | |
| "process", | |
| ], | |
| transpilePackages: ["@omniroute/open-sse", "@lobehub/icons"], | |
| allowedDevOrigins: ["localhost", "127.0.0.1", "192.168.*"], | |
| typescript: { | |
| // TODO: Re-enable after fixing all sub-component useTranslations scope issues | |
| ignoreBuildErrors: true, | |
| }, | |
| images: { | |
| unoptimized: true, | |
| }, | |
| async headers() { | |
| return [ | |
| { | |
| source: "/:path*", | |
| headers: securityHeaders, | |
| }, | |
| ]; | |
| }, | |
| async rewrites() { | |
| return [ | |
| { | |
| source: "/chat/completions", | |
| destination: "/api/v1/chat/completions", | |
| }, | |
| { | |
| source: "/responses", | |
| destination: "/api/v1/responses", | |
| }, | |
| { | |
| source: "/responses/:path*", | |
| destination: "/api/v1/responses/:path*", | |
| }, | |
| { | |
| source: "/models", | |
| destination: "/api/v1/models", | |
| }, | |
| { | |
| source: "/v1/v1/:path*", | |
| destination: "/api/v1/:path*", | |
| }, | |
| { | |
| source: "/v1/v1", | |
| destination: "/api/v1", | |
| }, | |
| { | |
| source: "/codex/:path*", | |
| destination: "/api/v1/responses", | |
| }, | |
| { | |
| source: "/v1/:path*", | |
| destination: "/api/v1/:path*", | |
| }, | |
| { | |
| source: "/v1", | |
| destination: "/api/v1", | |
| }, | |
| ]; | |
| }, | |
| }; | |
| export default withNextIntl(nextConfig); | |