@sanity/workflow-studio 0.5.0 → 0.6.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.
- package/README.md +58 -12
- package/dist/index.cjs +95 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +82 -12
- package/dist/index.d.ts +82 -12
- package/dist/index.js +91 -37
- package/dist/index.js.map +1 -1
- package/package.json +4 -6
package/README.md
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
# @sanity/workflow-studio
|
|
2
2
|
|
|
3
|
-
Reactive workflow adapter for **Sanity Studio**.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Reactive workflow adapter for **Sanity Studio**. Everything must render inside
|
|
4
|
+
Studio source context (`useDocumentStore` / `useSource` / `useClient`).
|
|
5
|
+
|
|
6
|
+
- `useWorkflowEngine({workflowResource, tag, resourceClients?, apiVersion?})` —
|
|
7
|
+
build the Studio-side engine once: the workspace client rebound to the
|
|
8
|
+
engine's state dataset (pinned to the engine's API version unless
|
|
9
|
+
`apiVersion` overrides), with `studioResourceClients` (also exported) as the
|
|
10
|
+
default per-resource routing that reaches any `dataset:` GDR by rebinding
|
|
11
|
+
the same client. A custom `resourceClients` replaces the default — delegate
|
|
12
|
+
to `studioResourceClients` for the dataset arm and handle other schemes
|
|
13
|
+
(media-library, canvas) yourself.
|
|
14
|
+
- `useWorkflowSession` — drives an engine session for one instance and
|
|
15
|
+
returns `{evaluation, ready, guards, tick, fireAction, editField}`.
|
|
16
|
+
- `useWorkflowInstances` / `useDocumentWorkflows` — live instance lists
|
|
17
|
+
(filterable collection / per-document discovery), each returning
|
|
18
|
+
`{instances, loading}`. The list observes `documentStore.listenQuery` when
|
|
19
|
+
the engine dataset is the workspace's own, else the App SDK store — same
|
|
20
|
+
routing (and same `sdk` rules) as the instance doc below. On multi-hook
|
|
21
|
+
surfaces (a board with per-row `useWorkflowSession`), pass one shared
|
|
22
|
+
`sdk` instance to the hooks — each hook otherwise bootstraps its own
|
|
23
|
+
embedded SDK instance when the engine dataset is foreign.
|
|
7
24
|
|
|
8
25
|
## How observation routes (per watched ref)
|
|
9
26
|
|
|
@@ -12,10 +29,10 @@ project + dataset and observed by the store that can actually address it:
|
|
|
12
29
|
|
|
13
30
|
| Ref | Observed via |
|
|
14
31
|
| ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
15
|
-
| **Mounted workspace dataset** | `documentStore.pair.editState` — Studio's optimistic pair store, **including local uncommitted edits** (the one stream only Studio has).
|
|
16
|
-
| **Engine state dataset** (instance doc) | The workspace's `documentStore` when the engine dataset IS the workspace; otherwise the **App SDK store** (`sdkInstanceDocStore` from `@sanity/workflow-sdk`)
|
|
32
|
+
| **Mounted workspace dataset** | `documentStore.pair.editState` — Studio's optimistic pair store, **including local uncommitted edits** (the one stream only Studio has). Non-public Studio surface — see **Private Studio seam** below |
|
|
33
|
+
| **Engine state dataset** (instance doc) | The workspace's `documentStore` when the engine dataset IS the workspace; otherwise the **App SDK store** (`sdkInstanceDocStore` from `@sanity/workflow-sdk/observer`) |
|
|
17
34
|
| **Guards** (`observeGuards`) | Fanned per-resource across the datasets the instance's GDRs name: mounted-dataset guards via `documentStore.listenQuery`, any foreign dataset (engine's or a subject's) via `sdkGuardStore`, merged by `combineGuardStores` |
|
|
18
|
-
| **Any other dataset / project** | The **App SDK document store** (`sdkContentDocStore` from `@sanity/workflow-sdk`) — live, GDR-routed per-resource — through the bootstrapped or supplied SDK instance (see below)
|
|
35
|
+
| **Any other dataset / project** | The **App SDK document store** (`sdkContentDocStore` from `@sanity/workflow-sdk/observer`) — live, GDR-routed per-resource — through the bootstrapped or supplied SDK instance (see below) |
|
|
19
36
|
| **Non-dataset schemes** (`canvas:`, `media-library:`) | Routed like foreign resources; the SDK store rejects them loudly (it addresses dataset resources only) |
|
|
20
37
|
|
|
21
38
|
There is **no silent fallback**: a ref the configured stores can't address
|
|
@@ -25,10 +42,11 @@ throws, instead of being misread from the workspace dataset under the same
|
|
|
25
42
|
- **The engine's `workflowResource` is routinely a dedicated dataset** (e.g.
|
|
26
43
|
`workflows`), foreign to every content workspace. When it differs from the
|
|
27
44
|
workspace and no `sdk` is supplied, the hook **bootstraps an App SDK
|
|
28
|
-
instance automatically** from the Studio session's token
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
45
|
+
instance automatically** from the Studio session's token, read off the
|
|
46
|
+
source client's config (`source.getClient(...).config().token` — public
|
|
47
|
+
Studio API); that instance also observes foreign content refs. Under cookie
|
|
48
|
+
auth the client carries no token — the hook throws an actionable error;
|
|
49
|
+
supply your own instance: `useWorkflowSession({engine, instanceId, sdk})`.
|
|
32
50
|
- When the engine dataset IS the workspace and a watch-set ref points at a
|
|
33
51
|
foreign resource, there is no bootstrap signal — pass `sdk` or the
|
|
34
52
|
observer throws the config-mismatch error for that ref.
|
|
@@ -46,7 +64,35 @@ throws, instead of being misread from the workspace dataset under the same
|
|
|
46
64
|
Remaining gaps (ancestor-instance guards, full cascade write-set pre-flight,
|
|
47
65
|
live cross-dataset end-to-end verification) are known follow-up work.
|
|
48
66
|
|
|
67
|
+
## Packaging
|
|
68
|
+
|
|
69
|
+
This adapter is a **superset of `@sanity/workflow-sdk`'s store layer**, not
|
|
70
|
+
its peer. Foreign-resource observation is the routine path (the engine's
|
|
71
|
+
state dataset is usually dedicated), and it routes through the SDK stores —
|
|
72
|
+
so `@sanity/workflow-sdk` is a hard dependency, consumed through its headless
|
|
73
|
+
`./observer` entry. What that means for installs:
|
|
74
|
+
|
|
75
|
+
- **`@sanity/sdk` is required** (peer) — it addresses every resource outside
|
|
76
|
+
the mounted workspace.
|
|
77
|
+
- **`@sanity/sdk-react` is NOT required** — nothing here touches the App
|
|
78
|
+
SDK's React binding.
|
|
79
|
+
|
|
80
|
+
## Private Studio seam
|
|
81
|
+
|
|
82
|
+
One stream rests on non-public Studio surface; expect Studio to be able to
|
|
83
|
+
move it in a minor, and this package to track it:
|
|
84
|
+
|
|
85
|
+
- **`documentStore.pair.editState`** (reached via `useDocumentStore`; Studio
|
|
86
|
+
marks both `@hidden` / `@beta`) — the only stream of the optimistic pair,
|
|
87
|
+
local uncommitted edits included. No public Studio API exposes it; until
|
|
88
|
+
one does, this dependency is deliberate and documented rather than hidden.
|
|
89
|
+
|
|
90
|
+
(The context hooks themselves — `useDocumentStore`, `useSource` — are
|
|
91
|
+
non-public Studio surface too, the standard plugin-context caveat.)
|
|
92
|
+
|
|
49
93
|
## Notes
|
|
50
94
|
|
|
51
95
|
- See `@sanity/workflow-react`'s README for the guard-verdict semantics
|
|
52
|
-
(what `mutation-guard-denied` does and doesn't cover)
|
|
96
|
+
(what `mutation-guard-denied` does and doesn't cover) and the `editField`
|
|
97
|
+
commit caveat (discrete commits — never bind to an `onChange` per
|
|
98
|
+
keystroke).
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: !0 });
|
|
3
|
-
var workflowEngine = require("@sanity/workflow-engine"),
|
|
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
4
|
function observableStore({
|
|
5
5
|
observable,
|
|
6
6
|
resolve,
|
|
@@ -18,7 +18,7 @@ function observableStore({
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
function makeStudioObserver(documentStore, options) {
|
|
21
|
-
const { mounted, engineResource, sdk: sdk2 } = options, engineIsMounted =
|
|
21
|
+
const { mounted, engineResource, sdk: sdk2 } = options, engineIsMounted = observer.sameDataset(engineResource, mounted), editStateStore = ({
|
|
22
22
|
id,
|
|
23
23
|
type,
|
|
24
24
|
release
|
|
@@ -29,19 +29,19 @@ function makeStudioObserver(documentStore, options) {
|
|
|
29
29
|
}), requireSdk = (what) => {
|
|
30
30
|
if (sdk2 !== void 0) return sdk2;
|
|
31
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 (\`
|
|
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
33
|
);
|
|
34
34
|
};
|
|
35
35
|
return {
|
|
36
|
-
observeInstance: (instanceId) => engineIsMounted ? editStateStore({ id: instanceId, type: workflowEngine.WORKFLOW_INSTANCE_TYPE, release: void 0 }) :
|
|
36
|
+
observeInstance: (instanceId) => engineIsMounted ? editStateStore({ id: instanceId, type: workflowEngine.WORKFLOW_INSTANCE_TYPE, release: void 0 }) : observer$1.sdkInstanceDocStore({
|
|
37
37
|
sdk: requireSdk(
|
|
38
38
|
`instance "${instanceId}" lives in the engine dataset ${engineResource.projectId}.${engineResource.dataset}`
|
|
39
39
|
),
|
|
40
40
|
instanceId,
|
|
41
41
|
engineResource
|
|
42
42
|
}),
|
|
43
|
-
observeDocs: (documents, perspective) =>
|
|
44
|
-
documents.map((ref) =>
|
|
43
|
+
observeDocs: (documents, perspective) => observer.combineDocStores(
|
|
44
|
+
documents.map((ref) => observer.classifyRef(ref, mounted) === "mounted-dataset" ? {
|
|
45
45
|
key: ref.globalDocumentId,
|
|
46
46
|
store: editStateStore({
|
|
47
47
|
id: ref.documentId,
|
|
@@ -50,24 +50,24 @@ function makeStudioObserver(documentStore, options) {
|
|
|
50
50
|
})
|
|
51
51
|
} : {
|
|
52
52
|
key: ref.globalDocumentId,
|
|
53
|
-
store:
|
|
53
|
+
store: observer$1.sdkContentDocStore({
|
|
54
54
|
sdk: requireSdk(`"${ref.globalDocumentId}" lives outside this workspace`),
|
|
55
55
|
ref,
|
|
56
56
|
perspective
|
|
57
57
|
})
|
|
58
58
|
})
|
|
59
59
|
),
|
|
60
|
-
observeGuards: (instanceId, resources) =>
|
|
60
|
+
observeGuards: (instanceId, resources) => observer.combineGuardStores(
|
|
61
61
|
resources.map((resource) => {
|
|
62
|
-
if (
|
|
62
|
+
if (observer.sameDataset(resource, mounted)) {
|
|
63
63
|
const { query, params } = workflowEngine.instanceGuardQuery(instanceId);
|
|
64
64
|
return observableStore({
|
|
65
65
|
observable: documentStore.listenQuery(query, params, {}),
|
|
66
66
|
resolve: (docs) => docs,
|
|
67
|
-
initial:
|
|
67
|
+
initial: void 0
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
|
-
return
|
|
70
|
+
return observer$1.sdkGuardStore({
|
|
71
71
|
sdk: requireSdk(
|
|
72
72
|
`guards for "${instanceId}" live in ${resource.projectId}.${resource.dataset}`
|
|
73
73
|
),
|
|
@@ -75,27 +75,64 @@ function makeStudioObserver(documentStore, options) {
|
|
|
75
75
|
resource
|
|
76
76
|
});
|
|
77
77
|
})
|
|
78
|
-
)
|
|
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
|
+
})
|
|
79
90
|
};
|
|
80
91
|
}
|
|
81
92
|
function resolveEditState(editState) {
|
|
82
93
|
if (editState.ready)
|
|
83
94
|
return editState.version ?? editState.draft ?? editState.published;
|
|
84
95
|
}
|
|
85
|
-
function
|
|
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)
|
|
114
|
+
});
|
|
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({
|
|
86
122
|
engine,
|
|
87
|
-
instanceId,
|
|
88
|
-
access,
|
|
89
|
-
grantsFromPath,
|
|
90
123
|
sdk: suppliedSdk
|
|
91
124
|
}) {
|
|
92
|
-
const documentStore = sanity.useDocumentStore(), { projectId, dataset } =
|
|
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({
|
|
93
126
|
supplied: suppliedSdk,
|
|
94
127
|
// The engine dataset being foreign is the signal an SDK instance is
|
|
95
128
|
// needed; foreign content refs without one still fail loud per ref.
|
|
96
|
-
needed: !
|
|
97
|
-
mounted
|
|
98
|
-
|
|
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(
|
|
99
136
|
() => makeStudioObserver(documentStore, {
|
|
100
137
|
mounted,
|
|
101
138
|
engineResource,
|
|
@@ -103,23 +140,27 @@ function useWorkflowInstance({
|
|
|
103
140
|
}),
|
|
104
141
|
[documentStore, mounted, engineResource, sdk2]
|
|
105
142
|
);
|
|
106
|
-
return workflowReact.useWorkflowSession({ engine, instanceId, observer, opts: { access, grantsFromPath } });
|
|
107
143
|
}
|
|
108
144
|
function useEmbeddedSdk({
|
|
109
145
|
supplied,
|
|
110
146
|
needed,
|
|
111
|
-
mounted
|
|
147
|
+
mounted,
|
|
148
|
+
sessionToken
|
|
112
149
|
}) {
|
|
113
150
|
const wanted = supplied === void 0 && needed, held = react.useRef(void 0), key = `${mounted.projectId}.${mounted.dataset}`;
|
|
114
|
-
wanted && (held.current?.key !== key || held.current.instance.isDisposed()) && (held.current = { key, instance: bootstrapInstance(mounted) });
|
|
151
|
+
wanted && (held.current?.key !== key || held.current.instance.isDisposed()) && (held.current = { key, instance: bootstrapInstance(mounted, sessionToken) });
|
|
115
152
|
const embedded = wanted ? held.current?.instance : void 0;
|
|
116
153
|
return useDeferredDispose(embedded), supplied ?? embedded;
|
|
117
154
|
}
|
|
118
|
-
function bootstrapInstance(mounted) {
|
|
155
|
+
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
|
+
);
|
|
119
160
|
return sdk.createSanityInstance({
|
|
120
161
|
projectId: mounted.projectId,
|
|
121
162
|
dataset: mounted.dataset,
|
|
122
|
-
auth: { token:
|
|
163
|
+
auth: { token: sessionToken }
|
|
123
164
|
});
|
|
124
165
|
}
|
|
125
166
|
function useDeferredDispose(instance) {
|
|
@@ -136,24 +177,36 @@ function useDeferredDispose(instance) {
|
|
|
136
177
|
};
|
|
137
178
|
}, [instance]);
|
|
138
179
|
}
|
|
139
|
-
function
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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 } });
|
|
189
|
+
}
|
|
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 } : {} });
|
|
146
197
|
}
|
|
147
|
-
function
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
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 });
|
|
156
205
|
}
|
|
157
206
|
exports.makeStudioObserver = makeStudioObserver;
|
|
158
|
-
exports.
|
|
207
|
+
exports.studioResourceClients = studioResourceClients;
|
|
208
|
+
exports.useDocumentWorkflows = useDocumentWorkflows;
|
|
209
|
+
exports.useWorkflowEngine = useWorkflowEngine;
|
|
210
|
+
exports.useWorkflowInstances = useWorkflowInstances;
|
|
211
|
+
exports.useWorkflowSession = useWorkflowSession;
|
|
159
212
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -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,\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).\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 (\\`useWorkflowInstance(engine, id, {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 return observableStore<MutationGuardDoc[], readonly MutationGuardDoc[]>({\n observable: documentStore.listenQuery(query, params, {}),\n resolve: (docs) => docs,\n initial: NO_GUARDS,\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 }\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 `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,\n instanceId,\n access,\n grantsFromPath,\n sdk: suppliedSdk,\n}: {\n engine: Engine\n instanceId: string\n access?: WorkflowAccessOverride\n grantsFromPath?: string\n 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 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 })\n const observer = useMemo(\n () =>\n makeStudioObserver(documentStore, {\n mounted,\n engineResource,\n ...(sdk !== undefined ? {sdk} : {}),\n }),\n [documentStore, mounted, engineResource, sdk],\n )\n // `sdk` is a store handle for the observer, never an `engine.instance(...)`\n // argument — only the session options cross into the engine.\n return useWorkflowSession({engine, instanceId, observer, opts: {access, grantsFromPath}})\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,\n needed,\n mounted,\n}: {\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, instanceId, 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":";;;AA8BA,SAAS,gBAAsB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF,GAIgB;AACd,MAAI,SAAS;AACb,SAAO;AAAA,IACL,UAAU,UAAU;AAClB,YAAM,eAAe,WAAW,UAAU,CAAC,UAAU;AACnD,iBAAS,QAAQ,KAAK,GACtB,SAAA;AAAA,MACF,CAAC;AACD,aAAO,MAAM,aAAa,YAAA;AAAA,IAC5B;AAAA,IACA,aAAa,MAAM;AAAA,EAAA;AAEvB;AA8BO,SAAS,mBACd,eACA,SACkB;AAClB,QAAM,EAAC,SAAS,gBAAgB,KAAAA,KAAA,IAAO,SACjC,kBAAkBC,cAAAA,YAAY,gBAAgB,OAAO,GAErD,iBAAiB,CAAC;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,EAAA,MAMA,gBAA2C;AAAA,IACzC,YAAY,cAAc,KAAK,UAAU,IAAI,MAAM,OAAO;AAAA,IAC1D,SAAS;AAAA,IACT,SAAS;AAAA,EAAA,CACV,GAEG,aAAa,CAAC,SAAiC;AACnD,QAAID,SAAQ,OAAW,QAAOA;AAC9B,UAAM,IAAI;AAAA,MACR,4BAA4B,IAAI,+CAA0C,QAAQ,SAAS,IAAI,QAAQ,OAAO;AAAA,IAAA;AAAA,EAElH;AAEA,SAAO;AAAA,IACL,iBAAiB,CAAC,eACZ,kBACK,eAAe,EAAC,IAAI,YAAY,MAAME,eAAAA,wBAAwB,SAAS,OAAA,CAAU,IACnFC,YAAAA,oBAAoB;AAAA,MACzB,KAAK;AAAA,QACH,aAAa,UAAU,iCAAiC,eAAe,SAAS,IAAI,eAAe,OAAO;AAAA,MAAA;AAAA,MAE5G;AAAA,MACA;AAAA,IAAA,CACD;AAAA,IAEH,aAAa,CAAC,WAAW,gBACvBC,cAAAA;AAAAA,MACE,UAAU,IAAI,CAAC,QACTC,cAAAA,YAAY,KAAK,OAAO,MAAM,oBACzB;AAAA,QACL,KAAK,IAAI;AAAA,QACT,OAAO,eAAe;AAAA,UACpB,IAAI,IAAI;AAAA,UACR,MAAM,IAAI;AAAA,UACV,SAASC,eAAAA,mBAAmB,EAAC,KAAK,aAAY;AAAA,QAAA,CAC/C;AAAA,MAAA,IAGE;AAAA,QACL,KAAK,IAAI;AAAA,QACT,OAAOC,YAAAA,mBAAmB;AAAA,UACxB,KAAK,WAAW,IAAI,IAAI,gBAAgB,gCAAgC;AAAA,UACxE;AAAA,UACA;AAAA,QAAA,CACD;AAAA,MAAA,CAEJ;AAAA,IAAA;AAAA,IAEL,eAAe,CAAC,YAAY,cAC1BC,cAAAA;AAAAA,MACE,UAAU,IAAI,CAAC,aAAa;AAC1B,YAAIP,cAAAA,YAAY,UAAU,OAAO,GAAG;AAClC,gBAAM,EAAC,OAAO,WAAUQ,eAAAA,mBAAmB,UAAU;AACrD,iBAAO,gBAAiE;AAAA,YACtE,YAAY,cAAc,YAAY,OAAO,QAAQ,CAAA,CAAE;AAAA,YACvD,SAAS,CAAC,SAAS;AAAA,YACnB,SAASC,cAAAA;AAAAA,UAAA,CACV;AAAA,QACH;AACA,eAAOC,0BAAc;AAAA,UACnB,KAAK;AAAA,YACH,eAAe,UAAU,aAAa,SAAS,SAAS,IAAI,SAAS,OAAO;AAAA,UAAA;AAAA,UAE9E;AAAA,UACA;AAAA,QAAA,CACD;AAAA,MACH,CAAC;AAAA,IAAA;AAAA,EACH;AAEN;AAOA,SAAS,iBAAiB,WAAsC;AAC9D,MAAK,UAAU;AACf,WAAQ,UAAU,WAAW,UAAU,SAAS,UAAU;AAC5D;ACpJO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,KAAK;AACP,GAM+B;AAC7B,QAAM,gBAAgBC,OAAAA,iBAAA,GAChB,EAAC,WAAW,QAAA,IAAWC,iBAAA,GACvB,UAAUC,MAAAA,QAAQ,OAAO,EAAC,WAAW,QAAA,IAAW,CAAC,WAAW,OAAO,CAAC,GACpE,iBAAiBA,MAAAA,QAAQ,MAAMC,cAAAA,kBAAkB,OAAO,gBAAgB,GAAG,CAAC,MAAM,CAAC,GACnFf,OAAM,eAAe;AAAA,IACzB,UAAU;AAAA;AAAA;AAAA,IAGV,QAAQ,CAACC,cAAAA,YAAY,gBAAgB,OAAO;AAAA,IAC5C;AAAA,EAAA,CACD,GACK,WAAWa,MAAAA;AAAAA,IACf,MACE,mBAAmB,eAAe;AAAA,MAChC;AAAA,MACA;AAAA,MACA,GAAId,SAAQ,SAAY,EAAC,KAAAA,SAAO,CAAA;AAAA,IAAC,CAClC;AAAA,IACH,CAAC,eAAe,SAAS,gBAAgBA,IAAG;AAAA,EAAA;AAI9C,SAAOgB,cAAAA,mBAAmB,EAAC,QAAQ,YAAY,UAAU,MAAM,EAAC,QAAQ,eAAA,GAAgB;AAC1F;AAUO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF,GAI+B;AAC7B,QAAM,SAAS,aAAa,UAAa,QACnC,OAAOC,MAAAA,OAA4D,MAAS,GAC5E,MAAM,GAAG,QAAQ,SAAS,IAAI,QAAQ,OAAO;AAC/C,aAAW,KAAK,SAAS,QAAQ,OAAO,KAAK,QAAQ,SAAS,WAAA,OAChE,KAAK,UAAU,EAAC,KAAK,UAAU,kBAAkB,OAAO;AAE1D,QAAM,WAAW,SAAS,KAAK,SAAS,WAAW;AACnD,SAAA,mBAAmB,QAAQ,GACpB,YAAY;AACrB;AAIA,SAAS,kBAAkB,SAA4C;AACrE,SAAOC,yBAAqB;AAAA,IAC1B,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,IACjB,MAAM,EAAC,OAAO,mBAAmB,QAAQ,SAAS,EAAA;AAAA,EAAC,CACpD;AACH;AAOA,SAAS,mBAAmB,UAA4C;AACtE,QAAM,WAAWD,MAAAA,OAEf,MAAS;AACXE,QAAAA,UAAU,MAAM;AACd,QAAI,aAAa;AACjB,aAAI,SAAS,SAAS,aAAa,aACjC,aAAa,SAAS,QAAQ,SAAS,GACvC,SAAS,UAAU,SAEd,MAAM;AACX,iBAAS,UAAU;AAAA,UACjB;AAAA,UACA,WAAW,WAAW,MAAM;AACrB,qBAAS,WAAA,KAAc,SAAS,QAAA;AAAA,UACvC,GAAG,CAAC;AAAA,QAAA;AAAA,MAER;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AACf;AAIO,SAAS,mBAAmB,WAA2B;AAC5D,QAAM,QAAQ,eAAe,SAAS;AACtC,MAAI,OAAO,SAAU;AACnB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAGJ,SAAO;AACT;AAKA,SAAS,eAAe,WAA4B;AAClD,QAAM,MAAM,OAAO,aAAa,QAAQ,uBAAuB,SAAS,EAAE;AAC1E,MAAI,QAAQ;AACZ,QAAI;AACF,YAAM,SAAkB,KAAK,MAAM,GAAG;AACtC,aAAI,OAAO,UAAW,YAAY,WAAW,OAAM,SAC3C,OAA6B;AAAA,IACvC,QAAQ;AACN;AAAA,IACF;AACF;;;"}
|
|
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.d.cts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import { DatasetResourceId } from "@sanity/workflow-react";
|
|
1
|
+
import { DatasetResourceId } from "@sanity/workflow-react/observer";
|
|
2
2
|
import type { DocumentStore } from "sanity";
|
|
3
|
-
import
|
|
3
|
+
import { Engine } from "@sanity/workflow-engine";
|
|
4
|
+
import type { GdrUri } from "@sanity/workflow-engine";
|
|
5
|
+
import type { InstancesQueryFilter } from "@sanity/workflow-engine";
|
|
4
6
|
import { MutationGuardDoc } from "@sanity/workflow-react";
|
|
5
|
-
import {
|
|
7
|
+
import { ResourceClientResolver } from "@sanity/workflow-engine";
|
|
8
|
+
import type { SanityInstance } from "@sanity/sdk";
|
|
9
|
+
import { useClient } from "sanity";
|
|
6
10
|
import type { WorkflowAccessOverride } from "@sanity/workflow-engine";
|
|
7
|
-
import {
|
|
8
|
-
import { WorkflowObserver } from "@sanity/workflow-react";
|
|
11
|
+
import { WorkflowInstanceList } from "@sanity/workflow-react";
|
|
12
|
+
import { WorkflowObserver } from "@sanity/workflow-react/observer";
|
|
13
|
+
import { WorkflowResource } from "@sanity/workflow-engine";
|
|
14
|
+
import { WorkflowSession } from "@sanity/workflow-react";
|
|
9
15
|
|
|
10
16
|
/**
|
|
11
17
|
* A {@link WorkflowObserver} that routes every stream to the store that can
|
|
@@ -13,7 +19,8 @@ import { WorkflowObserver } from "@sanity/workflow-react";
|
|
|
13
19
|
*
|
|
14
20
|
* - Anything in the **mounted workspace dataset** → `documentStore`
|
|
15
21
|
* (`pair.editState` for docs — including Studio's local uncommitted edits,
|
|
16
|
-
* the one stream only Studio has — and `listenQuery` for guards
|
|
22
|
+
* the one stream only Studio has — and `listenQuery` for guards and
|
|
23
|
+
* instance lists).
|
|
17
24
|
* - Anything else (foreign content refs; the engine's state dataset when it
|
|
18
25
|
* isn't the workspace) → the App SDK store via {@link sdkInstanceDocStore} /
|
|
19
26
|
* {@link sdkContentDocStore} / {@link sdkGuardStore} when
|
|
@@ -27,6 +34,8 @@ export declare function makeStudioObserver(
|
|
|
27
34
|
|
|
28
35
|
export { MutationGuardDoc };
|
|
29
36
|
|
|
37
|
+
declare type StudioClient = ReturnType<typeof useClient>;
|
|
38
|
+
|
|
30
39
|
export declare interface StudioObserverOptions {
|
|
31
40
|
/** The workspace's project + dataset — the only resource Studio's
|
|
32
41
|
* `documentStore` can address. */
|
|
@@ -42,6 +51,66 @@ export declare interface StudioObserverOptions {
|
|
|
42
51
|
sdk?: SanityInstance;
|
|
43
52
|
}
|
|
44
53
|
|
|
54
|
+
/**
|
|
55
|
+
* The default Studio {@link ResourceClientResolver}: any fully-addressed
|
|
56
|
+
* `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.
|
|
60
|
+
*/
|
|
61
|
+
export declare function studioResourceClients(
|
|
62
|
+
client: StudioClient,
|
|
63
|
+
): ResourceClientResolver;
|
|
64
|
+
|
|
65
|
+
/** Which in-flight instances reference this document (GDR URI) — live,
|
|
66
|
+
* observed from Sanity Studio. Same routing and `sdk` rules as
|
|
67
|
+
* {@link useWorkflowInstances}. */
|
|
68
|
+
export declare function useDocumentWorkflows({
|
|
69
|
+
engine,
|
|
70
|
+
document,
|
|
71
|
+
sdk,
|
|
72
|
+
}: {
|
|
73
|
+
engine: Engine;
|
|
74
|
+
document: GdrUri;
|
|
75
|
+
sdk?: SanityInstance;
|
|
76
|
+
}): WorkflowInstanceList;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Build the Studio-side engine once: the workspace client rebound to the
|
|
80
|
+
* engine's state dataset, plus {@link studioResourceClients} as the default
|
|
81
|
+
* per-resource routing — so subjects and refs across many content datasets
|
|
82
|
+
* resolve without call sites assembling clients. Pass `resourceClients` to
|
|
83
|
+
* 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.
|
|
87
|
+
*/
|
|
88
|
+
export declare function useWorkflowEngine({
|
|
89
|
+
workflowResource,
|
|
90
|
+
tag,
|
|
91
|
+
resourceClients,
|
|
92
|
+
apiVersion,
|
|
93
|
+
}: {
|
|
94
|
+
workflowResource: WorkflowResource;
|
|
95
|
+
tag: string;
|
|
96
|
+
resourceClients?: ResourceClientResolver;
|
|
97
|
+
apiVersion?: string;
|
|
98
|
+
}): Engine;
|
|
99
|
+
|
|
100
|
+
/** A live, filterable workflow-instance list observed from Sanity Studio —
|
|
101
|
+
* through `documentStore.listenQuery` when the engine dataset is the
|
|
102
|
+
* workspace's own, else through an App SDK instance (auto-bootstrapped, or
|
|
103
|
+
* supply `sdk`). Must render inside Studio source context. */
|
|
104
|
+
export declare function useWorkflowInstances({
|
|
105
|
+
engine,
|
|
106
|
+
filter,
|
|
107
|
+
sdk,
|
|
108
|
+
}: {
|
|
109
|
+
engine: Engine;
|
|
110
|
+
filter?: InstancesQueryFilter;
|
|
111
|
+
sdk?: SanityInstance;
|
|
112
|
+
}): WorkflowInstanceList;
|
|
113
|
+
|
|
45
114
|
/**
|
|
46
115
|
* Drive a workflow instance reactively from Sanity Studio. Watched docs in the
|
|
47
116
|
* workspace's own dataset observe through `documentStore.pair.editState`
|
|
@@ -52,23 +121,24 @@ export declare interface StudioObserverOptions {
|
|
|
52
121
|
* Studio session (pass `sdk` to supply your own — required for
|
|
53
122
|
* cookie-authenticated studios, where no session token is readable). Returns
|
|
54
123
|
* `{evaluation, ready, guards, tick, fireAction, editField}`; the consumer decides when
|
|
55
|
-
* to advance. Must render inside Studio source context
|
|
56
|
-
* `useDocumentStore`/`useSource` resolve).
|
|
124
|
+
* to advance. Must render inside Studio source context.
|
|
57
125
|
*/
|
|
58
|
-
export declare function
|
|
126
|
+
export declare function useWorkflowSession({
|
|
59
127
|
engine,
|
|
60
128
|
instanceId,
|
|
61
129
|
access,
|
|
62
130
|
grantsFromPath,
|
|
63
|
-
sdk
|
|
131
|
+
sdk,
|
|
64
132
|
}: {
|
|
65
133
|
engine: Engine;
|
|
66
134
|
instanceId: string;
|
|
67
135
|
access?: WorkflowAccessOverride;
|
|
68
136
|
grantsFromPath?: string;
|
|
69
137
|
sdk?: SanityInstance;
|
|
70
|
-
}):
|
|
138
|
+
}): WorkflowSession;
|
|
139
|
+
|
|
140
|
+
export { WorkflowInstanceList };
|
|
71
141
|
|
|
72
|
-
export {
|
|
142
|
+
export { WorkflowSession };
|
|
73
143
|
|
|
74
144
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import { DatasetResourceId } from "@sanity/workflow-react";
|
|
1
|
+
import { DatasetResourceId } from "@sanity/workflow-react/observer";
|
|
2
2
|
import type { DocumentStore } from "sanity";
|
|
3
|
-
import
|
|
3
|
+
import { Engine } from "@sanity/workflow-engine";
|
|
4
|
+
import type { GdrUri } from "@sanity/workflow-engine";
|
|
5
|
+
import type { InstancesQueryFilter } from "@sanity/workflow-engine";
|
|
4
6
|
import { MutationGuardDoc } from "@sanity/workflow-react";
|
|
5
|
-
import {
|
|
7
|
+
import { ResourceClientResolver } from "@sanity/workflow-engine";
|
|
8
|
+
import type { SanityInstance } from "@sanity/sdk";
|
|
9
|
+
import { useClient } from "sanity";
|
|
6
10
|
import type { WorkflowAccessOverride } from "@sanity/workflow-engine";
|
|
7
|
-
import {
|
|
8
|
-
import { WorkflowObserver } from "@sanity/workflow-react";
|
|
11
|
+
import { WorkflowInstanceList } from "@sanity/workflow-react";
|
|
12
|
+
import { WorkflowObserver } from "@sanity/workflow-react/observer";
|
|
13
|
+
import { WorkflowResource } from "@sanity/workflow-engine";
|
|
14
|
+
import { WorkflowSession } from "@sanity/workflow-react";
|
|
9
15
|
|
|
10
16
|
/**
|
|
11
17
|
* A {@link WorkflowObserver} that routes every stream to the store that can
|
|
@@ -13,7 +19,8 @@ import { WorkflowObserver } from "@sanity/workflow-react";
|
|
|
13
19
|
*
|
|
14
20
|
* - Anything in the **mounted workspace dataset** → `documentStore`
|
|
15
21
|
* (`pair.editState` for docs — including Studio's local uncommitted edits,
|
|
16
|
-
* the one stream only Studio has — and `listenQuery` for guards
|
|
22
|
+
* the one stream only Studio has — and `listenQuery` for guards and
|
|
23
|
+
* instance lists).
|
|
17
24
|
* - Anything else (foreign content refs; the engine's state dataset when it
|
|
18
25
|
* isn't the workspace) → the App SDK store via {@link sdkInstanceDocStore} /
|
|
19
26
|
* {@link sdkContentDocStore} / {@link sdkGuardStore} when
|
|
@@ -27,6 +34,8 @@ export declare function makeStudioObserver(
|
|
|
27
34
|
|
|
28
35
|
export { MutationGuardDoc };
|
|
29
36
|
|
|
37
|
+
declare type StudioClient = ReturnType<typeof useClient>;
|
|
38
|
+
|
|
30
39
|
export declare interface StudioObserverOptions {
|
|
31
40
|
/** The workspace's project + dataset — the only resource Studio's
|
|
32
41
|
* `documentStore` can address. */
|
|
@@ -42,6 +51,66 @@ export declare interface StudioObserverOptions {
|
|
|
42
51
|
sdk?: SanityInstance;
|
|
43
52
|
}
|
|
44
53
|
|
|
54
|
+
/**
|
|
55
|
+
* The default Studio {@link ResourceClientResolver}: any fully-addressed
|
|
56
|
+
* `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.
|
|
60
|
+
*/
|
|
61
|
+
export declare function studioResourceClients(
|
|
62
|
+
client: StudioClient,
|
|
63
|
+
): ResourceClientResolver;
|
|
64
|
+
|
|
65
|
+
/** Which in-flight instances reference this document (GDR URI) — live,
|
|
66
|
+
* observed from Sanity Studio. Same routing and `sdk` rules as
|
|
67
|
+
* {@link useWorkflowInstances}. */
|
|
68
|
+
export declare function useDocumentWorkflows({
|
|
69
|
+
engine,
|
|
70
|
+
document,
|
|
71
|
+
sdk,
|
|
72
|
+
}: {
|
|
73
|
+
engine: Engine;
|
|
74
|
+
document: GdrUri;
|
|
75
|
+
sdk?: SanityInstance;
|
|
76
|
+
}): WorkflowInstanceList;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Build the Studio-side engine once: the workspace client rebound to the
|
|
80
|
+
* engine's state dataset, plus {@link studioResourceClients} as the default
|
|
81
|
+
* per-resource routing — so subjects and refs across many content datasets
|
|
82
|
+
* resolve without call sites assembling clients. Pass `resourceClients` to
|
|
83
|
+
* 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.
|
|
87
|
+
*/
|
|
88
|
+
export declare function useWorkflowEngine({
|
|
89
|
+
workflowResource,
|
|
90
|
+
tag,
|
|
91
|
+
resourceClients,
|
|
92
|
+
apiVersion,
|
|
93
|
+
}: {
|
|
94
|
+
workflowResource: WorkflowResource;
|
|
95
|
+
tag: string;
|
|
96
|
+
resourceClients?: ResourceClientResolver;
|
|
97
|
+
apiVersion?: string;
|
|
98
|
+
}): Engine;
|
|
99
|
+
|
|
100
|
+
/** A live, filterable workflow-instance list observed from Sanity Studio —
|
|
101
|
+
* through `documentStore.listenQuery` when the engine dataset is the
|
|
102
|
+
* workspace's own, else through an App SDK instance (auto-bootstrapped, or
|
|
103
|
+
* supply `sdk`). Must render inside Studio source context. */
|
|
104
|
+
export declare function useWorkflowInstances({
|
|
105
|
+
engine,
|
|
106
|
+
filter,
|
|
107
|
+
sdk,
|
|
108
|
+
}: {
|
|
109
|
+
engine: Engine;
|
|
110
|
+
filter?: InstancesQueryFilter;
|
|
111
|
+
sdk?: SanityInstance;
|
|
112
|
+
}): WorkflowInstanceList;
|
|
113
|
+
|
|
45
114
|
/**
|
|
46
115
|
* Drive a workflow instance reactively from Sanity Studio. Watched docs in the
|
|
47
116
|
* workspace's own dataset observe through `documentStore.pair.editState`
|
|
@@ -52,23 +121,24 @@ export declare interface StudioObserverOptions {
|
|
|
52
121
|
* Studio session (pass `sdk` to supply your own — required for
|
|
53
122
|
* cookie-authenticated studios, where no session token is readable). Returns
|
|
54
123
|
* `{evaluation, ready, guards, tick, fireAction, editField}`; the consumer decides when
|
|
55
|
-
* to advance. Must render inside Studio source context
|
|
56
|
-
* `useDocumentStore`/`useSource` resolve).
|
|
124
|
+
* to advance. Must render inside Studio source context.
|
|
57
125
|
*/
|
|
58
|
-
export declare function
|
|
126
|
+
export declare function useWorkflowSession({
|
|
59
127
|
engine,
|
|
60
128
|
instanceId,
|
|
61
129
|
access,
|
|
62
130
|
grantsFromPath,
|
|
63
|
-
sdk
|
|
131
|
+
sdk,
|
|
64
132
|
}: {
|
|
65
133
|
engine: Engine;
|
|
66
134
|
instanceId: string;
|
|
67
135
|
access?: WorkflowAccessOverride;
|
|
68
136
|
grantsFromPath?: string;
|
|
69
137
|
sdk?: SanityInstance;
|
|
70
|
-
}):
|
|
138
|
+
}): WorkflowSession;
|
|
139
|
+
|
|
140
|
+
export { WorkflowInstanceList };
|
|
71
141
|
|
|
72
|
-
export {
|
|
142
|
+
export { WorkflowSession };
|
|
73
143
|
|
|
74
144
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { instanceGuardQuery, contentReleaseName, WORKFLOW_INSTANCE_TYPE } from "@sanity/workflow-engine";
|
|
2
|
-
import { sameDataset, combineGuardStores, combineDocStores, classifyRef,
|
|
3
|
-
import { sdkGuardStore, sdkContentDocStore, sdkInstanceDocStore } from "@sanity/workflow-sdk";
|
|
4
|
-
import { createSanityInstance } from "@sanity/sdk";
|
|
1
|
+
import { instanceGuardQuery, contentReleaseName, WORKFLOW_INSTANCE_TYPE, ENGINE_API_VERSION, createEngine } from "@sanity/workflow-engine";
|
|
2
|
+
import { sameDataset, combineGuardStores, combineDocStores, classifyRef, useKeyed, datasetResourceId } from "@sanity/workflow-react/observer";
|
|
3
|
+
import { sdkInstancesStore, sdkGuardStore, sdkContentDocStore, sdkInstanceDocStore } from "@sanity/workflow-sdk/observer";
|
|
5
4
|
import { useMemo, useRef, useEffect } from "react";
|
|
6
|
-
import { useDocumentStore, useSource } from "sanity";
|
|
5
|
+
import { useClient, useDocumentStore, useSource } from "sanity";
|
|
6
|
+
import { useWorkflowSession as useWorkflowSession$1, useDocumentWorkflows as useDocumentWorkflows$1, useWorkflowInstances as useWorkflowInstances$1 } from "@sanity/workflow-react";
|
|
7
|
+
import { createSanityInstance } from "@sanity/sdk";
|
|
7
8
|
function observableStore({
|
|
8
9
|
observable,
|
|
9
10
|
resolve,
|
|
@@ -32,7 +33,7 @@ function makeStudioObserver(documentStore, options) {
|
|
|
32
33
|
}), requireSdk = (what) => {
|
|
33
34
|
if (sdk !== void 0) return sdk;
|
|
34
35
|
throw new Error(
|
|
35
|
-
`@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 (\`
|
|
36
|
+
`@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.`
|
|
36
37
|
);
|
|
37
38
|
};
|
|
38
39
|
return {
|
|
@@ -67,7 +68,7 @@ function makeStudioObserver(documentStore, options) {
|
|
|
67
68
|
return observableStore({
|
|
68
69
|
observable: documentStore.listenQuery(query, params, {}),
|
|
69
70
|
resolve: (docs) => docs,
|
|
70
|
-
initial:
|
|
71
|
+
initial: void 0
|
|
71
72
|
});
|
|
72
73
|
}
|
|
73
74
|
return sdkGuardStore({
|
|
@@ -78,27 +79,64 @@ function makeStudioObserver(documentStore, options) {
|
|
|
78
79
|
resource
|
|
79
80
|
});
|
|
80
81
|
})
|
|
81
|
-
)
|
|
82
|
+
),
|
|
83
|
+
observeInstances: (query) => engineIsMounted ? observableStore({
|
|
84
|
+
observable: documentStore.listenQuery(query.query, query.params, {}),
|
|
85
|
+
resolve: (docs) => docs,
|
|
86
|
+
initial: void 0
|
|
87
|
+
}) : sdkInstancesStore({
|
|
88
|
+
sdk: requireSdk(
|
|
89
|
+
`the instance list lives in the engine dataset ${engineResource.projectId}.${engineResource.dataset}`
|
|
90
|
+
),
|
|
91
|
+
query,
|
|
92
|
+
resource: engineResource
|
|
93
|
+
})
|
|
82
94
|
};
|
|
83
95
|
}
|
|
84
96
|
function resolveEditState(editState) {
|
|
85
97
|
if (editState.ready)
|
|
86
98
|
return editState.version ?? editState.draft ?? editState.published;
|
|
87
99
|
}
|
|
88
|
-
function
|
|
100
|
+
function useWorkflowEngine({
|
|
101
|
+
workflowResource,
|
|
102
|
+
tag,
|
|
103
|
+
resourceClients,
|
|
104
|
+
apiVersion
|
|
105
|
+
}) {
|
|
106
|
+
const client = useClient({ apiVersion: apiVersion ?? ENGINE_API_VERSION }), resource = useKeyed([workflowResource.type, workflowResource.id], () => workflowResource);
|
|
107
|
+
return useMemo(() => {
|
|
108
|
+
const engineDataset = datasetResourceId(resource), engineClient = client.withConfig({
|
|
109
|
+
projectId: engineDataset.projectId,
|
|
110
|
+
dataset: engineDataset.dataset,
|
|
111
|
+
useCdn: !1
|
|
112
|
+
});
|
|
113
|
+
return createEngine({
|
|
114
|
+
client: engineClient,
|
|
115
|
+
workflowResource: resource,
|
|
116
|
+
tag,
|
|
117
|
+
resourceClients: resourceClients ?? studioResourceClients(client)
|
|
118
|
+
});
|
|
119
|
+
}, [client, resource, tag, resourceClients]);
|
|
120
|
+
}
|
|
121
|
+
function studioResourceClients(client) {
|
|
122
|
+
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;
|
|
123
|
+
}
|
|
124
|
+
const SESSION_CLIENT_OPTIONS = { apiVersion: ENGINE_API_VERSION };
|
|
125
|
+
function useStudioObserver({
|
|
89
126
|
engine,
|
|
90
|
-
instanceId,
|
|
91
|
-
access,
|
|
92
|
-
grantsFromPath,
|
|
93
127
|
sdk: suppliedSdk
|
|
94
128
|
}) {
|
|
95
|
-
const documentStore = useDocumentStore(), { projectId, dataset } =
|
|
129
|
+
const documentStore = useDocumentStore(), source = useSource(), { projectId, dataset } = source, mounted = useMemo(() => ({ projectId, dataset }), [projectId, dataset]), engineResource = useMemo(() => datasetResourceId(engine.workflowResource), [engine]), sdk = useEmbeddedSdk({
|
|
96
130
|
supplied: suppliedSdk,
|
|
97
131
|
// The engine dataset being foreign is the signal an SDK instance is
|
|
98
132
|
// needed; foreign content refs without one still fail loud per ref.
|
|
99
133
|
needed: !sameDataset(engineResource, mounted),
|
|
100
|
-
mounted
|
|
101
|
-
|
|
134
|
+
mounted,
|
|
135
|
+
// The session's token rides the source client's config (absent under
|
|
136
|
+
// cookie auth) — the public read; Studio's token storage is private.
|
|
137
|
+
sessionToken: source.getClient(SESSION_CLIENT_OPTIONS).config().token
|
|
138
|
+
});
|
|
139
|
+
return useMemo(
|
|
102
140
|
() => makeStudioObserver(documentStore, {
|
|
103
141
|
mounted,
|
|
104
142
|
engineResource,
|
|
@@ -106,23 +144,27 @@ function useWorkflowInstance({
|
|
|
106
144
|
}),
|
|
107
145
|
[documentStore, mounted, engineResource, sdk]
|
|
108
146
|
);
|
|
109
|
-
return useWorkflowSession({ engine, instanceId, observer, opts: { access, grantsFromPath } });
|
|
110
147
|
}
|
|
111
148
|
function useEmbeddedSdk({
|
|
112
149
|
supplied,
|
|
113
150
|
needed,
|
|
114
|
-
mounted
|
|
151
|
+
mounted,
|
|
152
|
+
sessionToken
|
|
115
153
|
}) {
|
|
116
154
|
const wanted = supplied === void 0 && needed, held = useRef(void 0), key = `${mounted.projectId}.${mounted.dataset}`;
|
|
117
|
-
wanted && (held.current?.key !== key || held.current.instance.isDisposed()) && (held.current = { key, instance: bootstrapInstance(mounted) });
|
|
155
|
+
wanted && (held.current?.key !== key || held.current.instance.isDisposed()) && (held.current = { key, instance: bootstrapInstance(mounted, sessionToken) });
|
|
118
156
|
const embedded = wanted ? held.current?.instance : void 0;
|
|
119
157
|
return useDeferredDispose(embedded), supplied ?? embedded;
|
|
120
158
|
}
|
|
121
|
-
function bootstrapInstance(mounted) {
|
|
159
|
+
function bootstrapInstance(mounted, sessionToken) {
|
|
160
|
+
if (sessionToken === void 0)
|
|
161
|
+
throw new Error(
|
|
162
|
+
"@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})."
|
|
163
|
+
);
|
|
122
164
|
return createSanityInstance({
|
|
123
165
|
projectId: mounted.projectId,
|
|
124
166
|
dataset: mounted.dataset,
|
|
125
|
-
auth: { token:
|
|
167
|
+
auth: { token: sessionToken }
|
|
126
168
|
});
|
|
127
169
|
}
|
|
128
170
|
function useDeferredDispose(instance) {
|
|
@@ -139,26 +181,38 @@ function useDeferredDispose(instance) {
|
|
|
139
181
|
};
|
|
140
182
|
}, [instance]);
|
|
141
183
|
}
|
|
142
|
-
function
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
184
|
+
function useWorkflowSession({
|
|
185
|
+
engine,
|
|
186
|
+
instanceId,
|
|
187
|
+
access,
|
|
188
|
+
grantsFromPath,
|
|
189
|
+
sdk
|
|
190
|
+
}) {
|
|
191
|
+
const observer = useStudioObserver({ engine, sdk });
|
|
192
|
+
return useWorkflowSession$1({ engine, instanceId, observer, opts: { access, grantsFromPath } });
|
|
193
|
+
}
|
|
194
|
+
function useWorkflowInstances({
|
|
195
|
+
engine,
|
|
196
|
+
filter,
|
|
197
|
+
sdk
|
|
198
|
+
}) {
|
|
199
|
+
const observer = useStudioObserver({ engine, sdk });
|
|
200
|
+
return useWorkflowInstances$1({ engine, observer, ...filter !== void 0 ? { filter } : {} });
|
|
149
201
|
}
|
|
150
|
-
function
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
202
|
+
function useDocumentWorkflows({
|
|
203
|
+
engine,
|
|
204
|
+
document,
|
|
205
|
+
sdk
|
|
206
|
+
}) {
|
|
207
|
+
const observer = useStudioObserver({ engine, sdk });
|
|
208
|
+
return useDocumentWorkflows$1({ engine, observer, document });
|
|
159
209
|
}
|
|
160
210
|
export {
|
|
161
211
|
makeStudioObserver,
|
|
162
|
-
|
|
212
|
+
studioResourceClients,
|
|
213
|
+
useDocumentWorkflows,
|
|
214
|
+
useWorkflowEngine,
|
|
215
|
+
useWorkflowInstances,
|
|
216
|
+
useWorkflowSession
|
|
163
217
|
};
|
|
164
218
|
//# sourceMappingURL=index.js.map
|
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,\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).\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 (\\`useWorkflowInstance(engine, id, {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 return observableStore<MutationGuardDoc[], readonly MutationGuardDoc[]>({\n observable: documentStore.listenQuery(query, params, {}),\n resolve: (docs) => docs,\n initial: NO_GUARDS,\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 }\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 `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,\n instanceId,\n access,\n grantsFromPath,\n sdk: suppliedSdk,\n}: {\n engine: Engine\n instanceId: string\n access?: WorkflowAccessOverride\n grantsFromPath?: string\n 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 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 })\n const observer = useMemo(\n () =>\n makeStudioObserver(documentStore, {\n mounted,\n engineResource,\n ...(sdk !== undefined ? {sdk} : {}),\n }),\n [documentStore, mounted, engineResource, sdk],\n )\n // `sdk` is a store handle for the observer, never an `engine.instance(...)`\n // argument — only the session options cross into the engine.\n return useWorkflowSession({engine, instanceId, observer, opts: {access, grantsFromPath}})\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,\n needed,\n mounted,\n}: {\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, instanceId, 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-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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/workflow-studio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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,14 +40,13 @@
|
|
|
40
40
|
"access": "restricted"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@sanity/workflow-engine": "0.
|
|
44
|
-
"@sanity/workflow-react": "0.
|
|
45
|
-
"@sanity/workflow-sdk": "0.
|
|
43
|
+
"@sanity/workflow-engine": "0.14.0",
|
|
44
|
+
"@sanity/workflow-react": "0.9.0",
|
|
45
|
+
"@sanity/workflow-sdk": "0.6.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@sanity/pkg-utils": "^10.5.2",
|
|
49
49
|
"@sanity/sdk": "^2.12.0",
|
|
50
|
-
"@sanity/sdk-react": "^2.12.0",
|
|
51
50
|
"@testing-library/react": "^16.3.2",
|
|
52
51
|
"@types/react": "^19.2.17",
|
|
53
52
|
"jsdom": "^29.1.1",
|
|
@@ -58,7 +57,6 @@
|
|
|
58
57
|
},
|
|
59
58
|
"peerDependencies": {
|
|
60
59
|
"@sanity/sdk": "^2.12.0",
|
|
61
|
-
"@sanity/sdk-react": "^2.12.0",
|
|
62
60
|
"react": "^19.2.7",
|
|
63
61
|
"sanity": "^5.30.0"
|
|
64
62
|
},
|