Sitemaps
@scribe-atp/core exports getSitemapEntries — a function that takes a fetched Site and returns an array of { url, lastmod? } objects. You use those to build the XML yourself, giving you full control over the output format.
Basic usage
Section titled “Basic usage”import { fetchSite, getSitemapEntries } from '@scribe-atp/core';
const site = await fetchSite('alice.bsky.social', 'alice-bsky-social');const entries = getSitemapEntries(site, { baseUrl: 'https://alice.example.com' });
// entries is: Array<{ url: string; lastmod?: string }>Wiring into your framework
Section titled “Wiring into your framework”import { fetchSite, getSitemapEntries } from '@scribe-atp/core';
export async function loader({ request }: { request: Request }) { const origin = new URL(request.url).origin; const site = await fetchSite('alice.bsky.social', 'alice-bsky-social', request.signal); const entries = getSitemapEntries(site, { baseUrl: origin });
const xml = [ '<?xml version="1.0" encoding="UTF-8"?>', '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">', ...entries.map( (e) => `<url><loc>${e.url}</loc>${e.lastmod ? `<lastmod>${e.lastmod}</lastmod>` : ''}</url>` ), '</urlset>', ].join('');
return new Response(xml, { headers: { 'Content-Type': 'application/xml; charset=utf-8' }, });}import { fetchSite, getSitemapEntries } from '@scribe-atp/core';
export async function GET(request: Request) { const origin = new URL(request.url).origin; const site = await fetchSite('alice.bsky.social', 'alice-bsky-social', request.signal); const entries = getSitemapEntries(site, { baseUrl: origin });
const xml = [ '<?xml version="1.0" encoding="UTF-8"?>', '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">', ...entries.map( (e) => `<url><loc>${e.url}</loc>${e.lastmod ? `<lastmod>${e.lastmod}</lastmod>` : ''}</url>` ), '</urlset>', ].join('');
return new Response(xml, { headers: { 'Content-Type': 'application/xml; charset=utf-8' }, });}import { fetchSite, getSitemapEntries } from '@scribe-atp/core';import type { RequestHandler } from './$types';
export const GET: RequestHandler = async ({ url }) => { const site = await fetchSite('alice.bsky.social', 'alice-bsky-social'); const entries = getSitemapEntries(site, { baseUrl: url.origin });
const xml = [ '<?xml version="1.0" encoding="UTF-8"?>', '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">', ...entries.map( (e) => `<url><loc>${e.url}</loc>${e.lastmod ? `<lastmod>${e.lastmod}</lastmod>` : ''}</url>` ), '</urlset>', ].join('');
return new Response(xml, { headers: { 'Content-Type': 'application/xml; charset=utf-8' }, });};Adding static pages
Section titled “Adding static pages”getSitemapEntries only returns URLs for published articles. To include static pages (home page, about, etc.), append them manually:
const entries = getSitemapEntries(site, { baseUrl: origin });
const staticPages = [ { url: `${origin}/` }, { url: `${origin}/about` },];
const allEntries = [...staticPages, ...entries];What gets included
Section titled “What gets included”getSitemapEntries returns one entry per published article. Each entry includes:
url— the canonical article URL, built from the site’surlandurlPrefixlastmod— the article’supdatedAttimestamp (ISO 8601 format), when set
Unpublished articles (site.ungroupedArticles) are excluded.