import { withPayload } from "@payloadcms/next/withPayload"; import path from "node:path"; import { fileURLToPath } from "node:url"; import packageJson from "./package.json" with { type: "json" }; /** @type {import('next').NextConfig} */ const nextConfig = { // Your Next.js config here env: { version: packageJson.version, }, // Minigame routes moved under /minigames/* (source + URLs). Keep old URLs // working for bookmarks and stale links; temporary (307/308) so they stay // easy to change during active development. Next 16 requires `permanent` // to be set explicitly on every entry. async redirects() { return [ { source: "/qualification", destination: "/minigames/qualification", permanent: false }, { source: "/radio", destination: "/minigames/radio", permanent: false }, { source: "/radio/custom", destination: "/minigames/radio/custom", permanent: false }, { source: "/radio/custom/:id", destination: "/minigames/radio/custom/:id", permanent: false }, { source: "/eod", destination: "/minigames/eod", permanent: false }, { source: "/eod/custom", destination: "/minigames/eod/custom", permanent: false }, { source: "/eod/custom/:id", destination: "/minigames/eod/custom/:id", permanent: false }, { source: "/flappy", destination: "/minigames/flappy", permanent: false }, { source: "/opord", destination: "/minigames/opord", permanent: false }, ]; }, // Server Actions default to a 1 MB request body limit, which would reject // most image uploads. Bump it so wiki image uploads (capped at 8 MB in the // uploadWikiImage action) pass through with room for multipart overhead. // Next 16 keeps serverActions under `experimental` — a top-level key is not // recognized ("Unrecognized key(s) in object: 'serverActions'"). experimental: { serverActions: { bodySizeLimit: "10mb", }, }, // Pin the workspace root to this repo dir so the standalone build emits a // flat .next/standalone/server.js (Next otherwise walks up looking for // lockfiles and can pick a parent directory — here a stray // /home/jason/package-lock.json two levels up would nest the standalone // tree under .next/standalone/WebstormProjects/polaris-task-force/, which // breaks the Dockerfile's `COPY .../standalone ./` + `CMD ["node","server.js"]`). outputFileTracingRoot: path.resolve(path.dirname(fileURLToPath(import.meta.url))), webpack: (webpackConfig, { isServer }) => { webpackConfig.resolve.extensionAlias = { ".cjs": [".cts", ".cjs"], ".js": [".ts", ".tsx", ".js", ".jsx"], ".mjs": [".mts", ".mjs"], }; // @ai-stack/payloadcms client components (Compose -> setSafeLexicalState -> // lexicalToHTML) import the *server* entry of @payloadcms/richtext-lexical, which // transitively pulls in `payload` and all Node built-ins (node:fs, node:crypto, // child_process, worker_threads, ...). The client only needs two pure string // constants (BLOCK_PLACEHOLDER_PREFIX/SUFFIX) from lexicalToHTML; the server-only // convertLexicalToHTML is never invoked client-side. Stub the bare server entry in // the client bundle so the transitive import chain breaks. The `$` makes it an // exact-match alias, leaving the legitimate `@payloadcms/richtext-lexical/client` // subpath and the server bundle unaffected. if (!isServer) { webpackConfig.resolve.alias = { ...webpackConfig.resolve.alias, "@payloadcms/richtext-lexical$": false, }; } return webpackConfig; }, transpilePackages: [ "@payloadcms/richtext-lexical", "lexical", "@lexical/react", "@lexical/rich-text", "@lexical/history", "@lexical/list", "@lexical/link", "@lexical/markdown", "@lexical/selection", "@lexical/table", "@lexical/utils", ], output: "standalone", }; export default withPayload(nextConfig, { devBundleServerPackages: true });