@sanity/sdk 3.0.0-rc.0 → 3.0.0-rc.1

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 (197) hide show
  1. package/dist/_chunks-dts/createGroqSearchFilter.d.ts +1147 -0
  2. package/dist/_chunks-dts/createGroqSearchFilter.d.ts.map +1 -0
  3. package/dist/_chunks-es/_internal.js +134 -0
  4. package/dist/_chunks-es/_internal.js.map +1 -0
  5. package/dist/_chunks-es/createGroqSearchFilter.js +1864 -0
  6. package/dist/_chunks-es/createGroqSearchFilter.js.map +1 -0
  7. package/dist/_chunks-es/telemetryManager.js +93 -0
  8. package/dist/_chunks-es/telemetryManager.js.map +1 -0
  9. package/dist/_exports/_internal.d.ts +95 -0
  10. package/dist/_exports/_internal.d.ts.map +1 -0
  11. package/dist/_exports/_internal.js +24 -0
  12. package/dist/_exports/_internal.js.map +1 -0
  13. package/dist/index.d.ts +1079 -1076
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +1967 -2302
  16. package/dist/index.js.map +1 -1
  17. package/package.json +48 -47
  18. package/src/_exports/_internal.ts +26 -0
  19. package/src/_exports/index.ts +120 -11
  20. package/src/access/checkPermissions.test.ts +55 -0
  21. package/src/access/checkPermissions.ts +54 -0
  22. package/src/agent/agentActions.test.ts +16 -60
  23. package/src/agent/agentActions.ts +25 -38
  24. package/src/applications/applications.test-d.ts +83 -0
  25. package/src/applications/applications.test.ts +130 -0
  26. package/src/applications/applications.ts +364 -0
  27. package/src/applications/userApplications.test.ts +126 -0
  28. package/src/applications/userApplications.ts +261 -0
  29. package/src/auth/authLogger.ts +30 -0
  30. package/src/auth/authMode.test.ts +25 -0
  31. package/src/auth/authMode.ts +6 -3
  32. package/src/auth/authStore.test.ts +194 -13
  33. package/src/auth/authStore.ts +59 -26
  34. package/src/auth/getOrganizationVerificationState.test.ts +18 -17
  35. package/src/auth/getOrganizationVerificationState.ts +4 -4
  36. package/src/auth/handleAuthCallback.test.ts +35 -1
  37. package/src/auth/handleAuthCallback.ts +25 -6
  38. package/src/auth/logout.test.ts +75 -2
  39. package/src/auth/logout.ts +23 -4
  40. package/src/auth/refreshStampedToken.test.ts +219 -469
  41. package/src/auth/refreshStampedToken.ts +79 -195
  42. package/src/auth/studioAuth.ts +1 -1
  43. package/src/auth/studioModeAuth.ts +2 -1
  44. package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +146 -13
  45. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +37 -6
  46. package/src/auth/subscribeToStorageEventsAndSetToken.test.ts +2 -0
  47. package/src/client/clientStore.test.ts +62 -37
  48. package/src/client/clientStore.ts +45 -75
  49. package/src/client/liveEvents.test.ts +151 -0
  50. package/src/client/liveEvents.ts +107 -0
  51. package/src/comlink/controller/actions/destroyController.test.ts +4 -1
  52. package/src/comlink/controller/actions/getOrCreateChannel.test.ts +4 -1
  53. package/src/comlink/controller/actions/getOrCreateChannel.ts +2 -2
  54. package/src/comlink/controller/actions/getOrCreateController.test.ts +4 -1
  55. package/src/comlink/controller/actions/releaseChannel.test.ts +1 -1
  56. package/src/comlink/controller/comlinkControllerStore.test.ts +4 -1
  57. package/src/comlink/node/actions/getOrCreateNode.test.ts +9 -3
  58. package/src/comlink/node/actions/getOrCreateNode.ts +2 -2
  59. package/src/comlink/node/actions/releaseNode.test.ts +7 -4
  60. package/src/comlink/node/comlinkNodeStore.test.ts +2 -2
  61. package/src/comlink/node/getNodeState.test.ts +1 -1
  62. package/src/comlink/node/getNodeState.ts +2 -1
  63. package/src/config/__tests__/handles.test.ts +18 -12
  64. package/src/config/handles.ts +25 -7
  65. package/src/config/sanityConfig.ts +109 -79
  66. package/src/datasets/datasets.test.ts +2 -2
  67. package/src/datasets/datasets.ts +10 -4
  68. package/src/document/actions.test.ts +115 -33
  69. package/src/document/actions.ts +212 -15
  70. package/src/document/applyDocumentActions.test.ts +38 -12
  71. package/src/document/applyDocumentActions.ts +30 -9
  72. package/src/document/documentConstants.ts +7 -0
  73. package/src/document/documentStore.concurrency.test.ts +1306 -0
  74. package/src/document/documentStore.test.ts +673 -278
  75. package/src/document/documentStore.ts +162 -71
  76. package/src/document/events.test.ts +57 -2
  77. package/src/document/events.ts +82 -26
  78. package/src/document/listen.test.ts +56 -0
  79. package/src/document/listen.ts +74 -21
  80. package/src/document/listenerEventOperators.test.ts +311 -0
  81. package/src/document/listenerEventOperators.ts +217 -0
  82. package/src/document/patchOperations.test.ts +49 -2
  83. package/src/document/patchOperations.ts +50 -0
  84. package/src/document/permissions.test.ts +105 -60
  85. package/src/document/permissions.ts +44 -19
  86. package/src/document/processActions/create.ts +138 -0
  87. package/src/document/processActions/delete.ts +100 -0
  88. package/src/document/processActions/discard.ts +63 -0
  89. package/src/document/processActions/edit.ts +154 -0
  90. package/src/document/processActions/processActions.ts +218 -0
  91. package/src/document/processActions/publish.ts +120 -0
  92. package/src/document/processActions/releaseArchive.ts +77 -0
  93. package/src/document/processActions/releaseCreate.ts +59 -0
  94. package/src/document/processActions/releaseDelete.ts +65 -0
  95. package/src/document/processActions/releaseEdit.ts +37 -0
  96. package/src/document/processActions/releasePublish.ts +45 -0
  97. package/src/document/processActions/releaseSchedule.ts +87 -0
  98. package/src/document/processActions/releaseUtil.ts +31 -0
  99. package/src/document/processActions/shared.ts +308 -0
  100. package/src/document/processActions/unpublish.ts +85 -0
  101. package/src/document/processActions.test.ts +1129 -121
  102. package/src/document/reducers.test.ts +639 -64
  103. package/src/document/reducers.ts +187 -48
  104. package/src/document/resourceRules.test.ts +178 -0
  105. package/src/document/resourceRules.ts +117 -0
  106. package/src/document/sharedListener.test.ts +16 -14
  107. package/src/document/sharedListener.ts +24 -8
  108. package/src/document/util.ts +14 -0
  109. package/src/favorites/favorites.test.ts +5 -6
  110. package/src/installations/installations.test-d.ts +68 -0
  111. package/src/installations/installations.test.ts +62 -0
  112. package/src/installations/installations.ts +202 -0
  113. package/src/organization/organization.test-d.ts +36 -0
  114. package/src/organization/organization.test.ts +138 -0
  115. package/src/organization/organization.ts +138 -0
  116. package/src/organizations/organizations.test-d.ts +56 -0
  117. package/src/organizations/organizations.test.ts +150 -0
  118. package/src/organizations/organizations.ts +107 -0
  119. package/src/presence/bifurTransport.test.ts +46 -6
  120. package/src/presence/bifurTransport.ts +19 -2
  121. package/src/presence/presenceStore.test.ts +94 -23
  122. package/src/presence/presenceStore.ts +85 -29
  123. package/src/preview/getPreviewState.test.ts +137 -0
  124. package/src/preview/getPreviewState.ts +69 -0
  125. package/src/preview/previewProjectionUtils.test.ts +9 -22
  126. package/src/preview/previewProjectionUtils.ts +7 -3
  127. package/src/preview/resolvePreview.test.ts +64 -0
  128. package/src/preview/resolvePreview.ts +43 -0
  129. package/src/preview/types.ts +10 -0
  130. package/src/project/project.test-d.ts +37 -0
  131. package/src/project/project.test.ts +157 -12
  132. package/src/project/project.ts +138 -25
  133. package/src/projection/getProjectionState.test.ts +18 -20
  134. package/src/projection/getProjectionState.ts +23 -3
  135. package/src/projection/projectionQuery.ts +5 -5
  136. package/src/projection/projectionStore.test.ts +1 -1
  137. package/src/projection/resolveProjection.test.ts +1 -2
  138. package/src/projection/resolveProjection.ts +16 -0
  139. package/src/projection/subscribeToStateAndFetchBatches.test.ts +1 -1
  140. package/src/projection/subscribeToStateAndFetchBatches.ts +32 -23
  141. package/src/projection/types.ts +8 -0
  142. package/src/projects/projects.test-d.ts +32 -0
  143. package/src/projects/projects.test.ts +108 -42
  144. package/src/projects/projects.ts +63 -27
  145. package/src/query/queryStore.test.ts +259 -123
  146. package/src/query/queryStore.ts +78 -63
  147. package/src/query/reducers.test.ts +0 -42
  148. package/src/query/reducers.ts +2 -18
  149. package/src/releases/getPerspectiveState.test.ts +17 -23
  150. package/src/releases/getPerspectiveState.ts +8 -20
  151. package/src/releases/observeReleases.test.ts +127 -0
  152. package/src/releases/observeReleases.ts +102 -0
  153. package/src/releases/releasesStore.test.ts +100 -53
  154. package/src/releases/releasesStore.ts +69 -44
  155. package/src/releases/utils/sortReleases.test.ts +38 -2
  156. package/src/releases/utils/sortReleases.ts +15 -10
  157. package/src/store/createActionBinder.test.ts +87 -90
  158. package/src/store/createActionBinder.ts +79 -25
  159. package/src/store/createSanityInstance.test.ts +83 -13
  160. package/src/store/createSanityInstance.ts +77 -2
  161. package/src/store/createStateSourceAction.test.ts +64 -2
  162. package/src/store/createStateSourceAction.ts +39 -44
  163. package/src/store/createStoreInstance.test.ts +4 -2
  164. package/src/store/fetcherStore.test-d.ts +121 -0
  165. package/src/store/fetcherStore.test.ts +299 -0
  166. package/src/store/fetcherStore.ts +801 -0
  167. package/src/telemetry/environment.test.ts +119 -0
  168. package/src/telemetry/environment.ts +92 -0
  169. package/src/telemetry/events.ts +42 -0
  170. package/src/telemetry/initTelemetry.test.ts +432 -0
  171. package/src/telemetry/initTelemetry.ts +218 -0
  172. package/src/telemetry/telemetryManager.test.ts +327 -0
  173. package/src/telemetry/telemetryManager.ts +199 -0
  174. package/src/users/reducers.test.ts +6 -1
  175. package/src/users/reducers.ts +5 -6
  176. package/src/users/types.ts +4 -4
  177. package/src/users/usersStore.test.ts +16 -12
  178. package/src/users/usersStore.ts +5 -1
  179. package/src/utils/buildQuery.test.ts +14 -0
  180. package/src/utils/buildQuery.ts +17 -0
  181. package/src/utils/createFetcherStore.test.ts +7 -5
  182. package/src/utils/createFetcherStore.ts +8 -5
  183. package/src/utils/getStagingApiHost.test.ts +21 -0
  184. package/src/utils/getStagingApiHost.ts +14 -0
  185. package/src/utils/ids.test.ts +1 -29
  186. package/src/utils/ids.ts +0 -10
  187. package/src/utils/includeShape.ts +36 -0
  188. package/src/utils/isImportError.test.ts +72 -0
  189. package/src/utils/isImportError.ts +34 -0
  190. package/src/utils/logger.test.ts +12 -0
  191. package/src/utils/logger.ts +8 -3
  192. package/src/utils/object.test.ts +95 -0
  193. package/src/utils/object.ts +142 -0
  194. package/src/utils/setCleanupTimeout.ts +37 -0
  195. package/src/document/processActions.ts +0 -707
  196. package/src/utils/defineIntent.test.ts +0 -477
  197. package/src/utils/defineIntent.ts +0 -244
@@ -1,7 +1,7 @@
1
1
  import {type ClientConfig, createClient, type SanityClient} from '@sanity/client'
2
2
  import {type CurrentUser} from '@sanity/types'
3
3
  import {NEVER, type Subscription} from 'rxjs'
4
- import {afterEach, beforeEach, describe, it, vi} from 'vitest'
4
+ import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest'
5
5
 
6
6
  import {createSanityInstance} from '../store/createSanityInstance'
7
7
  import {AuthStateType} from './authStateType'
@@ -46,6 +46,24 @@ vi.mock('./studioModeAuth', async (importOriginal) => {
46
46
 
47
47
  vi.mock('./subscribeToStateAndFetchCurrentUser')
48
48
  vi.mock('./subscribeToStorageEventsAndSetToken')
49
+ // Mock logger to prevent actual logging during tests
50
+ vi.mock('../utils/logger', async (importOriginal) => {
51
+ const original = await importOriginal<typeof import('../utils/logger')>()
52
+ return {
53
+ ...original,
54
+ createLogger: vi.fn(() => ({
55
+ info: vi.fn(),
56
+ debug: vi.fn(),
57
+ warn: vi.fn(),
58
+ error: vi.fn(),
59
+ trace: vi.fn(),
60
+ })),
61
+ }
62
+ })
63
+
64
+ // Import createLogger after mocking
65
+ // eslint-disable-next-line import-x/first
66
+ import {createLogger} from '../utils/logger'
49
67
 
50
68
  describe('authStore', () => {
51
69
  // Global beforeEach and afterEach for all tests
@@ -73,6 +91,35 @@ describe('authStore', () => {
73
91
  instance?.dispose()
74
92
  })
75
93
 
94
+ it('uses staging apiHost when __SANITY_STAGING__ is true and no explicit apiHost', () => {
95
+ vi.stubGlobal('__SANITY_STAGING__', true)
96
+
97
+ instance = createSanityInstance({
98
+ projectId: 'p',
99
+ dataset: 'd',
100
+ })
101
+
102
+ const {options} = authStore.getInitialState(instance, null)
103
+ expect(options.apiHost).toBe('https://api.sanity.work')
104
+
105
+ vi.unstubAllGlobals()
106
+ })
107
+
108
+ it('prefers explicit apiHost over __SANITY_STAGING__', () => {
109
+ vi.stubGlobal('__SANITY_STAGING__', true)
110
+
111
+ instance = createSanityInstance({
112
+ projectId: 'p',
113
+ dataset: 'd',
114
+ auth: {apiHost: 'https://custom.host'},
115
+ })
116
+
117
+ const {options} = authStore.getInitialState(instance, null)
118
+ expect(options.apiHost).toBe('https://custom.host')
119
+
120
+ vi.unstubAllGlobals()
121
+ })
122
+
76
123
  it('sets initial options onto state', () => {
77
124
  const apiHost = 'test-api-host'
78
125
  const callbackUrl = '/login/callback'
@@ -85,6 +132,8 @@ describe('authStore', () => {
85
132
  const storageArea = {} as Storage
86
133
 
87
134
  instance = createSanityInstance({
135
+ projectId: 'p',
136
+ dataset: 'd',
88
137
  auth: {
89
138
  apiHost,
90
139
  callbackUrl,
@@ -113,6 +162,8 @@ describe('authStore', () => {
113
162
  const context = {mode: 'test', env: 'staging', orgId: 'abc'}
114
163
  const initialLocationHref = `https://example.com/?_context=${encodeURIComponent(JSON.stringify(context))}`
115
164
  instance = createSanityInstance({
165
+ projectId: 'p',
166
+ dataset: 'd',
116
167
  auth: {initialLocationHref},
117
168
  })
118
169
 
@@ -126,6 +177,8 @@ describe('authStore', () => {
126
177
  const expectedContext = {mode: 'test', env: 'staging', orgId: 'abc'}
127
178
  const initialLocationHref = `https://example.com/?_context=${encodeURIComponent(JSON.stringify(context))}`
128
179
  instance = createSanityInstance({
180
+ projectId: 'p',
181
+ dataset: 'd',
129
182
  auth: {initialLocationHref},
130
183
  })
131
184
 
@@ -138,6 +191,8 @@ describe('authStore', () => {
138
191
  const initialLocationHref = `https://example.com/?_context=invalid-json`
139
192
  const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
140
193
  instance = createSanityInstance({
194
+ projectId: 'p',
195
+ dataset: 'd',
141
196
  auth: {initialLocationHref},
142
197
  })
143
198
 
@@ -154,6 +209,8 @@ describe('authStore', () => {
154
209
  it('rejects array _context and falls back to standalone mode', () => {
155
210
  const initialLocationHref = `https://example.com/?_context=${encodeURIComponent(JSON.stringify(['a', 'b']))}`
156
211
  instance = createSanityInstance({
212
+ projectId: 'p',
213
+ dataset: 'd',
157
214
  auth: {initialLocationHref},
158
215
  })
159
216
 
@@ -166,6 +223,8 @@ describe('authStore', () => {
166
223
  it('rejects empty object _context and falls back to standalone mode', () => {
167
224
  const initialLocationHref = `https://example.com/?_context=${encodeURIComponent(JSON.stringify({}))}`
168
225
  instance = createSanityInstance({
226
+ projectId: 'p',
227
+ dataset: 'd',
169
228
  auth: {initialLocationHref},
170
229
  })
171
230
 
@@ -180,6 +239,8 @@ describe('authStore', () => {
180
239
  const context = {mode: 'dashboard'}
181
240
  const initialLocationHref = `https://example.com/?_context=${encodeURIComponent(JSON.stringify(context))}`
182
241
  instance = createSanityInstance({
242
+ projectId: 'p',
243
+ dataset: 'd',
183
244
  auth: {
184
245
  token,
185
246
  initialLocationHref,
@@ -195,6 +256,8 @@ describe('authStore', () => {
195
256
  const context = {orgId: 'org1'}
196
257
  const initialLocationHref = `https://example.com/?_context=${encodeURIComponent(JSON.stringify(context))}`
197
258
  instance = createSanityInstance({
259
+ projectId: 'p',
260
+ dataset: 'd',
198
261
  auth: {initialLocationHref},
199
262
  })
200
263
 
@@ -207,7 +270,10 @@ describe('authStore', () => {
207
270
 
208
271
  it('sets to logged in from storage token when NOT in dashboard', () => {
209
272
  const storageToken = 'storage-token'
210
- instance = createSanityInstance()
273
+ instance = createSanityInstance({
274
+ projectId: 'p',
275
+ dataset: 'd',
276
+ })
211
277
 
212
278
  vi.mocked(getAuthCode).mockReturnValue(null)
213
279
  vi.mocked(getTokenFromStorage).mockReturnValue(storageToken)
@@ -222,6 +288,8 @@ describe('authStore', () => {
222
288
  const context = {mode: 'dashboard'}
223
289
  const initialLocationHref = `https://example.com/?_context=${encodeURIComponent(JSON.stringify(context))}`
224
290
  instance = createSanityInstance({
291
+ projectId: 'p',
292
+ dataset: 'd',
225
293
  auth: {initialLocationHref},
226
294
  })
227
295
 
@@ -234,7 +302,10 @@ describe('authStore', () => {
234
302
  })
235
303
 
236
304
  it('sets the state to logged out when no token, code, or context', () => {
237
- instance = createSanityInstance()
305
+ instance = createSanityInstance({
306
+ projectId: 'p',
307
+ dataset: 'd',
308
+ })
238
309
 
239
310
  vi.mocked(getAuthCode).mockReturnValue(null)
240
311
  vi.mocked(getTokenFromStorage).mockReturnValue(null)
@@ -256,8 +327,10 @@ describe('authStore', () => {
256
327
  vi.mocked(getStudioTokenFromLocalStorage).mockReturnValue(studioToken)
257
328
 
258
329
  instance = createSanityInstance({
259
- studio: {projectId},
260
- auth: {storageArea: mockStorage},
330
+ projectId,
331
+ dataset: 'd',
332
+ studio: {},
333
+ auth: {storageArea: mockStorage}, // Provide mock storage
261
334
  })
262
335
 
263
336
  const {authState, options} = authStore.getInitialState(instance, null)
@@ -266,6 +339,54 @@ describe('authStore', () => {
266
339
  expect(options.authMethod).toBe('localstorage')
267
340
  })
268
341
 
342
+ it('logs auth initialized in logged out state when no token available', () => {
343
+ instance = createSanityInstance({
344
+ projectId: 'p',
345
+ dataset: 'd',
346
+ })
347
+
348
+ vi.mocked(getAuthCode).mockReturnValue(null)
349
+ vi.mocked(getTokenFromStorage).mockReturnValue(null)
350
+ vi.mocked(getTokenFromLocation).mockReturnValue(null)
351
+
352
+ const {authState} = authStore.getInitialState(instance, null)
353
+ expect(authState.type).toBe(AuthStateType.LOGGED_OUT)
354
+ // Logger should have been called
355
+ expect(createLogger).toHaveBeenCalled()
356
+ })
357
+
358
+ it('logs when auth initialized with storage token', () => {
359
+ const storageToken = 'storage-token'
360
+ instance = createSanityInstance({
361
+ projectId: 'p',
362
+ dataset: 'd',
363
+ })
364
+
365
+ vi.mocked(getAuthCode).mockReturnValue(null)
366
+ vi.mocked(getTokenFromStorage).mockReturnValue(storageToken)
367
+ vi.mocked(getTokenFromLocation).mockReturnValue(null)
368
+
369
+ const {authState} = authStore.getInitialState(instance, null)
370
+ expect(authState).toMatchObject({type: AuthStateType.LOGGED_IN, token: storageToken})
371
+ // Logger should have been called
372
+ expect(createLogger).toHaveBeenCalled()
373
+ })
374
+
375
+ it('logs when auth initialized with logging in state', () => {
376
+ instance = createSanityInstance({
377
+ projectId: 'p',
378
+ dataset: 'd',
379
+ })
380
+
381
+ vi.mocked(getAuthCode).mockReturnValue('test-code')
382
+ vi.mocked(getTokenFromLocation).mockReturnValue(null)
383
+
384
+ const {authState} = authStore.getInitialState(instance, null)
385
+ expect(authState.type).toBe(AuthStateType.LOGGING_IN)
386
+ // Logger should have been called
387
+ expect(createLogger).toHaveBeenCalled()
388
+ })
389
+
269
390
  it('checks for cookie auth during initialize when studio config is provided and no studio token exists', () => {
270
391
  const projectId = 'studio-project'
271
392
  const studioStorageKey = `__studio_auth_token_${projectId}`
@@ -278,7 +399,9 @@ describe('authStore', () => {
278
399
  vi.mocked(checkForCookieAuth).mockResolvedValue(true)
279
400
 
280
401
  instance = createSanityInstance({
281
- studio: {projectId},
402
+ projectId,
403
+ dataset: 'd',
404
+ studio: {},
282
405
  auth: {storageArea: mockStorage},
283
406
  })
284
407
 
@@ -299,6 +422,8 @@ describe('authStore', () => {
299
422
  }
300
423
 
301
424
  instance = createSanityInstance({
425
+ projectId: 'studio-project',
426
+ dataset: 'production',
302
427
  studio: {
303
428
  auth: {token: mockTokenSource},
304
429
  },
@@ -310,13 +435,15 @@ describe('authStore', () => {
310
435
  expect(getStudioTokenFromLocalStorage).not.toHaveBeenCalled()
311
436
  })
312
437
 
313
- it('resolves to studio mode when studio config is provided', () => {
438
+ it('resolves to studio mode when studio config is provided (without studioMode flag)', () => {
314
439
  instance = createSanityInstance({
440
+ projectId: 'studio-project',
441
+ dataset: 'production',
315
442
  studio: {},
316
443
  })
317
444
 
318
445
  const {authState} = authStore.getInitialState(instance, null)
319
- // Without tokenSource, falls back to localStorage discovery
446
+ // Without tokenSource, falls back to localStorage discovery like studioMode
320
447
  expect(authState.type).toBe(AuthStateType.LOGGED_OUT)
321
448
  expect(getStudioTokenFromLocalStorage).toHaveBeenCalled()
322
449
  })
@@ -327,6 +454,8 @@ describe('authStore', () => {
327
454
  const mockTokenSource = {subscribe: mockSubscribe}
328
455
 
329
456
  instance = createSanityInstance({
457
+ projectId: 'studio-project',
458
+ dataset: 'production',
330
459
  studio: {
331
460
  auth: {token: mockTokenSource},
332
461
  },
@@ -349,6 +478,8 @@ describe('authStore', () => {
349
478
  const mockTokenSource = {subscribe: mockSubscribe}
350
479
 
351
480
  instance = createSanityInstance({
481
+ projectId: 'studio-project',
482
+ dataset: 'production',
352
483
  studio: {
353
484
  authenticated: true,
354
485
  auth: {token: mockTokenSource},
@@ -375,6 +506,8 @@ describe('authStore', () => {
375
506
  const mockTokenSource = {subscribe: mockSubscribe}
376
507
 
377
508
  instance = createSanityInstance({
509
+ projectId: 'studio-project',
510
+ dataset: 'production',
378
511
  studio: {
379
512
  authenticated: false,
380
513
  auth: {token: mockTokenSource},
@@ -395,7 +528,10 @@ describe('authStore', () => {
395
528
  const storageToken = 'regular-storage-token'
396
529
  vi.mocked(getTokenFromStorage).mockReturnValue(storageToken)
397
530
 
398
- instance = createSanityInstance()
531
+ instance = createSanityInstance({
532
+ projectId: 'p',
533
+ dataset: 'd',
534
+ })
399
535
 
400
536
  const {authState, options} = authStore.getInitialState(instance, null)
401
537
  expect(getStudioTokenFromLocalStorage).not.toHaveBeenCalled()
@@ -407,6 +543,8 @@ describe('authStore', () => {
407
543
  it('sets to logging in if getTokenFromLocation returns a token', () => {
408
544
  const initialLocationHref = 'https://example.com/#token=hash-token'
409
545
  instance = createSanityInstance({
546
+ projectId: 'p',
547
+ dataset: 'd',
410
548
  auth: {initialLocationHref},
411
549
  })
412
550
 
@@ -461,6 +599,8 @@ describe('authStore', () => {
461
599
 
462
600
  it('subscribes to state and storage events and unsubscribes on dispose', () => {
463
601
  instance = createSanityInstance({
602
+ projectId: 'p',
603
+ dataset: 'd',
464
604
  auth: {storageArea: mockLocalStorage},
465
605
  })
466
606
 
@@ -485,6 +625,8 @@ describe('authStore', () => {
485
625
 
486
626
  it('does not subscribe to storage events when not using storage area', () => {
487
627
  instance = createSanityInstance({
628
+ projectId: 'p',
629
+ dataset: 'd',
488
630
  auth: {storageArea: undefined},
489
631
  })
490
632
 
@@ -498,6 +640,35 @@ describe('authStore', () => {
498
640
  expect(stateUnsubscribe).toHaveBeenCalled()
499
641
  expect(storageEventsUnsubscribe).not.toHaveBeenCalled()
500
642
  })
643
+
644
+ it('logs when checking for cookie auth in studio mode', async () => {
645
+ const projectId = 'studio-project'
646
+ const mockStorage = {
647
+ getItem: vi.fn(),
648
+ setItem: vi.fn(),
649
+ removeItem: vi.fn(),
650
+ } as unknown as Storage
651
+ vi.mocked(getStudioTokenFromLocalStorage).mockReturnValue(null)
652
+ vi.mocked(checkForCookieAuth).mockResolvedValue(true)
653
+
654
+ instance = createSanityInstance({
655
+ projectId,
656
+ dataset: 'd',
657
+ studioMode: {enabled: true},
658
+ auth: {storageArea: mockStorage},
659
+ })
660
+
661
+ // Trigger store initialization
662
+ getAuthState(instance)
663
+
664
+ // Wait for async cookie check
665
+ await vi.waitFor(() => {
666
+ expect(checkForCookieAuth).toHaveBeenCalledWith(projectId, expect.any(Function))
667
+ })
668
+
669
+ // Logger should have been called during initialization
670
+ expect(createLogger).toHaveBeenCalled()
671
+ })
501
672
  })
502
673
 
503
674
  describe('getCurrentUserState', () => {
@@ -525,7 +696,7 @@ describe('authStore', () => {
525
696
  return NEVER.subscribe()
526
697
  })
527
698
 
528
- instance = createSanityInstance()
699
+ instance = createSanityInstance({projectId: 'p', dataset: 'd'})
529
700
 
530
701
  const {getCurrent} = getCurrentUserState(instance)
531
702
 
@@ -534,7 +705,7 @@ describe('authStore', () => {
534
705
  })
535
706
 
536
707
  it('returns null otherwise', () => {
537
- instance = createSanityInstance()
708
+ instance = createSanityInstance({projectId: 'p', dataset: 'd'})
538
709
  const {getCurrent} = getCurrentUserState(instance)
539
710
  expect(getCurrent()).toBe(null)
540
711
  })
@@ -550,6 +721,8 @@ describe('authStore', () => {
550
721
  it('returns the token if logged in', () => {
551
722
  const token = 'hard-coded-token'
552
723
  instance = createSanityInstance({
724
+ projectId: 'p',
725
+ dataset: 'd',
553
726
  auth: {token},
554
727
  })
555
728
  const tokenState = getTokenState(instance)
@@ -560,7 +733,7 @@ describe('authStore', () => {
560
733
  })
561
734
 
562
735
  it('returns null otherwise', () => {
563
- instance = createSanityInstance()
736
+ instance = createSanityInstance({projectId: 'p', dataset: 'd'})
564
737
 
565
738
  const tokenState = getTokenState(instance)
566
739
  expect(tokenState.getCurrent()).toBe(null)
@@ -578,7 +751,7 @@ describe('authStore', () => {
578
751
  })
579
752
 
580
753
  it('returns the default login url', () => {
581
- instance = createSanityInstance()
754
+ instance = createSanityInstance({projectId: 'p', dataset: 'd'})
582
755
 
583
756
  const loginUrlState = getLoginUrlState(instance)
584
757
  expect(loginUrlState.getCurrent()).toBe(
@@ -596,6 +769,8 @@ describe('authStore', () => {
596
769
 
597
770
  it('returns the current state in `authState`', () => {
598
771
  instance = createSanityInstance({
772
+ projectId: 'p',
773
+ dataset: 'd',
599
774
  auth: {token: 'hard-coded-token'},
600
775
  })
601
776
 
@@ -626,6 +801,8 @@ describe('authStore', () => {
626
801
  const context = {orgId: 'initial-org-id'}
627
802
  const initialLocationHref = `https://example.com/?_context=${encodeURIComponent(JSON.stringify(context))}`
628
803
  instance = createSanityInstance({
804
+ projectId: 'p',
805
+ dataset: 'd',
629
806
  auth: {initialLocationHref},
630
807
  })
631
808
 
@@ -642,6 +819,8 @@ describe('authStore', () => {
642
819
  const authCode = 'test-auth-code'
643
820
 
644
821
  instance = createSanityInstance({
822
+ projectId: 'p',
823
+ dataset: 'd',
645
824
  auth: {
646
825
  clientFactory: () => mockClient as unknown as SanityClient,
647
826
  initialLocationHref, // Set initial context
@@ -670,6 +849,8 @@ describe('authStore', () => {
670
849
  const context = {mode: 'test'} // No orgId
671
850
  const initialLocationHref = `https://example.com/?_context=${encodeURIComponent(JSON.stringify(context))}`
672
851
  instance = createSanityInstance({
852
+ projectId: 'p',
853
+ dataset: 'd',
673
854
  auth: {initialLocationHref},
674
855
  })
675
856
 
@@ -5,6 +5,8 @@ import {type AuthConfig, type AuthProvider} from '../config/authConfig'
5
5
  import {bindActionGlobally} from '../store/createActionBinder'
6
6
  import {createStateSourceAction} from '../store/createStateSourceAction'
7
7
  import {defineStore} from '../store/defineStore'
8
+ import {getStagingApiHost} from '../utils/getStagingApiHost'
9
+ import {getAuthLogger} from './authLogger'
8
10
  import {resolveAuthMode} from './authMode'
9
11
  import {AuthStateType} from './authStateType'
10
12
  import {type AuthStrategyOptions} from './authStrategy'
@@ -101,8 +103,18 @@ export const authStore = defineStore<AuthStoreState>({
101
103
  name: 'Auth',
102
104
 
103
105
  getInitialState(instance) {
106
+ const logger = getAuthLogger(instance)
107
+
108
+ logger.debug('Initializing auth store', {
109
+ hasProvidedToken: !!instance.config.auth?.token,
110
+ hasCustomProviders: !!(
111
+ instance.config.auth?.providers && instance.config.auth.providers.length > 0
112
+ ),
113
+ studioMode: instance.config.studioMode?.enabled ?? false,
114
+ })
115
+
104
116
  const {
105
- apiHost,
117
+ apiHost: configApiHost,
106
118
  callbackUrl,
107
119
  providers: customProviders,
108
120
  token: providedToken,
@@ -110,6 +122,7 @@ export const authStore = defineStore<AuthStoreState>({
110
122
  initialLocationHref = getDefaultLocation(),
111
123
  } = instance.config.auth ?? {}
112
124
 
125
+ const apiHost = configApiHost ?? getStagingApiHost()
113
126
  const authConfig = instance.config.auth ?? {}
114
127
 
115
128
  // Build login URL (used by standalone mode, but always computed for the
@@ -132,7 +145,7 @@ export const authStore = defineStore<AuthStoreState>({
132
145
 
133
146
  const strategyOptions: AuthStrategyOptions = {
134
147
  authConfig,
135
- projectId: instance.config.studio?.projectId,
148
+ projectId: instance.config.projectId,
136
149
  initialLocationHref,
137
150
  clientFactory,
138
151
  tokenSource: instance.config.studio?.auth?.token,
@@ -151,6 +164,12 @@ export const authStore = defineStore<AuthStoreState>({
151
164
  break
152
165
  }
153
166
 
167
+ logger.debug('Auth state initialized', {
168
+ authStateType: result.authState.type,
169
+ mode,
170
+ authMethod: result.authMethod,
171
+ })
172
+
154
173
  return {
155
174
  authState: result.authState,
156
175
  dashboardContext: result.dashboardContext,
@@ -170,10 +189,14 @@ export const authStore = defineStore<AuthStoreState>({
170
189
  },
171
190
 
172
191
  initialize(context) {
192
+ const logger = getAuthLogger(context.instance)
193
+
173
194
  const initialLocationHref =
174
195
  context.state.get().options?.initialLocationHref ?? getDefaultLocation()
175
196
  const mode = resolveAuthMode(context.instance.config, initialLocationHref)
176
197
 
198
+ logger.debug('Setting up auth subscriptions', {mode})
199
+
177
200
  let initResult
178
201
  switch (mode) {
179
202
  case 'studio':
@@ -191,7 +214,10 @@ export const authStore = defineStore<AuthStoreState>({
191
214
  tokenRefresherRunning = true
192
215
  }
193
216
 
194
- return initResult.dispose
217
+ return () => {
218
+ logger.debug('Cleaning up auth subscriptions')
219
+ initResult.dispose()
220
+ }
195
221
  },
196
222
  })
197
223
 
@@ -269,27 +295,34 @@ export const getIsInDashboardState = bindActionGlobally(
269
295
  * Used internally by the Comlink token refresh.
270
296
  * @internal
271
297
  */
272
- export const setAuthToken = bindActionGlobally(authStore, ({state}, token: string | null) => {
273
- const currentAuthState = state.get().authState
274
- if (token) {
275
- // Update state only if the new token is different or currently logged out
276
- if (currentAuthState.type !== AuthStateType.LOGGED_IN || currentAuthState.token !== token) {
277
- const currentUser =
278
- currentAuthState.type === AuthStateType.LOGGED_IN ? currentAuthState.currentUser : null
279
- const preservedLastTokenRefresh =
280
- currentAuthState.type === AuthStateType.LOGGED_IN
281
- ? currentAuthState.lastTokenRefresh
282
- : undefined
283
- state.set('setToken', {
284
- authState: createLoggedInAuthState(token, currentUser, preservedLastTokenRefresh),
285
- })
286
- }
287
- } else {
288
- // Handle setting token to null (logging out)
289
- if (currentAuthState.type !== AuthStateType.LOGGED_OUT) {
290
- state.set('setToken', {
291
- authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},
292
- })
298
+ export const setAuthToken = bindActionGlobally(
299
+ authStore,
300
+ ({state, instance}, token: string | null) => {
301
+ const logger = getAuthLogger(instance)
302
+
303
+ const currentAuthState = state.get().authState
304
+ if (token) {
305
+ // Update state only if the new token is different or currently logged out
306
+ if (currentAuthState.type !== AuthStateType.LOGGED_IN || currentAuthState.token !== token) {
307
+ logger.info('Setting auth token')
308
+ const currentUser =
309
+ currentAuthState.type === AuthStateType.LOGGED_IN ? currentAuthState.currentUser : null
310
+ const preservedLastTokenRefresh =
311
+ currentAuthState.type === AuthStateType.LOGGED_IN
312
+ ? currentAuthState.lastTokenRefresh
313
+ : undefined
314
+ state.set('setToken', {
315
+ authState: createLoggedInAuthState(token, currentUser, preservedLastTokenRefresh),
316
+ })
317
+ }
318
+ } else {
319
+ // Handle setting token to null (logging out)
320
+ if (currentAuthState.type !== AuthStateType.LOGGED_OUT) {
321
+ logger.info('Clearing auth token')
322
+ state.set('setToken', {
323
+ authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},
324
+ })
325
+ }
293
326
  }
294
- }
295
- })
327
+ },
328
+ )