@sanity/sdk 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.
Files changed (241) hide show
  1. package/README.md +12 -0
  2. package/dist/_exports/_internal.d.ts +163 -0
  3. package/dist/_exports/_internal.d.ts.map +1 -0
  4. package/dist/_exports/_internal.js +332 -0
  5. package/dist/_exports/_internal.js.map +1 -0
  6. package/dist/_exports/agent.d.ts +65 -0
  7. package/dist/_exports/agent.d.ts.map +1 -0
  8. package/dist/_exports/agent.js +71 -0
  9. package/dist/_exports/agent.js.map +1 -0
  10. package/dist/_exports/comlink.d.ts +118 -0
  11. package/dist/_exports/comlink.d.ts.map +1 -0
  12. package/dist/_exports/comlink.js +69 -0
  13. package/dist/_exports/comlink.js.map +1 -0
  14. package/dist/authStore-CtE9bLHW.js +754 -0
  15. package/dist/authStore-CtE9bLHW.js.map +1 -0
  16. package/dist/authStore-DKFX8fn7.d.ts +3179 -0
  17. package/dist/authStore-DKFX8fn7.d.ts.map +1 -0
  18. package/dist/clientStore-BtE2-q2i.js +90 -0
  19. package/dist/clientStore-BtE2-q2i.js.map +1 -0
  20. package/dist/createSanityInstance-DUI1bGIg.d.ts +278 -0
  21. package/dist/createSanityInstance-DUI1bGIg.d.ts.map +1 -0
  22. package/dist/createStateSourceAction-BOKtqFNm.js +300 -0
  23. package/dist/createStateSourceAction-BOKtqFNm.js.map +1 -0
  24. package/dist/getEnv-D5RGkQLu.js +8 -0
  25. package/dist/getEnv-D5RGkQLu.js.map +1 -0
  26. package/dist/getNodeState-CR3__B2D.js +67 -0
  27. package/dist/getNodeState-CR3__B2D.js.map +1 -0
  28. package/dist/index.d.ts +3 -2332
  29. package/dist/index.js +4171 -4332
  30. package/dist/index.js.map +1 -1
  31. package/dist/logger-DAtJb5RQ.js +173 -0
  32. package/dist/logger-DAtJb5RQ.js.map +1 -0
  33. package/dist/object-CxXlSVg7.js +83 -0
  34. package/dist/object-CxXlSVg7.js.map +1 -0
  35. package/dist/queryStore-DPf9sN3V.js +1346 -0
  36. package/dist/queryStore-DPf9sN3V.js.map +1 -0
  37. package/dist/rolldown-runtime-vyAXikos.js +9 -0
  38. package/dist/setCleanupTimeout-BiM6q1KF.js +31 -0
  39. package/dist/setCleanupTimeout-BiM6q1KF.js.map +1 -0
  40. package/dist/telemetryManager-Dq_qCkeI.js +127 -0
  41. package/dist/telemetryManager-Dq_qCkeI.js.map +1 -0
  42. package/dist/version-BChjsi4u.js +9 -0
  43. package/dist/version-BChjsi4u.js.map +1 -0
  44. package/package.json +47 -52
  45. package/src/_exports/_internal.ts +27 -0
  46. package/src/_exports/agent.ts +19 -0
  47. package/src/_exports/comlink.ts +16 -0
  48. package/src/_exports/index.ts +125 -64
  49. package/src/access/checkPermissions.test.ts +55 -0
  50. package/src/access/checkPermissions.ts +54 -0
  51. package/src/agent/agentActions.test.ts +16 -60
  52. package/src/agent/agentActions.ts +25 -38
  53. package/src/applications/applications.test-d.ts +88 -0
  54. package/src/applications/applications.test.ts +130 -0
  55. package/src/applications/applications.ts +367 -0
  56. package/src/auth/authLogger.ts +30 -0
  57. package/src/auth/authStore.test.ts +194 -13
  58. package/src/auth/authStore.ts +58 -26
  59. package/src/auth/getOrganizationVerificationState.test.ts +18 -17
  60. package/src/auth/getOrganizationVerificationState.ts +4 -4
  61. package/src/auth/handleAuthCallback.test.ts +35 -1
  62. package/src/auth/handleAuthCallback.ts +25 -6
  63. package/src/auth/logout.test.ts +75 -2
  64. package/src/auth/logout.ts +23 -4
  65. package/src/auth/refreshStampedToken.test.ts +219 -469
  66. package/src/auth/refreshStampedToken.ts +79 -195
  67. package/src/auth/studioAuth.ts +1 -1
  68. package/src/auth/studioModeAuth.ts +2 -1
  69. package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +146 -13
  70. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +37 -6
  71. package/src/auth/subscribeToStorageEventsAndSetToken.test.ts +2 -0
  72. package/src/client/clientStore.test.ts +62 -37
  73. package/src/client/clientStore.ts +45 -75
  74. package/src/client/liveEvents.test.ts +151 -0
  75. package/src/client/liveEvents.ts +107 -0
  76. package/src/comlink/controller/actions/destroyController.test.ts +4 -1
  77. package/src/comlink/controller/actions/getOrCreateChannel.test.ts +4 -1
  78. package/src/comlink/controller/actions/getOrCreateChannel.ts +2 -2
  79. package/src/comlink/controller/actions/getOrCreateController.test.ts +4 -1
  80. package/src/comlink/controller/actions/releaseChannel.test.ts +1 -1
  81. package/src/comlink/controller/comlinkControllerStore.test.ts +4 -1
  82. package/src/comlink/node/actions/getOrCreateNode.test.ts +9 -3
  83. package/src/comlink/node/actions/getOrCreateNode.ts +2 -2
  84. package/src/comlink/node/actions/releaseNode.test.ts +7 -4
  85. package/src/comlink/node/comlinkNodeStore.test.ts +2 -2
  86. package/src/comlink/node/getNodeState.test.ts +1 -1
  87. package/src/comlink/node/getNodeState.ts +2 -1
  88. package/src/comments/addonDatasetStore.test.ts +215 -0
  89. package/src/comments/addonDatasetStore.ts +249 -0
  90. package/src/comments/buildCommentThreads.test.ts +83 -0
  91. package/src/comments/buildCommentThreads.ts +54 -0
  92. package/src/comments/commentActions.test.ts +540 -0
  93. package/src/comments/commentActions.ts +555 -0
  94. package/src/comments/commentFieldPath.test.ts +40 -0
  95. package/src/comments/commentFieldPath.ts +44 -0
  96. package/src/comments/commentsConstants.ts +80 -0
  97. package/src/comments/commentsStore.test.ts +419 -0
  98. package/src/comments/commentsStore.ts +483 -0
  99. package/src/comments/normalizeComment.test.ts +116 -0
  100. package/src/comments/normalizeComment.ts +45 -0
  101. package/src/comments/observeComments.test.ts +193 -0
  102. package/src/comments/observeComments.ts +113 -0
  103. package/src/comments/reducers.test.ts +277 -0
  104. package/src/comments/reducers.ts +316 -0
  105. package/src/comments/types.ts +249 -0
  106. package/src/comments/weakenReferences.test.ts +47 -0
  107. package/src/comments/weakenReferences.ts +29 -0
  108. package/src/config/__tests__/handles.test.ts +18 -12
  109. package/src/config/handles.ts +25 -7
  110. package/src/config/sanityConfig.ts +40 -82
  111. package/src/datasets/datasets.test.ts +2 -2
  112. package/src/datasets/datasets.ts +10 -4
  113. package/src/document/actions.test.ts +115 -33
  114. package/src/document/actions.ts +212 -15
  115. package/src/document/applyDocumentActions.test.ts +35 -13
  116. package/src/document/applyDocumentActions.ts +30 -9
  117. package/src/document/documentConstants.ts +15 -0
  118. package/src/document/documentStore.concurrency.test.ts +1306 -0
  119. package/src/document/documentStore.test.ts +753 -273
  120. package/src/document/documentStore.ts +197 -75
  121. package/src/document/events.test.ts +57 -2
  122. package/src/document/events.ts +82 -26
  123. package/src/document/listen.test.ts +56 -0
  124. package/src/document/listen.ts +74 -21
  125. package/src/document/listenerEventOperators.test.ts +311 -0
  126. package/src/document/listenerEventOperators.ts +217 -0
  127. package/src/document/patchOperations.test.ts +76 -2
  128. package/src/document/patchOperations.ts +60 -1
  129. package/src/document/permissions.test.ts +107 -60
  130. package/src/document/permissions.ts +44 -19
  131. package/src/document/processActions/create.ts +138 -0
  132. package/src/document/processActions/delete.ts +100 -0
  133. package/src/document/processActions/discard.ts +63 -0
  134. package/src/document/processActions/edit.ts +154 -0
  135. package/src/document/processActions/processActions.ts +218 -0
  136. package/src/document/processActions/publish.ts +120 -0
  137. package/src/document/processActions/releaseArchive.ts +77 -0
  138. package/src/document/processActions/releaseCreate.ts +59 -0
  139. package/src/document/processActions/releaseDelete.ts +65 -0
  140. package/src/document/processActions/releaseEdit.ts +37 -0
  141. package/src/document/processActions/releasePublish.ts +45 -0
  142. package/src/document/processActions/releaseSchedule.ts +87 -0
  143. package/src/document/processActions/releaseUtil.ts +31 -0
  144. package/src/document/processActions/shared.ts +308 -0
  145. package/src/document/processActions/unpublish.ts +85 -0
  146. package/src/document/processActions.test.ts +1129 -121
  147. package/src/document/reducers.test.ts +772 -64
  148. package/src/document/reducers.ts +205 -51
  149. package/src/document/resourceRules.test.ts +178 -0
  150. package/src/document/resourceRules.ts +117 -0
  151. package/src/document/sharedListener.test.ts +16 -14
  152. package/src/document/sharedListener.ts +24 -8
  153. package/src/document/util.test.ts +46 -0
  154. package/src/document/util.ts +50 -0
  155. package/src/favorites/favorites.test.ts +5 -6
  156. package/src/installations/installations.test-d.ts +73 -0
  157. package/src/installations/installations.test.ts +62 -0
  158. package/src/installations/installations.ts +206 -0
  159. package/src/organization/organization.test-d.ts +36 -0
  160. package/src/organization/organization.test.ts +138 -0
  161. package/src/organization/organization.ts +138 -0
  162. package/src/organizations/organizations.test-d.ts +56 -0
  163. package/src/organizations/organizations.test.ts +150 -0
  164. package/src/organizations/organizations.ts +107 -0
  165. package/src/presence/bifurTransport.test.ts +201 -9
  166. package/src/presence/bifurTransport.ts +98 -14
  167. package/src/presence/paths.test.ts +70 -0
  168. package/src/presence/paths.ts +41 -0
  169. package/src/presence/presenceStore.test.ts +915 -24
  170. package/src/presence/presenceStore.ts +576 -104
  171. package/src/presence/types.ts +175 -3
  172. package/src/preview/previewProjectionUtils.test.ts +9 -22
  173. package/src/preview/previewProjectionUtils.ts +7 -3
  174. package/src/preview/types.ts +0 -15
  175. package/src/project/project.test-d.ts +37 -0
  176. package/src/project/project.test.ts +157 -12
  177. package/src/project/project.ts +138 -25
  178. package/src/projection/getProjectionState.test.ts +18 -20
  179. package/src/projection/getProjectionState.ts +23 -3
  180. package/src/projection/projectionQuery.ts +5 -5
  181. package/src/projection/projectionStore.test.ts +1 -9
  182. package/src/projection/resolveProjection.test.ts +1 -2
  183. package/src/projection/resolveProjection.ts +16 -0
  184. package/src/projection/subscribeToStateAndFetchBatches.test.ts +1 -1
  185. package/src/projection/subscribeToStateAndFetchBatches.ts +32 -23
  186. package/src/projects/projects.test-d.ts +32 -0
  187. package/src/projects/projects.test.ts +108 -42
  188. package/src/projects/projects.ts +63 -27
  189. package/src/query/queryStore.test.ts +259 -123
  190. package/src/query/queryStore.ts +85 -69
  191. package/src/query/reducers.test.ts +0 -42
  192. package/src/query/reducers.ts +2 -18
  193. package/src/releases/getPerspectiveState.test.ts +17 -23
  194. package/src/releases/getPerspectiveState.ts +8 -20
  195. package/src/releases/observeReleases.test.ts +127 -0
  196. package/src/releases/observeReleases.ts +102 -0
  197. package/src/releases/releasesStore.test.ts +100 -53
  198. package/src/releases/releasesStore.ts +69 -44
  199. package/src/releases/utils/sortReleases.test.ts +38 -2
  200. package/src/releases/utils/sortReleases.ts +15 -10
  201. package/src/store/createActionBinder.test.ts +109 -90
  202. package/src/store/createActionBinder.ts +36 -28
  203. package/src/store/createSanityInstance.test.ts +15 -13
  204. package/src/store/createSanityInstance.ts +14 -2
  205. package/src/store/createStateSourceAction.test.ts +64 -2
  206. package/src/store/createStateSourceAction.ts +38 -43
  207. package/src/store/createStoreInstance.test.ts +4 -2
  208. package/src/store/fetcherStore.test-d.ts +121 -0
  209. package/src/store/fetcherStore.test.ts +299 -0
  210. package/src/store/fetcherStore.ts +801 -0
  211. package/src/telemetry/environment.test.ts +119 -0
  212. package/src/telemetry/environment.ts +92 -0
  213. package/src/telemetry/events.ts +42 -0
  214. package/src/telemetry/initTelemetry.test.ts +432 -0
  215. package/src/telemetry/initTelemetry.ts +218 -0
  216. package/src/telemetry/telemetryManager.test.ts +327 -0
  217. package/src/telemetry/telemetryManager.ts +199 -0
  218. package/src/users/reducers.test.ts +3 -1
  219. package/src/users/reducers.ts +5 -6
  220. package/src/users/types.ts +4 -4
  221. package/src/users/usersStore.test.ts +16 -12
  222. package/src/users/usersStore.ts +5 -1
  223. package/src/utils/buildQuery.test.ts +14 -0
  224. package/src/utils/buildQuery.ts +17 -0
  225. package/src/utils/createFetcherStore.test.ts +7 -5
  226. package/src/utils/createFetcherStore.ts +8 -5
  227. package/src/utils/getStagingApiHost.test.ts +21 -0
  228. package/src/utils/getStagingApiHost.ts +14 -0
  229. package/src/utils/ids.test.ts +1 -29
  230. package/src/utils/ids.ts +0 -10
  231. package/src/utils/includeShape.ts +36 -0
  232. package/src/utils/isImportError.test.ts +72 -0
  233. package/src/utils/isImportError.ts +34 -0
  234. package/src/utils/logger.test.ts +12 -0
  235. package/src/utils/logger.ts +8 -3
  236. package/src/utils/object.test.ts +95 -0
  237. package/src/utils/object.ts +142 -0
  238. package/src/utils/setCleanupTimeout.ts +37 -0
  239. package/src/document/processActions.ts +0 -707
  240. package/src/utils/defineIntent.test.ts +0 -477
  241. package/src/utils/defineIntent.ts +0 -244
@@ -5,7 +5,7 @@ import {afterEach, beforeEach, describe, it} from 'vitest'
5
5
  import {getClientState} from '../client/clientStore'
6
6
  import {createSanityInstance, type SanityInstance} from '../store/createSanityInstance'
7
7
  import {type StateSource} from '../store/createStateSourceAction'
8
- import {resolveProjects} from './projects'
8
+ import {getProjectsCacheKey, projects} from './projects'
9
9
 
10
10
  vi.mock('../client/clientStore')
11
11
 
@@ -13,64 +13,130 @@ describe('projects', () => {
13
13
  let instance: SanityInstance
14
14
 
15
15
  beforeEach(() => {
16
- instance = createSanityInstance()
16
+ instance = createSanityInstance({projectId: 'p', dataset: 'd'})
17
17
  })
18
18
 
19
19
  afterEach(() => {
20
20
  instance.dispose()
21
21
  })
22
22
 
23
- it('calls the `client.observable.projects.list` method on the client and returns the result', async () => {
24
- const projects = [{id: 'a'}, {id: 'b'}]
25
- const list = vi.fn().mockReturnValue(of(projects))
23
+ it('calls `client.observable.request` against `/projects` and returns the result', async () => {
24
+ const list = [{id: 'a'}, {id: 'b'}]
25
+ const request = vi.fn().mockReturnValue(of(list))
26
26
 
27
27
  const mockClient = {
28
- observable: {
29
- projects: {list} as unknown as SanityClient['observable']['projects'],
30
- },
28
+ observable: {request} as unknown as SanityClient['observable'],
31
29
  } as SanityClient
32
30
 
33
31
  vi.mocked(getClientState).mockReturnValue({
34
32
  observable: of(mockClient),
35
33
  } as StateSource<SanityClient>)
36
34
 
37
- const result = await resolveProjects(instance)
38
- expect(result).toEqual(projects)
39
- expect(list).toHaveBeenCalledWith({includeMembers: false, organizationId: undefined})
35
+ const result = await projects.resolveState(instance)
36
+ expect(result).toEqual(list)
37
+ expect(request).toHaveBeenCalledWith({
38
+ uri: '/projects',
39
+ query: {includeMembers: 'false', includeFeatures: 'true', onlyExplicitMembership: 'false'},
40
+ tag: 'projects.list',
41
+ })
40
42
  })
41
- })
42
43
 
43
- describe('projects cache key generation', () => {
44
- it('generates correct cache keys for different parameter combinations', async () => {
45
- // Test the getKey function directly by creating a mock store
46
- const mockGetKey = (
47
- _instance: SanityInstance,
48
- options?: {organizationId?: string; includeMembers?: boolean},
49
- ) => {
50
- const orgKey = options?.organizationId ? `:org:${options.organizationId}` : ''
51
- const membersKey = options?.includeMembers === false ? ':no-members' : ''
52
- return `projects${orgKey}${membersKey}`
53
- }
54
-
55
- const mockInstance = {} as SanityInstance
56
-
57
- // Test default behavior (no options)
58
- const defaultKey = mockGetKey(mockInstance)
59
- expect(defaultKey).toBe('projects')
60
-
61
- // Test with organizationId only
62
- const orgKey = mockGetKey(mockInstance, {organizationId: 'org123'})
63
- expect(orgKey).toBe('projects:org:org123')
64
-
65
- // Test with includeMembers: false only
66
- const noMembersKey = mockGetKey(mockInstance, {includeMembers: false})
67
- expect(noMembersKey).toBe('projects:no-members')
68
-
69
- // Test with both parameters
70
- const bothKey = mockGetKey(mockInstance, {
44
+ it('serializes query params (booleans → strings) and omits undefined values', async () => {
45
+ const request = vi.fn().mockReturnValue(of([]))
46
+ const mockClient = {
47
+ observable: {request} as unknown as SanityClient['observable'],
48
+ } as SanityClient
49
+
50
+ vi.mocked(getClientState).mockReturnValue({
51
+ observable: of(mockClient),
52
+ } as StateSource<SanityClient>)
53
+
54
+ await projects.resolveState(instance, {
71
55
  organizationId: 'org123',
72
- includeMembers: false,
56
+ includeMembers: true,
57
+ includeFeatures: false,
73
58
  })
74
- expect(bothKey).toBe('projects:org:org123:no-members')
59
+
60
+ expect(request).toHaveBeenCalledWith({
61
+ uri: '/projects',
62
+ query: {
63
+ organizationId: 'org123',
64
+ includeMembers: 'true',
65
+ includeFeatures: 'false',
66
+ onlyExplicitMembership: 'false',
67
+ },
68
+ tag: 'projects.list',
69
+ })
70
+ })
71
+ })
72
+
73
+ describe('projects cache key generation', () => {
74
+ let instance: SanityInstance
75
+
76
+ beforeEach(() => {
77
+ instance = createSanityInstance({projectId: 'p', dataset: 'd'})
78
+ })
79
+
80
+ afterEach(() => {
81
+ instance.dispose()
82
+ })
83
+
84
+ it('default call includes :features (default-true) and excludes :members (default-false)', () => {
85
+ expect(getProjectsCacheKey(instance)).toBe('projects:features')
86
+ })
87
+
88
+ it('treats undefined and the matching default as the same key', () => {
89
+ expect(getProjectsCacheKey(instance)).toBe(
90
+ getProjectsCacheKey(instance, {includeMembers: false, includeFeatures: true}),
91
+ )
92
+ })
93
+
94
+ it('treats raw and explicit defaults equivalently', () => {
95
+ expect(getProjectsCacheKey(instance, {organizationId: 'org123'})).toBe(
96
+ getProjectsCacheKey(instance, {
97
+ organizationId: 'org123',
98
+ includeMembers: false,
99
+ includeFeatures: true,
100
+ onlyExplicitMembership: false,
101
+ }),
102
+ )
103
+ })
104
+
105
+ it('explicit includeFeatures: false drops the :features segment', () => {
106
+ expect(getProjectsCacheKey(instance, {includeFeatures: false})).toBe('projects')
107
+ })
108
+
109
+ it('appends an org segment when organizationId is set', () => {
110
+ expect(getProjectsCacheKey(instance, {organizationId: 'org123'})).toBe(
111
+ 'projects:org:org123:features',
112
+ )
113
+ })
114
+
115
+ it('appends :members when includeMembers is true', () => {
116
+ expect(getProjectsCacheKey(instance, {includeMembers: true})).toBe('projects:members:features')
117
+ })
118
+
119
+ it('combines all segments in order', () => {
120
+ expect(
121
+ getProjectsCacheKey(instance, {
122
+ organizationId: 'org123',
123
+ includeMembers: true,
124
+ includeFeatures: true,
125
+ onlyExplicitMembership: true,
126
+ }),
127
+ ).toBe('projects:org:org123:members:features:explicit')
128
+ })
129
+
130
+ it('produces distinct keys for each meaningful option permutation', () => {
131
+ const keys = new Set([
132
+ getProjectsCacheKey(instance),
133
+ getProjectsCacheKey(instance, {includeMembers: true}),
134
+ getProjectsCacheKey(instance, {includeFeatures: false}),
135
+ getProjectsCacheKey(instance, {includeMembers: true, includeFeatures: false}),
136
+ getProjectsCacheKey(instance, {onlyExplicitMembership: true}),
137
+ getProjectsCacheKey(instance, {organizationId: 'a'}),
138
+ getProjectsCacheKey(instance, {organizationId: 'b'}),
139
+ ])
140
+ expect(keys.size).toBe(7)
75
141
  })
76
142
  })
@@ -1,35 +1,71 @@
1
1
  import {switchMap} from 'rxjs'
2
2
 
3
3
  import {getClientState} from '../client/clientStore'
4
- import {createFetcherStore} from '../utils/createFetcherStore'
4
+ import {type Project} from '../project/project'
5
+ import {type SanityInstance} from '../store/createSanityInstance'
6
+ import {defineFetcher} from '../store/fetcherStore'
7
+ import {buildQuery} from '../utils/buildQuery'
5
8
 
6
9
  const API_VERSION = 'v2025-02-19'
7
10
 
8
- const projects = createFetcherStore({
9
- name: 'Projects',
10
- getKey: (_instance, options?: {organizationId?: string; includeMembers?: boolean}) => {
11
- const orgKey = options?.organizationId ? `:org:${options.organizationId}` : ''
12
- const membersKey = options?.includeMembers === false ? ':no-members' : ''
13
- return `projects${orgKey}${membersKey}`
14
- },
15
- fetcher: (instance) => (options?: {organizationId?: string; includeMembers?: boolean}) =>
16
- getClientState(instance, {
17
- apiVersion: API_VERSION,
18
- scope: 'global',
19
- requestTagPrefix: 'sanity.sdk.projects',
20
- }).observable.pipe(
21
- switchMap((client) => {
22
- const organizationId = options?.organizationId
23
- return client.observable.projects.list({
24
- // client method has a type that expects false | undefined
25
- includeMembers: !options?.includeMembers ? false : undefined,
26
- organizationId,
27
- })
28
- }),
11
+ /** @public */
12
+ export interface ProjectsOptions<
13
+ IncludeMembers extends boolean = false,
14
+ IncludeFeatures extends boolean = true,
15
+ > {
16
+ organizationId?: string
17
+ includeMembers?: IncludeMembers
18
+ includeFeatures?: IncludeFeatures
19
+ onlyExplicitMembership?: boolean
20
+ }
21
+
22
+ function normalizeProjectsOptions(options?: ProjectsOptions<boolean, boolean>) {
23
+ return {
24
+ organizationId: options?.organizationId,
25
+ includeMembers: options?.includeMembers ?? false,
26
+ includeFeatures: options?.includeFeatures ?? true,
27
+ onlyExplicitMembership: options?.onlyExplicitMembership ?? false,
28
+ }
29
+ }
30
+
31
+ /** @internal */
32
+ export function getProjectsCacheKey(
33
+ _instance: SanityInstance,
34
+ options?: ProjectsOptions<boolean, boolean>,
35
+ ): string {
36
+ const {organizationId, includeMembers, includeFeatures, onlyExplicitMembership} =
37
+ normalizeProjectsOptions(options)
38
+ const orgKey = organizationId ? `:org:${organizationId}` : ''
39
+ const membersKey = includeMembers ? ':members' : ''
40
+ const featuresKey = includeFeatures ? ':features' : ''
41
+ const explicitKey = onlyExplicitMembership ? ':explicit' : ''
42
+ return `projects${orgKey}${membersKey}${featuresKey}${explicitKey}`
43
+ }
44
+
45
+ /**
46
+ * Fetcher for the current user's projects (`GET /projects`), on the shared
47
+ * fetcher cache.
48
+ *
49
+ * @internal
50
+ */
51
+ export const projects = defineFetcher<
52
+ [options?: ProjectsOptions<boolean, boolean>],
53
+ Project<boolean, boolean>[]
54
+ >({
55
+ name: 'projects',
56
+ getKey: getProjectsCacheKey,
57
+ fetch: (instance) => (options) =>
58
+ getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(
59
+ switchMap((client) =>
60
+ client.observable.request<Project<boolean, boolean>[]>({
61
+ uri: '/projects',
62
+ query: buildQuery(normalizeProjectsOptions(options)),
63
+ tag: 'projects.list',
64
+ }),
65
+ ),
29
66
  ),
67
+ tags: (data) => [
68
+ {type: 'project', id: 'LIST'},
69
+ ...data.map((project) => ({type: 'project', id: project.id})),
70
+ ],
30
71
  })
31
-
32
- /** @public */
33
- export const getProjectsState = projects.getState
34
- /** @public */
35
- export const resolveProjects = projects.resolveState