TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1import type { NextConfig } from "next";23const isProd = process.env.NODE_ENV === "production";45/**6 * Content-Security-Policy. Inline styles are required by Tailwind's runtime-free7 * output only for a few third-party components (Radix measures via style attrs),8 * and Next.js injects inline scripts for hydration; nonces are not used because the9 * app is fully static-shell + client-fetch and `next start` runs behind ngrok.10 */11const csp = [12 "default-src 'self'",13 "base-uri 'self'",14 "frame-ancestors 'none'",15 "form-action 'self'",16 "object-src 'none'",17 "img-src 'self' data: blob: https:",18 "font-src 'self' data:",19 "style-src 'self' 'unsafe-inline'",20 isProd ? "script-src 'self' 'unsafe-inline'" : "script-src 'self' 'unsafe-inline' 'unsafe-eval'",21 "connect-src 'self'",22 "worker-src 'self' blob:",23 "upgrade-insecure-requests",24].join("; ");2526const nextConfig: NextConfig = {27 reactStrictMode: true,28 poweredByHeader: false,29 agentRules: false,30 serverExternalPackages: ["pg", "argon2", "resend", "@anthropic-ai/sdk", "openai", "@google/genai", "shiki"],31 experimental: {32 serverActions: { bodySizeLimit: "2mb" },33 },34 async headers() {35 return [36 {37 source: "/(.*)",38 headers: [39 { key: "X-Content-Type-Options", value: "nosniff" },40 { key: "X-Frame-Options", value: "DENY" },41 { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },42 { key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=(), payment=()" },43 { key: "Content-Security-Policy", value: csp },44 ...(isProd ? [{ key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" }] : []),45 ],46 },47 ];48 },49};5051export default nextConfig;52