Skip to content

@scribe-atp/core

function fetchSite(
author: string,
publicationUrl: string,
signal?: AbortSignal
): Promise<Site>

Fetches a site record from the author’s PDS. Resolves the author handle to a DID, discovers the PDS, and returns the full Site with embedded group and article metadata.

ParameterTypeDescription
authorstringAuthor handle (alice.bsky.social) or DID (did:plc:…)
publicationUrlstringThe site’s canonical HTTPS URL, e.g. "https://alice.bsky.social"
signalAbortSignalOptional. Cancel the request when the signal fires

function fetchArticleBySlug(
author: string,
publicationUrl: string,
articleSlug: string,
signal?: AbortSignal
): Promise<ArticleResult>

Fetches a full article record and its AT URI in a single call. Resolves the site record first (using the publication URL cache if already fetched), then locates the article ref by slug and fetches the full article.

ParameterTypeDescription
authorstringAuthor handle or DID
publicationUrlstringThe site’s canonical HTTPS URL, e.g. "https://alice.bsky.social"
articleSlugstringThe article’s rkey / slug
signalAbortSignalOptional. Cancel the request when the signal fires

Returns { article: Article, uri: string }. The uri is the full AT URI of the site.standard.document record — pass it to @scribe-atp/social’s LikeButton component.

This is the preferred function for article pages in server-rendered frameworks. Use fetchArticle only when you don’t need the AT URI.


function fetchArticle(
author: string,
articleSlug: string,
signal?: AbortSignal
): Promise<Article>

Fetches a single article record (including full HTML content) directly by slug. Does not return the AT URI.

ParameterTypeDescription
authorstringAuthor handle or DID
articleSlugstringThe article’s rkey / slug
signalAbortSignalOptional. Cancel the request when the signal fires

function resolvePublicationUri(
author: string,
publicationUrl: string,
signal?: AbortSignal
): Promise<string>

Resolves the AT URI of a site record given the author handle and publication URL. Results are cached for the lifetime of the module — repeated calls with the same arguments make no additional network requests.

ParameterTypeDescription
authorstringAuthor handle or DID
publicationUrlstringThe site’s canonical HTTPS URL
signalAbortSignalOptional. Cancel the request when the signal fires

Returns a string AT URI, e.g. "at://did:plc:.../site.standard.publication/3mp4nd46xwr2h". Pass this to @scribe-atp/social’s SubscribeButton component.


function listSites(
author: string,
signal?: AbortSignal
): Promise<SiteRecord[]>

Returns all site records for the given author. Calls com.atproto.repo.listRecords for the site.standard.publication collection and follows cursor pagination automatically.

ParameterTypeDescription
authorstringAuthor handle (alice.bsky.social) or DID (did:plc:…)
signalAbortSignalOptional. Cancel the request when the signal fires

Each SiteRecord is a Site with an additional uri field (the full AT URI of the record). Use slugFromUri(record.uri) to extract the rkey when you need to construct URLs.


function listArticles(
author: string,
signal?: AbortSignal
): Promise<ArticleRef[]>

Returns all published article records for the given author as lightweight ArticleRef objects (no content field). Calls com.atproto.repo.listRecords for the site.standard.document collection and follows cursor pagination automatically.

ParameterTypeDescription
authorstringAuthor handle or DID
signalAbortSignalOptional. Cancel the request when the signal fires

Call fetchArticle to retrieve the full content for any article.


function toSlug(domain: string): string

Derives a slug from a domain name by replacing . with - and removing non-alphanumeric characters.

toSlug('norobots.blog') // → "norobots-blog"
toSlug('anthonycregan.co.uk') // → "anthonycregan-co-uk"

toSlug is no longer needed for SDK calls — fetchSite, fetchArticleBySlug, and resolvePublicationUri now take a full HTTPS URL instead of a slug. It remains exported for any other use where slug-style strings are useful.


function slugFromUri(uri: string): string

Extracts the rkey (slug) from an AT URI.

slugFromUri('at://did:plc:abc/site.standard.document/my-post') // → "my-post"

function flattenArticles(
groups: Array<{ articles: ArticleRef[] }>
): ArticleRef[]

Flattens all ArticleRef objects from all groups into a single ordered array.

const allArticles = flattenArticles(site.groups);

function generateFeed(site: Site, options: FeedOptions): string

Returns a complete RSS 2.0 XML string for all published articles in the site.

FeedOptions

PropertyTypeRequiredDescription
baseUrlstringYesYour site’s origin, e.g. "https://alice.example.com"
feedUrlstringNoCanonical URL of the feed — used for the <atom:link> self-reference
languagestringNoRSS <language> tag. Default: "en"
limitnumberNoMaximum number of items to include

See the RSS feeds guide for usage examples.


function getSitemapEntries(
site: Site,
options: GetSitemapEntriesOptions
): SitemapEntry[]

Returns an array of sitemap entries for all published articles (plus the site root and group index pages).

GetSitemapEntriesOptions

PropertyTypeRequiredDescription
baseUrlstringYesYour site’s origin, e.g. "https://alice.example.com"

SitemapEntry

interface SitemapEntry {
url: string;
lastmod?: string; // ISO 8601 date, e.g. "2024-03-15"
}

See the Sitemaps guide for usage examples.


function generateArticleMeta(article: Article, site: Site): ScribeMetaTag[]

Returns a framework-neutral array of meta tag descriptors for an article page. Covers og:type, og:title, og:url, og:site_name, og:description, og:image, twitter:card, twitter:title, twitter:description, and twitter:image.

ParameterTypeDescription
articleArticleThe full article object, as returned by fetchArticleBySlug or fetchArticle
siteSiteThe site object, used for og:site_name and canonical URL derivation

Pass the output to a framework adapter (articleMeta in @scribe-atp/react-router-framework, articleMetadata in @scribe-atp/next, articleSeoMeta in @scribe-atp/nuxt) or convert to your framework’s format manually.

See the Open Graph meta tags guide for framework-specific usage.


function generateSiteMeta(site: Site): ScribeMetaTag[]

Returns meta tag descriptors for a site index or group page — covers title, og:type (website), and optionally description and splash image.

ParameterTypeDescription
siteSiteThe site object

function buildCanonicalUrl(article: Article, site: Site): string

Derives the fully-qualified canonical URL for an article. Uses article.canonicalUrl if set; otherwise combines site.url (the site’s domain, e.g. "myblog.com"), site.urlPrefix, and article.path to produce an https:// URL.

buildCanonicalUrl(article, site);
// → "https://alice.bsky.social/blog/my-first-post"

interface Site {
title: string;
url: string; // Domain without protocol, e.g. "alice.bsky.social"
urlPrefix: string; // Path prefix, e.g. "blog" — empty string if content is at root
description?: string;
splashImageUrl?: string;
logoImageUrl?: string;
groups: SiteGroup[];
ungroupedArticles: ArticleRef[];
}
interface SiteGroup {
slug: string;
title: string;
articles: ArticleRef[];
}

A lightweight snapshot of article metadata, embedded in the site record to avoid N+1 fetch patterns. Does not include content.

interface ArticleRef {
uri: string; // AT URI, e.g. "at://did:plc:…/site.standard.document/my-post"
title: string;
slug?: string; // Article slug / rkey
splashImageUrl: string | null;
description?: string | null;
tags?: string[];
createdAt: string; // ISO 8601
publishedAt?: string; // ISO 8601
updatedAt?: string; // ISO 8601
}

The full article record, including HTML content. Returned by fetchArticle.

interface Article {
title: string;
content: string; // Sanitised HTML — safe to render directly
textContent?: string; // Plain-text version of content (HTML tags stripped)
path: string; // e.g. "/creative-writing/my-post"
site: string; // AT URI of the publication, e.g. "at://did:plc:…/site.standard.publication/3abc"
canonicalUrl?: string; // Fully-qualified article URL, e.g. "https://myblog.com/blog/my-article"
coverImageUrl?: string; // URL of the cover/splash image
description?: string;
tags?: string[];
contributors?: ArticleContributor[];
bskyPostRef?: { uri: string; cid: string }; // Bluesky post reference if the article was cross-posted
createdAt?: string; // ISO 8601
publishedAt: string; // ISO 8601
updatedAt: string; // ISO 8601
}

Additional contributors on a published article. Populated via Scribe CMS when the contributor invitation flow is in place; an empty array is written on first publish.

interface ArticleContributor {
did: string; // AT Protocol DID of the contributor
role?: string; // e.g. "author", "editor", "illustrator"
displayName?: string; // Human-readable name
}

A Site with the AT URI of its underlying record included. Returned by listSites.

interface SiteRecord extends Site {
uri: string; // AT URI, e.g. "at://did:plc:…/site.standard.publication/3mp4nd46xwr2h"
}

Use slugFromUri(record.uri) to extract the rkey when constructing URLs.

Returned by fetchArticleBySlug. Contains the full article and its AT URI.

interface ArticleResult {
article: Article;
uri: string; // AT URI, e.g. "at://did:plc:…/site.standard.document/3abc123"
}

The output element type of generateArticleMeta and generateSiteMeta. A union of three tag shapes:

type ScribeMetaTag =
| { title: string }
| { name: string; content: string }
| { property: string; content: string };

Framework adapters convert this to their own meta format. Consume it directly only if you’re writing your own adapter or using a framework not covered by the existing packages.