/** * `/` — a page you wrote, reading data Assemora owns. * * This is the half of the arrangement that answers "I already have a Next.js site". * Nothing here is generated and nothing here is a block: it is a React server * component that happens to call the CMS. Your routes stay yours. * * It is a *server* component, so the call below runs in the Next.js process and the * browser is sent HTML. The token never leaves this machine, and a visitor downloads * no JavaScript for it. */ // assemora:if pages import Link from 'next/link' // assemora:end import { api, isUnauthenticated } from './lib/assemora.ts' /** * Rendered per request, never at build time. * * The content lives in Assemora, so baking this page into the bundle would freeze it * at whatever the database held when somebody ran `next build` — and that build may * be in CI, where the API is not running at all. A CMS page is dynamic by nature; * add `revalidate` if you want it cached for a while instead. */ export const dynamic = 'force-dynamic' /** * What `GET /api/articles` sends, which is not what the model holds. * * Deliberately not `typeof Article.$infer`: the record type says `createdAt: Date`, * and JSON has no such thing. `pnpm sdk:generate` writes this type from the Schema * Registry — from the *wire* schema — which is how it stops being written by hand. */ type Article = { readonly id: string readonly title: string readonly slug: string } /** Nothing is cached: Next 15 stopped caching `fetch` by default, so an edit shows. */ const latest = async (): Promise => { try { const page = await api.resource
('articles').list({ perPage: 5, sort: '-createdAt' }) return page.data } catch (error) { if (isUnauthenticated(error)) return 'unauthenticated' throw error } } const Home = async () => { const articles = await latest() return (

My site

{articles === 'unauthenticated' ? (

This frontend has no ASSEMORA_TOKEN, so the application refused the read — which is what it is supposed to do. Copy the token pnpm dev:api printed on its first boot into .env, then restart.

) : ( <>

Latest articles

    {articles.map((article) => (
  • {article.title}
  • ))}
)}

Where to go next

  • {/* A plain anchor, not `next/link`: /studio is a different application, on the far side of the rewrite, and there is nothing here to transition to. */} Studio — sign in and edit
  • {/* assemora:if pages */}
  • The seeded page — assembled from blocks, rendered by{' '} @assemora/react
  • {/* assemora:end */}
) } export default Home