import 'server-only'; import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { api, ApiError, safe } from '@/lib/api'; import { PATH_TYPES, routes, SITE_NAME, SITE_URL, TYPE_PATH, typeLabel } from '@/lib/site'; import type { EntityDetail } from '@/lib/types'; import { describeEntity } from './entity-page'; /** * Load an entity for a typed path (`models`, `companies`, `providers`…). 404 when the API says so or when the entity's * type is not accepted under this path (so /tools/ is a 404, not a duplicate canonical URL). */ export async function loadEntity(typePath: string, slug: string): Promise { const def = PATH_TYPES[typePath]; if (!def) notFound(); try { const d = def.api === 'entities' ? await api.entity(slug) : await api.entityOfType(def.api, slug); if (!def.types.includes(d.entity_type)) notFound(); return d; } catch (e) { if (e instanceof ApiError && e.notFound) notFound(); throw e; } } /** Load for the /explore// fallback: any type that has no dedicated path. */ export async function loadAnyEntity(type: string, slug: string): Promise { try { const d = await api.entity(slug); if (d.entity_type !== type) notFound(); return d; } catch (e) { if (e instanceof ApiError && e.notFound) notFound(); throw e; } } export async function entityMetadata(typePath: string, slug: string): Promise { const def = PATH_TYPES[typePath]; const d = def ? await safe(def.api === 'entities' ? api.entity(slug) : api.entityOfType(def.api, slug)) : null; if (!d || (def && !def.types.includes(d.entity_type))) return { title: def?.singular ?? 'Entity', robots: { index: false } }; return buildMetadata(d); } export function buildMetadata(d: EntityDetail): Metadata { const canonical = routes.entity(d); const label = typeLabel(d.entity_type); const title = d.organization && d.entity_type === 'model' ? `${d.name} — ${d.organization.name} ${label.toLowerCase()}` : `${d.name} — ${label}`; const description = describeEntity(d); return { title, description, alternates: { canonical }, openGraph: { title: `${title} | ${SITE_NAME}`, description, url: `${SITE_URL}${canonical}`, type: 'article', siteName: SITE_NAME }, twitter: { card: 'summary_large_image', title, description }, }; } export function canonicalFor(d: EntityDetail): string { return routes.entity(d); } export { TYPE_PATH };