@sanity/sdk 2.7.0 → 3.0.0-rc.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 (99) hide show
  1. package/dist/index.d.ts +228 -239
  2. package/dist/index.js +287 -454
  3. package/dist/index.js.map +1 -1
  4. package/package.json +4 -4
  5. package/src/_exports/index.ts +16 -17
  6. package/src/agent/agentActions.test.ts +60 -16
  7. package/src/agent/agentActions.ts +29 -20
  8. package/src/auth/authMode.test.ts +0 -25
  9. package/src/auth/authMode.ts +3 -6
  10. package/src/auth/authStore.test.ts +129 -66
  11. package/src/auth/authStore.ts +9 -11
  12. package/src/auth/dashboardAuth.ts +2 -2
  13. package/src/auth/getOrganizationVerificationState.test.ts +10 -11
  14. package/src/auth/handleAuthCallback.test.ts +0 -12
  15. package/src/auth/handleAuthCallback.ts +9 -3
  16. package/src/auth/logout.test.ts +0 -6
  17. package/src/auth/refreshStampedToken.test.ts +121 -17
  18. package/src/auth/standaloneAuth.ts +9 -3
  19. package/src/auth/studioAuth.ts +35 -8
  20. package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +9 -3
  21. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +1 -1
  22. package/src/auth/subscribeToStorageEventsAndSetToken.test.ts +0 -2
  23. package/src/auth/subscribeToStorageEventsAndSetToken.ts +2 -2
  24. package/src/auth/utils.ts +33 -0
  25. package/src/client/clientStore.test.ts +14 -61
  26. package/src/client/clientStore.ts +52 -28
  27. package/src/comlink/controller/actions/destroyController.test.ts +1 -4
  28. package/src/comlink/controller/actions/getOrCreateChannel.test.ts +1 -4
  29. package/src/comlink/controller/actions/getOrCreateController.test.ts +1 -4
  30. package/src/comlink/controller/actions/releaseChannel.test.ts +1 -1
  31. package/src/comlink/controller/comlinkControllerStore.test.ts +1 -4
  32. package/src/comlink/node/actions/getOrCreateNode.test.ts +1 -4
  33. package/src/comlink/node/actions/releaseNode.test.ts +1 -4
  34. package/src/comlink/node/comlinkNodeStore.test.ts +2 -2
  35. package/src/comlink/node/getNodeState.test.ts +1 -1
  36. package/src/config/__tests__/handles.test.ts +12 -18
  37. package/src/config/handles.ts +7 -25
  38. package/src/config/sanityConfig.ts +99 -52
  39. package/src/datasets/datasets.test.ts +2 -2
  40. package/src/datasets/datasets.ts +4 -10
  41. package/src/document/actions.test.ts +33 -4
  42. package/src/document/actions.ts +3 -10
  43. package/src/document/applyDocumentActions.test.ts +17 -18
  44. package/src/document/applyDocumentActions.ts +9 -12
  45. package/src/document/documentStore.test.ts +303 -133
  46. package/src/document/documentStore.ts +70 -61
  47. package/src/document/permissions.test.ts +44 -8
  48. package/src/document/processActions.test.ts +77 -7
  49. package/src/document/reducers.test.ts +35 -3
  50. package/src/document/sharedListener.test.ts +13 -13
  51. package/src/document/sharedListener.ts +8 -3
  52. package/src/favorites/favorites.test.ts +10 -2
  53. package/src/presence/presenceStore.test.ts +34 -9
  54. package/src/presence/presenceStore.ts +29 -13
  55. package/src/preview/previewProjectionUtils.test.ts +192 -0
  56. package/src/preview/previewProjectionUtils.ts +88 -0
  57. package/src/preview/{previewStore.ts → types.ts} +6 -25
  58. package/src/project/project.test.ts +1 -1
  59. package/src/project/project.ts +14 -20
  60. package/src/projection/getProjectionState.test.ts +4 -2
  61. package/src/projection/getProjectionState.ts +2 -21
  62. package/src/projection/projectionQuery.ts +2 -3
  63. package/src/projection/projectionStore.test.ts +3 -3
  64. package/src/projection/resolveProjection.test.ts +2 -1
  65. package/src/projection/resolveProjection.ts +2 -18
  66. package/src/projection/subscribeToStateAndFetchBatches.test.ts +2 -2
  67. package/src/projection/subscribeToStateAndFetchBatches.ts +23 -36
  68. package/src/projection/types.ts +1 -9
  69. package/src/projects/projects.test.ts +1 -1
  70. package/src/query/queryStore.test.ts +86 -28
  71. package/src/query/queryStore.ts +23 -38
  72. package/src/releases/getPerspectiveState.test.ts +14 -13
  73. package/src/releases/getPerspectiveState.ts +6 -6
  74. package/src/releases/releasesStore.test.ts +21 -6
  75. package/src/releases/releasesStore.ts +18 -8
  76. package/src/store/createActionBinder.test.ts +114 -111
  77. package/src/store/createActionBinder.ts +52 -101
  78. package/src/store/createSanityInstance.test.ts +13 -83
  79. package/src/store/createSanityInstance.ts +2 -78
  80. package/src/store/createStateSourceAction.test.ts +2 -2
  81. package/src/store/createStateSourceAction.ts +5 -5
  82. package/src/store/createStoreInstance.test.ts +2 -4
  83. package/src/users/reducers.test.ts +1 -6
  84. package/src/users/reducers.ts +2 -2
  85. package/src/users/types.ts +4 -4
  86. package/src/users/usersStore.test.ts +12 -15
  87. package/src/utils/createFetcherStore.test.ts +1 -1
  88. package/src/utils/logger.test.ts +0 -12
  89. package/src/utils/logger.ts +3 -8
  90. package/src/preview/getPreviewState.test.ts +0 -120
  91. package/src/preview/getPreviewState.ts +0 -91
  92. package/src/preview/previewQuery.test.ts +0 -236
  93. package/src/preview/previewQuery.ts +0 -153
  94. package/src/preview/previewStore.test.ts +0 -36
  95. package/src/preview/resolvePreview.test.ts +0 -47
  96. package/src/preview/resolvePreview.ts +0 -20
  97. package/src/preview/subscribeToStateAndFetchBatches.test.ts +0 -221
  98. package/src/preview/subscribeToStateAndFetchBatches.ts +0 -112
  99. package/src/preview/util.ts +0 -13
@@ -1,7 +1,7 @@
1
1
  import {filter, firstValueFrom, of, Subject, take} from 'rxjs'
2
2
  import {describe, expect, it, vi} from 'vitest'
3
3
 
4
- import {type PerspectiveHandle, type ReleasePerspective} from '../config/sanityConfig'
4
+ import {type ReleasePerspective, type ResourceHandle} from '../config/sanityConfig'
5
5
  import {getQueryState} from '../query/queryStore'
6
6
  import {createSanityInstance, type SanityInstance} from '../store/createSanityInstance'
7
7
  import {type StateSource} from '../store/createStateSourceAction'
@@ -39,9 +39,10 @@ describe('getPerspectiveState', () => {
39
39
 
40
40
  // the release store is reversed in getActiveReleases to match UI elsewhere
41
41
  const activeReleases = [release2, release1]
42
+ const resource: ResourceHandle['resource'] = {projectId: 'p', dataset: 'd'}
42
43
 
43
44
  beforeEach(() => {
44
- instance = createSanityInstance({projectId: 'test', dataset: 'test'})
45
+ instance = createSanityInstance()
45
46
 
46
47
  mockReleasesQuerySubject = new Subject<ReleaseDocument[] | undefined>()
47
48
  vi.mocked(getQueryState).mockReturnValue({
@@ -57,7 +58,7 @@ describe('getPerspectiveState', () => {
57
58
  })
58
59
 
59
60
  it('should return default perspective if no options or instance perspective is provided', async () => {
60
- const state = getPerspectiveState(instance)
61
+ const state = getPerspectiveState(instance, {resource})
61
62
  mockReleasesQuerySubject.next([])
62
63
  const perspective = await firstValueFrom(state.observable)
63
64
  expect(perspective).toBe('drafts')
@@ -65,14 +66,14 @@ describe('getPerspectiveState', () => {
65
66
 
66
67
  it('should return instance perspective if provided and no options perspective', async () => {
67
68
  instance.config.perspective = 'published'
68
- const state = getPerspectiveState(instance)
69
+ const state = getPerspectiveState(instance, {resource})
69
70
  mockReleasesQuerySubject.next([])
70
71
  const perspective = await firstValueFrom(state.observable)
71
72
  expect(perspective).toBe('published')
72
73
  })
73
74
 
74
75
  it('should return options perspective if provided', async () => {
75
- const options: PerspectiveHandle = {perspective: 'raw'}
76
+ const options = {perspective: 'raw' as const, resource}
76
77
  const state = getPerspectiveState(instance, options)
77
78
  mockReleasesQuerySubject.next([])
78
79
  const perspective = await firstValueFrom(state.observable)
@@ -80,7 +81,7 @@ describe('getPerspectiveState', () => {
80
81
  })
81
82
 
82
83
  it('should return undefined if release perspective is requested but no active releases', async () => {
83
- const options: PerspectiveHandle = {perspective: {releaseName: 'release1'}}
84
+ const options = {perspective: {releaseName: 'release1'}, resource}
84
85
  const state = getPerspectiveState(instance, options)
85
86
  mockReleasesQuerySubject.next([])
86
87
  const perspective = await firstValueFrom(state.observable)
@@ -88,7 +89,7 @@ describe('getPerspectiveState', () => {
88
89
  })
89
90
 
90
91
  it('should calculate perspective based on active releases and releaseName', async () => {
91
- const options: PerspectiveHandle = {perspective: {releaseName: 'release1'}}
92
+ const options = {perspective: {releaseName: 'release1'}, resource}
92
93
  const state = getPerspectiveState(instance, options)
93
94
  mockReleasesQuerySubject.next(activeReleases)
94
95
 
@@ -102,7 +103,7 @@ describe('getPerspectiveState', () => {
102
103
  })
103
104
 
104
105
  it('should calculate perspective including multiple releases up to the specified releaseName', async () => {
105
- const options: PerspectiveHandle = {perspective: {releaseName: 'release2'}}
106
+ const options = {perspective: {releaseName: 'release2'}, resource}
106
107
  const state = getPerspectiveState(instance, options)
107
108
  mockReleasesQuerySubject.next(activeReleases)
108
109
  const perspective = await firstValueFrom(
@@ -119,7 +120,7 @@ describe('getPerspectiveState', () => {
119
120
  releaseName: 'release2',
120
121
  excludedPerspectives: ['release1', 'drafts'],
121
122
  }
122
- const options: PerspectiveHandle = {perspective: perspectiveConfig}
123
+ const options = {perspective: perspectiveConfig, resource}
123
124
  const state = getPerspectiveState(instance, options)
124
125
  mockReleasesQuerySubject.next(activeReleases)
125
126
  const perspective = await firstValueFrom(
@@ -132,7 +133,7 @@ describe('getPerspectiveState', () => {
132
133
  })
133
134
 
134
135
  it('should throw if the specified releaseName is not found in active releases', async () => {
135
- const options: PerspectiveHandle = {perspective: {releaseName: 'nonexistent'}}
136
+ const options = {perspective: {releaseName: 'nonexistent'}, resource}
136
137
  const state = getPerspectiveState(instance, options)
137
138
  mockReleasesQuerySubject.next(activeReleases)
138
139
 
@@ -147,8 +148,8 @@ describe('getPerspectiveState', () => {
147
148
  })
148
149
 
149
150
  it('should reuse the same options object for identical inputs (cache test)', async () => {
150
- const options1: PerspectiveHandle = {perspective: {releaseName: 'release1'}}
151
- const options2: PerspectiveHandle = {perspective: {releaseName: 'release1'}}
151
+ const options1 = {perspective: {releaseName: 'release1'}, resource}
152
+ const options2 = {perspective: {releaseName: 'release1'}, resource}
152
153
 
153
154
  const state1 = getPerspectiveState(instance, options1)
154
155
  mockReleasesQuerySubject.next(activeReleases)
@@ -166,7 +167,7 @@ describe('getPerspectiveState', () => {
166
167
  })
167
168
 
168
169
  it('should handle changes in activeReleases (cache test)', async () => {
169
- const options: PerspectiveHandle = {perspective: {releaseName: 'release1'}}
170
+ const options = {perspective: {releaseName: 'release1'}, resource}
170
171
 
171
172
  const state1 = getPerspectiveState(instance, options)
172
173
  mockReleasesQuerySubject.next(activeReleases)
@@ -1,7 +1,7 @@
1
1
  import {createSelector} from 'reselect'
2
2
 
3
- import {type PerspectiveHandle} from '../config/sanityConfig'
4
- import {bindActionByDataset, type BoundStoreAction} from '../store/createActionBinder'
3
+ import {type DocumentResource, type PerspectiveHandle} from '../config/sanityConfig'
4
+ import {bindActionByResource, type BoundStoreAction} from '../store/createActionBinder'
5
5
  import {createStateSourceAction, type SelectorContext} from '../store/createStateSourceAction'
6
6
  /*
7
7
  * Although this is an import dependency cycle, it is not a logical cycle:
@@ -26,7 +26,7 @@ const selectActiveReleases = (context: SelectorContext<ReleasesStoreState>) =>
26
26
  context.state.activeReleases
27
27
  const selectOptions = (
28
28
  _context: SelectorContext<ReleasesStoreState>,
29
- options: PerspectiveHandle & {projectId?: string; dataset?: string},
29
+ options: PerspectiveHandle & {resource?: DocumentResource},
30
30
  ) => options
31
31
 
32
32
  const memoizedOptionsSelector = createSelector(
@@ -103,12 +103,12 @@ let _boundGetPerspectiveState: BoundGetPerspectiveState | undefined
103
103
  *
104
104
  * @public
105
105
  */
106
- export const getPerspectiveState: BoundGetPerspectiveState = (...args) => {
106
+ export const getPerspectiveState: BoundGetPerspectiveState = (instance, ...rest) => {
107
107
  if (!_boundGetPerspectiveState) {
108
- _boundGetPerspectiveState = bindActionByDataset(
108
+ _boundGetPerspectiveState = bindActionByResource(
109
109
  releasesStore,
110
110
  _getPerspectiveStateSelector,
111
111
  ) as BoundGetPerspectiveState
112
112
  }
113
- return _boundGetPerspectiveState(...args)
113
+ return _boundGetPerspectiveState(instance, ...rest)
114
114
  }
@@ -15,7 +15,7 @@ describe('releasesStore', () => {
15
15
  beforeEach(() => {
16
16
  vi.clearAllMocks()
17
17
 
18
- instance = createSanityInstance({projectId: 'test', dataset: 'test'})
18
+ instance = createSanityInstance()
19
19
 
20
20
  vi.mocked(getQueryState).mockReturnValue({
21
21
  subscribe: () => () => {},
@@ -30,6 +30,21 @@ describe('releasesStore', () => {
30
30
  instance.dispose()
31
31
  })
32
32
 
33
+ it('supports calls with explicit resource', () => {
34
+ const state = getActiveReleasesState(instance, {resource: {projectId: 'test', dataset: 'test'}})
35
+
36
+ expect(state.getCurrent()).toBeUndefined()
37
+ expect(getQueryState).toHaveBeenCalledWith(
38
+ instance,
39
+ expect.objectContaining({
40
+ query: 'releases::all()',
41
+ perspective: 'raw',
42
+ resource: {projectId: 'test', dataset: 'test'},
43
+ tag: 'releases',
44
+ }),
45
+ )
46
+ })
47
+
33
48
  it('should set active releases state when the releases query emits', async () => {
34
49
  const teardown = vi.fn()
35
50
  const subscriber = vi
@@ -58,7 +73,7 @@ describe('releasesStore', () => {
58
73
  } as ReleaseDocument,
59
74
  ]
60
75
 
61
- const state = getActiveReleasesState(instance)
76
+ const state = getActiveReleasesState(instance, {resource: {projectId: 'test', dataset: 'test'}})
62
77
 
63
78
  const [observer] = subscriber.mock.lastCall!
64
79
 
@@ -77,7 +92,7 @@ describe('releasesStore', () => {
77
92
  observable: releasesSubject.asObservable(),
78
93
  } as StateSource<ReleaseDocument[] | undefined>)
79
94
 
80
- const state = getActiveReleasesState(instance)
95
+ const state = getActiveReleasesState(instance, {resource: {projectId: 'test', dataset: 'test'}})
81
96
 
82
97
  // Initial state should be default
83
98
  expect(state.getCurrent()).toBeUndefined() // Default initial state
@@ -124,7 +139,7 @@ describe('releasesStore', () => {
124
139
  observable: of([]),
125
140
  } as StateSource<ReleaseDocument[] | undefined>)
126
141
 
127
- const state = getActiveReleasesState(instance)
142
+ const state = getActiveReleasesState(instance, {resource: {projectId: 'test', dataset: 'test'}})
128
143
 
129
144
  await new Promise((resolve) => setTimeout(resolve, 0))
130
145
 
@@ -138,7 +153,7 @@ describe('releasesStore', () => {
138
153
  getCurrent: () => null as unknown as ReleaseDocument[] | undefined,
139
154
  observable: of(null as unknown as ReleaseDocument[] | undefined),
140
155
  } as StateSource<ReleaseDocument[] | undefined>)
141
- const state = getActiveReleasesState(instance)
156
+ const state = getActiveReleasesState(instance, {resource: {projectId: 'test', dataset: 'test'}})
142
157
  await new Promise((resolve) => setTimeout(resolve, 0))
143
158
  expect(state.getCurrent()).toEqual([])
144
159
 
@@ -160,7 +175,7 @@ describe('releasesStore', () => {
160
175
  observable: subject.asObservable(),
161
176
  } as StateSource<ReleaseDocument[] | undefined>)
162
177
 
163
- const state = getActiveReleasesState(instance)
178
+ const state = getActiveReleasesState(instance, {resource: {projectId: 'test', dataset: 'test'}})
164
179
 
165
180
  subject.error(new Error('Query failed'))
166
181
 
@@ -1,6 +1,7 @@
1
1
  import {type SanityDocument} from '@sanity/types'
2
2
  import {map} from 'rxjs'
3
3
 
4
+ import {type DocumentResource} from '../config/sanityConfig'
4
5
  /*
5
6
  * Although this is an import dependency cycle, it is not a logical cycle:
6
7
  * 1. releasesStore uses queryStore as a data source
@@ -10,8 +11,9 @@ import {map} from 'rxjs'
10
11
  */
11
12
  // eslint-disable-next-line import/no-cycle
12
13
  import {getQueryState} from '../query/queryStore'
13
- import {bindActionByDataset, type BoundDatasetKey} from '../store/createActionBinder'
14
- import {createStateSourceAction} from '../store/createStateSourceAction'
14
+ import {bindActionByResource, type BoundResourceKey} from '../store/createActionBinder'
15
+ import {type SanityInstance} from '../store/createSanityInstance'
16
+ import {createStateSourceAction, type StateSource} from '../store/createStateSourceAction'
15
17
  import {defineStore, type StoreContext} from '../store/defineStore'
16
18
  import {sortReleases} from './utils/sortReleases'
17
19
 
@@ -39,7 +41,7 @@ export interface ReleasesStoreState {
39
41
  error?: unknown
40
42
  }
41
43
 
42
- export const releasesStore = defineStore<ReleasesStoreState, BoundDatasetKey>({
44
+ export const releasesStore = defineStore<ReleasesStoreState, BoundResourceKey>({
43
45
  name: 'Releases',
44
46
  getInitialState: (): ReleasesStoreState => ({
45
47
  activeReleases: undefined,
@@ -54,25 +56,33 @@ export const releasesStore = defineStore<ReleasesStoreState, BoundDatasetKey>({
54
56
  * Get the active releases from the store.
55
57
  * @internal
56
58
  */
57
- export const getActiveReleasesState = bindActionByDataset(
59
+ const _getActiveReleasesState = bindActionByResource(
58
60
  releasesStore,
59
61
  createStateSourceAction({
60
62
  selector: ({state}, _?) => state.activeReleases,
61
63
  }),
62
64
  )
63
65
 
66
+ /**
67
+ * Get the active releases from the store.
68
+ * @internal
69
+ */
70
+ export const getActiveReleasesState = (
71
+ instance: SanityInstance,
72
+ options: {resource: DocumentResource},
73
+ ): StateSource<ReleaseDocument[] | undefined> => _getActiveReleasesState(instance, options)
74
+
64
75
  const RELEASES_QUERY = 'releases::all()'
65
76
 
66
77
  const subscribeToReleases = ({
67
78
  instance,
68
79
  state,
69
- key: {projectId, dataset},
70
- }: StoreContext<ReleasesStoreState, BoundDatasetKey>) => {
80
+ key: {resource},
81
+ }: StoreContext<ReleasesStoreState, BoundResourceKey>) => {
71
82
  const {observable: releases$} = getQueryState<ReleaseDocument[]>(instance, {
72
83
  query: RELEASES_QUERY,
73
84
  perspective: 'raw',
74
- projectId,
75
- dataset,
85
+ resource,
76
86
  tag: 'releases',
77
87
  })
78
88
  return releases$