import type { NextConfig } from 'next'; const nextConfig: NextConfig = { // Standalone output keeps the production image small: only the traced // dependencies ship, not the whole node_modules tree. output: 'standalone', reactStrictMode: true, // Next writes its own AGENTS.md/CLAUDE.md otherwise; this project documents // itself in README.md and PLAN.md. agentRules: false, // The panel's HTTP client does not follow redirects: it reports any non-2xx // as "returned code is not OK" and gives up. The firmware asks for // /api/setup/ with a trailing slash, which Next would answer with a 308 — // so the device never obtained a token, then failed /api/display with an // empty one, and reported that it could not reach the API at all. // // Serving both spellings is the fix. The redirect is disabled and the // slashed paths are rewritten, rather than the device being asked to behave // differently: it cannot. skipTrailingSlashRedirect: true, async rewrites() { return [ { source: '/api/setup/', destination: '/api/setup' }, { source: '/api/display/', destination: '/api/display' }, { source: '/api/log/', destination: '/api/log' }, { source: '/api/health/', destination: '/api/health' }, // Admin pages keep working when someone types the slash by hand, which // Next would otherwise have redirected for us. { source: '/admin/', destination: '/admin' }, ]; }, // These must be required from node_modules at runtime, not bundled. // satori loads harfbuzz and yoga as WebAssembly by relative path; bundling // rewrites that path and the renderer dies with a missing hb.wasm. resvg is // a native addon, and node-cron is started from instrumentation.ts. serverExternalPackages: [ 'satori', 'yoga-wasm-web', 'harfbuzzjs', '@resvg/resvg-js', 'node-cron', ], }; export default nextConfig;