import type { NextConfig } from "next"; const nextConfig: NextConfig = { poweredByHeader: false, // 禁用 cacheComponents 以支持 dynamic = "force-dynamic" // cacheComponents: true, // 外部包配置(Next.js 16+) serverExternalPackages: ["sharp"], transpilePackages: ["@sparkjsdev/spark"], // 实验性功能:增加代理请求体大小限制以支持大文件上传(视频等) experimental: { proxyClientMaxBodySize: "500mb", // 代理/中间件请求体限制 }, images: { dangerouslyAllowLocalIP: false, contentDispositionType: "attachment", remotePatterns: [ { hostname: "avatar.vercel.sh", }, { protocol: "https", //https://nextjs.org/docs/messages/next-image-unconfigured-host hostname: "*.public.blob.vercel-storage.com", }, { // 支持 HTTP 协议的 MinIO / S3(本地或内网部署) protocol: "http", hostname: "**", // 允许所有 HTTP 域名(MinIO 等) }, { // 支持 HTTPS 协议的 S3 / MinIO(公网部署) protocol: "https", hostname: "**", // 允许所有 HTTPS 域名 }, ], }, // HTTP 安全头 async headers() { const isDev = process.env.NODE_ENV === "development"; const csp = [ "default-src 'self'", // Next.js App Router/RSC emits inline bootstrap scripts in production. // WebAssembly is required by in-browser 3D decoders (Spark SPZ, KTX2/Basis). `script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'${isDev ? " 'unsafe-eval'" : ""}`, // Next.js 需要 unsafe-inline 用于样式 (CSS-in-JS / Tailwind) "style-src 'self' 'unsafe-inline'", "img-src 'self' data: blob: https: http:", "font-src 'self' data:", // Spark bundles its WASM decoder as a data: URL and initializes it via fetch(). "connect-src 'self' data: https: wss:", "media-src 'self' blob: https:", "frame-src 'self'", "worker-src 'self' blob:", "object-src 'none'", "base-uri 'self'", "form-action 'self'", ].join("; "); return [ { source: "/(.*)", headers: [ { key: "X-Content-Type-Options", value: "nosniff" }, { key: "X-Frame-Options", value: "SAMEORIGIN" }, { key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains; preload", }, { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" }, { key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()", }, { key: "Content-Security-Policy", value: csp }, ], }, // 对需要嵌入的页面放宽 frame 限制 { source: "/worlds/share/:path*", headers: [ { key: "X-Frame-Options", value: "ALLOW-FROM https://www.risesail.com", }, ], }, ]; }, async redirects() { return [ { source: "/favicon.ico", destination: "/api/favicon", permanent: false, }, { source: "/apple-touch-icon.png", destination: "/api/favicon", permanent: false, }, ]; }, }; export default nextConfig;