@sanity/workflow-studio 0.6.0 → 0.7.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.
package/dist/index.cjs CHANGED
@@ -1,212 +1,267 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var workflowEngine = require("@sanity/workflow-engine"), observer = require("@sanity/workflow-react/observer"), observer$1 = require("@sanity/workflow-sdk/observer"), react = require("react"), sanity = require("sanity"), workflowReact = require("@sanity/workflow-react"), sdk = require("@sanity/sdk");
4
- function observableStore({
5
- observable,
6
- resolve,
7
- initial
8
- }) {
9
- let latest = initial;
10
- return {
11
- subscribe(onChange) {
12
- const subscription = observable.subscribe((value) => {
13
- latest = resolve(value), onChange();
14
- });
15
- return () => subscription.unsubscribe();
16
- },
17
- getSnapshot: () => latest
18
- };
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: !0
5
+ });
6
+
7
+ var workflowEngine = require("@sanity/workflow-engine"), observer = require("@sanity/workflow-react/observer"), observer$1 = require("@sanity/workflow-sdk/observer"), sdk = require("@sanity/sdk"), react = require("react"), sanity = require("sanity"), workflowReact = require("@sanity/workflow-react");
8
+
9
+ const RESUBSCRIBE_DELAY_MS = 5e3;
10
+
11
+ function observableStore({observable: observable, resolve: resolve, initial: initial, name: name}) {
12
+ let latest = initial;
13
+ return {
14
+ subscribe(onChange) {
15
+ let subscription, retry, stopped = !1;
16
+ const connect = () => {
17
+ subscription = observable.subscribe({
18
+ next: value => {
19
+ latest = resolve(value), onChange();
20
+ },
21
+ error: err => {
22
+ console.error(`[workflow-studio] ${name} stream errored — resubscribing in ${RESUBSCRIBE_DELAY_MS / 1e3}s:`, err),
23
+ stopped || (retry = setTimeout(connect, RESUBSCRIBE_DELAY_MS));
24
+ }
25
+ });
26
+ };
27
+ return connect(), () => {
28
+ stopped = !0, retry !== void 0 && clearTimeout(retry), subscription?.unsubscribe();
29
+ };
30
+ },
31
+ getSnapshot: () => latest
32
+ };
19
33
  }
34
+
20
35
  function makeStudioObserver(documentStore, options) {
21
- const { mounted, engineResource, sdk: sdk2 } = options, engineIsMounted = observer.sameDataset(engineResource, mounted), editStateStore = ({
22
- id,
23
- type,
24
- release
25
- }) => observableStore({
26
- observable: documentStore.pair.editState(id, type, release),
27
- resolve: resolveEditState,
28
- initial: void 0
29
- }), requireSdk = (what) => {
30
- if (sdk2 !== void 0) return sdk2;
31
- throw new Error(
32
- `@sanity/workflow-studio: ${what} \u2014 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.`
33
- );
34
- };
35
- return {
36
- observeInstance: (instanceId) => engineIsMounted ? editStateStore({ id: instanceId, type: workflowEngine.WORKFLOW_INSTANCE_TYPE, release: void 0 }) : observer$1.sdkInstanceDocStore({
37
- sdk: requireSdk(
38
- `instance "${instanceId}" lives in the engine dataset ${engineResource.projectId}.${engineResource.dataset}`
39
- ),
40
- instanceId,
41
- engineResource
42
- }),
43
- observeDocs: (documents, perspective) => observer.combineDocStores(
44
- documents.map((ref) => observer.classifyRef(ref, mounted) === "mounted-dataset" ? {
45
- key: ref.globalDocumentId,
46
- store: editStateStore({
47
- id: ref.documentId,
48
- type: ref.type,
49
- release: workflowEngine.contentReleaseName({ ref, perspective })
50
- })
51
- } : {
52
- key: ref.globalDocumentId,
53
- store: observer$1.sdkContentDocStore({
54
- sdk: requireSdk(`"${ref.globalDocumentId}" lives outside this workspace`),
55
- ref,
56
- perspective
57
- })
58
- })
59
- ),
60
- observeGuards: (instanceId, resources) => observer.combineGuardStores(
61
- resources.map((resource) => {
62
- if (observer.sameDataset(resource, mounted)) {
63
- const { query, params } = workflowEngine.instanceGuardQuery(instanceId);
64
- return observableStore({
65
- observable: documentStore.listenQuery(query, params, {}),
66
- resolve: (docs) => docs,
67
- initial: void 0
68
- });
69
- }
70
- return observer$1.sdkGuardStore({
71
- sdk: requireSdk(
72
- `guards for "${instanceId}" live in ${resource.projectId}.${resource.dataset}`
73
- ),
74
- instanceId,
75
- resource
76
- });
77
- })
78
- ),
79
- observeInstances: (query) => engineIsMounted ? observableStore({
80
- observable: documentStore.listenQuery(query.query, query.params, {}),
81
- resolve: (docs) => docs,
82
- initial: void 0
83
- }) : observer$1.sdkInstancesStore({
84
- sdk: requireSdk(
85
- `the instance list lives in the engine dataset ${engineResource.projectId}.${engineResource.dataset}`
86
- ),
87
- query,
88
- resource: engineResource
89
- })
90
- };
36
+ const {mounted: mounted, engineResource: engineResource, sdk: sdk2, client: client} = options, engineIsMounted = observer.sameDataset(engineResource, mounted), editStateStore = ({id: id, type: type, release: release, draftFallback: draftFallback}) => observableStore({
37
+ observable: documentStore.pair.editState(id, type, release),
38
+ resolve: editState => resolveEditState(editState, draftFallback),
39
+ initial: void 0,
40
+ name: `the edit state of "${id}"`
41
+ }), requireSdk = what => {
42
+ if (sdk2 !== void 0) return sdk2;
43
+ throw new Error(`@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.`);
44
+ };
45
+ return {
46
+ observeInstance: instanceId => engineIsMounted ? editStateStore({
47
+ id: instanceId,
48
+ type: workflowEngine.WORKFLOW_INSTANCE_TYPE,
49
+ release: void 0,
50
+ draftFallback: !0
51
+ }) : observer$1.sdkInstanceDocStore({
52
+ sdk: requireSdk(`instance "${instanceId}" lives in the engine dataset ${engineResource.projectId}.${engineResource.dataset}`),
53
+ instanceId: instanceId,
54
+ engineResource: engineResource
55
+ }),
56
+ observeDocs: (documents, perspective) => observer.combineDocStores(documents.map(ref => observer.classifyRef(ref, mounted) === "mounted-dataset" ? {
57
+ key: ref.globalDocumentId,
58
+ store: editStateStore({
59
+ id: ref.documentId,
60
+ type: ref.type,
61
+ release: workflowEngine.contentReleaseName({
62
+ ref: ref,
63
+ perspective: perspective
64
+ }),
65
+ draftFallback: workflowEngine.contentDraftFallback({
66
+ ref: ref,
67
+ perspective: perspective
68
+ })
69
+ })
70
+ } : {
71
+ key: ref.globalDocumentId,
72
+ store: observer$1.sdkContentDocStore({
73
+ sdk: requireSdk(`"${ref.globalDocumentId}" lives outside this workspace`),
74
+ ref: ref,
75
+ perspective: perspective
76
+ })
77
+ })),
78
+ observeGuards: (instanceId, resources) => observer.combineGuardStores(resources.map(resource => {
79
+ if (observer.sameDataset(resource, mounted)) {
80
+ const {query: query, params: params} = workflowEngine.instanceGuardQuery(instanceId);
81
+ return observableStore({
82
+ observable: documentStore.listenQuery(query, params, {}),
83
+ resolve: docs => docs,
84
+ initial: void 0,
85
+ name: `the guard list for "${instanceId}"`
86
+ });
87
+ }
88
+ return observer$1.sdkGuardStore({
89
+ sdk: requireSdk(`guards for "${instanceId}" live in ${resource.projectId}.${resource.dataset}`),
90
+ instanceId: instanceId,
91
+ resource: resource
92
+ });
93
+ })),
94
+ observeInstances: query => engineIsMounted ? observableStore({
95
+ observable: documentStore.listenQuery(query.query, query.params, {}),
96
+ resolve: docs => docs,
97
+ initial: void 0,
98
+ name: "the instance list"
99
+ }) : observer$1.sdkInstancesStore({
100
+ sdk: requireSdk(`the instance list lives in the engine dataset ${engineResource.projectId}.${engineResource.dataset}`),
101
+ query: query,
102
+ resource: engineResource
103
+ }),
104
+ ensureDocumentExists: args => observer.ensureDocumentExists(client, args)
105
+ };
91
106
  }
92
- function resolveEditState(editState) {
93
- if (editState.ready)
94
- return editState.version ?? editState.draft ?? editState.published;
107
+
108
+ function resolveEditState(editState, draftFallback) {
109
+ if (!editState.ready) return;
110
+ const draft = draftFallback ? editState.draft : null;
111
+ return editState.version ?? draft ?? editState.published;
95
112
  }
96
- function useWorkflowEngine({
97
- workflowResource,
98
- tag,
99
- resourceClients,
100
- apiVersion
101
- }) {
102
- const client = sanity.useClient({ apiVersion: apiVersion ?? workflowEngine.ENGINE_API_VERSION }), resource = observer.useKeyed([workflowResource.type, workflowResource.id], () => workflowResource);
103
- return react.useMemo(() => {
104
- const engineDataset = observer.datasetResourceId(resource), engineClient = client.withConfig({
105
- projectId: engineDataset.projectId,
106
- dataset: engineDataset.dataset,
107
- useCdn: !1
108
- });
109
- return workflowEngine.createEngine({
110
- client: engineClient,
111
- workflowResource: resource,
112
- tag,
113
- resourceClients: resourceClients ?? studioResourceClients(client)
113
+
114
+ const SESSION_CLIENT_OPTIONS = {
115
+ apiVersion: workflowEngine.ENGINE_API_VERSION
116
+ };
117
+
118
+ function useStudioObserver({engine: engine, sdk: suppliedSdk}) {
119
+ const documentStore = sanity.useDocumentStore(), source = sanity.useSource(), {projectId: projectId, dataset: dataset} = source, mounted = react.useMemo(() => ({
120
+ projectId: projectId,
121
+ dataset: dataset
122
+ }), [ projectId, dataset ]), engineResource = react.useMemo(() => observer.datasetResourceId(engine.workflowResource), [ engine ]), sdk2 = useEmbeddedSdk({
123
+ supplied: suppliedSdk,
124
+ needed: !observer.sameDataset(engineResource, mounted),
125
+ mounted: mounted,
126
+ sessionToken: source.getClient(SESSION_CLIENT_OPTIONS).config().token
114
127
  });
115
- }, [client, resource, tag, resourceClients]);
116
- }
117
- function studioResourceClients(client) {
118
- return (parsed) => parsed.scheme === "dataset" && parsed.projectId !== void 0 && parsed.dataset !== void 0 ? client.withConfig({ projectId: parsed.projectId, dataset: parsed.dataset, useCdn: !1 }) : void 0;
119
- }
120
- const SESSION_CLIENT_OPTIONS = { apiVersion: workflowEngine.ENGINE_API_VERSION };
121
- function useStudioObserver({
122
- engine,
123
- sdk: suppliedSdk
124
- }) {
125
- const documentStore = sanity.useDocumentStore(), source = sanity.useSource(), { projectId, dataset } = source, mounted = react.useMemo(() => ({ projectId, dataset }), [projectId, dataset]), engineResource = react.useMemo(() => observer.datasetResourceId(engine.workflowResource), [engine]), sdk2 = useEmbeddedSdk({
126
- supplied: suppliedSdk,
127
- // The engine dataset being foreign is the signal an SDK instance is
128
- // needed; foreign content refs without one still fail loud per ref.
129
- needed: !observer.sameDataset(engineResource, mounted),
130
- mounted,
131
- // The session's token rides the source client's config (absent under
132
- // cookie auth) — the public read; Studio's token storage is private.
133
- sessionToken: source.getClient(SESSION_CLIENT_OPTIONS).config().token
134
- });
135
- return react.useMemo(
136
- () => makeStudioObserver(documentStore, {
137
- mounted,
138
- engineResource,
139
- ...sdk2 !== void 0 ? { sdk: sdk2 } : {}
140
- }),
141
- [documentStore, mounted, engineResource, sdk2]
142
- );
128
+ return react.useMemo(() => makeStudioObserver(documentStore, {
129
+ mounted: mounted,
130
+ client: source.getClient(SESSION_CLIENT_OPTIONS),
131
+ engineResource: engineResource,
132
+ ...sdk2 !== void 0 ? {
133
+ sdk: sdk2
134
+ } : {}
135
+ }), [ documentStore, source, mounted, engineResource, sdk2 ]);
143
136
  }
144
- function useEmbeddedSdk({
145
- supplied,
146
- needed,
147
- mounted,
148
- sessionToken
149
- }) {
150
- const wanted = supplied === void 0 && needed, held = react.useRef(void 0), key = `${mounted.projectId}.${mounted.dataset}`;
151
- wanted && (held.current?.key !== key || held.current.instance.isDisposed()) && (held.current = { key, instance: bootstrapInstance(mounted, sessionToken) });
152
- const embedded = wanted ? held.current?.instance : void 0;
153
- return useDeferredDispose(embedded), supplied ?? embedded;
137
+
138
+ function useEmbeddedSdk({supplied: supplied, needed: needed, mounted: mounted, sessionToken: sessionToken}) {
139
+ const wanted = supplied === void 0 && needed, held = react.useRef(void 0), key = `${mounted.projectId}.${mounted.dataset}`;
140
+ wanted && (held.current?.key !== key || held.current.instance.isDisposed()) && (held.current = {
141
+ key: key,
142
+ instance: bootstrapInstance(mounted, sessionToken)
143
+ });
144
+ const embedded = wanted ? held.current?.instance : void 0;
145
+ return useDeferredDispose(embedded), supplied ?? embedded;
154
146
  }
147
+
155
148
  function bootstrapInstance(mounted, sessionToken) {
156
- if (sessionToken === void 0)
157
- throw new Error(
158
- "@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})."
159
- );
160
- return sdk.createSanityInstance({
161
- projectId: mounted.projectId,
162
- dataset: mounted.dataset,
163
- auth: { token: sessionToken }
164
- });
149
+ if (sessionToken === void 0) throw new Error("@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}).");
150
+ return sdk.createSanityInstance({
151
+ projectId: mounted.projectId,
152
+ dataset: mounted.dataset,
153
+ auth: {
154
+ token: sessionToken
155
+ }
156
+ });
165
157
  }
158
+
166
159
  function useDeferredDispose(instance) {
167
- const disposal = react.useRef(void 0);
168
- react.useEffect(() => {
169
- if (instance !== void 0)
170
- return disposal.current?.instance === instance && (clearTimeout(disposal.current.timeoutId), disposal.current = void 0), () => {
171
- disposal.current = {
172
- instance,
173
- timeoutId: setTimeout(() => {
174
- instance.isDisposed() || instance.dispose();
175
- }, 0)
160
+ const disposal = react.useRef(void 0);
161
+ react.useEffect(() => {
162
+ if (instance !== void 0) return disposal.current?.instance === instance && (clearTimeout(disposal.current.timeoutId),
163
+ disposal.current = void 0), () => {
164
+ disposal.current = {
165
+ instance: instance,
166
+ timeoutId: setTimeout(() => {
167
+ instance.isDisposed() || instance.dispose();
168
+ }, 0)
169
+ };
176
170
  };
177
- };
178
- }, [instance]);
171
+ }, [ instance ]);
179
172
  }
180
- function useWorkflowSession({
181
- engine,
182
- instanceId,
183
- access,
184
- grantsFromPath,
185
- sdk: sdk2
186
- }) {
187
- const observer2 = useStudioObserver({ engine, sdk: sdk2 });
188
- return workflowReact.useWorkflowSession({ engine, instanceId, observer: observer2, opts: { access, grantsFromPath } });
173
+
174
+ function useWorkflowEngine({workflowResource: workflowResource, tag: tag, resourceClients: resourceClients, effectHandlers: effectHandlers, missingHandler: missingHandler}) {
175
+ const client = sanity.useClient({
176
+ apiVersion: workflowEngine.ENGINE_API_VERSION
177
+ }), resource = observer.useKeyed([ workflowResource.type, workflowResource.id ], () => workflowResource), telemetry = workflowReact.useWorkflowTelemetry();
178
+ return react.useMemo(() => {
179
+ const engineDataset = observer.datasetResourceId(resource), engineClient = client.withConfig({
180
+ projectId: engineDataset.projectId,
181
+ dataset: engineDataset.dataset,
182
+ useCdn: !1,
183
+ requestTagPrefix: "sanity.workflows.studio"
184
+ });
185
+ return workflowEngine.createEngine({
186
+ client: engineClient,
187
+ workflowResource: resource,
188
+ tag: tag,
189
+ resourceClients: resourceClients ?? studioResourceClients(client),
190
+ executionContext: {
191
+ kind: workflowEngine.EXECUTION_KINDS.studio
192
+ },
193
+ ...effectHandlers !== void 0 ? {
194
+ effectHandlers: effectHandlers
195
+ } : {},
196
+ ...missingHandler !== void 0 ? {
197
+ missingHandler: missingHandler
198
+ } : {},
199
+ telemetry: telemetry
200
+ });
201
+ }, [ client, resource, tag, resourceClients, effectHandlers, missingHandler, telemetry ]);
189
202
  }
190
- function useWorkflowInstances({
191
- engine,
192
- filter,
193
- sdk: sdk2
194
- }) {
195
- const observer2 = useStudioObserver({ engine, sdk: sdk2 });
196
- return workflowReact.useWorkflowInstances({ engine, observer: observer2, ...filter !== void 0 ? { filter } : {} });
203
+
204
+ function studioResourceClients(client) {
205
+ return parsed => parsed.scheme === "dataset" && parsed.projectId !== void 0 && parsed.dataset !== void 0 ? client.withConfig({
206
+ projectId: parsed.projectId,
207
+ dataset: parsed.dataset,
208
+ useCdn: !1,
209
+ requestTagPrefix: "sanity.workflows.studio"
210
+ }) : void 0;
211
+ }
212
+
213
+ function useWorkflowSession({engine: engine, instanceId: instanceId, grantsFromPath: grantsFromPath, sdk: sdk2}) {
214
+ const observer2 = useStudioObserver({
215
+ engine: engine,
216
+ sdk: sdk2
217
+ });
218
+ return workflowReact.useWorkflowSession({
219
+ engine: engine,
220
+ instanceId: instanceId,
221
+ observer: observer2,
222
+ host: "studio",
223
+ opts: {
224
+ grantsFromPath: grantsFromPath
225
+ }
226
+ });
197
227
  }
198
- function useDocumentWorkflows({
199
- engine,
200
- document,
201
- sdk: sdk2
202
- }) {
203
- const observer2 = useStudioObserver({ engine, sdk: sdk2 });
204
- return workflowReact.useDocumentWorkflows({ engine, observer: observer2, document });
228
+
229
+ function useWorkflowInstances({engine: engine, filter: filter, sdk: sdk2}) {
230
+ const observer2 = useStudioObserver({
231
+ engine: engine,
232
+ sdk: sdk2
233
+ });
234
+ return workflowReact.useWorkflowInstances({
235
+ engine: engine,
236
+ observer: observer2,
237
+ ...filter !== void 0 ? {
238
+ filter: filter
239
+ } : {}
240
+ });
241
+ }
242
+
243
+ function useDocumentWorkflows({engine: engine, document: document, sdk: sdk2}) {
244
+ const observer2 = useStudioObserver({
245
+ engine: engine,
246
+ sdk: sdk2
247
+ });
248
+ return workflowReact.useDocumentWorkflows({
249
+ engine: engine,
250
+ observer: observer2,
251
+ document: document
252
+ });
205
253
  }
254
+
206
255
  exports.makeStudioObserver = makeStudioObserver;
256
+
207
257
  exports.studioResourceClients = studioResourceClients;
258
+
208
259
  exports.useDocumentWorkflows = useDocumentWorkflows;
260
+
261
+ exports.useStudioObserver = useStudioObserver;
262
+
209
263
  exports.useWorkflowEngine = useWorkflowEngine;
264
+
210
265
  exports.useWorkflowInstances = useWorkflowInstances;
266
+
211
267
  exports.useWorkflowSession = useWorkflowSession;
212
- //# sourceMappingURL=index.cjs.map
package/dist/index.d.cts CHANGED
@@ -1,13 +1,15 @@
1
1
  import { DatasetResourceId } from "@sanity/workflow-react/observer";
2
2
  import type { DocumentStore } from "sanity";
3
+ import { EffectHandler } from "@sanity/workflow-engine";
3
4
  import { Engine } from "@sanity/workflow-engine";
4
5
  import type { GdrUri } from "@sanity/workflow-engine";
5
6
  import type { InstancesQueryFilter } from "@sanity/workflow-engine";
7
+ import { MissingHandlerPolicy } from "@sanity/workflow-engine";
6
8
  import { MutationGuardDoc } from "@sanity/workflow-react";
7
9
  import { ResourceClientResolver } from "@sanity/workflow-engine";
8
- import type { SanityInstance } from "@sanity/sdk";
10
+ import type { SanityClient } from "sanity";
11
+ import { SanityInstance } from "@sanity/sdk";
9
12
  import { useClient } from "sanity";
10
- import type { WorkflowAccessOverride } from "@sanity/workflow-engine";
11
13
  import { WorkflowInstanceList } from "@sanity/workflow-react";
12
14
  import { WorkflowObserver } from "@sanity/workflow-react/observer";
13
15
  import { WorkflowResource } from "@sanity/workflow-engine";
@@ -40,6 +42,9 @@ export declare interface StudioObserverOptions {
40
42
  /** The workspace's project + dataset — the only resource Studio's
41
43
  * `documentStore` can address. */
42
44
  mounted: DatasetResourceId;
45
+ /** A workspace-bound client — carries `ensureDocumentExists` writes, which
46
+ * address the mounted dataset (where the workspace's subject docs live). */
47
+ client: SanityClient;
43
48
  /** The engine's state dataset (`datasetResourceId(engine.workflowResource)`)
44
49
  * — where the instance doc and its verdict-relevant guards live. Routinely
45
50
  * a dedicated `workflows` dataset distinct from the workspace. */
@@ -54,9 +59,11 @@ export declare interface StudioObserverOptions {
54
59
  /**
55
60
  * The default Studio {@link ResourceClientResolver}: any fully-addressed
56
61
  * `dataset:` GDR resolves to the workspace client rebound to that
57
- * project/dataset; other schemes (media-library, canvas) return `undefined` so
58
- * the engine falls back to its own client. A custom resolver can delegate to
59
- * this for the dataset arm and handle other schemes itself.
62
+ * project/dataset; other schemes (media-library, canvas) return `undefined`,
63
+ * letting the engine route them a sibling client derived from the engine
64
+ * client's own credentials for foreign resources, its own client for the
65
+ * workflow resource. A custom resolver can delegate to this for the dataset
66
+ * arm and handle other schemes itself.
60
67
  */
61
68
  export declare function studioResourceClients(
62
69
  client: StudioClient,
@@ -75,26 +82,46 @@ export declare function useDocumentWorkflows({
75
82
  sdk?: SanityInstance;
76
83
  }): WorkflowInstanceList;
77
84
 
85
+ /**
86
+ * The Studio observer for this engine — the shared wiring under every
87
+ * reactive hook in this package. Workspace-dataset streams ride
88
+ * `documentStore`; anything foreign (routinely the engine's dedicated
89
+ * `workflows` dataset) rides an App SDK instance, bootstrapped from the
90
+ * Studio session when the caller doesn't supply one. Must run inside Studio
91
+ * source context (so `useDocumentStore`/`useSource` resolve).
92
+ */
93
+ export declare function useStudioObserver({
94
+ engine,
95
+ sdk: suppliedSdk,
96
+ }: {
97
+ engine: Engine;
98
+ sdk?: SanityInstance | undefined;
99
+ }): WorkflowObserver;
100
+
78
101
  /**
79
102
  * Build the Studio-side engine once: the workspace client rebound to the
80
103
  * engine's state dataset, plus {@link studioResourceClients} as the default
81
104
  * per-resource routing — so subjects and refs across many content datasets
82
105
  * resolve without call sites assembling clients. Pass `resourceClients` to
83
106
  * override the routing (compose with {@link studioResourceClients} to keep
84
- * dataset-GDR routing). Memoized on the config's content, so inline
85
- * `workflowResource` literals are fine; a custom `resourceClients` function
86
- * should still be stable. Must render inside Studio source context.
107
+ * dataset-GDR routing). `effectHandlers`/`missingHandler` feed
108
+ * {@link Engine.drainEffects} for engines that drain effects in the Studio.
109
+ * Memoized on the config's content, so inline `workflowResource` literals are
110
+ * fine; custom `resourceClients` and `effectHandlers` values should still be
111
+ * stable. Must render inside Studio source context.
87
112
  */
88
113
  export declare function useWorkflowEngine({
89
114
  workflowResource,
90
115
  tag,
91
116
  resourceClients,
92
- apiVersion,
117
+ effectHandlers,
118
+ missingHandler,
93
119
  }: {
94
120
  workflowResource: WorkflowResource;
95
121
  tag: string;
96
122
  resourceClients?: ResourceClientResolver;
97
- apiVersion?: string;
123
+ effectHandlers?: Record<string, EffectHandler>;
124
+ missingHandler?: MissingHandlerPolicy;
98
125
  }): Engine;
99
126
 
100
127
  /** A live, filterable workflow-instance list observed from Sanity Studio —
@@ -120,19 +147,18 @@ export declare function useWorkflowInstances({
120
147
  * from the workspace, an SDK instance is bootstrapped automatically from the
121
148
  * Studio session (pass `sdk` to supply your own — required for
122
149
  * cookie-authenticated studios, where no session token is readable). Returns
123
- * `{evaluation, ready, guards, tick, fireAction, editField}`; the consumer decides when
124
- * to advance. Must render inside Studio source context.
150
+ * the full {@link WorkflowSession} (evaluation, ready, guards, and the
151
+ * tick/fireAction/editField/preview verbs); the consumer decides when to
152
+ * advance. Must render inside Studio source context.
125
153
  */
126
154
  export declare function useWorkflowSession({
127
155
  engine,
128
156
  instanceId,
129
- access,
130
157
  grantsFromPath,
131
158
  sdk,
132
159
  }: {
133
160
  engine: Engine;
134
161
  instanceId: string;
135
- access?: WorkflowAccessOverride;
136
162
  grantsFromPath?: string;
137
163
  sdk?: SanityInstance;
138
164
  }): WorkflowSession;