Skip to content

API reference

Every export of @ghostwritr/react-router. The fetchers, the webhook verifier, GhostwritrError, and the types are re-exported from the shared @ghostwritr/feed core, so the contract is identical across the Next / Astro / React Router SDKs. articleMeta is React-Router-specific.

function fetchArticles(options: FeedFetchOptions): Promise<Article[]>

Every published Article for the site, newest first. Resolves the feed manifest, then walks each immutable build page (20 per page) and de-duplicates by id. Returns [] when the feed has zero pages; throws GhostwritrError NOT_FOUND when the site has no feed yet. Call it inside a route loader.

function fetchArticle(
options: FeedFetchOptions & { slug: string },
): Promise<Article | null>

One published article by slug, read directly from the by-slug document (no page walk), or null when the slug isn’t in the current feed. A blank slug throws GhostwritrError CONFIG. Throw a 404 Response yourself on null — see Writing loaders.

interface FeedFetchOptions {
siteId: string; // the unguessable keyless read key (required)
staticBaseUrl?: string; // feed origin override; default DEFAULT_STATIC_BASE_URL
fetch?: typeof fetch; // your own fetch (caching/retries/test stub)
}
function articleMeta(article: Article, opts?: ArticleMetaOptions): MetaDescriptor[]

Builds the React Router MetaDescriptor[] for an article route’s meta export: <title> (from seoTitle), description, Open Graph + Twitter cards, <link rel="canonical">, and schema.org Article JSON-LD. Full breakdown in SEO meta.

interface ArticleMetaOptions {
url?: string; // canonical + og:url for THIS page; wins over article.canonicalUrl
siteName?: string; // og:site_name + JSON-LD publisher
twitterSite?: string; // twitter:site @handle
}

verifyFeedSignature(secret, rawBody, signature)

Section titled “verifyFeedSignature(secret, rawBody, signature)”
function verifyFeedSignature(
secret: string,
rawBody: string,
signature: string | null | undefined,
): Promise<boolean>

Verify a signed feed.updated webhook: HMAC-SHA256 of the raw body against the shared secret, compared in constant time. Returns false for a missing or mismatched signature. Web Crypto — runs in Node 20+ and on edge. See Feed-freshness webhook.

const FEED_SIGNATURE_HEADER = "X-GW-Signature"

The header that carries the hex HMAC of the raw webhook body.

const DEFAULT_STATIC_BASE_URL = "https://feeds.ghostwritr.io"

The default static-feed origin. Override per call with FeedFetchOptions.staticBaseUrl.

class GhostwritrError extends Error {
readonly status: number; // HTTP status, or 0 for client-side errors
readonly code: GhostwritrErrorCode | null;
readonly details?: unknown;
}

The single error type the fetchers throw. code is one of CONFIG, NETWORK_ERROR, NOT_FOUND, RATE_LIMITED, SERVER_ERROR, INVALID_RESPONSE (and the auth codes UNAUTHORIZED / FORBIDDEN). See Error handling.

From @ghostwritr/feed, available as type-only imports:

  • Article — a published article. See The article shape.
  • ArticleImage — the cover image (url, alt, width, height, srcset), or null.
  • Author — the byline; kind is "real" or "persona" and drives the JSON-LD type.
  • ArticleOrder"published-desc" (default, newest first) or "feed".
  • FeedFetchOptions — the fetcher options above.
  • FeedUpdatedPayload — the webhook body (event, siteId, buildId).
  • GhostwritrErrorCode — the union of error codes.
  • ArticleMetaOptions — the articleMeta options above (this package’s own type).