TypeScript 55.4%
Python 43.2%
SQL 1.2%
1import type { MetadataRoute } from "next";2import { api, SITE_URL } from "@/lib/api";3import { CHANNEL_KEYS } from "@/lib/format";45export const dynamic = "force-dynamic";67/** Public, crawlable surface only — user tools (/watchlists, /alerts, /bookmarks, /monitors, /ops) are noindex. */8export default async function sitemap(): Promise<MetadataRoute.Sitemap> {9 const now = new Date();10 const statics: MetadataRoute.Sitemap = [11 { url: `${SITE_URL}/`, lastModified: now, changeFrequency: "always", priority: 1 },12 { url: `${SITE_URL}/live`, lastModified: now, changeFrequency: "always", priority: 0.9 },13 { url: `${SITE_URL}/breaking`, lastModified: now, changeFrequency: "always", priority: 0.9 },14 { url: `${SITE_URL}/pulse`, lastModified: now, changeFrequency: "always", priority: 0.8 },15 { url: `${SITE_URL}/radar`, lastModified: now, changeFrequency: "hourly", priority: 0.7 },16 { url: `${SITE_URL}/silent`, lastModified: now, changeFrequency: "hourly", priority: 0.8 },17 { url: `${SITE_URL}/explore`, lastModified: now, changeFrequency: "hourly", priority: 0.7 },18 { url: `${SITE_URL}/sources`, lastModified: now, changeFrequency: "daily", priority: 0.6 },19 { url: `${SITE_URL}/entities`, lastModified: now, changeFrequency: "hourly", priority: 0.6 },20 { url: `${SITE_URL}/country`, lastModified: now, changeFrequency: "hourly", priority: 0.6 },21 { url: `${SITE_URL}/api`, lastModified: now, changeFrequency: "weekly", priority: 0.5 },22 { url: `${SITE_URL}/health`, lastModified: now, changeFrequency: "hourly", priority: 0.3 },23 { url: `${SITE_URL}/bot`, lastModified: now, changeFrequency: "monthly", priority: 0.3 },24 ...CHANNEL_KEYS.map((c) => ({ url: `${SITE_URL}/category/${c}`, lastModified: now, changeFrequency: "hourly" as const, priority: 0.7 })),25 ];26 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)]);27 const more = await (events.nextCursor ? api.events({ limit: 200, cursor: events.nextCursor }) : Promise.resolve({ items: [], nextCursor: null }));28 const third = await (more.nextCursor ? api.events({ limit: 100, cursor: more.nextCursor }) : Promise.resolve({ items: [], nextCursor: null }));29 const seen = new Set<string>();30 const unique = <T extends { url: string }>(rows: T[]): T[] => rows.filter((r) => (seen.has(r.url) ? false : (seen.add(r.url), true)));31 return unique([32 ...statics,33 ...[...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) })),34 ...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 })),35 ...countries.items.map((c) => ({ url: `${SITE_URL}/country/${c.slug}`, lastModified: now, changeFrequency: "hourly" as const, priority: 0.6 })),36 ...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 })),37 ...sources.items.map((s) => ({ url: `${SITE_URL}/domain/${s.domain}`, lastModified: now, changeFrequency: "daily" as const, priority: 0.4 })),38 ...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 })),39 ]);40}41