@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.

.npmrcbash
@lifefuturedev:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}
package.jsonjson
{
  "dependencies": {
    "@atlas/client": "npm:@lifefuturedev/[email protected]"
  }
}

Create a client

atlas.tstypescript
import { createAtlasClient } from '@atlas/client'

export const atlas = createAtlasClient({
  baseUrl: 'https://api.atlascms.id',
  token: process.env.ATLAS_TOKEN!,
  timeoutMs: 8000,
})
OptionDescription
baseUrlRequired. The address of the API, with no trailing path.
tokenRequired. A read token.
previewTokenOptional. Replaces the token, makes drafts reachable and turns the cache off.
fetchOptional. Your own fetch.
cacheOptional. An ETag cache to share. The default is an in-memory LRU of 500 responses.
timeoutMsOptional. Abort a request after this long.

Methods

MethodReturns
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

read.tstypescript
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 an AtlasApiError with status and url.
  • The client keeps the ETag of every response and sends If-None-Match next time. A 304 returns the stored body, so repeated reads are cheap.
  • Use one client per brand and keep it alive. With a previewToken nothing is cached, because the API answers private, no-store.
errors.tstypescript
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?

Suggest a change