@atlas/client
A typed fetch client for /v1/public with ETag revalidation. Works in Node 22 and any runtime with fetch.
1 min read
Install
The four @atlas/* packages share one version and are published privately to GitHub Packages as @lifefuturedev/atlas-*. Write to [email protected] to get access for your team, then point the scope at GitHub Packages and alias the package.
@lifefuturedev:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}{
"dependencies": {
"@atlas/client": "npm:@lifefuturedev/[email protected]"
}
}Create a client
import { createAtlasClient } from '@atlas/client'
export const atlas = createAtlasClient({
baseUrl: 'https://api.atlascms.id',
token: process.env.ATLAS_TOKEN!,
timeoutMs: 8000,
})| Option | Description |
|---|---|
baseUrl | Required. The address of the API, with no trailing path. |
token | Required. A read token. |
previewToken | Optional. Replaces the token, makes drafts reachable and turns the cache off. |
fetch | Optional. Your own fetch. |
cache | Optional. An ETag cache to share. The default is an in-memory LRU of 500 responses. |
timeoutMs | Optional. Abort a request after this long. |
Methods
| Method | Returns |
|---|---|
getPage({ path, locale }) | The page, or null on a 404. Media is already resolved. |
getRoute({ path, locale }) | The route and theme of a path the page endpoint does not answer, or null. |
getEntries({ type, locale, cursor, limit, term, taxonomy, fields, count }) | { data, next_cursor, count }. |
getMenu(key, locale) | A menu with its items sanitised, or null. |
getTerms({ taxonomy, slug }) | A list of terms with their archive paths. |
getSettings() | The brand settings the registry marks public, or null. |
getTheme({ locale }) | { tokens, options }. |
getStrings({ locale, namespace }) | Interface strings, or null. |
getSitemapUrls(), getRedirects() | Lists for a sitemap and a redirect map. |
getLlms(locale), getLlmsText(locale) | Data or text for llms.txt. |
getManifest(), getIndexNowKey() | The web manifest and the IndexNow key. |
Read a page and a list
const page = await atlas.getPage({ path: '/pricing', locale: 'en' })
if (!page) throw new Error('No such page')
let cursor: string | undefined
const posts = []
do {
const batch = await atlas.getEntries({ type: 'post', locale: 'en', limit: 25, cursor })
posts.push(...batch.data)
cursor = batch.next_cursor ?? undefined
} while (cursor)Errors and caching
- A 404 returns
null. Any other failing status throws anAtlasApiErrorwithstatusandurl. - The client keeps the ETag of every response and sends
If-None-Matchnext time. A 304 returns the stored body, so repeated reads are cheap. - Use one client per brand and keep it alive. With a
previewTokennothing is cached, because the API answersprivate, no-store.
import { AtlasApiError } from '@atlas/client'
try {
await atlas.getPage({ path: '/' })
} catch (error) {
if (error instanceof AtlasApiError && error.status === 429) {
// back off and try again
}
throw error
}Was this page helpful?