UNPKG

@sanity/client

Version:

Client for retrieving, creating and patching data from Sanity.io

1 lines 411 kB
{"version":3,"file":"index.cjs","sources":["../src/types.ts","../src/util/codeFrame.ts","../src/http/errors.ts","../src/http/request.ts","../src/data/eventsource.ts","../src/util/getSelection.ts","../src/data/patch.ts","../src/data/transaction.ts","../src/http/requestOptions.ts","../src/data/encodeQueryString.ts","../src/data/dataMethods.ts","../src/agent/actions/generate.ts","../src/agent/actions/patch.ts","../src/agent/actions/prompt.ts","../src/agent/actions/transform.ts","../src/agent/actions/translate.ts","../src/agent/actions/AgentActionsClient.ts","../src/assets/AssetsClient.ts","../src/util/defaults.ts","../src/util/pick.ts","../src/data/eventsourcePolyfill.ts","../src/data/reconnectOnConnectionFailure.ts","../src/data/listen.ts","../src/util/shareReplayLatest.ts","../src/data/live.ts","../src/datasets/DatasetsClient.ts","../src/mediaLibrary/MediaLibraryVideoClient.ts","../src/projects/ProjectsClient.ts","../src/util/createVersionId.ts","../src/releases/createRelease.ts","../src/releases/ReleasesClient.ts","../src/users/UsersClient.ts","../src/SanityClient.ts","../src/defineCreateClient.ts","../src/defineDeprecatedCreateClient.ts","../src/http/nodeMiddleware.ts","../src/index.ts"],"sourcesContent":["// deno-lint-ignore-file no-empty-interface\n/* eslint-disable @typescript-eslint/no-empty-object-type */\n\nimport type {Requester} from 'get-it'\nimport type {Observable} from 'rxjs'\n\nimport type {SanityClient} from './SanityClient'\nimport type {InitializedStegaConfig, StegaConfig} from './stega/types'\n\n/**\n * Used to tag types that is set to `any` as a temporary measure, but should be replaced with proper typings in the future\n * @internal\n */\nexport type Any = any // eslint-disable-line @typescript-eslint/no-explicit-any\n\ndeclare global {\n // Declare empty stub interfaces for environments where \"dom\" lib is not included\n interface File {}\n}\n\n/** @public */\nexport type UploadBody = File | Blob | Buffer | NodeJS.ReadableStream\n\n/** @public */\nexport interface RequestOptions {\n timeout?: number\n token?: string\n tag?: string\n headers?: Record<string, string>\n method?: string\n query?: Any\n body?: Any\n signal?: AbortSignal\n}\n\n/**\n * @public\n * @deprecated – The `r`-prefix is not required, use `string` instead\n */\nexport type ReleaseId = `r${string}`\n\n/**\n * @deprecated use 'drafts' instead\n */\ntype DeprecatedPreviewDrafts = 'previewDrafts'\n\n/** @public */\nexport type StackablePerspective = ('published' | 'drafts' | string) & {}\n\n/** @public */\nexport type ClientPerspective =\n DeprecatedPreviewDrafts | 'published' | 'drafts' | 'raw' | StackablePerspective[]\n\n/**\n * @public\n * @beta\n */\nexport type ClientVariantConditions = Record<string, string>\n\n/**\n * @public\n * @beta\n */\nexport type ClientVariant = ClientVariantConditions | string\n\ntype ClientConfigResource =\n | {\n type: 'canvas'\n id: string\n }\n | {\n type: 'media-library'\n id: string\n }\n | {\n type: 'dataset'\n id: string\n }\n | {\n type: 'dashboard'\n id: string\n }\n\n/** @public */\nexport interface ClientConfig {\n projectId?: string\n dataset?: string\n /** @defaultValue true */\n useCdn?: boolean\n token?: string\n\n /**\n * Configure the client to work with a specific Sanity resource (Media Library, Canvas, etc.)\n * @remarks\n * This allows the client to interact with resources beyond traditional project datasets.\n * When configured, methods like `fetch()`, `assets.upload()`, and mutations will operate on the specified resource.\n * @example\n * ```ts\n * createClient({\n * resource: {\n * type: 'media-library',\n * id: 'your-media-library-id'\n * }\n * })\n * ```\n */\n resource?: ClientConfigResource\n\n /**\n * @deprecated Use `resource` instead\n * @internal\n */\n '~experimental_resource'?: ClientConfigResource\n\n /**\n * What perspective to use for the client. See {@link https://www.sanity.io/docs/perspectives|perspective documentation}\n * @remarks\n * 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}\n * @defaultValue 'published'\n */\n perspective?: ClientPerspective\n /**\n * @beta\n */\n variant?: ClientVariant\n apiHost?: string\n\n /**\n @remarks\n * 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}\n */\n apiVersion?: string\n proxy?: string\n\n /**\n * Optional request tag prefix for all request tags\n */\n requestTagPrefix?: string\n\n /**\n * Optional default headers to include with all requests\n *\n * @remarks request-specific headers will override any default headers with the same name.\n */\n headers?: Record<string, string>\n\n ignoreBrowserTokenWarning?: boolean\n /**\n * Ignore specific warning messages from the client.\n *\n * @remarks\n * - String values perform substring matching (not exact matching) against warning messages\n * - RegExp values are tested against the full warning message\n * - Array values allow multiple patterns to be specified\n *\n * @example\n * ```typescript\n * // Ignore warnings containing \"experimental\"\n * ignoreWarnings: 'experimental'\n *\n * // Ignore multiple warning types\n * ignoreWarnings: ['experimental', 'deprecated']\n *\n * // Use regex for exact matching\n * ignoreWarnings: /^This is an experimental API version$/\n *\n * // Mix strings and regex patterns\n * ignoreWarnings: ['rate limit', /^deprecated/i]\n * ```\n */\n ignoreWarnings?: string | RegExp | Array<string | RegExp>\n withCredentials?: boolean\n allowReconfigure?: boolean\n timeout?: number\n\n /** Number of retries for requests. Defaults to 5. */\n maxRetries?: number\n\n /**\n * The amount of time, in milliseconds, to wait before retrying, given an attemptNumber (starting at 0).\n *\n * Defaults to exponential back-off, starting at 100ms, doubling for each attempt, together with random\n * jitter between 0 and 100 milliseconds. More specifically the following algorithm is used:\n *\n * Delay = 100 * 2^attemptNumber + randomNumberBetween0and100\n */\n retryDelay?: (attemptNumber: number) => number\n\n /**\n * @deprecated Don't use\n */\n useProjectHostname?: boolean\n\n /**\n * @deprecated Don't use\n */\n requester?: Requester\n\n /**\n * Adds a `resultSourceMap` key to the API response, with the type `ContentSourceMap`\n */\n resultSourceMap?: boolean | 'withKeyArraySelector'\n /**\n *@deprecated set `cache` and `next` options on `client.fetch` instead\n */\n fetch?:\n | {\n cache?: ResponseQueryOptions['cache']\n next?: ResponseQueryOptions['next']\n }\n | boolean\n /**\n * Options for how, if enabled, Content Source Maps are encoded into query results using steganography\n */\n stega?: StegaConfig | boolean\n /**\n * Lineage token for recursion control\n */\n lineage?: string\n\n /**\n * A custom request handler that intercepts all HTTP requests made by the client.\n *\n * Useful for logging, adding custom headers, refreshing auth tokens, rate limiting, etc.\n *\n * When using `withConfig()`, the new handler **replaces** the previous one (it does not\n * wrap it). To compose handlers, you can chain them manually:\n *\n * ```ts\n * const parent = createClient({...config, _requestHandler: handlerA})\n * const child = parent.withConfig({\n * _requestHandler: (req, defaultRequester) =>\n * handlerB(req, (opts) => handlerA(opts, defaultRequester)),\n * })\n * ```\n *\n * Setting `_requestHandler` to `undefined` via `withConfig()` removes the handler.\n *\n * Note: This only applies to HTTP requests. Real-time listener connections\n * (`client.listen()`) use EventSource and are not intercepted by this handler.\n *\n * @internal\n * @deprecated Don't use outside of Sanity internals\n * @see {@link RequestHandler}\n */\n _requestHandler?: RequestHandler\n}\n\n/** @public */\nexport interface InitializedClientConfig extends ClientConfig {\n // These are required in the initialized config\n apiHost: string\n apiVersion: string\n useProjectHostname: boolean\n useCdn: boolean\n // These are added by the initConfig function\n /**\n * @deprecated Internal, don't use\n */\n isDefaultApi: boolean\n /**\n * @deprecated Internal, don't use\n */\n url: string\n /**\n * @deprecated Internal, don't use\n */\n cdnUrl: string\n /**\n * The fully initialized stega config, can be used to check if stega is enabled\n */\n stega: InitializedStegaConfig\n /**\n * Default headers to include with all requests\n *\n * @remarks request-specific headers will override any default headers with the same name.\n */\n headers?: Record<string, string>\n}\n\n/** @public */\nexport type AssetMetadataType =\n 'location' | 'exif' | 'image' | 'palette' | 'lqip' | 'blurhash' | 'thumbhash' | 'none'\n\n/** @public */\nexport interface UploadClientConfig {\n /**\n * Optional request tag for the upload\n */\n tag?: string\n\n /**\n * Whether or not to preserve the original filename (default: true)\n */\n preserveFilename?: boolean\n\n /**\n * Filename for this file (optional)\n */\n filename?: string\n\n /**\n * Milliseconds to wait before timing the request out\n */\n timeout?: number\n\n /**\n * Mime type of the file\n */\n contentType?: string\n\n /**\n * Array of metadata parts to extract from asset\n */\n extract?: AssetMetadataType[]\n\n /**\n * Optional freeform label for the asset. Generally not used.\n */\n label?: string\n\n /**\n * Optional title for the asset\n */\n title?: string\n\n /**\n * Optional description for the asset\n */\n description?: string\n\n /**\n * The credit to person(s) and/or organization(s) required by the supplier of the asset to be used when published\n */\n creditLine?: string\n\n /**\n * Source data (when the asset is from an external service)\n */\n source?: {\n /**\n * The (u)id of the asset within the source, i.e. 'i-f323r1E'\n */\n id: string\n\n /**\n * The name of the source, i.e. 'unsplash'\n */\n name: string\n\n /**\n * A url to where to find the asset, or get more info about it in the source\n */\n url?: string\n }\n}\n\n/** @internal */\nexport interface SanityReference {\n _ref: string\n}\n\n/** @internal */\nexport type SanityDocument<T extends Record<string, Any> = Record<string, Any>> = {\n [P in keyof T]: T[P]\n} & {\n _id: string\n _rev: string\n _type: string\n _createdAt: string\n _updatedAt: string\n /**\n * Present when `perspective` is set to `previewDrafts`\n */\n _originalId?: string\n}\n\n/** @internal */\nexport interface SanityAssetDocument extends SanityDocument {\n url: string\n path: string\n size: number\n assetId: string\n mimeType: string\n sha1hash: string\n extension: string\n uploadId?: string\n originalFilename?: string\n}\n\n/** @internal */\nexport interface SanityImagePalette {\n background: string\n foreground: string\n population: number\n title: string\n}\n\n/** @internal */\nexport interface SanityImageAssetDocument extends SanityAssetDocument {\n metadata: {\n _type: 'sanity.imageMetadata'\n hasAlpha: boolean\n isOpaque: boolean\n lqip?: string\n blurHash?: string\n thumbHash?: string\n dimensions: {\n _type: 'sanity.imageDimensions'\n aspectRatio: number\n height: number\n width: number\n }\n palette?: {\n _type: 'sanity.imagePalette'\n darkMuted?: SanityImagePalette\n darkVibrant?: SanityImagePalette\n dominant?: SanityImagePalette\n lightMuted?: SanityImagePalette\n lightVibrant?: SanityImagePalette\n muted?: SanityImagePalette\n vibrant?: SanityImagePalette\n }\n image?: {\n _type: 'sanity.imageExifTags'\n [key: string]: Any\n }\n exif?: {\n _type: 'sanity.imageExifMetadata'\n [key: string]: Any\n }\n }\n}\n\n/** @public */\nexport interface ErrorProps {\n message: string\n response: Any\n statusCode: number\n responseBody: Any\n traceId?: string\n details: Any\n}\n\n/** @public */\nexport type HttpRequest = {\n (options: RequestOptions, requester: Requester): ReturnType<Requester>\n}\n\n/**\n * A function that intercepts HTTP requests made by the client.\n *\n * Receives the resolved request options, a `defaultRequester` function that\n * executes the request through the normal pipeline, and a `client` instance\n * without a `_requestHandler` (to avoid recursive interception).\n *\n * The consumer can:\n * - Modify request options before calling `defaultRequester`\n * - Transform the response stream (e.g. via `pipe`)\n * - Skip `defaultRequester` entirely and return a custom Observable\n * - Use `client` to make additional requests (e.g. refresh an auth token on 401)\n *\n * When set via `withConfig()`, the new handler **replaces** (not wraps) the previous one.\n *\n * Note: This only applies to HTTP requests. Real-time listener connections\n * (`client.listen()`) use EventSource and are not intercepted by this handler.\n *\n * @param request - The resolved request options including `url`\n * @param defaultRequester - Executes the request through the normal pipeline\n * @param client - A client instance with the same configuration but without a `_requestHandler`,\n * useful for making side requests (e.g. token refresh) without triggering the handler recursively\n *\n * @internal\n * @deprecated Don't use outside of Sanity internals\n */\nexport type RequestHandler = (\n request: RequestOptions & {url: string},\n defaultRequester: (options: RequestOptions & {url: string}) => Observable<HttpRequestEvent>,\n client: SanityClient,\n) => Observable<HttpRequestEvent>\n\n/** @internal */\nexport interface RequestObservableOptions extends Omit<RequestOptions, 'url'> {\n url?: string\n uri?: string\n canUseCdn?: boolean\n useCdn?: boolean\n tag?: string\n returnQuery?: boolean\n resultSourceMap?: boolean | 'withKeyArraySelector'\n perspective?: ClientPerspective\n /**\n * @beta\n */\n variant?: ClientVariant\n lastLiveEventId?: string\n cacheMode?: 'noStale'\n}\n\n/** @public */\nexport interface ProgressEvent {\n type: 'progress'\n stage: 'upload' | 'download'\n percent: number\n total?: number\n loaded?: number\n lengthComputable: boolean\n}\n\n/** @public */\nexport interface ResponseEvent<T = unknown> {\n type: 'response'\n body: T\n url: string\n method: string\n statusCode: number\n statusMessage?: string\n headers: Record<string, string>\n}\n\n/** @public */\nexport type HttpRequestEvent<T = unknown> = ResponseEvent<T> | ProgressEvent\n\n/** @internal */\nexport interface AuthProvider {\n name: string\n title: string\n url: string\n}\n\n/** @internal */\nexport type AuthProviderResponse = {providers: AuthProvider[]}\n\n/** @public */\nexport type DatasetAclMode = 'public' | 'private' | 'custom'\n\n/** @public */\nexport type DatasetCreateOptions = {\n aclMode?: DatasetAclMode\n embeddings?: {\n enabled: boolean\n projection?: string\n }\n}\n\n/** @public */\nexport type DatasetEditOptions = {\n aclMode?: DatasetAclMode\n}\n\n/** @public */\nexport type EmbeddingsSettings = {\n enabled: boolean\n projection?: string\n status: string\n}\n\n/** @public */\nexport type EmbeddingsSettingsBody = {\n enabled: boolean\n projection?: string\n}\n\n/** @public */\nexport type DatasetResponse = {datasetName: string; aclMode: DatasetAclMode}\n/** @public */\nexport type DatasetsResponse = {\n name: string\n aclMode: DatasetAclMode\n createdAt: string\n createdByUserId: string\n addonFor: string | null\n datasetProfile: string\n features: string[]\n tags: string[]\n}[]\n\n/** @public */\nexport interface SanityProjectMember {\n id: string\n role: string\n isRobot: boolean\n isCurrentUser: boolean\n}\n\n/** @public */\nexport interface SanityProject {\n id: string\n displayName: string\n /**\n * @deprecated Use the `/user-applications` endpoint instead, which lists all deployed studios/applications\n * @see https://www.sanity.io/help/studio-host-user-applications\n */\n studioHost: string | null\n organizationId: string | null\n isBlocked: boolean\n isDisabled: boolean\n isDisabledByUser: boolean\n createdAt: string\n pendingInvites?: number\n maxRetentionDays?: number\n members: SanityProjectMember[]\n features: string[]\n metadata: {\n cliInitializedAt?: string\n color?: string\n /**\n * @deprecated Use the `/user-applications` endpoint instead, which lists all deployed studios/applications\n * @see https://www.sanity.io/help/studio-host-user-applications\n */\n externalStudioHost?: string\n }\n}\n\n/** @public */\nexport interface SanityUser {\n id: string\n projectId: string\n displayName: string\n familyName: string | null\n givenName: string | null\n middleName: string | null\n imageUrl: string | null\n createdAt: string\n updatedAt: string\n isCurrentUser: boolean\n}\n\n/** @public */\nexport interface CurrentSanityUser {\n id: string\n name: string\n email: string\n profileImage: string | null\n role: string\n provider: string\n}\n\n/** @public */\nexport type SanityDocumentStub<T extends Record<string, Any> = Record<string, Any>> = {\n [P in keyof T]: T[P]\n} & {\n _type: string\n}\n\n/** @public */\nexport type IdentifiedSanityDocumentStub<T extends Record<string, Any> = Record<string, Any>> = {\n [P in keyof T]: T[P]\n} & {\n _id: string\n} & SanityDocumentStub\n\n/** @internal */\nexport type InsertPatch =\n {before: string; items: Any[]} | {after: string; items: Any[]} | {replace: string; items: Any[]}\n\n// Note: this is actually incorrect/invalid, but implemented as-is for backwards compatibility\n/** @internal */\nexport interface PatchOperations {\n set?: {[key: string]: Any}\n setIfMissing?: {[key: string]: Any}\n diffMatchPatch?: {[key: string]: Any}\n unset?: string[]\n inc?: {[key: string]: number}\n dec?: {[key: string]: number}\n insert?: InsertPatch\n ifRevisionID?: string\n}\n\n/** @public */\nexport interface QueryParams {\n /* eslint-disable @typescript-eslint/no-explicit-any */\n [key: string]: any\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n body?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n cache?: 'next' extends keyof RequestInit ? never : any\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n filterResponse?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n headers?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n method?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n next?: 'next' extends keyof RequestInit ? never : any\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n perspective?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n variant?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n query?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n resultSourceMap?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n returnQuery?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n signal?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n stega?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n tag?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n timeout?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n token?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n useCdn?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n lastLiveEventId?: never\n /** @deprecated you're using a fetch option as a GROQ parameter, this is likely a mistake */\n cacheMode?: never\n /* eslint-enable @typescript-eslint/no-explicit-any */\n}\n\n/**\n * This type can be used with `client.fetch` to indicate that the query has no GROQ parameters.\n * @public\n */\nexport type QueryWithoutParams = Record<string, never> | undefined\n\n/** @internal */\nexport type MutationSelectionQueryParams = {[key: string]: Any}\n/** @internal */\nexport type MutationSelection =\n {query: string; params?: MutationSelectionQueryParams} | {id: string | string[]}\n/** @internal */\nexport type PatchSelection = string | string[] | MutationSelection\n/** @internal */\nexport type PatchMutationOperation = PatchOperations & MutationSelection\n\n/** @public */\nexport type Mutation<R extends Record<string, Any> = Record<string, Any>> =\n | {create: SanityDocumentStub<R>}\n | {createOrReplace: IdentifiedSanityDocumentStub<R>}\n | {createIfNotExists: IdentifiedSanityDocumentStub<R>}\n | {delete: MutationSelection}\n | {patch: PatchMutationOperation}\n\n/** @public */\nexport type ReleaseAction =\n | CreateReleaseAction\n | EditReleaseAction\n | PublishReleaseAction\n | ArchiveReleaseAction\n | UnarchiveReleaseAction\n | ScheduleReleaseAction\n | UnscheduleReleaseAction\n | DeleteReleaseAction\n | ImportReleaseAction\n\n/** @public */\nexport type VersionAction =\n CreateVersionAction | DiscardVersionAction | ReplaceVersionAction | UnpublishVersionAction\n\n/** @public */\nexport type Action =\n | CreateAction\n | ReplaceDraftAction\n | EditAction\n | DeleteAction\n | DiscardAction\n | PublishAction\n | UnpublishAction\n | VersionAction\n | ReleaseAction\n\n/** @public */\nexport type ImportReleaseAction =\n | {\n actionType: 'sanity.action.release.import'\n attributes: IdentifiedSanityDocumentStub\n releaseId: string\n ifExists: 'fail' | 'ignore' | 'replace'\n }\n | {\n actionType: 'sanity.action.release.import'\n document: IdentifiedSanityDocumentStub\n releaseId: string\n ifExists: 'fail' | 'ignore' | 'replace'\n }\n\n/**\n * Creates a new release under the given id, with metadata.\n *\n * @public\n */\nexport interface CreateReleaseAction {\n actionType: 'sanity.action.release.create'\n releaseId: string\n metadata?: Partial<ReleaseDocument['metadata']>\n}\n\n/**\n * Edits an existing release, updating the metadata.\n *\n * @public\n */\nexport interface EditReleaseAction {\n actionType: 'sanity.action.release.edit'\n releaseId: string\n patch: PatchOperations\n}\n\n/**\n * Publishes all documents in a release at once.\n *\n * @public\n */\nexport interface PublishReleaseAction {\n actionType: 'sanity.action.release.publish'\n releaseId: string\n}\n\n/**\n * Archives an `active` release, and deletes all the release documents.\n *\n * @public\n */\nexport interface ArchiveReleaseAction {\n actionType: 'sanity.action.release.archive'\n releaseId: string\n}\n\n/**\n * Unarchived an `archived` release, and restores all the release documents.\n *\n * @public\n */\nexport interface UnarchiveReleaseAction {\n actionType: 'sanity.action.release.unarchive'\n releaseId: string\n}\n\n/**\n * Queues release for publishing at the given future time.\n *\n * @public\n */\nexport interface ScheduleReleaseAction {\n actionType: 'sanity.action.release.schedule'\n releaseId: string\n publishAt: string\n}\n\n/**\n * Unschedules a `scheduled` release, stopping it from being published.\n *\n * @public\n */\nexport interface UnscheduleReleaseAction {\n actionType: 'sanity.action.release.unschedule'\n releaseId: string\n}\n\n/**\n * Deletes a `archived` or `published` release, and all the release documents versions.\n *\n * @public\n */\nexport interface DeleteReleaseAction {\n actionType: 'sanity.action.release.delete'\n releaseId: string\n}\n\n/**\n * Creates a new version of an existing document.\n *\n * If the `document` is provided, the version is created from the document\n * attached to the release as given by `document._id`\n *\n * If the `baseId` and `versionId` are provided, the version is created from the base document\n * and the version is attached to the release as given by `publishedId` and `versionId`\n *\n * @public\n */\nexport type CreateVersionAction = {\n actionType: 'sanity.action.document.version.create'\n publishedId: string\n} & (\n | {\n document: IdentifiedSanityDocumentStub\n }\n | {\n baseId: string\n versionId: string\n ifBaseRevisionId?: string\n }\n)\n\n/**\n * Delete a version of a document.\n *\n * @public\n */\nexport interface DiscardVersionAction {\n actionType: 'sanity.action.document.version.discard'\n versionId: string\n purge?: boolean\n}\n\n/**\n * Replace an existing version of a document.\n *\n * @public\n */\nexport interface ReplaceVersionAction {\n actionType: 'sanity.action.document.version.replace'\n document: IdentifiedSanityDocumentStub\n}\n\n/**\n * Identify that a version of a document should be unpublished when\n * the release that version is contained within is published.\n *\n * @public\n */\nexport interface UnpublishVersionAction {\n actionType: 'sanity.action.document.version.unpublish'\n versionId: string\n publishedId: string\n}\n\n/**\n * Creates a new draft document. The published version of the document must not already exist.\n * If the draft version of the document already exists the action will fail by default, but\n * this can be adjusted to instead leave the existing document in place.\n *\n * @public\n */\nexport type CreateAction = {\n actionType: 'sanity.action.document.create'\n\n /**\n * ID of the published document to create a draft for.\n */\n publishedId: string\n\n /**\n * Document to create. Requires a `_type` property.\n */\n attributes: IdentifiedSanityDocumentStub\n\n /**\n * ifExists controls what to do if the draft already exists\n */\n ifExists: 'fail' | 'ignore'\n}\n\n/**\n * Replaces an existing draft document.\n * At least one of the draft or published versions of the document must exist.\n *\n * @public\n * @deprecated Use {@link ReplaceVersionAction} instead\n */\nexport type ReplaceDraftAction = {\n actionType: 'sanity.action.document.replaceDraft'\n\n /**\n * Published document ID to create draft from, if draft does not exist\n */\n publishedId: string\n\n /**\n * Document to create if it does not already exist. Requires `_id` and `_type` properties.\n */\n attributes: IdentifiedSanityDocumentStub\n}\n\n/**\n * Modifies an existing draft document.\n * It applies the given patch to the document referenced by draftId.\n * If there is no such document then one is created using the current state of the published version and then that is updated accordingly.\n *\n * @public\n */\nexport type EditAction = {\n actionType: 'sanity.action.document.edit'\n\n /**\n * Draft document ID to edit\n */\n draftId: string\n\n /**\n * Published document ID to create draft from, if draft does not exist\n */\n publishedId: string\n\n /**\n * Patch operations to apply\n */\n patch: PatchOperations\n}\n\n/**\n * Deletes the published version of a document and optionally some (likely all known) draft versions.\n * If any draft version exists that is not specified for deletion this is an error.\n * If the purge flag is set then the document history is also deleted.\n *\n * @public\n */\nexport type DeleteAction = {\n actionType: 'sanity.action.document.delete'\n\n /**\n * Published document ID to delete\n */\n publishedId: string\n\n /**\n * Draft document ID to delete\n */\n includeDrafts: string[]\n\n /**\n * Delete document history\n */\n purge?: boolean\n}\n\n/**\n * Delete the draft version of a document.\n * It is an error if it does not exist. If the purge flag is set, the document history is also deleted.\n *\n * @public\n * @deprecated Use {@link DiscardVersionAction} instead\n */\nexport type DiscardAction = {\n actionType: 'sanity.action.document.discard'\n\n /**\n * Draft document ID to delete\n */\n draftId: string\n\n /**\n * Delete document history\n */\n purge?: boolean\n}\n\n/**\n * Publishes a draft document.\n * If a published version of the document already exists this is replaced by the current draft document.\n * In either case the draft document is deleted.\n * The optional revision id parameters can be used for optimistic locking to ensure\n * that the draft and/or published versions of the document have not been changed by another client.\n *\n * @public\n */\nexport type PublishAction = {\n actionType: 'sanity.action.document.publish'\n\n /**\n * Draft document ID to publish\n */\n draftId: string\n\n /**\n * Draft revision ID to match\n */\n ifDraftRevisionId?: string\n\n /**\n * Published document ID to replace\n */\n publishedId: string\n\n /**\n * Published revision ID to match\n */\n ifPublishedRevisionId?: string\n}\n\n/**\n * Retract a published document.\n * If there is no draft version then this is created from the published version.\n * In either case the published version is deleted.\n *\n * @public\n */\nexport type UnpublishAction = {\n actionType: 'sanity.action.document.unpublish'\n\n /**\n * Draft document ID to replace the published document with\n */\n draftId: string\n\n /**\n * Published document ID to delete\n */\n publishedId: string\n}\n\n/**\n * A mutation was performed. Note that when updating multiple documents in a transaction,\n * each document affected will get a separate mutation event.\n *\n * @public\n */\nexport type MutationEvent<R extends Record<string, Any> = Record<string, Any>> = {\n type: 'mutation'\n\n /**\n * The ID of the document that was affected\n */\n documentId: string\n\n /**\n * A unique ID for this event\n */\n eventId: string\n\n /**\n * The user ID of the user that performed the mutation\n */\n identity: string\n\n /**\n * An array of mutations that were performed. Note that this can differ slightly from the\n * mutations sent to the server, as the server may perform some mutations automatically.\n */\n mutations: Mutation[]\n\n /**\n * The revision ID of the document before the mutation was performed\n */\n previousRev?: string\n\n /**\n * The revision ID of the document after the mutation was performed\n */\n resultRev?: string\n\n /**\n * The document as it looked after the mutation was performed. This is only included if\n * the listener was configured with `includeResult: true`.\n */\n result?: SanityDocument<R>\n\n /**\n * The document as it looked before the mutation was performed. This is only included if\n * the listener was configured with `includePreviousRevision: true`.\n */\n previous?: SanityDocument<R> | null\n\n /**\n * The effects of the mutation, if the listener was configured with `effectFormat: 'mendoza'`.\n * Object with `apply` and `revert` arrays, see {@link https://github.com/sanity-io/mendoza}.\n */\n effects?: {apply: unknown[]; revert: unknown[]}\n\n /**\n * A timestamp for when the mutation was performed\n */\n timestamp: string\n\n /**\n * The transaction ID for the mutation\n */\n transactionId: string\n\n /**\n * The type of transition the document went through.\n *\n * - `update` means the document was previously part of the subscribed set of documents,\n * and still is.\n * - `appear` means the document was not previously part of the subscribed set of documents,\n * but is now. This can happen both on create or if updating to a state where it now matches\n * the filter provided to the listener.\n * - `disappear` means the document was previously part of the subscribed set of documents,\n * but is no longer. This can happen both on delete or if updating to a state where it no\n * longer matches the filter provided to the listener.\n */\n transition: 'update' | 'appear' | 'disappear'\n\n /**\n * Whether the change that triggered this event is visible to queries (query) or only to\n * subsequent transactions (transaction). The listener client can specify a preferred visibility\n * through the `visibility` parameter on the listener, but this is only on a best-effort basis,\n * and may yet not be accurate.\n */\n visibility: 'query' | 'transaction'\n\n /**\n * The total number of events that will be sent for this transaction.\n * Note that this may differ from the amount of _documents_ affected by the transaction, as this\n * number only includes the documents that matches the given filter.\n *\n * This can be useful if you need to perform changes to all matched documents atomically,\n * eg you would wait for `transactionTotalEvents` events with the same `transactionId` before\n * applying the changes locally.\n */\n transactionTotalEvents: number\n\n /**\n * The index of this event within the transaction. Note that events may be delivered out of order,\n * and that the index is zero-based.\n */\n transactionCurrentEvent: number\n}\n\n/**\n * An error occurred. This is different from a network-level error (which will be emitted as 'error').\n * Possible causes are things such as malformed filters, non-existant datasets or similar.\n *\n * @public\n */\nexport type ChannelErrorEvent = {\n type: 'channelError'\n message: string\n}\n\n/**\n * The listener has been told to explicitly disconnect and not reconnect.\n * This is a rare situation, but may occur if the API knows reconnect attempts will fail,\n * eg in the case of a deleted dataset, a blocked project or similar events.\n *\n * Note that this is not treated as an error on the observable, but will complete the observable.\n *\n * @public\n */\nexport type DisconnectEvent = {\n type: 'disconnect'\n reason: string\n}\n\n/**\n * The listener has been disconnected, and a reconnect attempt is scheduled.\n *\n * @public\n */\nexport type ReconnectEvent = {\n type: 'reconnect'\n}\n\n/**\n * The listener connection has been established\n * note: it's usually a better option to use the 'welcome' event\n * @public\n */\nexport type OpenEvent = {\n type: 'open'\n}\n\n/**\n * Emitted when the listener connection has been successfully established\n * and is ready to receive events.\n *\n * If the listener was created with `enableResume: true` and resume support\n * is available, the `welcome` event will only be emitted on the initial\n * connection. On subsequent reconnects, a `welcomeback` event will be\n * emitted instead, followed by any events that were missed while the\n * connection was disconnected.\n *\n * @public\n */\nexport type WelcomeEvent = {\n type: 'welcome'\n listenerName: string\n}\n\n/**\n * Emitted when the listener reconnects and successfully resumes from\n * its previous position.\n *\n * Even if the listener is created with `enableResume: true`, resume support\n * may not be available. In that case, a reconnect will emit `welcome`\n * instead of `welcomeback`.\n *\n * If resumability is unavailable, even listeners created with `enableResume: true` may still\n * emit `welcome` when reconnected. Subscribers should therefore treat `welcome` after a reconnect\n * the same way they would otherwise treat a `reset` event.\n *\n * @public\n */\nexport type WelcomeBackEvent = {\n type: 'welcomeback'\n listenerName: string\n}\n\n/**\n * The listener can't be resumed or otherwise need to reset its local state\n *\n * If resumability is unavailable, even listeners created with `enableResume: true` may still\n * emit `welcome` when reconnected. Subscribers should therefore treat `welcome` after a reconnect\n * the same way they would otherwise treat a `reset` event.\n *\n * @public\n */\nexport type ResetEvent = {\n type: 'reset'\n}\n\n/** @public */\nexport type ListenEvent<R extends Record<string, Any> = Record<string, Any>> =\n MutationEvent<R> | ReconnectEvent | WelcomeBackEvent | ResetEvent | WelcomeEvent | OpenEvent\n\n/** @public */\nexport type ListenEventName =\n /** A mutation was performed */\n | 'mutation'\n /** The listener has been (re)established */\n | 'welcome'\n /** The listener has been disconnected, and a reconnect attempt is scheduled */\n | 'reconnect'\n /**\n * The listener connection has been established\n * note: it's usually a better option to use the 'welcome' event\n */\n | 'open'\n\n/** @public */\nexport type ResumableListenEventNames =\n | ListenEventName\n /** The listener has reconnected and successfully resumed from where it left off */\n | 'welcomeback'\n /** The listener can't be resumed or otherwise need to reset its local state */\n | 'reset'\n\n/** @public */\nexport type ListenParams = {[key: string]: Any}\n\n/** @public */\nexport interface ListenOptions {\n /**\n * Whether or not to include the resulting document in addition to the mutations performed.\n * If you do not need the actual document, set this to `false` to reduce bandwidth usage.\n * The result will be available on the `.result` property of the events.\n * @defaultValue `true`\n */\n includeResult?: boolean\n\n /**\n * Whether or not to include the mutations that was performed.\n * If you do not need the mutations, set this to `false` to reduce bandwidth usage.\n * @defaultValue `true`\n */\n includeMutations?: boolean\n\n /**\n * Whether or not to include the document as it looked before the mutation event.\n * The previous revision will be available on the `.previous` property of the events,\n * and may be `null` in the case of a new document.\n * @defaultValue `false`\n */\n includePreviousRevision?: boolean\n\n /*\n * Whether to include events for drafts and versions. As of API Version >= v2025-02-19, only events\n * for published documents will be included by default (see {@link https://www.sanity.io/changelog/676aaa9d-2da6-44fb-abe5-580f28047c10|Changelog})\n * If you need events from drafts and versions, set this to `true`.\n * Note: Keep in mind that additional document variants may be introduced in the future, so it's\n * recommended to respond to events in a way that's tolerant of potential future variants, e.g. by\n * explicitly checking whether the event is for a draft or a version.\n * @defaultValue `false`\n */\n includeAllVersions?: boolean\n\n /**\n * Whether events should be sent as soon as a transaction has been committed (`transaction`, default),\n * or only after they are available for queries (query). Note that this is on a best-effort basis,\n * and listeners with `query` may in certain cases (notably with deferred transactions) receive events\n * that are not yet visible to queries.\n *\n * @defaultValue `'transaction'`\n */\n visibility?: 'transaction' | 'query'\n\n /**\n * Array of event names to include in the observable. By default, only mutation events are included.\n * Note: `welcomeback` and `reset` events requires `enableResume: true`\n * @defaultValue `['mutation']`\n */\n events?: ListenEventName[]\n\n /**\n * Format of \"effects\", eg the resulting changes of a mutation.\n * Currently only `mendoza` is supported, and (if set) will include `apply` and `revert` arrays\n * in the mutation events under the `effects` property.\n *\n * See {@link https://github.com/sanity-io/mendoza | The mendoza docs} for more info\n *\n * @defaultValue `undefined`\n */\n effectFormat?: 'mendoza'\n\n /**\n * Optional request tag for the listener. Use to identify the request in logs.\n *\n * @defaultValue `undefined`\n */\n tag?: string\n\n /**\n * If this is enabled, the client will normally resume events upon reconnect\n * 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.\n * @beta\n * @defaultValue `false`\n */\n enableResume?: boolean\n}\n\n/** @public */\nexport interface ResumableListenOptions extends Omit<ListenOptions, 'events' | 'enableResume'> {\n /**\n * If this is enabled, the client will normally resume events upon reconnect\n * Note that you should also subscribe to `reset`-events and handle the case where the backend is unable to resume\n * @beta\n * @defaultValue `false`\n */\n enableResume: true\n\n /**\n * Array of event names to include in the observable. By default, only mutation events are included.\n *\n * @defaultValue `['mutation']`\n */\n events?: ResumableListenEventNames[]\n}\n\n/** @public */\nexport interface ResponseQueryOptions extends RequestOptions {\n perspective?: ClientPerspective\n /**\n * @beta\n */\n variant?: ClientVariant\n resultSourceMap?: boolean | 'withKeyArraySelector'\n returnQuery?: boolean\n useCdn?: boolean\n stega?: boolean | StegaConfig\n // The `cache` and `next` options are specific to the Next.js App Router integration\n cache?: 'next' extends keyof RequestInit ? RequestInit['cache'] : never\n next?: ('next' extends keyof RequestInit ? RequestInit : never)['next']\n lastLiveEventId?: string | string[] | null\n\n /**\n * When set to `noStale`, APICDN will not return a cached response if the content is stale.\n * Tradeoff between latency and freshness of content.\n *\n * Only to be used with live content queries and when useCdn is true.\n */\n cacheMode?: 'noStale'\n}\n\n/** @public */\nexport interface FilteredResponseQueryOptions extends ResponseQueryOptions {\n filterResponse?: true\n}\n\n/** @public */\nexport interface UnfilteredResponseQueryOptions extends ResponseQueryOptions {\n filterResponse: false\n\n /**\n * When `filterResponse` is `false`, `returnQuery` also defaults to `true` for\n * backwards compatibility (on the client side, not from the content lake API).\n * Can also explicitly be set to `true`.\n */\n returnQuery?: true\n}\n\n/**\n * When using `filterResponse: false`, but you do not wish to receive back the query from\n * the content lake API.\n *\n * @public\n */\nexport interface UnfilteredResponseWithoutQuery extends ResponseQueryOptions {\n filterResponse: false\n returnQuery: false\n}\n\n/** @public */\nexport type QueryOptions =\n FilteredResponseQueryOptions | UnfilteredResponseQueryOptions | UnfilteredResponseWithoutQuery\n\n/** @public */\nexport interface RawQueryResponse<R> {\n query: string\n ms: number\n result: R\n resultSourceMap?: ContentSourceMap\n /** Requires `apiVersion` to be `2021-03-25` or later. */\n syncTags?: SyncTag[]\n}\n\n/** @public */\nexport type RawQuerylessQueryResponse<R> = Omit<RawQueryResponse<R>, 'query'>\n\n/** @internal */\nexport type BaseMutationOptions = RequestOptions & {\n visibility?: 'sync' | 'async' | 'deferred'\n returnDocuments?: boolean\n returnFirst?: boolean\n dryRun?: boolean\n autoGenerateArrayKeys?: boolean\n skipCrossDatasetReferenceValidation?: boolean\n transactionId?: string\n}\n\n/** @internal */\nexport type FirstDocumentMutationOptions = BaseMutationOptions & {\n returnFirst?: true\n returnDocuments?: true\n}\n\n/** @internal */\nexport type FirstDocumentIdMutationOptions = BaseMutationOptions & {\n returnFirst?: true\n returnDocuments: false\n}\n\n/** @internal */\nexport type AllDocumentsMutationOptions = BaseMutationOptions & {\n returnFirst: false\n returnDocuments?: true\n}\n\n/** @internal */\nexport type MutationOperation = 'create' | 'delete' | 'update' | 'none'\n\n/** @internal */\nexport interface SingleMutationResult {\n transactionId: string\n documentId: string\n results: {id: string; operation: MutationOperation}[]\n}\n\n/** @internal */\nexport interface MultipleMutationResult {\n transactionId: string\n documentIds: string[]\n results: {id: string; operation: MutationOperation}[]\n}\n\n/** @internal */\nexport type AllDocumentIdsMutationOptions = BaseMutationOptions & {\n returnFirst: false\n returnDocuments: false\n}\n\n/** @internal */\nexport type AttributeSet = {[key: string]: Any}\n\n/** @internal */\nexport type TransactionFirstDocumentMutationOptions = BaseMutationOptions & {\n returnFirst: true\n returnDocuments: true\n}\n\n/** @internal */\nexport type TransactionFirstDocumentIdMutationOptions = BaseMutationOptions & {\n returnFirst: true\n returnDocuments?: false\n}\n\n/** @internal */\nexport type TransactionAllDocumentsMutationOptions = BaseMutationOptions & {\n returnFirst?: false\n returnDocuments: true\n}\n\n/** @internal */\nexport type TransactionAllDocumentIdsMutationOptions = BaseMutationOptions & {\n returnFirst?: false\n returnDocuments?: false\n}\n\n/** @internal */\nexport type TransactionMutationOptions =\n | TransactionFirstDocumentMutationOptions\n | TransactionFirstDocumentIdMutationOptions\n | TransactionAllDocumentsMutationOptions\n | TransactionAllDocumentIdsMutationOptions\n\n/** @internal */\nexport type BaseActionOptions = RequestOptions & {\n transactionId?: string\n skipCrossDatasetReferenceValidation?: boolean\n dryRun?: boolean\n}\n\n/** @internal */\nexport interface SingleActionResult {\n transactionId: string\n}\n\n/** @internal */\nexport interface MultipleActionResult {\n transactionId: string\n}\n\n/** @internal */\nexport interface RawRequestOptions {\n url?: string\n uri?: string\n method?: string\n token?: string\n json?: boolean\n tag?: string\n useGlobalApi?: boolean\n withCredentials?: boolean\n query?: {[key: string]: string | string[]}\n headers?: {[key: string]: string}\n timeout?: number\n proxy?: string\n body?: Any\n maxRedirects?: number\n signal?: AbortSignal\n}\n\n/** @internal */\nexport interface ApiError {\n error: string\n message: string\n statusCode: number\n}\n\n/** @internal */\nexport interface MutationError {\n type: 'mutationError'\n description: string\n items?: MutationErrorItem[]\n}\n\n/**\n * Returned from the Content Lake API when a query is malformed, usually with a start\n * and end column to indicate where the error occurred, but not always. Can we used to\n * provide a more structured error message to the user.\n *\n * This will be located under the response `error` property.\n *\n * @public\n */\nexport interface QueryParseError {\n type: 'queryParseError'\n description: string\n start?: number\n end?: number\n query?: string\n}\n\n/** @internal */\nexport interface MutationErrorItem {\n error: {\n type: string\n description: string\n value?: unknown\n }\n}\n\n/** @internal */\nexport interface ActionError {\n type: 'actionError'\n description: string\n items?: ActionErrorItem[]\n}\n\n/** @internal */\nexport interface ActionErrorItem {\n error: {\n type: string\n description: string\n value?: unknown\n }\n index: number\n}\n\n/** @internal */\nexport type PartialExcept<T, K extends keyof T> = Pick<T, K> & Partial<Omit<T, K>>\n\n/** @beta */\nexport type ReleaseState =\n | 'active'\n | 'archiving'\n | 'unarchiving'\n | 'archived'\n | 'published'\n | 'publishing'\n | 'scheduled'\n | 'scheduling'\n\n/** @internal */\nexport type ReleaseType = 'asap' | 'scheduled' | 'undecided'\n\n/** @public */\nexport type ReleaseCardinality = 'many' | 'one' | undefined\n\n/** @internal */\nexport interface ReleaseDocument extends SanityDocument {\n /**\n * typically\n * `_.releases.<name>`\n */\n _id: string\n /**\n * where a release has _id `_.releases.foo`, the name is `foo`\n */\n name: string\n _type: 'system.release'\n _createdAt: string\n _updatedAt: string\n _rev: string\n state: ReleaseState\n error?: {\n message: string\n }\n finalDocumentStates?: {\n /** Document ID */\n id: string\n }[]\n /**\n * If defined, it takes precedence over the intendedPublishAt, the state should be 'scheduled'\n */\n publishAt?: string\n /**\n * If defined, it provides the time the release was actually published\n */\n publishedAt?: string\n metadata: {\n title?: string\n description?: string\n intendedPublishAt?: string\n releaseType: ReleaseType\n cardinality?: ReleaseCardinality\n }\n}\n\n/** @internal */\nexport type EditableReleaseDocument = Omit<\n PartialExcept<ReleaseDocument, '_id'>,\n 'metadata' | '_type'\n> & {\n _id: string\n metadata: Partial<ReleaseDocument['metadata']>\n}\n\n/**\n * DocumentValueSource is a path to a value within a document\n * @public\n */\nexport interface ContentSourceMapDocumentValueSource {\n type: 'documentValue'\n // index location of the document\n document: number\n // index location of the path\n path: number\n}\n/**\n * When a value is not from a source, its a literal\n * @public\n */\nexport interface ContentSourceMapLiteralSource {\n type: 'literal'\n}\n/**\n * When a field source is unknown\n * @public\n */\nexport interface ContentSourceMapUnknownSource {\n type: 'unknown'\n}\n/** @public */\nexport type ContentSourceMapSource =\n | ContentSourceMapDocumentValueSource\n | ContentSourceMapLiteralSource\n | ContentSourceMapUnknownSource\n/**\n * ValueMapping is a mapping when for value that is from a single source value\n * It may refer to a field within a document or a literal value\n * @public\n */\nexport interface ContentSourc