← back to Stayclaim
src/app/timeline/rss.xml/route.ts
62 lines
import { NextResponse } from 'next/server';
import { getArchiveTimeline } from '@/lib/db';
import { SITE_DOMAIN, SITE_NAME, SITE_TAGLINE } from '@/lib/site';
export const dynamic = 'force-dynamic';
export const runtime = 'nodejs';
/**
* RSS 2.0 feed of the archive's most recent events.
* For archivists, GIS folks, and history-twitter.
*/
export async function GET() {
const events = await getArchiveTimeline({ limit: 50 });
const base = (process.env.NEXT_PUBLIC_BASE_URL ?? `https://${SITE_DOMAIN}`).replace(/\/$/, '');
const items = events.map(e => {
const link = `${base}/address/${encodeURIComponent(e.listing_slug)}`;
const date = e.valid_from ?? e.recorded_at;
const pubDate = new Date(date).toUTCString();
const title = `${e.kind.replace(/_/g, ' ')} · ${e.listing_title}`;
return [
' <item>',
` <title>${escapeXml(title)}</title>`,
` <link>${escapeXml(link)}</link>`,
` <guid isPermaLink="false">pastdoor:event:${escapeXml(e.id)}</guid>`,
` <pubDate>${pubDate}</pubDate>`,
` <category>${escapeXml(e.kind)}</category>`,
` <description>${escapeXml(e.summary)}${e.source_label ? ` — ${escapeXml(e.source_label)}` : ''}</description>`,
' </item>',
].join('\n');
});
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>${escapeXml(SITE_NAME)} — archive timeline</title>
<link>${escapeXml(base + '/timeline')}</link>
<description>${escapeXml(SITE_TAGLINE)} New events in the archive — permits, sales, archival media.</description>
<language>en-us</language>
<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
<atom:link xmlns:atom="http://www.w3.org/2005/Atom" href="${escapeXml(base + '/timeline/rss.xml')}" rel="self" type="application/rss+xml" />
${items.join('\n')}
</channel>
</rss>`;
return new NextResponse(xml, {
headers: {
'Content-Type': 'application/rss+xml; charset=utf-8',
'Cache-Control': 'public, max-age=600, s-maxage=3600',
},
});
}
function escapeXml(s: string): string {
return String(s ?? '')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}