@sanity/sdk 0.0.0-alpha.21 → 0.0.0-alpha.23
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/dist/index.d.ts +428 -325
- package/dist/index.js +1618 -1553
- package/dist/index.js.map +1 -1
- package/package.json +6 -7
- package/src/_exports/index.ts +31 -30
- package/src/auth/authStore.test.ts +149 -104
- package/src/auth/authStore.ts +51 -100
- package/src/auth/handleAuthCallback.test.ts +67 -34
- package/src/auth/handleAuthCallback.ts +8 -7
- package/src/auth/logout.test.ts +61 -29
- package/src/auth/logout.ts +26 -28
- package/src/auth/refreshStampedToken.test.ts +9 -9
- package/src/auth/refreshStampedToken.ts +62 -56
- package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +5 -5
- package/src/auth/subscribeToStateAndFetchCurrentUser.ts +45 -47
- package/src/auth/subscribeToStorageEventsAndSetToken.test.ts +4 -5
- package/src/auth/subscribeToStorageEventsAndSetToken.ts +22 -24
- package/src/client/clientStore.test.ts +131 -67
- package/src/client/clientStore.ts +117 -116
- package/src/comlink/controller/actions/destroyController.test.ts +38 -13
- package/src/comlink/controller/actions/destroyController.ts +11 -15
- package/src/comlink/controller/actions/getOrCreateChannel.test.ts +56 -27
- package/src/comlink/controller/actions/getOrCreateChannel.ts +37 -35
- package/src/comlink/controller/actions/getOrCreateController.test.ts +27 -16
- package/src/comlink/controller/actions/getOrCreateController.ts +23 -22
- package/src/comlink/controller/actions/releaseChannel.test.ts +37 -13
- package/src/comlink/controller/actions/releaseChannel.ts +22 -21
- package/src/comlink/controller/comlinkControllerStore.test.ts +65 -36
- package/src/comlink/controller/comlinkControllerStore.ts +44 -5
- package/src/comlink/node/actions/getOrCreateNode.test.ts +31 -15
- package/src/comlink/node/actions/getOrCreateNode.ts +30 -29
- package/src/comlink/node/actions/releaseNode.test.ts +75 -55
- package/src/comlink/node/actions/releaseNode.ts +19 -21
- package/src/comlink/node/comlinkNodeStore.test.ts +6 -11
- package/src/comlink/node/comlinkNodeStore.ts +22 -5
- package/src/config/authConfig.ts +79 -0
- package/src/config/sanityConfig.ts +48 -0
- package/src/datasets/datasets.test.ts +2 -2
- package/src/datasets/datasets.ts +18 -5
- package/src/document/actions.test.ts +22 -10
- package/src/document/actions.ts +44 -56
- package/src/document/applyDocumentActions.test.ts +96 -36
- package/src/document/applyDocumentActions.ts +140 -99
- package/src/document/documentStore.test.ts +103 -155
- package/src/document/documentStore.ts +247 -237
- package/src/document/listen.ts +56 -55
- package/src/document/patchOperations.ts +0 -43
- package/src/document/permissions.test.ts +25 -12
- package/src/document/permissions.ts +11 -4
- package/src/document/processActions.test.ts +41 -8
- package/src/document/reducers.test.ts +87 -16
- package/src/document/reducers.ts +2 -2
- package/src/document/sharedListener.test.ts +34 -16
- package/src/document/sharedListener.ts +33 -11
- package/src/preview/getPreviewState.test.ts +40 -39
- package/src/preview/getPreviewState.ts +68 -56
- package/src/preview/previewConstants.ts +43 -0
- package/src/preview/previewQuery.test.ts +1 -1
- package/src/preview/previewQuery.ts +4 -5
- package/src/preview/previewStore.test.ts +13 -58
- package/src/preview/previewStore.ts +7 -21
- package/src/preview/resolvePreview.test.ts +33 -104
- package/src/preview/resolvePreview.ts +11 -21
- package/src/preview/subscribeToStateAndFetchBatches.test.ts +96 -97
- package/src/preview/subscribeToStateAndFetchBatches.ts +85 -81
- package/src/preview/util.ts +1 -0
- package/src/project/project.test.ts +3 -3
- package/src/project/project.ts +28 -5
- package/src/projection/getProjectionState.test.ts +69 -49
- package/src/projection/getProjectionState.ts +42 -50
- package/src/projection/projectionQuery.ts +1 -1
- package/src/projection/projectionStore.test.ts +13 -51
- package/src/projection/projectionStore.ts +6 -18
- package/src/projection/resolveProjection.test.ts +32 -127
- package/src/projection/resolveProjection.ts +15 -28
- package/src/projection/subscribeToStateAndFetchBatches.test.ts +105 -90
- package/src/projection/subscribeToStateAndFetchBatches.ts +94 -81
- package/src/projection/util.ts +2 -0
- package/src/projects/projects.test.ts +13 -4
- package/src/projects/projects.ts +6 -1
- package/src/query/queryStore.test.ts +10 -47
- package/src/query/queryStore.ts +151 -133
- package/src/query/queryStoreConstants.ts +2 -0
- package/src/store/createActionBinder.test.ts +153 -0
- package/src/store/createActionBinder.ts +176 -0
- package/src/store/createSanityInstance.test.ts +84 -0
- package/src/store/createSanityInstance.ts +124 -0
- package/src/store/createStateSourceAction.test.ts +196 -0
- package/src/store/createStateSourceAction.ts +260 -0
- package/src/store/createStoreInstance.test.ts +81 -0
- package/src/store/createStoreInstance.ts +80 -0
- package/src/store/createStoreState.test.ts +85 -0
- package/src/store/createStoreState.ts +92 -0
- package/src/store/defineStore.test.ts +18 -0
- package/src/store/defineStore.ts +81 -0
- package/src/users/reducers.test.ts +318 -0
- package/src/users/reducers.ts +88 -0
- package/src/users/types.ts +46 -4
- package/src/users/usersConstants.ts +4 -0
- package/src/users/usersStore.test.ts +350 -223
- package/src/users/usersStore.ts +285 -149
- package/src/utils/createFetcherStore.test.ts +6 -7
- package/src/utils/createFetcherStore.ts +150 -153
- package/src/{common/util.test.ts → utils/hashString.test.ts} +1 -1
- package/src/auth/fetchLoginUrls.test.ts +0 -163
- package/src/auth/fetchLoginUrls.ts +0 -74
- package/src/common/createLiveEventSubscriber.test.ts +0 -121
- package/src/common/createLiveEventSubscriber.ts +0 -55
- package/src/common/types.ts +0 -4
- package/src/instance/identity.test.ts +0 -46
- package/src/instance/identity.ts +0 -29
- package/src/instance/sanityInstance.test.ts +0 -77
- package/src/instance/sanityInstance.ts +0 -57
- package/src/instance/types.ts +0 -37
- package/src/preview/getPreviewProjection.ts +0 -45
- package/src/resources/README.md +0 -370
- package/src/resources/createAction.test.ts +0 -101
- package/src/resources/createAction.ts +0 -44
- package/src/resources/createResource.test.ts +0 -112
- package/src/resources/createResource.ts +0 -102
- package/src/resources/createStateSourceAction.test.ts +0 -114
- package/src/resources/createStateSourceAction.ts +0 -83
- package/src/resources/createStore.test.ts +0 -67
- package/src/resources/createStore.ts +0 -46
- package/src/store/createStore.test.ts +0 -108
- package/src/store/createStore.ts +0 -106
- /package/src/{common/util.ts → utils/hashString.ts} +0 -0
|
@@ -3,10 +3,9 @@ import {delay, filter, firstValueFrom, Observable, of, Subject} from 'rxjs'
|
|
|
3
3
|
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
|
4
4
|
|
|
5
5
|
import {getClientState} from '../client/clientStore'
|
|
6
|
-
import {createSanityInstance} from '../
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {errorHandler, getQueryState, queryStore, resolveQuery} from './queryStore'
|
|
6
|
+
import {createSanityInstance, type SanityInstance} from '../store/createSanityInstance'
|
|
7
|
+
import {type StateSource} from '../store/createStateSourceAction'
|
|
8
|
+
import {getQueryState, resolveQuery} from './queryStore'
|
|
10
9
|
|
|
11
10
|
vi.mock('./queryStoreConstants', async (importOriginal) => ({
|
|
12
11
|
...(await importOriginal<typeof import('./queryStoreConstants')>()),
|
|
@@ -18,6 +17,7 @@ vi.mock('../client/clientStore', () => ({
|
|
|
18
17
|
}))
|
|
19
18
|
|
|
20
19
|
describe('queryStore', () => {
|
|
20
|
+
let instance: SanityInstance
|
|
21
21
|
let liveEvents: Subject<LiveEvent>
|
|
22
22
|
let fetch: SanityClient['observable']['fetch']
|
|
23
23
|
// Mock data for testing
|
|
@@ -29,6 +29,8 @@ describe('queryStore', () => {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
beforeEach(() => {
|
|
32
|
+
instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
33
|
+
|
|
32
34
|
fetch = vi
|
|
33
35
|
.fn()
|
|
34
36
|
.mockReturnValue(
|
|
@@ -50,8 +52,11 @@ describe('queryStore', () => {
|
|
|
50
52
|
} as StateSource<SanityClient>)
|
|
51
53
|
})
|
|
52
54
|
|
|
55
|
+
afterEach(() => {
|
|
56
|
+
instance.dispose()
|
|
57
|
+
})
|
|
58
|
+
|
|
53
59
|
it('initializes query state and cleans up after unsubscribe', async () => {
|
|
54
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
55
60
|
const query = '*[_type == "movie"]'
|
|
56
61
|
const state = getQueryState(instance, query)
|
|
57
62
|
|
|
@@ -78,12 +83,9 @@ describe('queryStore', () => {
|
|
|
78
83
|
|
|
79
84
|
// Verify state is cleared
|
|
80
85
|
expect(state.getCurrent()).toBeUndefined()
|
|
81
|
-
|
|
82
|
-
instance.dispose()
|
|
83
86
|
})
|
|
84
87
|
|
|
85
88
|
it('maintains state when multiple subscribers exist', async () => {
|
|
86
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
87
89
|
const query = '*[_type == "movie"]'
|
|
88
90
|
const state = getQueryState(instance, query)
|
|
89
91
|
|
|
@@ -117,12 +119,9 @@ describe('queryStore', () => {
|
|
|
117
119
|
|
|
118
120
|
// Verify state is cleared after all subscribers are gone
|
|
119
121
|
expect(state.getCurrent()).toBeUndefined()
|
|
120
|
-
|
|
121
|
-
instance.dispose()
|
|
122
122
|
})
|
|
123
123
|
|
|
124
124
|
it('resolveQuery works without affecting subscriber cleanup', async () => {
|
|
125
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
126
125
|
const query = '*[_type == "movie"]'
|
|
127
126
|
|
|
128
127
|
const state = getQueryState(instance, query)
|
|
@@ -151,12 +150,9 @@ describe('queryStore', () => {
|
|
|
151
150
|
unsubscribe()
|
|
152
151
|
await new Promise((resolve) => setTimeout(resolve, 20))
|
|
153
152
|
expect(state.getCurrent()).toBeUndefined()
|
|
154
|
-
|
|
155
|
-
instance.dispose()
|
|
156
153
|
})
|
|
157
154
|
|
|
158
155
|
it('handles abort signal in resolveQuery', async () => {
|
|
159
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
160
156
|
const query = '*[_type == "movie"]'
|
|
161
157
|
const abortController = new AbortController()
|
|
162
158
|
|
|
@@ -171,8 +167,6 @@ describe('queryStore', () => {
|
|
|
171
167
|
|
|
172
168
|
// Verify state is cleared after abort
|
|
173
169
|
expect(getQueryState(instance, query).getCurrent()).toBeUndefined()
|
|
174
|
-
|
|
175
|
-
instance.dispose()
|
|
176
170
|
})
|
|
177
171
|
|
|
178
172
|
it('refetches query when receiving live event with matching sync tag', async () => {
|
|
@@ -190,7 +184,6 @@ describe('queryStore', () => {
|
|
|
190
184
|
),
|
|
191
185
|
)
|
|
192
186
|
|
|
193
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
194
187
|
const query = '*[_type == "movie"]'
|
|
195
188
|
const state = getQueryState<{_id: string; _type: string; title: string}[]>(instance, query)
|
|
196
189
|
|
|
@@ -214,7 +207,6 @@ describe('queryStore', () => {
|
|
|
214
207
|
expect(result).toContainEqual(updatedMovie)
|
|
215
208
|
|
|
216
209
|
unsubscribe()
|
|
217
|
-
instance.dispose()
|
|
218
210
|
})
|
|
219
211
|
|
|
220
212
|
it('does not refetch for non-matching sync tags', async () => {
|
|
@@ -223,7 +215,6 @@ describe('queryStore', () => {
|
|
|
223
215
|
of({result: mockData.movies, syncTags: mockSyncTags, ms: 0}).pipe(delay(0)),
|
|
224
216
|
)
|
|
225
217
|
|
|
226
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
227
218
|
const query = '*[_type == "movie"]'
|
|
228
219
|
const state = getQueryState(instance, query)
|
|
229
220
|
|
|
@@ -243,7 +234,6 @@ describe('queryStore', () => {
|
|
|
243
234
|
expect(fetch).toHaveBeenCalledTimes(1)
|
|
244
235
|
|
|
245
236
|
unsubscribe()
|
|
246
|
-
instance.dispose()
|
|
247
237
|
})
|
|
248
238
|
|
|
249
239
|
it('handles multiple live events with same sync tag', async () => {
|
|
@@ -258,7 +248,6 @@ describe('queryStore', () => {
|
|
|
258
248
|
of({result: mockData.movies, syncTags: mockSyncTags, ms: 0}).pipe(delay(0)),
|
|
259
249
|
)
|
|
260
250
|
|
|
261
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
262
251
|
const query = '*[_type == "movie"]'
|
|
263
252
|
const state = getQueryState(instance, query)
|
|
264
253
|
|
|
@@ -284,11 +273,9 @@ describe('queryStore', () => {
|
|
|
284
273
|
expect(vi.mocked(fetch).mock.calls[2][2]?.lastLiveEventId).toBe('event2')
|
|
285
274
|
|
|
286
275
|
unsubscribe()
|
|
287
|
-
instance.dispose()
|
|
288
276
|
})
|
|
289
277
|
|
|
290
278
|
it('handles errors in query fetching', async () => {
|
|
291
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
292
279
|
const errorMessage = 'Query failed'
|
|
293
280
|
|
|
294
281
|
// Override fetch to simulate error
|
|
@@ -306,29 +293,9 @@ describe('queryStore', () => {
|
|
|
306
293
|
expect(() => state.getCurrent()).toThrow(errorMessage)
|
|
307
294
|
|
|
308
295
|
unsubscribe()
|
|
309
|
-
instance.dispose()
|
|
310
|
-
})
|
|
311
|
-
|
|
312
|
-
it('throws an error if an errorHandler has been called', () => {
|
|
313
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
314
|
-
const query = '*[_type == "movie"]'
|
|
315
|
-
const state = getQueryState(instance, query)
|
|
316
|
-
|
|
317
|
-
const resource = getOrCreateResource(instance, queryStore)
|
|
318
|
-
|
|
319
|
-
// Create an error and call the error handler
|
|
320
|
-
const testError = new Error('Global error from error handler')
|
|
321
|
-
const handler = errorHandler({state: resource.state, instance})
|
|
322
|
-
handler(testError)
|
|
323
|
-
|
|
324
|
-
// Verify the error is thrown when accessing state
|
|
325
|
-
expect(() => state.getCurrent()).toThrow('Global error from error handler')
|
|
326
|
-
|
|
327
|
-
instance.dispose()
|
|
328
296
|
})
|
|
329
297
|
|
|
330
298
|
it('delays query state removal after unsubscribe', async () => {
|
|
331
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
332
299
|
const query = '*[_type == "movie"]'
|
|
333
300
|
const state = getQueryState(instance, query)
|
|
334
301
|
const unsubscribe = state.subscribe()
|
|
@@ -342,12 +309,9 @@ describe('queryStore', () => {
|
|
|
342
309
|
// Wait for the cleanup delay and then state should be removed
|
|
343
310
|
await new Promise((resolve) => setTimeout(resolve, 20))
|
|
344
311
|
expect(state.getCurrent()).toBeUndefined()
|
|
345
|
-
|
|
346
|
-
instance.dispose()
|
|
347
312
|
})
|
|
348
313
|
|
|
349
314
|
it('preserves query state if a new subscriber subscribes before cleanup delay', async () => {
|
|
350
|
-
const instance = createSanityInstance({projectId: 'test', dataset: 'test'})
|
|
351
315
|
const query = '*[_type == "movie"]'
|
|
352
316
|
const state = getQueryState(instance, query)
|
|
353
317
|
const unsubscribe1 = state.subscribe()
|
|
@@ -374,6 +338,5 @@ describe('queryStore', () => {
|
|
|
374
338
|
{_id: 'movie2', _type: 'movie', title: 'Movie 2'},
|
|
375
339
|
])
|
|
376
340
|
unsubscribe2()
|
|
377
|
-
instance.dispose()
|
|
378
341
|
})
|
|
379
342
|
})
|
package/src/query/queryStore.ts
CHANGED
|
@@ -20,13 +20,19 @@ import {
|
|
|
20
20
|
tap,
|
|
21
21
|
} from 'rxjs'
|
|
22
22
|
|
|
23
|
-
import {
|
|
24
|
-
import {type
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
23
|
+
import {getClientState} from '../client/clientStore'
|
|
24
|
+
import {type DatasetHandle} from '../config/sanityConfig'
|
|
25
|
+
import {bindActionByDataset} from '../store/createActionBinder'
|
|
26
|
+
import {type SanityInstance} from '../store/createSanityInstance'
|
|
27
|
+
import {
|
|
28
|
+
createStateSourceAction,
|
|
29
|
+
type SelectorContext,
|
|
30
|
+
type StateSource,
|
|
31
|
+
} from '../store/createStateSourceAction'
|
|
32
|
+
import {type StoreState} from '../store/createStoreState'
|
|
33
|
+
import {defineStore, type StoreContext} from '../store/defineStore'
|
|
28
34
|
import {insecureRandomId} from '../utils/ids'
|
|
29
|
-
import {QUERY_STATE_CLEAR_DELAY} from './queryStoreConstants'
|
|
35
|
+
import {QUERY_STATE_CLEAR_DELAY, QUERY_STORE_API_VERSION} from './queryStoreConstants'
|
|
30
36
|
import {
|
|
31
37
|
addSubscriber,
|
|
32
38
|
cancelQuery,
|
|
@@ -42,8 +48,11 @@ import {
|
|
|
42
48
|
* @beta
|
|
43
49
|
*/
|
|
44
50
|
export interface QueryOptions
|
|
45
|
-
extends Pick<
|
|
46
|
-
|
|
51
|
+
extends Pick<
|
|
52
|
+
ResponseQueryOptions,
|
|
53
|
+
'perspective' | 'useCdn' | 'cache' | 'next' | 'cacheMode' | 'tag'
|
|
54
|
+
>,
|
|
55
|
+
DatasetHandle {
|
|
47
56
|
params?: Record<string, unknown>
|
|
48
57
|
}
|
|
49
58
|
|
|
@@ -63,13 +72,13 @@ export const getQueryKey = (query: string, options: QueryOptions = {}): string =
|
|
|
63
72
|
export const parseQueryKey = (key: string): {query: string; options: QueryOptions} =>
|
|
64
73
|
JSON.parse(key)
|
|
65
74
|
|
|
66
|
-
|
|
75
|
+
const queryStore = defineStore<QueryStoreState>({
|
|
67
76
|
name: 'QueryStore',
|
|
68
77
|
getInitialState: () => ({queries: {}}),
|
|
69
|
-
initialize() {
|
|
78
|
+
initialize(context) {
|
|
70
79
|
const subscriptions = [
|
|
71
|
-
listenForNewSubscribersAndFetch(
|
|
72
|
-
listenToLiveClientAndSetLastLiveEventIds(
|
|
80
|
+
listenForNewSubscribersAndFetch(context),
|
|
81
|
+
listenToLiveClientAndSetLastLiveEventIds(context),
|
|
73
82
|
]
|
|
74
83
|
|
|
75
84
|
return () => {
|
|
@@ -80,106 +89,107 @@ export const queryStore = createResource<QueryStoreState>({
|
|
|
80
89
|
},
|
|
81
90
|
})
|
|
82
91
|
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
const listenForNewSubscribersAndFetch = createInternalAction(
|
|
90
|
-
({state, instance}: ActionContext<QueryStoreState>) => {
|
|
91
|
-
return function () {
|
|
92
|
-
return state.observable
|
|
93
|
-
.pipe(
|
|
94
|
-
map((s) => new Set(Object.keys(s.queries))),
|
|
95
|
-
distinctUntilChanged((curr, next) => {
|
|
96
|
-
if (curr.size !== next.size) return false
|
|
97
|
-
return Array.from(next).every((i) => curr.has(i))
|
|
98
|
-
}),
|
|
99
|
-
startWith(new Set<string>()),
|
|
100
|
-
pairwise(),
|
|
101
|
-
mergeMap(([curr, next]) => {
|
|
102
|
-
const added = Array.from(next).filter((i) => !curr.has(i))
|
|
103
|
-
const removed = Array.from(curr).filter((i) => !next.has(i))
|
|
104
|
-
|
|
105
|
-
return [
|
|
106
|
-
...added.map((key) => ({key, added: true})),
|
|
107
|
-
...removed.map((key) => ({key, added: false})),
|
|
108
|
-
]
|
|
109
|
-
}),
|
|
110
|
-
groupBy((i) => i.key),
|
|
111
|
-
mergeMap((group$) =>
|
|
112
|
-
group$.pipe(
|
|
113
|
-
switchMap((e) => {
|
|
114
|
-
if (!e.added) return EMPTY
|
|
92
|
+
const errorHandler = (state: StoreState<{error?: unknown}>) => {
|
|
93
|
+
return (error: unknown): void => state.set('setError', {error})
|
|
94
|
+
}
|
|
115
95
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
96
|
+
const listenForNewSubscribersAndFetch = ({state, instance}: StoreContext<QueryStoreState>) => {
|
|
97
|
+
return state.observable
|
|
98
|
+
.pipe(
|
|
99
|
+
map((s) => new Set(Object.keys(s.queries))),
|
|
100
|
+
distinctUntilChanged((curr, next) => {
|
|
101
|
+
if (curr.size !== next.size) return false
|
|
102
|
+
return Array.from(next).every((i) => curr.has(i))
|
|
103
|
+
}),
|
|
104
|
+
startWith(new Set<string>()),
|
|
105
|
+
pairwise(),
|
|
106
|
+
mergeMap(([curr, next]) => {
|
|
107
|
+
const added = Array.from(next).filter((i) => !curr.has(i))
|
|
108
|
+
const removed = Array.from(curr).filter((i) => !next.has(i))
|
|
122
109
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}),
|
|
134
|
-
catchError((error) => {
|
|
135
|
-
state.set('setQueryError', setQueryError(group$.key, error))
|
|
136
|
-
return EMPTY
|
|
137
|
-
}),
|
|
138
|
-
tap(({result, syncTags}) => {
|
|
139
|
-
state.set('setQueryData', setQueryData(group$.key, result, syncTags))
|
|
140
|
-
}),
|
|
141
|
-
),
|
|
142
|
-
),
|
|
143
|
-
)
|
|
144
|
-
.subscribe({error: errorHandler(this)})
|
|
145
|
-
}
|
|
146
|
-
},
|
|
147
|
-
)
|
|
110
|
+
return [
|
|
111
|
+
...added.map((key) => ({key, added: true})),
|
|
112
|
+
...removed.map((key) => ({key, added: false})),
|
|
113
|
+
]
|
|
114
|
+
}),
|
|
115
|
+
groupBy((i) => i.key),
|
|
116
|
+
mergeMap((group$) =>
|
|
117
|
+
group$.pipe(
|
|
118
|
+
switchMap((e) => {
|
|
119
|
+
if (!e.added) return EMPTY
|
|
148
120
|
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
return function () {
|
|
152
|
-
const liveMessages$ = getClientState(instance, {apiVersion: 'vX'}).observable.pipe(
|
|
153
|
-
switchMap((client) =>
|
|
154
|
-
client.live.events({includeDrafts: !!client.config().token, tag: 'query-store'}),
|
|
155
|
-
),
|
|
156
|
-
share(),
|
|
157
|
-
filter((e) => e.type === 'message'),
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
return state.observable
|
|
161
|
-
.pipe(
|
|
162
|
-
mergeMap((s) => Object.entries(s.queries)),
|
|
163
|
-
groupBy(([key]) => key),
|
|
164
|
-
mergeMap((group$) => {
|
|
165
|
-
const syncTags$ = group$.pipe(
|
|
166
|
-
map(([, queryState]) => queryState),
|
|
167
|
-
map((i) => i?.syncTags ?? EMPTY_ARRAY),
|
|
121
|
+
const lastLiveEventId$ = state.observable.pipe(
|
|
122
|
+
map((s) => s.queries[group$.key]?.lastLiveEventId),
|
|
168
123
|
distinctUntilChanged(),
|
|
169
124
|
)
|
|
125
|
+
const {query, options: {params, projectId, dataset, tag, ...options} = {}} =
|
|
126
|
+
parseQueryKey(group$.key)
|
|
127
|
+
const client$ = getClientState(instance, {
|
|
128
|
+
apiVersion: QUERY_STORE_API_VERSION,
|
|
129
|
+
projectId,
|
|
130
|
+
dataset,
|
|
131
|
+
}).observable
|
|
170
132
|
|
|
171
|
-
return combineLatest([
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
133
|
+
return combineLatest([lastLiveEventId$, client$]).pipe(
|
|
134
|
+
switchMap(([lastLiveEventId, client]) =>
|
|
135
|
+
client.observable.fetch(query, params, {
|
|
136
|
+
...options,
|
|
137
|
+
filterResponse: false,
|
|
138
|
+
returnQuery: false,
|
|
139
|
+
lastLiveEventId,
|
|
140
|
+
tag,
|
|
141
|
+
}),
|
|
142
|
+
),
|
|
176
143
|
)
|
|
177
144
|
}),
|
|
145
|
+
catchError((error) => {
|
|
146
|
+
state.set('setQueryError', setQueryError(group$.key, error))
|
|
147
|
+
return EMPTY
|
|
148
|
+
}),
|
|
149
|
+
tap(({result, syncTags}) => {
|
|
150
|
+
state.set('setQueryData', setQueryData(group$.key, result, syncTags))
|
|
151
|
+
}),
|
|
152
|
+
),
|
|
153
|
+
),
|
|
154
|
+
)
|
|
155
|
+
.subscribe({error: errorHandler(state)})
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const listenToLiveClientAndSetLastLiveEventIds = ({
|
|
159
|
+
state,
|
|
160
|
+
instance,
|
|
161
|
+
}: StoreContext<QueryStoreState>) => {
|
|
162
|
+
const liveMessages$ = getClientState(instance, {
|
|
163
|
+
apiVersion: QUERY_STORE_API_VERSION,
|
|
164
|
+
}).observable.pipe(
|
|
165
|
+
switchMap((client) =>
|
|
166
|
+
client.live.events({includeDrafts: !!client.config().token, tag: 'query-store'}),
|
|
167
|
+
),
|
|
168
|
+
share(),
|
|
169
|
+
filter((e) => e.type === 'message'),
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
return state.observable
|
|
173
|
+
.pipe(
|
|
174
|
+
mergeMap((s) => Object.entries(s.queries)),
|
|
175
|
+
groupBy(([key]) => key),
|
|
176
|
+
mergeMap((group$) => {
|
|
177
|
+
const syncTags$ = group$.pipe(
|
|
178
|
+
map(([, queryState]) => queryState),
|
|
179
|
+
map((i) => i?.syncTags ?? EMPTY_ARRAY),
|
|
180
|
+
distinctUntilChanged(),
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return combineLatest([liveMessages$, syncTags$]).pipe(
|
|
184
|
+
filter(([message, syncTags]) => message.tags.some((tag) => syncTags.includes(tag))),
|
|
185
|
+
tap(([message]) => {
|
|
186
|
+
state.set('setLastLiveEventId', setLastLiveEventId(group$.key, message.id))
|
|
187
|
+
}),
|
|
178
188
|
)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
189
|
+
}),
|
|
190
|
+
)
|
|
191
|
+
.subscribe({error: errorHandler(state)})
|
|
192
|
+
}
|
|
183
193
|
|
|
184
194
|
/**
|
|
185
195
|
* Returns the state source for a query.
|
|
@@ -198,13 +208,13 @@ const listenToLiveClientAndSetLastLiveEventIds = createInternalAction(
|
|
|
198
208
|
* @beta
|
|
199
209
|
*/
|
|
200
210
|
export function getQueryState<T>(
|
|
201
|
-
instance: SanityInstance
|
|
211
|
+
instance: SanityInstance,
|
|
202
212
|
query: string,
|
|
203
213
|
options?: QueryOptions,
|
|
204
214
|
): StateSource<T | undefined>
|
|
205
215
|
/** @beta */
|
|
206
216
|
export function getQueryState(
|
|
207
|
-
instance: SanityInstance
|
|
217
|
+
instance: SanityInstance,
|
|
208
218
|
query: string,
|
|
209
219
|
options?: QueryOptions,
|
|
210
220
|
): StateSource<unknown>
|
|
@@ -212,29 +222,36 @@ export function getQueryState(
|
|
|
212
222
|
export function getQueryState(...args: Parameters<typeof _getQueryState>): StateSource<unknown> {
|
|
213
223
|
return _getQueryState(...args)
|
|
214
224
|
}
|
|
215
|
-
const _getQueryState =
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
225
|
+
const _getQueryState = bindActionByDataset(
|
|
226
|
+
queryStore,
|
|
227
|
+
createStateSourceAction({
|
|
228
|
+
selector: (
|
|
229
|
+
{state}: SelectorContext<QueryStoreState>,
|
|
230
|
+
query: string,
|
|
231
|
+
options?: QueryOptions,
|
|
232
|
+
) => {
|
|
233
|
+
if (state.error) throw state.error
|
|
234
|
+
const key = getQueryKey(query, options)
|
|
235
|
+
const queryState = state.queries[key]
|
|
236
|
+
if (queryState?.error) throw queryState.error
|
|
237
|
+
return queryState?.result
|
|
238
|
+
},
|
|
239
|
+
onSubscribe: ({state}, query, options?: QueryOptions) => {
|
|
240
|
+
const subscriptionId = insecureRandomId()
|
|
241
|
+
const key = getQueryKey(query, options)
|
|
226
242
|
|
|
227
|
-
|
|
243
|
+
state.set('addSubscriber', addSubscriber(key, subscriptionId))
|
|
228
244
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
})
|
|
245
|
+
return () => {
|
|
246
|
+
// this runs on unsubscribe
|
|
247
|
+
setTimeout(
|
|
248
|
+
() => state.set('removeSubscriber', removeSubscriber(key, subscriptionId)),
|
|
249
|
+
QUERY_STATE_CLEAR_DELAY,
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
}),
|
|
254
|
+
)
|
|
238
255
|
|
|
239
256
|
/**
|
|
240
257
|
* Resolves the result of a query without registering a lasting subscriber.
|
|
@@ -251,13 +268,13 @@ const _getQueryState = createStateSourceAction(queryStore, {
|
|
|
251
268
|
* @beta
|
|
252
269
|
*/
|
|
253
270
|
export function resolveQuery<T>(
|
|
254
|
-
instance: SanityInstance
|
|
271
|
+
instance: SanityInstance,
|
|
255
272
|
query: string,
|
|
256
273
|
options?: ResolveQueryOptions,
|
|
257
274
|
): Promise<T>
|
|
258
275
|
/** @beta */
|
|
259
276
|
export function resolveQuery(
|
|
260
|
-
instance: SanityInstance
|
|
277
|
+
instance: SanityInstance,
|
|
261
278
|
query: string,
|
|
262
279
|
options?: ResolveQueryOptions,
|
|
263
280
|
): Promise<unknown>
|
|
@@ -265,9 +282,10 @@ export function resolveQuery(
|
|
|
265
282
|
export function resolveQuery(...args: Parameters<typeof _resolveQuery>): Promise<unknown> {
|
|
266
283
|
return _resolveQuery(...args)
|
|
267
284
|
}
|
|
268
|
-
const _resolveQuery =
|
|
269
|
-
|
|
270
|
-
|
|
285
|
+
const _resolveQuery = bindActionByDataset(
|
|
286
|
+
queryStore,
|
|
287
|
+
({state, instance}, query: string, {signal, ...options}: ResolveQueryOptions = {}) => {
|
|
288
|
+
const {getCurrent} = getQueryState(instance, query, options)
|
|
271
289
|
const key = getQueryKey(query, options)
|
|
272
290
|
|
|
273
291
|
const aborted$ = signal
|
|
@@ -302,5 +320,5 @@ const _resolveQuery = createAction(queryStore, ({state}) => {
|
|
|
302
320
|
)
|
|
303
321
|
|
|
304
322
|
return firstValueFrom(race([resolved$, aborted$]))
|
|
305
|
-
}
|
|
306
|
-
|
|
323
|
+
},
|
|
324
|
+
)
|