/* * A second sitemap for the URLs Next owns. * * /sitemap.xml is proxied from FastAPI (app/(frontend)/sitemap.xml), which * knows nothing about Payload — the backend and frontend ship as separate * images. Rather than teach it, the Next-owned URLs get their own sitemap and * robots.txt lists both. */ import { getCachedPayload } from '@/lib/payload'; import { absoluteUrl } from '@/lib/site'; import { getFlags } from '@/lib/flags'; /* * Dynamic, not ISR. * * This route has no dynamic params, so Next prerenders it at build time — and * CI builds the image with no database reachable, which fails the build. It is * a single indexed query against Postgres on the same Docker network, so * rendering per request is cheap, and it means a newly published post appears * here immediately rather than waiting on a revalidation. */ export const dynamic = 'force-dynamic'; export async function GET() { /* * A dark page must not be advertised. Submitting a URL that 404s is the one * thing a sitemap is not allowed to do, so each entry is gated on the same * flag that gates the page itself. * * With both flags dark this emits a valid, empty rather than a 404: * robots.txt names this sitemap unconditionally, and an empty sitemap is a * well-formed statement that there is nothing here yet. */ const flags = await getFlags(); const aboutEnabled = flags.about_page === true; const blogEnabled = flags.blog === true; // Only query Payload when the blog is actually being advertised. const docs = blogEnabled ? (await (await getCachedPayload()).find({ collection: 'posts', where: { _status: { equals: 'published' } }, sort: '-publishedAt', limit: 500, depth: 0, })).docs : []; const urls: Array<{ loc: string; lastmod: string | null }> = [ ...(aboutEnabled ? [{ loc: absoluteUrl('/about'), lastmod: null }] : []), ...(blogEnabled ? [{ loc: absoluteUrl('/blog'), lastmod: null }] : []), ...docs.map((post) => ({ loc: absoluteUrl(`/blog/${post.slug}`), lastmod: new Date(String(post.updatedAt ?? post.publishedAt)).toISOString(), })), ]; const xml = ` ${urls.map(({ loc, lastmod }) => ` ${loc}${lastmod ? `${lastmod}` : ''}`, ).join('\n')} `; return new Response(xml, { headers: { 'Content-Type': 'application/xml; charset=utf-8' }, }); }