import type { NextConfig } from "next"; import createNextIntlPlugin from "next-intl/plugin"; const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts"); /** * Security headers. X-Frame-Options is omitted entirely when DEMO_MODE is * active — in that mode CSP frame-ancestors is the sole frame-embedding gate * (see buildCsp below), and sending both X-Frame-Options and a permissive * frame-ancestors simultaneously is contradictory per the spec. In normal * mode, SAMEORIGIN prevents clickjacking on non-demo deployments. */ const securityHeaders = process.env.DEMO_MODE === "true" ? [ { 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=63072000; includeSubDomains; preload", }, ] : [ { key: "X-Frame-Options", value: "SAMEORIGIN" }, { 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=63072000; includeSubDomains; preload", }, ]; /** * Build the Content-Security-Policy header value. * * When DEMO_MODE=true, the frame-ancestors directive is relaxed to allow * embedding from the origin specified in DEMO_FRAME_ORIGIN (e.g. the * marketing website). This enables the live demo iframe without weakening * security for normal self-hosted deployments. */ function buildCsp(): { key: string; value: string } { const frameAncestors = process.env.DEMO_MODE === "true" && process.env.DEMO_FRAME_ORIGIN ? `frame-ancestors 'self' ${process.env.DEMO_FRAME_ORIGIN}` : "frame-ancestors 'self'"; // React dev mode uses eval() for stack reconstruction. Production never does. const isDev = process.env.NODE_ENV === "development"; // External analytics domains (Plausible, Umami, Matomo, etc.). // Space-separated list in EXTRA_SCRIPT_SRC. Each domain is added to // script-src so the operator's analytics `