Files
claudemesh/apps/web/next.config.ts
Alejandro Gutiérrez 9cefe863e3
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled
fix(web): fully remove withPayload + admin routes from prod
withPayload crashes ALL routes with React #130 in standalone
output — even with admin page replaced by redirect. The wrapper
injects a client-side ConfigProvider that fails hydration.

Removed: withPayload wrapper, entire (payload) route group.
Kept: payload.config.ts, migrations, blog/changelog server-side
queries with graceful DB fallback.

Payload admin runs on local dev only (add withPayload back in
next.config when running pnpm dev). Production content via
static TSX pages or future API-based publishing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 02:30:26 +01:00

119 lines
3.0 KiB
TypeScript

import type { NextConfig } from "next";
import env from "./env.config";
const INTERNAL_PACKAGES = [
"@turbostarter/analytics-web",
"@turbostarter/api",
"@turbostarter/auth",
"@turbostarter/billing",
"@turbostarter/cms",
"@turbostarter/email",
"@turbostarter/db",
"@turbostarter/i18n",
"@turbostarter/monitoring-web",
"@turbostarter/shared",
"@turbostarter/storage",
"@turbostarter/ui",
"@turbostarter/ui-web",
];
// Security headers for production
const securityHeaders = [
{
key: "X-DNS-Prefetch-Control",
value: "on",
},
{
key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubDomains; preload",
},
{
key: "X-Frame-Options",
value: "SAMEORIGIN",
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "X-XSS-Protection",
value: "1; mode=block",
},
{
key: "Referrer-Policy",
value: "strict-origin-when-cross-origin",
},
{
key: "Permissions-Policy",
value: "camera=(), microphone=(), geolocation=(), interest-cohort=()",
},
// Content-Security-Policy - configured for development flexibility
// In production, tighten 'unsafe-inline' and 'unsafe-eval' as needed
{
key: "Content-Security-Policy",
value: [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.stripe.com https://challenges.cloudflare.com",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: blob: https: http:",
"font-src 'self' data:",
"connect-src 'self' https://api.stripe.com https://*.sentry.io wss:",
"frame-src 'self' https://js.stripe.com https://hooks.stripe.com https://challenges.cloudflare.com",
"object-src 'none'",
"base-uri 'self'",
"form-action 'self'",
"frame-ancestors 'self'",
"upgrade-insecure-requests",
].join("; "),
},
];
const config: NextConfig = {
reactStrictMode: true,
output: "standalone",
// TEMPORARY: Hono RPC + TanStack Query type inference whack-a-mole blocking production deploy.
// Ship now, fix types post-launch as dedicated tech-debt sprint.
typescript: {
ignoreBuildErrors: true,
},
serverExternalPackages: [
"better-sqlite3",
"@mapbox/node-pre-gyp",
],
images: {
remotePatterns: [
{
hostname: "images.unsplash.com",
},
],
},
/** Enables hot reloading for local packages without a build step */
transpilePackages: INTERNAL_PACKAGES,
experimental: {
optimizePackageImports: INTERNAL_PACKAGES,
},
// Apply security headers only in production
// CSP with upgrade-insecure-requests breaks Next.js client-side navigation in dev
async headers() {
if (process.env.NODE_ENV !== "production") {
return [];
}
return [
{
// Apply to all routes
source: "/:path*",
headers: securityHeaders,
},
];
},
};
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: env.ANALYZE,
});
export default withBundleAnalyzer(config);