@sanity/client
Version:
Client for retrieving, creating and patching data from Sanity.io
2,604 lines • 68 kB
text/typescript
// deno-lint-ignore-file no-empty-interface
import type {FetchFunction, RequestOptions as GetItRequestOptions} from 'get-it'
import type {Observable} from 'rxjs'
import type {InitializedStegaConfig, StegaConfig} from './stega/types'
/**
* Low-level requester returned by `defineRequester(...).observable`.
* Surfaces as `client.config().requester` and as the named `requester`
* export.
*
* Defined locally rather than imported from `http/request` so api-extractor
* inlines it into the bundled `.d.ts` instead of emitting a relative import
* that doesn't survive into `dist/` ([#1290][]).
*
* [#1290]: https://github.com/sanity-io/client/issues/1290
*
* @public
*/
export type Requester = (options: Any) => Observable<unknown>
/**
* Used to tag types that is set to `any` as a temporary measure, but should be replaced with proper typings in the future
* @internal
*/
export type Any = any // oxlint-disable-line typescript/no-explicit-any
declare global {
// Declare empty stub interfaces for environments where "dom" lib is not included
interface File {}
}
/** @public */
export type UploadBody = File | Blob | Buffer | NodeJS.ReadableStream
/** @public */
export interface RequestOptions {
timeout?: number
token?: string
tag?: string
headers?: Record<string, string>
method?: string
query?: Any
body?: Any
signal?: AbortSignal
}
/**
* The fully resolved request passed to a {@link RequestHandler}.
*
* @public
*/
export type RequestHandlerOptions = GetItRequestOptions
/**
* Intercepts a client request around the normal HTTP pipeline.
*
* Call `next(request)` to execute the request. It resolves to the parsed
* response body and rejects with the same errors the client normally exposes,
* including {@link ClientError} and {@link ServerError}. A handler can modify
* the request, retry it by calling `next` again, or return a synthetic body.
*
* Browser asset uploads and server-sent event connections do not use this handler.
*
* @public
*/
export type RequestHandler = (
request: RequestHandlerOptions,
next: (request: RequestHandlerOptions) => Promise<unknown>,
) => Promise<unknown>
/**
* @public
* @deprecated – The `r`-prefix is not required, use `string` instead
*/
export type ReleaseId = `r${string}`
/**
* @deprecated use 'drafts' instead
*/
type DeprecatedPreviewDrafts = 'previewDrafts'
/** @public */
export type StackablePerspective = 'published' | 'drafts' | (string & {})
/** @public */
export type ClientPerspective =
| DeprecatedPreviewDrafts
| 'published'
| 'drafts'
| 'raw'
| StackablePerspective[]
/**
* @public
* @beta
*/
export type ClientVariantConditions = Record<string, string>
/**
* @public
* @beta
*/
export type ClientVariant = ClientVariantConditions | string
type ClientConfigResource =
| {
type: 'canvas'
id: string
}
| {
type: 'knowledge-base'
id: string
}
| {
type: 'media-library'
id: string
}
| {
type: 'dataset'
id: string
}
| {
type: 'dashboard'
id: string
}
/** @public */
export interface ClientConfig {
projectId?: string
dataset?: string
/** @defaultValue true */
useCdn?: boolean
token?: string
/**
* Configure the client to work with a specific Sanity resource (Media Library, Canvas, etc.)
* @remarks
* This allows the client to interact with resources beyond traditional project datasets.
* When configured, methods like `fetch()`, `assets.upload()`, and mutations will operate on the specified resource.
* @example
* ```ts
* createClient({
* resource: {
* type: 'media-library',
* id: 'your-media-library-id'
* }
* })
* ```
*/
resource?: ClientConfigResource
/**
* @deprecated Use `resource` instead
* @internal
*/
'~experimental_resource'?: ClientConfigResource
/**
* What perspective to use for the client. See {@link https://www.sanity.io/docs/perspectives|perspective documentation}
* @remarks
* As of API version `v2025-02-19`, the default perspective has changed from `raw` to `published`. {@link https://www.sanity.io/changelog/676aaa9d-2da6-44fb-abe5-580f28047c10|Changelog}
* @defaultValue 'published'
*/
perspective?: ClientPerspective
/**
* @beta
*/
variant?: ClientVariant
apiHost?: string
/**
@remarks
* As of API version `v2025-02-19`, the default perspective has changed from `raw` to `published`. {@link https://www.sanity.io/changelog/676aaa9d-2da6-44fb-abe5-580f28047c10|Changelog}
*/
apiVersion?: string
/**
* Route requests through an HTTP(S) proxy. Node.js only. Can be replaced
* on an existing client via `client.config({proxy})` or
* `client.withConfig({proxy})`. For environment-driven proxying, set
* `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY` before the process starts.
*/
proxy?: string
/**
* Optional request tag prefix for all request tags
*/
requestTagPrefix?: string
/**
* Intercepts requests after the client has resolved their URL, headers, and
* transport options. The handler wraps the normal client pipeline, so errors
* from `next` are already converted to {@link ClientError} or
* {@link ServerError}.
*
* A handler supplied through `withConfig()` replaces the current handler.
* To compose handlers, read the current handler from `client.config()` and
* call it from the replacement.
*
* Browser asset uploads and server-sent event connections are not intercepted.
*/
requestHandler?: RequestHandler
/**
* Optional default headers to include with all requests
*
* @remarks request-specific headers will override any default headers with the same name.
*/
headers?: Record<string, string>
ignoreBrowserTokenWarning?: boolean
/**
* Ignore specific warning messages from the client.
*
* @remarks
* - String values perform substring matching (not exact matching) against warning messages
* - RegExp values are tested against the full warning message
* - Array values allow multiple patterns to be specified
*
* @example
* ```typescript
* // Ignore warnings containing "experimental"
* ignoreWarnings: 'experimental'
*
* // Ignore multiple warning types
* ignoreWarnings: ['experimental', 'deprecated']
*
* // Use regex for exact matching
* ignoreWarnings: /^This is an experimental API version$/
*
* // Mix strings and regex patterns
* ignoreWarnings: ['rate limit', /^deprecated/i]
* ```
*/
ignoreWarnings?: string | RegExp | Array<string | RegExp>
withCredentials?: boolean
allowReconfigure?: boolean
timeout?: number
/** Number of retries for requests. Defaults to 5. */
maxRetries?: number
/**
* The amount of time, in milliseconds, to wait before retrying, given an attemptNumber (starting at 0).
*
* Defaults to exponential back-off, starting at 100ms, doubling for each attempt, together with random
* jitter between 0 and 100 milliseconds. More specifically the following algorithm is used:
*
* Delay = 100 * 2^attemptNumber + randomNumberBetween0and100
*/
retryDelay?: (attemptNumber: number) => number
/**
* @deprecated Don't use
*/
useProjectHostname?: boolean
/**
* Resolves the fetch implementation every request (including EventSource
* connections) goes through. Defaults to the environment entry point's
* fetch — the Node entry supplies get-it's undici-backed fetch (resolved
* via the entry point instead of a direct import so `get-it/node`/`undici`
* stays out of the browser bundle), the browser entry leaves it unset (the
* global fetch IS the environment's fetch there). Receives the explicit
* `proxy` config, when set, as its argument.
*
* Supplying it in the client config replaces the transport wholesale —
* custom fetch variants, alternative undici configurations, or a mock
* (the test suite injects `get-it/mock` this way).
*
* Returns get-it's minimal `FetchFunction` contract rather than the full
* `typeof fetch` — that is what the environments actually provide, and
* every consumer (the transport, the EventSource fetch resolver) only
* needs that subset.
*
* @internal
*/
resolveFetch?: (proxyUrl?: string) => FetchFunction
/**
* Adds a `resultSourceMap` key to the API response, with the type `ContentSourceMap`
*/
resultSourceMap?: boolean | 'withKeyArraySelector'
/**
* @deprecated set `cache` and `next` options on `client.fetch` instead
*/
fetch?:
| {
cache?: ResponseQueryOptions['cache']
next?: ResponseQueryOptions['next']
}
| boolean
/**
* Options for how, if enabled, Content Source Maps are encoded into query results using steganography
*/
stega?: StegaConfig | boolean
/**
* Lineage token for recursion control
*/
lineage?: string
/**
* ID of the blueprints stack that `functions.invoke()` resolves function
* names against. Function names are unique within a stack
*/
stackId?: string
/**
* ID of the organization owning the blueprints stack
*/
organizationId?: string
/**
* Organization-scoped configuration for collaboration APIs.
*
* Currently this is used by `collaboration.comments` methods.
*
* @alpha
*/
collaboration?: {
organizationId?: string
}
/**
* Organization-scoped configuration for Context APIs.
*
* Currently this is used by `context.insights` methods.
*
* @beta
*/
context?: {
organizationId?: string
}
}
/** @public */
export interface InitializedClientConfig extends ClientConfig {
// These are required in the initialized config
apiHost: string
apiVersion: string
useProjectHostname: boolean
useCdn: boolean
// These are added by the initConfig function
/**
* @deprecated Internal, don't use
*/
isDefaultApi: boolean
/**
* @deprecated Internal, don't use
*/
url: string
/**
* @deprecated Internal, don't use
*/
cdnUrl: string
/**
* The fully initialized stega config, can be used to check if stega is enabled
*/
stega: InitializedStegaConfig
/**
* The resolved low-level requester for this client. Always populated by
* `createClient` so internal paths (e.g. the asset upload event stream) can
* reach the underlying transport.
*
* @internal
*/
requester: Requester
/**
* Default headers to include with all requests
*
* @remarks request-specific headers will override any default headers with the same name.
*/
headers?: Record<string, string>
}
/** @public */
export type AssetMetadataType =
| 'location'
| 'exif'
| 'image'
| 'palette'
| 'lqip'
| 'blurhash'
| 'thumbhash'
| 'none'
/** @public */
export interface UploadClientConfig {
/**
* Optional request tag for the upload
*/
tag?: string
/**
* Whether or not to preserve the original filename (default: true)
*/
preserveFilename?: boolean
/**
* Filename for this file (optional)
*/
filename?: string
/**
* Milliseconds to wait before timing the request out.
*
* Unlike other requests, uploads have NO timeout unless one is explicitly
* set here — uploads can legitimately be slow, so timing out is opt-in.
*/
timeout?: number
/**
* Mime type of the file
*/
contentType?: string
/**
* Array of metadata parts to extract from asset
*/
extract?: AssetMetadataType[]
/**
* Optional freeform label for the asset. Generally not used.
*/
label?: string
/**
* Optional title for the asset
*/
title?: string
/**
* Optional description for the asset
*/
description?: string
/**
* The credit to person(s) and/or organization(s) required by the supplier of the asset to be used when published
*/
creditLine?: string
/**
* Source data (when the asset is from an external service)
*/
source?: {
/**
* The (u)id of the asset within the source, i.e. 'i-f323r1E'
*/
id: string
/**
* The name of the source, i.e. 'unsplash'
*/
name: string
/**
* A url to where to find the asset, or get more info about it in the source
*/
url?: string
}
}
/** @internal */
export interface SanityReference {
_ref: string
}
/** @internal */
export type SanityDocument<T extends Record<string, Any> = Record<string, Any>> = {
[P in keyof T]: T[P]
} & {
_id: string
_rev: string
_type: string
_createdAt: string
_updatedAt: string
/**
* Present when `perspective` is set to `previewDrafts`
*/
_originalId?: string
}
/** @internal */
export interface SanityAssetDocument extends SanityDocument {
url: string
path: string
size: number
assetId: string
mimeType: string
sha1hash: string
extension: string
uploadId?: string
originalFilename?: string
}
/** @internal */
export interface SanityImagePalette {
background: string
foreground: string
population: number
title: string
}
/** @internal */
export interface SanityImageAssetDocument extends SanityAssetDocument {
metadata: {
_type: 'sanity.imageMetadata'
hasAlpha: boolean
isOpaque: boolean
lqip?: string
blurHash?: string
thumbHash?: string
dimensions: {
_type: 'sanity.imageDimensions'
aspectRatio: number
height: number
width: number
}
palette?: {
_type: 'sanity.imagePalette'
darkMuted?: SanityImagePalette
darkVibrant?: SanityImagePalette
dominant?: SanityImagePalette
lightMuted?: SanityImagePalette
lightVibrant?: SanityImagePalette
muted?: SanityImagePalette
vibrant?: SanityImagePalette
}
image?: {
_type: 'sanity.imageExifTags'
[key: string]: Any
}
exif?: {
_type: 'sanity.imageExifMetadata'
[key: string]: Any
}
}
}
/** @public */
export interface ErrorProps {
message: string
response: Any
statusCode: number
responseBody: Any
traceId?: string
details: Any
}
/**
* The internal HTTP request abstraction used by the client. Resolves directly
* to the parsed response body as a Promise — middleware-level transport
* details (status codes, headers, progress events) are not exposed. The
* observable client surface wraps this in an Observable; the promise surface
* uses it directly.
*
* The body is typed as `unknown`; consumers narrow at their own boundary.
*
* @internal
*/
export type HttpRequest = {
(options: Any, requestHandler?: RequestHandler): Promise<unknown>
}
/**
* Target URL for a request. Exactly one of `url` or the deprecated `uri` alias
* must be given.
*
* @internal
*/
export type RequestUrlOptions =
| {url: string; uri?: never}
| {
/**
* @deprecated Use `url` instead. Support for `uri` will be removed in a future version.
*/
uri: string
url?: never
}
/** @internal */
export type RequestObservableOptions = RequestUrlOptions &
Omit<RequestOptions, 'url'> & {
canUseCdn?: boolean
useCdn?: boolean
tag?: string
returnQuery?: boolean
resultSourceMap?: boolean | 'withKeyArraySelector'
perspective?: ClientPerspective
/**
* @beta
*/
variant?: ClientVariant
lastLiveEventId?: string
cacheMode?: 'noStale'
}
/** @public */
export interface UploadProgressEvent {
type: 'progress'
stage: 'upload' | 'download'
percent: number
total?: number
loaded?: number
lengthComputable: boolean
}
/** @public */
export interface UploadResponseEvent<T = unknown> {
type: 'response'
body: T
}
/**
* Events emitted by `client.assets.upload()` when called via the observable
* API. Progress events are best-effort — they're only emitted when the
* environment supports tracking upload/download bytes (e.g. browsers via
* `XMLHttpRequest`). Other runtimes only emit the terminal `response` event.
*
* @public
*/
export type UploadEvent<T = unknown> = UploadResponseEvent<T> | UploadProgressEvent
/** @internal */
export interface AuthProvider {
name: string
title: string
url: string
}
/** @internal */
export type AuthProviderResponse = {providers: AuthProvider[]}
/** @public */
export type DatasetAclMode = 'public' | 'private' | 'custom'
/** @public */
export type DatasetCreateOptions = {
aclMode?: DatasetAclMode
description?: string
embeddings?: {
enabled: boolean
projection?: string
}
}
/** @public */
export type DatasetEditOptions = {
aclMode?: DatasetAclMode
description?: string
}
/** @public */
export type EmbeddingsSettings = {
enabled: boolean
projection?: string
status: string
}
/** @public */
export type EmbeddingsSettingsBody = {
enabled: boolean
projection?: string
}
/** @public */
export type DatasetResponse = {datasetName: string; aclMode: DatasetAclMode; description: string}
/** @public */
export type DatasetsResponse = {
name: string
aclMode: DatasetAclMode
description: string
createdAt: string
createdByUserId: string
addonFor: string | null
datasetProfile: string
features: string[]
tags: {
name: string
title: string
}[]
}[]
/** @public */
export interface SanityProjectMember {
id: string
role: string
isRobot: boolean
isCurrentUser: boolean
}
/** @public */
export interface SanityProject {
id: string
displayName: string
/**
* @deprecated Use the `/user-applications` endpoint instead, which lists all deployed studios/applications
* @see https://www.sanity.io/help/studio-host-user-applications
*/
studioHost: string | null
organizationId: string | null
isBlocked: boolean
isDisabled: boolean
isDisabledByUser: boolean
createdAt: string
pendingInvites?: number
maxRetentionDays?: number
members: SanityProjectMember[]
features: string[]
metadata: {
cliInitializedAt?: string
color?: string
/**
* @deprecated Use the `/user-applications` endpoint instead, which lists all deployed studios/applications
* @see https://www.sanity.io/help/studio-host-user-applications
*/
externalStudioHost?: string
}
}
/** @public */
export interface SanityUser {
id: string
projectId: string
displayName: string
familyName: string | null
givenName: string | null
middleName: string | null
imageUrl: string | null
createdAt: string
updatedAt: string
isCurrentUser: boolean
}
/** @public */
export interface CurrentSanityUser {
id: string
name: string
email: string
profileImage: string | null
role: string
provider: string
}
/** @public */
export type SanityDocumentStub<T extends Record<string, Any> = Record<string, Any>> = {
[P in keyof T]: T[P]
} & {
_type: string
}
/** @public */
export type IdentifiedSanityDocumentStub<T extends Record<string, Any> = Record<string, Any>> = {
[P in keyof T]: T[P]
} & {
_id: string
} & SanityDocumentStub
/** @internal */
export type InsertPatch =
| {before: string; items: Any[]}
| {after: string; items: Any[]}
| {replace: string; items: Any[]}
// Note: this is actually incorrect/invalid, but implemented as-is for backwards compatibility
/** @internal */
export interface PatchOperations {
set?: {[key: string]: Any}
setIfMissing?: {[key: string]: Any}
diffMatchPatch?: {[key: string]: Any}
unset?: string[]
inc?: {[key: string]: number}
dec?: {[key: string]: number}
insert?: InsertPatch
ifRevisionID?: string
}
/** @public */
export interface QueryParams {
/* oxlint-disable typescript/no-explicit-any */
[key: string]: any
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
body?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
cache?: 'next' extends keyof RequestInit ? never : any
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
filterResponse?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
headers?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
method?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
next?: 'next' extends keyof RequestInit ? never : any
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
perspective?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
variant?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
query?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
resultSourceMap?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
returnQuery?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
signal?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
stega?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
tag?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
timeout?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
token?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
useCdn?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
lastLiveEventId?: never
/** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */
cacheMode?: never
/* oxlint-enable typescript/no-explicit-any */
}
/**
* This type can be used with `client.fetch` to indicate that the query has no GROQ parameters.
* @public
*/
export type QueryWithoutParams = Record<string, never> | undefined
/** @internal */
export type MutationSelectionQueryParams = {[key: string]: Any}
/** @internal */
export type MutationSelection =
| {query: string; params?: MutationSelectionQueryParams}
| {id: string | string[]}
/** @internal */
export type PatchSelection = string | string[] | MutationSelection
/** @internal */
export type PatchMutationOperation = PatchOperations & MutationSelection
/** @public */
export type Mutation<R extends Record<string, Any> = Record<string, Any>> =
| {create: SanityDocumentStub<R>}
| {createOrReplace: IdentifiedSanityDocumentStub<R>}
| {createIfNotExists: IdentifiedSanityDocumentStub<R>}
| {delete: MutationSelection}
| {patch: PatchMutationOperation}
/** @public */
export type ReleaseAction =
| CreateReleaseAction
| EditReleaseAction
| PublishReleaseAction
| ArchiveReleaseAction
| UnarchiveReleaseAction
| ScheduleReleaseAction
| UnscheduleReleaseAction
| DeleteReleaseAction
| ImportReleaseAction
/**
* @public
* @beta
*/
export type VariantDefinitionAction =
| CreateVariantDefinitionAction
| EditVariantDefinitionAction
| DeleteVariantDefinitionAction
/** @public */
export type VersionAction =
| CreateVersionAction
| DiscardVersionAction
| ReplaceVersionAction
| UnpublishVersionAction
/**
* @public
* @beta
*/
export type VariantAction =
| CreateVariantAction
| EditVariantAction
| DeleteVariantAction
| PublishVariantAction
| UnpublishVariantAction
/** @public */
export type Action =
| CreateAction
| ReplaceDraftAction
| EditAction
| DeleteAction
| DiscardAction
| PublishAction
| UnpublishAction
| VersionAction
| VariantAction
| ReleaseAction
| VariantDefinitionAction
/** @public */
export type ImportReleaseAction =
| {
actionType: 'sanity.action.release.import'
attributes: IdentifiedSanityDocumentStub
releaseId: string
ifExists: 'fail' | 'ignore' | 'replace'
}
| {
actionType: 'sanity.action.release.import'
document: IdentifiedSanityDocumentStub
releaseId: string
ifExists: 'fail' | 'ignore' | 'replace'
}
/**
* Creates a new release under the given id, with metadata.
*
* @public
*/
export interface CreateReleaseAction {
actionType: 'sanity.action.release.create'
releaseId: string
metadata?: Partial<ReleaseDocument['metadata']>
}
/**
* Edits an existing release, updating the metadata.
*
* @public
*/
export interface EditReleaseAction {
actionType: 'sanity.action.release.edit'
releaseId: string
patch: PatchOperations
}
/**
* Publishes all documents in a release at once.
*
* @public
*/
export interface PublishReleaseAction {
actionType: 'sanity.action.release.publish'
releaseId: string
}
/**
* Archives an `active` release, and deletes all the release documents.
*
* @public
*/
export interface ArchiveReleaseAction {
actionType: 'sanity.action.release.archive'
releaseId: string
}
/**
* Unarchived an `archived` release, and restores all the release documents.
*
* @public
*/
export interface UnarchiveReleaseAction {
actionType: 'sanity.action.release.unarchive'
releaseId: string
}
/**
* Queues release for publishing at the given future time.
*
* @public
*/
export interface ScheduleReleaseAction {
actionType: 'sanity.action.release.schedule'
releaseId: string
publishAt: string
}
/**
* Unschedules a `scheduled` release, stopping it from being published.
*
* @public
*/
export interface UnscheduleReleaseAction {
actionType: 'sanity.action.release.unschedule'
releaseId: string
}
/**
* Deletes a `archived` or `published` release, and all the release documents versions.
*
* @public
*/
export interface DeleteReleaseAction {
actionType: 'sanity.action.release.delete'
releaseId: string
}
/**
* Creates a new version of an existing document.
*
* If the `document` is provided, the version is created from the document
* attached to the release as given by `document._id`
*
* If the `baseId` and `versionId` are provided, the version is created from the base document
* and the version is attached to the release as given by `publishedId` and `versionId`
*
* @public
*/
export type CreateVersionAction = {
actionType: 'sanity.action.document.version.create'
publishedId: string
} & (
| {
document: IdentifiedSanityDocumentStub
}
| {
baseId: string
versionId: string
ifBaseRevisionId?: string
}
)
/**
* Delete a version of a document.
*
* @public
*/
export interface DiscardVersionAction {
actionType: 'sanity.action.document.version.discard'
versionId: string
purge?: boolean
}
/**
* Replace an existing version of a document.
*
* @public
*/
export interface ReplaceVersionAction {
actionType: 'sanity.action.document.version.replace'
document: IdentifiedSanityDocumentStub
}
/**
* Identify that a version of a document should be unpublished when
* the release that version is contained within is published.
*
* @public
*/
export interface UnpublishVersionAction {
actionType: 'sanity.action.document.version.unpublish'
versionId: string
publishedId: string
}
/**
* Creates a variant of a document, either by supplying the full document
* content, or the base ID of a document to copy.
*
* @public
* @beta
*/
export type CreateVariantAction = {
actionType: 'sanity.action.document.variant.create'
/**
* ID of the document group to create a variant in. Must be a published
* document ID, without a `drafts.` or `versions.` prefix.
*/
publishedId: string
/**
* Name of the variant definition this document belongs to, as in
* `_.variants.{variantName}`. Must be a bare name, not a full document ID.
*/
variantId: string
/**
* Source bundle: `'drafts'`, or a release id.
*
* Defaults to the published bundle.
*/
bundleId?: 'drafts' | (string & {})
} & (
| {
/**
* The full document content. Requires a `_type` property.
*/
document: SanityDocumentStub
baseId?: never
ifBaseRevisionId?: never
}
| {
/**
* ID of an existing document to copy the content from.
*/
baseId: string
/**
* When set, the action fails unless the current revision of the base
* document matches this value.
*/
ifBaseRevisionId?: string
document?: never
}
)
/**
* Modifies a variant version of a document by applying a patch.
*
* If no such variant document exists it is first created, by copying the
* variant's published sibling, or the published document if the variant was
* never published.
*
* @public
* @beta
*/
export interface EditVariantAction {
actionType: 'sanity.action.document.variant.edit'
/**
* ID of the document group the variant belongs to. Must be a published
* document ID, without a `drafts.` or `versions.` prefix.
*/
publishedId: string
/**
* Name of the variant definition this document belongs to, as in
* `_.variants.{variantName}`. Must be a bare name, not a full document ID.
*/
variantId: string
/**
* Source bundle: `'drafts'`, or a release id.
*
* Defaults to the published bundle.
*/
bundleId?: 'drafts' | (string & {})
/**
* Patch operations to apply.
*/
patch: PatchOperations
}
/**
* Deletes a variant of a document.
*
* @public
* @beta
*/
export interface DeleteVariantAction {
actionType: 'sanity.action.document.variant.delete'
/**
* ID of the document group the variant belongs to. Must be a published
* document ID, without a `drafts.` or `versions.` prefix.
*/
publishedId: string
/**
* Name of the variant definition this document belongs to, as in
* `_.variants.{variantName}`. Must be a bare name, not a full document ID.
*/
variantId: string
/**
* Source bundle: `'drafts'`, or a release id.
*
* Defaults to the published bundle.
*/
bundleId?: 'drafts' | (string & {})
/**
* Delete document history.
*/
purge?: boolean
}
/**
* Publishes a variant version of a document, replacing the published variant
* and removing the source variant document.
*
* @public
* @beta
*/
export interface PublishVariantAction {
actionType: 'sanity.action.document.variant.publish'
/**
* ID of the document group the variant belongs to. Must be a published
* document ID, without a `drafts.` or `versions.` prefix.
*/
publishedId: string
/**
* Name of the variant definition this document belongs to, as in
* `_.variants.{variantName}`. Must be a bare name, not a full document ID.
*/
variantId: string
/**
* Bundle to publish from: `'drafts'`, or a release id.
*/
bundleId: 'drafts' | (string & {})
/**
* When set, publishing fails unless the current revision of the source
* variant document matches this value.
*/
ifVersionRevisionId?: string
/**
* When set, publishing fails unless the current revision of the published
* variant document matches this value.
*/
ifPublishedVariantRevisionId?: string
}
/**
* Unpublishes a variant version of a document.
*
* By default the published variant is removed and preserved as a draft
* variant. When a release id is given as the `bundleId`, the deletion is
* instead staged in that release, and takes effect when it is published.
*
* @public
* @beta
*/
export interface UnpublishVariantAction {
actionType: 'sanity.action.document.variant.unpublish'
/**
* ID of the document group the variant belongs to. Must be a published
* document ID, without a `drafts.` or `versions.` prefix.
*/
publishedId: string
/**
* Name of the variant definition this document belongs to, as in
* `_.variants.{variantName}`. Must be a bare name, not a full document ID.
*/
variantId: string
/**
* The content release in which to stage the unpublish.
*
* By default, the currently published document is unpublished immediately.
*/
bundleId?: string
}
/**
* Creates a new `system.variant` definition document.
*
* @public
* @beta
*/
export interface CreateVariantDefinitionAction {
actionType: 'sanity.action.variant.definition.create'
/**
* Name of the variant definition to create, as in
* `_.variants.{variantName}`. Must be a bare name, not a full document ID.
*/
variantId: string
/**
* Conditions used to select this variant.
*/
conditions?: ClientVariantConditions
/**
* Selection priority. Higher values are preferred when multiple variants
* match.
*
* Defaults to `0`.
*/
priority?: number
metadata?: Record<string, Any>
}
/**
* Edits an existing variant definition.
*
* @public
* @beta
*/
export interface EditVariantDefinitionAction {
actionType: 'sanity.action.variant.definition.edit'
/**
* Name of the variant definition to edit, as in `_.variants.{variantName}`.
* Must be a bare name, not a full document ID.
*/
variantId: string
/**
* Patch operations to apply.
*/
patch: PatchOperations
/**
* When set, the action fails unless the current revision of the variant
* definition matches this value.
*/
ifRevisionId?: string
}
/**
* Deletes a variant definition.
*
* Deletion fails if any document holds a strong reference to this variant.
*
* @public
* @beta
*/
export interface DeleteVariantDefinitionAction {
actionType: 'sanity.action.variant.definition.delete'
/**
* Name of the variant definition to delete, as in
* `_.variants.{variantName}`. Must be a bare name, not a full document ID.
*/
variantId: string
/**
* When set, the action fails unless the current revision of the variant
* definition matches this value.
*/
ifRevisionId?: string
}
/**
* Creates a new draft document. The published version of the document must not already exist.
* If the draft version of the document already exists the action will fail by default, but
* this can be adjusted to instead leave the existing document in place.
*
* @public
*/
export type CreateAction = {
actionType: 'sanity.action.document.create'
/**
* ID of the published document to create a draft for.
*/
publishedId: string
/**
* Document to create. Requires a `_type` property.
*/
attributes: IdentifiedSanityDocumentStub
/**
* ifExists controls what to do if the draft already exists
*/
ifExists: 'fail' | 'ignore'
}
/**
* Replaces an existing draft document.
* At least one of the draft or published versions of the document must exist.
*
* @public
* @deprecated Use {@link ReplaceVersionAction} instead
*/
export type ReplaceDraftAction = {
actionType: 'sanity.action.document.replaceDraft'
/**
* Published document ID to create draft from, if draft does not exist
*/
publishedId: string
/**
* Document to create if it does not already exist. Requires `_id` and `_type` properties.
*/
attributes: IdentifiedSanityDocumentStub
}
/**
* Modifies an existing draft document.
* It applies the given patch to the document referenced by draftId.
* If there is no such document then one is created using the current state of the published version and then that is updated accordingly.
*
* @public
*/
export type EditAction = {
actionType: 'sanity.action.document.edit'
/**
* Draft document ID to edit
*/
draftId: string
/**
* Published document ID to create draft from, if draft does not exist
*/
publishedId: string
/**
* Patch operations to apply
*/
patch: PatchOperations
}
/**
* Deletes the published version of a document and optionally some (likely all known) draft versions.
* If any draft version exists that is not specified for deletion this is an error.
* If the purge flag is set then the document history is also deleted.
*
* @public
*/
export type DeleteAction = {
actionType: 'sanity.action.document.delete'
/**
* Published document ID to delete
*/
publishedId: string
/**
* Draft document ID to delete
*/
includeDrafts: string[]
/**
* Delete document history
*/
purge?: boolean
}
/**
* Delete the draft version of a document.
* It is an error if it does not exist. If the purge flag is set, the document history is also deleted.
*
* @public
* @deprecated Use {@link DiscardVersionAction} instead
*/
export type DiscardAction = {
actionType: 'sanity.action.document.discard'
/**
* Draft document ID to delete
*/
draftId: string
/**
* Delete document history
*/
purge?: boolean
}
/**
* Publishes a draft document.
* If a published version of the document already exists this is replaced by the current draft document.
* In either case the draft document is deleted.
* The optional revision id parameters can be used for optimistic locking to ensure
* that the draft and/or published versions of the document have not been changed by another client.
*
* @public
*/
export type PublishAction = {
actionType: 'sanity.action.document.publish'
/**
* Draft document ID to publish
*/
draftId: string
/**
* Draft revision ID to match
*/
ifDraftRevisionId?: string
/**
* Published document ID to replace
*/
publishedId: string
/**
* Published revision ID to match
*/
ifPublishedRevisionId?: string
}
/**
* Retract a published document.
* If there is no draft version then this is created from the published version.
* In either case the published version is deleted.
*
* @public
*/
export type UnpublishAction = {
actionType: 'sanity.action.document.unpublish'
/**
* Draft document ID to replace the published document with
*/
draftId: string
/**
* Published document ID to delete
*/
publishedId: string
}
/**
* A mutation was performed. Note that when updating multiple documents in a transaction,
* each document affected will get a separate mutation event.
*
* @public
*/
export type MutationEvent<R extends Record<string, Any> = Record<string, Any>> = {
type: 'mutation'
/**
* The ID of the document that was affected
*/
documentId: string
/**
* A unique ID for this event
*/
eventId: string
/**
* The user ID of the user that performed the mutation
*/
identity: string
/**
* An array of mutations that were performed. Note that this can differ slightly from the
* mutations sent to the server, as the server may perform some mutations automatically.
*/
mutations: Mutation[]
/**
* The revision ID of the document before the mutation was performed
*/
previousRev?: string
/**
* The revision ID of the document after the mutation was performed
*/
resultRev?: string
/**
* The document as it looked after the mutation was performed. This is only included if
* the listener was configured with `includeResult: true`.
*/
result?: SanityDocument<R>
/**
* The document as it looked before the mutation was performed. This is only included if
* the listener was configured with `includePreviousRevision: true`.
*/
previous?: SanityDocument<R> | null
/**
* The effects of the mutation, if the listener was configured with `effectFormat: 'mendoza'`.
* Object with `apply` and `revert` arrays, see {@link https://github.com/sanity-io/mendoza}.
*/
effects?: {apply: unknown[]; revert: unknown[]}
/**
* A timestamp for when the mutation was performed
*/
timestamp: string
/**
* The transaction ID for the mutation
*/
transactionId: string
/**
* The type of transition the document went through.
*
* - `update` means the document was previously part of the subscribed set of documents,
* and still is.
* - `appear` means the document was not previously part of the subscribed set of documents,
* but is now. This can happen both on create or if updating to a state where it now matches
* the filter provided to the listener.
* - `disappear` means the document was previously part of the subscribed set of documents,
* but is no longer. This can happen both on delete or if updating to a state where it no
* longer matches the filter provided to the listener.
*/
transition: 'update' | 'appear' | 'disappear'
/**
* Whether the change that triggered this event is visible to queries (query) or only to
* subsequent transactions (transaction). The listener client can specify a preferred visibility
* through the `visibility` parameter on the listener, but this is only on a best-effort basis,
* and may yet not be accurate.
*/
visibility: 'query' | 'transaction'
/**
* The total number of events that will be sent for this transaction.
* Note that this may differ from the amount of _documents_ affected by the transaction, as this
* number only includes the documents that matches the given filter.
*
* This can be useful if you need to perform changes to all matched documents atomically,
* eg you would wait for `transactionTotalEvents` events with the same `transactionId` before
* applying the changes locally.
*/
transactionTotalEvents: number
/**
* The index of this event within the transaction. Note that events may be delivered out of order,
* and that the index is zero-based.
*/
transactionCurrentEvent: number
}
/**
* An error occurred. This is different from a network-level error (which will be emitted as 'error').
* Possible causes are things such as malformed filters, non-existant datasets or similar.
*
* @public
*/
export type ChannelErrorEvent = {
type: 'channelError'
message: string
}
/**
* The listener has been told to explicitly disconnect and not reconnect.
* This is a rare situation, but may occur if the API knows reconnect attempts will fail,
* eg in the case of a deleted dataset, a blocked project or similar events.
*
* Note that this is not treated as an error on the observable, but will complete the observable.
*
* @public
*/
export type DisconnectEvent = {
type: 'disconnect'
reason: string
}
/**
* The listener has been disconnected, and a reconnect attempt is scheduled.
*
* @public
*/
export type ReconnectEvent = {
type: 'reconnect'
}
/**
* The listener connection has been established
* note: it's usually a better option to use the 'welcome' event
* @public
*/
export type OpenEvent = {
type: 'open'
}
/**
* Emitted when the listener connection has been successfully established
* and is ready to receive events.
*
* If the listener was created with `enableResume: true` and resume support
* is available, the `welcome` event will only be emitted on the initial
* connection. On subsequent reconnects, a `welcomeback` event will be
* emitted instead, followed by any events that were missed while the
* connection was disconnected.
*
* @public
*/
export type WelcomeEvent = {
type: 'welcome'
listenerName: string
}
/**
* Emitted when the listener reconnects and successfully resumes from
* its previous position.
*
* Even if the listener is created with `enableResume: true`, resume support
* may not be available. In that case, a reconnect will emit `welcome`
* instead of `welcomeback`.
*
* If resumability is unavailable, even listeners created with `enableResume: true` may still
* emit `welcome` when reconnected. Subscribers should therefore treat `welcome` after a reconnect
* the same way they would otherwise treat a `reset` event.
*
* @public
*/
export type WelcomeBackEvent = {
type: 'welcomeback'
listenerName: string
}
/**
* The listener can't be resumed or otherwise need to reset its local state
*
* If resumability is unavailable, even listeners created with `enableResume: true` may still
* emit `welcome` when reconnected. Subscribers should therefore treat `welcome` after a reconnect
* the same way they would otherwise treat a `reset` event.
*
* @public
*/
export type ResetEvent = {
type: 'reset'
}
/** @public */
export type ListenEvent<R extends Record<string, Any> = Record<string, Any>> =
| MutationEvent<R>
| ReconnectEvent
| WelcomeBackEvent
| ResetEvent
| WelcomeEvent
| OpenEvent
/** @public */
export type ListenEventName =
/** A mutation was performed */
| 'mutation'
/** The listener has been (re)established */
| 'welcome'
/** The listener has been disconnected, and a reconnect attempt is scheduled */
| 'reconnect'
/**
* The listener connection has been established
* note: it's usually a better option to use the 'welcome' event
*/
| 'open'
/** @public */
export type ResumableListenEventNames =
| ListenEventName
/** The listener has reconnected and successfully resumed from where it left off */
| 'welcomeback'
/** The listener can't be resumed or otherwise need to reset its local state */
| 'reset'
/** @public */
export type ListenParams = {[key: string]: Any}
/** @public */
export interface ListenOptions {
/**
* Whether or not to include the resulting document in addition to the mutations performed.
* If you do not need the actual document, set this to `false` to reduce bandwidth usage.
* The result will be available on the `.result` property of the events.
* @defaultValue `true`
*/
includeResult?: boolean
/**
* Whether or not to include the mutations that was performed.
* If you do not need the mutations, set this to `false` to reduce bandwidth usage.
* @defaultValue `true`
*/
includeMutations?: boolean
/**
* Whether or not to include the document as it looked before the mutation event.
* The previous revision will be available on the `.previous` property of the events,
* and may be `null` in the case of a new document.
* @defaultValue `false`
*/
includePreviousRevision?: boolean
/*
* Whether to include events for drafts and versions. As of API Version >= v2025-02-19, only events
* for published documents will be included by default (see {@link https://www.sanity.io/changelog/676aaa9d-2da6-44fb-abe5-580f28047c10|Changelog})
* If you need events from drafts and versions, set this to `true`.
* Note: Keep in mind that additional document variants may be introduced in the future, so it's
* recommended to respond to events in a way that's tolerant of potential future variants, e.g. by
* explicitly checking whether the event is for a draft or a version.
* @defaultValue `false`
*/
includeAllVersions?: boolean
/**
* Whether events should be sent as soon as a transaction has been committed (`transaction`, default),
* or only after they are available for queries (query). Note that this is on a best-effort basis,
* and listeners with `query` may in certain cases (notably with deferred transactions) receive events
* that are not yet visible to queries.
*
* @defaultValue `'transaction'`
*/
visibility?: 'transaction' | 'query'
/**
* Array of event names to include in the observable. By default, only mutation events are included.
* Note: `welcomeback` and `reset` events requires `enableResume: true`
* @defaultValue `['mutation']`
*/
events?: ListenEventName[]
/**
* Format of "effects", eg the resulting changes of a mutation.
* Currently only `mendoza` is supported, and (if set) will include `apply` and `revert` arrays
* in the mutation events under the `effects` property.
*
* See {@link https://github.com/sanity-io/mendoza | The mendoza docs} for more info
*
* @defaultValue `undefined`
*/
effectFormat?: 'mendoza'
/**
* Optional request tag for the listener. Use to identify the request in logs.
*
* @defaultValue `undefined`
*/
tag?: string
/**
* If this is enabled, the client will normally resume events upon reconnect
* When if enabling this, you should also add the `reset` to the events array and handle the case where the backend is unable to resume.
* @beta
* @defaultValue `false`
*/
enableResume?: boolean
}
/** @public */
export interface ResumableListenOptions extends Omit<ListenOptions, 'events' | 'enableResume'> {
/**
* If this is enabled, the client will normally resume events upon reconnect
* Note that you should also subscribe to `reset`-events and handle the case where the backend is unable to resume
* @beta
* @defaultValue `false`
*/
enableResume: true
/**
* Array of event names to include in the observable. By default, only mutation events are included.
*
* @defaultValue `['mutation']`
*/
events?: ResumableListenEventNames[]
}
/** @public */
export interface ResponseQueryOptions extends RequestOptions {
perspective?: ClientPerspective
/**
* @beta
*/
variant?: ClientVariant
resultSourceMap?: boolean | 'withKeyArraySelector'
returnQuery?: boolean
useCdn?: boolean
stega?: boolean | StegaConfig
// The `cache` and `next` options are specific to the Next.js App Router integration
cache?: 'next' extends keyof RequestInit ? RequestInit['cache'] : never
next?: ('next' extends keyof RequestInit ? RequestInit : never)['next']
lastLiveEventId?: string | string[] | null
/**
* When set to `noStale`, APICDN will not return a cached response if the content is stale.
* Tradeoff between latency and freshness of content.
*
* Only to be used with live content queries and when useCdn is true.
*/
cacheMode?: 'noStale'
}
/** @public */
export interface FilteredResponseQueryOptions extends ResponseQueryOptions {
filterResponse?: true
}
/** @public */
export interface UnfilteredResponseQueryOptions extends ResponseQueryOptions {
filterResponse: false
/**
* When `filterResponse` is `false`, `returnQuery` also defaults to `true` for
* backwards compatibility (on the client side, not from the content lake API).
* Can also explicitly be set to `true`.
*/
returnQuery?: true
}
/**
* When using `filterResponse: false`, but you do not wish to receive back the query from
* the content lake API.
*
* @public
*/
export interface UnfilteredResponseWithoutQuery extends ResponseQueryOptions {
filterResponse: false
returnQuery: false
}
/** @public */
export type QueryOptions =
| FilteredResponseQueryOptions
| UnfilteredResponseQueryOptions
| UnfilteredResponseWithoutQuery
/** @public */
export interface RawQueryResponse<R> {
query: string
ms: number
result: R
resultSourceMap?: ContentSourceMap
/** Requires `apiVersion` to be `2021-03-25` or later. */
syncTags?: SyncTag[]
}
/** @public */
export type RawQuerylessQueryResponse<R> = Omit<RawQueryResponse<R>, 'query'>
/** @internal */
export type BaseMutationOptions = RequestOptions & {
visibility?: 'sync' | 'async' | 'deferred'
returnDocuments?: boolean
returnFirst?: boolean
dryRun?: boolean
autoGenerateArrayKeys?: boolean
skipCrossDatasetReferenceValidation?: boolean
transactionId?: string
}
/** @internal */
export type FirstDocumentMutationOptions = BaseMutationOptions & {
returnFirst?: true
returnDocuments?: true
}
/** @internal */
export type FirstDocumentIdMutationOptions = BaseMutationOptions & {
returnFirst?: true
returnDocuments: false
}
/** @internal */
export type AllDocumentsMutationOptions = BaseMutationOptions & {
returnFirst: false
returnDocuments?: true
}
/** @internal */
export type MutationOperation = 'create' | 'delete' | 'update' | 'none'
/** @internal */
export interface SingleMutationResult {
transactionId: string
documentId: string
results: {id: string; operation: MutationOperation}[]
}
/** @internal */
export interface MultipleMutationResult {
transactionId: string
documentIds: string[]
results: {id: string; operation: MutationOperation}[]
}
/** @internal */
export type AllDocumentIdsMutationOptions = BaseMutationOptions & {
returnFirst: false
returnDocuments: false
}
/** @internal */
export type AttributeSet = {[key: string]: Any}
/** @internal */
export type TransactionFirstDocumentMutationOptions = BaseMutationOptions & {
returnFirst: true
returnDocuments: true
}
/** @internal */
export type TransactionFirstDocumentIdMutationOptions = BaseMutationOptions & {
returnFirst: true
returnDocuments?: false
}
/** @internal */
export type TransactionAllDocumentsMutationOptions = BaseMutationOptions & {
returnFirst?: false
returnDocuments: true
}
/** @internal */
export type TransactionAllDocumentIdsMutationOptions = BaseMutationOptions & {
returnFirst?: false
returnDocuments?: false
}
/** @internal */
export type TransactionMutationOptions =
| TransactionFirstDocumentMutationOptions
| TransactionFirstDocumentIdMutationOptions
| TransactionAllDocumentsMutationOptions
| TransactionAllDocumentIdsMutationOptions
/** @internal */
export type BaseActionOptions = RequestOptions & {
transactionId?: string
skipCrossDatasetReferenceValidation?: boolean
dryRun?: boolean
}
/** @internal */
export interface SingleActionResult {
transactionId: string
}
/** @internal */
export interface MultipleActionResult {
transactionId: string
}
/** @internal */
export type RawRequestOptions = RequestUrlOptions & {
method?: string
token?: string
/** @deprecated has no effect — response parsing is driven by the response `content-type` */
json?: boolean
tag?: string
useGlobalApi?: boolean
withCredentials?: boolean
query?: {[key: string]: string | string[]}
headers?: {[key: string]: string}
timeout?: number
body?: Any
maxRedirects?: number
/** Max retries for this request; `0` disables retries. Overrides the client-level maximum in both directions. */
maxRetries?: number
signal?: AbortSignal
}
/** @internal */
export interface ApiError {
error: string
message: string
statusCode: number
}
/** @internal */
export interface MutationError {
type: 'mutationError'
description: string
items?: MutationErrorItem[]
}
/**
* Returned from the Content Lake API when a query is malformed, usually with a start
* and end column to indicate where the error occurred, but not always. Can we used to
* provide a more structured error message to the user.
*
* This will be located under the response `error` property.
*
* @public
*/
export interface QueryParseError {
type: 'queryParseError'
description: string
start?: number
end?: number
query?: string
}
/** @internal */
export interface MutationErrorItem {
error: {
type: string
description: string
value?: unknown
}
}
/** @internal */
export interface ActionError {
type: 'actionError'
description: string
items?: ActionErrorItem[]
}
/** @internal */
export interface ActionErrorItem {
error: {
type: string
description: string
value?: unknown
}
index: number
}
/** @internal */
export type PartialExcept<T, K extends keyof T> = Pick<T, K> & Partial<Omit<T, K>>
/** @beta */
export type ReleaseState =
| 'active'
| 'archiving'
| 'unarchiving'
| 'archived'
| 'published'
| 'publishing'
| 'scheduled'
| 'scheduling'
/** @internal */
export type ReleaseType = 'asap' | 'scheduled' | 'undecided'
/** @public */
export type ReleaseCardinality = 'many' | 'one' | undefined
/** @internal */
export interface ReleaseDocument extends SanityDocument {
/**
* typically
* `_.releases.<name>`
*/
_id: string
/**
* where a release has _id `_.releases.foo`, the name is `foo`
*/
name: string
_type: 'system.release'
_createdAt: string
_updatedAt: string
_rev: string
state: ReleaseState
error?: {
message: string
}
finalDocumentStates?: {
/** Document ID */
id: string
}[]
/**
* If defined, it takes precedence over the intendedPublishAt, the state should be 'scheduled'
*/
publishAt?: string
/**
* If defined, it provides the time the release was actually published
*/
publishedAt?: string
metadata: {
title?: string
description?: string
intendedPublishAt?: string
releaseType: ReleaseType
cardinality?: ReleaseCardinality
}
}
/** @internal */
export type EditableReleaseDocument = Omit<
PartialExcept<ReleaseDocument, '_id'>,
'metadata' | '_type'
> & {
_id: string
metadata: Partial<ReleaseDocument['metadata']>
}
/**
* DocumentValueSource is a path to a value within a document
* @public
*/
export interface ContentSourceMapDocumentValueSource {
type: 'documentValue'
// index location of the document
document: number
// index location of the path
path: number
}
/**
* When a value is not from a source, its a literal
* @public
*/
export interface ContentSourceMapLiteralSource {
type: 'literal'
}
/**
* When a field source is unknown
* @public
*/
export interface ContentSourceMapUnknownSource {
type: 'unknown'
}
/** @public */
export type ContentSourceMapSource =
| ContentSourceMapDocumentValueSource
| ContentSourceMapLiteralSource
| ContentSourceMapUnknownSource
/**
* ValueMapping is a mapping when for value that is from a single source value
* It may refer to a field within a document or a literal value
* @public
*/
export interface ContentSourceMapValueMapping {
type: 'value'
// source of the value
source: ContentSourceMapSource
}
/** @public */
export type ContentSourceMapMapping = ContentSourceMapValueMapping
/** @public */
export type ContentSourceMapMappings = Record<string, ContentSourceMapMapping>
/** @public */
export interface ContentSourceMapDocumentBase {
_id: string
_type: string
}
/** @public */
export interface ContentSourceMapDocument extends ContentSourceMapDocumentBase {
_projectId?: undefined
_dataset?: undefined
}
/** @public */
export interface ContentSourceMapRemoteDocument extends ContentSourceMapDocumentBase {
_projectId: string
_dataset: string
}
/** @public */
export type ContentSourceMapDocuments = (
| ContentSourceMapDocument
| ContentSourceMapRemoteDocument
)[]
/** @public */
export type ContentSourceMapPaths = string[]
/** @public */
export interface ContentSourceMap {
mappings: ContentSourceMapMappings
documents: ContentSourceMapDocuments
paths: ContentSourceMapPaths
}
/** @public */
export type SyncTag = `s1:${string}`
/** @public */
export interface LiveEventRestart {
type: 'restart'
id: string
}
/** @public */
export interface LiveEventReconnect {
type: 'reconnect'
}
/** @public */
export interface LiveEventMessage {
type: 'message'
id: string
tags: SyncTag[]
}
/** @public */
export interface LiveEventWelcome {
type: 'welcome'
}
/**
* The `id` field is the position at which the connection was rejected or closed.
* The `reason` field will specify why the connection rejected/closed.
* @public
*/
export interface LiveEventGoAway {
type: 'goaway'
id: string
reason: string
}
/** @public */
export type LiveEvent =
| LiveEventRestart
| LiveEventReconnect
| LiveEventMessage
| LiveEventWelcome
| LiveEventGoAway
/** @public */
export interface SanityQueries {}
/** @public */
export type ClientReturn<
GroqString extends string,
Fallback = Any,
> = GroqString extends keyof SanityQueries ? SanityQueries[GroqString] : Fallback
export type {
AgentActionParam,
AgentActionParams,
AgentActionPath,
AgentActionPathSegment,
AgentActionTarget,
ConstantAgentActionParam,
DocumentAgentActionParam,
FieldAgentActionParam,
GroqAgentActionParam,
} from './agent/actions/commonTypes'
export type {
GenerateInstruction,
GenerateOperation,
GenerateTarget,
GenerateTargetDocument,
GenerateTargetInclude,
} from './agent/actions/generate'
export type {PatchDocument, PatchOperation, PatchTarget} from './agent/actions/patch'
export type {PromptRequest} from './agent/actions/prompt'
export type {
ImageDescriptionOperation,
TransformDocument,
TransformOperation,
TransformTarget,
TransformTargetDocument,
TransformTargetInclude,
} from './agent/actions/transform'
export type {
TranslateDocument,
TranslateTarget,
TranslateTargetInclude,
} from './agent/actions/translate'
export type {
InvokeFunctionEvent,
InvokeFunctionOptions,
InvokeFunctionRequest,
} from './functions/invoke'
export type {
CollaborationCommentCreate,
CollaborationCommentDocument,
CollaborationCommentMessage,
CollaborationCommentPortableTextBlock,
CollaborationCommentReactionShortName,
CollaborationCommentSelection,
CollaborationCommentsListenOptions,
CollaborationCommentsRequestOptions,
CollaborationCommentStatus,
CollaborationCommentsWriteOptions,
CollaborationCommentTarget,
CollaborationCommentUpdate,
CollaborationCommentRange,
CollaborationCommentFieldValue,
} from './collaboration/types'
export type {
ContentSourceMapParsedPath,
ContentSourceMapParsedPathKeyedSegment,
FilterDefault,
InitializedStegaConfig,
Logger,
ResolveStudioUrl,
StegaConfig,
StegaConfigRequiredKeys,
StudioBaseRoute,
StudioBaseUrl,
StudioUrl,
} from './stega/types'
/**
* A string constant containing the experimental API version warning message.
* Use this with the `ignoreWarnings` option to suppress warnings when using experimental API versions.
*
* @example
* ```typescript
* import { createClient, EXPERIMENTAL_API_WARNING } from '@sanity/client'
*
* const client = createClient({
* projectId: 'your-project-id',
* dataset: 'production',
* apiVersion: 'vX', // experimental version
* ignoreWarnings: EXPERIMENTAL_API_WARNING
* })
* ```
*
* @public
*/
export const EXPERIMENTAL_API_WARNING = 'This is an experimental API version'
// Media Libraries types
/**
* Fit / resize modes accepted for thumbnail params.
* @public
*/
export type FitMode = 'preserve' | 'stretch' | 'crop' | 'smartcrop' | 'pad'
/**
* Allowed still image formats (thumbnail + storyboard).
* @public
*/
export type StillImageFormat = 'jpg' | 'png' | 'webp'
/**
* Allowed animated image formats.
* @public
*/
export type AnimatedImageFormat = 'gif' | 'webp'
/**
* Thumbnail rendition (single frame) options.
* @public
*/
export interface ThumbnailTransformOptions {
/** Pixel width of the thumbnail frame. */
width?: number
/** Pixel height of the thumbnail frame. */
height?: number
/** Timestamp (seconds) from which to grab the frame. */
time?: number
/** Resize / fit mode applied to the extracted frame. */
fit?: FitMode
/** Output image format. */
format?: StillImageFormat
}
/**
* Animated preview rendition options (e.g. GIF / animated WebP).
* @public
*/
export interface AnimatedTransformOptions {
/** Pixel width of the animated output. Max 640 px. */
width?: number
/** Pixel height of the animated output. Max 640 px. */
height?: number
/** Start time in seconds (inclusive). */
start?: number
/** End time in seconds. */
end?: number
/** Frames per second (1–30). */
fps?: number
/** Output animated format. */
format?: AnimatedImageFormat
}
/**
* Storyboard (contact sheet) options.
* @public
*/
export interface StoryboardTransformOptions {
/** Output image format for the storyboard. */
format?: StillImageFormat
}
/**
* Video-specific playback transformation option groups.
* Only explicitly provided values are serialized into query parameters.
* @public
*/
export interface MediaLibraryVideoPlaybackTransformations {
/** Static thumbnail (single frame) options. */
thumbnail?: ThumbnailTransformOptions
/** Animated preview options (GIF / animated WebP). */
animated?: AnimatedTransformOptions
/** Storyboard (contact sheet) options. */
storyboard?: StoryboardTransformOptions
}
/**
* Options for requesting playback info (URLs + optional tokens) for a Media Library video asset.
*
* Removed: generic fallback parameters (width, height, fit, format). Supply per‑transformation values instead.
* Animated transformations intentionally exclude any fit option (not supported by Mux).
*
* includeTokens is a client-side flag (not sent to the server) controlling whether
* returned tokens should be appended to URLs when consumed.
* @public
*/
export interface MediaLibraryPlaybackInfoOptions {
/** Explicit per-video transformation options (thumbnail, animated, storyboard). */
transformations?: MediaLibraryVideoPlaybackTransformations
/** Expiration hint for secured/signed URLs (string or number, number will be stringified). */
expiration?: string | number
}
/** @public */
export interface VideoPlaybackInfoItemPublic {
url: string
}
/** @public */
export interface VideoPlaybackInfoItemSigned extends VideoPlaybackInfoItemPublic {
token: string
}
/** @public */
export type VideoPlaybackInfoItem = VideoPlaybackInfoItemPublic | VideoPlaybackInfoItemSigned
/** @public */
export interface VideoRenditionInfoPublic {
/** URL to the MP4 rendition (redirects to CDN) */
url: string
/** Resolution identifier, e.g. "1080p", "480p", "270p" */
resolution: '1080p' | '480p' | '270p' | (string & {})
}
/** @public */
export interface VideoRenditionInfoSigned extends VideoRenditionInfoPublic {
/** Authentication token for signed playback */
token: string
/** Token expiration time in ISO 8601 format */
expiresAt: string
}
/** @public */
export type VideoRenditionInfo = VideoRenditionInfoPublic | VideoRenditionInfoSigned
/** @public */
export interface VideoSubtitleInfoPublic {
/** Subtitle track identifier */
trackId: string
/** ISO 639-1 language code */
languageCode: string
/** URL to the subtitle file */
url: string
/** Whether this track contains closed captions */
closedCaptions: boolean
}
/** @public */
export interface VideoSubtitleInfoSigned extends VideoSubtitleInfoPublic {
/** Authentication token for signed playback */
token: string
/** Token expiration time in ISO 8601 format */
expiresAt: string
}
/** @public */
export type VideoSubtitleInfo = VideoSubtitleInfoPublic | VideoSubtitleInfoSigned
/** @public */
export interface VideoPlaybackInfo<
T extends VideoPlaybackInfoItem = VideoPlaybackInfoItem,
R extends VideoRenditionInfo = T extends VideoPlaybackInfoItemSigned
? VideoRenditionInfoSigned
: VideoRenditionInfo,
S extends VideoSubtitleInfo = T extends VideoPlaybackInfoItemSigned
? VideoSubtitleInfoSigned
: VideoSubtitleInfo,
> {
id: string
thumbnail: T
animated: T
storyboard: T
stream: T
duration: number
aspectRatio: number
renditions?: R[]
subtitles?: S[]
}
/** @public */
export type VideoPlaybackInfoSigned = VideoPlaybackInfo<VideoPlaybackInfoItemSigned>
/** @public */
export type VideoPlaybackInfoPublic = VideoPlaybackInfo<VideoPlaybackInfoItemPublic>
/** @public */
export interface VideoPlaybackTokens {
stream?: string
thumbnail?: string
storyboard?: string
animated?: string
}
/** @public */
export type MediaLibraryAssetInstanceIdentifier = string | SanityReference
/**
* A single tracked version of a Media Library asset - one uploaded instance,
* referencing the underlying (Content Lake shaped) asset document it wraps.
*
* @public
*/
export interface MediaLibraryAssetVersion {
_key: string
_type: 'sanity.asset.version'
title?: string
instance: SanityReference
}
/**
* The document returned by the Media Library upload endpoint
* (`POST /media-libraries/:id/upload`).
*
* This is _not_ the same shape as {@link SanityAssetDocument} /
* {@link SanityImageAssetDocument}: a Media Library asset is a `sanity.asset`
* document that tracks one or more uploaded versions, each pointing at its
* own underlying Content Lake asset document via `currentVersion`/`versions`.
*
* Modelled directly on an observed API response. Fields whose full shape has
* not been confirmed (`parent`, `rootDirectory`, `aspects`) are typed loosely
* on purpose - widen them once their shape is confirmed.
*
* @public
*/
export interface MediaLibraryAssetDocument {
_id: string
_type: 'sanity.asset'
assetType: string
title?: string
cdnAccessPolicy?: string
currentVersion: SanityReference
versions: MediaLibraryAssetVersion[]
aspects?: Record<string, Any>
parent?: SanityReference | null
rootDirectory?: Any
}