claude again

This commit is contained in:
Andras Schmelczer 2026-05-11 08:12:35 +01:00
parent df2267a968
commit f3fc893675
81 changed files with 945 additions and 2813 deletions

View file

@ -1,10 +1,37 @@
import rss from '@astrojs/rss';
import type { APIRoute } from 'astro';
import { absoluteUrl, articlePath, getPublishedPosts, site } from '../lib/site';
import ogDefault from '../assets/og-default.jpg';
import {
absoluteUrl,
articlePath,
entrySlug,
getPublishedPosts,
optimizeOgImage,
site,
} from '../lib/site';
// Escape characters that would otherwise break XML parsing inside text nodes
// (the `customData` strings are inserted as-is by @astrojs/rss).
function escapeXml(value: string) {
return value
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
// Format a Date as `YYYY-MM-DD` in UTC for use inside tag: URIs.
function isoDate(date: Date) {
return date.toISOString().slice(0, 10);
}
export const GET: APIRoute = async (context) => {
const posts = await getPublishedPosts();
const feedUrl = absoluteUrl('/rss.xml');
const channelImage = await optimizeOgImage(ogDefault);
const channelImageUrl = absoluteUrl(channelImage.src);
const creator = escapeXml(site.name);
return rss({
title: site.name,
@ -13,14 +40,24 @@ export const GET: APIRoute = async (context) => {
xmlns: {
atom: 'http://www.w3.org/2005/Atom',
content: 'http://purl.org/rss/1.0/modules/content/',
dc: 'http://purl.org/dc/elements/1.1/',
},
customData: [
'<language>en-us</language>',
`<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>`,
`<atom:link href="${feedUrl}" rel="self" type="application/rss+xml" />`,
'<image>',
` <url>${channelImageUrl}</url>`,
` <title>${escapeXml(site.name)}</title>`,
` <link>${site.url}</link>`,
'</image>',
].join('\n'),
items: posts.map((post) => {
const url = absoluteUrl(articlePath(post));
// Stable tag: URI keeps the GUID constant across path renames
// (e.g. the `/writing/` → `/articles/` migration). The date is the
// original publish date so re-publishing won't change the GUID.
const guid = `tag:schmelczer.dev,${isoDate(post.data.date)}:posts/${entrySlug(post)}`;
const updated = post.data.updated
? `<atom:updated>${post.data.updated.toISOString()}</atom:updated>`
: '';
@ -31,7 +68,13 @@ export const GET: APIRoute = async (context) => {
link: url,
author: `${site.email} (${site.name})`,
categories: [...post.data.tags],
customData: `<guid isPermaLink="true">${url}</guid>${updated}`,
customData: [
`<guid isPermaLink="false">${escapeXml(guid)}</guid>`,
`<dc:creator>${creator}</dc:creator>`,
updated,
]
.filter(Boolean)
.join(''),
};
}),
});