templates2.Content.Next/app/rss.xml/route.ts
w4c-templates 3caefb8833
Some checks are pending
CI / quality (push) Waiting to run
chore(template): publish Content.Next
2026-10-11 23:29:57 +03:00

44 lines
1.4 KiB
TypeScript

import { db } from '@/lib/server/db';
export const dynamic = 'force-dynamic';
function escapeXml(s: string): string {
return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
export async function GET() {
const base = (process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000').replace(/\/$/, '');
let posts: { slug: string; title: string; excerpt: string; publishedAt: Date | null }[] = [];
try {
posts = await db.post.findMany({
where: { status: 'published' },
select: { slug: true, title: true, excerpt: true, publishedAt: true },
orderBy: { publishedAt: 'desc' },
take: 50,
});
} catch {
posts = [];
}
const items = posts
.map(
(p) => ` <item>
<title>${escapeXml(p.title)}</title>
<link>${base}/blog/${p.slug}</link>
<guid>${base}/blog/${p.slug}</guid>
<pubDate>${(p.publishedAt ?? new Date()).toUTCString()}</pubDate>
<description>${escapeXml(p.excerpt)}</description>
</item>`,
)
.join('\n');
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"><channel>
<title>Acme Blog</title>
<link>${base}/blog</link>
<description>Notes, guides and product updates.</description>
${items}
</channel></rss>`;
return new Response(xml, { headers: { 'content-type': 'application/rss+xml; charset=utf-8' } });
}