@stetcms/client
The typed content client your codegen writes, the REST client for everything else in the API, and the types every entry carries.
@stetcms/client is two clients in one package.
The content client is what you use day to day. You do not construct it:
codegen writes a stet.gen.ts that constructs it for
you, typed by your organization’s content model.
The REST client covers everything else in the API — organizations, billing, webhooks — as a fully typed call for every endpoint in the contract.
The content client
stet
The generated module exports a ready stet. Its keys are your collections and
maps:
import { stet } from './stet.gen';
const posts = await stet.posts.list(); // PostsEntry[]
const post = await stet.posts.get('hello-world'); // PostsEntry
const landing = await stet.landing.get(); // LandingEntry
A collection holds many entries and gets list() and get(slug). A
map holds exactly one and gets get() with no argument — the type system
knows which is which, so calling list() on a map is a compile error.
list()?Promise<E[]>
Every entry in the collection, oldest first. Collections only.
Promise<E[]>get(slug)?Promise<E>
One entry, addressed by its slug. Collections only.
Promise<E>get()?Promise<E>
The map's single entry. Maps only; throws if the map is empty.
Promise<E>Both reject with an Error carrying the status when a request fails, so a
missing slug surfaces as a rejected promise rather than undefined.
createContentClient
The function stet.gen.ts calls. Reach for it directly only when you need a
second client — a different organization, or a fetch you control:
import { createContentClient } from '@stetcms/client';
import type { StetContentModel } from './stet.gen';
const preview = createContentClient<StetContentModel>({
origin: 'https://stetcms.com',
apiKey: process.env.STET_PREVIEW_KEY,
});
origin?string
The Stet deployment to read from.
stringhttps://stetcms.comapiKey?string
Organization API key, sent as x-api-key.
stringfetch?typeof fetch
Override the fetch implementation, e.g. in tests.
typeof fetchThe runtime is one Proxy over the content API, so an unknown key costs
nothing and the module stays small.
What an entry holds
Every entry carries the same base, whatever its collection:
idstring
The entry's stable identifier.
stringslugstring
The addressable name, unique per collection.
stringtitlestring
The entry's title.
stringcreatedAtstring
ISO 8601.
stringupdatedAtstring
ISO 8601.
stringfieldsRecord<string, unknown>
The fields your content team defined, typed per collection.
Record<string, unknown>Everything under fields is optional and nullable, because an editor may not
have filled it in. See the content model for what each field
type becomes.
Assets and references
Two field types arrive as objects rather than scalars:
ContentAsset?{ id, url, name, contentType, size }
An uploaded file. url is fully qualified and public, so it goes straight into an img tag or a download link.
{ id, url, name, contentType, size }ContentReference?{ id, slug, title }
A pointer at an entry of another collection: enough to render a link, plus the slug to fetch the rest. The target collection is named in the generated field's doc comment.
{ id, slug, title }The API returns asset URLs relative to itself, since the same bytes serve
whichever origin you reach them through. The client joins them to the origin
it was configured with — including the ones an editor dropped inside a rich
text body — so what you get is ready to use on your own site.
If you call the REST API directly rather than through the client, do that join yourself:
assetUrl(url, origin)?string
Joins one asset path to an origin. Anything already absolute is left alone.
stringresolveAssetPaths(text, origin)?string
The same join applied inside a body's markdown: link and image destinations, and the src of any raw HTML.
stringThe REST client
createStetClient returns a typed call for every endpoint in the
contract, over oRPC:
import { createStetClient, isDefinedError, safe } from '@stetcms/client';
const client = createStetClient({ apiKey: process.env.STET_API_KEY });
const { data, error, isDefined } = await safe(client.org.current());
if (isDefined && error.code === 'UNAUTHORIZED') {
throw new Error('Invalid or revoked API key.');
}
origin?string
The Stet deployment.
stringhttps://stetcms.comapiKey?string
Organization API key, sent as x-api-key.
stringfetch?typeof fetch
Override the fetch implementation.
typeof fetchsafe and isDefinedError are re-exported from @orpc/client, so error
handling needs no second dependency. safe turns a rejection into a result
object; isDefined tells you the error came from the contract rather than the
network, which is what makes error.code safe to switch on.
Exports
createContentClient?function
The model-shaped content client. Called for you by stet.gen.ts.
functioncreateStetClient?function
The typed REST client for the rest of the API.
functionassetUrl?function
Join an asset path to an origin.
functionresolveAssetPaths?function
Join every asset path inside a body's markdown.
functionsafe?function
Re-export from @orpc/client: a rejection as a result object.
functionisDefinedError?function
Re-export from @orpc/client: whether an error came from the contract.
functionDEFAULT_ORIGIN?string
https://stetcms.com
stringApiInputs?type
Inputs of every contract procedure, keyed by path.
typeApiOutputs?type
Outputs of every contract procedure, keyed by path.
typeStetClient?type
The REST client type.
typeContentClient?type
The content client, given a model shape.
typeContentModelShape?type
What stet.gen.ts generates: each key carries a kind and an entry type.
typeContentEntryBase?type
The fields every entry carries.
typeContentAsset?type
An asset field's value.
typeContentReference?type
A reference field's value.
typeCollectionClient?type
list() and get(slug).
typeMapClient?type
get().
type@stetcms/client/codegen is a second entry point holding fetchContentModel,
renderContentModule and entryTypeName. It is documented under
codegen.