@sanity/sdk-react 2.4.0 → 2.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.
Files changed (30) hide show
  1. package/README.md +652 -4
  2. package/dist/index.d.ts +85 -14
  3. package/dist/index.js +184 -57
  4. package/dist/index.js.map +1 -1
  5. package/package.json +9 -8
  6. package/src/_exports/sdk-react.ts +5 -0
  7. package/src/components/SDKProvider.tsx +8 -3
  8. package/src/components/SanityApp.tsx +2 -1
  9. package/src/context/SourcesContext.tsx +7 -0
  10. package/src/context/renderSanityApp.test.tsx +355 -0
  11. package/src/context/renderSanityApp.tsx +48 -0
  12. package/src/hooks/agent/useAgentResourceContext.test.tsx +245 -0
  13. package/src/hooks/agent/useAgentResourceContext.ts +106 -0
  14. package/src/hooks/context/useSource.tsx +34 -0
  15. package/src/hooks/dashboard/useDispatchIntent.test.ts +25 -22
  16. package/src/hooks/dashboard/useDispatchIntent.ts +9 -10
  17. package/src/hooks/dashboard/utils/{getResourceIdFromDocumentHandle.test.ts → useResourceIdFromDocumentHandle.test.ts} +33 -59
  18. package/src/hooks/dashboard/utils/useResourceIdFromDocumentHandle.ts +46 -0
  19. package/src/hooks/document/useApplyDocumentActions.test.ts +124 -9
  20. package/src/hooks/document/useApplyDocumentActions.ts +44 -4
  21. package/src/hooks/document/useDocumentPermissions.test.tsx +3 -3
  22. package/src/hooks/document/useDocumentPermissions.ts +9 -6
  23. package/src/hooks/document/useEditDocument.ts +3 -0
  24. package/src/hooks/documents/useDocuments.ts +3 -2
  25. package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +1 -0
  26. package/src/hooks/query/useQuery.ts +21 -8
  27. package/src/hooks/releases/usePerspective.test.tsx +1 -0
  28. package/src/hooks/releases/usePerspective.ts +1 -1
  29. package/src/hooks/dashboard/types.ts +0 -12
  30. package/src/hooks/dashboard/utils/getResourceIdFromDocumentHandle.ts +0 -53
package/dist/index.d.ts CHANGED
@@ -52,6 +52,24 @@ import {StudioResource} from '@sanity/message-protocol'
52
52
  import {UserPresence} from '@sanity/sdk'
53
53
  import {WindowMessage} from '@sanity/sdk'
54
54
 
55
+ /**
56
+ * @public
57
+ */
58
+ export declare interface AgentResourceContextOptions {
59
+ /**
60
+ * The project ID of the current context
61
+ */
62
+ projectId: string
63
+ /**
64
+ * The dataset of the current context
65
+ */
66
+ dataset: string
67
+ /**
68
+ * Optional document ID if the user is viewing/editing a specific document
69
+ */
70
+ documentId?: string
71
+ }
72
+
55
73
  /**
56
74
  * A component that handles authentication flow and error boundaries for a
57
75
  * protected section of the application.
@@ -158,18 +176,6 @@ declare interface DispatchIntent {
158
176
  dispatchIntent: () => void
159
177
  }
160
178
 
161
- /**
162
- * Document handle that optionally includes a source (e.g., media library source)
163
- * or projectId and dataset for traditional dataset sources
164
- * (but now marked optional since it's valid to just use a source)
165
- * @beta
166
- */
167
- declare interface DocumentHandleWithSource extends Omit<DocumentHandle, 'projectId' | 'dataset'> {
168
- source?: DocumentSource
169
- projectId?: string
170
- dataset?: string
171
- }
172
-
173
179
  declare interface DocumentInteractionHistory {
174
180
  recordEvent: (eventType: 'viewed' | 'edited' | 'created' | 'deleted') => void
175
181
  }
@@ -200,6 +206,7 @@ export declare interface DocumentsOptions<
200
206
  batchSize?: number
201
207
  /**
202
208
  * Sorting configuration for the results
209
+ * @beta
203
210
  */
204
211
  orderings?: SortOrderingItem[]
205
212
  /**
@@ -289,6 +296,13 @@ export declare type MessageHandler<TWindowMessage extends WindowMessage> = (
289
296
  event: TWindowMessage['data'],
290
297
  ) => TWindowMessage['response'] | Promise<TWindowMessage['response']>
291
298
 
299
+ /** In-flight CLI PR is using named sources since it's aspirational.
300
+ * We can transform the shape in this function until it's finalized.
301
+ */
302
+ declare interface NamedSources {
303
+ [key: string]: SanityConfig
304
+ }
305
+
292
306
  /**
293
307
  * @public
294
308
  * @category Types
@@ -325,6 +339,7 @@ export declare interface PaginatedDocumentsOptions<
325
339
  pageSize?: number
326
340
  /**
327
341
  * Sorting configuration for the results
342
+ * @beta
328
343
  */
329
344
  orderings?: SortOrderingItem[]
330
345
  /**
@@ -428,6 +443,18 @@ export declare type ProjectWithoutMembers = Omit<SanityProject_2, 'members'>
428
443
  */
429
444
  export declare const REACT_SDK_VERSION: {}
430
445
 
446
+ /** @internal */
447
+ export declare function renderSanityApp(
448
+ rootElement: HTMLElement | null,
449
+ namedSources: NamedSources,
450
+ options: RenderSanitySDKAppOptions,
451
+ children: React.ReactNode,
452
+ ): () => void
453
+
454
+ declare interface RenderSanitySDKAppOptions {
455
+ reactStrictMode?: boolean
456
+ }
457
+
431
458
  /**
432
459
  * Provides a Sanity instance to child components through React Context
433
460
  *
@@ -565,6 +592,7 @@ export declare interface SanityAppProps {
565
592
  config: SanityConfig | SanityConfig[]
566
593
  /** @deprecated use the `config` prop instead. */
567
594
  sanityConfigs?: SanityConfig[]
595
+ sources?: Record<string, DocumentSource>
568
596
  children: React.ReactNode
569
597
  fallback: React.ReactNode
570
598
  }
@@ -594,6 +622,7 @@ export declare interface SDKProviderProps extends AuthBoundaryProps {
594
622
  children: ReactNode
595
623
  config: SanityConfig | SanityConfig[]
596
624
  fallback: ReactNode
625
+ sources?: Record<string, DocumentSource>
597
626
  }
598
627
 
599
628
  export {SortOrderingItem}
@@ -679,6 +708,38 @@ export declare const useAgentPrompt: () => (
679
708
  options: AgentPromptOptions,
680
709
  ) => Promise<AgentPromptResult>
681
710
 
711
+ /**
712
+ * @public
713
+ * Hook for emitting agent resource context updates to the Dashboard.
714
+ * This allows the Agent to understand what resource the user is currently
715
+ * interacting with (e.g., which document they're editing).
716
+ *
717
+ * The hook will automatically emit the context when it changes, and also
718
+ * emit the initial context when the hook is first mounted.
719
+ *
720
+ * @category Agent
721
+ * @param options - The resource context options containing projectId, dataset, and optional documentId
722
+ *
723
+ * @example
724
+ * ```tsx
725
+ * import {useAgentResourceContext} from '@sanity/sdk-react'
726
+ *
727
+ * function MyComponent() {
728
+ * const documentId = 'my-document-id'
729
+ *
730
+ * // Automatically updates the Agent's context whenever the document changes
731
+ * useAgentResourceContext({
732
+ * projectId: 'my-project',
733
+ * dataset: 'production',
734
+ * documentId,
735
+ * })
736
+ *
737
+ * return <div>Editing document: {documentId}</div>
738
+ * }
739
+ * ```
740
+ */
741
+ export declare function useAgentResourceContext(options: AgentResourceContextOptions): void
742
+
682
743
  /**
683
744
  * @alpha
684
745
  * Transforms an existing document or selected fields using Sanity Agent Actions.
@@ -1096,7 +1157,7 @@ export declare function useDispatchIntent(params: UseDispatchIntentParams): Disp
1096
1157
  declare interface UseDispatchIntentParams {
1097
1158
  action?: 'edit'
1098
1159
  intentId?: string
1099
- documentHandle: DocumentHandleWithSource
1160
+ documentHandle: DocumentHandle
1100
1161
  parameters?: Record<string, unknown>
1101
1162
  }
1102
1163
 
@@ -2408,8 +2469,9 @@ export declare function useQuery<
2408
2469
  TQuery extends string = string,
2409
2470
  TDataset extends string = string,
2410
2471
  TProjectId extends string = string,
2472
+ TSourceName extends string = string,
2411
2473
  >(
2412
- options: QueryOptions<TQuery, TDataset, TProjectId>,
2474
+ options: UseQueryOptions<TQuery, TDataset, TProjectId, TSourceName>,
2413
2475
  ): {
2414
2476
  /** The query result, typed based on the GROQ query string */
2415
2477
  data: SanityQueryResult<TQuery, `${TProjectId}.${TDataset}`>
@@ -2452,6 +2514,15 @@ export declare function useQuery<TData>(options: QueryOptions): {
2452
2514
  isPending: boolean
2453
2515
  }
2454
2516
 
2517
+ declare interface UseQueryOptions<
2518
+ TQuery extends string = string,
2519
+ TDataset extends string = string,
2520
+ TProjectId extends string = string,
2521
+ TSourceName extends string = string,
2522
+ > extends QueryOptions<TQuery, TDataset, TProjectId> {
2523
+ sourceName?: TSourceName
2524
+ }
2525
+
2455
2526
  /**
2456
2527
  * @internal
2457
2528
  * Hook for managing document interaction history in Sanity Studio.
package/dist/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { c } from "react-compiler-runtime";
3
3
  import { ClientError, CorsOriginError } from "@sanity/client";
4
- import { getAuthState, getNodeState, getIsInDashboardState, setAuthToken, AuthStateType, getLoginUrlState, observeOrganizationVerificationState, handleAuthCallback, logout, isProjectUserNotFoundClientError, getClientErrorApiDescription, getClientErrorApiBody, getCorsErrorProjectId, createSanityInstance, agentGenerate, agentTransform, agentTranslate, agentPrompt, agentPatch, getTokenState, getCurrentUserState, getDashboardOrganizationId, getClientState, getOrCreateController, getOrCreateChannel, releaseChannel, getFavoritesState, resolveFavoritesState, resolveDatasets, getDatasetsState, applyDocumentActions, resolveDocument, getDocumentState, subscribeDocumentEvents, getPermissionsState, getDocumentSyncStatus, editDocument, getQueryKey, parseQueryKey, getQueryState, resolveQuery, createGroqSearchFilter, getPresence, getPreviewState, resolvePreview, getProjectionState, resolveProjection, resolveProject, getProjectState, resolveProjects, getProjectsState, getActiveReleasesState, getPerspectiveState, getUsersKey, parseUsersKey, getUsersState, resolveUsers, loadMoreUsers } from "@sanity/sdk";
4
+ import { getAuthState, getNodeState, getIsInDashboardState, setAuthToken, AuthStateType, getLoginUrlState, observeOrganizationVerificationState, handleAuthCallback, logout, isProjectUserNotFoundClientError, getClientErrorApiDescription, getClientErrorApiBody, getCorsErrorProjectId, createSanityInstance, agentGenerate, agentTransform, agentTranslate, agentPrompt, agentPatch, getTokenState, getCurrentUserState, getDashboardOrganizationId, getClientState, getOrCreateController, getOrCreateChannel, releaseChannel, isDatasetSource, isMediaLibrarySource, isCanvasSource, getFavoritesState, resolveFavoritesState, resolveDatasets, getDatasetsState, applyDocumentActions, resolveDocument, getDocumentState, subscribeDocumentEvents, getPermissionsState, getDocumentSyncStatus, editDocument, getQueryKey, parseQueryKey, getQueryState, resolveQuery, createGroqSearchFilter, getPresence, getPreviewState, resolvePreview, getProjectionState, resolveProjection, resolveProject, getProjectState, resolveProjects, getProjectsState, getActiveReleasesState, getPerspectiveState, getUsersKey, parseUsersKey, getUsersState, resolveUsers, loadMoreUsers } from "@sanity/sdk";
5
5
  export * from "@sanity/sdk";
6
- import { createContext, useContext, useSyncExternalStore, useRef, useEffect, useState, Suspense, useCallback, useMemo, useInsertionEffect, useTransition } from "react";
6
+ import { createContext, useContext, useSyncExternalStore, useRef, useEffect, useState, Suspense, StrictMode, useCallback, useMemo, useInsertionEffect, useTransition } from "react";
7
7
  import { ErrorBoundary } from "react-error-boundary";
8
8
  import { SDK_CHANNEL_NAME, SDK_NODE_NAME } from "@sanity/message-protocol";
9
9
  import { firstValueFrom, filter, identity, Observable, startWith, distinctUntilChanged, switchMap, EMPTY } from "rxjs";
10
+ import { createRoot } from "react-dom/client";
10
11
  import { pick } from "lodash-es";
11
12
  const SanityInstanceContext = createContext(null), useSanityInstance = (config) => {
12
13
  const $ = c(3), instance = useContext(SanityInstanceContext);
@@ -65,7 +66,7 @@ function useWindowConnection(t0) {
65
66
  const [type, handler] = t42, messageUnsubscribe = node.on(type, handler);
66
67
  messageUnsubscribe && messageUnsubscribers.current.push(messageUnsubscribe);
67
68
  }), () => {
68
- messageUnsubscribers.current.forEach(_temp$7), messageUnsubscribers.current = [];
69
+ messageUnsubscribers.current.forEach(_temp$8), messageUnsubscribers.current = [];
69
70
  }), $[4] = node, $[5] = onMessage, $[6] = t3) : t3 = $[6];
70
71
  let t4;
71
72
  $[7] !== instance || $[8] !== name || $[9] !== node || $[10] !== onMessage ? (t4 = [instance, name, onMessage, node], $[7] = instance, $[8] = name, $[9] = node, $[10] = onMessage, $[11] = t4) : t4 = $[11], useEffect(t3, t4);
@@ -83,7 +84,7 @@ function useWindowConnection(t0) {
83
84
  fetch
84
85
  }, $[16] = fetch, $[17] = sendMessage, $[18] = t7) : t7 = $[18], t7;
85
86
  }
86
- function _temp$7(unsubscribe) {
87
+ function _temp$8(unsubscribe) {
87
88
  return unsubscribe();
88
89
  }
89
90
  const DEFAULT_RESPONSE_TIMEOUT = 1e4;
@@ -113,7 +114,7 @@ function DashboardTokenRefresh(t0) {
113
114
  if (clearRefreshTimeout(), res.token) {
114
115
  setAuthToken(instance, res.token);
115
116
  const errorContainer = document.getElementById("__sanityError");
116
- errorContainer && Array.from(errorContainer.getElementsByTagName("div")).some(_temp$6) && errorContainer.remove();
117
+ errorContainer && Array.from(errorContainer.getElementsByTagName("div")).some(_temp$7) && errorContainer.remove();
117
118
  }
118
119
  isTokenRefreshInProgress.current = !1;
119
120
  } catch {
@@ -134,7 +135,7 @@ function DashboardTokenRefresh(t0) {
134
135
  let t7;
135
136
  return $[11] !== authState || $[12] !== requestNewToken ? (t7 = [authState, requestNewToken], $[11] = authState, $[12] = requestNewToken, $[13] = t7) : t7 = $[13], useEffect(t6, t7), children;
136
137
  }
137
- function _temp$6(div) {
138
+ function _temp$7(div) {
138
139
  return div.textContent?.includes("Uncaught error: Unauthorized - A valid session is required for this endpoint");
139
140
  }
140
141
  const ComlinkTokenRefreshProvider = (t0) => {
@@ -289,10 +290,10 @@ function LoginCallback() {
289
290
  let t0, t1;
290
291
  return $[0] !== handleAuthCallback2 ? (t0 = () => {
291
292
  const url = new URL(location.href);
292
- handleAuthCallback2(url.toString()).then(_temp$5);
293
+ handleAuthCallback2(url.toString()).then(_temp$6);
293
294
  }, t1 = [handleAuthCallback2], $[0] = handleAuthCallback2, $[1] = t0, $[2] = t1) : (t0 = $[1], t1 = $[2]), useEffect(t0, t1), null;
294
295
  }
295
- function _temp$5(replacementLocation) {
296
+ function _temp$6(replacementLocation) {
296
297
  replacementLocation && history.replaceState(null, "", replacementLocation);
297
298
  }
298
299
  const useLogOut = createCallbackHook(logout);
@@ -419,14 +420,37 @@ function ResourceProvider(t0) {
419
420
  let t7;
420
421
  return $[13] !== instance || $[14] !== t6 ? (t7 = /* @__PURE__ */ jsx(SanityInstanceContext.Provider, { value: instance, children: t6 }), $[13] = instance, $[14] = t6, $[15] = t7) : t7 = $[15], t7;
421
422
  }
422
- function SDKProvider({
423
- children,
424
- config,
425
- fallback,
426
- ...props
427
- }) {
428
- const configs = (Array.isArray(config) ? config : [config]).slice().reverse(), projectIds = configs.map((c2) => c2.projectId).filter((id) => !!id), createNestedProviders = (index) => index >= configs.length ? /* @__PURE__ */ jsx(AuthBoundary, { ...props, projectIds, children }) : /* @__PURE__ */ jsx(ResourceProvider, { ...configs[index], fallback, children: createNestedProviders(index + 1) });
429
- return createNestedProviders(0);
423
+ const SourcesContext = createContext({});
424
+ function SDKProvider(t0) {
425
+ const $ = c(19);
426
+ let children, config, fallback, props;
427
+ $[0] !== t0 ? ({
428
+ children,
429
+ config,
430
+ fallback,
431
+ ...props
432
+ } = t0, $[0] = t0, $[1] = children, $[2] = config, $[3] = fallback, $[4] = props) : (children = $[1], config = $[2], fallback = $[3], props = $[4]);
433
+ let t1;
434
+ $[5] !== config ? (t1 = Array.isArray(config) ? config : [config], $[5] = config, $[6] = t1) : t1 = $[6];
435
+ let configs, t2;
436
+ $[7] !== t1 ? (configs = t1.slice().reverse(), t2 = configs.map(_temp$5).filter(_temp2$1), $[7] = t1, $[8] = configs, $[9] = t2) : (configs = $[8], t2 = $[9]);
437
+ const projectIds = t2;
438
+ let t3, t4;
439
+ $[10] !== props.sources ? (t4 = props.sources ?? {}, $[10] = props.sources, $[11] = t4) : t4 = $[11], t3 = t4;
440
+ const sourcesValue = t3;
441
+ let t5;
442
+ if ($[12] !== children || $[13] !== configs || $[14] !== fallback || $[15] !== projectIds || $[16] !== props || $[17] !== sourcesValue) {
443
+ const createNestedProviders = (index) => index >= configs.length ? /* @__PURE__ */ jsx(AuthBoundary, { ...props, projectIds, children: /* @__PURE__ */ jsx(SourcesContext.Provider, { value: sourcesValue, children }) }) : /* @__PURE__ */ jsx(ResourceProvider, { ...configs[index], fallback, children: createNestedProviders(index + 1) });
444
+ t5 = createNestedProviders(0), $[12] = children, $[13] = configs, $[14] = fallback, $[15] = projectIds, $[16] = props, $[17] = sourcesValue, $[18] = t5;
445
+ } else
446
+ t5 = $[18];
447
+ return t5;
448
+ }
449
+ function _temp2$1(id) {
450
+ return !!id;
451
+ }
452
+ function _temp$5(c2) {
453
+ return c2.projectId;
430
454
  }
431
455
  const REDIRECT_URL = "https://sanity.io/welcome";
432
456
  function SanityApp(t0) {
@@ -453,6 +477,14 @@ function SanityApp(t0) {
453
477
  function _temp$4() {
454
478
  console.warn("Redirecting to core", REDIRECT_URL), window.location.replace(REDIRECT_URL);
455
479
  }
480
+ function renderSanityApp(rootElement, namedSources, options, children) {
481
+ if (!rootElement)
482
+ throw new Error("Missing root element to mount application into");
483
+ const {
484
+ reactStrictMode = !1
485
+ } = options, root = createRoot(rootElement), config = Object.values(namedSources);
486
+ return root.render(reactStrictMode ? /* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(SanityApp, { config, fallback: /* @__PURE__ */ jsx("div", { children: "Loading..." }), children }) }) : /* @__PURE__ */ jsx(SanityApp, { config, fallback: /* @__PURE__ */ jsx("div", { children: "Loading..." }), children })), () => root.unmount();
487
+ }
456
488
  const useAgentGenerate = createCallbackHook(agentGenerate), useAgentTransform = createCallbackHook(agentTransform), useAgentTranslate = createCallbackHook(agentTranslate);
457
489
  function promptAdapter(instance, options) {
458
490
  return firstValueFrom(agentPrompt(instance, options));
@@ -461,7 +493,53 @@ const useAgentPrompt = createCallbackHook(promptAdapter);
461
493
  function patchAdapter(instance, options) {
462
494
  return firstValueFrom(agentPatch(instance, options));
463
495
  }
464
- const useAgentPatch = createCallbackHook(patchAdapter), useAuthToken = createStateSourceHook(getTokenState), useCurrentUser = createStateSourceHook(getCurrentUserState);
496
+ const useAgentPatch = createCallbackHook(patchAdapter);
497
+ function useAgentResourceContext(options) {
498
+ const $ = c(9), {
499
+ projectId,
500
+ dataset,
501
+ documentId
502
+ } = options;
503
+ let t0;
504
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
505
+ name: SDK_NODE_NAME,
506
+ connectTo: SDK_CHANNEL_NAME
507
+ }, $[0] = t0) : t0 = $[0];
508
+ const {
509
+ sendMessage
510
+ } = useWindowConnection(t0), lastContextRef = useRef(null);
511
+ let t1;
512
+ $[1] !== dataset || $[2] !== documentId || $[3] !== projectId || $[4] !== sendMessage ? (t1 = () => {
513
+ if (!projectId || !dataset) {
514
+ console.warn("[useAgentResourceContext] projectId and dataset are required", {
515
+ projectId,
516
+ dataset
517
+ });
518
+ return;
519
+ }
520
+ const contextKey = `${projectId}:${dataset}:${documentId || ""}`;
521
+ if (lastContextRef.current !== contextKey)
522
+ try {
523
+ const message = {
524
+ type: "dashboard/v1/events/agent/resource/update",
525
+ data: {
526
+ projectId,
527
+ dataset,
528
+ documentId
529
+ }
530
+ };
531
+ sendMessage(message.type, message.data), lastContextRef.current = contextKey;
532
+ } catch (t22) {
533
+ console.error("[useAgentResourceContext] Failed to update context:", t22);
534
+ }
535
+ }, $[1] = dataset, $[2] = documentId, $[3] = projectId, $[4] = sendMessage, $[5] = t1) : t1 = $[5];
536
+ const updateContext = t1;
537
+ let t2, t3;
538
+ $[6] !== updateContext ? (t2 = () => {
539
+ updateContext();
540
+ }, t3 = [updateContext], $[6] = updateContext, $[7] = t2, $[8] = t3) : (t2 = $[7], t3 = $[8]), useEffect(t2, t3);
541
+ }
542
+ const useAuthToken = createStateSourceHook(getTokenState), useCurrentUser = createStateSourceHook(getCurrentUserState);
465
543
  function useDashboardOrganizationId() {
466
544
  const $ = c(2), instance = useSanityInstance();
467
545
  let t0, t1;
@@ -542,28 +620,28 @@ function useDashboardNavigate(navigateFn) {
542
620
  }
543
621
  }, $[0] = navigateFn, $[1] = t0) : t0 = $[1], useWindowConnection(t0);
544
622
  }
545
- const SOURCE_ID = "__sanity_internal_sourceId", isDocumentHandleWithSource = (documentHandle) => "source" in documentHandle;
546
- function getResourceIdFromDocumentHandle(documentHandle) {
547
- let source;
548
- const {
623
+ function useSource(options) {
624
+ const sources = useContext(SourcesContext);
625
+ if (!(!options.sourceName && !options.source)) {
626
+ if (options.source)
627
+ return options.source;
628
+ if (options.sourceName && !Object.hasOwn(sources, options.sourceName))
629
+ throw new Error(`There's no source named ${JSON.stringify(options.sourceName)} in context. Please use <SourceProvider>.`);
630
+ return options.sourceName ? sources[options.sourceName] : void 0;
631
+ }
632
+ }
633
+ function useResourceIdFromDocumentHandle(documentHandle) {
634
+ const $ = c(3), source = useSource(documentHandle), {
549
635
  projectId,
550
636
  dataset
551
637
  } = documentHandle;
552
- isDocumentHandleWithSource(documentHandle) && (source = documentHandle.source);
553
- let resourceId = projectId + "." + dataset, resourceType;
554
- if (source) {
555
- const sourceId = source[SOURCE_ID];
556
- if (Array.isArray(sourceId))
557
- (sourceId[0] === "media-library" || sourceId[0] === "canvas") && (resourceType = sourceId[0], resourceId = sourceId[1]);
558
- else if (sourceId && typeof sourceId == "object" && "projectId" in sourceId) {
559
- const datasetSource = sourceId;
560
- resourceId = `${datasetSource.projectId}.${datasetSource.dataset}`;
561
- }
562
- }
563
- return {
638
+ let resourceId = "", resourceType;
639
+ projectId && dataset && (resourceId = `${projectId}.${dataset}`), source && (isDatasetSource(source) ? (resourceId = `${source.projectId}.${source.dataset}`, resourceType = void 0) : isMediaLibrarySource(source) ? (resourceId = source.mediaLibraryId, resourceType = "media-library") : isCanvasSource(source) && (resourceId = source.canvasId, resourceType = "canvas"));
640
+ let t0;
641
+ return $[0] !== resourceId || $[1] !== resourceType ? (t0 = {
564
642
  id: resourceId,
565
643
  type: resourceType
566
- };
644
+ }, $[0] = resourceId, $[1] = resourceType, $[2] = t0) : t0 = $[2], t0;
567
645
  }
568
646
  function useDispatchIntent(params) {
569
647
  const {
@@ -576,7 +654,7 @@ function useDispatchIntent(params) {
576
654
  } = useWindowConnection({
577
655
  name: SDK_NODE_NAME,
578
656
  connectTo: SDK_CHANNEL_NAME
579
- });
657
+ }), resource = useResourceIdFromDocumentHandle(documentHandle);
580
658
  return {
581
659
  dispatchIntent: useCallback(() => {
582
660
  try {
@@ -585,11 +663,11 @@ function useDispatchIntent(params) {
585
663
  const {
586
664
  projectId,
587
665
  dataset,
588
- source
666
+ sourceName
589
667
  } = documentHandle;
590
- if (action && intentId && console.warn("useDispatchIntent: Both `action` and `intentId` were provided. Using `intentId` and ignoring `action`."), !source && (!projectId || !dataset))
591
- throw new Error("useDispatchIntent: Either `source` or both `projectId` and `dataset` must be provided in documentHandle.");
592
- const resource = getResourceIdFromDocumentHandle(documentHandle), message = {
668
+ if (action && intentId && console.warn("useDispatchIntent: Both `action` and `intentId` were provided. Using `intentId` and ignoring `action`."), !sourceName && (!projectId || !dataset))
669
+ throw new Error("useDispatchIntent: Either `sourceName` or both `projectId` and `dataset` must be provided in documentHandle.");
670
+ const message = {
593
671
  type: "dashboard/v1/events/intents/dispatch-intent",
594
672
  data: {
595
673
  ...action && !intentId ? {
@@ -617,7 +695,7 @@ function useDispatchIntent(params) {
617
695
  } catch (error) {
618
696
  throw console.error("Failed to dispatch intent:", error), error;
619
697
  }
620
- }, [action, intentId, documentHandle, parameters, sendMessage])
698
+ }, [action, intentId, documentHandle, parameters, sendMessage, resource.id, resource.type])
621
699
  };
622
700
  }
623
701
  function useManageFavorite({
@@ -832,7 +910,41 @@ const useDatasets = createStateSourceHook({
832
910
  ),
833
911
  suspender: resolveDatasets,
834
912
  getConfig: identity
835
- }), useApplyDocumentActions = createCallbackHook(applyDocumentActions), useDocumentValue = createStateSourceHook({
913
+ }), useApplyDocumentActions = () => {
914
+ const $ = c(2), instance = useSanityInstance();
915
+ let t0;
916
+ return $[0] !== instance ? (t0 = (actionOrActions, options) => {
917
+ const actions = Array.isArray(actionOrActions) ? actionOrActions : [actionOrActions];
918
+ let projectId, dataset;
919
+ for (const action of actions)
920
+ if (action.projectId) {
921
+ if (projectId || (projectId = action.projectId), action.projectId !== projectId)
922
+ throw new Error(`Mismatched project IDs found in actions. All actions must belong to the same project. Found "${action.projectId}" but expected "${projectId}".`);
923
+ if (action.dataset && (dataset || (dataset = action.dataset), action.dataset !== dataset))
924
+ throw new Error(`Mismatched datasets found in actions. All actions must belong to the same dataset. Found "${action.dataset}" but expected "${dataset}".`);
925
+ }
926
+ if (projectId || dataset) {
927
+ const actualInstance = instance.match({
928
+ projectId,
929
+ dataset
930
+ });
931
+ if (!actualInstance)
932
+ throw new Error(`Could not find a matching Sanity instance for the requested action: ${JSON.stringify({
933
+ projectId,
934
+ dataset
935
+ }, null, 2)}.
936
+ Please ensure there is a ResourceProvider component with a matching configuration in the component hierarchy.`);
937
+ return applyDocumentActions(actualInstance, {
938
+ actions,
939
+ ...options
940
+ });
941
+ }
942
+ return applyDocumentActions(instance, {
943
+ actions,
944
+ ...options
945
+ });
946
+ }, $[0] = instance, $[1] = t0) : t0 = $[1], t0;
947
+ }, useDocumentValue = createStateSourceHook({
836
948
  // Pass options directly to getDocumentState
837
949
  getState: (instance, options) => getDocumentState(instance, options),
838
950
  // Pass options directly to getDocumentState for checking current value
@@ -871,8 +983,8 @@ function useDocumentEvent(options) {
871
983
  }
872
984
  function useDocumentPermissions(actionOrActions) {
873
985
  const $ = c(13);
874
- let t0;
875
- $[0] !== actionOrActions ? (t0 = Array.isArray(actionOrActions) ? actionOrActions : [actionOrActions], $[0] = actionOrActions, $[1] = t0) : t0 = $[1];
986
+ let t0, t1;
987
+ $[0] !== actionOrActions ? (t1 = Array.isArray(actionOrActions) ? actionOrActions : [actionOrActions], $[0] = actionOrActions, $[1] = t1) : t1 = $[1], t0 = t1;
876
988
  const actions = t0;
877
989
  let projectId, dataset;
878
990
  if ($[2] !== actions || $[3] !== dataset || $[4] !== projectId) {
@@ -886,20 +998,26 @@ function useDocumentPermissions(actionOrActions) {
886
998
  $[2] = actions, $[3] = dataset, $[4] = projectId, $[5] = projectId, $[6] = dataset;
887
999
  } else
888
1000
  projectId = $[5], dataset = $[6];
889
- let t1;
890
- $[7] !== dataset || $[8] !== projectId ? (t1 = {
1001
+ let t2;
1002
+ $[7] !== dataset || $[8] !== projectId ? (t2 = {
891
1003
  projectId,
892
1004
  dataset
893
- }, $[7] = dataset, $[8] = projectId, $[9] = t1) : t1 = $[9];
894
- const instance = useSanityInstance(t1);
895
- if (getPermissionsState(instance, actionOrActions).getCurrent() === void 0)
896
- throw firstValueFrom(getPermissionsState(instance, actionOrActions).observable.pipe(filter(_temp$2)));
897
- let t2, t3;
898
- $[10] !== actionOrActions || $[11] !== instance ? (t3 = getPermissionsState(instance, actionOrActions), $[10] = actionOrActions, $[11] = instance, $[12] = t3) : t3 = $[12], t2 = t3;
1005
+ }, $[7] = dataset, $[8] = projectId, $[9] = t2) : t2 = $[9];
1006
+ const instance = useSanityInstance(t2);
1007
+ if (getPermissionsState(instance, {
1008
+ actions
1009
+ }).getCurrent() === void 0)
1010
+ throw firstValueFrom(getPermissionsState(instance, {
1011
+ actions
1012
+ }).observable.pipe(filter(_temp$2)));
1013
+ let t3, t4;
1014
+ $[10] !== actions || $[11] !== instance ? (t4 = getPermissionsState(instance, {
1015
+ actions
1016
+ }), $[10] = actions, $[11] = instance, $[12] = t4) : t4 = $[12], t3 = t4;
899
1017
  const {
900
1018
  subscribe,
901
1019
  getCurrent
902
- } = t2;
1020
+ } = t3;
903
1021
  return useSyncExternalStore(subscribe, getCurrent);
904
1022
  }
905
1023
  function _temp$2(result) {
@@ -958,7 +1076,7 @@ function _temp$1(key) {
958
1076
  return !ignoredKeys.includes(key);
959
1077
  }
960
1078
  function useQuery(options) {
961
- const instance = useSanityInstance(options), [isPending, startTransition] = useTransition(), queryKey = getQueryKey(options), [deferredQueryKey, setDeferredQueryKey] = useState(queryKey), deferred = useMemo(() => parseQueryKey(deferredQueryKey), [deferredQueryKey]), ref = useRef(new AbortController());
1079
+ const instance = useSanityInstance(options), source = useSource(options), [isPending, startTransition] = useTransition(), queryKey = getQueryKey(options), [deferredQueryKey, setDeferredQueryKey] = useState(queryKey), ref = useRef(new AbortController());
962
1080
  useEffect(() => {
963
1081
  queryKey !== deferredQueryKey && startTransition(() => {
964
1082
  ref && !ref.current.signal.aborted && (ref.current.abort(), ref.current = new AbortController()), setDeferredQueryKey(queryKey);
@@ -967,11 +1085,18 @@ function useQuery(options) {
967
1085
  const {
968
1086
  getCurrent,
969
1087
  subscribe
970
- } = useMemo(() => getQueryState(instance, deferred), [instance, deferred]);
1088
+ } = useMemo(() => {
1089
+ const deferred = parseQueryKey(deferredQueryKey);
1090
+ return getQueryState(instance, {
1091
+ ...deferred,
1092
+ source
1093
+ });
1094
+ }, [instance, deferredQueryKey, source]);
971
1095
  if (getCurrent() === void 0) {
972
- const currentSignal = ref.current.signal;
1096
+ const currentSignal = ref.current.signal, deferred_0 = parseQueryKey(deferredQueryKey);
973
1097
  throw resolveQuery(instance, {
974
- ...deferred,
1098
+ ...deferred_0,
1099
+ source,
975
1100
  signal: currentSignal
976
1101
  });
977
1102
  }
@@ -1320,7 +1445,7 @@ function useUsers(options) {
1320
1445
  loadMore
1321
1446
  };
1322
1447
  }
1323
- var version = "2.4.0";
1448
+ var version = "2.6.0";
1324
1449
  function getEnv(key) {
1325
1450
  if (typeof import.meta < "u" && import.meta.env)
1326
1451
  return import.meta.env[key];
@@ -1337,10 +1462,12 @@ export {
1337
1462
  ResourceProvider,
1338
1463
  SDKProvider,
1339
1464
  SanityApp,
1465
+ renderSanityApp,
1340
1466
  useActiveReleases,
1341
1467
  useAgentGenerate,
1342
1468
  useAgentPatch,
1343
1469
  useAgentPrompt,
1470
+ useAgentResourceContext,
1344
1471
  useAgentTransform,
1345
1472
  useAgentTranslate,
1346
1473
  useApplyDocumentActions,