@sanity/sdk 0.0.0-chore-react-18-compat.1 → 0.0.0-chore-react-18-compat.3
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 +441 -322
- package/dist/index.js +1685 -1481
- package/dist/index.js.map +1 -1
- package/package.json +13 -15
- package/src/_exports/index.ts +32 -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 +197 -91
- package/src/auth/refreshStampedToken.ts +170 -59
- 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 -238
- 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 +188 -72
- package/src/projection/getProjectionState.ts +92 -62
- package/src/projection/projectionQuery.test.ts +114 -12
- package/src/projection/projectionQuery.ts +75 -32
- package/src/projection/projectionStore.test.ts +13 -51
- package/src/projection/projectionStore.ts +6 -43
- package/src/projection/resolveProjection.test.ts +32 -127
- package/src/projection/resolveProjection.ts +16 -28
- package/src/projection/subscribeToStateAndFetchBatches.test.ts +203 -116
- package/src/projection/subscribeToStateAndFetchBatches.ts +140 -85
- package/src/projection/types.ts +50 -0
- package/src/projection/util.ts +3 -1
- 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/utils/createGroqSearchFilter.test.ts +75 -0
- package/src/utils/createGroqSearchFilter.ts +85 -0
- package/src/{common/util.test.ts → utils/hashString.test.ts} +1 -1
- package/dist/index.cjs +0 -4888
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -2121
- 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
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
|
+
)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {bindActionByDataset, bindActionGlobally, createActionBinder} from './createActionBinder'
|
|
4
|
+
import {createSanityInstance} from './createSanityInstance'
|
|
5
|
+
import {createStoreInstance} from './createStoreInstance'
|
|
6
|
+
|
|
7
|
+
// Mock store instance creation for testing
|
|
8
|
+
vi.mock('./createStoreInstance', () => ({
|
|
9
|
+
createStoreInstance: vi.fn(() => ({state: {counter: 0}, dispose: vi.fn()})),
|
|
10
|
+
}))
|
|
11
|
+
beforeEach(() => vi.mocked(createStoreInstance).mockClear())
|
|
12
|
+
|
|
13
|
+
describe('createActionBinder', () => {
|
|
14
|
+
it('should bind an action and call it with correct context and parameters, using caching', () => {
|
|
15
|
+
const binder = createActionBinder(() => '')
|
|
16
|
+
const storeDefinition = {
|
|
17
|
+
name: 'TestStore',
|
|
18
|
+
getInitialState: () => ({counter: 0}),
|
|
19
|
+
}
|
|
20
|
+
// Action that increments counter by given value
|
|
21
|
+
const action = vi.fn((context, increment: number) => {
|
|
22
|
+
context.state.counter += increment
|
|
23
|
+
return context.state.counter
|
|
24
|
+
})
|
|
25
|
+
const boundAction = binder(storeDefinition, action)
|
|
26
|
+
const instance = createSanityInstance({projectId: 'proj1', dataset: 'ds1'})
|
|
27
|
+
|
|
28
|
+
// First call creates store instance
|
|
29
|
+
const result1 = boundAction(instance, 5)
|
|
30
|
+
expect(result1).toBe(5)
|
|
31
|
+
// Second call reuses cached store
|
|
32
|
+
const result2 = boundAction(instance, 5)
|
|
33
|
+
expect(result2).toBe(10)
|
|
34
|
+
|
|
35
|
+
expect(action).toHaveBeenCalledTimes(2)
|
|
36
|
+
expect(vi.mocked(createStoreInstance)).toHaveBeenCalledTimes(1)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should create separate store instances for different composite keys', () => {
|
|
40
|
+
const binder = createActionBinder(({projectId, dataset}) => `${projectId}.${dataset}`)
|
|
41
|
+
const storeDefinition = {
|
|
42
|
+
name: 'TestStore',
|
|
43
|
+
getInitialState: () => ({counter: 0}),
|
|
44
|
+
}
|
|
45
|
+
const action = vi.fn((context, val: number) => {
|
|
46
|
+
context.state.counter += val
|
|
47
|
+
return context.state.counter
|
|
48
|
+
})
|
|
49
|
+
const boundAction = binder(storeDefinition, action)
|
|
50
|
+
const instanceA = createSanityInstance({projectId: 'p1', dataset: 'd1'})
|
|
51
|
+
const instanceB = createSanityInstance({projectId: 'p2', dataset: 'd2'})
|
|
52
|
+
|
|
53
|
+
const resultA = boundAction(instanceA, 3)
|
|
54
|
+
const resultB = boundAction(instanceB, 4)
|
|
55
|
+
|
|
56
|
+
expect(resultA).toBe(3)
|
|
57
|
+
expect(resultB).toBe(4)
|
|
58
|
+
expect(vi.mocked(createStoreInstance)).toHaveBeenCalledTimes(2)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('should dispose the store instance when the last instance is disposed', () => {
|
|
62
|
+
const binder = createActionBinder(() => '')
|
|
63
|
+
const storeDefinition = {
|
|
64
|
+
name: 'TestStore',
|
|
65
|
+
getInitialState: () => ({counter: 0}),
|
|
66
|
+
}
|
|
67
|
+
const action = vi.fn((context) => context.state.counter)
|
|
68
|
+
const boundAction = binder(storeDefinition, action)
|
|
69
|
+
const instance1 = createSanityInstance({projectId: 'p1', dataset: 'd1'})
|
|
70
|
+
const instance2 = createSanityInstance({projectId: 'p1', dataset: 'd1'})
|
|
71
|
+
|
|
72
|
+
// Call action on both instances
|
|
73
|
+
boundAction(instance1)
|
|
74
|
+
boundAction(instance2)
|
|
75
|
+
expect(vi.mocked(createStoreInstance)).toHaveBeenCalledTimes(1)
|
|
76
|
+
|
|
77
|
+
const [{value: storeInstance}] = vi.mocked(createStoreInstance).mock.results
|
|
78
|
+
expect(storeInstance).toBeDefined()
|
|
79
|
+
|
|
80
|
+
// First disposal shouldn't trigger store disposal
|
|
81
|
+
instance1.dispose()
|
|
82
|
+
expect(storeInstance.dispose).not.toHaveBeenCalled()
|
|
83
|
+
|
|
84
|
+
// Last disposal should trigger store disposal
|
|
85
|
+
instance2.dispose()
|
|
86
|
+
expect(storeInstance.dispose).toHaveBeenCalledTimes(1)
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
describe('bindActionByDataset', () => {
|
|
91
|
+
it('should work correctly when projectId and dataset are provided', () => {
|
|
92
|
+
const storeDefinition = {
|
|
93
|
+
name: 'DSStore',
|
|
94
|
+
getInitialState: () => ({counter: 0}),
|
|
95
|
+
}
|
|
96
|
+
const action = vi.fn((_context, value: string) => value)
|
|
97
|
+
const boundAction = bindActionByDataset(storeDefinition, action)
|
|
98
|
+
const instance = createSanityInstance({projectId: 'proj1', dataset: 'ds1'})
|
|
99
|
+
const result = boundAction(instance, 'hello')
|
|
100
|
+
expect(result).toBe('hello')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('should throw an error if projectId or dataset is missing', () => {
|
|
104
|
+
const storeDefinition = {
|
|
105
|
+
name: 'DSStore',
|
|
106
|
+
getInitialState: () => ({counter: 0}),
|
|
107
|
+
}
|
|
108
|
+
const action = vi.fn((_context) => 'fail')
|
|
109
|
+
const boundAction = bindActionByDataset(storeDefinition, action)
|
|
110
|
+
// Instance with missing dataset
|
|
111
|
+
const instance = createSanityInstance({projectId: 'proj1', dataset: ''})
|
|
112
|
+
expect(() => boundAction(instance)).toThrow(
|
|
113
|
+
'This API requires a project ID and dataset configured.',
|
|
114
|
+
)
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
describe('bindActionGlobally', () => {
|
|
119
|
+
it('should work correctly ignoring config in key generation', () => {
|
|
120
|
+
const storeDefinition = {
|
|
121
|
+
name: 'GlobalStore',
|
|
122
|
+
getInitialState: () => ({counter: 0}),
|
|
123
|
+
}
|
|
124
|
+
const action = vi.fn((_context, x: number) => x)
|
|
125
|
+
const boundAction = bindActionGlobally(storeDefinition, action)
|
|
126
|
+
|
|
127
|
+
// Create instances with different configs
|
|
128
|
+
const instance1 = createSanityInstance({projectId: 'any', dataset: 'any'})
|
|
129
|
+
const instance2 = createSanityInstance({projectId: 'different', dataset: 'config'})
|
|
130
|
+
|
|
131
|
+
// Both instances should use the same store
|
|
132
|
+
const result1 = boundAction(instance1, 42)
|
|
133
|
+
const result2 = boundAction(instance2, 99)
|
|
134
|
+
|
|
135
|
+
expect(result1).toBe(42)
|
|
136
|
+
expect(result2).toBe(99)
|
|
137
|
+
|
|
138
|
+
// Verify single store instance used
|
|
139
|
+
expect(vi.mocked(createStoreInstance)).toHaveBeenCalledTimes(1)
|
|
140
|
+
|
|
141
|
+
// Verify action called with correct arguments
|
|
142
|
+
expect(action).toHaveBeenNthCalledWith(1, expect.anything(), 42)
|
|
143
|
+
expect(action).toHaveBeenNthCalledWith(2, expect.anything(), 99)
|
|
144
|
+
|
|
145
|
+
// Test disposal tracking
|
|
146
|
+
const [{value: storeInstance}] = vi.mocked(createStoreInstance).mock.results
|
|
147
|
+
instance1.dispose()
|
|
148
|
+
expect(storeInstance.dispose).not.toHaveBeenCalled()
|
|
149
|
+
|
|
150
|
+
instance2.dispose()
|
|
151
|
+
expect(storeInstance.dispose).toHaveBeenCalledTimes(1)
|
|
152
|
+
})
|
|
153
|
+
})
|