/**
 * RSS 2.0 + JSON Feed 1.1 builders.
 *
 * Feeds are how readers, aggregators, and increasingly AI agents subscribe to
 * fresh content without polling HTML. These are pure functions over an already
 * resolved item list so they are trivially testable; the route layer
 * (`seo-public.ts`) does the DB work and URL resolution.
 */
import { escapeXml } from '../api/route-helpers.js';
function toRfc822(iso) {
    if (!iso)
        return undefined;
    const d = new Date(iso);
    return Number.isNaN(d.getTime()) ? undefined : d.toUTCString();
}
/** Build an RSS 2.0 document. */
export function buildRssFeed(channel, items) {
    const lastBuild = toRfc822(channel.updated ?? items[0]?.date);
    const lines = [
        '<?xml version="1.0" encoding="UTF-8"?>',
        '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">',
        '  <channel>',
        `    <title>${escapeXml(channel.title)}</title>`,
        `    <link>${escapeXml(channel.homeUrl)}</link>`,
        `    <atom:link href="${escapeXml(channel.feedUrl)}" rel="self" type="application/rss+xml" />`,
    ];
    if (channel.description)
        lines.push(`    <description>${escapeXml(channel.description)}</description>`);
    if (channel.language)
        lines.push(`    <language>${escapeXml(channel.language)}</language>`);
    if (lastBuild)
        lines.push(`    <lastBuildDate>${lastBuild}</lastBuildDate>`);
    for (const item of items) {
        lines.push('    <item>');
        lines.push(`      <title>${escapeXml(item.title)}</title>`);
        lines.push(`      <link>${escapeXml(item.url)}</link>`);
        lines.push(`      <guid isPermaLink="true">${escapeXml(item.url)}</guid>`);
        if (item.description)
            lines.push(`      <description>${escapeXml(item.description)}</description>`);
        const pub = toRfc822(item.date);
        if (pub)
            lines.push(`      <pubDate>${pub}</pubDate>`);
        if (item.author)
            lines.push(`      <author>${escapeXml(item.author)}</author>`);
        lines.push('    </item>');
    }
    lines.push('  </channel>', '</rss>');
    return lines.join('\n');
}
/** Build a JSON Feed 1.1 document (https://www.jsonfeed.org/version/1.1/). */
export function buildJsonFeed(channel, items) {
    const feed = {
        version: 'https://jsonfeed.org/version/1.1',
        title: channel.title,
        home_page_url: channel.homeUrl,
        feed_url: channel.feedUrl,
        ...(channel.description ? { description: channel.description } : {}),
        ...(channel.language ? { language: channel.language } : {}),
        items: items.map((item) => ({
            id: item.url,
            url: item.url,
            title: item.title,
            ...(item.description ? { summary: item.description } : {}),
            ...(item.date ? { date_published: item.date } : {}),
            ...(item.dateModified ? { date_modified: item.dateModified } : {}),
            ...(item.author ? { authors: [{ name: item.author }] } : {}),
        })),
    };
    return JSON.stringify(feed, null, 2);
}
//# sourceMappingURL=feeds.js.map