The content feed
Every read in every SDK resolves to one place: the static content feed at feeds.ghostwritr.io/{siteId}/. It is a cacheable projection of your published articles, served from R2 behind Cloudflare’s CDN — free egress, fast at the edge, and keyless.
A projection of published state
Section titled “A projection of published state”The feed is not a database you query. It is a snapshot of exactly the articles that are currently published for your site, rebuilt on publish: when an article goes live, is updated, or is unpublished, Ghost Writr regenerates the static files. Between rebuilds the feed is fixed, which is what makes it safe to cache aggressively.
The layout
Section titled “The layout”Under your site prefix, the feed is a small manifest plus immutable per-build snapshots.
feeds.ghostwritr.io/{siteId}/ feed/index.json — the manifest (the only mutable file) b/{buildId}/page-1.json — 20 articles, newest first b/{buildId}/page-2.json b/{buildId}/by-slug/{slug}.json — one article, by slug-
The manifest is the entry point.
feed/index.jsoncarries abuildId, apageCount, and atotal. It is the only file that changes in place — it always points at the latest build. -
The build is immutable. Each rebuild writes a fresh
b/{buildId}/...tree and then flips the manifest’sbuildIdto it. Because a build’s keys never change, anything underb/{buildId}/can be cached forever. -
Pages hold the list. Each
b/{buildId}/page-N.jsonholds up to 20 articles, newest first. The manifest’spageCounttells a client how many to expect. -
By-slug holds one.
b/{buildId}/by-slug/{slug}.jsonresolves a single article for a dynamic route without paging through the whole list — it returns the article, or a404the SDK surfaces asnull.
How the SDK walks it
Section titled “How the SDK walks it”The fetchers always start from the manifest, then read from the build it names — never a hard-coded page or slug URL.
fetchArticles({ siteId })resolves the manifest, then fetchespage-1 … page-{pageCount}in order and concatenates them, newest first. (It de-duplicates byiddefensively, though immutable per-build keys mean an id should appear once.)fetchArticle({ siteId, slug })resolves the manifest, then reads exactly oneby-slug/{slug}.json— cheaper than walking every page for a[slug]route. A missing object isnull, not an error.
import { fetchArticles, fetchArticle } from "@ghostwritr/feed";
const all = await fetchArticles({ siteId }); // manifest → every pageconst one = await fetchArticle({ siteId, slug }); // manifest → by-slug, or nullFreshness
Section titled “Freshness”Because the snapshot only changes on publish, a consumer can cache it and refresh on its own schedule — or react instantly. Ghost Writr can POST a signed feed.updated webhook the moment a rebuild lands, so you revalidate within seconds instead of waiting on a timer. See Instant updates.