spicebook/frontend/src/pages/og/[id].png.ts
Ryan Malloy c9116c5d86 Add SEO meta tags, OG image generation, and astro-icon integration
Wire astro-seo-meta for OG, Twitter Card, and canonical tags on all
pages. Add Satori + resvg dynamic OG image endpoints at /og/[id].png
with branded dark-theme cards. Replace inline SVGs with zero-JS
astro-icon rendering. SSR fetches use 5s AbortController timeout and
shared ID validation across all dynamic routes.
2026-02-14 13:15:52 -07:00

32 lines
1.1 KiB
TypeScript

import type { APIRoute } from 'astro';
import { renderOgImage } from '../../lib/og-renderer';
import { fetchNotebookMeta } from '../../lib/server-api';
import { NOTEBOOK_ID_RE, buildNotebookDescription } from '../../lib/notebook-meta';
export const GET: APIRoute = async ({ params }) => {
const { id } = params;
if (!id || !NOTEBOOK_ID_RE.test(id)) {
return new Response('Invalid notebook ID', { status: 400 });
}
const notebook = await fetchNotebookMeta(id);
const title = notebook?.metadata?.title || id;
const engine = notebook?.metadata?.engine || 'ngspice';
const tags: string[] = notebook?.metadata?.tags || [];
const description = buildNotebookDescription(title, engine, tags);
try {
const png = await renderOgImage({ title, description, engine });
return new Response(png.buffer as ArrayBuffer, {
headers: {
'Content-Type': 'image/png',
'Cache-Control': 'public, max-age=3600, s-maxage=86400',
},
});
} catch (err) {
console.error(`[og/${id}] render failed:`, err);
return new Response('OG image generation failed', { status: 500 });
}
};