Next.js
@scribe-atp/next provides a createScribeSite factory for the Next.js 13+ App Router. It returns ready-made implementations of generateStaticParams and generateMetadata so you don’t have to write them yourself.
Install
Section titled “Install”npm install @scribe-atp/nextCall createScribeSite once per site, outside your components:
import { createScribeSite } from '@scribe-atp/next';
export const scribe = createScribeSite('alice.bsky.social', 'alice-bsky-social');Site index page
Section titled “Site index page”import { scribe } from '@/lib/scribe';
export const generateMetadata = scribe.generateSiteMetadata;
export default async function BlogPage() { const site = await scribe.fetchSite();
return ( <main> <h1>{site.title}</h1> {site.groups.map((group) => ( <section key={group.slug}> <h2>{group.title}</h2> <ul> {group.articles.map((article) => ( <li key={article.uri}> <a href={`/blog/${group.slug}/${article.url}`}>{article.title}</a> </li> ))} </ul> </section> ))} </main> );}Group page
Section titled “Group page”import { scribe } from '@/lib/scribe';
export const generateStaticParams = scribe.generateGroupParams;export const generateMetadata = scribe.generateGroupMetadata;
export default async function GroupPage({ params }: { params: { group: string } }) { const site = await scribe.fetchSite(); const group = site.groups.find((g) => g.slug === params.group);
if (!group) return <p>Not found</p>;
return ( <section> <h1>{group.title}</h1> <ul> {group.articles.map((article) => ( <li key={article.uri}> <a href={`/blog/${group.slug}/${article.url}`}>{article.title}</a> </li> ))} </ul> </section> );}Article page
Section titled “Article page”import { scribe } from '@/lib/scribe';
export const generateStaticParams = scribe.generateGroupArticleParams;export const generateMetadata = scribe.generateArticleMetadata;
export default async function ArticlePage({ params }: { params: { slug: string } }) { const article = await scribe.fetchArticle(params.slug);
return ( <article> <h1>{article.title}</h1> {article.synopsis && <p>{article.synopsis}</p>} <div dangerouslySetInnerHTML={{ __html: article.content }} /> </article> );}ISR (Incremental Static Regeneration)
Section titled “ISR (Incremental Static Regeneration)”Control revalidation via Next.js route segment config — the SDK does not manage this:
// Revalidate every hourexport const revalidate = 3600;TypeScript types
Section titled “TypeScript types”All types from @scribe-atp/core are re-exported from @scribe-atp/next:
import type { Site, Article, ArticleRef, SiteGroup } from '@scribe-atp/next';