@sanity/sdk-react 3.0.0-rc.0 → 3.0.0-rc.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/README.md +103 -155
- package/dist/index.d.ts +2488 -2019
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4435 -1529
- package/dist/index.js.map +1 -1
- package/package.json +55 -59
- package/src/_exports/index.ts +2 -4
- package/src/_exports/sdk-react.ts +30 -18
- package/src/components/SDKProvider.test.tsx +173 -32
- package/src/components/SDKProvider.tsx +87 -28
- package/src/components/SanityApp.test.tsx +68 -12
- package/src/components/SanityApp.tsx +93 -87
- package/src/components/auth/AuthBoundary.recovery.test.tsx +86 -0
- package/src/components/auth/AuthBoundary.test.tsx +7 -7
- package/src/components/auth/AuthBoundary.tsx +29 -6
- package/src/components/auth/DashboardAccessRequest.tsx +37 -0
- package/src/components/auth/LoginError.test.tsx +191 -5
- package/src/components/auth/LoginError.tsx +104 -61
- package/src/components/errors/ChunkLoadError.test.tsx +59 -0
- package/src/components/errors/ChunkLoadError.tsx +56 -0
- package/src/components/errors/CorsErrorComponent.tsx +2 -2
- package/src/components/errors/chunkReloadStorage.ts +57 -0
- package/src/config/handles.ts +29 -27
- package/src/constants.ts +5 -0
- package/src/context/ComlinkTokenRefresh.test.tsx +10 -27
- package/src/context/ComlinkTokenRefresh.tsx +3 -5
- package/src/context/DefaultResourceContext.ts +3 -3
- package/src/context/OrganizationResourcesProvider.test.tsx +189 -0
- package/src/context/OrganizationResourcesProvider.tsx +111 -0
- package/src/context/PerspectiveContext.ts +3 -3
- package/src/context/ProjectContext.ts +15 -0
- package/src/context/ResourceProvider.test.tsx +93 -90
- package/src/context/ResourceProvider.tsx +62 -93
- package/src/context/SDKStudioContext.test.tsx +28 -33
- package/src/context/SanityInstanceProvider.test.tsx +100 -0
- package/src/context/SanityInstanceProvider.tsx +71 -0
- package/src/context/WorkbenchTokenRefresh.test.tsx +106 -0
- package/src/context/WorkbenchTokenRefresh.tsx +61 -0
- package/src/context/renderSanityApp.test.tsx +151 -49
- package/src/context/renderSanityApp.tsx +12 -8
- package/src/context/workbenchToken.ts +63 -0
- package/src/hooks/access/useCheckPermissions.test-d.ts +15 -0
- package/src/hooks/access/useCheckPermissions.test.tsx +53 -0
- package/src/hooks/access/useCheckPermissions.ts +24 -0
- package/src/hooks/agent/agentActions.test.tsx +2 -2
- package/src/hooks/agent/agentActions.ts +52 -72
- package/src/hooks/agent/useAgentResourceContext.ts +1 -1
- package/src/hooks/applications/useApplication.test-d.ts +30 -0
- package/src/hooks/applications/useApplication.ts +22 -0
- package/src/hooks/applications/useApplications.test-d.ts +31 -0
- package/src/hooks/applications/useApplications.ts +25 -0
- package/src/hooks/applications/useDeleteApplication.test-d.ts +12 -0
- package/src/hooks/applications/useDeleteApplication.ts +11 -0
- package/src/hooks/applications/useUpdateApplication.test-d.ts +12 -0
- package/src/hooks/applications/useUpdateApplication.ts +11 -0
- package/src/hooks/auth/useDashboardOrganizationId.test.tsx +2 -8
- package/src/hooks/auth/useVerifyOrgProjects.test.tsx +8 -32
- package/src/hooks/auth/useVerifyOrgProjects.tsx +13 -6
- package/src/hooks/client/useClient.test.tsx +1 -4
- package/src/hooks/client/useClient.ts +1 -0
- package/src/hooks/comlink/useFrameConnection.test.tsx +3 -2
- package/src/hooks/comlink/useFrameConnection.ts +1 -1
- package/src/hooks/comlink/useWindowConnection.test.tsx +4 -3
- package/src/hooks/comlink/useWindowConnection.ts +2 -3
- package/src/hooks/comments/useCommentActions.test.tsx +150 -0
- package/src/hooks/comments/useCommentActions.ts +109 -0
- package/src/hooks/comments/useCommentList.ts +79 -0
- package/src/hooks/comments/useCommentThreads.test.tsx +107 -0
- package/src/hooks/comments/useCommentThreads.ts +73 -0
- package/src/hooks/comments/useComments.test.tsx +242 -0
- package/src/hooks/comments/useComments.ts +59 -0
- package/src/hooks/context/useResource.test.tsx +32 -0
- package/src/hooks/context/useResource.ts +24 -0
- package/src/hooks/context/useSanityInstance.test.tsx +18 -1
- package/src/hooks/context/useSanityInstance.ts +6 -6
- package/src/hooks/dashboard/useManageFavorite.test.tsx +110 -46
- package/src/hooks/dashboard/useManageFavorite.ts +11 -17
- package/src/hooks/dashboard/useNavigateToStudioDocument.test.ts +5 -7
- package/src/hooks/dashboard/useNavigateToStudioDocument.ts +2 -6
- package/src/hooks/dashboard/useRecordDocumentHistoryEvent.test.ts +0 -2
- package/src/hooks/dashboard/useRecordDocumentHistoryEvent.ts +2 -2
- package/src/hooks/dashboard/useWindowTitle.test.ts +244 -0
- package/src/hooks/dashboard/useWindowTitle.ts +114 -0
- package/src/hooks/datasets/useDatasets.test.tsx +116 -0
- package/src/hooks/datasets/useDatasets.ts +33 -13
- package/src/hooks/document/useApplyDocumentActions.test.tsx +48 -0
- package/src/hooks/document/useApplyDocumentActions.ts +66 -48
- package/src/hooks/document/useCreateDocument.test.tsx +83 -0
- package/src/hooks/document/useCreateDocument.ts +117 -0
- package/src/hooks/document/useDocument.test.tsx +37 -8
- package/src/hooks/document/useDocument.ts +131 -66
- package/src/hooks/document/useDocumentEvent.test.tsx +16 -4
- package/src/hooks/document/useDocumentEvent.ts +16 -10
- package/src/hooks/document/useDocumentPermissions.test.tsx +8 -7
- package/src/hooks/document/useDocumentPermissions.ts +71 -39
- package/src/hooks/document/useDocumentSyncStatus.test.ts +1 -0
- package/src/hooks/document/useDocumentSyncStatus.ts +13 -9
- package/src/hooks/document/useEditDocument.test.tsx +21 -14
- package/src/hooks/document/useEditDocument.ts +163 -17
- package/src/hooks/documents/useDocuments.test.tsx +64 -44
- package/src/hooks/documents/useDocuments.ts +31 -20
- package/src/hooks/helpers/createCallbackHook.test.tsx +13 -19
- package/src/hooks/helpers/createFetcherHook.test.tsx +180 -0
- package/src/hooks/helpers/createFetcherHook.ts +69 -0
- package/src/hooks/helpers/createMutationHook.test.tsx +125 -0
- package/src/hooks/helpers/createMutationHook.tsx +93 -0
- package/src/hooks/helpers/createStateSourceHook.test.tsx +10 -10
- package/src/hooks/helpers/createStateSourceHook.tsx +2 -1
- package/src/hooks/{document/useApplyDocumentActions.test.ts → helpers/useApplyActions.test.tsx} +92 -53
- package/src/hooks/helpers/useApplyActions.ts +68 -0
- package/src/hooks/helpers/useNormalizedResourceOptions.test.tsx +226 -0
- package/src/hooks/helpers/useNormalizedResourceOptions.ts +79 -48
- package/src/hooks/helpers/useResolvedProjectId.test.tsx +59 -0
- package/src/hooks/helpers/useResolvedProjectId.ts +35 -0
- package/src/hooks/helpers/useTrackHookUsage.ts +37 -0
- package/src/hooks/installations/useInstallation.test-d.ts +19 -0
- package/src/hooks/installations/useInstallation.ts +22 -0
- package/src/hooks/installations/useInstallations.test-d.ts +26 -0
- package/src/hooks/installations/useInstallations.ts +25 -0
- package/src/hooks/organizations/useOrganization.test-d.ts +60 -0
- package/src/hooks/organizations/useOrganization.test.ts +63 -0
- package/src/hooks/organizations/useOrganization.ts +34 -0
- package/src/hooks/organizations/useOrganizations.test-d.ts +68 -0
- package/src/hooks/organizations/useOrganizations.test.ts +63 -0
- package/src/hooks/organizations/useOrganizations.ts +39 -0
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.test.tsx +34 -27
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +35 -22
- package/src/hooks/presence/usePresence.test.tsx +0 -15
- package/src/hooks/presence/usePresence.ts +22 -20
- package/src/hooks/presence/usePresenceForDocument.test.tsx +141 -0
- package/src/hooks/presence/usePresenceForDocument.ts +104 -0
- package/src/hooks/presence/useReportPresence.test.tsx +202 -0
- package/src/hooks/presence/useReportPresence.ts +170 -0
- package/src/hooks/preview/useDocumentPreview.test.tsx +0 -1
- package/src/hooks/preview/useDocumentPreview.tsx +12 -14
- package/src/hooks/projection/useDocumentProjection.test.tsx +78 -9
- package/src/hooks/projection/useDocumentProjection.ts +81 -2
- package/src/hooks/projects/useProject.test-d.ts +56 -0
- package/src/hooks/projects/useProject.test.tsx +120 -0
- package/src/hooks/projects/useProject.ts +42 -43
- package/src/hooks/projects/useProjects.test-d.ts +60 -0
- package/src/hooks/projects/useProjects.test.ts +45 -98
- package/src/hooks/projects/useProjects.ts +17 -32
- package/src/hooks/query/useQuery.test.tsx +6 -5
- package/src/hooks/query/useQuery.ts +94 -17
- package/src/hooks/releases/useActiveReleases.test.tsx +13 -7
- package/src/hooks/releases/useActiveReleases.ts +28 -24
- package/src/hooks/releases/useAllReleases.test.tsx +93 -0
- package/src/hooks/releases/useAllReleases.ts +62 -0
- package/src/hooks/releases/useApplyReleaseActions.test.tsx +66 -0
- package/src/hooks/releases/useApplyReleaseActions.ts +82 -0
- package/src/hooks/releases/usePerspective.test.tsx +18 -10
- package/src/hooks/releases/usePerspective.ts +13 -17
- package/src/hooks/users/useUser.test.tsx +3 -9
- package/src/hooks/users/useUser.ts +4 -8
- package/src/hooks/users/useUsers.test.tsx +103 -7
- package/src/hooks/users/useUsers.ts +38 -5
- package/src/utils/resolveOrgResources.test.ts +111 -0
- package/src/utils/resolveOrgResources.ts +69 -0
- package/src/hooks/context/useDefaultResource.test.tsx +0 -25
- package/src/hooks/context/useDefaultResource.ts +0 -30
- package/src/hooks/dashboard/useDispatchIntent.test.ts +0 -254
- package/src/hooks/dashboard/useDispatchIntent.ts +0 -157
- package/src/hooks/dashboard/utils/useResourceIdFromDocumentHandle.test.ts +0 -107
- package/src/hooks/dashboard/utils/useResourceIdFromDocumentHandle.ts +0 -39
- package/src/hooks/datasets/useDatasets.test.ts +0 -66
- package/src/hooks/helpers/useNormalizedResourceOptions.test.ts +0 -65
- package/src/hooks/projects/useProject.test.ts +0 -79
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {from, type Observable, of} from 'rxjs'
|
|
2
|
+
import {catchError, switchMap} from 'rxjs/operators'
|
|
3
|
+
|
|
4
|
+
// The workbench host installs its shared message bus on this well-known global
|
|
5
|
+
// symbol before it loads federated remotes. It must match the key used by
|
|
6
|
+
// `@sanity/workbench` (`Symbol.for('sanity.os.bus')`).
|
|
7
|
+
const OS_BUS_KEY = Symbol.for('sanity.os.bus')
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Whether this app is running as a federated remote inside the workbench.
|
|
11
|
+
*
|
|
12
|
+
* Federation shares the host's realm, so the installed bus is visible on
|
|
13
|
+
* `globalThis`. This is `false` in a standalone app, where we must never import
|
|
14
|
+
* `@sanity/workbench` (it would install a bus and add bundle weight for no
|
|
15
|
+
* reason). Note: this is a different embedding model to the Core UI iframe,
|
|
16
|
+
* which is detected separately via the dashboard context — that signal is not
|
|
17
|
+
* set on the federation path.
|
|
18
|
+
*
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export function isWorkbenchEnvironment(): boolean {
|
|
22
|
+
return typeof globalThis === 'object' && OS_BUS_KEY in globalThis
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Observes the session token issued by the workbench "OS", tracking the OS auth
|
|
27
|
+
* state over time.
|
|
28
|
+
*
|
|
29
|
+
* Returns `undefined` when the app is not embedded in the workbench, so the
|
|
30
|
+
* caller uses its normal auth flow. Inside the workbench, subscribes to the
|
|
31
|
+
* `auth.token` state topic, emitting the current token — or `null` when the OS
|
|
32
|
+
* is signed out — and re-emitting as the OS auth state changes, so sign-in/out
|
|
33
|
+
* propagates instead of being captured once. Any bus error is treated as "no
|
|
34
|
+
* token" (`null`). The token is used in-memory only and never persisted.
|
|
35
|
+
*
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
export function observeWorkbenchToken(): Observable<string | null> | undefined {
|
|
39
|
+
if (!isWorkbenchEnvironment()) return undefined
|
|
40
|
+
|
|
41
|
+
return from(import('@sanity/workbench')).pipe(
|
|
42
|
+
switchMap(({os}) => os.subscribe('auth.token')),
|
|
43
|
+
// Any failure (importing the host bundle, or the subscription) means "no OS token".
|
|
44
|
+
catchError(() => of(null)),
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Asks the workbench "OS" to reissue the session token, e.g. after its current
|
|
50
|
+
* one was rejected with a 401. Fire-and-forget: the reissued token arrives via
|
|
51
|
+
* the `auth.token` subscription in {@link observeWorkbenchToken}. No-op outside
|
|
52
|
+
* the workbench.
|
|
53
|
+
*
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
export function refreshWorkbenchToken(): void {
|
|
57
|
+
if (!isWorkbenchEnvironment()) return
|
|
58
|
+
|
|
59
|
+
void import('@sanity/workbench').then(
|
|
60
|
+
({os}) => os.emit('auth.token.refresh', undefined),
|
|
61
|
+
() => {},
|
|
62
|
+
)
|
|
63
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {expectTypeOf, test} from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {type FetcherHookResult} from '../helpers/createFetcherHook'
|
|
4
|
+
import {useCheckPermissions} from './useCheckPermissions'
|
|
5
|
+
|
|
6
|
+
test('useCheckPermissions — the result is keyed by exactly the permissions passed', () => {
|
|
7
|
+
const result = useCheckPermissions('project', 'proj_1', ['read', 'write'])
|
|
8
|
+
expectTypeOf(result).toEqualTypeOf<FetcherHookResult<Record<'read' | 'write', boolean>>>()
|
|
9
|
+
expectTypeOf(result.data).toEqualTypeOf<Record<'read' | 'write', boolean>>()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('useCheckPermissions — rejects an unknown resource type', () => {
|
|
13
|
+
// @ts-expect-error — resourceType must be an AccessResourceType
|
|
14
|
+
void useCheckPermissions('not-a-resource', 'id', ['read'])
|
|
15
|
+
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {checkPermissions, type StateSource} from '@sanity/sdk'
|
|
2
|
+
import {type FetcherSnapshot} from '@sanity/sdk/_internal'
|
|
3
|
+
import {type Observable} from 'rxjs'
|
|
4
|
+
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
|
5
|
+
|
|
6
|
+
import {renderHook} from '../../../test/test-utils'
|
|
7
|
+
import {useCheckPermissions} from './useCheckPermissions'
|
|
8
|
+
|
|
9
|
+
vi.mock('@sanity/sdk', async (importOriginal) => {
|
|
10
|
+
const original = await importOriginal<typeof import('@sanity/sdk')>()
|
|
11
|
+
return {
|
|
12
|
+
...original,
|
|
13
|
+
checkPermissions: {getState: vi.fn(), resolveState: vi.fn(), refetch: vi.fn()},
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const stateSource = (
|
|
18
|
+
current: Record<string, boolean>,
|
|
19
|
+
): StateSource<FetcherSnapshot<Record<string, boolean>>> => {
|
|
20
|
+
const snapshot = {
|
|
21
|
+
status: 'success',
|
|
22
|
+
data: current,
|
|
23
|
+
error: undefined,
|
|
24
|
+
isFetching: false,
|
|
25
|
+
dataUpdatedAt: 1,
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
getCurrent: vi.fn(() => snapshot),
|
|
29
|
+
subscribe: vi.fn(() => () => {}),
|
|
30
|
+
get observable(): Observable<unknown> {
|
|
31
|
+
throw new Error('Not implemented')
|
|
32
|
+
},
|
|
33
|
+
} as unknown as StateSource<FetcherSnapshot<Record<string, boolean>>>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const sanityInstance = expect.objectContaining({config: expect.any(Object)})
|
|
37
|
+
|
|
38
|
+
describe('useCheckPermissions', () => {
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
vi.clearAllMocks()
|
|
41
|
+
vi.mocked(checkPermissions.getState).mockReturnValue(stateSource({'sanity.project.read': true}))
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('forwards every param to the fetcher and returns the permission map', () => {
|
|
45
|
+
const {result} = renderHook(() =>
|
|
46
|
+
useCheckPermissions('project', 'proj_1', ['sanity.project.read']),
|
|
47
|
+
)
|
|
48
|
+
expect(checkPermissions.getState).toHaveBeenCalledWith(sanityInstance, 'project', 'proj_1', [
|
|
49
|
+
'sanity.project.read',
|
|
50
|
+
])
|
|
51
|
+
expect(result.current.data).toEqual({'sanity.project.read': true})
|
|
52
|
+
})
|
|
53
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {type AccessResourceType, checkPermissions} from '@sanity/sdk'
|
|
2
|
+
|
|
3
|
+
import {createFetcherHook, type FetcherHookResult} from '../helpers/createFetcherHook'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Checks whether the current user holds the given permissions on a resource.
|
|
7
|
+
*
|
|
8
|
+
* The hook suspends until the first fetch succeeds, so `data` is always present.
|
|
9
|
+
* `data` maps each requested permission to whether the user has it — keyed by
|
|
10
|
+
* exactly the permission strings you passed.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
* @param resourceType - The type of resource (e.g. `'project'`, `'organization'`).
|
|
14
|
+
* @param resourceId - The resource id.
|
|
15
|
+
* @param permissions - The permission names to check.
|
|
16
|
+
* @returns The result envelope `{data, isFetching, error, refetch}`.
|
|
17
|
+
*/
|
|
18
|
+
export const useCheckPermissions = createFetcherHook(checkPermissions) as <
|
|
19
|
+
Permission extends string,
|
|
20
|
+
>(
|
|
21
|
+
resourceType: AccessResourceType,
|
|
22
|
+
resourceId: string,
|
|
23
|
+
permissions: Permission[],
|
|
24
|
+
) => FetcherHookResult<Record<Permission, boolean>>
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
useAgentTranslate,
|
|
13
13
|
} from './agentActions'
|
|
14
14
|
|
|
15
|
-
vi.mock('@sanity/sdk', async (orig) => {
|
|
15
|
+
vi.mock('@sanity/sdk/agent', async (orig) => {
|
|
16
16
|
const actual = await orig()
|
|
17
17
|
return {
|
|
18
18
|
...(actual as Record<string, any>),
|
|
@@ -26,7 +26,7 @@ vi.mock('@sanity/sdk', async (orig) => {
|
|
|
26
26
|
|
|
27
27
|
describe('agent action hooks', () => {
|
|
28
28
|
const wrapper = ({children}: {children: React.ReactNode}) => (
|
|
29
|
-
<ResourceProvider
|
|
29
|
+
<ResourceProvider projectId="p" dataset="d" fallback={null}>
|
|
30
30
|
{children}
|
|
31
31
|
</ResourceProvider>
|
|
32
32
|
)
|
|
@@ -7,23 +7,17 @@ import {
|
|
|
7
7
|
agentPrompt,
|
|
8
8
|
type AgentPromptOptions,
|
|
9
9
|
type AgentPromptResult,
|
|
10
|
-
type AgentResourceOptions,
|
|
11
10
|
agentTransform,
|
|
12
11
|
type AgentTransformOptions,
|
|
13
12
|
agentTranslate,
|
|
14
13
|
type AgentTranslateOptions,
|
|
15
|
-
|
|
16
|
-
} from '
|
|
17
|
-
import {useCallback, useContext} from 'react'
|
|
14
|
+
} from '@sanity/sdk/agent'
|
|
15
|
+
import {useCallback} from 'react'
|
|
18
16
|
import {firstValueFrom} from 'rxjs'
|
|
19
17
|
|
|
20
|
-
import {
|
|
21
|
-
import {ResourcesContext} from '../../context/ResourcesContext'
|
|
18
|
+
import {type ResourceHandle} from '../../config/handles'
|
|
22
19
|
import {useSanityInstance} from '../context/useSanityInstance'
|
|
23
|
-
import {
|
|
24
|
-
normalizeResourceOptions,
|
|
25
|
-
type WithResourceNameSupport,
|
|
26
|
-
} from '../helpers/useNormalizedResourceOptions'
|
|
20
|
+
import {useNormalizedResourceOptions} from '../helpers/useNormalizedResourceOptions'
|
|
27
21
|
|
|
28
22
|
interface Subscription {
|
|
29
23
|
unsubscribe(): void
|
|
@@ -44,26 +38,6 @@ interface Subscribable<T> {
|
|
|
44
38
|
): Subscription
|
|
45
39
|
}
|
|
46
40
|
|
|
47
|
-
function useAgentCallback<TOptions extends object, TReturn>(
|
|
48
|
-
action: (instance: SanityInstance, options: TOptions & AgentResourceOptions) => TReturn,
|
|
49
|
-
): (options: TOptions & WithResourceNameSupport<AgentResourceOptions>) => TReturn {
|
|
50
|
-
const instance = useSanityInstance()
|
|
51
|
-
const resources = useContext(ResourcesContext)
|
|
52
|
-
const contextResource = useContext(ResourceContext)
|
|
53
|
-
return useCallback(
|
|
54
|
-
(options: TOptions & WithResourceNameSupport<AgentResourceOptions>) => {
|
|
55
|
-
const {resource} = normalizeResourceOptions(
|
|
56
|
-
{resource: options.resource, resourceName: options.resourceName},
|
|
57
|
-
resources,
|
|
58
|
-
contextResource,
|
|
59
|
-
)
|
|
60
|
-
const {resourceName: _, ...rest} = options
|
|
61
|
-
return action(instance, {...rest, resource} as TOptions & AgentResourceOptions)
|
|
62
|
-
},
|
|
63
|
-
[instance, resources, contextResource, action],
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
41
|
/**
|
|
68
42
|
* @alpha
|
|
69
43
|
* Generates content for a document (or specific fields) via Sanity Agent Actions.
|
|
@@ -131,10 +105,16 @@ function useAgentCallback<TOptions extends object, TReturn>(
|
|
|
131
105
|
*
|
|
132
106
|
* @category Agent Actions
|
|
133
107
|
*/
|
|
134
|
-
export function useAgentGenerate(
|
|
135
|
-
|
|
136
|
-
) => Subscribable<unknown> {
|
|
137
|
-
|
|
108
|
+
export function useAgentGenerate(
|
|
109
|
+
resourceHandle?: ResourceHandle,
|
|
110
|
+
): (options: AgentGenerateOptions) => Subscribable<unknown> {
|
|
111
|
+
const instance = useSanityInstance()
|
|
112
|
+
const {resource} = useNormalizedResourceOptions(resourceHandle ?? {})
|
|
113
|
+
return useCallback(
|
|
114
|
+
(options: AgentGenerateOptions) =>
|
|
115
|
+
agentGenerate(instance, options, resource) as unknown as Subscribable<unknown>,
|
|
116
|
+
[instance, resource],
|
|
117
|
+
)
|
|
138
118
|
}
|
|
139
119
|
|
|
140
120
|
/**
|
|
@@ -208,10 +188,16 @@ export function useAgentGenerate(): (
|
|
|
208
188
|
*
|
|
209
189
|
* @category Agent Actions
|
|
210
190
|
*/
|
|
211
|
-
export function useAgentTransform(
|
|
212
|
-
|
|
213
|
-
) => Subscribable<unknown> {
|
|
214
|
-
|
|
191
|
+
export function useAgentTransform(
|
|
192
|
+
resourceHandle?: ResourceHandle,
|
|
193
|
+
): (options: AgentTransformOptions) => Subscribable<unknown> {
|
|
194
|
+
const instance = useSanityInstance()
|
|
195
|
+
const {resource} = useNormalizedResourceOptions(resourceHandle ?? {})
|
|
196
|
+
return useCallback(
|
|
197
|
+
(options: AgentTransformOptions) =>
|
|
198
|
+
agentTransform(instance, options, resource) as unknown as Subscribable<unknown>,
|
|
199
|
+
[instance, resource],
|
|
200
|
+
)
|
|
215
201
|
}
|
|
216
202
|
|
|
217
203
|
/**
|
|
@@ -304,21 +290,16 @@ export function useAgentTransform(): (
|
|
|
304
290
|
*
|
|
305
291
|
* @category Agent Actions
|
|
306
292
|
*/
|
|
307
|
-
export function useAgentTranslate(
|
|
308
|
-
|
|
309
|
-
) => Subscribable<unknown> {
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
function promptAdapter(
|
|
318
|
-
instance: SanityInstance,
|
|
319
|
-
options: AgentPromptOptions & AgentResourceOptions,
|
|
320
|
-
): Promise<AgentPromptResult> {
|
|
321
|
-
return firstValueFrom(agentPrompt(instance, options))
|
|
293
|
+
export function useAgentTranslate(
|
|
294
|
+
resourceHandle?: ResourceHandle,
|
|
295
|
+
): (options: AgentTranslateOptions) => Subscribable<unknown> {
|
|
296
|
+
const instance = useSanityInstance()
|
|
297
|
+
const {resource} = useNormalizedResourceOptions(resourceHandle ?? {})
|
|
298
|
+
return useCallback(
|
|
299
|
+
(options: AgentTranslateOptions) =>
|
|
300
|
+
agentTranslate(instance, options, resource) as unknown as Subscribable<unknown>,
|
|
301
|
+
[instance, resource],
|
|
302
|
+
)
|
|
322
303
|
}
|
|
323
304
|
|
|
324
305
|
/**
|
|
@@ -415,21 +396,15 @@ function promptAdapter(
|
|
|
415
396
|
*
|
|
416
397
|
* @category Agent Actions
|
|
417
398
|
*/
|
|
418
|
-
export function useAgentPrompt(
|
|
419
|
-
|
|
420
|
-
) => Promise<AgentPromptResult> {
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
*/
|
|
428
|
-
function patchAdapter(
|
|
429
|
-
instance: SanityInstance,
|
|
430
|
-
options: AgentPatchOptions & AgentResourceOptions,
|
|
431
|
-
): Promise<AgentPatchResult> {
|
|
432
|
-
return firstValueFrom(agentPatch(instance, options))
|
|
399
|
+
export function useAgentPrompt(
|
|
400
|
+
resourceHandle?: ResourceHandle,
|
|
401
|
+
): (options: AgentPromptOptions) => Promise<AgentPromptResult> {
|
|
402
|
+
const instance = useSanityInstance()
|
|
403
|
+
const {resource} = useNormalizedResourceOptions(resourceHandle ?? {})
|
|
404
|
+
return useCallback(
|
|
405
|
+
(options: AgentPromptOptions) => firstValueFrom(agentPrompt(instance, options, resource)),
|
|
406
|
+
[instance, resource],
|
|
407
|
+
)
|
|
433
408
|
}
|
|
434
409
|
|
|
435
410
|
/**
|
|
@@ -581,8 +556,13 @@ function patchAdapter(
|
|
|
581
556
|
*
|
|
582
557
|
* @category Agent Actions
|
|
583
558
|
*/
|
|
584
|
-
export function useAgentPatch(
|
|
585
|
-
|
|
586
|
-
) => Promise<AgentPatchResult> {
|
|
587
|
-
|
|
559
|
+
export function useAgentPatch(
|
|
560
|
+
resourceHandle?: ResourceHandle,
|
|
561
|
+
): (options: AgentPatchOptions) => Promise<AgentPatchResult> {
|
|
562
|
+
const instance = useSanityInstance()
|
|
563
|
+
const {resource} = useNormalizedResourceOptions(resourceHandle ?? {})
|
|
564
|
+
return useCallback(
|
|
565
|
+
(options: AgentPatchOptions) => firstValueFrom(agentPatch(instance, options, resource)),
|
|
566
|
+
[instance, resource],
|
|
567
|
+
)
|
|
588
568
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {type Events, SDK_CHANNEL_NAME, SDK_NODE_NAME} from '@sanity/message-protocol'
|
|
2
|
-
import {type FrameMessage} from '@sanity/sdk'
|
|
2
|
+
import {type FrameMessage} from '@sanity/sdk/comlink'
|
|
3
3
|
import {useCallback, useEffect, useRef} from 'react'
|
|
4
4
|
|
|
5
5
|
import {useWindowConnection} from '../comlink/useWindowConnection'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Application,
|
|
3
|
+
type ApplicationDeployment,
|
|
4
|
+
type ApplicationStudioConfig,
|
|
5
|
+
} from '@sanity/sdk'
|
|
6
|
+
import {expectTypeOf, test} from 'vitest'
|
|
7
|
+
|
|
8
|
+
import {type FetcherHookResult} from '../helpers/createFetcherHook'
|
|
9
|
+
import {useApplication} from './useApplication'
|
|
10
|
+
|
|
11
|
+
test('useApplication — no include: the base application', () => {
|
|
12
|
+
const result = useApplication('app_1')
|
|
13
|
+
expectTypeOf(result).toEqualTypeOf<FetcherHookResult<Application<never>>>()
|
|
14
|
+
expectTypeOf<
|
|
15
|
+
Extract<keyof typeof result.data, 'activeDeployment' | 'config'>
|
|
16
|
+
>().toEqualTypeOf<never>()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('useApplication — config.studio include adds config.studio', () => {
|
|
20
|
+
const result = useApplication('app_1', {include: ['config.studio']})
|
|
21
|
+
expectTypeOf(result.data).toEqualTypeOf<Application<'config.studio'>>()
|
|
22
|
+
expectTypeOf(result.data.config.studio).toEqualTypeOf<ApplicationStudioConfig>()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('useApplication — a deployment-child include forces the deployment in', () => {
|
|
26
|
+
const result = useApplication('app_1', {include: ['activeDeployment']})
|
|
27
|
+
expectTypeOf(
|
|
28
|
+
result.data.activeDeployment,
|
|
29
|
+
).toEqualTypeOf<ApplicationDeployment<'activeDeployment'> | null>()
|
|
30
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {type Application, application, type ApplicationInclude} from '@sanity/sdk'
|
|
2
|
+
|
|
3
|
+
import {createFetcherHook, type FetcherHookResult} from '../helpers/createFetcherHook'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns a single application by id.
|
|
7
|
+
*
|
|
8
|
+
* The hook suspends until the first fetch succeeds, so `data` is always present.
|
|
9
|
+
* The `include` tokens you pass shape `data`: each requested token adds its
|
|
10
|
+
* field, and omitted ones are absent from the type.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
* @param applicationId - The application id.
|
|
14
|
+
* @param options - Optional `include` list to expand related resources.
|
|
15
|
+
* @returns The result envelope `{data, isFetching, error, refetch}`.
|
|
16
|
+
*/
|
|
17
|
+
export const useApplication = createFetcherHook(application) as <
|
|
18
|
+
Include extends ApplicationInclude = never,
|
|
19
|
+
>(
|
|
20
|
+
applicationId: string,
|
|
21
|
+
options?: {include?: Include[]},
|
|
22
|
+
) => FetcherHookResult<Application<Include>>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {type Application, type ApplicationInterface, type ApplicationsResponse} from '@sanity/sdk'
|
|
2
|
+
import {expectTypeOf, test} from 'vitest'
|
|
3
|
+
|
|
4
|
+
import {type FetcherHookResult} from '../helpers/createFetcherHook'
|
|
5
|
+
import {useApplications} from './useApplications'
|
|
6
|
+
|
|
7
|
+
test('useApplications — no include: base items, no deployment or config', () => {
|
|
8
|
+
const result = useApplications({organizationId: 'org_1'})
|
|
9
|
+
expectTypeOf(result).toEqualTypeOf<FetcherHookResult<ApplicationsResponse<never>>>()
|
|
10
|
+
type Item = (typeof result.data.data)[number]
|
|
11
|
+
expectTypeOf<Extract<keyof Item, 'activeDeployment' | 'config'>>().toEqualTypeOf<never>()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
test('useApplications — include shapes each item', () => {
|
|
15
|
+
const result = useApplications({organizationId: 'org_1', include: ['interfaces']})
|
|
16
|
+
expectTypeOf(result.data).toEqualTypeOf<ApplicationsResponse<'interfaces'>>()
|
|
17
|
+
type Item = (typeof result.data.data)[number]
|
|
18
|
+
expectTypeOf<NonNullable<Item['activeDeployment']>['interfaces']>().toEqualTypeOf<
|
|
19
|
+
ApplicationInterface[]
|
|
20
|
+
>()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('useApplications — result data is the current include-narrowed application', () => {
|
|
24
|
+
const result = useApplications({organizationId: 'org_1', include: ['config.studio']})
|
|
25
|
+
expectTypeOf(result.data.data).toEqualTypeOf<Application<'config.studio'>[]>()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('useApplications — requires an organizationId', () => {
|
|
29
|
+
// @ts-expect-error — organizationId is required
|
|
30
|
+
void useApplications({})
|
|
31
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ApplicationInclude,
|
|
3
|
+
applications,
|
|
4
|
+
type ApplicationsOptions,
|
|
5
|
+
type ApplicationsResponse,
|
|
6
|
+
} from '@sanity/sdk'
|
|
7
|
+
|
|
8
|
+
import {createFetcherHook, type FetcherHookResult} from '../helpers/createFetcherHook'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Returns the applications matching the given options.
|
|
12
|
+
*
|
|
13
|
+
* The hook suspends until the first fetch succeeds, so `data` is always present.
|
|
14
|
+
* The `include` tokens you pass shape `data.data`: each requested token adds its
|
|
15
|
+
* field, and omitted ones are absent from the type.
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
* @param options - Filter and include options for the applications list.
|
|
19
|
+
* @returns The result envelope `{data, isFetching, error, refetch}`.
|
|
20
|
+
*/
|
|
21
|
+
export const useApplications = createFetcherHook(applications) as <
|
|
22
|
+
Include extends ApplicationInclude = never,
|
|
23
|
+
>(
|
|
24
|
+
options: ApplicationsOptions<Include>,
|
|
25
|
+
) => FetcherHookResult<ApplicationsResponse<Include>>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {type DeleteApplicationInput, type DeletedResult} from '@sanity/sdk'
|
|
2
|
+
import {expectTypeOf, test} from 'vitest'
|
|
3
|
+
|
|
4
|
+
import {type MutationHookResult} from '../helpers/createMutationHook'
|
|
5
|
+
import {useDeleteApplication} from './useDeleteApplication'
|
|
6
|
+
|
|
7
|
+
test('useDeleteApplication — returns the mutation envelope', () => {
|
|
8
|
+
const result = useDeleteApplication()
|
|
9
|
+
expectTypeOf(result).toEqualTypeOf<MutationHookResult<DeleteApplicationInput, DeletedResult>>()
|
|
10
|
+
expectTypeOf(result.mutate).parameter(0).toEqualTypeOf<DeleteApplicationInput>()
|
|
11
|
+
expectTypeOf(result.data).toEqualTypeOf<DeletedResult | undefined>()
|
|
12
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {deleteApplication} from '@sanity/sdk'
|
|
2
|
+
|
|
3
|
+
import {createMutationHook} from '../helpers/createMutationHook'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Soft-deletes an application.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
* @returns The mutation envelope `{mutate, isPending, error, data, reset}`.
|
|
10
|
+
*/
|
|
11
|
+
export const useDeleteApplication = createMutationHook(deleteApplication)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {type Application, type UpdateApplicationInput} from '@sanity/sdk'
|
|
2
|
+
import {expectTypeOf, test} from 'vitest'
|
|
3
|
+
|
|
4
|
+
import {type MutationHookResult} from '../helpers/createMutationHook'
|
|
5
|
+
import {useUpdateApplication} from './useUpdateApplication'
|
|
6
|
+
|
|
7
|
+
test('useUpdateApplication — returns the mutation envelope', () => {
|
|
8
|
+
const result = useUpdateApplication()
|
|
9
|
+
expectTypeOf(result).toEqualTypeOf<MutationHookResult<UpdateApplicationInput, Application>>()
|
|
10
|
+
expectTypeOf(result.mutate).parameter(0).toEqualTypeOf<UpdateApplicationInput>()
|
|
11
|
+
expectTypeOf(result.data).toEqualTypeOf<Application | undefined>()
|
|
12
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {updateApplication} from '@sanity/sdk'
|
|
2
|
+
|
|
3
|
+
import {createMutationHook} from '../helpers/createMutationHook'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Updates an application's mutable properties (title, icon, visibility).
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
* @returns The mutation envelope `{mutate, isPending, error, data, reset}`.
|
|
10
|
+
*/
|
|
11
|
+
export const useUpdateApplication = createMutationHook(updateApplication)
|
|
@@ -22,10 +22,7 @@ describe('useDashboardOrganizationId', () => {
|
|
|
22
22
|
|
|
23
23
|
const {result} = renderHook(() => useDashboardOrganizationId(), {
|
|
24
24
|
wrapper: ({children}) => (
|
|
25
|
-
<ResourceProvider
|
|
26
|
-
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
27
|
-
fallback={null}
|
|
28
|
-
>
|
|
25
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
29
26
|
{children}
|
|
30
27
|
</ResourceProvider>
|
|
31
28
|
),
|
|
@@ -44,10 +41,7 @@ describe('useDashboardOrganizationId', () => {
|
|
|
44
41
|
|
|
45
42
|
const {result} = renderHook(() => useDashboardOrganizationId(), {
|
|
46
43
|
wrapper: ({children}) => (
|
|
47
|
-
<ResourceProvider
|
|
48
|
-
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
49
|
-
fallback={null}
|
|
50
|
-
>
|
|
44
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
51
45
|
{children}
|
|
52
46
|
</ResourceProvider>
|
|
53
47
|
),
|
|
@@ -26,10 +26,7 @@ describe('useVerifyOrgProjects', () => {
|
|
|
26
26
|
it('should return null and not observe state if disabled', () => {
|
|
27
27
|
const {result} = renderHook(() => useVerifyOrgProjects(true, testProjectIds), {
|
|
28
28
|
wrapper: ({children}) => (
|
|
29
|
-
<ResourceProvider
|
|
30
|
-
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
31
|
-
fallback={null}
|
|
32
|
-
>
|
|
29
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
33
30
|
{children}
|
|
34
31
|
</ResourceProvider>
|
|
35
32
|
),
|
|
@@ -42,10 +39,7 @@ describe('useVerifyOrgProjects', () => {
|
|
|
42
39
|
it('should return null and not observe state if projectIds is missing or empty', () => {
|
|
43
40
|
const {result: resultUndefined} = renderHook(() => useVerifyOrgProjects(false, undefined), {
|
|
44
41
|
wrapper: ({children}) => (
|
|
45
|
-
<ResourceProvider
|
|
46
|
-
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
47
|
-
fallback={null}
|
|
48
|
-
>
|
|
42
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
49
43
|
{children}
|
|
50
44
|
</ResourceProvider>
|
|
51
45
|
),
|
|
@@ -55,10 +49,7 @@ describe('useVerifyOrgProjects', () => {
|
|
|
55
49
|
|
|
56
50
|
const {result: resultEmpty} = renderHook(() => useVerifyOrgProjects(false, []), {
|
|
57
51
|
wrapper: ({children}) => (
|
|
58
|
-
<ResourceProvider
|
|
59
|
-
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
60
|
-
fallback={null}
|
|
61
|
-
>
|
|
52
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
62
53
|
{children}
|
|
63
54
|
</ResourceProvider>
|
|
64
55
|
),
|
|
@@ -73,10 +64,7 @@ describe('useVerifyOrgProjects', () => {
|
|
|
73
64
|
|
|
74
65
|
const {result} = renderHook(() => useVerifyOrgProjects(false, testProjectIds), {
|
|
75
66
|
wrapper: ({children}) => (
|
|
76
|
-
<ResourceProvider
|
|
77
|
-
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
78
|
-
fallback={null}
|
|
79
|
-
>
|
|
67
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
80
68
|
{children}
|
|
81
69
|
</ResourceProvider>
|
|
82
70
|
),
|
|
@@ -92,10 +80,7 @@ describe('useVerifyOrgProjects', () => {
|
|
|
92
80
|
|
|
93
81
|
const {result} = renderHook(() => useVerifyOrgProjects(false, testProjectIds), {
|
|
94
82
|
wrapper: ({children}) => (
|
|
95
|
-
<ResourceProvider
|
|
96
|
-
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
97
|
-
fallback={null}
|
|
98
|
-
>
|
|
83
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
99
84
|
{children}
|
|
100
85
|
</ResourceProvider>
|
|
101
86
|
),
|
|
@@ -117,10 +102,7 @@ describe('useVerifyOrgProjects', () => {
|
|
|
117
102
|
|
|
118
103
|
const {result} = renderHook(() => useVerifyOrgProjects(false, testProjectIds), {
|
|
119
104
|
wrapper: ({children}) => (
|
|
120
|
-
<ResourceProvider
|
|
121
|
-
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
122
|
-
fallback={null}
|
|
123
|
-
>
|
|
105
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
124
106
|
{children}
|
|
125
107
|
</ResourceProvider>
|
|
126
108
|
),
|
|
@@ -142,10 +124,7 @@ describe('useVerifyOrgProjects', () => {
|
|
|
142
124
|
|
|
143
125
|
const {unmount} = renderHook(() => useVerifyOrgProjects(false, testProjectIds), {
|
|
144
126
|
wrapper: ({children}) => (
|
|
145
|
-
<ResourceProvider
|
|
146
|
-
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
147
|
-
fallback={null}
|
|
148
|
-
>
|
|
127
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
149
128
|
{children}
|
|
150
129
|
</ResourceProvider>
|
|
151
130
|
),
|
|
@@ -173,10 +152,7 @@ describe('useVerifyOrgProjects', () => {
|
|
|
173
152
|
{
|
|
174
153
|
initialProps: {disabled: false, pIds: testProjectIds},
|
|
175
154
|
wrapper: ({children}) => (
|
|
176
|
-
<ResourceProvider
|
|
177
|
-
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
178
|
-
fallback={null}
|
|
179
|
-
>
|
|
155
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
180
156
|
{children}
|
|
181
157
|
</ResourceProvider>
|
|
182
158
|
),
|