import path from "path"; import type { NextConfig } from "next"; const nextConfig: NextConfig = { distDir: process.env.NEXT_DIST_DIR ?? ".next", output: "standalone", outputFileTracingRoot: path.resolve(__dirname, "../.."), devIndicators: false, experimental: { optimizePackageImports: ["recharts", "date-fns", "framer-motion", "@capakraken/shared"], }, transpilePackages: [ "@capakraken/api", "@capakraken/db", "@capakraken/engine", "@capakraken/shared", "@capakraken/staffing", ], typedRoutes: true, async redirects() { return [ // Common URL alias — redirect to the real auth entry point { source: "/login", destination: "/auth/signin", permanent: true }, // Common shorthand — redirect to the admin blueprints management page { source: "/blueprints", destination: "/admin/blueprints", permanent: true }, ]; }, async headers() { return [ { source: "/(.*)", headers: [ { 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=()" }, { key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" }, // Content-Security-Policy is set per-request by middleware.ts (nonce-based). // Static CSP here would conflict and cannot carry per-request nonces. { key: "X-XSS-Protection", value: "0" }, ], }, { source: "/auth/:path*", headers: [ { key: "Cache-Control", value: "no-store, no-cache, must-revalidate" }, { key: "Pragma", value: "no-cache" }, ], }, { source: "/api/:path*", headers: [ { key: "Cache-Control", value: "no-store" }, { key: "X-Content-Type-Options", value: "nosniff" }, ], }, { // Catch-all for error pages and any remaining routes source: "/:path*", headers: [ { key: "Cache-Control", value: "no-store, no-cache, must-revalidate" }, { key: "Pragma", value: "no-cache" }, ], }, ]; }, // Webpack config (used by `next build` and `next dev` without --turbo) webpack(config) { config.resolve.alias = { ...config.resolve.alias, "~": path.resolve(__dirname, "src"), }; // Resolve .js imports to .ts/.tsx (TypeScript ESM convention) config.resolve.extensionAlias = { ...config.resolve.extensionAlias, ".js": [".ts", ".tsx", ".js"], ".jsx": [".tsx", ".jsx"], }; return config; }, }; // Only wrap with Sentry in production — the worker.js crash in dev mode // (vendor-chunks/lib/worker.js MODULE_NOT_FOUND) makes the dev server unstable // Sentry only in production — dynamic import avoids side effects in dev let exportedConfig: NextConfig = nextConfig; if (process.env.NODE_ENV === "production") { try { const { withSentryConfig } = require("@sentry/nextjs"); exportedConfig = withSentryConfig(nextConfig, { silent: true, sourcemaps: { disable: true }, telemetry: false, }); } catch { // Sentry not available — use raw config } } export default exportedConfig;