@sanity/workflow-studio 0.3.5 → 0.4.1

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 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/studio-observer.ts","../src/use-workflow-instance.tsx"],"sourcesContent":["import type {SanityInstance} from '@sanity/sdk'\nimport {\n contentReleaseName,\n instanceGuardQuery,\n WORKFLOW_INSTANCE_TYPE,\n type MutationGuardDoc,\n} from '@sanity/workflow-engine'\nimport {\n classifyRef,\n combineDocStores,\n combineGuardStores,\n NO_GUARDS,\n sameDataset,\n type DatasetResourceId,\n type DocStore,\n type ObservedDoc,\n type WorkflowObserver,\n} from '@sanity/workflow-react'\nimport {sdkContentDocStore, sdkGuardStore, sdkInstanceDocStore} from '@sanity/workflow-sdk'\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: 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).\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: string,\n type: string,\n release: string | undefined,\n ): DocStore<ObservedDoc> =>\n observableStore<EditStateFor, ObservedDoc>(\n documentStore.pair.editState(id, type, release),\n resolveEditState,\n 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 (\\`useWorkflowInstance(engine, id, {sdk})\\`) to observe foreign resources.`,\n )\n }\n\n return {\n observeInstance: (instanceId) => {\n if (engineIsMounted) return editStateStore(instanceId, WORKFLOW_INSTANCE_TYPE, undefined)\n return sdkInstanceDocStore(\n 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 ref.documentId,\n ref.type,\n contentReleaseName({ref, perspective}),\n ),\n }\n }\n return {\n key: ref.globalDocumentId,\n store: sdkContentDocStore(\n 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 return observableStore<MutationGuardDoc[], readonly MutationGuardDoc[]>(\n documentStore.listenQuery(query, params, {}),\n (docs) => docs,\n NO_GUARDS,\n )\n }\n return sdkGuardStore(\n requireSdk(\n `guards for \"${instanceId}\" live in ${resource.projectId}.${resource.dataset}`,\n ),\n instanceId,\n resource,\n )\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 {createSanityInstance, type SanityInstance} from '@sanity/sdk'\nimport type {Engine, WorkflowAccessOverride} from '@sanity/workflow-engine'\nimport {\n datasetResourceId,\n sameDataset,\n useWorkflowSession,\n type DatasetResourceId,\n type WorkflowInstanceController,\n} from '@sanity/workflow-react'\nimport {useEffect, useMemo, useRef} from 'react'\nimport {useDocumentStore, useSource} from 'sanity'\n\nimport {makeStudioObserver} from './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 `opts.sdk` to supply your own — required for\n * cookie-authenticated studios, where no session token is readable). Returns\n * `{evaluation, ready, guards, tick, fireAction, editState}`; the consumer decides when\n * to advance. Must render inside Studio source context (so\n * `useDocumentStore`/`useSource` resolve).\n */\nexport function useWorkflowInstance(\n engine: Engine,\n instanceId: string,\n opts?: {access?: WorkflowAccessOverride; grantsFromPath?: string; sdk?: SanityInstance},\n): WorkflowInstanceController {\n const documentStore = useDocumentStore()\n const {projectId, dataset} = useSource()\n const mounted = useMemo(() => ({projectId, dataset}), [projectId, dataset])\n const engineResource = useMemo(() => datasetResourceId(engine.workflowResource), [engine])\n const sdk = useEmbeddedSdk(\n opts?.sdk,\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 !sameDataset(engineResource, mounted),\n mounted,\n )\n const observer = useMemo(\n () =>\n makeStudioObserver(documentStore, {\n mounted,\n engineResource,\n ...(sdk !== undefined ? {sdk} : {}),\n }),\n [documentStore, mounted, engineResource, sdk],\n )\n return useWorkflowSession(engine, instanceId, observer, sessionOptions(opts))\n}\n\n/** Only the session options cross into the engine — `sdk` is a store handle\n * for the observer, never an `engine.instance(...)` argument. */\nfunction sessionOptions(\n opts: {access?: WorkflowAccessOverride; grantsFromPath?: string; sdk?: SanityInstance} = {},\n): {access?: WorkflowAccessOverride; grantsFromPath?: string} {\n const {sdk: _, ...session} = opts\n return session\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. Exported for tests only.\n */\nexport function useEmbeddedSdk(\n supplied: SanityInstance | undefined,\n needed: boolean,\n mounted: DatasetResourceId,\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)}\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(mounted: DatasetResourceId): SanityInstance {\n return createSanityInstance({\n projectId: mounted.projectId,\n dataset: mounted.dataset,\n auth: {token: studioSessionToken(mounted.projectId)},\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\n/** The Studio session's token, as persisted by Studio's own auth store.\n * Exported for tests only. */\nexport function studioSessionToken(projectId: string): string {\n const token = persistedToken(projectId)\n if (typeof token !== 'string') {\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: useWorkflowInstance(engine, id, {sdk}).`,\n )\n }\n return token\n}\n\n/** Best-effort read of Studio's persisted `{token}` localStorage entry — any\n * unreadable shape (absent key, malformed JSON, non-object value) resolves to\n * `undefined` so every failure mode funnels into the one actionable error. */\nfunction persistedToken(projectId: string): unknown {\n const raw = window.localStorage.getItem(`__studio_auth_token_${projectId}`)\n if (raw === null) return undefined\n try {\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed !== 'object' || parsed === null) return undefined\n return (parsed as {token?: unknown}).token\n } catch {\n return undefined\n }\n}\n"],"names":["sdk","sameDataset","WORKFLOW_INSTANCE_TYPE","sdkInstanceDocStore","combineDocStores","classifyRef","contentReleaseName","sdkContentDocStore","combineGuardStores","instanceGuardQuery","NO_GUARDS","sdkGuardStore","useDocumentStore","useSource","useMemo","datasetResourceId","useWorkflowSession","useRef","createSanityInstance","useEffect"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/studio-observer.ts","../src/use-workflow-instance.tsx"],"sourcesContent":["import type {SanityInstance} from '@sanity/sdk'\nimport {\n contentReleaseName,\n instanceGuardQuery,\n WORKFLOW_INSTANCE_TYPE,\n type MutationGuardDoc,\n} from '@sanity/workflow-engine'\nimport {\n classifyRef,\n combineDocStores,\n combineGuardStores,\n NO_GUARDS,\n sameDataset,\n type DatasetResourceId,\n type DocStore,\n type ObservedDoc,\n type WorkflowObserver,\n} from '@sanity/workflow-react'\nimport {sdkContentDocStore, sdkGuardStore, sdkInstanceDocStore} from '@sanity/workflow-sdk'\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: 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).\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: string,\n type: string,\n release: string | undefined,\n ): DocStore<ObservedDoc> =>\n observableStore<EditStateFor, ObservedDoc>(\n documentStore.pair.editState(id, type, release),\n resolveEditState,\n 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 (\\`useWorkflowInstance(engine, id, {sdk})\\`) to observe foreign resources.`,\n )\n }\n\n return {\n observeInstance: (instanceId) => {\n if (engineIsMounted) return editStateStore(instanceId, WORKFLOW_INSTANCE_TYPE, undefined)\n return sdkInstanceDocStore(\n 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 ref.documentId,\n ref.type,\n contentReleaseName({ref, perspective}),\n ),\n }\n }\n return {\n key: ref.globalDocumentId,\n store: sdkContentDocStore(\n 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 return observableStore<MutationGuardDoc[], readonly MutationGuardDoc[]>(\n documentStore.listenQuery(query, params, {}),\n (docs) => docs,\n NO_GUARDS,\n )\n }\n return sdkGuardStore(\n requireSdk(\n `guards for \"${instanceId}\" live in ${resource.projectId}.${resource.dataset}`,\n ),\n instanceId,\n resource,\n )\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 {createSanityInstance, type SanityInstance} from '@sanity/sdk'\nimport type {Engine, WorkflowAccessOverride} from '@sanity/workflow-engine'\nimport {\n datasetResourceId,\n sameDataset,\n useWorkflowSession,\n type DatasetResourceId,\n type WorkflowInstanceController,\n} from '@sanity/workflow-react'\nimport {useEffect, useMemo, useRef} from 'react'\nimport {useDocumentStore, useSource} from 'sanity'\n\nimport {makeStudioObserver} from './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 `opts.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 (so\n * `useDocumentStore`/`useSource` resolve).\n */\nexport function useWorkflowInstance(\n engine: Engine,\n instanceId: string,\n opts?: {access?: WorkflowAccessOverride; grantsFromPath?: string; sdk?: SanityInstance},\n): WorkflowInstanceController {\n const documentStore = useDocumentStore()\n const {projectId, dataset} = useSource()\n const mounted = useMemo(() => ({projectId, dataset}), [projectId, dataset])\n const engineResource = useMemo(() => datasetResourceId(engine.workflowResource), [engine])\n const sdk = useEmbeddedSdk(\n opts?.sdk,\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 !sameDataset(engineResource, mounted),\n mounted,\n )\n const observer = useMemo(\n () =>\n makeStudioObserver(documentStore, {\n mounted,\n engineResource,\n ...(sdk !== undefined ? {sdk} : {}),\n }),\n [documentStore, mounted, engineResource, sdk],\n )\n return useWorkflowSession(engine, instanceId, observer, sessionOptions(opts))\n}\n\n/** Only the session options cross into the engine — `sdk` is a store handle\n * for the observer, never an `engine.instance(...)` argument. */\nfunction sessionOptions(\n opts: {access?: WorkflowAccessOverride; grantsFromPath?: string; sdk?: SanityInstance} = {},\n): {access?: WorkflowAccessOverride; grantsFromPath?: string} {\n const {sdk: _, ...session} = opts\n return session\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. Exported for tests only.\n */\nexport function useEmbeddedSdk(\n supplied: SanityInstance | undefined,\n needed: boolean,\n mounted: DatasetResourceId,\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)}\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(mounted: DatasetResourceId): SanityInstance {\n return createSanityInstance({\n projectId: mounted.projectId,\n dataset: mounted.dataset,\n auth: {token: studioSessionToken(mounted.projectId)},\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\n/** The Studio session's token, as persisted by Studio's own auth store.\n * Exported for tests only. */\nexport function studioSessionToken(projectId: string): string {\n const token = persistedToken(projectId)\n if (typeof token !== 'string') {\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: useWorkflowInstance(engine, id, {sdk}).`,\n )\n }\n return token\n}\n\n/** Best-effort read of Studio's persisted `{token}` localStorage entry — any\n * unreadable shape (absent key, malformed JSON, non-object value) resolves to\n * `undefined` so every failure mode funnels into the one actionable error. */\nfunction persistedToken(projectId: string): unknown {\n const raw = window.localStorage.getItem(`__studio_auth_token_${projectId}`)\n if (raw === null) return undefined\n try {\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed !== 'object' || parsed === null) return undefined\n return (parsed as {token?: unknown}).token\n } catch {\n return undefined\n }\n}\n"],"names":["sdk","sameDataset","WORKFLOW_INSTANCE_TYPE","sdkInstanceDocStore","combineDocStores","classifyRef","contentReleaseName","sdkContentDocStore","combineGuardStores","instanceGuardQuery","NO_GUARDS","sdkGuardStore","useDocumentStore","useSource","useMemo","datasetResourceId","useWorkflowSession","useRef","createSanityInstance","useEffect"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -51,7 +51,7 @@ export declare interface StudioObserverOptions {
51
51
  * from the workspace, an SDK instance is bootstrapped automatically from the
52
52
  * Studio session (pass `opts.sdk` to supply your own — required for
53
53
  * cookie-authenticated studios, where no session token is readable). Returns
54
- * `{evaluation, ready, guards, tick, fireAction, editState}`; the consumer decides when
54
+ * `{evaluation, ready, guards, tick, fireAction, editField}`; the consumer decides when
55
55
  * to advance. Must render inside Studio source context (so
56
56
  * `useDocumentStore`/`useSource` resolve).
57
57
  */
package/dist/index.d.ts CHANGED
@@ -51,7 +51,7 @@ export declare interface StudioObserverOptions {
51
51
  * from the workspace, an SDK instance is bootstrapped automatically from the
52
52
  * Studio session (pass `opts.sdk` to supply your own — required for
53
53
  * cookie-authenticated studios, where no session token is readable). Returns
54
- * `{evaluation, ready, guards, tick, fireAction, editState}`; the consumer decides when
54
+ * `{evaluation, ready, guards, tick, fireAction, editField}`; the consumer decides when
55
55
  * to advance. Must render inside Studio source context (so
56
56
  * `useDocumentStore`/`useSource` resolve).
57
57
  */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/studio-observer.ts","../src/use-workflow-instance.tsx"],"sourcesContent":["import type {SanityInstance} from '@sanity/sdk'\nimport {\n contentReleaseName,\n instanceGuardQuery,\n WORKFLOW_INSTANCE_TYPE,\n type MutationGuardDoc,\n} from '@sanity/workflow-engine'\nimport {\n classifyRef,\n combineDocStores,\n combineGuardStores,\n NO_GUARDS,\n sameDataset,\n type DatasetResourceId,\n type DocStore,\n type ObservedDoc,\n type WorkflowObserver,\n} from '@sanity/workflow-react'\nimport {sdkContentDocStore, sdkGuardStore, sdkInstanceDocStore} from '@sanity/workflow-sdk'\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: 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).\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: string,\n type: string,\n release: string | undefined,\n ): DocStore<ObservedDoc> =>\n observableStore<EditStateFor, ObservedDoc>(\n documentStore.pair.editState(id, type, release),\n resolveEditState,\n 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 (\\`useWorkflowInstance(engine, id, {sdk})\\`) to observe foreign resources.`,\n )\n }\n\n return {\n observeInstance: (instanceId) => {\n if (engineIsMounted) return editStateStore(instanceId, WORKFLOW_INSTANCE_TYPE, undefined)\n return sdkInstanceDocStore(\n 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 ref.documentId,\n ref.type,\n contentReleaseName({ref, perspective}),\n ),\n }\n }\n return {\n key: ref.globalDocumentId,\n store: sdkContentDocStore(\n 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 return observableStore<MutationGuardDoc[], readonly MutationGuardDoc[]>(\n documentStore.listenQuery(query, params, {}),\n (docs) => docs,\n NO_GUARDS,\n )\n }\n return sdkGuardStore(\n requireSdk(\n `guards for \"${instanceId}\" live in ${resource.projectId}.${resource.dataset}`,\n ),\n instanceId,\n resource,\n )\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 {createSanityInstance, type SanityInstance} from '@sanity/sdk'\nimport type {Engine, WorkflowAccessOverride} from '@sanity/workflow-engine'\nimport {\n datasetResourceId,\n sameDataset,\n useWorkflowSession,\n type DatasetResourceId,\n type WorkflowInstanceController,\n} from '@sanity/workflow-react'\nimport {useEffect, useMemo, useRef} from 'react'\nimport {useDocumentStore, useSource} from 'sanity'\n\nimport {makeStudioObserver} from './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 `opts.sdk` to supply your own — required for\n * cookie-authenticated studios, where no session token is readable). Returns\n * `{evaluation, ready, guards, tick, fireAction, editState}`; the consumer decides when\n * to advance. Must render inside Studio source context (so\n * `useDocumentStore`/`useSource` resolve).\n */\nexport function useWorkflowInstance(\n engine: Engine,\n instanceId: string,\n opts?: {access?: WorkflowAccessOverride; grantsFromPath?: string; sdk?: SanityInstance},\n): WorkflowInstanceController {\n const documentStore = useDocumentStore()\n const {projectId, dataset} = useSource()\n const mounted = useMemo(() => ({projectId, dataset}), [projectId, dataset])\n const engineResource = useMemo(() => datasetResourceId(engine.workflowResource), [engine])\n const sdk = useEmbeddedSdk(\n opts?.sdk,\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 !sameDataset(engineResource, mounted),\n mounted,\n )\n const observer = useMemo(\n () =>\n makeStudioObserver(documentStore, {\n mounted,\n engineResource,\n ...(sdk !== undefined ? {sdk} : {}),\n }),\n [documentStore, mounted, engineResource, sdk],\n )\n return useWorkflowSession(engine, instanceId, observer, sessionOptions(opts))\n}\n\n/** Only the session options cross into the engine — `sdk` is a store handle\n * for the observer, never an `engine.instance(...)` argument. */\nfunction sessionOptions(\n opts: {access?: WorkflowAccessOverride; grantsFromPath?: string; sdk?: SanityInstance} = {},\n): {access?: WorkflowAccessOverride; grantsFromPath?: string} {\n const {sdk: _, ...session} = opts\n return session\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. Exported for tests only.\n */\nexport function useEmbeddedSdk(\n supplied: SanityInstance | undefined,\n needed: boolean,\n mounted: DatasetResourceId,\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)}\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(mounted: DatasetResourceId): SanityInstance {\n return createSanityInstance({\n projectId: mounted.projectId,\n dataset: mounted.dataset,\n auth: {token: studioSessionToken(mounted.projectId)},\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\n/** The Studio session's token, as persisted by Studio's own auth store.\n * Exported for tests only. */\nexport function studioSessionToken(projectId: string): string {\n const token = persistedToken(projectId)\n if (typeof token !== 'string') {\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: useWorkflowInstance(engine, id, {sdk}).`,\n )\n }\n return token\n}\n\n/** Best-effort read of Studio's persisted `{token}` localStorage entry — any\n * unreadable shape (absent key, malformed JSON, non-object value) resolves to\n * `undefined` so every failure mode funnels into the one actionable error. */\nfunction persistedToken(projectId: string): unknown {\n const raw = window.localStorage.getItem(`__studio_auth_token_${projectId}`)\n if (raw === null) return undefined\n try {\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed !== 'object' || parsed === null) return undefined\n return (parsed as {token?: unknown}).token\n } catch {\n return undefined\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/studio-observer.ts","../src/use-workflow-instance.tsx"],"sourcesContent":["import type {SanityInstance} from '@sanity/sdk'\nimport {\n contentReleaseName,\n instanceGuardQuery,\n WORKFLOW_INSTANCE_TYPE,\n type MutationGuardDoc,\n} from '@sanity/workflow-engine'\nimport {\n classifyRef,\n combineDocStores,\n combineGuardStores,\n NO_GUARDS,\n sameDataset,\n type DatasetResourceId,\n type DocStore,\n type ObservedDoc,\n type WorkflowObserver,\n} from '@sanity/workflow-react'\nimport {sdkContentDocStore, sdkGuardStore, sdkInstanceDocStore} from '@sanity/workflow-sdk'\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: 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).\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: string,\n type: string,\n release: string | undefined,\n ): DocStore<ObservedDoc> =>\n observableStore<EditStateFor, ObservedDoc>(\n documentStore.pair.editState(id, type, release),\n resolveEditState,\n 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 (\\`useWorkflowInstance(engine, id, {sdk})\\`) to observe foreign resources.`,\n )\n }\n\n return {\n observeInstance: (instanceId) => {\n if (engineIsMounted) return editStateStore(instanceId, WORKFLOW_INSTANCE_TYPE, undefined)\n return sdkInstanceDocStore(\n 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 ref.documentId,\n ref.type,\n contentReleaseName({ref, perspective}),\n ),\n }\n }\n return {\n key: ref.globalDocumentId,\n store: sdkContentDocStore(\n 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 return observableStore<MutationGuardDoc[], readonly MutationGuardDoc[]>(\n documentStore.listenQuery(query, params, {}),\n (docs) => docs,\n NO_GUARDS,\n )\n }\n return sdkGuardStore(\n requireSdk(\n `guards for \"${instanceId}\" live in ${resource.projectId}.${resource.dataset}`,\n ),\n instanceId,\n resource,\n )\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 {createSanityInstance, type SanityInstance} from '@sanity/sdk'\nimport type {Engine, WorkflowAccessOverride} from '@sanity/workflow-engine'\nimport {\n datasetResourceId,\n sameDataset,\n useWorkflowSession,\n type DatasetResourceId,\n type WorkflowInstanceController,\n} from '@sanity/workflow-react'\nimport {useEffect, useMemo, useRef} from 'react'\nimport {useDocumentStore, useSource} from 'sanity'\n\nimport {makeStudioObserver} from './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 `opts.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 (so\n * `useDocumentStore`/`useSource` resolve).\n */\nexport function useWorkflowInstance(\n engine: Engine,\n instanceId: string,\n opts?: {access?: WorkflowAccessOverride; grantsFromPath?: string; sdk?: SanityInstance},\n): WorkflowInstanceController {\n const documentStore = useDocumentStore()\n const {projectId, dataset} = useSource()\n const mounted = useMemo(() => ({projectId, dataset}), [projectId, dataset])\n const engineResource = useMemo(() => datasetResourceId(engine.workflowResource), [engine])\n const sdk = useEmbeddedSdk(\n opts?.sdk,\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 !sameDataset(engineResource, mounted),\n mounted,\n )\n const observer = useMemo(\n () =>\n makeStudioObserver(documentStore, {\n mounted,\n engineResource,\n ...(sdk !== undefined ? {sdk} : {}),\n }),\n [documentStore, mounted, engineResource, sdk],\n )\n return useWorkflowSession(engine, instanceId, observer, sessionOptions(opts))\n}\n\n/** Only the session options cross into the engine — `sdk` is a store handle\n * for the observer, never an `engine.instance(...)` argument. */\nfunction sessionOptions(\n opts: {access?: WorkflowAccessOverride; grantsFromPath?: string; sdk?: SanityInstance} = {},\n): {access?: WorkflowAccessOverride; grantsFromPath?: string} {\n const {sdk: _, ...session} = opts\n return session\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. Exported for tests only.\n */\nexport function useEmbeddedSdk(\n supplied: SanityInstance | undefined,\n needed: boolean,\n mounted: DatasetResourceId,\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)}\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(mounted: DatasetResourceId): SanityInstance {\n return createSanityInstance({\n projectId: mounted.projectId,\n dataset: mounted.dataset,\n auth: {token: studioSessionToken(mounted.projectId)},\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\n/** The Studio session's token, as persisted by Studio's own auth store.\n * Exported for tests only. */\nexport function studioSessionToken(projectId: string): string {\n const token = persistedToken(projectId)\n if (typeof token !== 'string') {\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: useWorkflowInstance(engine, id, {sdk}).`,\n )\n }\n return token\n}\n\n/** Best-effort read of Studio's persisted `{token}` localStorage entry — any\n * unreadable shape (absent key, malformed JSON, non-object value) resolves to\n * `undefined` so every failure mode funnels into the one actionable error. */\nfunction persistedToken(projectId: string): unknown {\n const raw = window.localStorage.getItem(`__studio_auth_token_${projectId}`)\n if (raw === null) return undefined\n try {\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed !== 'object' || parsed === null) return undefined\n return (parsed as {token?: unknown}).token\n } catch {\n return undefined\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/workflow-studio",
3
- "version": "0.3.5",
3
+ "version": "0.4.1",
4
4
  "description": "React adapter that drives the @sanity/workflow-engine reactive session from the Sanity Studio document store.",
5
5
  "keywords": [
6
6
  "sanity",
@@ -40,9 +40,9 @@
40
40
  "access": "restricted"
41
41
  },
42
42
  "dependencies": {
43
- "@sanity/workflow-engine": "0.9.0",
44
- "@sanity/workflow-react": "0.5.0",
45
- "@sanity/workflow-sdk": "0.3.5"
43
+ "@sanity/workflow-engine": "0.11.0",
44
+ "@sanity/workflow-react": "0.6.1",
45
+ "@sanity/workflow-sdk": "0.4.1"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@sanity/pkg-utils": "^10.5.2",