44 lines
1.4 KiB
TypeScript
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, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
}
|
|
|
|
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' } });
|
|
}
|