@sanity/sdk-react 2.0.0 → 2.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/sdk-react",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "private": false,
5
5
  "description": "Sanity SDK React toolkit for Content OS",
6
6
  "keywords": [
@@ -51,7 +51,7 @@
51
51
  "react-compiler-runtime": "19.1.0-rc.1",
52
52
  "react-error-boundary": "^5.0.0",
53
53
  "rxjs": "^7.8.2",
54
- "@sanity/sdk": "2.0.0"
54
+ "@sanity/sdk": "2.0.2"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@sanity/browserslist-config": "^1.0.5",
@@ -75,10 +75,10 @@
75
75
  "vite": "^6.3.4",
76
76
  "vitest": "^3.1.2",
77
77
  "@repo/config-eslint": "0.0.0",
78
- "@repo/package.bundle": "3.82.0",
79
78
  "@repo/config-test": "0.0.1",
80
- "@repo/package.config": "0.0.1",
81
- "@repo/tsconfig": "0.0.1"
79
+ "@repo/tsconfig": "0.0.1",
80
+ "@repo/package.bundle": "3.82.0",
81
+ "@repo/package.config": "0.0.1"
82
82
  },
83
83
  "peerDependencies": {
84
84
  "react": "^18.0.0 || ^19.0.0",
@@ -4,6 +4,7 @@
4
4
  export {AuthBoundary, type AuthBoundaryProps} from '../components/auth/AuthBoundary'
5
5
  export {SanityApp, type SanityAppProps} from '../components/SanityApp'
6
6
  export {SDKProvider, type SDKProviderProps} from '../components/SDKProvider'
7
+ export {ComlinkTokenRefreshProvider} from '../context/ComlinkTokenRefresh'
7
8
  export {ResourceProvider, type ResourceProviderProps} from '../context/ResourceProvider'
8
9
  export {useAuthState} from '../hooks/auth/useAuthState'
9
10
  export {useAuthToken} from '../hooks/auth/useAuthToken'
@@ -1,4 +1,4 @@
1
- import {AuthStateType} from '@sanity/sdk'
1
+ import {AuthStateType, type SanityConfig} from '@sanity/sdk'
2
2
  import {render, screen, waitFor} from '@testing-library/react'
3
3
  import React from 'react'
4
4
  import {type FallbackProps} from 'react-error-boundary'
@@ -8,6 +8,7 @@ import {ResourceProvider} from '../../context/ResourceProvider'
8
8
  import {useAuthState} from '../../hooks/auth/useAuthState'
9
9
  import {useLoginUrl} from '../../hooks/auth/useLoginUrl'
10
10
  import {useVerifyOrgProjects} from '../../hooks/auth/useVerifyOrgProjects'
11
+ import {useSanityInstance} from '../../hooks/context/useSanityInstance'
11
12
  import {AuthBoundary} from './AuthBoundary'
12
13
 
13
14
  // Mock hooks
@@ -22,6 +23,9 @@ vi.mock('../../hooks/auth/useHandleAuthCallback', () => ({
22
23
  vi.mock('../../hooks/auth/useLogOut', () => ({
23
24
  useLogOut: vi.fn(() => async () => {}),
24
25
  }))
26
+ vi.mock('../../hooks/context/useSanityInstance', () => ({
27
+ useSanityInstance: vi.fn(),
28
+ }))
25
29
 
26
30
  // Mock AuthError throwing scenario
27
31
  vi.mock('./AuthError', async (importOriginal) => {
@@ -105,8 +109,27 @@ describe('AuthBoundary', () => {
105
109
  const mockUseAuthState = vi.mocked(useAuthState)
106
110
  const mockUseLoginUrl = vi.mocked(useLoginUrl)
107
111
  const mockUseVerifyOrgProjects = vi.mocked(useVerifyOrgProjects)
112
+ const mockUseSanityInstance = vi.mocked(useSanityInstance)
108
113
  const testProjectIds = ['proj-test'] // Example project ID for tests
109
114
 
115
+ // Mock Sanity instance
116
+ const mockSanityInstance = {
117
+ instanceId: 'test-instance-id',
118
+ config: {
119
+ projectId: 'test-project',
120
+ dataset: 'test-dataset',
121
+ },
122
+ isDisposed: () => false,
123
+ dispose: () => {},
124
+ onDispose: () => () => {},
125
+ getParent: () => undefined,
126
+ createChild: (config: SanityConfig) => ({
127
+ ...mockSanityInstance,
128
+ config: {...mockSanityInstance.config, ...config},
129
+ }),
130
+ match: () => undefined,
131
+ }
132
+
110
133
  beforeEach(() => {
111
134
  vi.clearAllMocks()
112
135
  consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
@@ -116,6 +139,8 @@ describe('AuthBoundary', () => {
116
139
  mockUseLoginUrl.mockReturnValue('http://example.com/login')
117
140
  // Default mock for useVerifyOrgProjects - returns null (no error)
118
141
  mockUseVerifyOrgProjects.mockImplementation(() => null)
142
+ // Mock useSanityInstance to return our mock instance
143
+ mockUseSanityInstance.mockReturnValue(mockSanityInstance)
119
144
  })
120
145
 
121
146
  afterEach(() => {
@@ -145,9 +170,7 @@ describe('AuthBoundary', () => {
145
170
  isExchangingToken: false,
146
171
  })
147
172
  const {container} = render(
148
- <ResourceProvider fallback={null}>
149
- <AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>
150
- </ResourceProvider>,
173
+ <AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>,
151
174
  )
152
175
 
153
176
  // The callback screen renders null check that it renders nothing
@@ -161,11 +184,7 @@ describe('AuthBoundary', () => {
161
184
  currentUser: null,
162
185
  token: 'exampleToken',
163
186
  })
164
- render(
165
- <ResourceProvider fallback={null}>
166
- <AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>
167
- </ResourceProvider>,
168
- )
187
+ render(<AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>)
169
188
 
170
189
  expect(screen.getByText('Protected Content')).toBeInTheDocument()
171
190
  })
@@ -175,11 +194,7 @@ describe('AuthBoundary', () => {
175
194
  type: AuthStateType.ERROR,
176
195
  error: new Error('test error'),
177
196
  })
178
- render(
179
- <ResourceProvider fallback={null}>
180
- <AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>
181
- </ResourceProvider>,
182
- )
197
+ render(<AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>)
183
198
 
184
199
  // The AuthBoundary should throw an AuthError internally
185
200
  // and then display the LoginError component as the fallback.
@@ -192,11 +207,7 @@ describe('AuthBoundary', () => {
192
207
  })
193
208
 
194
209
  it('renders children when logged in and org verification passes', () => {
195
- render(
196
- <ResourceProvider fallback={null}>
197
- <AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>
198
- </ResourceProvider>,
199
- )
210
+ render(<AuthBoundary projectIds={testProjectIds}>Protected Content</AuthBoundary>)
200
211
  expect(screen.getByText('Protected Content')).toBeInTheDocument()
201
212
  })
202
213
 
@@ -2,6 +2,7 @@ import {AuthStateType} from '@sanity/sdk'
2
2
  import {useEffect, useMemo} from 'react'
3
3
  import {ErrorBoundary, type FallbackProps} from 'react-error-boundary'
4
4
 
5
+ import {ComlinkTokenRefreshProvider} from '../../context/ComlinkTokenRefresh'
5
6
  import {useAuthState} from '../../hooks/auth/useAuthState'
6
7
  import {useLoginUrl} from '../../hooks/auth/useLoginUrl'
7
8
  import {useVerifyOrgProjects} from '../../hooks/auth/useVerifyOrgProjects'
@@ -111,9 +112,11 @@ export function AuthBoundary({
111
112
  }, [LoginErrorComponent])
112
113
 
113
114
  return (
114
- <ErrorBoundary FallbackComponent={FallbackComponent}>
115
- <AuthSwitch {...props} />
116
- </ErrorBoundary>
115
+ <ComlinkTokenRefreshProvider>
116
+ <ErrorBoundary FallbackComponent={FallbackComponent}>
117
+ <AuthSwitch {...props} />
118
+ </ErrorBoundary>
119
+ </ComlinkTokenRefreshProvider>
117
120
  )
118
121
  }
119
122
 
@@ -19,7 +19,15 @@ export type LoginErrorProps = FallbackProps
19
19
  * @alpha
20
20
  */
21
21
  export function LoginError({error, resetErrorBoundary}: LoginErrorProps): React.ReactNode {
22
- if (!(error instanceof AuthError || error instanceof ConfigurationError)) throw error
22
+ if (
23
+ !(
24
+ error instanceof AuthError ||
25
+ error instanceof ConfigurationError ||
26
+ error instanceof ClientError
27
+ )
28
+ )
29
+ throw error
30
+
23
31
  const logout = useLogOut()
24
32
  const authState = useAuthState()
25
33
 
@@ -33,11 +41,11 @@ export function LoginError({error, resetErrorBoundary}: LoginErrorProps): React.
33
41
  }, [logout, resetErrorBoundary])
34
42
 
35
43
  useEffect(() => {
36
- if (authState.type === AuthStateType.ERROR && authState.error instanceof ClientError) {
37
- if (authState.error.statusCode === 401) {
44
+ if (error instanceof ClientError) {
45
+ if (error.statusCode === 401) {
38
46
  handleRetry()
39
- } else if (authState.error.statusCode === 404) {
40
- const errorMessage = authState.error.response.body.message || ''
47
+ } else if (error.statusCode === 404) {
48
+ const errorMessage = error.response.body.message || ''
41
49
  if (errorMessage.startsWith('Session with sid') && errorMessage.endsWith('not found')) {
42
50
  setAuthErrorMessage('The session ID is invalid or expired.')
43
51
  } else {
@@ -0,0 +1,221 @@
1
+ import {SDK_CHANNEL_NAME, SDK_NODE_NAME} from '@sanity/message-protocol'
2
+ import {AuthStateType, getIsInDashboardState, setAuthToken} from '@sanity/sdk'
3
+ import {act, render} from '@testing-library/react'
4
+ import {afterEach, beforeEach, describe, expect, it, type Mock, vi} from 'vitest'
5
+
6
+ import {useAuthState} from '../hooks/auth/useAuthState'
7
+ import {useWindowConnection} from '../hooks/comlink/useWindowConnection'
8
+ import {useSanityInstance} from '../hooks/context/useSanityInstance'
9
+ import {ComlinkTokenRefreshProvider} from './ComlinkTokenRefresh'
10
+
11
+ // Mocks
12
+ vi.mock('@sanity/sdk', async () => {
13
+ const actual = await vi.importActual('@sanity/sdk')
14
+ return {
15
+ ...actual,
16
+ getIsInDashboardState: vi.fn(() => ({getCurrent: vi.fn()})),
17
+ setAuthToken: vi.fn(),
18
+ }
19
+ })
20
+
21
+ vi.mock('../hooks/auth/useAuthState', () => ({
22
+ useAuthState: vi.fn(),
23
+ }))
24
+
25
+ vi.mock('../hooks/comlink/useWindowConnection', () => ({
26
+ useWindowConnection: vi.fn(),
27
+ }))
28
+
29
+ vi.mock('../hooks/context/useSanityInstance', () => ({
30
+ useSanityInstance: vi.fn(),
31
+ }))
32
+
33
+ // Use simpler mock typings
34
+ const mockGetIsInDashboardState = getIsInDashboardState as Mock
35
+ const mockSetAuthToken = setAuthToken as Mock
36
+ const mockUseAuthState = useAuthState as Mock
37
+ const mockUseWindowConnection = useWindowConnection as Mock
38
+ const mockUseSanityInstance = useSanityInstance as Mock
39
+
40
+ const mockFetch = vi.fn()
41
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ const mockSanityInstance: any = {projectId: 'test', dataset: 'test'}
43
+
44
+ describe('ComlinkTokenRefresh', () => {
45
+ beforeEach(() => {
46
+ vi.useFakeTimers()
47
+ mockGetIsInDashboardState.mockReturnValue({getCurrent: vi.fn(() => false)})
48
+ mockUseAuthState.mockReturnValue({type: AuthStateType.LOGGED_IN})
49
+ mockUseWindowConnection.mockReturnValue({fetch: mockFetch})
50
+ mockUseSanityInstance.mockReturnValue(mockSanityInstance)
51
+ })
52
+
53
+ afterEach(() => {
54
+ vi.clearAllMocks()
55
+ vi.useRealTimers()
56
+ })
57
+
58
+ describe('ComlinkTokenRefreshProvider', () => {
59
+ describe('when not in dashboard', () => {
60
+ beforeEach(() => {
61
+ mockGetIsInDashboardState.mockReturnValue({getCurrent: () => false})
62
+ })
63
+
64
+ it('should not request new token on 401 if not in dashboard', async () => {
65
+ mockUseAuthState.mockReturnValue({type: AuthStateType.LOGGED_IN})
66
+ const {rerender} = render(
67
+ <ComlinkTokenRefreshProvider>
68
+ <div>Test</div>
69
+ </ComlinkTokenRefreshProvider>,
70
+ )
71
+
72
+ mockUseAuthState.mockReturnValue({
73
+ type: AuthStateType.ERROR,
74
+ error: {statusCode: 401, message: 'Unauthorized'},
75
+ })
76
+ act(() => {
77
+ rerender(
78
+ <ComlinkTokenRefreshProvider>
79
+ <div>Test</div>
80
+ </ComlinkTokenRefreshProvider>,
81
+ )
82
+ })
83
+
84
+ await act(async () => {
85
+ await vi.advanceTimersByTimeAsync(100)
86
+ })
87
+ expect(mockFetch).not.toHaveBeenCalled()
88
+ })
89
+ })
90
+
91
+ describe('when in dashboard', () => {
92
+ beforeEach(() => {
93
+ mockGetIsInDashboardState.mockReturnValue({getCurrent: () => true})
94
+ })
95
+
96
+ it('should initialize useWindowConnection with correct parameters', () => {
97
+ render(
98
+ <ComlinkTokenRefreshProvider>
99
+ <div>Test</div>
100
+ </ComlinkTokenRefreshProvider>,
101
+ )
102
+
103
+ expect(mockUseWindowConnection).toHaveBeenCalledWith(
104
+ expect.objectContaining({
105
+ name: SDK_NODE_NAME,
106
+ connectTo: SDK_CHANNEL_NAME,
107
+ }),
108
+ )
109
+ })
110
+
111
+ it('should handle received token', async () => {
112
+ mockUseAuthState.mockReturnValue({
113
+ type: AuthStateType.ERROR,
114
+ error: {statusCode: 401, message: 'Unauthorized'},
115
+ })
116
+ mockFetch.mockResolvedValueOnce({token: 'new-token'})
117
+
118
+ render(
119
+ <ComlinkTokenRefreshProvider>
120
+ <div>Test</div>
121
+ </ComlinkTokenRefreshProvider>,
122
+ )
123
+
124
+ await act(async () => {
125
+ await vi.advanceTimersByTimeAsync(100)
126
+ })
127
+
128
+ expect(mockSetAuthToken).toHaveBeenCalledWith(mockSanityInstance, 'new-token')
129
+ expect(mockFetch).toHaveBeenCalledTimes(1)
130
+ })
131
+
132
+ it('should not set auth token if received token is null', async () => {
133
+ mockUseAuthState.mockReturnValue({
134
+ type: AuthStateType.ERROR,
135
+ error: {statusCode: 401, message: 'Unauthorized'},
136
+ })
137
+ mockFetch.mockResolvedValueOnce({token: null})
138
+
139
+ render(
140
+ <ComlinkTokenRefreshProvider>
141
+ <div>Test</div>
142
+ </ComlinkTokenRefreshProvider>,
143
+ )
144
+
145
+ await act(async () => {
146
+ await vi.advanceTimersByTimeAsync(100)
147
+ })
148
+
149
+ expect(mockSetAuthToken).not.toHaveBeenCalled()
150
+ })
151
+
152
+ it('should handle fetch errors gracefully', async () => {
153
+ mockUseAuthState.mockReturnValue({
154
+ type: AuthStateType.ERROR,
155
+ error: {statusCode: 401, message: 'Unauthorized'},
156
+ })
157
+ mockFetch.mockRejectedValueOnce(new Error('Fetch failed'))
158
+
159
+ render(
160
+ <ComlinkTokenRefreshProvider>
161
+ <div>Test</div>
162
+ </ComlinkTokenRefreshProvider>,
163
+ )
164
+
165
+ await act(async () => {
166
+ await vi.advanceTimersByTimeAsync(100)
167
+ })
168
+
169
+ expect(mockFetch).toHaveBeenCalledTimes(1)
170
+ })
171
+
172
+ describe('Automatic token refresh', () => {
173
+ it('should not request new token for non-401 errors', async () => {
174
+ mockUseAuthState.mockReturnValue({type: AuthStateType.LOGGED_IN})
175
+ const {rerender} = render(
176
+ <ComlinkTokenRefreshProvider>
177
+ <div>Test</div>
178
+ </ComlinkTokenRefreshProvider>,
179
+ )
180
+
181
+ mockUseAuthState.mockReturnValue({
182
+ type: AuthStateType.ERROR,
183
+ error: {statusCode: 500, message: 'Server Error'},
184
+ })
185
+ act(() => {
186
+ rerender(
187
+ <ComlinkTokenRefreshProvider>
188
+ <div>Test</div>
189
+ </ComlinkTokenRefreshProvider>,
190
+ )
191
+ })
192
+
193
+ await act(async () => {
194
+ await vi.advanceTimersByTimeAsync(100)
195
+ })
196
+ expect(mockFetch).not.toHaveBeenCalled()
197
+ })
198
+
199
+ it('should request new token on LOGGED_OUT state', async () => {
200
+ mockUseAuthState.mockReturnValue({type: AuthStateType.LOGGED_IN})
201
+ const {rerender} = render(
202
+ <ComlinkTokenRefreshProvider>
203
+ <div>Test</div>
204
+ </ComlinkTokenRefreshProvider>,
205
+ )
206
+
207
+ mockUseAuthState.mockReturnValue({type: AuthStateType.LOGGED_OUT})
208
+ act(() => {
209
+ rerender(
210
+ <ComlinkTokenRefreshProvider>
211
+ <div>Test</div>
212
+ </ComlinkTokenRefreshProvider>,
213
+ )
214
+ })
215
+
216
+ expect(mockFetch).toHaveBeenCalledWith('dashboard/v1/auth/tokens/create')
217
+ })
218
+ })
219
+ })
220
+ })
221
+ })
@@ -0,0 +1,140 @@
1
+ import {type ClientError} from '@sanity/client'
2
+ import {SDK_CHANNEL_NAME, SDK_NODE_NAME} from '@sanity/message-protocol'
3
+ import {
4
+ AuthStateType,
5
+ type FrameMessage,
6
+ getIsInDashboardState,
7
+ type NewTokenResponseMessage,
8
+ type RequestNewTokenMessage,
9
+ setAuthToken,
10
+ type WindowMessage,
11
+ } from '@sanity/sdk'
12
+ import React, {type PropsWithChildren, useCallback, useEffect, useMemo, useRef} from 'react'
13
+
14
+ import {useAuthState} from '../hooks/auth/useAuthState'
15
+ import {useWindowConnection} from '../hooks/comlink/useWindowConnection'
16
+ import {useSanityInstance} from '../hooks/context/useSanityInstance'
17
+
18
+ // Define specific message types extending the base types for clarity
19
+ type SdkParentComlinkMessage = NewTokenResponseMessage | WindowMessage // Messages received by SDK
20
+ type SdkChildComlinkMessage = RequestNewTokenMessage | FrameMessage // Messages sent by SDK
21
+
22
+ const DEFAULT_RESPONSE_TIMEOUT = 10000 // 10 seconds
23
+
24
+ /**
25
+ * Component that handles token refresh in dashboard mode
26
+ */
27
+ function DashboardTokenRefresh({children}: PropsWithChildren) {
28
+ const instance = useSanityInstance()
29
+ const isTokenRefreshInProgress = useRef(false)
30
+ const timeoutRef = useRef<NodeJS.Timeout | null>(null)
31
+ const processed401ErrorRef = useRef<unknown | null>(null)
32
+ const authState = useAuthState()
33
+
34
+ const clearRefreshTimeout = useCallback(() => {
35
+ if (timeoutRef.current) {
36
+ clearTimeout(timeoutRef.current)
37
+ timeoutRef.current = null
38
+ }
39
+ }, [])
40
+
41
+ const windowConnection = useWindowConnection<SdkParentComlinkMessage, SdkChildComlinkMessage>({
42
+ name: SDK_NODE_NAME,
43
+ connectTo: SDK_CHANNEL_NAME,
44
+ })
45
+
46
+ const requestNewToken = useCallback(async () => {
47
+ if (isTokenRefreshInProgress.current) {
48
+ return
49
+ }
50
+
51
+ isTokenRefreshInProgress.current = true
52
+ clearRefreshTimeout()
53
+
54
+ timeoutRef.current = setTimeout(() => {
55
+ if (isTokenRefreshInProgress.current) {
56
+ isTokenRefreshInProgress.current = false
57
+ }
58
+ timeoutRef.current = null
59
+ }, DEFAULT_RESPONSE_TIMEOUT)
60
+
61
+ try {
62
+ const res = await windowConnection.fetch<{token: string | null; error?: string}>(
63
+ 'dashboard/v1/auth/tokens/create',
64
+ )
65
+ clearRefreshTimeout()
66
+
67
+ if (res.token) {
68
+ setAuthToken(instance, res.token)
69
+
70
+ // Remove the unauthorized error from the error container
71
+ const errorContainer = document.getElementById('__sanityError')
72
+ if (errorContainer) {
73
+ const hasUnauthorizedError = Array.from(errorContainer.getElementsByTagName('div')).some(
74
+ (div) =>
75
+ div.textContent?.includes(
76
+ 'Uncaught error: Unauthorized - A valid session is required for this endpoint',
77
+ ),
78
+ )
79
+
80
+ if (hasUnauthorizedError) {
81
+ errorContainer.remove()
82
+ }
83
+ }
84
+ }
85
+ isTokenRefreshInProgress.current = false
86
+ } catch {
87
+ isTokenRefreshInProgress.current = false
88
+ clearRefreshTimeout()
89
+ }
90
+ }, [windowConnection, clearRefreshTimeout, instance])
91
+
92
+ useEffect(() => {
93
+ return () => {
94
+ clearRefreshTimeout()
95
+ }
96
+ }, [clearRefreshTimeout])
97
+
98
+ useEffect(() => {
99
+ const has401Error =
100
+ authState.type === AuthStateType.ERROR &&
101
+ authState.error &&
102
+ (authState.error as ClientError)?.statusCode === 401 &&
103
+ !isTokenRefreshInProgress.current &&
104
+ processed401ErrorRef.current !== authState.error
105
+
106
+ const isLoggedOut =
107
+ authState.type === AuthStateType.LOGGED_OUT && !isTokenRefreshInProgress.current
108
+
109
+ if (has401Error || isLoggedOut) {
110
+ processed401ErrorRef.current =
111
+ authState.type === AuthStateType.ERROR ? authState.error : undefined
112
+ requestNewToken()
113
+ } else if (
114
+ authState.type !== AuthStateType.ERROR ||
115
+ processed401ErrorRef.current !==
116
+ (authState.type === AuthStateType.ERROR ? authState.error : undefined)
117
+ ) {
118
+ processed401ErrorRef.current = null
119
+ }
120
+ }, [authState, requestNewToken])
121
+
122
+ return children
123
+ }
124
+
125
+ /**
126
+ * This provider is used to provide the Comlink token refresh feature.
127
+ * It is used to automatically request a new token on 401 error if enabled.
128
+ * @public
129
+ */
130
+ export const ComlinkTokenRefreshProvider: React.FC<PropsWithChildren> = ({children}) => {
131
+ const instance = useSanityInstance()
132
+ const isInDashboard = useMemo(() => getIsInDashboardState(instance).getCurrent(), [instance])
133
+
134
+ if (isInDashboard) {
135
+ return <DashboardTokenRefresh>{children}</DashboardTokenRefresh>
136
+ }
137
+
138
+ // If we're not in the dashboard, we don't need to do anything
139
+ return children
140
+ }
@@ -21,23 +21,31 @@ export interface useDocumentPreviewOptions extends DocumentHandle {
21
21
  * @category Types
22
22
  */
23
23
  export interface useDocumentPreviewResults {
24
- /** The results of resolving the document’s preview values */
24
+ /** The results of inferring the document’s preview values */
25
25
  data: PreviewValue
26
- /** True when preview values are being refreshed */
26
+ /** True when inferred preview values are being refreshed */
27
27
  isPending: boolean
28
28
  }
29
29
 
30
30
  /**
31
31
  * @public
32
32
  *
33
- * Returns the preview values of a document (specified via a `DocumentHandle`),
33
+ * Attempts to infer preview values of a document (specified via a `DocumentHandle`),
34
34
  * including the document’s `title`, `subtitle`, `media`, and `status`. These values are live and will update in realtime.
35
35
  * To reduce unnecessary network requests for resolving the preview values, an optional `ref` can be passed to the hook so that preview
36
36
  * resolution will only occur if the `ref` is intersecting the current viewport.
37
37
  *
38
+ * See remarks below for futher information.
39
+ *
40
+ * @remarks
41
+ * Values returned by this hook may not be as expected. It is currently unable to read preview values as defined in your schema;
42
+ * instead, it attempts to infer these preview values by checking against a basic set of potential fields on your document.
43
+ * We are anticipating being able to significantly improve this hook’s functionality and output in a future release.
44
+ * For now, we recommend using {@link useDocumentProjection} for rendering individual document fields (or projections of those fields).
45
+ *
38
46
  * @category Documents
39
- * @param options - The document handle for the document you want to resolve preview values for, and an optional ref
40
- * @returns The preview values for the given document and a boolean to indicate whether the resolution is pending
47
+ * @param options - The document handle for the document you want to infer preview values for, and an optional ref
48
+ * @returns The inferred values for the given document and a boolean to indicate whether the resolution is pending
41
49
  *
42
50
  * @example Combining with useDocuments to render a collection of document previews
43
51
  * ```