Sanity Library Reference Docs
    Preparing search index...

    Module @sanity/workflow-studio - v0.32.0

    @sanity/workflow-studio

    Reactive workflow adapter for Sanity Studio. Everything must render inside Studio source context (useSource / useClient).

    • useWorkflowEngine({workflowResource, tag, resourceClients?}) — build the Studio-side engine once: the workspace client rebound to the engine's state dataset (engine traffic always rides the engine's own API version — createEngine pins it), with studioResourceClients (also exported) as the default per-resource routing that reaches any dataset: GDR by rebinding the same client, pinned to the engine version too. A custom resourceClients replaces the default — delegate to studioResourceClients for the dataset arm; schemes it returns undefined for (media-library, canvas) are READ by the engine itself, which derives a sibling client from the engine client's credentials. Writing a runtime-supplied ref to such a scheme into field state additionally needs the resolver to SERVE that resource — serving is what declares it on the engine's written-ref surface; an undeclared media-library/canvas ref is rejected at the write with RefResourceUndeclaredError. (Definition content is unaffected — deploy vets it.)
    • useWorkflowSession — drives an engine session for one instance and returns {evaluation, ready, invalid, error, guards, tick, fireAction, editField, previewField, discardFieldPreview}. The observer validates every engine-owned stream, so a model-ahead or corrupt doc surfaces as the explicit invalid state (never ready while set) instead of an eternal spinner.
    • useWorkflowInstances / useDocumentWorkflows — live instance lists (filterable collection / per-document discovery), each returning {instances, loading, unreadable, error} through the App SDK query store — rows the read discipline refuses are skipped from instances and flagged in unreadable. Hooks under one Studio source share the auto-bootstrapped SDK instance; callers can instead pass a shared sdk explicitly. SDK store errors surface reactively through error.
    • useWorkflowInstancePreviewsuseInstancePreviews (workflow-react) bound to the auto-bootstrapped observer: the whole tag partition as light preview rows, drained page by page and kept fresh from the shared change feed. Returns {previews, loading, drained, unreadable, error}.
    • useStudioProjectUsers — the shared Studio project-user directory used by actor resolution and member pickers. It returns the upstream membership and profile records without a Workflows projection, the project's assignable roles, and the engine's ProjectUserDirectory integration. The role catalog is read alongside the memberships and is the only account of a role nobody currently holds; it is filtered to roles a person can be assigned, and it is empty when the read is unavailable, which leaves role labels to the roles members hold and is reported once on the console with its cause. Concurrent loads are coalesced, the settled successful directory is reused for the client/project lifetime, and a failed membership load retries after a 30-second backoff. That backoff does not cover the catalog: an unavailable one is held empty for the client's lifetime rather than re-read. A directory that has not answered reports loading, including before its fetch starts (the fetch begins in a consumer's effect), so an empty users with loading: false and no error is a confirmed "no members" rather than a directory nobody has asked for. studioProjectUserDirectory provides the same contract outside React when a Studio client and project ID are already available.

    Every reactive stream uses the App SDK store, including documents in the mounted workspace, instance documents in the engine dataset, per-resource guard queries, and instance lists. Document and query observation therefore share the SDK's resource-scoped live streams instead of opening one Studio listener per document or query.

    Dataset GDRs route through {projectId, dataset} resource handles. canvas: and media-library: GDRs route through {canvasId} and {mediaLibraryId}. dashboard: remains unsupported because the App SDK has no dashboard document resource; a workflow with a dashboard subject must run engine-direct.

    The SDK store does not expose Studio's private, uncommitted form buffer. Reactive evaluation follows App SDK document state; Content Lake remains the authoritative state read by commits. For an explicit uncommitted projection, call the session's previewField callback and remove it with discardFieldPreview; these previews never persist the instance or content document.

    • When no sdk is supplied, the hook bootstraps an App SDK instance automatically in Studio mode. The SDK follows Studio's reactive token source, including token rotation; an authenticated Studio whose token source emits null uses cookie authentication. Callers may instead supply their own instance: useWorkflowSession({engine, instanceId, sdk}).
    • Guards (observeGuards) are observed wherever they live: a guard co-locates with the subject it locks, so the stream spans the datasets the instance's currently-observed GDRs name (engine dataset ∪ each open-stage/workflow-scope subject dataset). Every resource routes through the App SDK query store.
    • Auth caveat for foreign refs: the SDK instance's auth must cover the foreign resource; a foreign project needs a session/token valid there.
    • makeStudioObserver(sdk, {client, engineResource}) is exported for custom wiring, matching makeSdkObserver. client is required: a workspace-bound client that carries ensureDocumentExists writes into the mounted dataset.

    Remaining gaps (ancestor-instance guards, full cascade write-set pre-flight, live cross-dataset end-to-end verification) are known follow-up work.

    This adapter composes @sanity/workflow-sdk's store layer through its headless ./observer entry. What that means for installs:

    • @sanity/sdk is required (peer) — it addresses every observed resource.
    • @sanity/workflow-engine is required (peer) — the host and adapter share one engine runtime.
    • @sanity/workflow-react and @sanity/workflow-sdk are required (exact-version peers) — install the matching Workflows release stack so the reactive context and SDK store are single-sourced.
    • @sanity/sdk-react is NOT required — nothing here touches the App SDK's React binding.

    useSource remains a non-public Studio context hook, which is the standard plugin-context caveat.

    • See @sanity/workflow-react's README for the guard-verdict semantics (what mutation-guard-denied does and doesn't cover) and the editField commit caveat (discrete commits — never bind to an onChange per keystroke).

    Interfaces

    InstancePreviewList
    MutationGuardDoc
    StudioObserverOptions
    StudioProjectMembership
    StudioProjectUser
    StudioProjectUsersState
    StudioUserClient
    StudioUserProfile
    WorkflowInstanceList
    WorkflowSession

    Type Aliases

    InstancePreviewsFilter

    Functions

    makeStudioObserver
    studioProjectUserDirectory
    studioResourceClients
    useDocumentWorkflows
    useStudioObserver
    useStudioProjectUsers
    useWorkflowEngine
    useWorkflowInstancePreviews
    useWorkflowInstances
    useWorkflowSession