/**
* SEO artefacts — sitemap and robots.
*
* sitemap.xml enumerates every crawlable URL. The snapshot writes it to the
* bucket root; the live service serves the same file on request so a crawler
* hitting prometheus.x (via the apps.silentmode.st mirror in production) sees
* the same contents the snapshot does.
*
* robots.txt is the usual shape: allow everything except the admin and the
* raw API routes, which have no public content.
*/
const BASE = process.env.PUBLIC_BASE || 'https://prometheus.x';
/**
* @param {{categories: string[], listings: Array<{publisher: string, slug: string, lastmod?: string}>}} data
*/
export function renderSitemap({ categories, listings }) {
const now = new Date().toISOString();
const urls = [
{ loc: '/', lastmod: now, priority: '1.0' },
{ loc: '/browse', lastmod: now, priority: '0.9' },
{ loc: '/publish', lastmod: now, priority: '0.6' },
{ loc: '/boundaries', lastmod: now, priority: '0.5' },
{ loc: '/submit', lastmod: now, priority: '0.4' },
...categories.map((slug) => ({
loc: `/c/${slug}`, lastmod: now, priority: '0.7',
})),
...listings.map((l) => ({
loc: `/app/${l.publisher}/${l.slug}`,
lastmod: l.lastmod || now,
priority: '0.8',
})),
];
const body = urls.map((u) =>
` ${BASE}${u.loc}${u.lastmod}${u.priority}`
).join('\n');
return `
${body}
`;
}
export function renderRobots() {
return `User-agent: *
Allow: /
Disallow: /admin
Disallow: /admin/
Disallow: /api/
Disallow: /.well-known/
Sitemap: ${BASE}/sitemap.xml
`;
}
/**
* schema.org JSON-LD for a listing — Google renders a rich card for apps.
* Returns the raw JSON string; the template wraps it in a