@sanity/workflow-studio 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/studio-observer.ts","../src/use-workflow-engine.ts","../src/use-studio-observer.ts","../src/use-workflow-session.tsx","../src/use-workflow-instances.tsx"],"sourcesContent":["import type {SanityInstance} from '@sanity/sdk'\nimport {\n contentReleaseName,\n instanceGuardQuery,\n WORKFLOW_INSTANCE_TYPE,\n type MutationGuardDoc,\n type WorkflowInstance,\n} from '@sanity/workflow-engine'\nimport {\n classifyRef,\n combineDocStores,\n combineGuardStores,\n sameDataset,\n type DatasetResourceId,\n type DocStore,\n type ObservedDoc,\n type WorkflowObserver,\n} from '@sanity/workflow-react/observer'\nimport {\n sdkContentDocStore,\n sdkGuardStore,\n sdkInstanceDocStore,\n sdkInstancesStore,\n} from '@sanity/workflow-sdk/observer'\nimport type {DocumentStore, EditStateFor} from 'sanity'\n\n/** The slice of an RxJS observable this module needs — kept structural so the\n * file doesn't take an `rxjs` import just to name the type. */\ninterface ObservableLike<E> {\n subscribe: (next: (value: E) => void) => {unsubscribe: () => void}\n}\n\n/** Bridge a replayed RxJS observable into a {@link DocStore}: cache the latest\n * resolved value and notify `useSyncExternalStore` on each emission. Both the\n * per-doc `editState` stream and the guard `listenQuery` stream share it. */\nfunction observableStore<E, T>({\n observable,\n resolve,\n initial,\n}: {\n observable: ObservableLike<E>\n resolve: (value: E) => T\n initial: T\n}): DocStore<T> {\n let latest = initial\n return {\n subscribe(onChange) {\n const subscription = observable.subscribe((value) => {\n latest = resolve(value)\n onChange()\n })\n return () => subscription.unsubscribe()\n },\n getSnapshot: () => latest,\n }\n}\n\nexport interface StudioObserverOptions {\n /** The workspace's project + dataset — the only resource Studio's\n * `documentStore` can address. */\n mounted: DatasetResourceId\n /** The engine's state dataset (`datasetResourceId(engine.workflowResource)`)\n * — where the instance doc and its verdict-relevant guards live. Routinely\n * a dedicated `workflows` dataset distinct from the workspace. */\n engineResource: DatasetResourceId\n /** Observe resources OUTSIDE the mounted dataset (foreign content refs, and\n * the engine dataset when it differs from the workspace) through the App\n * SDK store. Omit ⇒ any foreign observation throws an actionable\n * config-mismatch error instead of being silently misread. */\n sdk?: SanityInstance\n}\n\n/**\n * A {@link WorkflowObserver} that routes every stream to the store that can\n * actually address it:\n *\n * - Anything in the **mounted workspace dataset** → `documentStore`\n * (`pair.editState` for docs — including Studio's local uncommitted edits,\n * the one stream only Studio has — and `listenQuery` for guards and\n * instance lists).\n * - Anything else (foreign content refs; the engine's state dataset when it\n * isn't the workspace) → the App SDK store via {@link sdkInstanceDocStore} /\n * {@link sdkContentDocStore} / {@link sdkGuardStore} when\n * {@link StudioObserverOptions.sdk} is supplied; otherwise an actionable\n * error. Never a silent wrong-dataset read.\n */\nexport function makeStudioObserver(\n documentStore: DocumentStore,\n options: StudioObserverOptions,\n): WorkflowObserver {\n const {mounted, engineResource, sdk} = options\n const engineIsMounted = sameDataset(engineResource, mounted)\n\n const editStateStore = ({\n id,\n type,\n release,\n }: {\n id: string\n type: string\n release: string | undefined\n }): DocStore<ObservedDoc> =>\n observableStore<EditStateFor, ObservedDoc>({\n observable: documentStore.pair.editState(id, type, release),\n resolve: resolveEditState,\n initial: undefined,\n })\n\n const requireSdk = (what: string): SanityInstance => {\n if (sdk !== undefined) return sdk\n throw new Error(\n `@sanity/workflow-studio: ${what} — Studio's document store is bound to ${mounted.projectId}.${mounted.dataset} and cannot observe it. Pass an App SDK instance via the hook's \\`sdk\\` option (e.g. \\`useWorkflowSession({engine, instanceId, sdk})\\`) to observe foreign resources.`,\n )\n }\n\n return {\n observeInstance: (instanceId) => {\n if (engineIsMounted)\n return editStateStore({id: instanceId, type: WORKFLOW_INSTANCE_TYPE, release: undefined})\n return sdkInstanceDocStore({\n sdk: requireSdk(\n `instance \"${instanceId}\" lives in the engine dataset ${engineResource.projectId}.${engineResource.dataset}`,\n ),\n instanceId,\n engineResource,\n })\n },\n observeDocs: (documents, perspective) =>\n combineDocStores(\n documents.map((ref) => {\n if (classifyRef(ref, mounted) === 'mounted-dataset') {\n return {\n key: ref.globalDocumentId,\n store: editStateStore({\n id: ref.documentId,\n type: ref.type,\n release: contentReleaseName({ref, perspective}),\n }),\n }\n }\n return {\n key: ref.globalDocumentId,\n store: sdkContentDocStore({\n sdk: requireSdk(`\"${ref.globalDocumentId}\" lives outside this workspace`),\n ref,\n perspective,\n }),\n }\n }),\n ),\n observeGuards: (instanceId, resources) =>\n combineGuardStores(\n resources.map((resource) => {\n if (sameDataset(resource, mounted)) {\n const {query, params} = instanceGuardQuery(instanceId)\n // `undefined` until the first `listenQuery` emission — the loading\n // signal the guard merge and the hook's `ready` gate distinguish\n // from a resolved-empty guard list.\n return observableStore<MutationGuardDoc[], readonly MutationGuardDoc[] | undefined>({\n observable: documentStore.listenQuery(query, params, {}),\n resolve: (docs) => docs,\n initial: undefined,\n })\n }\n return sdkGuardStore({\n sdk: requireSdk(\n `guards for \"${instanceId}\" live in ${resource.projectId}.${resource.dataset}`,\n ),\n instanceId,\n resource,\n })\n }),\n ),\n observeInstances: (query) => {\n if (engineIsMounted) {\n // `initial: undefined` (not a shared empty) — a pending first read and\n // a confirmed empty list must stay distinguishable for `loading`.\n return observableStore<WorkflowInstance[], readonly WorkflowInstance[] | undefined>({\n observable: documentStore.listenQuery(query.query, query.params, {}),\n resolve: (docs) => docs,\n initial: undefined,\n })\n }\n return sdkInstancesStore({\n sdk: requireSdk(\n `the instance list lives in the engine dataset ${engineResource.projectId}.${engineResource.dataset}`,\n ),\n query,\n resource: engineResource,\n })\n },\n }\n}\n\n/**\n * Resolve an `editState` emission to a single observed value: `undefined` while\n * not ready (gates the session feed), otherwise the version / draft / published\n * doc in precedence order (`null` when the doc doesn't exist).\n */\nfunction resolveEditState(editState: EditStateFor): ObservedDoc {\n if (!editState.ready) return undefined\n return (editState.version ?? editState.draft ?? editState.published) as ObservedDoc\n}\n","import {\n createEngine,\n ENGINE_API_VERSION,\n type Engine,\n type ResourceClientResolver,\n type WorkflowClient,\n type WorkflowResource,\n} from '@sanity/workflow-engine'\nimport {datasetResourceId, useKeyed} from '@sanity/workflow-react/observer'\nimport {useMemo} from 'react'\nimport {useClient} from 'sanity'\n\n/**\n * Build the Studio-side engine once: the workspace client rebound to the\n * engine's state dataset, plus {@link studioResourceClients} as the default\n * per-resource routing — so subjects and refs across many content datasets\n * resolve without call sites assembling clients. Pass `resourceClients` to\n * override the routing (compose with {@link studioResourceClients} to keep\n * dataset-GDR routing). Memoized on the config's content, so inline\n * `workflowResource` literals are fine; a custom `resourceClients` function\n * should still be stable. Must render inside Studio source context.\n */\nexport function useWorkflowEngine({\n workflowResource,\n tag,\n resourceClients,\n apiVersion,\n}: {\n workflowResource: WorkflowResource\n tag: string\n resourceClients?: ResourceClientResolver\n apiVersion?: string\n}): Engine {\n const client = useClient({apiVersion: apiVersion ?? ENGINE_API_VERSION})\n const resource = useKeyed([workflowResource.type, workflowResource.id], () => workflowResource)\n return useMemo(() => {\n const engineDataset = datasetResourceId(resource)\n const engineClient = asWorkflowClient(\n client.withConfig({\n projectId: engineDataset.projectId,\n dataset: engineDataset.dataset,\n useCdn: false,\n }),\n )\n return createEngine({\n client: engineClient,\n workflowResource: resource,\n tag,\n resourceClients: resourceClients ?? studioResourceClients(client),\n })\n }, [client, resource, tag, resourceClients])\n}\n\n/**\n * The default Studio {@link ResourceClientResolver}: any fully-addressed\n * `dataset:` GDR resolves to the workspace client rebound to that\n * project/dataset; other schemes (media-library, canvas) return `undefined` so\n * the engine falls back to its own client. A custom resolver can delegate to\n * this for the dataset arm and handle other schemes itself.\n */\nexport function studioResourceClients(client: StudioClient): ResourceClientResolver {\n return (parsed) =>\n parsed.scheme === 'dataset' && parsed.projectId !== undefined && parsed.dataset !== undefined\n ? asWorkflowClient(\n client.withConfig({projectId: parsed.projectId, dataset: parsed.dataset, useCdn: false}),\n )\n : undefined\n}\n\ntype StudioClient = ReturnType<typeof useClient>\n\n/** The Studio client is structurally assignable to the engine's narrower\n * client — a typed identity, so drift breaks loudly at compile time. */\nfunction asWorkflowClient(client: StudioClient): WorkflowClient {\n return client\n}\n","import {createSanityInstance, type SanityInstance} from '@sanity/sdk'\nimport {ENGINE_API_VERSION, type Engine} from '@sanity/workflow-engine'\nimport {\n datasetResourceId,\n sameDataset,\n type DatasetResourceId,\n type WorkflowObserver,\n} from '@sanity/workflow-react/observer'\nimport {useEffect, useMemo, useRef} from 'react'\nimport {useDocumentStore, useSource} from 'sanity'\n\nimport {makeStudioObserver} from './studio-observer.ts'\n\n/** The client is only read for its auth config — no request is ever issued\n * with it — but `getClient` requires an apiVersion to hand one out. */\nconst SESSION_CLIENT_OPTIONS = {apiVersion: ENGINE_API_VERSION}\n\n/**\n * The Studio observer for this engine — the shared wiring under every\n * reactive hook in this package. Workspace-dataset streams ride\n * `documentStore`; anything foreign (routinely the engine's dedicated\n * `workflows` dataset) rides an App SDK instance, bootstrapped from the\n * Studio session when the caller doesn't supply one. Must run inside Studio\n * source context (so `useDocumentStore`/`useSource` resolve).\n */\nexport function useStudioObserver({\n engine,\n sdk: suppliedSdk,\n}: {\n engine: Engine\n sdk?: SanityInstance | undefined\n}): WorkflowObserver {\n const documentStore = useDocumentStore()\n const source = useSource()\n const {projectId, dataset} = source\n const mounted = useMemo(() => ({projectId, dataset}), [projectId, dataset])\n const engineResource = useMemo(() => datasetResourceId(engine.workflowResource), [engine])\n const sdk = useEmbeddedSdk({\n supplied: suppliedSdk,\n // The engine dataset being foreign is the signal an SDK instance is\n // needed; foreign content refs without one still fail loud per ref.\n needed: !sameDataset(engineResource, mounted),\n mounted,\n // The session's token rides the source client's config (absent under\n // cookie auth) — the public read; Studio's token storage is private.\n sessionToken: source.getClient(SESSION_CLIENT_OPTIONS).config().token,\n })\n return useMemo(\n () =>\n makeStudioObserver(documentStore, {\n mounted,\n engineResource,\n ...(sdk !== undefined ? {sdk} : {}),\n }),\n [documentStore, mounted, engineResource, sdk],\n )\n}\n\n/**\n * The supplied SDK instance, or one bootstrapped from the Studio session's\n * token when foreign observation is needed. Lifecycle mirrors the SDK's own\n * `ResourceProvider`: created in render (the observer needs it synchronously),\n * recreated when a previous unmount disposed it, and released via\n * {@link useDeferredDispose} — so StrictMode's unmount/remount probe neither\n * leaks an instance nor hands the remount a dead one. `sessionToken` is\n * captured at bootstrap, deliberately not part of the recreate key: a rotated\n * token surfaces as auth failures until remount, and keying on it would churn\n * the instance on every rotation. Exported for tests only.\n */\nexport function useEmbeddedSdk({\n supplied,\n needed,\n mounted,\n sessionToken,\n}: {\n supplied: SanityInstance | undefined\n needed: boolean\n mounted: DatasetResourceId\n sessionToken: string | undefined\n}): SanityInstance | undefined {\n const wanted = supplied === undefined && needed\n const held = useRef<{key: string; instance: SanityInstance} | undefined>(undefined)\n const key = `${mounted.projectId}.${mounted.dataset}`\n if (wanted && (held.current?.key !== key || held.current.instance.isDisposed())) {\n held.current = {key, instance: bootstrapInstance(mounted, sessionToken)}\n }\n const embedded = wanted ? held.current?.instance : undefined\n useDeferredDispose(embedded)\n return supplied ?? embedded\n}\n\n/** An SDK instance over the workspace's own project, authed with the Studio\n * session's token — the engine dataset is reached per-resource from here. */\nfunction bootstrapInstance(\n mounted: DatasetResourceId,\n sessionToken: string | undefined,\n): SanityInstance {\n if (sessionToken === undefined) {\n throw new Error(\n `@sanity/workflow-studio: the engine's state dataset is not this workspace's dataset, and no Studio session token is readable to bootstrap an App SDK instance (cookie-authenticated studio?). Pass one explicitly via the hook's \\`sdk\\` option, e.g. useWorkflowSession({engine, instanceId, sdk}).`,\n )\n }\n return createSanityInstance({\n projectId: mounted.projectId,\n dataset: mounted.dataset,\n auth: {token: sessionToken},\n })\n}\n\n/**\n * Dispose `instance` after unmount via a zero-delay timer that an immediate\n * remount of the same instance cancels — the SDK `ResourceProvider`'s own\n * idiom for surviving StrictMode's unmount/remount probe.\n */\nfunction useDeferredDispose(instance: SanityInstance | undefined): void {\n const disposal = useRef<\n {instance: SanityInstance; timeoutId: ReturnType<typeof setTimeout>} | undefined\n >(undefined)\n useEffect(() => {\n if (instance === undefined) return undefined\n if (disposal.current?.instance === instance) {\n clearTimeout(disposal.current.timeoutId)\n disposal.current = undefined\n }\n return () => {\n disposal.current = {\n instance,\n timeoutId: setTimeout(() => {\n if (!instance.isDisposed()) instance.dispose()\n }, 0),\n }\n }\n }, [instance])\n}\n","import type {SanityInstance} from '@sanity/sdk'\nimport type {Engine, WorkflowAccessOverride} from '@sanity/workflow-engine'\nimport {\n useWorkflowSession as useWorkflowSessionCore,\n type WorkflowSession,\n} from '@sanity/workflow-react'\n\nimport {useStudioObserver} from './use-studio-observer.ts'\n\n/**\n * Drive a workflow instance reactively from Sanity Studio. Watched docs in the\n * workspace's own dataset observe through `documentStore.pair.editState`\n * (including local uncommitted edits); everything else — the engine's state\n * dataset (routinely a dedicated `workflows` dataset) and foreign content\n * refs — observes through the App SDK store. When the engine dataset differs\n * from the workspace, an SDK instance is bootstrapped automatically from the\n * Studio session (pass `sdk` to supply your own — required for\n * cookie-authenticated studios, where no session token is readable). Returns\n * `{evaluation, ready, guards, tick, fireAction, editField}`; the consumer decides when\n * to advance. Must render inside Studio source context.\n */\nexport function useWorkflowSession({\n engine,\n instanceId,\n access,\n grantsFromPath,\n sdk,\n}: {\n engine: Engine\n instanceId: string\n access?: WorkflowAccessOverride\n grantsFromPath?: string\n sdk?: SanityInstance\n}): WorkflowSession {\n const observer = useStudioObserver({engine, sdk})\n // `sdk` is a store handle for the observer, never an `engine.session(...)`\n // argument — only the session options cross into the engine.\n return useWorkflowSessionCore({engine, instanceId, observer, opts: {access, grantsFromPath}})\n}\n","import type {SanityInstance} from '@sanity/sdk'\nimport type {Engine, GdrUri, InstancesQueryFilter} from '@sanity/workflow-engine'\nimport {\n useDocumentWorkflows as useDocumentWorkflowsCore,\n useWorkflowInstances as useWorkflowInstancesCore,\n type WorkflowInstanceList,\n} from '@sanity/workflow-react'\n\nimport {useStudioObserver} from './use-studio-observer.ts'\n\n/** A live, filterable workflow-instance list observed from Sanity Studio —\n * through `documentStore.listenQuery` when the engine dataset is the\n * workspace's own, else through an App SDK instance (auto-bootstrapped, or\n * supply `sdk`). Must render inside Studio source context. */\nexport function useWorkflowInstances({\n engine,\n filter,\n sdk,\n}: {\n engine: Engine\n filter?: InstancesQueryFilter\n sdk?: SanityInstance\n}): WorkflowInstanceList {\n const observer = useStudioObserver({engine, sdk})\n return useWorkflowInstancesCore({engine, observer, ...(filter !== undefined ? {filter} : {})})\n}\n\n/** Which in-flight instances reference this document (GDR URI) — live,\n * observed from Sanity Studio. Same routing and `sdk` rules as\n * {@link useWorkflowInstances}. */\nexport function useDocumentWorkflows({\n engine,\n document,\n sdk,\n}: {\n engine: Engine\n document: GdrUri\n sdk?: SanityInstance\n}): WorkflowInstanceList {\n const observer = useStudioObserver({engine, sdk})\n return useDocumentWorkflowsCore({engine, observer, document})\n}\n"],"names":["sdk","sameDataset","WORKFLOW_INSTANCE_TYPE","sdkInstanceDocStore","combineDocStores","classifyRef","contentReleaseName","sdkContentDocStore","combineGuardStores","instanceGuardQuery","sdkGuardStore","sdkInstancesStore","useClient","ENGINE_API_VERSION","useKeyed","useMemo","datasetResourceId","createEngine","useDocumentStore","useSource","useRef","createSanityInstance","useEffect","observer","useWorkflowSessionCore","useWorkflowInstancesCore","useDocumentWorkflowsCore"],"mappings":"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"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":["../src/studio-observer.ts","../src/use-workflow-engine.ts","../src/use-studio-observer.ts","../src/use-workflow-session.tsx","../src/use-workflow-instances.tsx"],"sourcesContent":["import type {SanityInstance} from '@sanity/sdk'\nimport {\n contentReleaseName,\n instanceGuardQuery,\n WORKFLOW_INSTANCE_TYPE,\n type MutationGuardDoc,\n type WorkflowInstance,\n} from '@sanity/workflow-engine'\nimport {\n classifyRef,\n combineDocStores,\n combineGuardStores,\n sameDataset,\n type DatasetResourceId,\n type DocStore,\n type ObservedDoc,\n type WorkflowObserver,\n} from '@sanity/workflow-react/observer'\nimport {\n sdkContentDocStore,\n sdkGuardStore,\n sdkInstanceDocStore,\n sdkInstancesStore,\n} from '@sanity/workflow-sdk/observer'\nimport type {DocumentStore, EditStateFor} from 'sanity'\n\n/** The slice of an RxJS observable this module needs — kept structural so the\n * file doesn't take an `rxjs` import just to name the type. */\ninterface ObservableLike<E> {\n subscribe: (next: (value: E) => void) => {unsubscribe: () => void}\n}\n\n/** Bridge a replayed RxJS observable into a {@link DocStore}: cache the latest\n * resolved value and notify `useSyncExternalStore` on each emission. Both the\n * per-doc `editState` stream and the guard `listenQuery` stream share it. */\nfunction observableStore<E, T>({\n observable,\n resolve,\n initial,\n}: {\n observable: ObservableLike<E>\n resolve: (value: E) => T\n initial: T\n}): DocStore<T> {\n let latest = initial\n return {\n subscribe(onChange) {\n const subscription = observable.subscribe((value) => {\n latest = resolve(value)\n onChange()\n })\n return () => subscription.unsubscribe()\n },\n getSnapshot: () => latest,\n }\n}\n\nexport interface StudioObserverOptions {\n /** The workspace's project + dataset — the only resource Studio's\n * `documentStore` can address. */\n mounted: DatasetResourceId\n /** The engine's state dataset (`datasetResourceId(engine.workflowResource)`)\n * — where the instance doc and its verdict-relevant guards live. Routinely\n * a dedicated `workflows` dataset distinct from the workspace. */\n engineResource: DatasetResourceId\n /** Observe resources OUTSIDE the mounted dataset (foreign content refs, and\n * the engine dataset when it differs from the workspace) through the App\n * SDK store. Omit ⇒ any foreign observation throws an actionable\n * config-mismatch error instead of being silently misread. */\n sdk?: SanityInstance\n}\n\n/**\n * A {@link WorkflowObserver} that routes every stream to the store that can\n * actually address it:\n *\n * - Anything in the **mounted workspace dataset** → `documentStore`\n * (`pair.editState` for docs — including Studio's local uncommitted edits,\n * the one stream only Studio has — and `listenQuery` for guards and\n * instance lists).\n * - Anything else (foreign content refs; the engine's state dataset when it\n * isn't the workspace) → the App SDK store via {@link sdkInstanceDocStore} /\n * {@link sdkContentDocStore} / {@link sdkGuardStore} when\n * {@link StudioObserverOptions.sdk} is supplied; otherwise an actionable\n * error. Never a silent wrong-dataset read.\n */\nexport function makeStudioObserver(\n documentStore: DocumentStore,\n options: StudioObserverOptions,\n): WorkflowObserver {\n const {mounted, engineResource, sdk} = options\n const engineIsMounted = sameDataset(engineResource, mounted)\n\n const editStateStore = ({\n id,\n type,\n release,\n }: {\n id: string\n type: string\n release: string | undefined\n }): DocStore<ObservedDoc> =>\n observableStore<EditStateFor, ObservedDoc>({\n observable: documentStore.pair.editState(id, type, release),\n resolve: resolveEditState,\n initial: undefined,\n })\n\n const requireSdk = (what: string): SanityInstance => {\n if (sdk !== undefined) return sdk\n throw new Error(\n `@sanity/workflow-studio: ${what} — Studio's document store is bound to ${mounted.projectId}.${mounted.dataset} and cannot observe it. Pass an App SDK instance via the hook's \\`sdk\\` option (e.g. \\`useWorkflowSession({engine, instanceId, sdk})\\`) to observe foreign resources.`,\n )\n }\n\n return {\n observeInstance: (instanceId) => {\n if (engineIsMounted)\n return editStateStore({id: instanceId, type: WORKFLOW_INSTANCE_TYPE, release: undefined})\n return sdkInstanceDocStore({\n sdk: requireSdk(\n `instance \"${instanceId}\" lives in the engine dataset ${engineResource.projectId}.${engineResource.dataset}`,\n ),\n instanceId,\n engineResource,\n })\n },\n observeDocs: (documents, perspective) =>\n combineDocStores(\n documents.map((ref) => {\n if (classifyRef(ref, mounted) === 'mounted-dataset') {\n return {\n key: ref.globalDocumentId,\n store: editStateStore({\n id: ref.documentId,\n type: ref.type,\n release: contentReleaseName({ref, perspective}),\n }),\n }\n }\n return {\n key: ref.globalDocumentId,\n store: sdkContentDocStore({\n sdk: requireSdk(`\"${ref.globalDocumentId}\" lives outside this workspace`),\n ref,\n perspective,\n }),\n }\n }),\n ),\n observeGuards: (instanceId, resources) =>\n combineGuardStores(\n resources.map((resource) => {\n if (sameDataset(resource, mounted)) {\n const {query, params} = instanceGuardQuery(instanceId)\n // `undefined` until the first `listenQuery` emission — the loading\n // signal the guard merge and the hook's `ready` gate distinguish\n // from a resolved-empty guard list.\n return observableStore<MutationGuardDoc[], readonly MutationGuardDoc[] | undefined>({\n observable: documentStore.listenQuery(query, params, {}),\n resolve: (docs) => docs,\n initial: undefined,\n })\n }\n return sdkGuardStore({\n sdk: requireSdk(\n `guards for \"${instanceId}\" live in ${resource.projectId}.${resource.dataset}`,\n ),\n instanceId,\n resource,\n })\n }),\n ),\n observeInstances: (query) => {\n if (engineIsMounted) {\n // `initial: undefined` (not a shared empty) — a pending first read and\n // a confirmed empty list must stay distinguishable for `loading`.\n return observableStore<WorkflowInstance[], readonly WorkflowInstance[] | undefined>({\n observable: documentStore.listenQuery(query.query, query.params, {}),\n resolve: (docs) => docs,\n initial: undefined,\n })\n }\n return sdkInstancesStore({\n sdk: requireSdk(\n `the instance list lives in the engine dataset ${engineResource.projectId}.${engineResource.dataset}`,\n ),\n query,\n resource: engineResource,\n })\n },\n }\n}\n\n/**\n * Resolve an `editState` emission to a single observed value: `undefined` while\n * not ready (gates the session feed), otherwise the version / draft / published\n * doc in precedence order (`null` when the doc doesn't exist).\n */\nfunction resolveEditState(editState: EditStateFor): ObservedDoc {\n if (!editState.ready) return undefined\n return (editState.version ?? editState.draft ?? editState.published) as ObservedDoc\n}\n","import {\n createEngine,\n ENGINE_API_VERSION,\n type Engine,\n type ResourceClientResolver,\n type WorkflowClient,\n type WorkflowResource,\n} from '@sanity/workflow-engine'\nimport {datasetResourceId, useKeyed} from '@sanity/workflow-react/observer'\nimport {useMemo} from 'react'\nimport {useClient} from 'sanity'\n\n/**\n * Build the Studio-side engine once: the workspace client rebound to the\n * engine's state dataset, plus {@link studioResourceClients} as the default\n * per-resource routing — so subjects and refs across many content datasets\n * resolve without call sites assembling clients. Pass `resourceClients` to\n * override the routing (compose with {@link studioResourceClients} to keep\n * dataset-GDR routing). Memoized on the config's content, so inline\n * `workflowResource` literals are fine; a custom `resourceClients` function\n * should still be stable. Must render inside Studio source context.\n */\nexport function useWorkflowEngine({\n workflowResource,\n tag,\n resourceClients,\n apiVersion,\n}: {\n workflowResource: WorkflowResource\n tag: string\n resourceClients?: ResourceClientResolver\n apiVersion?: string\n}): Engine {\n const client = useClient({apiVersion: apiVersion ?? ENGINE_API_VERSION})\n const resource = useKeyed([workflowResource.type, workflowResource.id], () => workflowResource)\n return useMemo(() => {\n const engineDataset = datasetResourceId(resource)\n const engineClient = asWorkflowClient(\n client.withConfig({\n projectId: engineDataset.projectId,\n dataset: engineDataset.dataset,\n useCdn: false,\n }),\n )\n return createEngine({\n client: engineClient,\n workflowResource: resource,\n tag,\n resourceClients: resourceClients ?? studioResourceClients(client),\n })\n }, [client, resource, tag, resourceClients])\n}\n\n/**\n * The default Studio {@link ResourceClientResolver}: any fully-addressed\n * `dataset:` GDR resolves to the workspace client rebound to that\n * project/dataset; other schemes (media-library, canvas) return `undefined` so\n * the engine falls back to its own client. A custom resolver can delegate to\n * this for the dataset arm and handle other schemes itself.\n */\nexport function studioResourceClients(client: StudioClient): ResourceClientResolver {\n return (parsed) =>\n parsed.scheme === 'dataset' && parsed.projectId !== undefined && parsed.dataset !== undefined\n ? asWorkflowClient(\n client.withConfig({projectId: parsed.projectId, dataset: parsed.dataset, useCdn: false}),\n )\n : undefined\n}\n\ntype StudioClient = ReturnType<typeof useClient>\n\n/** The Studio client is structurally assignable to the engine's narrower\n * client — a typed identity, so drift breaks loudly at compile time. */\nfunction asWorkflowClient(client: StudioClient): WorkflowClient {\n return client\n}\n","import {createSanityInstance, type SanityInstance} from '@sanity/sdk'\nimport {ENGINE_API_VERSION, type Engine} from '@sanity/workflow-engine'\nimport {\n datasetResourceId,\n sameDataset,\n type DatasetResourceId,\n type WorkflowObserver,\n} from '@sanity/workflow-react/observer'\nimport {useEffect, useMemo, useRef} from 'react'\nimport {useDocumentStore, useSource} from 'sanity'\n\nimport {makeStudioObserver} from './studio-observer.ts'\n\n/** The client is only read for its auth config — no request is ever issued\n * with it — but `getClient` requires an apiVersion to hand one out. */\nconst SESSION_CLIENT_OPTIONS = {apiVersion: ENGINE_API_VERSION}\n\n/**\n * The Studio observer for this engine — the shared wiring under every\n * reactive hook in this package. Workspace-dataset streams ride\n * `documentStore`; anything foreign (routinely the engine's dedicated\n * `workflows` dataset) rides an App SDK instance, bootstrapped from the\n * Studio session when the caller doesn't supply one. Must run inside Studio\n * source context (so `useDocumentStore`/`useSource` resolve).\n */\nexport function useStudioObserver({\n engine,\n sdk: suppliedSdk,\n}: {\n engine: Engine\n sdk?: SanityInstance | undefined\n}): WorkflowObserver {\n const documentStore = useDocumentStore()\n const source = useSource()\n const {projectId, dataset} = source\n const mounted = useMemo(() => ({projectId, dataset}), [projectId, dataset])\n const engineResource = useMemo(() => datasetResourceId(engine.workflowResource), [engine])\n const sdk = useEmbeddedSdk({\n supplied: suppliedSdk,\n // The engine dataset being foreign is the signal an SDK instance is\n // needed; foreign content refs without one still fail loud per ref.\n needed: !sameDataset(engineResource, mounted),\n mounted,\n // The session's token rides the source client's config (absent under\n // cookie auth) — the public read; Studio's token storage is private.\n sessionToken: source.getClient(SESSION_CLIENT_OPTIONS).config().token,\n })\n return useMemo(\n () =>\n makeStudioObserver(documentStore, {\n mounted,\n engineResource,\n ...(sdk !== undefined ? {sdk} : {}),\n }),\n [documentStore, mounted, engineResource, sdk],\n )\n}\n\n/**\n * The supplied SDK instance, or one bootstrapped from the Studio session's\n * token when foreign observation is needed. Lifecycle mirrors the SDK's own\n * `ResourceProvider`: created in render (the observer needs it synchronously),\n * recreated when a previous unmount disposed it, and released via\n * {@link useDeferredDispose} — so StrictMode's unmount/remount probe neither\n * leaks an instance nor hands the remount a dead one. `sessionToken` is\n * captured at bootstrap, deliberately not part of the recreate key: a rotated\n * token surfaces as auth failures until remount, and keying on it would churn\n * the instance on every rotation. Exported for tests only.\n */\nexport function useEmbeddedSdk({\n supplied,\n needed,\n mounted,\n sessionToken,\n}: {\n supplied: SanityInstance | undefined\n needed: boolean\n mounted: DatasetResourceId\n sessionToken: string | undefined\n}): SanityInstance | undefined {\n const wanted = supplied === undefined && needed\n const held = useRef<{key: string; instance: SanityInstance} | undefined>(undefined)\n const key = `${mounted.projectId}.${mounted.dataset}`\n if (wanted && (held.current?.key !== key || held.current.instance.isDisposed())) {\n held.current = {key, instance: bootstrapInstance(mounted, sessionToken)}\n }\n const embedded = wanted ? held.current?.instance : undefined\n useDeferredDispose(embedded)\n return supplied ?? embedded\n}\n\n/** An SDK instance over the workspace's own project, authed with the Studio\n * session's token — the engine dataset is reached per-resource from here. */\nfunction bootstrapInstance(\n mounted: DatasetResourceId,\n sessionToken: string | undefined,\n): SanityInstance {\n if (sessionToken === undefined) {\n throw new Error(\n `@sanity/workflow-studio: the engine's state dataset is not this workspace's dataset, and no Studio session token is readable to bootstrap an App SDK instance (cookie-authenticated studio?). Pass one explicitly via the hook's \\`sdk\\` option, e.g. useWorkflowSession({engine, instanceId, sdk}).`,\n )\n }\n return createSanityInstance({\n projectId: mounted.projectId,\n dataset: mounted.dataset,\n auth: {token: sessionToken},\n })\n}\n\n/**\n * Dispose `instance` after unmount via a zero-delay timer that an immediate\n * remount of the same instance cancels — the SDK `ResourceProvider`'s own\n * idiom for surviving StrictMode's unmount/remount probe.\n */\nfunction useDeferredDispose(instance: SanityInstance | undefined): void {\n const disposal = useRef<\n {instance: SanityInstance; timeoutId: ReturnType<typeof setTimeout>} | undefined\n >(undefined)\n useEffect(() => {\n if (instance === undefined) return undefined\n if (disposal.current?.instance === instance) {\n clearTimeout(disposal.current.timeoutId)\n disposal.current = undefined\n }\n return () => {\n disposal.current = {\n instance,\n timeoutId: setTimeout(() => {\n if (!instance.isDisposed()) instance.dispose()\n }, 0),\n }\n }\n }, [instance])\n}\n","import type {SanityInstance} from '@sanity/sdk'\nimport type {Engine, WorkflowAccessOverride} from '@sanity/workflow-engine'\nimport {\n useWorkflowSession as useWorkflowSessionCore,\n type WorkflowSession,\n} from '@sanity/workflow-react'\n\nimport {useStudioObserver} from './use-studio-observer.ts'\n\n/**\n * Drive a workflow instance reactively from Sanity Studio. Watched docs in the\n * workspace's own dataset observe through `documentStore.pair.editState`\n * (including local uncommitted edits); everything else — the engine's state\n * dataset (routinely a dedicated `workflows` dataset) and foreign content\n * refs — observes through the App SDK store. When the engine dataset differs\n * from the workspace, an SDK instance is bootstrapped automatically from the\n * Studio session (pass `sdk` to supply your own — required for\n * cookie-authenticated studios, where no session token is readable). Returns\n * `{evaluation, ready, guards, tick, fireAction, editField}`; the consumer decides when\n * to advance. Must render inside Studio source context.\n */\nexport function useWorkflowSession({\n engine,\n instanceId,\n access,\n grantsFromPath,\n sdk,\n}: {\n engine: Engine\n instanceId: string\n access?: WorkflowAccessOverride\n grantsFromPath?: string\n sdk?: SanityInstance\n}): WorkflowSession {\n const observer = useStudioObserver({engine, sdk})\n // `sdk` is a store handle for the observer, never an `engine.session(...)`\n // argument — only the session options cross into the engine.\n return useWorkflowSessionCore({engine, instanceId, observer, opts: {access, grantsFromPath}})\n}\n","import type {SanityInstance} from '@sanity/sdk'\nimport type {Engine, GdrUri, InstancesQueryFilter} from '@sanity/workflow-engine'\nimport {\n useDocumentWorkflows as useDocumentWorkflowsCore,\n useWorkflowInstances as useWorkflowInstancesCore,\n type WorkflowInstanceList,\n} from '@sanity/workflow-react'\n\nimport {useStudioObserver} from './use-studio-observer.ts'\n\n/** A live, filterable workflow-instance list observed from Sanity Studio —\n * through `documentStore.listenQuery` when the engine dataset is the\n * workspace's own, else through an App SDK instance (auto-bootstrapped, or\n * supply `sdk`). Must render inside Studio source context. */\nexport function useWorkflowInstances({\n engine,\n filter,\n sdk,\n}: {\n engine: Engine\n filter?: InstancesQueryFilter\n sdk?: SanityInstance\n}): WorkflowInstanceList {\n const observer = useStudioObserver({engine, sdk})\n return useWorkflowInstancesCore({engine, observer, ...(filter !== undefined ? {filter} : {})})\n}\n\n/** Which in-flight instances reference this document (GDR URI) — live,\n * observed from Sanity Studio. Same routing and `sdk` rules as\n * {@link useWorkflowInstances}. */\nexport function useDocumentWorkflows({\n engine,\n document,\n sdk,\n}: {\n engine: Engine\n document: GdrUri\n sdk?: SanityInstance\n}): WorkflowInstanceList {\n const observer = useStudioObserver({engine, sdk})\n return useDocumentWorkflowsCore({engine, observer, document})\n}\n"],"names":["useWorkflowSessionCore","useWorkflowInstancesCore","useDocumentWorkflowsCore"],"mappings":"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"}