@sanity/sdk-react 2.3.1 → 2.4.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/dist/index.d.ts CHANGED
@@ -1,4 +1,11 @@
1
1
  import {ActionsResult} from '@sanity/sdk'
2
+ import {AgentGenerateOptions} from '@sanity/sdk'
3
+ import {AgentPatchOptions} from '@sanity/sdk'
4
+ import {AgentPatchResult} from '@sanity/sdk'
5
+ import {AgentPromptOptions} from '@sanity/sdk'
6
+ import {AgentPromptResult} from '@sanity/sdk'
7
+ import {AgentTransformOptions} from '@sanity/sdk'
8
+ import {AgentTranslateOptions} from '@sanity/sdk'
2
9
  import {ApplyDocumentActionsOptions} from '@sanity/sdk'
3
10
  import {AuthState} from '@sanity/sdk'
4
11
  import {CanvasResource} from '@sanity/message-protocol'
@@ -11,6 +18,7 @@ import {DocumentEvent} from '@sanity/sdk'
11
18
  import {DocumentHandle} from '@sanity/sdk'
12
19
  import {DocumentOptions} from '@sanity/sdk'
13
20
  import {DocumentPermissionsResult} from '@sanity/sdk'
21
+ import {DocumentSource} from '@sanity/sdk'
14
22
  import {FallbackProps} from 'react-error-boundary'
15
23
  import {FavoriteStatusResponse} from '@sanity/sdk'
16
24
  import {FrameMessage} from '@sanity/sdk'
@@ -142,6 +150,26 @@ declare interface DashboardResource {
142
150
 
143
151
  export {DatasetsResponse}
144
152
 
153
+ /**
154
+ * Return type for the useDispatchIntent hook
155
+ * @beta
156
+ */
157
+ declare interface DispatchIntent {
158
+ dispatchIntent: () => void
159
+ }
160
+
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
+
145
173
  declare interface DocumentInteractionHistory {
146
174
  recordEvent: (eventType: 'viewed' | 'edited' | 'created' | 'deleted') => void
147
175
  }
@@ -156,8 +184,8 @@ export declare interface DocumentsOptions<
156
184
  TDocumentType extends string = string,
157
185
  TDataset extends string = string,
158
186
  TProjectId extends string = string,
159
- > extends DatasetHandle<TDataset, TProjectId>,
160
- Pick<QueryOptions, 'perspective' | 'params'> {
187
+ >
188
+ extends DatasetHandle<TDataset, TProjectId>, Pick<QueryOptions, 'perspective' | 'params'> {
161
189
  /**
162
190
  * Filter documents by their `_type`. Can be a single type or an array of types.
163
191
  */
@@ -269,6 +297,12 @@ export declare interface NavigateToStudioResult {
269
297
  navigateToStudioDocument: () => void
270
298
  }
271
299
 
300
+ declare interface Observer<T> {
301
+ next?: (value: T) => void
302
+ error?: (err: unknown) => void
303
+ complete?: () => void
304
+ }
305
+
272
306
  /**
273
307
  * Configuration options for the usePaginatedDocuments hook
274
308
  *
@@ -569,6 +603,19 @@ declare interface StudioWorkspacesResult {
569
603
  error: string | null
570
604
  }
571
605
 
606
+ declare interface Subscribable<T> {
607
+ subscribe(observer: Observer<T>): Subscription
608
+ subscribe(
609
+ next: (value: T) => void,
610
+ error?: (err: unknown) => void,
611
+ complete?: () => void,
612
+ ): Subscription
613
+ }
614
+
615
+ declare interface Subscription {
616
+ unsubscribe(): void
617
+ }
618
+
572
619
  declare type Updater<TValue> = TValue | ((currentValue: TValue) => TValue)
573
620
 
574
621
  /**
@@ -595,6 +642,70 @@ declare type UseActiveReleases = {
595
642
  */
596
643
  export declare const useActiveReleases: UseActiveReleases
597
644
 
645
+ /**
646
+ * @alpha
647
+ * Generates content for a document (or specific fields) via Sanity Agent Actions.
648
+ * - Uses instruction templates with `$variables` and supports `instructionParams` (constants, fields, documents, GROQ queries).
649
+ * - Can target specific paths/fields; supports image generation when targeting image fields.
650
+ * - Supports optional `temperature`, `async`, `noWrite`, and `conditionalPaths`.
651
+ *
652
+ * Returns a stable callback that triggers the action and yields a Subscribable stream.
653
+ */
654
+ export declare const useAgentGenerate: () => (
655
+ options: AgentGenerateOptions,
656
+ ) => Subscribable<unknown>
657
+
658
+ /**
659
+ * @alpha
660
+ * Schema-aware patching with Sanity Agent Actions.
661
+ * - Validates provided paths/values against the document schema and merges object values safely.
662
+ * - Prevents duplicate keys and supports array appends (including after a specific keyed item).
663
+ * - Accepts `documentId` or `targetDocument` (mutually exclusive).
664
+ * - Optional `async`, `noWrite`, `conditionalPaths`.
665
+ *
666
+ * Returns a stable callback that triggers the action and resolves a Promise with the patch result.
667
+ */
668
+ export declare const useAgentPatch: () => (options: AgentPatchOptions) => Promise<AgentPatchResult>
669
+
670
+ /**
671
+ * @alpha
672
+ * Prompts the LLM using the same instruction template format as other actions.
673
+ * - `format`: 'string' or 'json' (instruction must contain the word "json" for JSON responses).
674
+ * - Optional `temperature`.
675
+ *
676
+ * Returns a stable callback that triggers the action and resolves a Promise with the prompt result.
677
+ */
678
+ export declare const useAgentPrompt: () => (
679
+ options: AgentPromptOptions,
680
+ ) => Promise<AgentPromptResult>
681
+
682
+ /**
683
+ * @alpha
684
+ * Transforms an existing document or selected fields using Sanity Agent Actions.
685
+ * - Accepts `instruction` and `instructionParams` (constants, fields, documents, GROQ queries).
686
+ * - Can write to the same or a different `targetDocument` (create/edit), and target specific paths.
687
+ * - Supports per-path image transform instructions and image description operations.
688
+ * - Optional `temperature`, `async`, `noWrite`, `conditionalPaths`.
689
+ *
690
+ * Returns a stable callback that triggers the action and yields a Subscribable stream.
691
+ */
692
+ export declare const useAgentTransform: () => (
693
+ options: AgentTransformOptions,
694
+ ) => Subscribable<unknown>
695
+
696
+ /**
697
+ * @alpha
698
+ * Translates documents or fields using Sanity Agent Actions.
699
+ * - Configure `fromLanguage`/`toLanguage`, optional `styleGuide`, and `protectedPhrases`.
700
+ * - Can write into a different `targetDocument`, and/or store language in a field.
701
+ * - Optional `temperature`, `async`, `noWrite`, `conditionalPaths`.
702
+ *
703
+ * Returns a stable callback that triggers the action and yields a Subscribable stream.
704
+ */
705
+ export declare const useAgentTranslate: () => (
706
+ options: AgentTranslateOptions,
707
+ ) => Subscribable<unknown>
708
+
598
709
  /**
599
710
  * @public
600
711
  */
@@ -702,6 +813,37 @@ declare interface UseApplyDocumentActions {
702
813
  * )
703
814
  * }
704
815
  * ```
816
+ *
817
+ * @example Create a document with initial field values
818
+ * ```tsx
819
+ * import {
820
+ * createDocument,
821
+ * createDocumentHandle,
822
+ * useApplyDocumentActions
823
+ * } from '@sanity/sdk-react'
824
+ *
825
+ * function CreateArticleButton() {
826
+ * const apply = useApplyDocumentActions()
827
+ *
828
+ * const handleCreateArticle = () => {
829
+ * const newDocHandle = createDocumentHandle({
830
+ * documentId: crypto.randomUUID(),
831
+ * documentType: 'article'
832
+ * })
833
+ *
834
+ * // Create document with initial values in one action
835
+ * apply(
836
+ * createDocument(newDocHandle, {
837
+ * title: 'New Article',
838
+ * author: 'John Doe',
839
+ * publishedAt: new Date().toISOString(),
840
+ * })
841
+ * )
842
+ * }
843
+ *
844
+ * return <button onClick={handleCreateArticle}>Create Article</button>
845
+ * }
846
+ * ```
705
847
  */
706
848
  export declare const useApplyDocumentActions: UseApplyDocumentActions
707
849
 
@@ -762,7 +904,7 @@ export declare const useAuthToken: () => string | null
762
904
  * @public
763
905
  * @function
764
906
  */
765
- export declare const useClient: (x: ClientOptions) => SanityClient
907
+ export declare const useClient: (options: ClientOptions) => SanityClient
766
908
 
767
909
  declare type UseCurrentUser = {
768
910
  /**
@@ -894,6 +1036,70 @@ declare type UseDatasets = {
894
1036
  */
895
1037
  export declare const useDatasets: UseDatasets
896
1038
 
1039
+ /**
1040
+ * @beta
1041
+ *
1042
+ * A hook for dispatching intent messages to the Dashboard with a document handle.
1043
+ * This allows applications to signal their intent to pass the referenced document to other applications that have registered the ability to perform specific actions on that document.
1044
+ *
1045
+ * @param params - Object containing:
1046
+ * - `action` - Action to perform (currently only 'edit' is supported). Will prompt a picker if multiple handlers are available.
1047
+ * - `intentId` - Specific ID of the intent to dispatch. Either `action` or `intentId` is required.
1048
+ * - `documentHandle` - The document handle containing document ID, type, and either:
1049
+ * - `projectId` and `dataset` for traditional dataset sources, like `{documentId: '123', documentType: 'book', projectId: 'abc123', dataset: 'production'}`
1050
+ * - `source` for media library, canvas, or dataset sources, like `{documentId: '123', documentType: 'sanity.asset', source: mediaLibrarySource('ml123')}` or `{documentId: '123', documentType: 'sanity.canvas.document', source: canvasSource('canvas123')}`
1051
+ * - `paremeters` - Optional parameters to include in the dispatch; will be passed to the resolved intent handler
1052
+ * @returns An object containing:
1053
+ * - `dispatchIntent` - Function to dispatch the intent message
1054
+ *
1055
+ * @example
1056
+ * ```tsx
1057
+ * import {useDispatchIntent} from '@sanity/sdk-react'
1058
+ * import {Button} from '@sanity/ui'
1059
+ * import {Suspense} from 'react'
1060
+ *
1061
+ * function DispatchIntentButton({documentId, documentType, projectId, dataset}) {
1062
+ * const {dispatchIntent} = useDispatchIntent({
1063
+ * action: 'edit',
1064
+ * documentHandle: {documentId, documentType, projectId, dataset},
1065
+ * })
1066
+ *
1067
+ * return (
1068
+ * <Button
1069
+ * onClick={() => dispatchIntent()}
1070
+ * text="Dispatch Intent"
1071
+ * />
1072
+ * )
1073
+ * }
1074
+ *
1075
+ * // Wrap the component with Suspense since the hook may suspend
1076
+ * function MyDocumentAction({documentId, documentType, projectId, dataset}) {
1077
+ * return (
1078
+ * <Suspense fallback={<Button text="Loading..." disabled />}>
1079
+ * <DispatchIntentButton
1080
+ * documentId={documentId}
1081
+ * documentType={documentType}
1082
+ * projectId={projectId}
1083
+ * dataset={dataset}
1084
+ * />
1085
+ * </Suspense>
1086
+ * )
1087
+ * }
1088
+ * ```
1089
+ */
1090
+ export declare function useDispatchIntent(params: UseDispatchIntentParams): DispatchIntent
1091
+
1092
+ /**
1093
+ * Parameters for the useDispatchIntent hook
1094
+ * @beta
1095
+ */
1096
+ declare interface UseDispatchIntentParams {
1097
+ action?: 'edit'
1098
+ intentId?: string
1099
+ documentHandle: DocumentHandleWithSource
1100
+ parameters?: Record<string, unknown>
1101
+ }
1102
+
897
1103
  declare interface UseDocument {
898
1104
  /** @internal */
899
1105
  <TDocumentType extends string, TDataset extends string, TProjectId extends string = string>(
@@ -2499,7 +2705,7 @@ export declare function useUser(options: GetUserOptions): UserResult
2499
2705
  * <address>{user.profile.email}</address>
2500
2706
  * </figure>
2501
2707
  * ))}
2502
- * {hasMore && <button onClick={loadMore}>{isPending ? 'Loading...' : 'Load More'</button>}
2708
+ * {hasMore && <button onClick={loadMore}>{isPending ? 'Loading...' : 'Load More'}</button>}
2503
2709
  * </div>
2504
2710
  * )
2505
2711
  * ```
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
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, getCorsErrorProjectId, createSanityInstance, 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, 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, useMemo, useCallback, useInsertionEffect, useTransition } from "react";
6
+ import { createContext, useContext, useSyncExternalStore, useRef, useEffect, useState, Suspense, 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";
@@ -297,13 +297,13 @@ function _temp$5(replacementLocation) {
297
297
  }
298
298
  const useLogOut = createCallbackHook(logout);
299
299
  function LoginError(t0) {
300
- const $ = c(17), {
300
+ const $ = c(18), {
301
301
  error,
302
302
  resetErrorBoundary
303
303
  } = t0;
304
304
  if (!(error instanceof AuthError || error instanceof ConfigurationError || error instanceof ClientError))
305
305
  throw error;
306
- const logout2 = useLogOut(), authState = useAuthState(), [authErrorMessage, setAuthErrorMessage] = useState("Please try again or contact support if the problem persists.");
306
+ const logout2 = useLogOut(), authState = useAuthState(), [authErrorMessage, setAuthErrorMessage] = useState("Please try again or contact support if the problem persists."), [showRetryCta, setShowRetryCta] = useState(!0);
307
307
  let t1;
308
308
  $[0] !== logout2 || $[1] !== resetErrorBoundary ? (t1 = async () => {
309
309
  await logout2(), resetErrorBoundary();
@@ -313,24 +313,28 @@ function LoginError(t0) {
313
313
  $[3] !== authState.type || $[4] !== error || $[5] !== handleRetry ? (t2 = () => {
314
314
  if (error instanceof ClientError) {
315
315
  if (error.statusCode === 401)
316
- handleRetry();
316
+ if (isProjectUserNotFoundClientError(error)) {
317
+ const description = getClientErrorApiDescription(error);
318
+ description && setAuthErrorMessage(description), setShowRetryCta(!1);
319
+ } else
320
+ setShowRetryCta(!0), handleRetry();
317
321
  else if (error.statusCode === 404) {
318
- const errorMessage = error.response.body.message || "";
319
- errorMessage.startsWith("Session with sid") && errorMessage.endsWith("not found") ? setAuthErrorMessage("The session ID is invalid or expired.") : setAuthErrorMessage("The login link is invalid or expired. Please try again.");
322
+ const errorMessage = getClientErrorApiBody(error)?.message || "";
323
+ errorMessage.startsWith("Session with sid") && errorMessage.endsWith("not found") ? setAuthErrorMessage("The session ID is invalid or expired.") : setAuthErrorMessage("The login link is invalid or expired. Please try again."), setShowRetryCta(!0);
320
324
  }
321
325
  }
322
- authState.type !== AuthStateType.ERROR && error instanceof ConfigurationError && setAuthErrorMessage(error.message);
326
+ authState.type !== AuthStateType.ERROR && error instanceof ConfigurationError && (setAuthErrorMessage(error.message), setShowRetryCta(!0));
323
327
  }, $[3] = authState.type, $[4] = error, $[5] = handleRetry, $[6] = t2) : t2 = $[6];
324
328
  let t3;
325
329
  $[7] !== authState || $[8] !== error || $[9] !== handleRetry ? (t3 = [authState, handleRetry, error], $[7] = authState, $[8] = error, $[9] = handleRetry, $[10] = t3) : t3 = $[10], useEffect(t2, t3);
326
330
  const t4 = error instanceof AuthError ? "Authentication Error" : "Configuration Error";
327
331
  let t5;
328
- $[11] !== handleRetry ? (t5 = {
332
+ $[11] !== handleRetry || $[12] !== showRetryCta ? (t5 = showRetryCta ? {
329
333
  text: "Retry",
330
334
  onClick: handleRetry
331
- }, $[11] = handleRetry, $[12] = t5) : t5 = $[12];
335
+ } : void 0, $[11] = handleRetry, $[12] = showRetryCta, $[13] = t5) : t5 = $[13];
332
336
  let t6;
333
- return $[13] !== authErrorMessage || $[14] !== t4 || $[15] !== t5 ? (t6 = /* @__PURE__ */ jsx(Error$1, { heading: t4, description: authErrorMessage, cta: t5 }), $[13] = authErrorMessage, $[14] = t4, $[15] = t5, $[16] = t6) : t6 = $[16], t6;
337
+ return $[14] !== authErrorMessage || $[15] !== t4 || $[16] !== t5 ? (t6 = /* @__PURE__ */ jsx(Error$1, { heading: t4, description: authErrorMessage, cta: t5 }), $[14] = authErrorMessage, $[15] = t4, $[16] = t5, $[17] = t6) : t6 = $[17], t6;
334
338
  }
335
339
  if (isInIframe() && !document.querySelector("[data-sanity-core]")) {
336
340
  const parsedUrl = new URL(window.location.href), mode = new URLSearchParams(parsedUrl.hash.slice(1)).get("mode"), script = document.createElement("script");
@@ -449,7 +453,15 @@ function SanityApp(t0) {
449
453
  function _temp$4() {
450
454
  console.warn("Redirecting to core", REDIRECT_URL), window.location.replace(REDIRECT_URL);
451
455
  }
452
- const useAuthToken = createStateSourceHook(getTokenState), useCurrentUser = createStateSourceHook(getCurrentUserState);
456
+ const useAgentGenerate = createCallbackHook(agentGenerate), useAgentTransform = createCallbackHook(agentTransform), useAgentTranslate = createCallbackHook(agentTranslate);
457
+ function promptAdapter(instance, options) {
458
+ return firstValueFrom(agentPrompt(instance, options));
459
+ }
460
+ const useAgentPrompt = createCallbackHook(promptAdapter);
461
+ function patchAdapter(instance, options) {
462
+ return firstValueFrom(agentPatch(instance, options));
463
+ }
464
+ const useAgentPatch = createCallbackHook(patchAdapter), useAuthToken = createStateSourceHook(getTokenState), useCurrentUser = createStateSourceHook(getCurrentUserState);
453
465
  function useDashboardOrganizationId() {
454
466
  const $ = c(2), instance = useSanityInstance();
455
467
  let t0, t1;
@@ -461,8 +473,12 @@ function useDashboardOrganizationId() {
461
473
  return useSyncExternalStore(subscribe, getCurrent);
462
474
  }
463
475
  const useClient = createStateSourceHook({
464
- getState: getClientState,
465
- getConfig: identity
476
+ getState: (instance, options) => {
477
+ if (!options || typeof options != "object")
478
+ throw new Error('useClient() requires a configuration object with at least an "apiVersion" property. Example: useClient({ apiVersion: "2024-11-12" })');
479
+ return getClientState(instance, options);
480
+ },
481
+ getConfig: (options) => options
466
482
  });
467
483
  function useFrameConnection(options) {
468
484
  const $ = c(12), {
@@ -526,6 +542,84 @@ function useDashboardNavigate(navigateFn) {
526
542
  }
527
543
  }, $[0] = navigateFn, $[1] = t0) : t0 = $[1], useWindowConnection(t0);
528
544
  }
545
+ const SOURCE_ID = "__sanity_internal_sourceId", isDocumentHandleWithSource = (documentHandle) => "source" in documentHandle;
546
+ function getResourceIdFromDocumentHandle(documentHandle) {
547
+ let source;
548
+ const {
549
+ projectId,
550
+ dataset
551
+ } = 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 {
564
+ id: resourceId,
565
+ type: resourceType
566
+ };
567
+ }
568
+ function useDispatchIntent(params) {
569
+ const {
570
+ action,
571
+ intentId,
572
+ documentHandle,
573
+ parameters
574
+ } = params, {
575
+ sendMessage
576
+ } = useWindowConnection({
577
+ name: SDK_NODE_NAME,
578
+ connectTo: SDK_CHANNEL_NAME
579
+ });
580
+ return {
581
+ dispatchIntent: useCallback(() => {
582
+ try {
583
+ if (!action && !intentId)
584
+ throw new Error("useDispatchIntent: Either `action` or `intentId` must be provided.");
585
+ const {
586
+ projectId,
587
+ dataset,
588
+ source
589
+ } = 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 = {
593
+ type: "dashboard/v1/events/intents/dispatch-intent",
594
+ data: {
595
+ ...action && !intentId ? {
596
+ action
597
+ } : {},
598
+ ...intentId ? {
599
+ intentId
600
+ } : {},
601
+ document: {
602
+ id: documentHandle.documentId,
603
+ type: documentHandle.documentType
604
+ },
605
+ resource: {
606
+ id: resource.id,
607
+ ...resource.type ? {
608
+ type: resource.type
609
+ } : {}
610
+ },
611
+ ...parameters && Object.keys(parameters).length > 0 ? {
612
+ parameters
613
+ } : {}
614
+ }
615
+ };
616
+ sendMessage(message.type, message.data);
617
+ } catch (error) {
618
+ throw console.error("Failed to dispatch intent:", error), error;
619
+ }
620
+ }, [action, intentId, documentHandle, parameters, sendMessage])
621
+ };
622
+ }
529
623
  function useManageFavorite({
530
624
  documentId,
531
625
  documentType,
@@ -1125,35 +1219,27 @@ function useDocumentPreview(t0) {
1125
1219
  return currentState;
1126
1220
  }, $[9] = docHandle, $[10] = instance, $[11] = stateSource, $[12] = t3) : t3 = $[12], useSyncExternalStore(subscribe, t3);
1127
1221
  }
1128
- function useDocumentProjection(t0) {
1129
- const $ = c(12);
1130
- let docHandle, projection, ref;
1131
- $[0] !== t0 ? ({
1132
- ref,
1133
- projection,
1134
- ...docHandle
1135
- } = t0, $[0] = t0, $[1] = docHandle, $[2] = projection, $[3] = ref) : (docHandle = $[1], projection = $[2], ref = $[3]);
1136
- const instance = useSanityInstance(docHandle);
1137
- let stateSource, t1;
1138
- if ($[4] !== docHandle || $[5] !== instance || $[6] !== projection ? (stateSource = getProjectionState(instance, {
1222
+ function useDocumentProjection({
1223
+ ref,
1224
+ projection,
1225
+ ...docHandle
1226
+ }) {
1227
+ const instance = useSanityInstance(docHandle), normalizedProjection = useMemo(() => projection.trim(), [projection]), stateSource = useMemo(() => getProjectionState(instance, {
1139
1228
  ...docHandle,
1140
- projection
1141
- }), t1 = stateSource.getCurrent()?.data, $[4] = docHandle, $[5] = instance, $[6] = projection, $[7] = stateSource, $[8] = t1) : (stateSource = $[7], t1 = $[8]), t1 === null)
1229
+ projection: normalizedProjection
1230
+ }), [instance, normalizedProjection, docHandle]);
1231
+ if (stateSource.getCurrent()?.data === null)
1142
1232
  throw resolveProjection(instance, {
1143
1233
  ...docHandle,
1144
- projection
1234
+ projection: normalizedProjection
1145
1235
  });
1146
- let t2;
1147
- return $[9] !== ref || $[10] !== stateSource ? (t2 = (onStoreChanged) => {
1236
+ const subscribe = useCallback((onStoreChanged) => {
1148
1237
  const subscription = new Observable((observer) => {
1149
1238
  if (typeof IntersectionObserver > "u" || typeof HTMLElement > "u") {
1150
1239
  observer.next(!0);
1151
1240
  return;
1152
1241
  }
1153
- const intersectionObserver = new IntersectionObserver((t3) => {
1154
- const [entry] = t3;
1155
- return observer.next(entry.isIntersecting);
1156
- }, {
1242
+ const intersectionObserver = new IntersectionObserver(([entry]) => observer.next(entry.isIntersecting), {
1157
1243
  rootMargin: "0px",
1158
1244
  threshold: 0
1159
1245
  });
@@ -1162,7 +1248,8 @@ function useDocumentProjection(t0) {
1162
1248
  next: onStoreChanged
1163
1249
  });
1164
1250
  return () => subscription.unsubscribe();
1165
- }, $[9] = ref, $[10] = stateSource, $[11] = t2) : t2 = $[11], useSyncExternalStore(t2, stateSource.getCurrent);
1251
+ }, [stateSource, ref]);
1252
+ return useSyncExternalStore(subscribe, stateSource.getCurrent);
1166
1253
  }
1167
1254
  const useProject = createStateSourceHook({
1168
1255
  // remove `undefined` since we're suspending when that is the case
@@ -1233,7 +1320,7 @@ function useUsers(options) {
1233
1320
  loadMore
1234
1321
  };
1235
1322
  }
1236
- var version = "2.3.1";
1323
+ var version = "2.4.0";
1237
1324
  function getEnv(key) {
1238
1325
  if (typeof import.meta < "u" && import.meta.env)
1239
1326
  return import.meta.env[key];
@@ -1251,6 +1338,11 @@ export {
1251
1338
  SDKProvider,
1252
1339
  SanityApp,
1253
1340
  useActiveReleases,
1341
+ useAgentGenerate,
1342
+ useAgentPatch,
1343
+ useAgentPrompt,
1344
+ useAgentTransform,
1345
+ useAgentTranslate,
1254
1346
  useApplyDocumentActions,
1255
1347
  useAuthState,
1256
1348
  useAuthToken,
@@ -1259,6 +1351,7 @@ export {
1259
1351
  useDashboardNavigate,
1260
1352
  useDashboardOrganizationId,
1261
1353
  useDatasets,
1354
+ useDispatchIntent,
1262
1355
  useDocument,
1263
1356
  useDocumentEvent,
1264
1357
  useDocumentPermissions,