@arcolab/arcoseo-client
v0.3.0
Published
Typed HTTP client for arcoseo — the multi-tenant content service.
Readme
@arcolab/arcoseo-client
The typed HTTP client for arcoseo, our multi-tenant content service. A site installs this; it does not install arcoseo.
npm install @arcolab/arcoseo-clientimport { createClient } from '@arcolab/arcoseo-client'
const cms = createClient({
baseUrl: process.env.ARCOSEO_URL!, // https://tinypost.wiki
apiKey: process.env.ARCOSEO_KEY!, // a reader key — SERVER-SIDE ONLY
})
const page = await cms.getBySlug({ site: 'zh-cn', slug: 'chatgpt-china', contentType: 'blog_post' })
const list = await cms.listContent({ site: 'zh-cn', contentType: 'blog_post', sort: '-publishedAt' })
const urls = await cms.getIndexable({ site: 'zh-cn' }) // for your sitemapThree things to get right
The API key is a server secret. It is a tenant's credential, not a public token — anything holding it
can read that tenant's content. Never expose it to a browser bundle (no VITE_/NEXT_PUBLIC_ prefix, no
client component). Call this client from a server route, a loader, or a server function.
There is no tenant argument, and there never will be. The tenant lives inside the key. An argument
would imply the server might honour one.
getBySlug needs a contentType. A slug is unique within a content type, not within a site —
/blog/onboarding and /resources/onboarding are different URLs and may both be live. Your /blog/$slug
route knows it wants a blog post; say so, or the answer is whichever row the index reached first.
A missing page is null. A broken service THROWS. Do not collapse the two. A client that turns "arcoseo
is down" into "this page does not exist" will serve a 404 to Google and delist a page that was fine. If a
read throws, let it 500 — a 500 tells a crawler to come back, a 404 tells it to forget.
Errors
Failures are ArcoseoClientError and carry the service's stable machine-readable code. Branch on the
code, never on a substring of the message:
catch (err) {
if (err instanceof ArcoseoClientError && err.code === 'VERSION_CONFLICT') { /* someone else edited */ }
}Versioning
The contract is the service's /v1 HTTP API, not this package. The client is a thin fetch wrapper
over it with zero runtime dependencies — an older client talking to a newer service simply does not know
about endpoints added since; it does not break.
