HTML 77.2%
TypeScript 10.5%
Python 9.6%
JavaScript 2.5%
1import 'server-only';2import type { Metadata } from 'next';3import { notFound } from 'next/navigation';4import { api, ApiError, safe } from '@/lib/api';5import { PATH_TYPES, routes, SITE_NAME, SITE_URL, TYPE_PATH, typeLabel } from '@/lib/site';6import type { EntityDetail } from '@/lib/types';7import { describeEntity } from './entity-page';89/**10 * Load an entity for a typed path (`models`, `companies`, `providers`…). 404 when the API says so or when the entity's11 * type is not accepted under this path (so /tools/<framework-slug> is a 404, not a duplicate canonical URL).12 */13export async function loadEntity(typePath: string, slug: string): Promise<EntityDetail> {14 const def = PATH_TYPES[typePath];15 if (!def) notFound();16 try {17 const d = def.api === 'entities' ? await api.entity(slug) : await api.entityOfType(def.api, slug);18 if (!def.types.includes(d.entity_type)) notFound();19 return d;20 } catch (e) {21 if (e instanceof ApiError && e.notFound) notFound();22 throw e;23 }24}2526/** Load for the /explore/<type>/<slug> fallback: any type that has no dedicated path. */27export async function loadAnyEntity(type: string, slug: string): Promise<EntityDetail> {28 try {29 const d = await api.entity(slug);30 if (d.entity_type !== type) notFound();31 return d;32 } catch (e) {33 if (e instanceof ApiError && e.notFound) notFound();34 throw e;35 }36}3738export async function entityMetadata(typePath: string, slug: string): Promise<Metadata> {39 const def = PATH_TYPES[typePath];40 const d = def ? await safe(def.api === 'entities' ? api.entity(slug) : api.entityOfType(def.api, slug)) : null;41 if (!d || (def && !def.types.includes(d.entity_type))) return { title: def?.singular ?? 'Entity', robots: { index: false } };42 return buildMetadata(d);43}4445export function buildMetadata(d: EntityDetail): Metadata {46 const canonical = routes.entity(d);47 const label = typeLabel(d.entity_type);48 const title = d.organization && d.entity_type === 'model' ? `${d.name} — ${d.organization.name} ${label.toLowerCase()}` : `${d.name} — ${label}`;49 const description = describeEntity(d);50 return {51 title,52 description,53 alternates: { canonical },54 openGraph: { title: `${title} | ${SITE_NAME}`, description, url: `${SITE_URL}${canonical}`, type: 'article', siteName: SITE_NAME },55 twitter: { card: 'summary_large_image', title, description },56 };57}5859export function canonicalFor(d: EntityDetail): string {60 return routes.entity(d);61}6263export { TYPE_PATH };64