/** * 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