71 lines
1.9 KiB
TypeScript
71 lines
1.9 KiB
TypeScript
import type { APIRoute } from "astro";
|
|
import { getEmDashCollection } from "emdash";
|
|
|
|
const siteTitle = "My Blog";
|
|
const siteDescription = "A blog about software, design, and the occasional stray thought.";
|
|
|
|
export const GET: APIRoute = async ({ site, url }) => {
|
|
const siteUrl = site?.toString() || url.origin;
|
|
|
|
const { entries: posts } = await getEmDashCollection("posts", {
|
|
orderBy: { published_at: "desc" },
|
|
limit: 20,
|
|
});
|
|
|
|
const items = posts
|
|
.map((post) => {
|
|
if (!post.data.publishedAt) return null;
|
|
const pubDate = post.data.publishedAt.toUTCString();
|
|
|
|
const postUrl = `${siteUrl}/posts/${post.id}`;
|
|
const title = escapeXml(post.data.title || "Untitled");
|
|
const description = escapeXml(post.data.excerpt || "");
|
|
|
|
return ` <item>
|
|
<title>${title}</title>
|
|
<link>${postUrl}</link>
|
|
<guid isPermaLink="true">${postUrl}</guid>
|
|
<pubDate>${pubDate}</pubDate>
|
|
<description>${description}</description>
|
|
</item>`;
|
|
})
|
|
.filter(Boolean)
|
|
.join("\n");
|
|
|
|
const rss = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
<channel>
|
|
<title>${escapeXml(siteTitle)}</title>
|
|
<description>${escapeXml(siteDescription)}</description>
|
|
<link>${siteUrl}</link>
|
|
<atom:link href="${siteUrl}/rss.xml" rel="self" type="application/rss+xml"/>
|
|
<language>en-us</language>
|
|
<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
|
|
${items}
|
|
</channel>
|
|
</rss>`;
|
|
|
|
return new Response(rss, {
|
|
headers: {
|
|
"Content-Type": "application/rss+xml; charset=utf-8",
|
|
"Cache-Control": "public, max-age=3600",
|
|
},
|
|
});
|
|
};
|
|
|
|
const XML_ESCAPE_PATTERNS = [
|
|
[/&/g, "&"],
|
|
[/</g, "<"],
|
|
[/>/g, ">"],
|
|
[/"/g, """],
|
|
[/'/g, "'"],
|
|
] as const;
|
|
|
|
function escapeXml(str: string): string {
|
|
let result = str;
|
|
for (const [pattern, replacement] of XML_ESCAPE_PATTERNS) {
|
|
result = result.replace(pattern, replacement);
|
|
}
|
|
return result;
|
|
}
|