UNPKG

@sanity/sdk

Version:
1,431 lines (1,398 loc) 80.9 kB
import * as _sanity_client12 from "@sanity/client"; import { ClientConfig, ClientPerspective, ListenEvent, ResponseQueryOptions, SanityClient, SanityDocument as SanityDocument$1, SanityProject as SanityProject$1, StackablePerspective } from "@sanity/client"; import { Observable, Subject } from "rxjs"; import { CurrentUser, CurrentUser as CurrentUser$1, Mutation, PatchOperations, Role, SanityDocument, SanityDocument as SanityDocument$2, SanityDocumentLike } from "@sanity/types"; import * as _sanity_comlink3 from "@sanity/comlink"; import { ChannelInput, ChannelInstance, Controller, Message, Node, NodeInput, Status } from "@sanity/comlink"; import { PatchMutation } from "@sanity/mutate/_unstable_store"; import { SanityDocument as SanityDocument$3, SanityProjectionResult, SanityQueryResult } from "groq"; import { CanvasResource, MediaResource, StudioResource } from "@sanity/message-protocol"; import { getIndexForKey, getPathDepth, joinPaths, jsonMatch, slicePath, stringifyPath } from "@sanity/json-match"; /** * Represents the various states the authentication type can be in. * * @public */ declare enum AuthStateType { LOGGED_IN = "logged-in", LOGGING_IN = "logging-in", ERROR = "error", LOGGED_OUT = "logged-out", } /** * Configuration for an authentication provider * @public */ interface AuthProvider { /** * Unique identifier for the auth provider (e.g., 'google', 'github') */ name: string; /** * Display name for the auth provider in the UI */ title: string; /** * Complete authentication URL including callback and token parameters */ url: string; /** * Optional URL for direct sign-up flow */ signUpUrl?: string; } /** * Configuration options for creating an auth store. * * @public */ interface AuthConfig { /** * The initial location href to use when handling auth callbacks. * Defaults to the current window location if available. */ initialLocationHref?: string; /** * Factory function to create a SanityClient instance. * Defaults to the standard Sanity client factory if not provided. */ clientFactory?: (config: ClientConfig) => SanityClient; /** * Custom authentication providers to use instead of or in addition to the default ones. * Can be an array of providers or a function that takes the default providers and returns * a modified array or a Promise resolving to one. */ providers?: AuthProvider[] | ((prev: AuthProvider[]) => AuthProvider[] | Promise<AuthProvider[]>); /** * The API hostname for requests. Usually leave this undefined, but it can be set * if using a custom domain or CNAME for the API endpoint. */ apiHost?: string; /** * Storage implementation to persist authentication state. * Defaults to `localStorage` if available. */ storageArea?: Storage; /** * A callback URL for your application. * If none is provided, the auth API will redirect back to the current location (`location.href`). * When handling callbacks, this URL's pathname is checked to ensure it matches the callback. */ callbackUrl?: string; /** * A static authentication token to use instead of handling the OAuth flow. * When provided, the auth store will remain in a logged-in state with this token, * ignoring any storage or callback handling. */ token?: string; } /** * Represents the minimal configuration required to identify a Sanity project. * @public */ interface ProjectHandle<TProjectId extends string = string> { projectId?: TProjectId; } /** * @public */ type ReleasePerspective = { releaseName: string; excludedPerspectives?: StackablePerspective[]; }; /** * @public */ interface PerspectiveHandle { perspective?: ClientPerspective | ReleasePerspective; } /** * @public */ interface DatasetHandle<TDataset extends string = string, TProjectId extends string = string> extends ProjectHandle<TProjectId>, PerspectiveHandle { dataset?: TDataset; } /** * Identifies a specific document type within a Sanity dataset and project. * Includes `projectId`, `dataset`, and `documentType`. * Optionally includes a `documentId`, useful for referencing a specific document type context, potentially without a specific document ID. * @public */ interface DocumentTypeHandle<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string> extends DatasetHandle<TDataset, TProjectId> { documentId?: string; documentType: TDocumentType; } /** * Uniquely identifies a specific document within a Sanity dataset and project. * Includes `projectId`, `dataset`, `documentType`, and the required `documentId`. * Commonly used by document-related hooks and components to reference a document without fetching its full content initially. * @public */ interface DocumentHandle<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string> extends DocumentTypeHandle<TDocumentType, TDataset, TProjectId> { documentId: string; } /** * Represents the complete configuration for a Sanity SDK instance * @public */ interface SanityConfig extends DatasetHandle, PerspectiveHandle { /** * Authentication configuration for the instance * @remarks Merged with parent configurations when using createChild */ auth?: AuthConfig; /** * Studio mode configuration for use of the SDK in a Sanity Studio * @remarks Controls whether studio mode features are enabled */ studioMode?: { enabled: boolean; }; } /** * Represents a Sanity.io resource instance with its own configuration and lifecycle * @remarks Instances form a hierarchy through parent/child relationships * * @public */ interface SanityInstance { /** * Unique identifier for this instance * @remarks Generated using crypto.randomUUID() */ readonly instanceId: string; /** * Resolved configuration for this instance * @remarks Merges values from parent instances where appropriate */ readonly config: SanityConfig; /** * Checks if the instance has been disposed * @returns true if dispose() has been called */ isDisposed(): boolean; /** * Disposes the instance and cleans up associated resources * @remarks Triggers all registered onDispose callbacks */ dispose(): void; /** * Registers a callback to be invoked when the instance is disposed * @param cb - Callback to execute on disposal * @returns Function to unsubscribe the callback */ onDispose(cb: () => void): () => void; /** * Gets the parent instance in the hierarchy * @returns Parent instance or undefined if this is the root */ getParent(): SanityInstance | undefined; /** * Creates a child instance with merged configuration * @param config - Configuration to merge with parent values * @remarks Child instances inherit parent configuration but can override values */ createChild(config: SanityConfig): SanityInstance; /** * Traverses the instance hierarchy to find the first instance whose configuration * matches the given target config using a shallow comparison. * @param targetConfig - A partial configuration object containing key-value pairs to match. * @returns The first matching instance or undefined if no match is found. */ match(targetConfig: Partial<SanityConfig>): SanityInstance | undefined; } /** * Creates a new Sanity resource instance * @param config - Configuration for the instance (optional) * @returns A configured SanityInstance * @remarks When creating child instances, configurations are merged with parent values * * @public */ declare function createSanityInstance(config?: SanityConfig): SanityInstance; /** * Represents a store action that has been bound to a specific store instance */ type BoundStoreAction<_TState, TParams extends unknown[], TReturn> = (instance: SanityInstance, ...params: TParams) => TReturn; /** * Creates an action binder function that uses the provided key function * to determine how store instances are shared between Sanity instances * * @param keyFn - Function that generates a key from a Sanity config * @returns A function that binds store actions to Sanity instances * * @remarks * Action binders determine how store instances are shared across multiple * Sanity instances. The key function determines which instances share state. * * @example * ```ts * // Create a custom binder that uses a tenant ID for isolation * const bindActionByTenant = createActionBinder(config => config.tenantId || 'default') * * // Use the custom binder with a store definition * const getTenantUsers = bindActionByTenant( * userStore, * ({state}) => state.get().users * ) * ``` */ /** * Represents the various states the authentication can be in. * * @public */ type AuthState = LoggedInAuthState | LoggedOutAuthState | LoggingInAuthState | ErrorAuthState; /** * Logged-in state from the auth state. * @public */ type LoggedInAuthState = { type: AuthStateType.LOGGED_IN; token: string; currentUser: CurrentUser$1 | null; lastTokenRefresh?: number; }; /** * Logged-out state from the auth state. * @public */ type LoggedOutAuthState = { type: AuthStateType.LOGGED_OUT; isDestroyingSession: boolean; }; /** * Logging-in state from the auth state. * @public */ type LoggingInAuthState = { type: AuthStateType.LOGGING_IN; isExchangingToken: boolean; }; /** * Error state from the auth state. * @public */ type ErrorAuthState = { type: AuthStateType.ERROR; error: unknown; }; /** * Represents the various states the authentication can be in. * * @public */ interface DashboardContext { mode?: string; env?: string; orgId?: string; } type AuthMethodOptions = 'localstorage' | 'cookie' | undefined; /** * @public */ interface AuthStoreState { authState: AuthState; providers?: AuthProvider[]; options: { initialLocationHref: string; clientFactory: (config: ClientConfig) => SanityClient; customProviders: AuthConfig['providers']; storageKey: string; storageArea: Storage | undefined; apiHost: string | undefined; loginUrl: string; callbackUrl: string | undefined; providedToken: string | undefined; authMethod: AuthMethodOptions; }; dashboardContext?: DashboardContext; } /** * @public */ declare const getCurrentUserState: BoundStoreAction<AuthStoreState, [], StateSource<CurrentUser$1 | null>>; /** * @public */ declare const getTokenState: BoundStoreAction<AuthStoreState, [], StateSource<string | null>>; /** * @internal */ /** * @public */ declare const getLoginUrlState: BoundStoreAction<AuthStoreState, [], StateSource<string>>; /** * @public */ declare const getAuthState: BoundStoreAction<AuthStoreState, [], StateSource<AuthState>>; /** * @public */ declare const getDashboardOrganizationId: BoundStoreAction<AuthStoreState, [], StateSource<string | undefined>>; /** * Returns a state source indicating if the SDK is running within a dashboard context. * @public */ declare const getIsInDashboardState: BoundStoreAction<AuthStoreState, [], StateSource<boolean>>; /** * Action to explicitly set the authentication token. * Used internally by the Comlink token refresh. * @internal */ declare const setAuthToken: BoundStoreAction<AuthStoreState, [token: string | null], void>; /** * Error message returned by the organization verification * @public */ interface OrgVerificationResult { error: string | null; } /** * Compares a project's actual organization ID with the expected organization ID. * @public */ /** * Creates an observable that emits the organization verification state for a given instance. * It combines the dashboard organization ID (from auth context) with the * project's actual organization ID (fetched via getProjectState) and compares them. * @public */ declare function observeOrganizationVerificationState(instance: SanityInstance, projectIds: string[]): Observable<OrgVerificationResult>; /** * @public */ declare const handleAuthCallback: BoundStoreAction<AuthStoreState, [locationHref?: string | undefined], Promise<string | false>>; /** * @public */ declare const logout: BoundStoreAction<AuthStoreState, [], Promise<void>>; type AllowedClientConfigKey = 'useCdn' | 'token' | 'perspective' | 'apiHost' | 'proxy' | 'withCredentials' | 'timeout' | 'maxRetries' | 'dataset' | 'projectId' | 'requestTagPrefix' | 'useProjectHostname'; /** * States tracked by the client store * @public */ interface ClientStoreState { token: string | null; clients: { [TKey in string]?: SanityClient }; authMethod?: 'localstorage' | 'cookie'; } /** * Options used when retrieving a client instance from the client store. * * This interface extends the base {@link ClientConfig} and adds: * * - **apiVersion:** A required string indicating the API version for the client. * - **scope:** An optional flag to choose between the project-specific client * ('project') and the global client ('global'). When set to `'global'`, the * global client is used. * * These options are utilized by `getClient` and `getClientState` to configure and * return appropriate client instances that automatically handle authentication * updates and configuration changes. * * @public */ interface ClientOptions extends Pick<ClientConfig, AllowedClientConfigKey> { /** * An optional flag to choose between the default client (typically project-level) * and the global client ('global'). When set to `'global'`, the global client * is used. */ 'scope'?: 'default' | 'global'; /** * A required string indicating the API version for the client. */ 'apiVersion': string; /** * @internal */ '~experimental_resource'?: ClientConfig['~experimental_resource']; } /** * Retrieves a Sanity client instance configured with the provided options. * * This function returns a client instance configured for the project or as a * global client based on the options provided. It ensures efficient reuse of * client instances by returning the same instance for the same options. * For automatic handling of authentication token updates, consider using * `getClientState`. * * @public */ declare const getClient: BoundStoreAction<ClientStoreState, [options: ClientOptions], SanityClient>; /** * Returns a state source for the Sanity client instance. * * This function provides a subscribable state source that emits updated client * instances whenever relevant configurations change (such as authentication tokens). * Use this when you need to react to client configuration changes in your application. * * @public */ declare const getClientState: BoundStoreAction<ClientStoreState, [options: ClientOptions], StateSource<SanityClient>>; /** * Message sent from a containing app to an iframe * @public */ type FrameMessage = Message; /** * Message sent from an iframe to a containing app * @public */ type WindowMessage = Message; /** * Message from SDK (iframe) to Parent (dashboard) to request a new token * @internal */ type RequestNewTokenMessage = { type: 'dashboard/v1/auth/tokens/create'; payload?: undefined; }; /** * Message from Parent (dashboard) to SDK (iframe) with the new token * @internal */ type NewTokenResponseMessage = { type: 'dashboard/v1/auth/tokens/create'; payload: { token: string | null; error?: string; }; }; /** * Individual channel with its relevant options * @public */ interface ChannelEntry { channel: ChannelInstance<FrameMessage, WindowMessage>; options: ChannelInput; refCount: number; } /** * Internal state tracking comlink connections * @public */ interface ComlinkControllerState { controller: Controller | null; controllerOrigin: string | null; channels: Map<string, ChannelEntry>; } /** * Calls the destroy method on the controller and resets the controller state. * @public */ declare const destroyController: BoundStoreAction<ComlinkControllerState, [], void>; /** * Retrieve or create a channel to be used for communication between * an application and the controller. * @public */ declare const getOrCreateChannel: BoundStoreAction<ComlinkControllerState, [options: ChannelInput], ChannelInstance<_sanity_comlink3.Message, _sanity_comlink3.Message>>; /** * Initializes or fetches a controller to handle communication * between an application and iframes. * @public */ declare const getOrCreateController: BoundStoreAction<ComlinkControllerState, [targetOrigin: string], Controller>; /** * Signals to the store that the consumer has stopped using the channel * @public */ declare const releaseChannel: BoundStoreAction<ComlinkControllerState, [name: string], void>; /** * Individual node with its relevant options * @public */ interface NodeEntry { node: Node<WindowMessage, FrameMessage>; options: NodeInput; status: Status; statusUnsub?: () => void; } /** * Internal state tracking comlink connections * @public */ interface ComlinkNodeState { nodes: Map<string, NodeEntry>; subscriptions: Map<string, Set<symbol>>; } /** * Signals to the store that the consumer has stopped using the node * @public */ declare const releaseNode: BoundStoreAction<ComlinkNodeState, [name: string], void>; /** * Retrieve or create a node to be used for communication between * an application and the controller -- specifically, a node should * be created within a frame / window to communicate with the controller. * @public */ declare const getOrCreateNode: BoundStoreAction<ComlinkNodeState, [options: NodeInput], Node<_sanity_comlink3.Message, _sanity_comlink3.Message>>; /** * @public */ interface NodeState { node: Node<WindowMessage, FrameMessage>; status: Status | undefined; } /** * Provides a subscribable state source for a node by name * @param instance - The Sanity instance to get the node state for * @param nodeInput - The configuration for the node to get the state for * @returns A subscribable state source for the node * @public */ declare const getNodeState: BoundStoreAction<ComlinkNodeState, [NodeInput], StateSource<NodeState | undefined>>; /** * Creates or validates a `DocumentHandle` object. * Ensures the provided object conforms to the `DocumentHandle` interface. * @param handle - The object containing document identification properties. * @returns The validated `DocumentHandle` object. * @public */ declare function createDocumentHandle<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string>(handle: DocumentHandle<TDocumentType, TDataset, TProjectId>): DocumentHandle<TDocumentType, TDataset, TProjectId>; /** * Creates or validates a `DocumentTypeHandle` object. * Ensures the provided object conforms to the `DocumentTypeHandle` interface. * @param handle - The object containing document type identification properties. * @returns The validated `DocumentTypeHandle` object. * @public */ declare function createDocumentTypeHandle<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string>(handle: DocumentTypeHandle<TDocumentType, TDataset, TProjectId>): DocumentTypeHandle<TDocumentType, TDataset, TProjectId>; /** * Creates or validates a `ProjectHandle` object. * Ensures the provided object conforms to the `ProjectHandle` interface. * @param handle - The object containing project identification properties. * @returns The validated `ProjectHandle` object. * @public */ declare function createProjectHandle<TProjectId extends string = string>(handle: ProjectHandle<TProjectId>): ProjectHandle<TProjectId>; /** * Creates or validates a `DatasetHandle` object. * Ensures the provided object conforms to the `DatasetHandle` interface. * @param handle - The object containing dataset identification properties. * @returns The validated `DatasetHandle` object. * @public */ declare function createDatasetHandle<TDataset extends string = string, TProjectId extends string = string>(handle: DatasetHandle<TDataset, TProjectId>): DatasetHandle<TDataset, TProjectId>; /** @public */ declare const getDatasetsState: BoundStoreAction<FetcherStoreState<[options?: ProjectHandle<string> | undefined], _sanity_client12.DatasetsResponse>, [options?: ProjectHandle<string> | undefined], StateSource<_sanity_client12.DatasetsResponse | undefined>>; /** @public */ declare const resolveDatasets: BoundStoreAction<FetcherStoreState<[options?: ProjectHandle<string> | undefined], _sanity_client12.DatasetsResponse>, [options?: ProjectHandle<string> | undefined], Promise<_sanity_client12.DatasetsResponse>>; /** * Represents an action to create a new document. * Specifies the document type and optionally a document ID (which will be treated as the published ID). * @beta */ interface CreateDocumentAction<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string> extends DocumentTypeHandle<TDocumentType, TDataset, TProjectId> { type: 'document.create'; } /** * Represents an action to delete an existing document. * Requires the full document handle including the document ID. * @beta */ interface DeleteDocumentAction<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string> extends DocumentHandle<TDocumentType, TDataset, TProjectId> { type: 'document.delete'; } /** * Represents an action to edit an existing document using patches. * Requires the full document handle and an array of patch operations. * @beta */ interface EditDocumentAction<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string> extends DocumentHandle<TDocumentType, TDataset, TProjectId> { type: 'document.edit'; patches?: PatchOperations[]; } /** * Represents an action to publish the draft version of a document. * Requires the full document handle. * @beta */ interface PublishDocumentAction<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string> extends DocumentHandle<TDocumentType, TDataset, TProjectId> { type: 'document.publish'; } /** * Represents an action to unpublish a document, moving its published content to a draft. * Requires the full document handle. * @beta */ interface UnpublishDocumentAction<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string> extends DocumentHandle<TDocumentType, TDataset, TProjectId> { type: 'document.unpublish'; } /** * Represents an action to discard the draft changes of a document. * Requires the full document handle. * @beta */ interface DiscardDocumentAction<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string> extends DocumentHandle<TDocumentType, TDataset, TProjectId> { type: 'document.discard'; } /** * Union type representing all possible document actions within the SDK. * @beta */ type DocumentAction<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string> = CreateDocumentAction<TDocumentType, TDataset, TProjectId> | DeleteDocumentAction<TDocumentType, TDataset, TProjectId> | EditDocumentAction<TDocumentType, TDataset, TProjectId> | PublishDocumentAction<TDocumentType, TDataset, TProjectId> | UnpublishDocumentAction<TDocumentType, TDataset, TProjectId> | DiscardDocumentAction<TDocumentType, TDataset, TProjectId>; /** * Creates a `CreateDocumentAction` object. * @param doc - A handle identifying the document type, dataset, and project. An optional `documentId` can be provided. * @returns A `CreateDocumentAction` object ready for dispatch. * @beta */ declare function createDocument<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string>(doc: DocumentTypeHandle<TDocumentType, TDataset, TProjectId>): CreateDocumentAction<TDocumentType, TDataset, TProjectId>; /** * Creates a `DeleteDocumentAction` object. * @param doc - A handle uniquely identifying the document to be deleted. * @returns A `DeleteDocumentAction` object ready for dispatch. * @beta */ declare function deleteDocument<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string>(doc: DocumentHandle<TDocumentType, TDataset, TProjectId>): DeleteDocumentAction<TDocumentType, TDataset, TProjectId>; /** * Creates an `EditDocumentAction` object with patches for modifying a document. * Accepts patches in either the standard `PatchOperations` format or as a `SanityMutatePatchMutation` from `@sanity/mutate`. * * @param doc - A handle uniquely identifying the document to be edited. * @param sanityMutatePatch - A patch mutation object from `@sanity/mutate`. * @returns An `EditDocumentAction` object ready for dispatch. * @beta */ declare function editDocument<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string>(doc: DocumentHandle<TDocumentType, TDataset, TProjectId>, sanityMutatePatch: PatchMutation): EditDocumentAction<TDocumentType, TDataset, TProjectId>; /** * Creates an `EditDocumentAction` object with patches for modifying a document. * * @param doc - A handle uniquely identifying the document to be edited. * @param patches - A single patch operation or an array of patch operations. * @returns An `EditDocumentAction` object ready for dispatch. * @beta */ declare function editDocument<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string>(doc: DocumentHandle<TDocumentType, TDataset, TProjectId>, patches?: PatchOperations | PatchOperations[]): EditDocumentAction<TDocumentType, TDataset, TProjectId>; /** * Creates a `PublishDocumentAction` object. * @param doc - A handle uniquely identifying the document to be published. * @returns A `PublishDocumentAction` object ready for dispatch. * @beta */ declare function publishDocument<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string>(doc: DocumentHandle<TDocumentType, TDataset, TProjectId>): PublishDocumentAction<TDocumentType, TDataset, TProjectId>; /** * Creates an `UnpublishDocumentAction` object. * @param doc - A handle uniquely identifying the document to be unpublished. * @returns An `UnpublishDocumentAction` object ready for dispatch. * @beta */ declare function unpublishDocument<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string>(doc: DocumentHandle<TDocumentType, TDataset, TProjectId>): UnpublishDocumentAction<TDocumentType, TDataset, TProjectId>; /** * Creates a `DiscardDocumentAction` object. * @param doc - A handle uniquely identifying the document whose draft changes are to be discarded. * @returns A `DiscardDocumentAction` object ready for dispatch. * @beta */ declare function discardDocument<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string>(doc: DocumentHandle<TDocumentType, TDataset, TProjectId>): DiscardDocumentAction<TDocumentType, TDataset, TProjectId>; /** * Represents a set of document that will go into `applyMutations`. Before * applying a mutation, it's expected that all relevant documents that the * mutations affect are included, including those that do not exist yet. * Documents that don't exist have a `null` value. */ type DocumentSet<TDocument extends SanityDocument$2 = SanityDocument$2> = { [TDocumentId in string]?: TDocument | null }; /** * Implements ID generation: * * A create mutation creates a new document. It takes the literal document * content as its argument. The rules for the new document's identifier are as * follows: * * - If the `_id` attribute is missing, then a new, random, unique ID is * generated. * - If the `_id` attribute is present but ends with `.`, then it is used as a * prefix for a new, random, unique ID. * - If the _id attribute is present, it is used as-is. * * [- source](https://www.sanity.io/docs/http-mutations#c732f27330a4) */ /** @beta */ interface ActionsResult<TDocument extends SanityDocument$3 = SanityDocument$3> { transactionId: string; documents: DocumentSet<TDocument>; previous: DocumentSet<TDocument>; previousRevs: { [documentId: string]: string | undefined; }; appeared: string[]; updated: string[]; disappeared: string[]; submitted: () => ReturnType<SanityClient['action']>; } /** @beta */ interface ApplyDocumentActionsOptions { /** * Optionally provide an ID to be used as this transaction ID */ transactionId?: string; /** * Set this to true to prevent this action from being batched with others. */ disableBatching?: boolean; } /** @beta */ declare function applyDocumentActions<TDocumentType extends string = string, TDataset extends string = string, TProjectId extends string = string>(instance: SanityInstance, action: DocumentAction<TDocumentType, TDataset, TProjectId> | DocumentAction<TDocumentType, TDataset, TProjectId>[], options?: ApplyDocumentActionsOptions): Promise<ActionsResult<SanityDocument$3<TDocumentType, `${TProjectId}.${TDataset}`>>>; /** @beta */ declare function applyDocumentActions(instance: SanityInstance, action: DocumentAction | DocumentAction[], options?: ApplyDocumentActionsOptions): Promise<ActionsResult>; declare interface AccessAttributeNode extends BaseNode { type: 'AccessAttribute'; base?: ExprNode; name: string; } declare interface AccessElementNode extends BaseNode { type: 'AccessElement'; base: ExprNode; index: number; } declare interface AndNode extends BaseNode { type: 'And'; left: ExprNode; right: ExprNode; } declare type AnyStaticValue = StringValue | NumberValue | NullValue | BooleanValue | DateTimeValue | ObjectValue | ArrayValue | PathValue; declare interface ArrayCoerceNode extends BaseNode { type: 'ArrayCoerce'; base: ExprNode; } declare interface ArrayElementNode extends BaseNode { type: 'ArrayElement'; value: ExprNode; isSplat: boolean; } declare interface ArrayNode extends BaseNode { type: 'Array'; elements: ArrayElementNode[]; } /** Describes a type node for array values. */ declare type ArrayValue = StaticValue<unknown[], 'array'>; declare interface AscNode extends BaseNode { type: 'Asc'; base: ExprNode; } /** The base interface for SyntaxNode. */ declare interface BaseNode { type: string; } /** Describes a type node for boolean values, optionally including a value. If a value is provided it will always be the given boolean value. */ declare type BooleanValue = StaticValue<boolean, 'boolean'>; declare interface Context { timestamp: Date; identity: string; before: Value | null; after: Value | null; sanity?: { projectId: string; dataset: string; }; dereference?: DereferenceFunction; } declare interface ContextNode extends BaseNode { type: 'Context'; key: string; } /** * createReferenceTypeNode creates a ObjectTypeNode representing a reference type * it adds required attributes for a reference type. * @param name - The name of the reference type * @param inArray - Whether the reference is in an array * @returns A ObjectTypeNode representing a reference type * @internal */ declare class DateTime { date: Date; constructor(date: Date); static parseToValue(str: string): Value; equals(other: DateTime): boolean; add(secs: number): DateTime; difference(other: DateTime): number; compareTo(other: DateTime): number; toString(): string; toJSON(): string; } declare type DateTimeValue = StaticValue<DateTime, 'datetime'>; declare type DereferenceFunction = (obj: { _ref: string; }) => PromiseLike<Document_2 | null | undefined>; declare interface DerefNode extends BaseNode { type: 'Deref'; base: ExprNode; } declare interface DescNode extends BaseNode { type: 'Desc'; base: ExprNode; } declare type Document_2 = { _id?: string; _type?: string; [T: string]: unknown; }; declare interface EverythingNode extends BaseNode { type: 'Everything'; } declare type Executor<N = ExprNode> = (node: N, scope: Scope) => Value | PromiseLike<Value>; /** * A node which can be evaluated into a value. * @public */ declare type ExprNode = AccessAttributeNode | AccessElementNode | AndNode | ArrayNode | ArrayCoerceNode | AscNode | ContextNode | DerefNode | DescNode | EverythingNode | FilterNode | FlatMapNode | FuncCallNode | GroupNode | InRangeNode | MapNode | NegNode | NotNode | ObjectNode | OpCallNode | OrNode | ParameterNode | ParentNode_2 | PipeFuncCallNode | PosNode | ProjectionNode | SelectNode | SelectorNode | SliceNode | ThisNode | TupleNode | ValueNode; declare interface FilterNode extends BaseNode { type: 'Filter'; base: ExprNode; expr: ExprNode; } declare interface FlatMapNode extends BaseNode { type: 'FlatMap'; base: ExprNode; expr: ExprNode; } declare interface FuncCallNode extends BaseNode { type: 'FuncCall'; func: GroqFunction; namespace: string; name: string; args: ExprNode[]; } /** @public */ declare type GroqFunction = (args: GroqFunctionArg[], scope: Scope, execute: Executor) => PromiseLike<Value>; /** @public */ declare type GroqFunctionArg = ExprNode; declare type GroqPipeFunction = (base: Value, args: ExprNode[], scope: Scope, execute: Executor) => PromiseLike<Value>; /** * A type of a value in GROQ. */ declare type GroqType = 'null' | 'boolean' | 'number' | 'string' | 'array' | 'object' | 'path' | 'datetime'; declare interface GroupNode extends BaseNode { type: 'Group'; base: ExprNode; } /** Describes a type node for inline values, including a name that references another type. */ declare interface InRangeNode extends BaseNode { type: 'InRange'; base: ExprNode; left: ExprNode; right: ExprNode; isInclusive: boolean; } declare interface MapNode extends BaseNode { type: 'Map'; base: ExprNode; expr: ExprNode; } declare interface NegNode extends BaseNode { type: 'Neg'; base: ExprNode; } declare interface NotNode extends BaseNode { type: 'Not'; base: ExprNode; } /** Describes a type node for null values, always being the null value. */ declare type NullValue = StaticValue<null, 'null'>; /** Describes a type node for number values, optionally including a value. If a value is provided it will always be the given numeric value.*/ declare type NumberValue = StaticValue<number, 'number'>; /** Describes a type node for object attributes, including a type and an optional flag for being optional. */ declare type ObjectAttributeNode = ObjectAttributeValueNode | ObjectConditionalSplatNode | ObjectSplatNode; declare interface ObjectAttributeValueNode extends BaseNode { type: 'ObjectAttributeValue'; name: string; value: ExprNode; } declare interface ObjectConditionalSplatNode extends BaseNode { type: 'ObjectConditionalSplat'; condition: ExprNode; value: ExprNode; } declare interface ObjectNode extends BaseNode { type: 'Object'; attributes: ObjectAttributeNode[]; } declare interface ObjectSplatNode extends BaseNode { type: 'ObjectSplat'; value: ExprNode; } /** * Describes a type node for object values, including a collection of attributes and an optional rest value. * The rest value can be another ObjectTypeNode, an UnknownTypeNode, or an InlineTypeNode. * If the rest value is an ObjectTypeNode, it means that the object can have additional attributes. * If the rest value is an UnknownTypeNode, the entire object is unknown. * If the rest value is an InlineTypeNode, it means that the object has additional attributes from the referenced type. */ declare type ObjectValue = StaticValue<Record<string, unknown>, 'object'>; declare type OpCall = '==' | '!=' | '>' | '>=' | '<' | '<=' | '+' | '-' | '*' | '/' | '%' | '**' | 'in' | 'match'; declare interface OpCallNode extends BaseNode { type: 'OpCall'; op: OpCall; left: ExprNode; right: ExprNode; } declare interface OrNode extends BaseNode { type: 'Or'; left: ExprNode; right: ExprNode; } declare interface ParameterNode extends BaseNode { type: 'Parameter'; name: string; } declare interface ParentNode_2 extends BaseNode { type: 'Parent'; n: number; } declare class Path { private pattern; private patternRe; constructor(pattern: string); matches(str: string): boolean; toJSON(): string; } declare type PathValue = StaticValue<Path, 'path'>; declare interface PipeFuncCallNode extends BaseNode { type: 'PipeFuncCall'; func: GroqPipeFunction; base: ExprNode; name: string; args: ExprNode[]; } declare interface PosNode extends BaseNode { type: 'Pos'; base: ExprNode; } /** Union of any primitive type nodes. */ declare interface ProjectionNode extends BaseNode { type: 'Projection'; base: ExprNode; expr: ExprNode; } /** A schema consisting of a list of Document or TypeDeclaration items, allowing for complex type definitions. */ declare class Scope { params: Record<string, unknown>; source: Value; value: Value; parent: Scope | null; context: Context; isHidden: boolean; constructor(params: Record<string, unknown>, source: Value, value: Value, context: Context, parent: Scope | null); createNested(value: Value): Scope; createHidden(value: Value): Scope; } declare interface SelectAlternativeNode extends BaseNode { type: 'SelectAlternative'; condition: ExprNode; value: ExprNode; } declare interface SelectNode extends BaseNode { type: 'Select'; alternatives: SelectAlternativeNode[]; fallback?: ExprNode; } declare interface SelectorNode extends BaseNode { type: 'Selector'; } declare interface SliceNode extends BaseNode { type: 'Slice'; base: ExprNode; left: number; right: number; isInclusive: boolean; } declare class StaticValue<P, T extends GroqType> { data: P; type: T; constructor(data: P, type: T); isArray(): boolean; get(): Promise<any>; [Symbol.asyncIterator](): Generator<Value, void, unknown>; } declare class StreamValue { type: 'stream'; private generator; private ticker; private isDone; private data; constructor(generator: () => AsyncGenerator<Value, void, unknown>); isArray(): boolean; get(): Promise<any>; [Symbol.asyncIterator](): AsyncGenerator<Value, void, unknown>; _nextTick(): Promise<void>; } /** Describes a type node for string values, optionally including a value. If a value is provided it will always be the given string value. */ declare type StringValue = StaticValue<string, 'string'>; /** Any sort of node which appears as syntax */ declare interface ThisNode extends BaseNode { type: 'This'; } declare interface TupleNode extends BaseNode { type: 'Tuple'; members: Array<ExprNode>; } /** Defines a type declaration with a specific name and a value that describes the structure of the type using a TypeNode. */ /** * The result of an expression. */ declare type Value = AnyStaticValue | StreamValue; declare interface ValueNode<P = any> { type: 'Value'; value: P; } /** * Represents a reactive state source that provides synchronized access to store data * * @remarks * Designed to work with React's useSyncExternalStore hook. Provides three ways to access data: * 1. `getCurrent()` for synchronous current value access * 2. `subscribe()` for imperative change notifications * 3. `observable` for reactive stream access * * @public */ interface StateSource<T> { /** * Subscribes to state changes with optional callback * @param onStoreChanged - Called whenever relevant state changes occur * @returns Unsubscribe function to clean up the subscription */ subscribe: (onStoreChanged?: () => void) => () => void; /** * Gets the current derived state value * * @remarks * Safe to call without subscription. Will always return the latest value * based on the current store state and selector parameters. */ getCurrent: () => T; /** * Observable stream of state values * * @remarks * Shares a single underlying subscription between all observers. Emits: * - Immediately with current value on subscription * - On every relevant state change * - Errors if selector throws */ observable: Observable<T>; } /** * Context passed to selectors when deriving state * * @remarks * Provides access to both the current state value and the Sanity instance, * allowing selectors to use configuration values when computing derived state. * The context is memoized for each state object and instance combination * to optimize performance and prevent unnecessary recalculations. * * @example * ```ts * // Using both state and instance in a selector (psuedo example) * const getUserByProjectId = createStateSourceAction( * ({ state, instance }: SelectorContext<UsersState>, options?: ProjectHandle) => { * const allUsers = state.users * const projectId = options?.projectId ?? instance.config.projectId * return allUsers.filter(user => user.projectId === projectId) * } * ) * ``` */ interface SelectorContext<TState> { /** * The current state object from the store */ state: TState; /** * The Sanity instance associated with this state */ instance: SanityInstance; } /** * Function type for selecting derived state from store state and parameters * @public */ type Selector<TState, TParams extends unknown[], TReturn> = (context: SelectorContext<TState>, ...params: TParams) => TReturn; /** * Configuration options for creating a state source action */ type ActionMap = { create: 'sanity.action.document.version.create'; discard: 'sanity.action.document.version.discard'; unpublish: 'sanity.action.document.unpublish'; delete: 'sanity.action.document.delete'; edit: 'sanity.action.document.edit'; publish: 'sanity.action.document.publish'; }; type OptimisticLock = { ifDraftRevisionId?: string; ifPublishedRevisionId?: string; }; type HttpAction = { actionType: ActionMap['create']; publishedId: string; attributes: SanityDocumentLike; } | { actionType: ActionMap['discard']; versionId: string; purge?: boolean; } | { actionType: ActionMap['unpublish']; draftId: string; publishedId: string; } | { actionType: ActionMap['delete']; publishedId: string; includeDrafts?: string[]; } | { actionType: ActionMap['edit']; draftId: string; publishedId: string; patch: PatchOperations; } | ({ actionType: ActionMap['publish']; draftId: string; publishedId: string; } & OptimisticLock); /** * Represents a transaction that is queued to be applied but has not yet been * applied. A transaction will remain in a queued state until all required * documents for the transactions are available locally. */ interface QueuedTransaction { /** * the ID of this transaction. this is generated client-side. */ transactionId: string; /** * the high-level actions associated with this transaction. note that these * actions don't mention draft IDs and is meant to abstract away the draft * model from users. */ actions: DocumentAction[]; /** * An optional flag set to disable this transaction from being batched with * other transactions. */ disableBatching?: boolean; } /** * Represents a transaction that has been applied locally but has not been * committed/transitioned-to-outgoing. These transactions are visible to the * user but may be rebased upon a new working document set. Applied transactions * also contain the resulting `outgoingActions` that will be submitted to * Content Lake. These `outgoingActions` depend on the state of the working * documents so they are recomputed on rebase and are only relevant to applied * actions (we cannot compute `outgoingActions` for queued transactions because * we haven't resolved the set of documents the actions are dependent on yet). * * In order to support better conflict resolution, the original `previous` set * is saved as the `base` set. */ interface AppliedTransaction extends QueuedTransaction { /** * the resulting set of documents after the actions have been applied */ working: DocumentSet; /** * the previous set of documents before the action was applied */ previous: DocumentSet; /** * the original `previous` document set captured when this action was * originally applied. this is used as a reference point to do a 3-way merge * if this applied transaction ever needs to be reapplied on a different * set of documents. */ base: DocumentSet; /** * the `_rev`s from `previous` document set */ previousRevs: { [TDocumentId in string]?: string }; /** * a timestamp for when this transaction was applied locally */ timestamp: string; /** * the resulting HTTP actions derived from the state of the `working` document * set. these are sent to Content Lake as-is when this transaction is batched * and transitioned into an outgoing transaction. */ outgoingActions: HttpAction[]; /** * similar to `outgoingActions` but comprised of mutations instead of action. * this left here for debugging purposes but could be used to send mutations * to Content Lake instead of actions. */ outgoingMutations: Mutation[]; } /** * Represents a set of applied transactions batched into a single outgoing * transaction. An outgoing transaction is the result of batching many applied * actions. An outgoing transaction may be reverted locally if the server * does not accept it. */ interface OutgoingTransaction extends AppliedTransaction { disableBatching: boolean; batchedTransactionIds: string[]; } interface UnverifiedDocumentRevision { transactionId: string; documentId: string; previousRev: string | undefined; timestamp: string; } type Grant = 'read' | 'update' | 'create' | 'history'; /** @beta */ interface PermissionDeniedReason { type: 'precondition' | 'access'; message: string; documentId?: string; } /** @beta */ type DocumentPermissionsResult = { allowed: false; message: string; reasons: PermissionDeniedReason[]; } | { allowed: true; message?: undefined; reasons?: undefined; }; /** @beta */ type DocumentEvent = ActionErrorEvent | TransactionRevertedEvent | TransactionAcceptedEvent | DocumentRebaseErrorEvent | DocumentEditedEvent | DocumentCreatedEvent | DocumentDeletedEvent | DocumentPublishedEvent | DocumentUnpublishedEvent | DocumentDiscardedEvent; /** * @beta * Event emitted when a precondition to applying an action fails. * (For example: when trying to edit a document that no longer exists.) */ interface ActionErrorEvent { type: 'error'; documentId: string; transactionId: string; message: string; error: unknown; } /** * @beta * Event emitted when a transaction is accepted. */ interface TransactionAcceptedEvent { type: 'accepted'; outgoing: OutgoingTransaction; result: Awaited<ReturnType<SanityClient['action']>>; } /** * @beta * Event emitted when a transaction is reverted. */ interface TransactionRevertedEvent { type: 'reverted'; message: string; error: unknown; outgoing: OutgoingTransaction; } /** * @beta * Event emitted when an attempt to apply local changes to a modified remote document fails. */ interface DocumentRebaseErrorEvent { type: 'rebase-error'; documentId: string; transactionId: string; message: string; error: unknown; } /** * @beta * Event emitted when a document is edited. */ interface DocumentEditedEvent { type: 'edited'; documentId: string; outgoing: OutgoingTransaction; } /** * @beta * Event emitted when a document is created. */ interface DocumentCreatedEvent { type: 'created'; documentId: string; outgoing: OutgoingTransaction; } /** * @beta * Event emitted when a document is deleted. */ interface DocumentDeletedEvent { type: 'deleted'; documentId: string; outgoing: OutgoingTransaction; } /** * @beta * Event emitted when a document is published. */ interface DocumentPublishedEvent { type: 'published'; documentId: string; outgoing: OutgoingTransaction; } /** * @beta * Event emitted when a document is unpublished. */ interface DocumentUnpublishedEvent { type: 'unpublished'; documentId: string; outgoing: OutgoingTransaction; } /** * @beta * Event emitted when a document version is discarded. */ interface DocumentDiscardedEvent { type: 'discarded'; documentId: string; outgoing: OutgoingTransaction; } /** * Split the entire path string on dots "outside" of any brackets. * * For example: * ``` * "friends[0].name" * ``` * * becomes: * * ``` * [...ParseSegment<"friends[0]">, ...ParseSegment<"name">] * ``` * * (We use a simple recursion that splits on the first dot.) */ type PathParts<TPath extends string> = TPath extends `${infer Head}.${infer Tail}` ? [Head, ...PathParts<Tail>] : TPath extends '' ? [] : [TPath]; /** * Given a type T and an array of "access keys" Parts, recursively index into T. * * If a part is a key, it looks up that property. * If T is an array and the part is a number, it "indexes" into the element type. */ type DeepGet<TValue, TPath extends readonly (string | number)[]> = TPath extends [] ? TValue : TPath extends readonly [infer THead, ...infer TTail] ? DeepGet<TValue extends undefined | null ? undefined : THead extends keyof TValue ? TValue[THead] : THead extends number ? TValue extends readonly (infer TElement)[] ? TElement | undefined : undefined : undefined, // Key/index doesn't exist TTail extends readonly (string | number)[] ? TTail : []> : never; /** * Given a document type TDocument and a JSON Match path string TPath, * compute the type found at that path. * @beta */ type JsonMatch<TDocument, TPath extends string> = DeepGet<TDocument, PathParts<TPath>>; /** * Recursively traverse a value. When an array is encountered, ensure that * each object item has a _key property. Memoized such that sub-objects that * have not changed aren't re-computed. */ interface SharedListener { events: Observable<Lis