sanity#
Query Sanity, hydrate locally stored documents, and render CMS content.
Requirements#
A Sanity project for API calls. Local reference hydration requires a native
MongoDB database with document and draft collections.
Install#
npm i @nodedk/sanity
Usage#
Create a configured CMS instance. Pass your connected MongoDB database as db
when using local hydration:
var sanity = require('@nodedk/sanity')
var cms = sanity({
db,
locale: 'no-NB',
blockOptions: {
components: {}
},
clientOptions: {
projectId: 'project-id',
dataset: 'production',
apiVersion: '2025-02-06',
token: process.env.SANITY_TOKEN,
useCdn: false
}
})
Configuration#
sanity(options = {}) returns the configured CMS object.
db: native MongoDB database used bypublishedanddraft.clientOptions:projectId(default'test'),dataset(default'production'),apiVersion(default'2025-02-06', optional leadingv),token, anduseCdn(queries only, default false).markdownOptions: forwarded to markdown.blockOptions: Portable Text options, includingcomponents.locale: default date locale,'no-NB'.localeOptions:Intl.DateTimeFormatoptions for dates; default{ day: '2-digit', month: '2-digit', year: 'numeric' }.
Local hydration#
published(data) and draft(data) return Promises. They walk objects and
arrays in place and resolve Sanity _ref objects by _id. An unresolved
reference becomes {}. They read MongoDB, without fetching from Sanity.
Published hydration resolves document references from the document
collection and leaves all other values unchanged:
var data = await cms.published(document)
Draft hydration checks root documents and references in the draft collection
using their drafts.<id> IDs, then falls back to published documents:
var data = await cms.draft(document)
Content rendering#
block(state, content, options) converts Portable Text to an HTML string.
options replaces the configured blockOptions for that call. Custom
component functions receive (state, props) rather than only Portable Text
props. Missing content and arrays of blank text blocks return ''.
var { esc, html } = require('@nodedk/page')
var content = cms.block(state, document.content, {
components: {
types: {
notice: function (state, props) {
return html`<aside>${esc(props.value.text)}</aside>`
}
}
}
})
markdown(source = '') renders a Markdown block; inline(source = '')
renders inline Markdown without a paragraph wrapper. Both use the configured
markdownOptions; nullish input becomes ''. Results are strings by default,
or Promises when Marked’s async option is enabled. Raw HTML is preserved.
cms.markdown('## About\n\nA **short** introduction.')
cms.inline('A **short** title')
date(value, options = {}) formats a Date or date string. A YYYY-MM-DD
string is interpreted as a local calendar date. Unsupported or invalid values
return ''. options.locale and options.localeOptions override the
configured date settings for that call.
cms.date('2026-09-11')
cms.date('2026-09-11', {
locale: 'en-GB',
localeOptions: { day: 'numeric', month: 'long', year: 'numeric' }
})
Images and links#
image(node = {}) accepts a hydrated Sanity image node with asset.url and
optional crop/hotspot data. Returns a copy of the asset with its generated
image URL, or {} when the asset URL is missing.
var asset = cms.image(document.image)
console.log(asset.url)
link(node = {}) returns a URL string according to node.type, or '' when
the required data is missing:
'page':node.page.route.'file':node.file.asset.url.'image':node.image.asset.url.'url':node.url.'exhibit':node.exhibit.route, replacing:slugwithnode.document.slug.currentwhen present in the route.
route(node) reads node.route and expands /:slug with
node.slug.current. Missing routes or required slugs return ''.
cms.link({ type: 'url', url: 'https://example.com' })
cms.route({ route: '/articles/:slug', slug: { current: 'hello' } })
// '/articles/hello'
sanity.revive(value)#
Recursively replaces ISO timestamp strings with Dates and encoded regular
expressions such as '%r/hello/ig' with RegExps. Mutates objects and arrays
and returns the supplied or converted value. Existing Dates and RegExps are
preserved. Use it when restoring typed values from JSON.
var data = sanity.revive({
publishedAt: '2026-09-11T10:00:00Z',
pattern: '%r/hello/ig'
})
Client#
All four client methods return Promises. The configured token is sent as
a Bearer token with every request. useCdn affects queries; writes always use
the API endpoint.
client.fetch(query, params = {}, queryOptions = {})#
Runs a GROQ query and returns its result. params contains GROQ parameter
values; queryOptions is forwarded as API URL parameters, omitting nullish
values.
var pages = await cms.client.fetch(
'*[_type == $type]',
{ type: 'page' },
{ perspective: 'published' }
)
client.mutate(mutations, mutationOptions = {})#
Create, replace, update, and delete documents with mutation objects:
await cms.client.mutate({ create: { _type: 'page', title: 'New page' } })
await cms.client.mutate({
createOrReplace: { _id: 'page-1', _type: 'page', title: 'Page' }
})
await cms.client.mutate({
patch: { id: 'page-1', set: { title: 'Updated page' } }
})
await cms.client.mutate({ delete: { id: 'page-1' } })
Pass an array to run mutations in one transaction. Options are forwarded as Sanity API query parameters.
var result = await cms.client.mutate(
[
{ create: { _id: 'page-1', _type: 'page', title: 'Page' } },
{ patch: { id: 'settings', set: { home: 'page-1' } } }
],
{ returnDocuments: true, visibility: 'sync' }
)
Queries return the Sanity result. Mutations return the full response with
the transaction ID and mutation results.
client.action(actions)#
Create or edit drafts and publish documents with actions:
await cms.client.action({
actionType: 'sanity.action.document.edit',
publishedId: 'page-1',
draftId: 'drafts.page-1',
patch: { set: { title: 'Updated page' } }
})
await cms.client.action({
actionType: 'sanity.action.document.publish',
publishedId: 'page-1',
draftId: 'drafts.page-1'
})
Pass one action object or an array. Returns the full API response.
client.upload(type, body, uploadOptions = {})#
Upload image and file assets from a buffer, blob, or stream. type must be
'image' or 'file'; other values throw:
var image = await cms.client.upload('image', imageBuffer, {
filename: 'photo.png',
contentType: 'image/png'
})
var file = await cms.client.upload('file', fileStream, {
filename: 'document.pdf',
contentType: 'application/pdf'
})
Uploads return the created Sanity asset document. Upload options include
filename (defaults to body.name) and contentType (defaults to body.type).
Errors#
HTTP errors return a JARPC result. Network and invalid JSON errors reject.
var error = {
ok: false,
message: 'Forbidden',
code: 403,
details: { error: { description: 'Mutation denied' } }
}
Created by Vidar Eldøy