@alphablue/content-client
v0.3.1
Published
Framework-agnostic client for the AlphaBlue content-api (published content + live state).
Readme
@alphablue/content-client
A tiny, framework-agnostic client for the AlphaBlue content-api — the public read API every customer site consumes. One client, used from every layer:
- build time (Astro frontmatter / Node) — the SSG data source;
- the browser (React islands) — runtime, for dynamic modules;
- a Worker — pass a bound
fetch.
It has no dependencies and ships types that mirror content-api's JSON exactly
(snake_case; translatable fields as { value, resolved_locale }).
Usage
import { createContentClient, val, money } from "@alphablue/content-client";
const client = createContentClient({
baseUrl: "https://content.alphablueth.com",
siteId: "0195da70-0000-7000-8000-000000000001",
});
// Channel A — the aggregate a build wants in one consistent read.
const content = await client.content({ locale: "en" });
content.meta && val(content.meta.business_name); // "Content API Demo Cafe"
content.catalog.map((i) => `${val(i.name)} — ${money(i.price)}`);
content.faqs.map((faq) => [faq.question, faq.answer]);
// Channel A — continue an immutable feed page with its returned cursor.
const firstPosts = await client.posts({ limit: 50 });
const older = firstPosts.next_before
? await client.posts({ before: firstPosts.next_before, limit: 50 })
: null;
// Channel B — live state (short TTL). Runtime only.
const live = await client.live({ cache: "no-store" });
// Published Articles — build revision bypasses a stale CDN object after publish.
const articles = await client.articles({
locale: "en",
buildRevision: "deploy-42",
});
const article = await client.article(articles.articles[0].slug, {
locale: "en",
buildRevision: "deploy-42",
});Two channels, one contract
| Method | Channel | Use |
| -------------------------- | -------------- | ----------------------------------------------------------- |
| content() | A (published) | build-time SSG and runtime islands |
| posts() | A (published) | paginating the feed |
| live() | B (live state) | runtime only — grayscale, announcement, availability |
| articles() / article() | A (published) | Article list/detail for static routes, SEO, sitemap and RSS |
Publish-type content (content()) baked at build needs a rebuild to change;
that is the pipeline in
publish-rebuild-pipeline.md.
Fetched from an island instead, it updates on refresh. Live state (live()) is
runtime by design.
API
createContentClient({ baseUrl, siteId, fetch? })→{ content, posts, live, articles, article }val(text)— resolve a{ value, resolved_locale }field to its stringmoney(price, { enquireLabel?, fromPrefix? })— format satang without float mathContentApiError— thrown on any non-2xx (.status,.path)
Published methods take { locale?, signal?, cache?, buildRevision? }.
posts()、articles()、catalog() 与 FAQ methods 接受 cursor paging (before, limit);
before 必须使用同一 response 的 next_before/next_cursor,因为它是绑定 published
revision、surface、locale 与 filter 的 opaque cursor。live()
only accepts runtime fetch controls (signal, cache). Astro customer sites
should consume this package through @alphablue/astro-site/content rather than
adding a second direct AlphaBlue dependency.
