import { getDb } from "@/lib/mongo"; import { getSiteUrl } from "@/lib/site"; export const dynamic = "force-dynamic"; function escapeXml(input: string) { return input .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function stripMarkdown(input: string) { return input .replace(/```[\s\S]*?```/g, " ") .replace(/`[^`]*`/g, " ") .replace(/!\[[^\]]*]\([^)]+\)/g, " ") .replace(/\[([^\]]*)\]\([^)]+\)/g, "$1") .replace(/[#>*_~\-]+/g, " ") .replace(/\s+/g, " ") .trim(); } export async function GET() { const db = await getDb(); const posts = await db .collection("posts") .find({}, { projection: { title: 1, slug: 1, markdown: 1, createdAt: 1, updatedAt: 1 } }) .sort({ createdAt: -1 }) .limit(50) .toArray(); const siteUrl = getSiteUrl(); const now = new Date().toUTCString(); const items = posts .map((post: any) => { const link = `${siteUrl}/p/${post.slug}`; const description = stripMarkdown(post.markdown || "").slice(0, 200); const pubDate = new Date(post.createdAt || post.updatedAt || Date.now()).toUTCString(); return [ "", `${escapeXml(post.title || "未命名")}`, `${escapeXml(link)}`, `${escapeXml(link)}`, `${pubDate}`, `${escapeXml(description)}`, "" ].join(""); }) .join(""); const xml = ` OPC Feed ${escapeXml(siteUrl)} Public feed ${now} ${items} `; return new Response(xml, { headers: { "Content-Type": "application/rss+xml; charset=utf-8" } }); }