import type { MetadataRoute } from "next"; import { api, SITE_URL } from "@/lib/api"; import { CHANNEL_KEYS } from "@/lib/format"; export const dynamic = "force-dynamic"; /** Public, crawlable surface only — user tools (/watchlists, /alerts, /bookmarks, /monitors, /ops) are noindex. */ export default async function sitemap(): Promise { const now = new Date(); const statics: MetadataRoute.Sitemap = [ { url: `${SITE_URL}/`, lastModified: now, changeFrequency: "always", priority: 1 }, { url: `${SITE_URL}/live`, lastModified: now, changeFrequency: "always", priority: 0.9 }, { url: `${SITE_URL}/breaking`, lastModified: now, changeFrequency: "always", priority: 0.9 }, { url: `${SITE_URL}/pulse`, lastModified: now, changeFrequency: "always", priority: 0.8 }, { url: `${SITE_URL}/radar`, lastModified: now, changeFrequency: "hourly", priority: 0.7 }, { url: `${SITE_URL}/silent`, lastModified: now, changeFrequency: "hourly", priority: 0.8 }, { url: `${SITE_URL}/explore`, lastModified: now, changeFrequency: "hourly", priority: 0.7 }, { url: `${SITE_URL}/sources`, lastModified: now, changeFrequency: "daily", priority: 0.6 }, { url: `${SITE_URL}/entities`, lastModified: now, changeFrequency: "hourly", priority: 0.6 }, { url: `${SITE_URL}/country`, lastModified: now, changeFrequency: "hourly", priority: 0.6 }, { url: `${SITE_URL}/api`, lastModified: now, changeFrequency: "weekly", priority: 0.5 }, { url: `${SITE_URL}/health`, lastModified: now, changeFrequency: "hourly", priority: 0.3 }, { url: `${SITE_URL}/bot`, lastModified: now, changeFrequency: "monthly", priority: 0.3 }, ...CHANNEL_KEYS.map((c) => ({ url: `${SITE_URL}/category/${c}`, lastModified: now, changeFrequency: "hourly" as const, priority: 0.7 })), ]; const [events, sources, entities, countries, clusters] = await Promise.all([api.events({ limit: 200 }), api.sources(), api.entities({ limit: 500 }), api.countries(), api.clusters(200, 168)]); const more = await (events.nextCursor ? api.events({ limit: 200, cursor: events.nextCursor }) : Promise.resolve({ items: [], nextCursor: null })); const third = await (more.nextCursor ? api.events({ limit: 100, cursor: more.nextCursor }) : Promise.resolve({ items: [], nextCursor: null })); const seen = new Set(); const unique = (rows: T[]): T[] => rows.filter((r) => (seen.has(r.url) ? false : (seen.add(r.url), true))); return unique([ ...statics, ...[...events.items, ...more.items, ...third.items].map((e) => ({ url: `${SITE_URL}/event/${e.slug}`, lastModified: new Date(e.detected_at), changeFrequency: "daily" as const, priority: Math.min(0.9, 0.4 + (e.signal_score ?? e.importance) / 200) })), ...clusters.items.filter((c) => c.slug).map((c) => ({ url: `${SITE_URL}/cluster/${c.slug}`, lastModified: new Date(c.last_at), changeFrequency: "hourly" as const, priority: c.state === "breaking" ? 0.9 : 0.6 })), ...countries.items.map((c) => ({ url: `${SITE_URL}/country/${c.slug}`, lastModified: now, changeFrequency: "hourly" as const, priority: 0.6 })), ...sources.items.map((s) => ({ url: `${SITE_URL}/source/${s.id}`, lastModified: s.last_event_at ? new Date(s.last_event_at) : now, changeFrequency: "hourly" as const, priority: 0.6 })), ...sources.items.map((s) => ({ url: `${SITE_URL}/domain/${s.domain}`, lastModified: now, changeFrequency: "daily" as const, priority: 0.4 })), ...entities.items.map((e) => ({ url: `${SITE_URL}/entity/${e.id}`, lastModified: e.last_event_at ? new Date(e.last_event_at) : now, changeFrequency: "hourly" as const, priority: 0.6 })), ]); }