Sanity Library Reference Docs
    Preparing search index...

    Store-specific observation, supplied by an adapter (@sanity/workflow-sdk / @sanity/workflow-studio). The engine session is store-agnostic; only these two reads differ between the App SDK and Studio document stores. Both start in loading and leave it on a value, validation failure, or read error, so the session is never fed a half-synced set, and resolve content docs to the perspective's release form (instance / ancestor / system.release docs read raw). Adapters typically build observeDocs from combineDocStores over a per-doc primitive.

    interface WorkflowObserver {
        ensureDocumentExists: (args: EnsureDocumentExistsArgs) => Promise<void>;
        fetchInstancePreviews: (
            query: CompiledQuery,
        ) => Promise<readonly unknown[]>;
        listenInstanceChanges: (
            args: {
                onEvent: (event: InstanceChangeEvent) => void;
                query: CompiledQuery;
            },
        ) => () => void;
        observeDocs: (
            documents: SubscriptionDocument[],
            perspective: WorkflowPerspective | undefined,
        ) => DocStore<ReadonlyMap<string, ObservedDoc>>;
        observeGuards: (
            args: {
                instanceId: string;
                resources: readonly DatasetResourceId[];
                sharedIds?: readonly string[];
            },
        ) => DocStore<ObservedGuards>;
        observeInstance: (instanceId: string) => DocStore<ObservedInstance>;
        observeInstances: (query: CompiledQuery) => DocStore<ObservedInstances>;
    }
    Index

    Properties

    ensureDocumentExists: (args: EnsureDocumentExistsArgs) => Promise<void>

    The store seam's one write primitive: make the document exist in the representations the engine's field hydration reads (drafts-over-published, or the release's version docs when releaseId is set — the matrix lives on the shared ensureDocumentExists implementation). Resolves once the write is committed, so a start flow can call it and then startInstance without racing the lake. Addresses the adapter's own content dataset (Studio: the mounted workspace; SDK: the instance's configured dataset).

    fetchInstancePreviews: (query: CompiledQuery) => Promise<readonly unknown[]>

    One-shot page fetch for the engine's instancePreviewsQuery reads, returning raw results; the react layer parses per row. One-shot by design: hydrated pages are kept fresh by WorkflowObserver.listenInstanceChanges refetches, never by re-running page queries.

    listenInstanceChanges: (
        args: {
            onEvent: (event: InstanceChangeEvent) => void;
            query: CompiledQuery;
        },
    ) => () => void

    Subscribe to the engine dataset's instance-change feed (the engine's instanceChangesQuery). The adapter holds one upstream listener per feed however many stores subscribe. A listener error never throws: the adapter reconnects with backoff and then emits a reset event, on which a consumer resynchronizes whatever the gap missed. Returns the unsubscribe.

    observeDocs: (
        documents: SubscriptionDocument[],
        perspective: WorkflowPerspective | undefined,
    ) => DocStore<ReadonlyMap<string, ObservedDoc>>
    observeGuards: (
        args: {
            instanceId: string;
            resources: readonly DatasetResourceId[];
            sharedIds?: readonly string[];
        },
    ) => DocStore<ObservedGuards>

    The instance's live mutation guards (temp.system.guard docs keyed by sourceInstanceId). A standalone stream — the engine excludes guards from the session's SubscriptionDocument set, so the adapter watches them separately; the hook surfaces the list and feeds it to the session (updateGuards) so evaluation re-runs as guards are deployed / deleted. Use the engine's instancesGuardQuery to build the per-resource query.

    Must start in loading, like observeDocs, and leave it on a value, validation failure, or read error, so the hook can distinguish a pending read from resolved-no-guards and gate readiness. A resolved-empty snapshot should be the shared NO_GUARDS identity.

    Guards co-locate with the subjects they lock, so they're spread across the resources the instance's currently-observed GDRs name; resources holds that set (engine dataset ∪ each open-stage/workflow-scope subject dataset, from guardResourcesFor, which is where guards that can deny right now live). The adapter subscribes one guard stream per resource and merges them (combineGuardStores); a dataset resource foreign to the store's own binding is reached the same way observeDocs reaches a foreign content ref.

    sharedIds is the consolidation seam: the id-set of every co-mounted session, handed identically to each one, so an adapter can subscribe one set-shaped live query per resource (the engine's instancesGuardQuery) instead of one per instance, fanning results back out per sourceInstanceId. The returned stream still holds only this instance's guards. The set must include instanceId — its rows could never arrive otherwise, so adapters reject the call rather than resolve a vacuously empty stream. Omitted, the adapter subscribes for this instance alone.

    observeInstance: (instanceId: string) => DocStore<ObservedInstance>
    observeInstances: (query: CompiledQuery) => DocStore<ObservedInstances>

    A live instance-list read against the engine's workflow resource. The CompiledQuery comes from the engine's instancesQuery, so the stateless and reactive paths see the same rows. Single-resource by definition — instances live only in the engine's own dataset. The snapshot starts in loading ("still discovering" and "confirmed none" must be distinguishable), then becomes the matching ObservedInstances snapshot (readable rows in instances, refused rows flagged per row in unreadable), an invalid result, or a read error, and remains reactive.