sanity 3.72.1 → 3.72.2-use-live-content-api.9

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 (48) hide show
  1. package/lib/_chunks-cjs/LiveQueries.js +236 -163
  2. package/lib/_chunks-cjs/LiveQueries.js.map +1 -1
  3. package/lib/_chunks-cjs/PresentationToolGrantsCheck.js +3 -7
  4. package/lib/_chunks-cjs/PresentationToolGrantsCheck.js.map +1 -1
  5. package/lib/_chunks-cjs/buildAction.js +3 -0
  6. package/lib/_chunks-cjs/buildAction.js.map +1 -1
  7. package/lib/_chunks-cjs/presentation.js +3 -4
  8. package/lib/_chunks-cjs/presentation.js.map +1 -1
  9. package/lib/_chunks-cjs/version.js +1 -1
  10. package/lib/_chunks-es/LiveQueries.mjs +235 -162
  11. package/lib/_chunks-es/LiveQueries.mjs.map +1 -1
  12. package/lib/_chunks-es/PresentationToolGrantsCheck.mjs +2 -4
  13. package/lib/_chunks-es/PresentationToolGrantsCheck.mjs.map +1 -1
  14. package/lib/_chunks-es/presentation.mjs +3 -3
  15. package/lib/_chunks-es/presentation.mjs.map +1 -1
  16. package/lib/_chunks-es/version.mjs +1 -1
  17. package/lib/_internal/cli/threads/validateDocuments.js +1 -1
  18. package/lib/_internal/cli/threads/validateDocuments.js.map +1 -1
  19. package/lib/_legacy/LiveQueries.esm.js +235 -162
  20. package/lib/_legacy/LiveQueries.esm.js.map +1 -1
  21. package/lib/_legacy/PresentationToolGrantsCheck.esm.js +2 -4
  22. package/lib/_legacy/PresentationToolGrantsCheck.esm.js.map +1 -1
  23. package/lib/_legacy/presentation.esm.js +3 -3
  24. package/lib/_legacy/presentation.esm.js.map +1 -1
  25. package/lib/_legacy/version.esm.js +1 -1
  26. package/package.json +13 -14
  27. package/src/_internal/cli/server/buildVendorDependencies.ts +1 -0
  28. package/src/_internal/cli/threads/validateDocuments.ts +2 -2
  29. package/src/presentation/PresentationTool.tsx +10 -21
  30. package/src/presentation/constants.ts +4 -16
  31. package/src/presentation/loader/LiveQueries.tsx +79 -234
  32. package/src/presentation/loader/useLiveEvents.ts +75 -0
  33. package/src/presentation/loader/useLiveQueries.ts +127 -0
  34. package/src/presentation/loader/utils.ts +2 -125
  35. package/src/presentation/types.ts +1 -18
  36. package/lib/_chunks-cjs/LoaderQueries.js +0 -281
  37. package/lib/_chunks-cjs/LoaderQueries.js.map +0 -1
  38. package/lib/_chunks-cjs/utils.js +0 -70
  39. package/lib/_chunks-cjs/utils.js.map +0 -1
  40. package/lib/_chunks-es/LoaderQueries.mjs +0 -288
  41. package/lib/_chunks-es/LoaderQueries.mjs.map +0 -1
  42. package/lib/_chunks-es/utils.mjs +0 -74
  43. package/lib/_chunks-es/utils.mjs.map +0 -1
  44. package/lib/_legacy/LoaderQueries.esm.js +0 -288
  45. package/lib/_legacy/LoaderQueries.esm.js.map +0 -1
  46. package/lib/_legacy/utils.esm.js +0 -74
  47. package/lib/_legacy/utils.esm.js.map +0 -1
  48. package/src/presentation/loader/LoaderQueries.tsx +0 -564
@@ -2,7 +2,6 @@ import {toPlainText} from '@portabletext/react'
2
2
  import {isPortableTextBlock} from '@portabletext/toolkit'
3
3
  import {type ClientPerspective, type QueryParams} from '@sanity/client'
4
4
  import {type ApplySourceDocumentsUpdateFunction} from '@sanity/client/csm'
5
- import {useCallback, useEffect, useMemo, useState, useSyncExternalStore} from 'react'
6
5
  import {type FIXME} from 'sanity'
7
6
 
8
7
  /**
@@ -37,7 +36,7 @@ export const mapChangedValue: ApplySourceDocumentsUpdateFunction = (
37
36
  /**
38
37
  * @internal
39
38
  */
40
- export type QueryCacheKey = `${string}-${string}-${string}`
39
+ export type QueryCacheKey = `${string}:${string}:${string}`
41
40
  /**
42
41
  * @internal
43
42
  */
@@ -46,127 +45,5 @@ export function getQueryCacheKey(
46
45
  query: string,
47
46
  params: QueryParams,
48
47
  ): QueryCacheKey {
49
- return `${perspective}-${query}-${JSON.stringify(params)}`
50
- }
51
-
52
- /**
53
- * Return params that are stable with deep equal as long as the key order is the same
54
- * @internal
55
- */
56
- export function useQueryParams(params?: undefined | null | QueryParams): QueryParams {
57
- const stringifiedParams = useMemo(() => JSON.stringify(params || {}), [params])
58
- return useMemo(() => JSON.parse(stringifiedParams) as QueryParams, [stringifiedParams])
59
- }
60
-
61
- /**
62
- * 'hit' - the cache is fresh and valid
63
- * 'stale' - the cache should revalidate, but can't/shouldn't yet (offline, visibility = hidden)
64
- * 'refresh' - stale cache, and now is a great time to start refreshing
65
- * 'inflight' - refreshing cache, revalidate events should be ignored
66
- */
67
- export type RevalidateState = 'hit' | 'stale' | 'refresh' | 'inflight'
68
- /**
69
- * Keeps track of when queries should revalidate
70
- */
71
- export function useRevalidate(props: {
72
- /**
73
- * How frequently queries should be refetched in the background to refresh the parts of queries that can't be source mapped.
74
- * Setting it to `0` will disable background refresh.
75
- */
76
- refreshInterval: number
77
- }): [RevalidateState, () => () => void] {
78
- const {refreshInterval} = props
79
-
80
- const shouldPause = useShouldPause()
81
- const [state, setState] = useState<RevalidateState>('hit')
82
-
83
- // Keep track of indicators for when revalidation should be 'paused'
84
- // Like if we're currently offline, or the document isn't visible
85
- // Basically if 'stale' and all good we return 'refresh'
86
-
87
- // Next keep track of staleness itself. If we come back online, on a windows focus event
88
- // or on a refreshInterval timeout
89
- // Basically it controls if cache should be 'hit' or 'stale'
90
-
91
- // How to handle refresh to inflight?
92
-
93
- const startRefresh = useCallback(() => {
94
- setState('inflight')
95
- return () => setState('hit')
96
- }, [])
97
-
98
- // Revalidate on refreshInterval
99
- useEffect(() => {
100
- // If refreshInterval is nullish then we don't want to refresh.
101
- // Inflight means it's already refreshing and we pause the countdown.
102
- // It's only necessary to start the countdown if the cache isn't already stale
103
- if (!refreshInterval || state !== 'hit') {
104
- return undefined
105
- }
106
- const timeout = setTimeout(() => setState('stale'), refreshInterval)
107
- return () => clearTimeout(timeout)
108
- }, [refreshInterval, state])
109
- // Revalidate on windows focus
110
- useEffect(() => {
111
- if (state !== 'hit') {
112
- return undefined
113
- }
114
- const onFocus = () => setState('stale')
115
- window.addEventListener('focus', onFocus)
116
- return () => window.removeEventListener('focus', onFocus)
117
- }, [refreshInterval, state])
118
- // Revalidate on changes to shouldPause
119
- useEffect(() => {
120
- // Mark as stale pre-emptively if we're offline or the document isn't visible
121
- if (shouldPause && state === 'hit') {
122
- setState('stale')
123
- }
124
- // If not paused we can mark stale as ready for refresh
125
- if (!shouldPause && state === 'stale') {
126
- setState('refresh')
127
- }
128
- }, [shouldPause, state])
129
-
130
- return [state, startRefresh]
131
- }
132
-
133
- /**
134
- * Keeps track of when revalidation and activities should be paused
135
- */
136
- function useShouldPause(): boolean {
137
- const [online, setOnline] = useState(false)
138
- useEffect(() => {
139
- setOnline(navigator.onLine)
140
- // eslint-disable-next-line @typescript-eslint/no-shadow
141
- const online = () => setOnline(true)
142
- const offline = () => setOnline(false)
143
- window.addEventListener('online', online)
144
- window.addEventListener('offline', offline)
145
- return () => {
146
- window.removeEventListener('online', online)
147
- window.removeEventListener('offline', offline)
148
- }
149
- }, [])
150
- const visibilityState = useSyncExternalStore(
151
- onVisibilityChange,
152
- () => document.visibilityState,
153
- () => 'hidden' satisfies DocumentVisibilityState,
154
- )
155
-
156
- // Should pause activity when offline
157
- if (!online) {
158
- return true
159
- }
160
-
161
- // Should pause when the document isn't visible, as it's likely the user isn't looking at the page
162
- if (visibilityState === 'hidden') {
163
- return true
164
- }
165
-
166
- return false
167
- }
168
-
169
- function onVisibilityChange(onStoreChange: () => void): () => void {
170
- document.addEventListener('visibilitychange', onStoreChange)
171
- return () => document.removeEventListener('visibilitychange', onStoreChange)
48
+ return `${perspective}:${query}:${JSON.stringify(params)}`
172
49
  }
@@ -1,4 +1,4 @@
1
- import {type ClientPerspective, type QueryParams} from '@sanity/client'
1
+ import {type ClientPerspective} from '@sanity/client'
2
2
  import {type ChannelInstance} from '@sanity/comlink'
3
3
  import {
4
4
  type LoaderControllerMsg,
@@ -257,23 +257,6 @@ export type PresentationPerspective = Extract<'published' | 'previewDrafts', Cli
257
257
  /** @public */
258
258
  export type PresentationViewport = 'desktop' | 'mobile'
259
259
 
260
- /** @internal */
261
- export type LiveQueriesState = Record<string, LiveQueriesStateValue>
262
-
263
- /** @internal */
264
- export interface LiveQueriesStateValue {
265
- query: string
266
- params: QueryParams
267
- perspective: ClientPerspective
268
- receivedAt: number
269
- /**
270
- * If false it means the query can't safely be garbage collected,
271
- * as older versions of \@sanity/core-loader doesn't fire listen events
272
- * on an interval.
273
- */
274
- heartbeat: number | false
275
- }
276
-
277
260
  /** @internal */
278
261
  export interface FrameState {
279
262
  title: string | undefined
@@ -1,281 +0,0 @@
1
- "use strict";
2
- var jsxRuntime = require("react/jsx-runtime"), reactCompilerRuntime = require("react-compiler-runtime"), csm = require("@sanity/client/csm"), comlink = require("@sanity/comlink"), presentationComlink = require("@sanity/presentation-comlink"), mendoza = require("mendoza"), LRUCache = require("mnemonist/lru-cache-with-delete"), React = require("react"), sanity = require("sanity"), presentation = require("./presentation.js"), utils = require("./utils.js");
3
- function _interopDefaultCompat(e) {
4
- return e && typeof e == "object" && "default" in e ? e : { default: e };
5
- }
6
- var LRUCache__default = /* @__PURE__ */ _interopDefaultCompat(LRUCache);
7
- function LoaderQueries(props) {
8
- const {
9
- liveDocument,
10
- controller,
11
- perspective: activePerspective,
12
- documentsOnPage,
13
- onLoadersConnection,
14
- onDocumentsOnPage
15
- } = props, [comlink$1, setComlink] = React.useState(), [liveQueries, setLiveQueries] = React.useState({}), projectId = sanity.useProjectId(), dataset = sanity.useDataset();
16
- React.useEffect(() => {
17
- const interval = setInterval(() => (
18
- // eslint-disable-next-line @typescript-eslint/no-shadow
19
- setLiveQueries((liveQueries_0) => {
20
- if (Object.keys(liveQueries_0).length < 1)
21
- return liveQueries_0;
22
- const now = Date.now();
23
- if (!Object.values(liveQueries_0).some(
24
- // eslint-disable-next-line max-nested-callbacks
25
- (liveQuery) => liveQuery.heartbeat !== !1 && now > liveQuery.receivedAt + liveQuery.heartbeat
26
- ))
27
- return liveQueries_0;
28
- const next = {};
29
- for (const [key, value] of Object.entries(liveQueries_0))
30
- value.heartbeat !== !1 && now > value.receivedAt + value.heartbeat || (next[key] = value);
31
- return next;
32
- })
33
- ), presentation.MIN_LOADER_QUERY_LISTEN_HEARTBEAT_INTERVAL);
34
- return () => clearInterval(interval);
35
- }, []), React.useEffect(() => {
36
- if (controller) {
37
- const comlink_0 = controller.createChannel({
38
- name: "presentation",
39
- connectTo: "loaders",
40
- heartbeat: !0
41
- }, comlink.createConnectionMachine().provide({
42
- actors: presentationComlink.createCompatibilityActors()
43
- }));
44
- return setComlink(comlink_0), comlink_0.onStatus(onLoadersConnection), comlink_0.on("loader/documents", (data) => {
45
- data.projectId === projectId && data.dataset === dataset && onDocumentsOnPage(
46
- "loaders",
47
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
48
- data.perspective,
49
- data.documents
50
- );
51
- }), comlink_0.on("loader/query-listen", (data_0) => {
52
- if (data_0.projectId === projectId && data_0.dataset === dataset) {
53
- if (typeof data_0.heartbeat == "number" && data_0.heartbeat < presentation.MIN_LOADER_QUERY_LISTEN_HEARTBEAT_INTERVAL)
54
- throw new Error(`Loader query listen heartbeat interval must be at least ${presentation.MIN_LOADER_QUERY_LISTEN_HEARTBEAT_INTERVAL}ms`);
55
- setLiveQueries((prev) => ({
56
- ...prev,
57
- [getQueryCacheKey(data_0.query, data_0.params)]: {
58
- perspective: data_0.perspective,
59
- query: data_0.query,
60
- params: data_0.params,
61
- receivedAt: Date.now(),
62
- heartbeat: data_0.heartbeat ?? !1
63
- }
64
- }));
65
- }
66
- }), comlink_0.start();
67
- }
68
- }, [controller, dataset, onDocumentsOnPage, onLoadersConnection, projectId]);
69
- const [cache] = React.useState(() => new LRUCache__default.default(presentation.LIVE_QUERY_CACHE_SIZE)), studioClient = sanity.useClient({
70
- apiVersion: "2023-10-16"
71
- }), clientConfig = React.useMemo(() => studioClient.config(), [studioClient]), client = React.useMemo(() => studioClient.withConfig({
72
- resultSourceMap: "withKeyArraySelector"
73
- }), [studioClient]);
74
- React.useEffect(() => {
75
- if (comlink$1) {
76
- const {
77
- projectId: projectId_0,
78
- dataset: dataset_0
79
- } = clientConfig;
80
- comlink$1.post("loader/perspective", {
81
- projectId: projectId_0,
82
- dataset: dataset_0,
83
- perspective: activePerspective
84
- });
85
- }
86
- }, [comlink$1, clientConfig, activePerspective]);
87
- const turboIds = React.useMemo(() => {
88
- const documentsActuallyInUse = documentsOnPage.map(({
89
- _id
90
- }) => _id), ids = [...new Set(documentsActuallyInUse)], max = cache.capacity;
91
- return ids.length >= max && (ids.length = max), ids;
92
- }, [cache.capacity, documentsOnPage]), [documentsCacheLastUpdated, setDocumentsCacheLastUpdated] = React.useState(0);
93
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
94
- /* @__PURE__ */ jsxRuntime.jsx(Turbo, { cache, client, turboIds, setDocumentsCacheLastUpdated }),
95
- Object.entries(liveQueries).map(([key_0, {
96
- query,
97
- params,
98
- perspective
99
- }]) => /* @__PURE__ */ jsxRuntime.jsx(QuerySubscription, { cache, projectId: clientConfig.projectId, dataset: clientConfig.dataset, perspective, query, params, comlink: comlink$1, client, refreshInterval: activePerspective ? 2e3 : 0, liveDocument, documentsCacheLastUpdated }, `${key_0}${perspective}`))
100
- ] });
101
- }
102
- const Turbo = React.memo(function(props) {
103
- const {
104
- cache,
105
- client,
106
- turboIds,
107
- setDocumentsCacheLastUpdated
108
- } = props, [batch, setBatch] = React.useState([]);
109
- return React.useEffect(() => {
110
- const batchSet = new Set(batch.flat()), nextBatch = /* @__PURE__ */ new Set();
111
- for (const turboId of turboIds)
112
- !batchSet.has(turboId) && !cache.has(turboId) && nextBatch.add(turboId);
113
- const nextBatchSlice = [...nextBatch].slice(0, presentation.LIVE_QUERY_CACHE_BATCH_SIZE);
114
- if (nextBatchSlice.length === 0) return;
115
- const raf = requestAnimationFrame(() => (
116
- // eslint-disable-next-line max-nested-callbacks
117
- setBatch((prevBatch) => [...prevBatch.slice(-100), nextBatchSlice])
118
- ));
119
- return () => cancelAnimationFrame(raf);
120
- }, [batch, cache, turboIds]), React.useEffect(() => {
121
- const subscription = client.listen("*", {}, {
122
- events: ["mutation"],
123
- effectFormat: "mendoza",
124
- includePreviousRevision: !1,
125
- includeResult: !1,
126
- tag: "presentation-loader"
127
- }).subscribe((update) => {
128
- if (update.type === "mutation" && update.transition === "disappear" && cache.delete(update.documentId) && setDocumentsCacheLastUpdated(Date.now()), update.type !== "mutation" || !update.effects?.apply?.length) return;
129
- const cachedDocument = cache.peek(update.documentId);
130
- if (cachedDocument) {
131
- const patchDoc = {
132
- ...cachedDocument
133
- };
134
- delete patchDoc._rev;
135
- const patchedDocument = mendoza.applyPatch(patchDoc, update.effects.apply);
136
- cache.set(update.documentId, patchedDocument), setDocumentsCacheLastUpdated(Date.now());
137
- }
138
- });
139
- return () => subscription.unsubscribe();
140
- }, [cache, client, setDocumentsCacheLastUpdated]), /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: batch.map((ids) => /* @__PURE__ */ jsxRuntime.jsx(GetDocuments, { cache, client, ids, setDocumentsCacheLastUpdated }, JSON.stringify(ids))) });
141
- }), GetDocuments = React.memo(function(props) {
142
- const {
143
- client,
144
- cache,
145
- ids,
146
- setDocumentsCacheLastUpdated
147
- } = props;
148
- return React.useEffect(() => {
149
- const missingIds = ids.filter((id) => !cache.has(id));
150
- missingIds.length !== 0 && client.getDocuments(missingIds).then((documents) => {
151
- for (const doc of documents)
152
- doc && doc?._id && (cache.set(doc._id, doc), setDocumentsCacheLastUpdated(Date.now()));
153
- }, console.error);
154
- }, [cache, client, ids, setDocumentsCacheLastUpdated]), null;
155
- });
156
- GetDocuments.displayName = "GetDocuments";
157
- function QuerySubscription(props) {
158
- const $ = reactCompilerRuntime.c(20), {
159
- cache,
160
- projectId,
161
- dataset,
162
- perspective,
163
- query,
164
- client,
165
- refreshInterval,
166
- liveDocument,
167
- comlink: comlink2,
168
- documentsCacheLastUpdated
169
- } = props, params = utils.useQueryParams(props.params);
170
- let t0;
171
- $[0] !== cache || $[1] !== client || $[2] !== documentsCacheLastUpdated || $[3] !== liveDocument || $[4] !== params || $[5] !== perspective || $[6] !== query || $[7] !== refreshInterval ? (t0 = {
172
- cache,
173
- client,
174
- liveDocument,
175
- params,
176
- perspective,
177
- query,
178
- refreshInterval,
179
- documentsCacheLastUpdated
180
- }, $[0] = cache, $[1] = client, $[2] = documentsCacheLastUpdated, $[3] = liveDocument, $[4] = params, $[5] = perspective, $[6] = query, $[7] = refreshInterval, $[8] = t0) : t0 = $[8];
181
- const data = useQuerySubscription(t0), result = data?.result, resultSourceMap = data?.resultSourceMap, tags = data?.tags;
182
- let t1, t2;
183
- return $[9] !== comlink2 || $[10] !== dataset || $[11] !== params || $[12] !== perspective || $[13] !== projectId || $[14] !== query || $[15] !== result || $[16] !== resultSourceMap || $[17] !== tags ? (t1 = () => {
184
- resultSourceMap && comlink2?.post("loader/query-change", {
185
- projectId,
186
- dataset,
187
- perspective,
188
- query,
189
- params,
190
- result,
191
- resultSourceMap,
192
- tags
193
- });
194
- }, t2 = [comlink2, dataset, params, perspective, projectId, query, result, resultSourceMap, tags], $[9] = comlink2, $[10] = dataset, $[11] = params, $[12] = perspective, $[13] = projectId, $[14] = query, $[15] = result, $[16] = resultSourceMap, $[17] = tags, $[18] = t1, $[19] = t2) : (t1 = $[18], t2 = $[19]), React.useEffect(t1, t2), null;
195
- }
196
- function useQuerySubscription(props) {
197
- const {
198
- cache,
199
- liveDocument,
200
- client,
201
- refreshInterval,
202
- query,
203
- params,
204
- perspective,
205
- documentsCacheLastUpdated
206
- } = props, [snapshot, setSnapshot] = React.useState(null), {
207
- projectId: projectId_0,
208
- dataset: dataset_0
209
- } = React.useMemo(() => {
210
- const {
211
- projectId,
212
- dataset
213
- } = client.config();
214
- return {
215
- projectId,
216
- dataset
217
- };
218
- }, [client]), [error, setError] = React.useState(null);
219
- if (error) throw error;
220
- const [revalidate, startRefresh] = utils.useRevalidate({
221
- refreshInterval
222
- }), shouldRefetch = revalidate === "refresh" || revalidate === "inflight";
223
- return React.useEffect(() => {
224
- if (!shouldRefetch)
225
- return;
226
- let fulfilled = !1, fetching = !1;
227
- const controller = new AbortController();
228
- async function effect() {
229
- const {
230
- signal
231
- } = controller;
232
- fetching = !0;
233
- const {
234
- result,
235
- resultSourceMap,
236
- syncTags
237
- } = await client.fetch(query, params, {
238
- tag: "presentation-loader",
239
- signal,
240
- perspective,
241
- filterResponse: !1
242
- });
243
- fetching = !1, signal.aborted || (setSnapshot({
244
- result,
245
- resultSourceMap,
246
- tags: syncTags
247
- }), fulfilled = !0);
248
- }
249
- const onFinally = startRefresh();
250
- return effect().catch((error_0) => {
251
- fetching = !1, error_0.name !== "AbortError" && setError(error_0);
252
- }).finally(onFinally), () => {
253
- !fulfilled && !fetching && controller.abort();
254
- };
255
- }, [client, dataset_0, liveDocument, params, perspective, projectId_0, query, shouldRefetch, startRefresh]), React.useMemo(() => documentsCacheLastUpdated && snapshot?.resultSourceMap ? {
256
- result: turboChargeResultIfSourceMap(cache, liveDocument, snapshot.result, perspective, snapshot.resultSourceMap),
257
- resultSourceMap: snapshot.resultSourceMap
258
- } : snapshot, [cache, documentsCacheLastUpdated, liveDocument, perspective, snapshot]);
259
- }
260
- let warnedAboutCrossDatasetReference = !1;
261
- function turboChargeResultIfSourceMap(cache, liveDocument, result, perspective, resultSourceMap) {
262
- if (perspective === "raw")
263
- throw new Error("turboChargeResultIfSourceMap does not support raw perspective");
264
- return csm.applySourceDocuments(result, resultSourceMap, (sourceDocument) => {
265
- if (sourceDocument._projectId) {
266
- warnedAboutCrossDatasetReference || (console.warn("Cross dataset references are not supported yet, ignoring source document", sourceDocument), warnedAboutCrossDatasetReference = !0);
267
- return;
268
- }
269
- return liveDocument?._id && csm.getPublishedId(liveDocument._id) === csm.getPublishedId(sourceDocument._id) ? typeof liveDocument._id == "string" && typeof sourceDocument._type == "string" ? liveDocument : {
270
- ...liveDocument,
271
- _id: liveDocument._id || sourceDocument._id,
272
- _type: liveDocument._type || sourceDocument._type
273
- } : cache.get(sourceDocument._id);
274
- }, utils.mapChangedValue, perspective);
275
- }
276
- function getQueryCacheKey(query, params) {
277
- return `${query}-${typeof params == "string" ? params : JSON.stringify(params)}`;
278
- }
279
- exports.default = LoaderQueries;
280
- exports.turboChargeResultIfSourceMap = turboChargeResultIfSourceMap;
281
- //# sourceMappingURL=LoaderQueries.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"LoaderQueries.js","sources":["../../src/presentation/loader/LoaderQueries.tsx"],"sourcesContent":["import {\n type ClientConfig,\n type ClientPerspective,\n type ContentSourceMap,\n type QueryParams,\n type SyncTag,\n} from '@sanity/client'\nimport {applySourceDocuments, getPublishedId} from '@sanity/client/csm'\nimport {\n type ChannelInstance,\n type Controller,\n createConnectionMachine,\n type StatusEvent,\n} from '@sanity/comlink'\nimport {\n createCompatibilityActors,\n type LoaderControllerMsg,\n type LoaderNodeMsg,\n} from '@sanity/presentation-comlink'\nimport {applyPatch} from 'mendoza'\nimport LRUCache from 'mnemonist/lru-cache-with-delete'\nimport {memo, useEffect, useMemo, useState} from 'react'\nimport {\n type SanityClient,\n type SanityDocument,\n useClient,\n // useCurrentUser,\n useDataset,\n useProjectId,\n} from 'sanity'\n\nimport {\n LIVE_QUERY_CACHE_BATCH_SIZE,\n LIVE_QUERY_CACHE_SIZE,\n MIN_LOADER_QUERY_LISTEN_HEARTBEAT_INTERVAL,\n} from '../constants'\nimport {\n type LiveQueriesState,\n type LiveQueriesStateValue,\n type LoaderConnection,\n type PresentationPerspective,\n} from '../types'\nimport {type DocumentOnPage} from '../useDocumentsOnPage'\nimport {mapChangedValue, useQueryParams, useRevalidate} from './utils'\n\nexport interface LoaderQueriesProps {\n liveDocument: Partial<SanityDocument> | null | undefined\n controller: Controller | undefined\n perspective: ClientPerspective\n documentsOnPage: {_id: string; _type: string}[]\n onLoadersConnection: (event: StatusEvent) => void\n onDocumentsOnPage: (\n key: string,\n perspective: PresentationPerspective,\n state: DocumentOnPage[],\n ) => void\n}\n\nexport default function LoaderQueries(props: LoaderQueriesProps): React.JSX.Element {\n const {\n liveDocument,\n controller,\n perspective: activePerspective,\n documentsOnPage,\n onLoadersConnection,\n onDocumentsOnPage,\n } = props\n\n const [comlink, setComlink] = useState<ChannelInstance<LoaderControllerMsg, LoaderNodeMsg>>()\n const [liveQueries, setLiveQueries] = useState<LiveQueriesState>({})\n\n const projectId = useProjectId()\n const dataset = useDataset()\n\n useEffect(() => {\n const interval = setInterval(\n () =>\n // eslint-disable-next-line @typescript-eslint/no-shadow\n setLiveQueries((liveQueries) => {\n if (Object.keys(liveQueries).length < 1) {\n return liveQueries\n }\n\n const now = Date.now()\n const hasAnyExpired = Object.values(liveQueries).some(\n // eslint-disable-next-line max-nested-callbacks\n (liveQuery) =>\n liveQuery.heartbeat !== false && now > liveQuery.receivedAt + liveQuery.heartbeat,\n )\n if (!hasAnyExpired) {\n return liveQueries\n }\n const next = {} as LiveQueriesState\n for (const [key, value] of Object.entries(liveQueries)) {\n if (value.heartbeat !== false && now > value.receivedAt + value.heartbeat) {\n continue\n }\n next[key] = value\n }\n return next\n }),\n MIN_LOADER_QUERY_LISTEN_HEARTBEAT_INTERVAL,\n )\n return () => clearInterval(interval)\n }, [])\n\n useEffect(() => {\n if (controller) {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const comlink = controller.createChannel<LoaderControllerMsg, LoaderNodeMsg>(\n {\n name: 'presentation',\n connectTo: 'loaders',\n heartbeat: true,\n },\n createConnectionMachine<LoaderControllerMsg, LoaderNodeMsg>().provide({\n actors: createCompatibilityActors<LoaderControllerMsg>(),\n }),\n )\n setComlink(comlink)\n\n comlink.onStatus(onLoadersConnection)\n\n comlink.on('loader/documents', (data) => {\n if (data.projectId === projectId && data.dataset === dataset) {\n onDocumentsOnPage(\n 'loaders',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n data.perspective as unknown as any,\n data.documents,\n )\n }\n })\n\n comlink.on('loader/query-listen', (data) => {\n if (data.projectId === projectId && data.dataset === dataset) {\n if (\n typeof data.heartbeat === 'number' &&\n data.heartbeat < MIN_LOADER_QUERY_LISTEN_HEARTBEAT_INTERVAL\n ) {\n throw new Error(\n `Loader query listen heartbeat interval must be at least ${MIN_LOADER_QUERY_LISTEN_HEARTBEAT_INTERVAL}ms`,\n )\n }\n setLiveQueries((prev) => ({\n ...prev,\n [getQueryCacheKey(data.query, data.params)]: {\n perspective: data.perspective,\n query: data.query,\n params: data.params,\n receivedAt: Date.now(),\n heartbeat: data.heartbeat ?? false,\n } satisfies LiveQueriesStateValue,\n }))\n }\n })\n\n return comlink.start()\n }\n return undefined\n }, [controller, dataset, onDocumentsOnPage, onLoadersConnection, projectId])\n\n const [cache] = useState(() => new LRUCache<string, SanityDocument>(LIVE_QUERY_CACHE_SIZE))\n const studioClient = useClient({apiVersion: '2023-10-16'})\n const clientConfig = useMemo(() => studioClient.config(), [studioClient])\n const client = useMemo(\n () =>\n studioClient.withConfig({\n resultSourceMap: 'withKeyArraySelector',\n }),\n [studioClient],\n )\n useEffect(() => {\n if (comlink) {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const {projectId, dataset} = clientConfig\n comlink.post('loader/perspective', {\n projectId: projectId!,\n dataset: dataset!,\n perspective: activePerspective,\n })\n }\n }, [comlink, clientConfig, activePerspective])\n\n const turboIds = useMemo(() => {\n const documentsActuallyInUse = documentsOnPage.map(({_id}) => _id)\n const set = new Set(documentsActuallyInUse)\n const ids = [...set]\n const max = cache.capacity\n if (ids.length >= max) {\n ids.length = max\n }\n return ids\n }, [cache.capacity, documentsOnPage])\n\n const [documentsCacheLastUpdated, setDocumentsCacheLastUpdated] = useState(0)\n\n return (\n <>\n <Turbo\n cache={cache}\n client={client}\n turboIds={turboIds}\n setDocumentsCacheLastUpdated={setDocumentsCacheLastUpdated}\n />\n {Object.entries(liveQueries).map(([key, {query, params, perspective}]) => (\n <QuerySubscription\n key={`${key}${perspective}`}\n cache={cache}\n projectId={clientConfig.projectId!}\n dataset={clientConfig.dataset!}\n perspective={perspective}\n query={query}\n params={params}\n comlink={comlink}\n client={client}\n refreshInterval={activePerspective ? 2000 : 0}\n liveDocument={liveDocument}\n documentsCacheLastUpdated={documentsCacheLastUpdated}\n />\n ))}\n </>\n )\n}\n\ninterface SharedProps {\n /**\n * The Sanity client to use for fetching data and listening to mutations.\n */\n client: SanityClient\n /**\n * How frequently queries should be refetched in the background to refresh the parts of queries that can't be source mapped.\n * Setting it to `0` will disable background refresh.\n * @defaultValue 10000\n */\n refreshInterval?: number\n /**\n * The documents cache to use for turbo-charging queries.\n */\n cache: LRUCache<string, SanityDocument>\n}\n\ninterface TurboProps extends Pick<SharedProps, 'client' | 'cache'> {\n turboIds: string[]\n setDocumentsCacheLastUpdated: (timestamp: number) => void\n}\n/**\n * A turbo-charged mutation observer that uses Content Source Maps to apply mendoza patches on your queries\n */\nconst Turbo = memo(function Turbo(props: TurboProps) {\n const {cache, client, turboIds, setDocumentsCacheLastUpdated} = props\n // Figure out which documents are missing from the cache\n const [batch, setBatch] = useState<string[][]>([])\n useEffect(() => {\n const batchSet = new Set(batch.flat())\n const nextBatch = new Set<string>()\n for (const turboId of turboIds) {\n if (!batchSet.has(turboId) && !cache.has(turboId)) {\n nextBatch.add(turboId)\n }\n }\n const nextBatchSlice = [...nextBatch].slice(0, LIVE_QUERY_CACHE_BATCH_SIZE)\n if (nextBatchSlice.length === 0) return undefined\n const raf = requestAnimationFrame(() =>\n // eslint-disable-next-line max-nested-callbacks\n setBatch((prevBatch) => [...prevBatch.slice(-LIVE_QUERY_CACHE_BATCH_SIZE), nextBatchSlice]),\n )\n return () => cancelAnimationFrame(raf)\n }, [batch, cache, turboIds])\n\n // Use the same listen instance and patch documents as they come in\n useEffect(() => {\n const subscription = client\n .listen(\n '*',\n {},\n {\n events: ['mutation'],\n effectFormat: 'mendoza',\n includePreviousRevision: false,\n includeResult: false,\n tag: 'presentation-loader',\n },\n )\n .subscribe((update) => {\n if (update.type === 'mutation' && update.transition === 'disappear') {\n if (cache.delete(update.documentId)) {\n setDocumentsCacheLastUpdated(Date.now())\n }\n }\n\n if (update.type !== 'mutation' || !update.effects?.apply?.length) return\n // Schedule a reach state update with the ID of the document that were mutated\n // This react handler will apply the document to related source map snapshots\n const cachedDocument = cache.peek(update.documentId)\n if (cachedDocument as SanityDocument) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const patchDoc = {...cachedDocument} as any\n delete patchDoc._rev\n const patchedDocument = applyPatch(patchDoc, update.effects.apply)\n cache.set(update.documentId, patchedDocument)\n setDocumentsCacheLastUpdated(Date.now())\n }\n })\n return () => subscription.unsubscribe()\n }, [cache, client, setDocumentsCacheLastUpdated])\n\n return (\n <>\n {batch.map((ids) => (\n <GetDocuments\n key={JSON.stringify(ids)}\n cache={cache}\n client={client}\n ids={ids}\n setDocumentsCacheLastUpdated={setDocumentsCacheLastUpdated}\n />\n ))}\n </>\n )\n})\n\ninterface GetDocumentsProps extends Pick<SharedProps, 'client' | 'cache'> {\n ids: string[]\n setDocumentsCacheLastUpdated: (timestamp: number) => void\n}\nconst GetDocuments = memo(function GetDocuments(props: GetDocumentsProps) {\n const {client, cache, ids, setDocumentsCacheLastUpdated} = props\n\n useEffect(() => {\n const missingIds = ids.filter((id) => !cache.has(id))\n if (missingIds.length === 0) return\n client.getDocuments(missingIds).then((documents) => {\n for (const doc of documents) {\n if (doc && doc?._id) {\n cache.set(doc._id, doc)\n setDocumentsCacheLastUpdated(Date.now())\n }\n }\n // eslint-disable-next-line no-console\n }, console.error)\n }, [cache, client, ids, setDocumentsCacheLastUpdated])\n\n return null\n})\nGetDocuments.displayName = 'GetDocuments'\n\ninterface QuerySubscriptionProps\n extends Pick<\n UseQuerySubscriptionProps,\n 'client' | 'cache' | 'refreshInterval' | 'liveDocument' | 'documentsCacheLastUpdated'\n > {\n projectId: string\n dataset: string\n perspective: ClientPerspective\n query: string\n params: QueryParams\n comlink: LoaderConnection | undefined\n}\nfunction QuerySubscription(props: QuerySubscriptionProps) {\n const {\n cache,\n projectId,\n dataset,\n perspective,\n query,\n client,\n refreshInterval,\n liveDocument,\n comlink,\n documentsCacheLastUpdated,\n } = props\n\n const params = useQueryParams(props.params)\n const data = useQuerySubscription({\n cache,\n client,\n liveDocument,\n params,\n perspective,\n query,\n refreshInterval,\n documentsCacheLastUpdated,\n })\n const result = data?.result\n const resultSourceMap = data?.resultSourceMap\n const tags = data?.tags\n\n useEffect(() => {\n if (resultSourceMap) {\n comlink?.post('loader/query-change', {\n projectId,\n dataset,\n perspective,\n query,\n params,\n result,\n resultSourceMap,\n tags,\n })\n }\n }, [comlink, dataset, params, perspective, projectId, query, result, resultSourceMap, tags])\n\n return null\n}\n\ninterface UseQuerySubscriptionProps\n extends Required<Pick<SharedProps, 'client' | 'refreshInterval' | 'cache'>> {\n liveDocument: Partial<SanityDocument> | null | undefined\n query: string\n params: QueryParams\n perspective: ClientPerspective\n documentsCacheLastUpdated: number\n}\nfunction useQuerySubscription(props: UseQuerySubscriptionProps) {\n const {\n cache,\n liveDocument,\n client,\n refreshInterval,\n query,\n params,\n perspective,\n documentsCacheLastUpdated,\n } = props\n const [snapshot, setSnapshot] = useState<{\n result: unknown\n resultSourceMap?: ContentSourceMap\n tags?: SyncTag[]\n } | null>(null)\n const {projectId, dataset} = useMemo(() => {\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const {projectId, dataset} = client.config()\n return {projectId, dataset} as Required<Pick<ClientConfig, 'projectId' | 'dataset'>>\n }, [client])\n\n // Make sure any async errors bubble up to the nearest error boundary\n const [error, setError] = useState<unknown>(null)\n if (error) throw error\n\n const [revalidate, startRefresh] = useRevalidate({refreshInterval})\n const shouldRefetch = revalidate === 'refresh' || revalidate === 'inflight'\n useEffect(() => {\n if (!shouldRefetch) {\n return undefined\n }\n\n let fulfilled = false\n let fetching = false\n const controller = new AbortController()\n // eslint-disable-next-line no-inner-declarations\n async function effect() {\n const {signal} = controller\n fetching = true\n const {result, resultSourceMap, syncTags} = await client.fetch(query, params, {\n tag: 'presentation-loader',\n signal,\n perspective,\n filterResponse: false,\n })\n fetching = false\n\n if (!signal.aborted) {\n setSnapshot({result, resultSourceMap, tags: syncTags})\n\n fulfilled = true\n }\n }\n const onFinally = startRefresh()\n effect()\n // eslint-disable-next-line @typescript-eslint/no-shadow\n .catch((error) => {\n fetching = false\n if (error.name !== 'AbortError') {\n setError(error)\n }\n })\n .finally(onFinally)\n return () => {\n if (!fulfilled && !fetching) {\n controller.abort()\n }\n }\n }, [\n client,\n dataset,\n liveDocument,\n params,\n perspective,\n projectId,\n query,\n shouldRefetch,\n startRefresh,\n ])\n\n return useMemo(() => {\n if (documentsCacheLastUpdated && snapshot?.resultSourceMap) {\n return {\n result: turboChargeResultIfSourceMap(\n cache,\n liveDocument,\n snapshot.result,\n perspective,\n snapshot.resultSourceMap,\n ),\n resultSourceMap: snapshot.resultSourceMap,\n }\n }\n return snapshot\n }, [cache, documentsCacheLastUpdated, liveDocument, perspective, snapshot])\n}\n\nlet warnedAboutCrossDatasetReference = false\nexport function turboChargeResultIfSourceMap<T = unknown>(\n cache: SharedProps['cache'],\n liveDocument: Partial<SanityDocument> | null | undefined,\n result: T,\n perspective: ClientPerspective,\n resultSourceMap?: ContentSourceMap,\n): T {\n if (perspective === 'raw') {\n throw new Error('turboChargeResultIfSourceMap does not support raw perspective')\n }\n return applySourceDocuments(\n result,\n resultSourceMap,\n (sourceDocument) => {\n if (sourceDocument._projectId) {\n // @TODO Handle cross dataset references\n if (!warnedAboutCrossDatasetReference) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Cross dataset references are not supported yet, ignoring source document',\n sourceDocument,\n )\n warnedAboutCrossDatasetReference = true\n }\n return undefined\n }\n // If there's a displayed document, always prefer it\n if (\n liveDocument?._id &&\n getPublishedId(liveDocument._id) === getPublishedId(sourceDocument._id)\n ) {\n if (typeof liveDocument._id === 'string' && typeof sourceDocument._type === 'string') {\n return liveDocument as unknown as Required<Pick<SanityDocument, '_id' | '_type'>>\n }\n return {\n ...liveDocument,\n _id: liveDocument._id || sourceDocument._id,\n _type: liveDocument._type || sourceDocument._type,\n }\n }\n // Fallback to general documents cache\n return cache.get(sourceDocument._id)\n },\n mapChangedValue,\n perspective,\n )\n}\n\nfunction getQueryCacheKey(query: string, params: QueryParams | string): `${string}-${string}` {\n return `${query}-${typeof params === 'string' ? params : JSON.stringify(params)}`\n}\n"],"names":["LoaderQueries","props","liveDocument","controller","perspective","activePerspective","documentsOnPage","onLoadersConnection","onDocumentsOnPage","comlink","setComlink","useState","liveQueries","setLiveQueries","projectId","useProjectId","dataset","useDataset","useEffect","interval","setInterval","Object","keys","length","now","Date","values","some","liveQuery","heartbeat","receivedAt","next","key","value","entries","MIN_LOADER_QUERY_LISTEN_HEARTBEAT_INTERVAL","clearInterval","createChannel","name","connectTo","createConnectionMachine","provide","actors","createCompatibilityActors","onStatus","on","data","documents","Error","prev","getQueryCacheKey","query","params","start","cache","LRUCache","LIVE_QUERY_CACHE_SIZE","studioClient","useClient","apiVersion","clientConfig","useMemo","config","client","withConfig","resultSourceMap","post","turboIds","documentsActuallyInUse","map","_id","ids","Set","max","capacity","documentsCacheLastUpdated","setDocumentsCacheLastUpdated","jsxs","Fragment","jsx","Turbo","memo","batch","setBatch","batchSet","flat","nextBatch","turboId","has","add","nextBatchSlice","slice","LIVE_QUERY_CACHE_BATCH_SIZE","raf","requestAnimationFrame","prevBatch","cancelAnimationFrame","subscription","listen","events","effectFormat","includePreviousRevision","includeResult","tag","subscribe","update","type","transition","delete","documentId","effects","apply","cachedDocument","peek","patchDoc","_rev","patchedDocument","applyPatch","set","unsubscribe","JSON","stringify","GetDocuments","missingIds","filter","id","getDocuments","then","doc","console","error","displayName","QuerySubscription","$","_c","refreshInterval","useQueryParams","t0","useQuerySubscription","result","tags","t1","t2","snapshot","setSnapshot","setError","revalidate","startRefresh","useRevalidate","shouldRefetch","fulfilled","fetching","AbortController","effect","signal","syncTags","fetch","filterResponse","aborted","onFinally","catch","finally","abort","turboChargeResultIfSourceMap","warnedAboutCrossDatasetReference","applySourceDocuments","sourceDocument","_projectId","warn","getPublishedId","_type","get","mapChangedValue"],"mappings":"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"}
@@ -1,70 +0,0 @@
1
- "use strict";
2
- var reactCompilerRuntime = require("react-compiler-runtime"), react = require("@portabletext/react"), toolkit = require("@portabletext/toolkit"), React = require("react");
3
- const mapChangedValue = (changedValue, {
4
- previousValue
5
- }) => {
6
- if (typeof previousValue == "string") {
7
- if (typeof changedValue == "number")
8
- return `${changedValue}`;
9
- if (Array.isArray(changedValue)) {
10
- if (changedValue.length === 0)
11
- return "";
12
- if (changedValue.some((node) => typeof node == "object" && toolkit.isPortableTextBlock(node)))
13
- return react.toPlainText(changedValue);
14
- }
15
- }
16
- return changedValue;
17
- };
18
- function useQueryParams(params) {
19
- const stringifiedParams = React.useMemo(() => JSON.stringify(params || {}), [params]);
20
- return React.useMemo(() => JSON.parse(stringifiedParams), [stringifiedParams]);
21
- }
22
- function useRevalidate(props) {
23
- const $ = reactCompilerRuntime.c(16), {
24
- refreshInterval
25
- } = props, shouldPause = useShouldPause(), [state, setState] = React.useState("hit");
26
- let t0;
27
- $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => (setState("inflight"), () => setState("hit")), $[0] = t0) : t0 = $[0];
28
- const startRefresh = t0;
29
- let t1, t2;
30
- $[1] !== refreshInterval || $[2] !== state ? (t1 = () => {
31
- if (!refreshInterval || state !== "hit")
32
- return;
33
- const timeout = setTimeout(() => setState("stale"), refreshInterval);
34
- return () => clearTimeout(timeout);
35
- }, t2 = [refreshInterval, state], $[1] = refreshInterval, $[2] = state, $[3] = t1, $[4] = t2) : (t1 = $[3], t2 = $[4]), React.useEffect(t1, t2);
36
- let t3;
37
- $[5] !== state ? (t3 = () => {
38
- if (state !== "hit")
39
- return;
40
- const onFocus = () => setState("stale");
41
- return window.addEventListener("focus", onFocus), () => window.removeEventListener("focus", onFocus);
42
- }, $[5] = state, $[6] = t3) : t3 = $[6];
43
- let t4;
44
- $[7] !== refreshInterval || $[8] !== state ? (t4 = [refreshInterval, state], $[7] = refreshInterval, $[8] = state, $[9] = t4) : t4 = $[9], React.useEffect(t3, t4);
45
- let t5, t6;
46
- $[10] !== shouldPause || $[11] !== state ? (t5 = () => {
47
- shouldPause && state === "hit" && setState("stale"), !shouldPause && state === "stale" && setState("refresh");
48
- }, t6 = [shouldPause, state], $[10] = shouldPause, $[11] = state, $[12] = t5, $[13] = t6) : (t5 = $[12], t6 = $[13]), React.useEffect(t5, t6);
49
- let t7;
50
- return $[14] !== state ? (t7 = [state, startRefresh], $[14] = state, $[15] = t7) : t7 = $[15], t7;
51
- }
52
- function useShouldPause() {
53
- const [online, setOnline] = React.useState(!1);
54
- React.useEffect(() => {
55
- setOnline(navigator.onLine);
56
- const online_0 = () => setOnline(!0), offline = () => setOnline(!1);
57
- return window.addEventListener("online", online_0), window.addEventListener("offline", offline), () => {
58
- window.removeEventListener("online", online_0), window.removeEventListener("offline", offline);
59
- };
60
- }, []);
61
- const visibilityState = React.useSyncExternalStore(onVisibilityChange, () => document.visibilityState, () => "hidden");
62
- return !online || visibilityState === "hidden";
63
- }
64
- function onVisibilityChange(onStoreChange) {
65
- return document.addEventListener("visibilitychange", onStoreChange), () => document.removeEventListener("visibilitychange", onStoreChange);
66
- }
67
- exports.mapChangedValue = mapChangedValue;
68
- exports.useQueryParams = useQueryParams;
69
- exports.useRevalidate = useRevalidate;
70
- //# sourceMappingURL=utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sources":["../../src/presentation/loader/utils.ts"],"sourcesContent":["import {toPlainText} from '@portabletext/react'\nimport {isPortableTextBlock} from '@portabletext/toolkit'\nimport {type ClientPerspective, type QueryParams} from '@sanity/client'\nimport {type ApplySourceDocumentsUpdateFunction} from '@sanity/client/csm'\nimport {useCallback, useEffect, useMemo, useState, useSyncExternalStore} from 'react'\nimport {type FIXME} from 'sanity'\n\n/**\n * Used by `applySourceDocuments`\n * @internal\n */\nexport const mapChangedValue: ApplySourceDocumentsUpdateFunction = (\n changedValue: FIXME,\n {previousValue},\n) => {\n if (typeof previousValue === 'string') {\n if (typeof changedValue === 'number') {\n // If the string() function was used in the query, we need to convert the source value to a string as well\n return `${changedValue}`\n }\n // If it's an array in the source, but a string in the query response, it could be pt::text\n if (Array.isArray(changedValue)) {\n if (changedValue.length === 0) {\n // If it's empty assume it's PT and return an empty string\n return ''\n }\n // If the array contains any valid block type, assume the GROQ initially used pt::text on it and do the same conversion\n if (changedValue.some((node) => typeof node === 'object' && isPortableTextBlock(node))) {\n return toPlainText(changedValue)\n }\n }\n }\n\n return changedValue\n}\n\n/**\n * @internal\n */\nexport type QueryCacheKey = `${string}-${string}-${string}`\n/**\n * @internal\n */\nexport function getQueryCacheKey(\n perspective: ClientPerspective,\n query: string,\n params: QueryParams,\n): QueryCacheKey {\n return `${perspective}-${query}-${JSON.stringify(params)}`\n}\n\n/**\n * Return params that are stable with deep equal as long as the key order is the same\n * @internal\n */\nexport function useQueryParams(params?: undefined | null | QueryParams): QueryParams {\n const stringifiedParams = useMemo(() => JSON.stringify(params || {}), [params])\n return useMemo(() => JSON.parse(stringifiedParams) as QueryParams, [stringifiedParams])\n}\n\n/**\n * 'hit' - the cache is fresh and valid\n * 'stale' - the cache should revalidate, but can't/shouldn't yet (offline, visibility = hidden)\n * 'refresh' - stale cache, and now is a great time to start refreshing\n * 'inflight' - refreshing cache, revalidate events should be ignored\n */\nexport type RevalidateState = 'hit' | 'stale' | 'refresh' | 'inflight'\n/**\n * Keeps track of when queries should revalidate\n */\nexport function useRevalidate(props: {\n /**\n * How frequently queries should be refetched in the background to refresh the parts of queries that can't be source mapped.\n * Setting it to `0` will disable background refresh.\n */\n refreshInterval: number\n}): [RevalidateState, () => () => void] {\n const {refreshInterval} = props\n\n const shouldPause = useShouldPause()\n const [state, setState] = useState<RevalidateState>('hit')\n\n // Keep track of indicators for when revalidation should be 'paused'\n // Like if we're currently offline, or the document isn't visible\n // Basically if 'stale' and all good we return 'refresh'\n\n // Next keep track of staleness itself. If we come back online, on a windows focus event\n // or on a refreshInterval timeout\n // Basically it controls if cache should be 'hit' or 'stale'\n\n // How to handle refresh to inflight?\n\n const startRefresh = useCallback(() => {\n setState('inflight')\n return () => setState('hit')\n }, [])\n\n // Revalidate on refreshInterval\n useEffect(() => {\n // If refreshInterval is nullish then we don't want to refresh.\n // Inflight means it's already refreshing and we pause the countdown.\n // It's only necessary to start the countdown if the cache isn't already stale\n if (!refreshInterval || state !== 'hit') {\n return undefined\n }\n const timeout = setTimeout(() => setState('stale'), refreshInterval)\n return () => clearTimeout(timeout)\n }, [refreshInterval, state])\n // Revalidate on windows focus\n useEffect(() => {\n if (state !== 'hit') {\n return undefined\n }\n const onFocus = () => setState('stale')\n window.addEventListener('focus', onFocus)\n return () => window.removeEventListener('focus', onFocus)\n }, [refreshInterval, state])\n // Revalidate on changes to shouldPause\n useEffect(() => {\n // Mark as stale pre-emptively if we're offline or the document isn't visible\n if (shouldPause && state === 'hit') {\n setState('stale')\n }\n // If not paused we can mark stale as ready for refresh\n if (!shouldPause && state === 'stale') {\n setState('refresh')\n }\n }, [shouldPause, state])\n\n return [state, startRefresh]\n}\n\n/**\n * Keeps track of when revalidation and activities should be paused\n */\nfunction useShouldPause(): boolean {\n const [online, setOnline] = useState(false)\n useEffect(() => {\n setOnline(navigator.onLine)\n // eslint-disable-next-line @typescript-eslint/no-shadow\n const online = () => setOnline(true)\n const offline = () => setOnline(false)\n window.addEventListener('online', online)\n window.addEventListener('offline', offline)\n return () => {\n window.removeEventListener('online', online)\n window.removeEventListener('offline', offline)\n }\n }, [])\n const visibilityState = useSyncExternalStore(\n onVisibilityChange,\n () => document.visibilityState,\n () => 'hidden' satisfies DocumentVisibilityState,\n )\n\n // Should pause activity when offline\n if (!online) {\n return true\n }\n\n // Should pause when the document isn't visible, as it's likely the user isn't looking at the page\n if (visibilityState === 'hidden') {\n return true\n }\n\n return false\n}\n\nfunction onVisibilityChange(onStoreChange: () => void): () => void {\n document.addEventListener('visibilitychange', onStoreChange)\n return () => document.removeEventListener('visibilitychange', onStoreChange)\n}\n"],"names":["mapChangedValue","changedValue","previousValue","Array","isArray","length","some","node","isPortableTextBlock","toPlainText","useQueryParams","params","stringifiedParams","useMemo","JSON","stringify","parse","useRevalidate","props","$","_c","refreshInterval","shouldPause","useShouldPause","state","setState","useState","t0","Symbol","for","startRefresh","t1","t2","timeout","setTimeout","clearTimeout","useEffect","t3","onFocus","addEventListener","window","removeEventListener","t4","t5","t6","t7","online","setOnline","navigator","onLine","offline","visibilityState","useSyncExternalStore","onVisibilityChange","document","onStoreChange"],"mappings":";;AAWaA,MAAAA,kBAAsDA,CACjEC,cACA;AAAA,EAACC;AAAa,MACX;AACC,MAAA,OAAOA,iBAAkB,UAAU;AACrC,QAAI,OAAOD,gBAAiB;AAE1B,aAAO,GAAGA,YAAY;AAGpBE,QAAAA,MAAMC,QAAQH,YAAY,GAAG;AAC/B,UAAIA,aAAaI,WAAW;AAEnB,eAAA;AAGLJ,UAAAA,aAAaK,KAAMC,CAAS,SAAA,OAAOA,QAAS,YAAYC,4BAAoBD,IAAI,CAAC;AACnF,eAAOE,MAAAA,YAAYR,YAAY;AAAA,IAAA;AAAA,EAEnC;AAGKA,SAAAA;AACT;AAqBO,SAASS,eAAeC,QAAsD;AAC7EC,QAAAA,oBAAoBC,cAAQ,MAAMC,KAAKC,UAAUJ,UAAU,CAAE,CAAA,GAAG,CAACA,MAAM,CAAC;AACvEE,SAAAA,MAAAA,QAAQ,MAAMC,KAAKE,MAAMJ,iBAAiB,GAAkB,CAACA,iBAAiB,CAAC;AACxF;AAYO,SAAAK,cAAAC,OAAA;AAAAC,QAAAA,IAAAC,uBAAA,EAAA,GAOL;AAAA,IAAAC;AAAAA,EAAAA,IAA0BH,OAE1BI,cAAoBC,eAAe,GACnC,CAAAC,OAAAC,QAAA,IAA0BC,MAAAA,SAA0B,KAAK;AAACC,MAAAA;AAAAR,IAAA,CAAA,MAAAS,OAAAC,IAAA,2BAAA,KAYzBF,KAAAA,OAC/BF,SAAS,UAAU,GACNA,MAAAA,SAAS,KAAK,IAC5BN,OAAAQ,MAAAA,KAAAR,EAAA,CAAA;AAHD,QAAAW,eAAqBH;AAGf,MAAAI,IAAAC;AAAAb,IAAAE,CAAAA,MAAAA,mBAAAF,SAAAK,SAGIO,KAAAA,MAAA;AAIJ,QAAA,CAACV,mBAAmBG,UAAU;AAAK;AAGvC,UAAAS,UAAgBC,WAAiBT,MAAAA,SAAS,OAAO,GAAGJ,eAAe;AACtDc,WAAAA,MAAAA,aAAaF,OAAO;AAAA,EAChCD,GAAAA,KAAA,CAACX,iBAAiBG,KAAK,GAACL,OAAAE,iBAAAF,OAAAK,OAAAL,OAAAY,IAAAZ,OAAAa,OAAAD,KAAAZ,EAAA,CAAA,GAAAa,KAAAb,EAAA,CAAA,IAT3BiB,MAAAA,UAAUL,IASPC,EAAwB;AAACK,MAAAA;AAAAlB,WAAAK,SAElBa,KAAAA,MAAA;AAAA,QACJb,UAAU;AAAK;AAGnBc,UAAAA,UAAAA,MAAsBb,SAAS,OAAO;AACtCc,WAAAA,OAAAA,iBAAwB,SAASD,OAAO,GAAC,MAC5BE,OAAAC,oBAA2B,SAASH,OAAO;AAAA,EAAC,GAC1DnB,OAAAK,OAAAL,OAAAkB,MAAAA,KAAAlB,EAAA,CAAA;AAAAuB,MAAAA;AAAAvB,IAAAE,CAAAA,MAAAA,mBAAAF,SAAAK,SAAEkB,KAAA,CAACrB,iBAAiBG,KAAK,GAACL,OAAAE,iBAAAF,OAAAK,OAAAL,OAAAuB,MAAAA,KAAAvB,EAAA,CAAA,GAP3BiB,MAAAA,UAAUC,IAOPK,EAAwB;AAAC,MAAAC,IAAAC;AAAAzB,IAAAG,EAAAA,MAAAA,eAAAH,UAAAK,SAElBmB,KAAAA,MAAA;AAEJrB,mBAAeE,UAAU,SAC3BC,SAAS,OAAO,GAGd,CAACH,eAAeE,UAAU,WAC5BC,SAAS,SAAS;AAAA,EAEnBmB,GAAAA,KAAA,CAACtB,aAAaE,KAAK,GAACL,QAAAG,aAAAH,QAAAK,OAAAL,QAAAwB,IAAAxB,QAAAyB,OAAAD,KAAAxB,EAAA,EAAA,GAAAyB,KAAAzB,EAAA,EAAA,IATvBiB,MAAAA,UAAUO,IASPC,EAAoB;AAACC,MAAAA;AAAA1B,SAAAA,UAAAK,SAEjBqB,KAAA,CAACrB,OAAOM,YAAY,GAACX,QAAAK,OAAAL,QAAA0B,MAAAA,KAAA1B,EAAA,EAAA,GAArB0B;AAAqB;AAM9B,SAAStB,iBAA0B;AACjC,QAAM,CAACuB,QAAQC,SAAS,IAAIrB,MAAAA,SAAS,EAAK;AAC1CU,QAAAA,UAAU,MAAM;AACdW,cAAUC,UAAUC,MAAM;AAEpBH,UAAAA,WAASA,MAAMC,UAAU,EAAI,GAC7BG,UAAUA,MAAMH,UAAU,EAAK;AAC9BR,WAAAA,OAAAA,iBAAiB,UAAUO,QAAM,GACxCN,OAAOD,iBAAiB,WAAWW,OAAO,GACnC,MAAM;AACXV,aAAOC,oBAAoB,UAAUK,QAAM,GAC3CN,OAAOC,oBAAoB,WAAWS,OAAO;AAAA,IAC/C;AAAA,EACF,GAAG,EAAE;AACL,QAAMC,kBAAkBC,MAAAA,qBACtBC,oBACA,MAAMC,SAASH,iBACf,MAAM,QACR;AAGI,SAAA,CAACL,UAKDK,oBAAoB;AAK1B;AAEA,SAASE,mBAAmBE,eAAuC;AACxDhB,SAAAA,SAAAA,iBAAiB,oBAAoBgB,aAAa,GACpD,MAAMD,SAASb,oBAAoB,oBAAoBc,aAAa;AAC7E;;;;"}