import type { Metadata } from 'next'; import Link from 'next/link'; import { HBars } from '@/components/charts/charts'; import { ChipRow, EmptyRow, ScrollTable, entityMetadata, first, type Params } from '@/components/entities/shared'; import { Container, PageHeader } from '@/components/ui/section'; import { Unavailable } from '@/components/ui/unavailable'; import { api, safe } from '@/lib/api'; import { fmtInt, num } from '@/lib/format'; import { routes } from '@/lib/site'; import type { CountryRow } from '@/lib/types'; type SearchParams = Record; const SORTS: { value: string | undefined; label: string; key: keyof CountryRow; noun: string }[] = [ { value: undefined, label: 'Active payloads', key: 'active_payloads', noun: 'active payloads' }, { value: 'objects', label: 'Objects on orbit', key: 'objects_on_orbit', noun: 'objects on orbit' }, { value: 'debris', label: 'Debris', key: 'debris_on_orbit', noun: 'debris fragments on orbit' }, { value: 'launches', label: 'Launches', key: 'launches', noun: 'launches' }, { value: 'name', label: 'Name', key: 'name', noun: 'name' }, ]; export async function generateMetadata({ searchParams }: { searchParams: Promise }): Promise { const sort = first((await searchParams).sort); const s = SORTS.find((x) => (x.value ?? '') === (sort ?? '')) ?? SORTS[0]!; return entityMetadata({ title: `Countries in orbit — ranked by ${s.noun}`, description: 'Every country with catalogued objects in Earth orbit, ranked by active payloads, objects on orbit, debris, rocket bodies, launches and operators — with regional breakdown.', path: routes.countries(), }); } export default async function CountriesPage({ searchParams }: { searchParams: Promise }) { const sp = await searchParams; const params: Params = { sort: first(sp.sort) }; const sortDef = SORTS.find((x) => (x.value ?? '') === (params.sort ?? '')) ?? SORTS[0]!; const res = await safe(api.countries(params.sort ?? 'active')); const rows = res?.data ?? []; const base = routes.countries(); const metricKey = sortDef.key === 'name' ? 'active_payloads' : sortDef.key; const metricNoun = sortDef.key === 'name' ? 'active payloads' : sortDef.noun; const top10 = rows.length ? [...rows].sort((a, b) => (num(b[metricKey] as never) ?? 0) - (num(a[metricKey] as never) ?? 0)).slice(0, 10).map((c) => ({ label: c.name, value: num(c[metricKey] as never) ?? 0, href: routes.country(c.slug) })) : []; const byRegion = new Map(); for (const c of rows) byRegion.set(c.region ?? 'Unattributed', (byRegion.get(c.region ?? 'Unattributed') ?? 0) + (num(c[metricKey] as never) ?? 0)); const regionData = [...byRegion.entries()].map(([label, value], i) => ({ label, value, color: `var(--series-${(i % 8) + 1})` })).sort((a, b) => b.value - a.value); const totals = rows.reduce( (t, c) => ({ active: t.active + (num(c.active_payloads) ?? 0), objects: t.objects + (num(c.objects_on_orbit) ?? 0), debris: t.debris + (num(c.debris_on_orbit) ?? 0) }), { active: 0, objects: 0, debris: 0 }, ); return ( {fmtInt(rows.length)} countries and jurisdictions hold catalogued objects in orbit — together {fmtInt(totals.active)} active payloads, {fmtInt(totals.objects)} objects on orbit and {fmtInt(totals.debris)} tracked debris fragments. Attribution follows SATCAT owner codes mapped to ISO 3166 (joint programmes are listed under their lead entry); see the{' '} methodology. ) : ( 'Country rankings are temporarily unavailable.' ) } />
({ value: s.value, label: s.label }))} />
{res && rows.length > 0 && (

Top 10 · {metricNoun}

By region · {metricNoun}

Regions aggregate the countries listed below; multinational organisations (e.g. ESA, Intelsat) appear as their own entry.

)}
{!res ? : }
); } function CountryTable({ rows }: { rows: CountryRow[] }) { return ( {rows.length === 0 && No countries returned.} {rows.map((c, i) => ( ))}
# Country Region Active payloads Payloads on orbit Objects on orbit Debris Rocket bodies Launches Operators Payloads 365 d
{i + 1} {c.name} {c.iso3 ?? c.code} {c.region ?? '—'} {fmtInt(c.active_payloads)} {fmtInt(c.on_orbit_payloads)} {fmtInt(c.objects_on_orbit)} {fmtInt(c.debris_on_orbit)} {fmtInt(c.rocket_bodies_on_orbit)} {fmtInt(c.launches)} {fmtInt(c.operators)} {fmtInt(c.payloads_last_365d)}
); }