@sanity/sdk 2.7.0 → 2.9.0

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 (92) hide show
  1. package/dist/_chunks-dts/utils.d.ts +2396 -0
  2. package/dist/_chunks-es/_internal.js +129 -0
  3. package/dist/_chunks-es/_internal.js.map +1 -0
  4. package/dist/_chunks-es/createGroqSearchFilter.js +1460 -0
  5. package/dist/_chunks-es/createGroqSearchFilter.js.map +1 -0
  6. package/dist/_chunks-es/telemetryManager.js +87 -0
  7. package/dist/_chunks-es/telemetryManager.js.map +1 -0
  8. package/dist/_chunks-es/version.js +7 -0
  9. package/dist/_chunks-es/version.js.map +1 -0
  10. package/dist/_exports/_internal.d.ts +64 -0
  11. package/dist/_exports/_internal.js +20 -0
  12. package/dist/_exports/_internal.js.map +1 -0
  13. package/dist/index.d.ts +2 -2343
  14. package/dist/index.js +383 -1777
  15. package/dist/index.js.map +1 -1
  16. package/package.json +11 -4
  17. package/src/_exports/_internal.ts +14 -0
  18. package/src/_exports/index.ts +10 -1
  19. package/src/auth/authStore.test.ts +150 -1
  20. package/src/auth/authStore.ts +11 -11
  21. package/src/auth/dashboardAuth.ts +2 -2
  22. package/src/auth/handleAuthCallback.ts +9 -3
  23. package/src/auth/logout.test.ts +1 -1
  24. package/src/auth/logout.ts +1 -1
  25. package/src/auth/refreshStampedToken.test.ts +118 -1
  26. package/src/auth/refreshStampedToken.ts +3 -2
  27. package/src/auth/standaloneAuth.ts +9 -3
  28. package/src/auth/studioAuth.ts +34 -7
  29. package/src/auth/studioModeAuth.ts +2 -1
  30. package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +10 -2
  31. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +5 -1
  32. package/src/auth/subscribeToStorageEventsAndSetToken.ts +2 -2
  33. package/src/auth/utils.ts +33 -0
  34. package/src/client/clientStore.test.ts +14 -0
  35. package/src/client/clientStore.ts +2 -1
  36. package/src/comlink/node/getNodeState.ts +2 -1
  37. package/src/config/sanityConfig.ts +6 -0
  38. package/src/document/actions.ts +18 -11
  39. package/src/document/applyDocumentActions.test.ts +7 -6
  40. package/src/document/applyDocumentActions.ts +10 -4
  41. package/src/document/documentStore.test.ts +536 -188
  42. package/src/document/documentStore.ts +142 -76
  43. package/src/document/events.ts +7 -2
  44. package/src/document/permissions.test.ts +18 -16
  45. package/src/document/permissions.ts +35 -11
  46. package/src/document/processActions.test.ts +359 -32
  47. package/src/document/processActions.ts +104 -76
  48. package/src/document/reducers.test.ts +117 -29
  49. package/src/document/reducers.ts +43 -36
  50. package/src/document/sharedListener.ts +16 -6
  51. package/src/document/util.ts +14 -0
  52. package/src/favorites/favorites.test.ts +9 -2
  53. package/src/presence/bifurTransport.ts +6 -1
  54. package/src/preview/getPreviewState.test.ts +115 -98
  55. package/src/preview/getPreviewState.ts +38 -60
  56. package/src/preview/previewProjectionUtils.test.ts +179 -0
  57. package/src/preview/previewProjectionUtils.ts +93 -0
  58. package/src/preview/resolvePreview.test.ts +42 -25
  59. package/src/preview/resolvePreview.ts +29 -10
  60. package/src/preview/{previewStore.ts → types.ts} +8 -17
  61. package/src/projection/getProjectionState.test.ts +16 -16
  62. package/src/projection/getProjectionState.ts +2 -1
  63. package/src/projection/projectionQuery.ts +2 -3
  64. package/src/projection/types.ts +1 -1
  65. package/src/query/queryStore.ts +2 -1
  66. package/src/releases/getPerspectiveState.ts +7 -6
  67. package/src/releases/releasesStore.test.ts +20 -5
  68. package/src/releases/releasesStore.ts +20 -8
  69. package/src/store/createStateSourceAction.test.ts +62 -0
  70. package/src/store/createStateSourceAction.ts +34 -39
  71. package/src/telemetry/__telemetry__/sdk.telemetry.ts +42 -0
  72. package/src/telemetry/devMode.test.ts +52 -0
  73. package/src/telemetry/devMode.ts +40 -0
  74. package/src/telemetry/initTelemetry.test.ts +225 -0
  75. package/src/telemetry/initTelemetry.ts +205 -0
  76. package/src/telemetry/telemetryManager.test.ts +263 -0
  77. package/src/telemetry/telemetryManager.ts +187 -0
  78. package/src/users/usersStore.test.ts +1 -0
  79. package/src/users/usersStore.ts +5 -1
  80. package/src/utils/createFetcherStore.test.ts +6 -4
  81. package/src/utils/createFetcherStore.ts +2 -1
  82. package/src/utils/getStagingApiHost.test.ts +21 -0
  83. package/src/utils/getStagingApiHost.ts +14 -0
  84. package/src/utils/ids.test.ts +1 -29
  85. package/src/utils/ids.ts +0 -10
  86. package/src/utils/setCleanupTimeout.ts +24 -0
  87. package/src/preview/previewQuery.test.ts +0 -236
  88. package/src/preview/previewQuery.ts +0 -153
  89. package/src/preview/previewStore.test.ts +0 -36
  90. package/src/preview/subscribeToStateAndFetchBatches.test.ts +0 -221
  91. package/src/preview/subscribeToStateAndFetchBatches.ts +0 -112
  92. package/src/preview/util.ts +0 -13
@@ -0,0 +1,1460 @@
1
+ import { pick, omit, isObject } from "lodash-es";
2
+ import { createClient, CorsOriginError } from "@sanity/client";
3
+ import { Observable, map, distinctUntilChanged, shareReplay, skip, defer, finalize, filter, exhaustMap, from, timer, switchMap, takeWhile, firstValueFrom, fromEvent, EMPTY, catchError, NEVER, first, race, startWith, pairwise, mergeMap, groupBy, of, combineLatest, tap, share } from "rxjs";
4
+ import { createSelector } from "reselect";
5
+ import { createImageUrlBuilder } from "@sanity/image-url";
6
+ import { devtools } from "zustand/middleware";
7
+ import { createStore } from "zustand/vanilla";
8
+ function isDatasetSource(source) {
9
+ return "projectId" in source && "dataset" in source;
10
+ }
11
+ function isMediaLibrarySource(source) {
12
+ return "mediaLibraryId" in source;
13
+ }
14
+ function isCanvasSource(source) {
15
+ return "canvasId" in source;
16
+ }
17
+ const isReleasePerspective = (perspective) => typeof perspective == "object" && perspective !== null && "releaseName" in perspective;
18
+ function insecureRandomId() {
19
+ return Array.from({ length: 16 }, () => Math.floor(Math.random() * 16).toString(16)).join("");
20
+ }
21
+ const LOG_LEVEL_PRIORITY = {
22
+ error: 0,
23
+ warn: 1,
24
+ info: 2,
25
+ debug: 3,
26
+ trace: 4
27
+ }, DEFAULT_CONFIG = {
28
+ level: "warn",
29
+ namespaces: [],
30
+ internal: !1,
31
+ timestamps: !0,
32
+ enableInProduction: !1,
33
+ handler: {
34
+ // eslint-disable-next-line no-console
35
+ error: console.error.bind(console),
36
+ // eslint-disable-next-line no-console
37
+ warn: console.warn.bind(console),
38
+ // eslint-disable-next-line no-console
39
+ info: console.info.bind(console),
40
+ // eslint-disable-next-line no-console
41
+ debug: console.debug.bind(console),
42
+ // eslint-disable-next-line no-console
43
+ trace: console.debug.bind(console)
44
+ // trace uses console.debug
45
+ }
46
+ };
47
+ function parseDebugEnvVar() {
48
+ if (typeof process > "u" || !process.env?.DEBUG)
49
+ return null;
50
+ const debug = process.env.DEBUG;
51
+ if (!debug.includes("sanity"))
52
+ return null;
53
+ const config = {}, levelMatch = debug.match(/sanity:(trace|debug|info|warn|error):/), hasLevelSpecifier = !!levelMatch;
54
+ if (levelMatch ? config.level = levelMatch[1] : config.level = "debug", debug === "sanity")
55
+ config.namespaces = ["*"];
56
+ else if (hasLevelSpecifier && debug.match(/sanity:(trace|debug|info|warn|error):\*/))
57
+ config.namespaces = ["*"];
58
+ else if (!hasLevelSpecifier && debug.includes("sanity:*"))
59
+ config.namespaces = ["*"];
60
+ else {
61
+ const namespaces = debug.split(",").filter((s) => s.includes("sanity:")).map((s) => {
62
+ const cleaned = s.replace(/^sanity:/, "");
63
+ return hasLevelSpecifier && cleaned.match(/^(trace|debug|info|warn|error):/) ? cleaned.split(":").slice(1).join(":") : cleaned.split(":")[0];
64
+ }).filter(Boolean).filter((ns) => ns !== "*");
65
+ namespaces.length > 0 && (config.namespaces = namespaces);
66
+ }
67
+ return debug.includes(":internal") && (config.internal = !0), config;
68
+ }
69
+ const envConfig = parseDebugEnvVar();
70
+ let globalConfig = {
71
+ ...DEFAULT_CONFIG,
72
+ ...envConfig ?? {}
73
+ };
74
+ envConfig && (["info", "debug", "trace"].includes(globalConfig.level) || globalConfig.level === "warn") && console.info(
75
+ `[${(/* @__PURE__ */ new Date()).toISOString()}] [INFO] [sdk] Logging auto-configured from DEBUG environment variable`,
76
+ {
77
+ level: globalConfig.level,
78
+ namespaces: globalConfig.namespaces,
79
+ internal: globalConfig.internal,
80
+ source: "env:DEBUG",
81
+ value: typeof process < "u" ? process.env?.DEBUG : void 0
82
+ }
83
+ );
84
+ function configureLogging(config) {
85
+ globalConfig = {
86
+ ...globalConfig,
87
+ ...config,
88
+ handler: config.handler ?? globalConfig.handler
89
+ };
90
+ }
91
+ function isLoggingEnabled() {
92
+ return typeof process < "u" && process.env?.NODE_ENV === "production" ? globalConfig.enableInProduction : !0;
93
+ }
94
+ function isNamespaceEnabled(namespace) {
95
+ return isLoggingEnabled() ? globalConfig.namespaces.includes("*") ? !0 : globalConfig.namespaces.includes(namespace) : !1;
96
+ }
97
+ function isLevelEnabled(level) {
98
+ return isLoggingEnabled() ? LOG_LEVEL_PRIORITY[level] <= LOG_LEVEL_PRIORITY[globalConfig.level] : !1;
99
+ }
100
+ function formatMessage(namespace, level, message, context) {
101
+ const parts = [];
102
+ if (globalConfig.timestamps) {
103
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
104
+ parts.push(`[${timestamp}]`);
105
+ }
106
+ parts.push(`[${level.toUpperCase()}]`), parts.push(`[${namespace}]`);
107
+ const instanceContext = context?.instanceContext;
108
+ return instanceContext && (instanceContext.projectId && parts.push(`[project:${instanceContext.projectId}]`), instanceContext.dataset && parts.push(`[dataset:${instanceContext.dataset}]`), instanceContext.instanceId && parts.push(`[instance:${instanceContext.instanceId.slice(0, 8)}]`)), parts.push(message), [parts.join(" "), context];
109
+ }
110
+ function sanitizeContext(context) {
111
+ if (!context || Object.keys(context).length === 0) return;
112
+ const sanitized = { ...context }, sensitiveKeys = ["token", "password", "secret", "apiKey", "authorization"];
113
+ for (const key of Object.keys(sanitized))
114
+ sensitiveKeys.some((sensitive) => key.toLowerCase().includes(sensitive)) && (sanitized[key] = "[REDACTED]");
115
+ return sanitized;
116
+ }
117
+ function createLogger(namespace, baseContext) {
118
+ const logAtLevel = (level, message, context) => {
119
+ if (!isNamespaceEnabled(namespace) || !isLevelEnabled(level) || context?.internal && !globalConfig.internal) return;
120
+ const mergedContext = { ...baseContext, ...context }, sanitized = sanitizeContext(mergedContext), [formatted, finalContext] = formatMessage(namespace, level, message, sanitized);
121
+ globalConfig.handler[level](formatted, finalContext);
122
+ };
123
+ return {
124
+ namespace,
125
+ error: (message, context) => logAtLevel("error", message, context),
126
+ warn: (message, context) => logAtLevel("warn", message, context),
127
+ info: (message, context) => logAtLevel("info", message, context),
128
+ debug: (message, context) => logAtLevel("debug", message, context),
129
+ trace: (message, context) => logAtLevel("trace", message, { ...context, internal: !0 }),
130
+ isLevelEnabled: (level) => isNamespaceEnabled(namespace) && isLevelEnabled(level),
131
+ child: (childContext) => createLogger(namespace, { ...baseContext, ...childContext }),
132
+ getInstanceContext: () => baseContext?.instanceContext
133
+ };
134
+ }
135
+ function getEnv(key) {
136
+ if (typeof import.meta < "u" && import.meta.env)
137
+ return import.meta.env[key];
138
+ if (typeof process < "u" && process.env)
139
+ return process.env[key];
140
+ if (typeof window < "u" && window.ENV)
141
+ return window.ENV?.[key];
142
+ }
143
+ function createStoreState(initialState, devToolsOptions) {
144
+ const store = createStore()(devtools(() => initialState, devToolsOptions));
145
+ return {
146
+ get: store.getState,
147
+ set: (actionKey, updatedState) => {
148
+ const currentState = store.getState(), nextState = typeof updatedState == "function" ? updatedState(currentState) : updatedState;
149
+ currentState !== nextState && store.setState(nextState, !1, actionKey);
150
+ },
151
+ observable: new Observable((observer) => {
152
+ const emit = () => observer.next(store.getState());
153
+ emit();
154
+ const unsubscribe = store.subscribe(emit);
155
+ return () => unsubscribe();
156
+ })
157
+ };
158
+ }
159
+ function defineStore(storeDefinition) {
160
+ return storeDefinition;
161
+ }
162
+ function createStoreInstance(instance, key, { name, getInitialState, initialize }) {
163
+ const state = createStoreState(getInitialState(instance, key), {
164
+ enabled: !!getEnv("DEV"),
165
+ name: `${name}-${key.name}`
166
+ }), dispose = initialize?.({ state, instance, key }), disposed = { current: !1 };
167
+ return {
168
+ state,
169
+ dispose: () => {
170
+ disposed.current || (disposed.current = !0, dispose?.());
171
+ },
172
+ isDisposed: () => disposed.current
173
+ };
174
+ }
175
+ function createActionBinder(keyFn) {
176
+ const instanceRegistry = /* @__PURE__ */ new Map(), storeRegistry = /* @__PURE__ */ new Map();
177
+ return function(storeDefinition, action) {
178
+ return function(instance, ...params) {
179
+ const key = keyFn(instance, ...params), compositeKey = storeDefinition.name + (key.name ? `:${key.name}` : "");
180
+ let instances = instanceRegistry.get(compositeKey);
181
+ instances || (instances = /* @__PURE__ */ new Set(), instanceRegistry.set(compositeKey, instances)), instances.has(instance.instanceId) || (instances.add(instance.instanceId), instance.onDispose(() => {
182
+ instances.delete(instance.instanceId), instances.size === 0 && (storeRegistry.get(compositeKey)?.dispose(), storeRegistry.delete(compositeKey), instanceRegistry.delete(compositeKey));
183
+ }));
184
+ let storeInstance = storeRegistry.get(compositeKey);
185
+ return storeInstance || (storeInstance = createStoreInstance(instance, key, storeDefinition), storeRegistry.set(compositeKey, storeInstance)), action({ instance, state: storeInstance.state, key }, ...params);
186
+ };
187
+ };
188
+ }
189
+ const bindActionByDataset = createActionBinder((instance, options) => {
190
+ const projectId = options?.projectId ?? instance.config.projectId, dataset = options?.dataset ?? instance.config.dataset;
191
+ if (!projectId || !dataset)
192
+ throw new Error("This API requires a project ID and dataset configured.");
193
+ return { name: `${projectId}.${dataset}`, projectId, dataset };
194
+ }), createSourceKey = (instance, source) => {
195
+ let name, sourceForKey;
196
+ if (source) {
197
+ if (sourceForKey = source, isDatasetSource(source))
198
+ name = `${source.projectId}.${source.dataset}`;
199
+ else if (isMediaLibrarySource(source))
200
+ name = `media-library:${source.mediaLibraryId}`;
201
+ else if (isCanvasSource(source))
202
+ name = `canvas:${source.canvasId}`;
203
+ else
204
+ throw new Error(`Received invalid source: ${JSON.stringify(source)}`);
205
+ return { name, source: sourceForKey };
206
+ }
207
+ const { projectId, dataset } = instance.config;
208
+ if (!projectId || !dataset)
209
+ throw new Error("This API requires a project ID and dataset configured.");
210
+ return { name: `${projectId}.${dataset}`, source: { projectId, dataset } };
211
+ }, bindActionBySource = createActionBinder((instance, { source }) => createSourceKey(instance, source)), bindActionBySourceAndPerspective = createActionBinder((instance, options) => {
212
+ const { source, perspective } = options, utilizedPerspective = perspective ?? instance.config.perspective ?? "drafts";
213
+ let perspectiveKey;
214
+ isReleasePerspective(utilizedPerspective) ? perspectiveKey = utilizedPerspective.releaseName : typeof utilizedPerspective == "string" ? perspectiveKey = utilizedPerspective : perspectiveKey = JSON.stringify(utilizedPerspective);
215
+ const sourceKey = createSourceKey(instance, source);
216
+ return {
217
+ name: `${sourceKey.name}:${perspectiveKey}`,
218
+ source: sourceKey.source,
219
+ perspective: utilizedPerspective
220
+ };
221
+ }), bindActionGlobally = createActionBinder((..._rest) => ({ name: "global" }));
222
+ function createStateSourceAction(options) {
223
+ const selector = typeof options == "function" ? options : options.selector, subscribeHandler = options && "onSubscribe" in options ? options.onSubscribe : void 0, isEqual = options && "isEqual" in options ? options.isEqual ?? Object.is : Object.is, selectorContextCache = /* @__PURE__ */ new WeakMap();
224
+ function stateSourceAction(context, ...params) {
225
+ const { state, instance } = context, getCurrent = (currentState) => {
226
+ if (typeof currentState != "object" || currentState === null)
227
+ throw new Error(
228
+ `Expected store state to be an object but got "${typeof currentState}" instead`
229
+ );
230
+ let instanceCache = selectorContextCache.get(currentState);
231
+ instanceCache || (instanceCache = /* @__PURE__ */ new WeakMap(), selectorContextCache.set(currentState, instanceCache));
232
+ let selectorContext = instanceCache.get(instance);
233
+ return selectorContext || (selectorContext = { state: currentState, instance }, instanceCache.set(instance, selectorContext)), selector(selectorContext, ...params);
234
+ };
235
+ let values = state.observable.pipe(map(getCurrent), distinctUntilChanged(isEqual));
236
+ subscribeHandler && (values = withSubscribeHook(values, () => subscribeHandler(context, ...params)));
237
+ const sharedValues = values.pipe(shareReplay({ bufferSize: 1, refCount: !0 }));
238
+ return {
239
+ getCurrent: () => getCurrent(state.get()),
240
+ subscribe: (onStoreChanged) => {
241
+ const subscription = sharedValues.pipe(skip(1)).subscribe({
242
+ next: () => onStoreChanged?.(),
243
+ // Propagate selector errors to both subscription types
244
+ error: () => onStoreChanged?.()
245
+ });
246
+ return () => {
247
+ subscription.unsubscribe();
248
+ };
249
+ },
250
+ observable: sharedValues
251
+ };
252
+ }
253
+ return stateSourceAction;
254
+ }
255
+ function withSubscribeHook(obs, fn) {
256
+ return defer(() => {
257
+ const cleanup = fn();
258
+ return cleanup ? obs.pipe(finalize(() => cleanup())) : obs;
259
+ });
260
+ }
261
+ function getStagingApiHost() {
262
+ if (typeof __SANITY_STAGING__ < "u" && __SANITY_STAGING__ === !0)
263
+ return "https://api.sanity.work";
264
+ }
265
+ const DEFAULT_BASE = "http://localhost", AUTH_CODE_PARAM = "sid", DEFAULT_API_VERSION$1 = "2021-06-07", REQUEST_TAG_PREFIX = "sanity.sdk.auth";
266
+ function resolveAuthMode(config, locationHref) {
267
+ return isStudioConfig(config) ? "studio" : detectDashboardContext(locationHref) ? "dashboard" : "standalone";
268
+ }
269
+ function isStudioConfig(config) {
270
+ return !!config.studio || !!config.studioMode?.enabled;
271
+ }
272
+ function detectDashboardContext(locationHref) {
273
+ try {
274
+ const contextParam = new URL(locationHref, DEFAULT_BASE).searchParams.get("_context");
275
+ if (!contextParam) return !1;
276
+ const parsed = JSON.parse(contextParam);
277
+ return typeof parsed == "object" && parsed !== null && !Array.isArray(parsed) && Object.keys(parsed).length > 0;
278
+ } catch (err) {
279
+ return console.error("Failed to parse dashboard context from initial location:", err), !1;
280
+ }
281
+ }
282
+ var AuthStateType = /* @__PURE__ */ ((AuthStateType2) => (AuthStateType2.LOGGED_IN = "logged-in", AuthStateType2.LOGGING_IN = "logging-in", AuthStateType2.ERROR = "error", AuthStateType2.LOGGED_OUT = "logged-out", AuthStateType2))(AuthStateType || {});
283
+ const REFRESH_INTERVAL = 720 * 60 * 1e3, LOCK_NAME = "sanity-token-refresh-lock";
284
+ function getLastRefreshTime(storageArea, storageKey) {
285
+ try {
286
+ const data = storageArea?.getItem(`${storageKey}_last_refresh`), parsed = data ? parseInt(data, 10) : 0;
287
+ return isNaN(parsed) ? 0 : parsed;
288
+ } catch {
289
+ return 0;
290
+ }
291
+ }
292
+ function setLastRefreshTime(storageArea, storageKey) {
293
+ try {
294
+ storageArea?.setItem(`${storageKey}_last_refresh`, Date.now().toString());
295
+ } catch {
296
+ }
297
+ }
298
+ function getNextRefreshDelay(storageArea, storageKey) {
299
+ const lastRefresh = getLastRefreshTime(storageArea, storageKey);
300
+ if (!lastRefresh) return 0;
301
+ const now = Date.now(), nextRefreshTime = lastRefresh + REFRESH_INTERVAL;
302
+ return Math.max(0, nextRefreshTime - now);
303
+ }
304
+ function createTokenRefreshStream(token, clientFactory, apiHost) {
305
+ return new Observable((subscriber) => {
306
+ const subscription = clientFactory({
307
+ apiVersion: DEFAULT_API_VERSION$1,
308
+ requestTagPrefix: REQUEST_TAG_PREFIX,
309
+ useProjectHostname: !1,
310
+ useCdn: !1,
311
+ token,
312
+ ignoreBrowserTokenWarning: !0,
313
+ ...apiHost && { apiHost }
314
+ }).observable.request({
315
+ uri: "auth/refresh-token",
316
+ method: "POST",
317
+ tag: "refresh-token",
318
+ body: {
319
+ token
320
+ }
321
+ }).subscribe(subscriber);
322
+ return () => subscription.unsubscribe();
323
+ });
324
+ }
325
+ async function acquireTokenRefreshLock(refreshFn, storageArea, storageKey) {
326
+ if (!navigator.locks)
327
+ return console.warn("Web Locks API not supported. Proceeding with uncoordinated refresh."), await refreshFn(), setLastRefreshTime(storageArea, storageKey), !0;
328
+ try {
329
+ return await navigator.locks.request(LOCK_NAME, { mode: "exclusive" }, async (lock) => {
330
+ if (!lock) return !1;
331
+ for (; ; ) {
332
+ const delay = getNextRefreshDelay(storageArea, storageKey);
333
+ delay > 0 && await new Promise((resolve) => setTimeout(resolve, delay));
334
+ try {
335
+ await refreshFn(), setLastRefreshTime(storageArea, storageKey);
336
+ } catch (error) {
337
+ console.error("Token refresh failed within lock:", error);
338
+ }
339
+ await new Promise((resolve) => setTimeout(resolve, REFRESH_INTERVAL));
340
+ }
341
+ }) === !0;
342
+ } catch (error) {
343
+ return console.error("Failed to request token refresh lock:", error), !1;
344
+ }
345
+ }
346
+ function shouldRefreshToken(lastRefresh) {
347
+ return lastRefresh ? Date.now() - lastRefresh >= REFRESH_INTERVAL : !0;
348
+ }
349
+ const refreshStampedToken = ({ state }) => {
350
+ const { clientFactory, apiHost, storageArea, storageKey } = state.get().options;
351
+ return state.observable.pipe(
352
+ map((storeState) => ({
353
+ authState: storeState.authState,
354
+ dashboardContext: storeState.dashboardContext
355
+ })),
356
+ filter(
357
+ (storeState) => storeState.authState.type === AuthStateType.LOGGED_IN
358
+ ),
359
+ distinctUntilChanged(
360
+ (prev, curr) => prev.authState.type === curr.authState.type && prev.authState.token === curr.authState.token && // Only care about token for distinctness here
361
+ prev.dashboardContext === curr.dashboardContext
362
+ ),
363
+ // Make distinctness check explicit
364
+ filter((storeState) => storeState.authState.token.includes("-st")),
365
+ // Ensure we only try to refresh stamped tokens
366
+ exhaustMap((storeState) => {
367
+ const performRefresh = async () => {
368
+ const currentState = state.get();
369
+ if (currentState.authState.type !== AuthStateType.LOGGED_IN)
370
+ throw new Error("User logged out before refresh could complete");
371
+ const currentToken = currentState.authState.token, response = await firstValueFrom(
372
+ createTokenRefreshStream(currentToken, clientFactory, apiHost)
373
+ );
374
+ state.set("setRefreshStampedToken", (prev) => ({
375
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, token: response.token } : prev.authState
376
+ })), storageArea?.setItem(storageKey, JSON.stringify({ token: response.token }));
377
+ };
378
+ return storeState.dashboardContext ? new Observable((subscriber) => {
379
+ const visibilityHandler = () => {
380
+ const currentState = state.get();
381
+ document.visibilityState === "visible" && currentState.authState.type === AuthStateType.LOGGED_IN && shouldRefreshToken(currentState.authState.lastTokenRefresh) && createTokenRefreshStream(
382
+ currentState.authState.token,
383
+ clientFactory,
384
+ apiHost
385
+ ).subscribe({
386
+ next: (response) => {
387
+ state.set("setRefreshStampedToken", (prev) => ({
388
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? {
389
+ ...prev.authState,
390
+ token: response.token,
391
+ lastTokenRefresh: Date.now()
392
+ } : prev.authState
393
+ })), subscriber.next(response);
394
+ },
395
+ error: (error) => subscriber.error(error)
396
+ });
397
+ }, timerSubscription = timer(REFRESH_INTERVAL, REFRESH_INTERVAL).pipe(
398
+ filter(() => document.visibilityState === "visible"),
399
+ switchMap(() => {
400
+ const currentState = state.get().authState;
401
+ if (currentState.type !== AuthStateType.LOGGED_IN)
402
+ throw new Error("User logged out before refresh could complete");
403
+ return createTokenRefreshStream(currentState.token, clientFactory, apiHost);
404
+ })
405
+ ).subscribe({
406
+ next: (response) => {
407
+ state.set("setRefreshStampedToken", (prev) => ({
408
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? {
409
+ ...prev.authState,
410
+ token: response.token,
411
+ lastTokenRefresh: Date.now()
412
+ } : prev.authState
413
+ })), subscriber.next(response);
414
+ },
415
+ error: (error) => subscriber.error(error)
416
+ });
417
+ return document.addEventListener("visibilitychange", visibilityHandler), () => {
418
+ document.removeEventListener("visibilitychange", visibilityHandler), timerSubscription.unsubscribe();
419
+ };
420
+ }).pipe(
421
+ takeWhile(() => state.get().authState.type === AuthStateType.LOGGED_IN),
422
+ map((response) => ({ token: response.token }))
423
+ ) : from(acquireTokenRefreshLock(performRefresh, storageArea, storageKey)).pipe(
424
+ filter((hasLock) => hasLock),
425
+ map(() => {
426
+ const currentState = state.get().authState;
427
+ if (currentState.type !== AuthStateType.LOGGED_IN)
428
+ throw new Error("User logged out before refresh could complete");
429
+ return { token: currentState.token };
430
+ })
431
+ );
432
+ })
433
+ ).subscribe({
434
+ next: (response) => {
435
+ state.set("setRefreshStampedToken", (prev) => ({
436
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? {
437
+ ...prev.authState,
438
+ token: response.token,
439
+ lastTokenRefresh: Date.now()
440
+ } : prev.authState
441
+ })), storageArea?.setItem(storageKey, JSON.stringify({ token: response.token }));
442
+ },
443
+ error: (error) => {
444
+ state.set("setRefreshStampedTokenError", { authState: { type: AuthStateType.ERROR, error } });
445
+ }
446
+ });
447
+ }, subscribeToStateAndFetchCurrentUser = ({ state, instance }, fetchOptions) => {
448
+ const { clientFactory, apiHost } = state.get().options, useProjectHostname = fetchOptions?.useProjectHostname ?? isStudioConfig(instance.config), projectId = instance.config.projectId;
449
+ return state.observable.pipe(
450
+ map(({ authState, options: storeOptions }) => ({
451
+ authState,
452
+ authMethod: storeOptions.authMethod
453
+ })),
454
+ filter(
455
+ (value) => value.authState.type === AuthStateType.LOGGED_IN && !value.authState.currentUser
456
+ ),
457
+ map((value) => ({ token: value.authState.token, authMethod: value.authMethod })),
458
+ distinctUntilChanged(
459
+ (prev, curr) => prev.token === curr.token && prev.authMethod === curr.authMethod
460
+ )
461
+ ).pipe(
462
+ map(
463
+ ({ token, authMethod }) => clientFactory({
464
+ apiVersion: DEFAULT_API_VERSION$1,
465
+ requestTagPrefix: REQUEST_TAG_PREFIX,
466
+ token: authMethod === "cookie" ? void 0 : token,
467
+ ignoreBrowserTokenWarning: !0,
468
+ useProjectHostname,
469
+ useCdn: !1,
470
+ ...authMethod === "cookie" ? { withCredentials: !0 } : {},
471
+ ...useProjectHostname && projectId ? { projectId } : {},
472
+ ...apiHost && { apiHost }
473
+ })
474
+ ),
475
+ switchMap(
476
+ (client) => client.observable.request({
477
+ uri: "/users/me",
478
+ method: "GET",
479
+ tag: "users.get-current"
480
+ })
481
+ )
482
+ ).subscribe({
483
+ next: (currentUser) => {
484
+ state.set("setCurrentUser", (prev) => ({
485
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, currentUser } : prev.authState
486
+ }));
487
+ },
488
+ error: (error) => {
489
+ state.set("setError", { authState: { type: AuthStateType.ERROR, error } });
490
+ }
491
+ });
492
+ };
493
+ function createLoggedInAuthState(token, currentUser, existingLastTokenRefresh) {
494
+ const isStampedToken = token.includes("-st"), lastTokenRefresh = existingLastTokenRefresh ?? (isStampedToken ? Date.now() : void 0);
495
+ return {
496
+ type: AuthStateType.LOGGED_IN,
497
+ token,
498
+ currentUser,
499
+ ...lastTokenRefresh !== void 0 && { lastTokenRefresh }
500
+ };
501
+ }
502
+ function getAuthCode(callbackUrl, locationHref) {
503
+ const loc = new URL(locationHref, DEFAULT_BASE), callbackLocation = callbackUrl ? new URL(callbackUrl, DEFAULT_BASE) : void 0, callbackLocationMatches = callbackLocation ? loc.pathname.toLowerCase().startsWith(callbackLocation.pathname.toLowerCase()) : !0;
504
+ let authCode = new URLSearchParams(loc.hash.slice(1)).get(AUTH_CODE_PARAM) || new URLSearchParams(loc.search).get(AUTH_CODE_PARAM);
505
+ if (!authCode) {
506
+ const contextParam = new URLSearchParams(loc.search).get("_context");
507
+ if (contextParam)
508
+ try {
509
+ const parsedContext = JSON.parse(contextParam);
510
+ parsedContext && typeof parsedContext == "object" && typeof parsedContext.sid == "string" && parsedContext.sid && (authCode = parsedContext.sid);
511
+ } catch {
512
+ }
513
+ }
514
+ return authCode && callbackLocationMatches ? authCode : null;
515
+ }
516
+ function getTokenFromLocation(locationHref) {
517
+ const loc = new URL(locationHref);
518
+ return new URLSearchParams(loc.hash.slice(1)).get("token") || null;
519
+ }
520
+ function getTokenFromStorage(storageArea, storageKey) {
521
+ if (!storageArea) return null;
522
+ const item = storageArea.getItem(storageKey);
523
+ if (item === null) return null;
524
+ try {
525
+ const parsed = JSON.parse(item);
526
+ if (typeof parsed != "object" || parsed === null || !("token" in parsed) || typeof parsed.token != "string")
527
+ throw new Error("Invalid stored auth data structure");
528
+ return parsed.token;
529
+ } catch {
530
+ return storageArea.removeItem(storageKey), null;
531
+ }
532
+ }
533
+ function getStorageEvents() {
534
+ return typeof window < "u" && typeof window.addEventListener == "function" ? fromEvent(window, "storage") : EMPTY;
535
+ }
536
+ function getDefaultStorage() {
537
+ try {
538
+ return typeof localStorage < "u" && typeof localStorage.getItem == "function" ? localStorage : void 0;
539
+ } catch {
540
+ return;
541
+ }
542
+ }
543
+ function getDefaultLocation() {
544
+ try {
545
+ return typeof location > "u" ? DEFAULT_BASE : typeof location.href == "string" ? location.href : DEFAULT_BASE;
546
+ } catch {
547
+ return DEFAULT_BASE;
548
+ }
549
+ }
550
+ function getCleanedUrl(locationUrl) {
551
+ const loc = new URL(locationUrl), rawHash = loc.hash.startsWith("#") ? loc.hash.slice(1) : loc.hash;
552
+ if (rawHash && rawHash.includes("=")) {
553
+ const hashParams = new URLSearchParams(rawHash);
554
+ hashParams.delete("token"), hashParams.delete("withSid");
555
+ const nextHash = hashParams.toString();
556
+ loc.hash = nextHash ? `#${nextHash}` : "";
557
+ }
558
+ return loc.searchParams.delete("sid"), loc.searchParams.delete("url"), loc.toString();
559
+ }
560
+ function getClientErrorApiBody(error) {
561
+ const body = error.response?.body;
562
+ return body && typeof body == "object" ? body : void 0;
563
+ }
564
+ function getClientErrorApiType(error) {
565
+ const body = getClientErrorApiBody(error);
566
+ return body?.error?.type ?? body?.type;
567
+ }
568
+ function getClientErrorApiDescription(error) {
569
+ const body = getClientErrorApiBody(error);
570
+ return body?.error?.description ?? body?.description;
571
+ }
572
+ function isProjectUserNotFoundClientError(error) {
573
+ return getClientErrorApiType(error) === "projectUserNotFoundError";
574
+ }
575
+ function parseDashboardContext(locationHref) {
576
+ try {
577
+ const contextParam = new URL(locationHref, DEFAULT_BASE).searchParams.get("_context");
578
+ if (contextParam) {
579
+ const parsedContext = JSON.parse(contextParam);
580
+ if (parsedContext && typeof parsedContext == "object" && !Array.isArray(parsedContext) && Object.keys(parsedContext).length > 0)
581
+ return delete parsedContext.sid, parsedContext;
582
+ }
583
+ } catch (err) {
584
+ console.error("Failed to parse dashboard context from initial location:", err);
585
+ }
586
+ return {};
587
+ }
588
+ function getDashboardInitialState(options) {
589
+ const { authConfig, initialLocationHref } = options, providedToken = authConfig.token, callbackUrl = authConfig.callbackUrl, storageKey = "__sanity_auth_token", dashboardContext = parseDashboardContext(initialLocationHref), storageArea = void 0;
590
+ return providedToken ? {
591
+ authState: createLoggedInAuthState(providedToken, null),
592
+ storageKey,
593
+ storageArea,
594
+ authMethod: void 0,
595
+ dashboardContext
596
+ } : getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref) ? {
597
+ authState: { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 },
598
+ storageKey,
599
+ storageArea,
600
+ authMethod: void 0,
601
+ dashboardContext
602
+ } : {
603
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 },
604
+ storageKey,
605
+ storageArea,
606
+ authMethod: void 0,
607
+ dashboardContext
608
+ };
609
+ }
610
+ function initializeDashboardAuth(context, tokenRefresherRunning2) {
611
+ const subscriptions = [];
612
+ let startedRefresher = !1;
613
+ return subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !1 })), tokenRefresherRunning2 || (startedRefresher = !0, subscriptions.push(refreshStampedToken(context))), {
614
+ dispose: () => {
615
+ for (const subscription of subscriptions)
616
+ subscription.unsubscribe();
617
+ },
618
+ tokenRefresherStarted: startedRefresher
619
+ };
620
+ }
621
+ const subscribeToStorageEventsAndSetToken = ({
622
+ state
623
+ }) => {
624
+ const { storageArea, storageKey } = state.get().options;
625
+ return defer(getStorageEvents).pipe(
626
+ filter(
627
+ (e) => e.storageArea === storageArea && e.key === storageKey
628
+ ),
629
+ map(() => getTokenFromStorage(storageArea, storageKey)),
630
+ distinctUntilChanged()
631
+ ).subscribe((token) => {
632
+ state.set("updateTokenFromStorageEvent", {
633
+ authState: token ? createLoggedInAuthState(token, null) : { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
634
+ });
635
+ });
636
+ };
637
+ function getStandaloneInitialState(options) {
638
+ const { authConfig, initialLocationHref } = options, providedToken = authConfig.token, callbackUrl = authConfig.callbackUrl, storageKey = "__sanity_auth_token", storageArea = authConfig.storageArea ?? getDefaultStorage();
639
+ if (providedToken)
640
+ return {
641
+ authState: createLoggedInAuthState(providedToken, null),
642
+ storageKey,
643
+ storageArea,
644
+ authMethod: void 0,
645
+ dashboardContext: {}
646
+ };
647
+ if (getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref))
648
+ return {
649
+ authState: { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 },
650
+ storageKey,
651
+ storageArea,
652
+ authMethod: void 0,
653
+ dashboardContext: {}
654
+ };
655
+ const token = getTokenFromStorage(storageArea, storageKey);
656
+ return token ? {
657
+ authState: createLoggedInAuthState(token, null),
658
+ storageKey,
659
+ storageArea,
660
+ authMethod: "localstorage",
661
+ dashboardContext: {}
662
+ } : {
663
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 },
664
+ storageKey,
665
+ storageArea,
666
+ authMethod: void 0,
667
+ dashboardContext: {}
668
+ };
669
+ }
670
+ function initializeStandaloneAuth(context, tokenRefresherRunning2) {
671
+ const subscriptions = [];
672
+ let startedRefresher = !1;
673
+ return subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !1 })), context.state.get().options?.storageArea && subscriptions.push(subscribeToStorageEventsAndSetToken(context)), tokenRefresherRunning2 || (startedRefresher = !0, subscriptions.push(refreshStampedToken(context))), {
674
+ dispose: () => {
675
+ for (const subscription of subscriptions)
676
+ subscription.unsubscribe();
677
+ },
678
+ tokenRefresherStarted: startedRefresher
679
+ };
680
+ }
681
+ const COOKIE_AUTH_TIMEOUT_MS = 1e4;
682
+ async function checkForCookieAuth(projectId, clientFactory) {
683
+ if (!projectId) return !1;
684
+ try {
685
+ const user = await clientFactory({
686
+ projectId,
687
+ useCdn: !1,
688
+ requestTagPrefix: REQUEST_TAG_PREFIX,
689
+ timeout: COOKIE_AUTH_TIMEOUT_MS
690
+ }).request({
691
+ uri: "/users/me",
692
+ withCredentials: !0,
693
+ tag: "users.get-current"
694
+ });
695
+ return user != null && typeof user == "object" && typeof user.id == "string";
696
+ } catch {
697
+ return !1;
698
+ }
699
+ }
700
+ function getStudioTokenFromLocalStorage(storageArea, storageKey) {
701
+ return !storageArea || !storageKey ? null : getTokenFromStorage(storageArea, storageKey) || null;
702
+ }
703
+ function getStudioInitialState(options) {
704
+ const { authConfig, projectId, tokenSource } = options, storageArea = authConfig.storageArea ?? getDefaultStorage(), studioStorageKey = `__studio_auth_token_${projectId ?? ""}`;
705
+ if (tokenSource)
706
+ return {
707
+ authState: { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 },
708
+ storageKey: studioStorageKey,
709
+ storageArea,
710
+ authMethod: void 0,
711
+ dashboardContext: {}
712
+ };
713
+ const providedToken = authConfig.token;
714
+ let authMethod;
715
+ const token = getStudioTokenFromLocalStorage(storageArea, studioStorageKey);
716
+ return token && (authMethod = "localstorage"), providedToken ? {
717
+ authState: createLoggedInAuthState(providedToken, null),
718
+ storageKey: studioStorageKey,
719
+ storageArea,
720
+ authMethod,
721
+ dashboardContext: {}
722
+ } : token ? {
723
+ authState: createLoggedInAuthState(token, null),
724
+ storageKey: studioStorageKey,
725
+ storageArea,
726
+ authMethod: "localstorage",
727
+ dashboardContext: {}
728
+ } : {
729
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 },
730
+ storageKey: studioStorageKey,
731
+ storageArea,
732
+ authMethod: void 0,
733
+ dashboardContext: {}
734
+ };
735
+ }
736
+ function initializeStudioAuth(context, tokenRefresherRunning2) {
737
+ const tokenSource = context.instance.config.studio?.auth?.token;
738
+ return tokenSource ? initializeWithTokenSource(context, tokenSource) : initializeWithFallback(context, tokenRefresherRunning2);
739
+ }
740
+ function initializeWithTokenSource(context, tokenSource) {
741
+ const subscriptions = [], studioAuthenticated = context.instance.config.studio?.authenticated === !0;
742
+ subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !0 }));
743
+ const tokenSub = tokenSource.subscribe({
744
+ next: (token) => {
745
+ const { state } = context;
746
+ token ? state.set("studioTokenSource", (prev) => ({
747
+ options: { ...prev.options, authMethod: void 0 },
748
+ authState: createLoggedInAuthState(token, null)
749
+ })) : studioAuthenticated ? state.set("studioTokenSourceCookieAuth", (prev) => ({
750
+ options: { ...prev.options, authMethod: "cookie" },
751
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? prev.authState : createLoggedInAuthState("", null)
752
+ })) : state.set("studioTokenSourceLoggedOut", (prev) => ({
753
+ options: { ...prev.options, authMethod: void 0 },
754
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
755
+ }));
756
+ }
757
+ });
758
+ return {
759
+ dispose: () => {
760
+ tokenSub.unsubscribe();
761
+ for (const subscription of subscriptions)
762
+ subscription.unsubscribe();
763
+ },
764
+ // Studio handles token refresh — do not start the SDK's refresher
765
+ tokenRefresherStarted: !1
766
+ };
767
+ }
768
+ function initializeWithFallback(context, tokenRefresherRunning2) {
769
+ const subscriptions = [];
770
+ let startedRefresher = !1;
771
+ subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !0 })), context.state.get().options?.storageArea && subscriptions.push(subscribeToStorageEventsAndSetToken(context));
772
+ try {
773
+ const { instance, state } = context;
774
+ if (!(state.get().authState?.type === AuthStateType.LOGGED_IN && state.get().authState.token)) {
775
+ const projectIdValue = instance.config.projectId, clientFactory = state.get().options.clientFactory;
776
+ checkForCookieAuth(projectIdValue, clientFactory).then((isCookieAuthEnabled) => {
777
+ isCookieAuthEnabled && state.set("enableCookieAuth", (prev) => ({
778
+ options: { ...prev.options, authMethod: "cookie" },
779
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? prev.authState : createLoggedInAuthState("", null)
780
+ }));
781
+ });
782
+ }
783
+ } catch {
784
+ }
785
+ return tokenRefresherRunning2 || (startedRefresher = !0, subscriptions.push(refreshStampedToken(context))), {
786
+ dispose: () => {
787
+ for (const subscription of subscriptions)
788
+ subscription.unsubscribe();
789
+ },
790
+ tokenRefresherStarted: startedRefresher
791
+ };
792
+ }
793
+ let tokenRefresherRunning = !1;
794
+ const authStore = {
795
+ name: "Auth",
796
+ getInitialState(instance) {
797
+ const {
798
+ apiHost: configApiHost,
799
+ callbackUrl,
800
+ providers: customProviders,
801
+ token: providedToken,
802
+ clientFactory = createClient,
803
+ initialLocationHref = getDefaultLocation()
804
+ } = instance.config.auth ?? {}, apiHost = configApiHost ?? getStagingApiHost(), authConfig = instance.config.auth ?? {};
805
+ let loginDomain = "https://www.sanity.io";
806
+ try {
807
+ apiHost && new URL(apiHost).hostname.endsWith(".sanity.work") && (loginDomain = "https://www.sanity.work");
808
+ } catch {
809
+ }
810
+ const loginUrl = new URL("/login", loginDomain);
811
+ loginUrl.searchParams.set("origin", getCleanedUrl(initialLocationHref)), loginUrl.searchParams.set("type", "stampedToken"), loginUrl.searchParams.set("withSid", "true");
812
+ const mode = resolveAuthMode(instance.config, initialLocationHref), strategyOptions = {
813
+ authConfig,
814
+ projectId: instance.config.projectId,
815
+ initialLocationHref,
816
+ tokenSource: instance.config.studio?.auth?.token
817
+ };
818
+ let result;
819
+ switch (mode) {
820
+ case "studio":
821
+ result = getStudioInitialState(strategyOptions);
822
+ break;
823
+ case "dashboard":
824
+ result = getDashboardInitialState(strategyOptions);
825
+ break;
826
+ case "standalone":
827
+ result = getStandaloneInitialState(strategyOptions);
828
+ break;
829
+ }
830
+ return {
831
+ authState: result.authState,
832
+ dashboardContext: result.dashboardContext,
833
+ options: {
834
+ apiHost,
835
+ loginUrl: loginUrl.toString(),
836
+ callbackUrl,
837
+ customProviders,
838
+ providedToken,
839
+ clientFactory,
840
+ initialLocationHref,
841
+ storageKey: result.storageKey,
842
+ storageArea: result.storageArea,
843
+ authMethod: result.authMethod
844
+ }
845
+ };
846
+ },
847
+ initialize(context) {
848
+ const initialLocationHref = context.state.get().options?.initialLocationHref ?? getDefaultLocation(), mode = resolveAuthMode(context.instance.config, initialLocationHref);
849
+ let initResult;
850
+ switch (mode) {
851
+ case "studio":
852
+ initResult = initializeStudioAuth(context, tokenRefresherRunning);
853
+ break;
854
+ case "dashboard":
855
+ initResult = initializeDashboardAuth(context, tokenRefresherRunning);
856
+ break;
857
+ case "standalone":
858
+ initResult = initializeStandaloneAuth(context, tokenRefresherRunning);
859
+ break;
860
+ }
861
+ return initResult.tokenRefresherStarted && (tokenRefresherRunning = !0), initResult.dispose;
862
+ }
863
+ }, getCurrentUserState = bindActionGlobally(
864
+ authStore,
865
+ createStateSourceAction(
866
+ ({ state: { authState } }) => authState.type === AuthStateType.LOGGED_IN ? authState.currentUser : null
867
+ )
868
+ ), getTokenState = bindActionGlobally(
869
+ authStore,
870
+ createStateSourceAction(
871
+ ({ state: { authState } }) => authState.type === AuthStateType.LOGGED_IN ? authState.token : null
872
+ )
873
+ ), getAuthMethodState = bindActionGlobally(
874
+ authStore,
875
+ createStateSourceAction(({ state: { options } }) => options.authMethod)
876
+ ), getLoginUrlState = bindActionGlobally(
877
+ authStore,
878
+ createStateSourceAction(({ state: { options } }) => options.loginUrl)
879
+ ), getAuthState = bindActionGlobally(
880
+ authStore,
881
+ createStateSourceAction(({ state: { authState } }) => authState)
882
+ ), getDashboardOrganizationId = bindActionGlobally(
883
+ authStore,
884
+ createStateSourceAction(({ state: { dashboardContext } }) => dashboardContext?.orgId)
885
+ ), getIsInDashboardState = bindActionGlobally(
886
+ authStore,
887
+ createStateSourceAction(
888
+ ({ state: { dashboardContext } }) => (
889
+ // Check if dashboardContext exists and is not empty
890
+ !!dashboardContext && Object.keys(dashboardContext).length > 0
891
+ )
892
+ )
893
+ ), setAuthToken = bindActionGlobally(authStore, ({ state }, token) => {
894
+ const currentAuthState = state.get().authState;
895
+ if (token) {
896
+ if (currentAuthState.type !== AuthStateType.LOGGED_IN || currentAuthState.token !== token) {
897
+ const currentUser = currentAuthState.type === AuthStateType.LOGGED_IN ? currentAuthState.currentUser : null, preservedLastTokenRefresh = currentAuthState.type === AuthStateType.LOGGED_IN ? currentAuthState.lastTokenRefresh : void 0;
898
+ state.set("setToken", {
899
+ authState: createLoggedInAuthState(token, currentUser, preservedLastTokenRefresh)
900
+ });
901
+ }
902
+ } else
903
+ currentAuthState.type !== AuthStateType.LOGGED_OUT && state.set("setToken", {
904
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
905
+ });
906
+ });
907
+ var authStore$1 = /* @__PURE__ */ Object.freeze({
908
+ __proto__: null,
909
+ authStore,
910
+ getAuthMethodState,
911
+ getAuthState,
912
+ getCurrentUserState,
913
+ getDashboardOrganizationId,
914
+ getIsInDashboardState,
915
+ getLoginUrlState,
916
+ getTokenState,
917
+ setAuthToken
918
+ });
919
+ const DEFAULT_API_VERSION = "2024-11-12", DEFAULT_REQUEST_TAG_PREFIX = "sanity.sdk", allowedKeys = Object.keys({
920
+ apiHost: null,
921
+ useCdn: null,
922
+ token: null,
923
+ perspective: null,
924
+ proxy: null,
925
+ withCredentials: null,
926
+ timeout: null,
927
+ maxRetries: null,
928
+ dataset: null,
929
+ projectId: null,
930
+ scope: null,
931
+ apiVersion: null,
932
+ requestTagPrefix: null,
933
+ useProjectHostname: null,
934
+ "~experimental_resource": null,
935
+ source: null
936
+ }), DEFAULT_CLIENT_CONFIG = {
937
+ apiVersion: DEFAULT_API_VERSION,
938
+ useCdn: !1,
939
+ ignoreBrowserTokenWarning: !0,
940
+ allowReconfigure: !1,
941
+ requestTagPrefix: DEFAULT_REQUEST_TAG_PREFIX
942
+ }, clientStore = {
943
+ name: "clientStore",
944
+ getInitialState: (instance) => ({
945
+ clients: {},
946
+ token: getTokenState(instance).getCurrent()
947
+ }),
948
+ initialize(context) {
949
+ const subscription = listenToToken(context), authMethodSubscription = listenToAuthMethod(context);
950
+ return () => {
951
+ subscription.unsubscribe(), authMethodSubscription.unsubscribe();
952
+ };
953
+ }
954
+ }, listenToToken = ({ instance, state }) => getTokenState(instance).observable.subscribe((token) => {
955
+ state.set("setTokenAndResetClients", { token, clients: {} });
956
+ }), listenToAuthMethod = ({ instance, state }) => getAuthMethodState(instance).observable.subscribe((authMethod) => {
957
+ state.set("setAuthMethod", { authMethod });
958
+ }), getClientConfigKey = (options) => JSON.stringify(pick(options, ...allowedKeys)), getClient = bindActionGlobally(
959
+ clientStore,
960
+ ({ state, instance }, options) => {
961
+ if (!options || typeof options != "object")
962
+ throw new Error(
963
+ 'getClient() requires a configuration object with at least an "apiVersion" property. Example: getClient(instance, { apiVersion: "2024-11-12" })'
964
+ );
965
+ const disallowedKeys = Object.keys(options).filter((key2) => !allowedKeys.includes(key2));
966
+ if (disallowedKeys.length > 0) {
967
+ const listFormatter = new Intl.ListFormat("en", { style: "long", type: "conjunction" });
968
+ throw new Error(
969
+ `The client options provided contains unsupported properties: ${listFormatter.format(disallowedKeys)}. Allowed keys are: ${listFormatter.format(allowedKeys)}.`
970
+ );
971
+ }
972
+ const tokenFromState = state.get().token, { clients, authMethod } = state.get();
973
+ let resource;
974
+ options.source && (isDatasetSource(options.source) ? resource = { type: "dataset", id: `${options.source.projectId}.${options.source.dataset}` } : isMediaLibrarySource(options.source) ? resource = { type: "media-library", id: options.source.mediaLibraryId } : isCanvasSource(options.source) && (resource = { type: "canvas", id: options.source.canvasId }));
975
+ const projectId = options.projectId ?? instance.config.projectId, dataset = options.dataset ?? instance.config.dataset, apiHost = options.apiHost ?? instance.config.auth?.apiHost ?? getStagingApiHost(), effectiveOptions = {
976
+ ...DEFAULT_CLIENT_CONFIG,
977
+ ...(options.scope === "global" || !projectId || resource) && { useProjectHostname: !1 },
978
+ token: authMethod === "cookie" ? void 0 : tokenFromState ?? void 0,
979
+ ...options,
980
+ ...projectId && { projectId },
981
+ ...dataset && { dataset },
982
+ ...apiHost && { apiHost },
983
+ ...resource && { "~experimental_resource": resource }
984
+ };
985
+ resource && ((options.projectId || options.dataset) && console.warn(
986
+ "Both source and explicit projectId/dataset are provided. The source will be used and projectId/dataset will be ignored."
987
+ ), delete effectiveOptions.projectId, delete effectiveOptions.dataset), effectiveOptions.token === null || typeof effectiveOptions.token > "u" ? (delete effectiveOptions.token, authMethod === "cookie" && (effectiveOptions.withCredentials = !0)) : delete effectiveOptions.withCredentials;
988
+ const key = getClientConfigKey(effectiveOptions);
989
+ if (clients[key]) return clients[key];
990
+ const client = createClient(effectiveOptions);
991
+ return state.set("addClient", (prev) => ({ clients: { ...prev.clients, [key]: client } })), client;
992
+ }
993
+ ), getClientState = bindActionGlobally(
994
+ clientStore,
995
+ createStateSourceAction(({ instance }, options) => getClient(instance, options))
996
+ );
997
+ var clientStore$1 = /* @__PURE__ */ Object.freeze({
998
+ __proto__: null,
999
+ getClient,
1000
+ getClientState
1001
+ });
1002
+ function setCleanupTimeout(fn, delay) {
1003
+ const timer2 = setTimeout(fn, delay), t = timer2;
1004
+ return typeof t == "object" && t !== null && "unref" in t && typeof t.unref == "function" && t.unref(), timer2;
1005
+ }
1006
+ const API_VERSION$1 = "vX", PROJECT_API_VERSION = "2025-07-18", USERS_STATE_CLEAR_DELAY = 5e3, DEFAULT_USERS_BATCH_SIZE = 100, getUsersKey = (instance, {
1007
+ resourceType,
1008
+ organizationId,
1009
+ batchSize = DEFAULT_USERS_BATCH_SIZE,
1010
+ projectId = instance.config.projectId,
1011
+ userId
1012
+ } = {}) => JSON.stringify({
1013
+ resourceType,
1014
+ organizationId,
1015
+ batchSize,
1016
+ projectId,
1017
+ userId
1018
+ }), parseUsersKey = (key) => JSON.parse(key), addSubscription = (subscriptionId, key) => (prev) => {
1019
+ const group = prev.users[key], subscriptions = [...group?.subscriptions ?? [], subscriptionId];
1020
+ return { ...prev, users: { ...prev.users, [key]: { ...group, subscriptions } } };
1021
+ }, removeSubscription = (subscriptionId, key) => (prev) => {
1022
+ const group = prev.users[key];
1023
+ if (!group) return prev;
1024
+ const subscriptions = group.subscriptions.filter((id) => id !== subscriptionId);
1025
+ return subscriptions.length ? { ...prev, users: { ...prev.users, [key]: { ...group, subscriptions } } } : { ...prev, users: omit(prev.users, key) };
1026
+ }, setUsersData = (key, { data, nextCursor, totalCount }) => (prev) => {
1027
+ const group = prev.users[key];
1028
+ if (!group) return prev;
1029
+ const users = [...group.users ?? [], ...data];
1030
+ return { ...prev, users: { ...prev.users, [key]: { ...group, users, totalCount, nextCursor } } };
1031
+ }, updateLastLoadMoreRequest = (timestamp, key) => (prev) => {
1032
+ const group = prev.users[key];
1033
+ return group ? { ...prev, users: { ...prev.users, [key]: { ...group, lastLoadMoreRequest: timestamp } } } : prev;
1034
+ }, setUsersError = (key, error) => (prev) => {
1035
+ const group = prev.users[key];
1036
+ return group ? { ...prev, users: { ...prev.users, [key]: { ...group, error } } } : prev;
1037
+ }, cancelRequest = (key) => (prev) => {
1038
+ const group = prev.users[key];
1039
+ return !group || group.subscriptions.length ? prev : { ...prev, users: omit(prev.users, key) };
1040
+ }, initializeRequest = (key) => (prev) => prev.users[key] ? prev : { ...prev, users: { ...prev.users, [key]: { subscriptions: [] } } };
1041
+ function sortReleases(releases = []) {
1042
+ return [...releases].sort((a, b) => {
1043
+ if (a.metadata.releaseType === "undecided" && b.metadata.releaseType !== "undecided")
1044
+ return -1;
1045
+ if (a.metadata.releaseType !== "undecided" && b.metadata.releaseType === "undecided")
1046
+ return 1;
1047
+ if (a.metadata.releaseType === "undecided" && b.metadata.releaseType === "undecided")
1048
+ return new Date(b._createdAt).getTime() - new Date(a._createdAt).getTime();
1049
+ if (a.metadata.releaseType === "scheduled" && b.metadata.releaseType === "scheduled") {
1050
+ const aPublishAt = a.publishAt || a.metadata.intendedPublishAt;
1051
+ if (!aPublishAt)
1052
+ return 1;
1053
+ const bPublishAt = b.publishAt || b.metadata.intendedPublishAt;
1054
+ return bPublishAt ? new Date(bPublishAt).getTime() - new Date(aPublishAt).getTime() : -1;
1055
+ }
1056
+ return a.metadata.releaseType === "asap" && b.metadata.releaseType !== "asap" ? 1 : a.metadata.releaseType !== "asap" && b.metadata.releaseType === "asap" ? -1 : a.metadata.releaseType === "asap" && b.metadata.releaseType === "asap" ? new Date(b._createdAt).getTime() - new Date(a._createdAt).getTime() : 0;
1057
+ });
1058
+ }
1059
+ const ARCHIVED_RELEASE_STATES = ["archived", "published"], STABLE_EMPTY_RELEASES = [], releasesStore = {
1060
+ name: "Releases",
1061
+ getInitialState: () => ({
1062
+ activeReleases: void 0
1063
+ }),
1064
+ initialize: (context) => {
1065
+ const subscription = subscribeToReleases(context);
1066
+ return () => subscription.unsubscribe();
1067
+ }
1068
+ }, _getActiveReleasesState = bindActionBySource(
1069
+ releasesStore,
1070
+ createStateSourceAction({
1071
+ selector: ({ state }, _) => state.activeReleases
1072
+ })
1073
+ ), getActiveReleasesState = (instance, options) => (
1074
+ // bindActionBySource keyFn destructures { source } from the first param, so pass {} when no options
1075
+ _getActiveReleasesState(instance, options ?? {})
1076
+ ), RELEASES_QUERY = "releases::all()", subscribeToReleases = ({
1077
+ instance,
1078
+ state,
1079
+ key: { source }
1080
+ }) => {
1081
+ const { observable: releases$ } = getQueryState(instance, {
1082
+ query: RELEASES_QUERY,
1083
+ perspective: "raw",
1084
+ source: source && !isDatasetSource(source) ? source : void 0,
1085
+ tag: "releases"
1086
+ });
1087
+ return releases$.pipe(
1088
+ map((releases) => {
1089
+ state.set("setActiveReleases", {
1090
+ activeReleases: sortReleases(releases ?? STABLE_EMPTY_RELEASES).filter((release) => !ARCHIVED_RELEASE_STATES.includes(release.state)).reverse()
1091
+ });
1092
+ })
1093
+ ).subscribe({ error: (error) => state.set("setError", { error }) });
1094
+ }, DEFAULT_PERSPECTIVE = "drafts", optionsCache = /* @__PURE__ */ new Map(), selectInstancePerspective = (context, _) => context.instance.config.perspective, selectActiveReleases = (context) => context.state.activeReleases, selectOptions = (_context, options) => options, memoizedOptionsSelector = createSelector(
1095
+ [selectActiveReleases, selectOptions],
1096
+ (activeReleases, options) => {
1097
+ if (!options || !activeReleases) return options;
1098
+ const releaseIds = activeReleases.map((release) => release._id).join(",");
1099
+ let nestedCache = optionsCache.get(releaseIds);
1100
+ nestedCache || (nestedCache = /* @__PURE__ */ new Map(), optionsCache.set(releaseIds, nestedCache));
1101
+ const optionsKey = JSON.stringify(options);
1102
+ let cachedOptions = nestedCache.get(optionsKey);
1103
+ return cachedOptions || (cachedOptions = options, nestedCache.set(optionsKey, cachedOptions)), cachedOptions;
1104
+ }
1105
+ ), _getPerspectiveStateSelector = createStateSourceAction({
1106
+ selector: createSelector(
1107
+ [selectInstancePerspective, selectActiveReleases, memoizedOptionsSelector],
1108
+ (instancePerspective, activeReleases, memoizedOptions) => {
1109
+ const perspective = memoizedOptions?.perspective ?? instancePerspective ?? DEFAULT_PERSPECTIVE;
1110
+ if (!isReleasePerspective(perspective)) return perspective;
1111
+ if (!activeReleases || activeReleases.length === 0) return;
1112
+ const releaseNames = sortReleases(activeReleases).map((release) => release.name), index = releaseNames.findIndex((name) => name === perspective.releaseName);
1113
+ if (index < 0)
1114
+ throw new Error(`Release "${perspective.releaseName}" not found in active releases`);
1115
+ return ["drafts", ...releaseNames.slice(0, index + 1)].filter((name) => !perspective.excludedPerspectives?.includes(name)).reverse();
1116
+ }
1117
+ )
1118
+ });
1119
+ let _boundGetPerspectiveState;
1120
+ const getPerspectiveState = (instance, ...rest) => (_boundGetPerspectiveState || (_boundGetPerspectiveState = bindActionBySource(
1121
+ releasesStore,
1122
+ _getPerspectiveStateSelector
1123
+ )), _boundGetPerspectiveState(instance, ...rest.length ? rest : [{}])), QUERY_STATE_CLEAR_DELAY = 1e3, QUERY_STORE_API_VERSION = "v2025-05-06", QUERY_STORE_DEFAULT_PERSPECTIVE = "drafts", setQueryError = (key, error) => (prev) => {
1124
+ const prevQuery = prev.queries[key];
1125
+ return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, error } } } : prev;
1126
+ }, setQueryData = (key, result, syncTags) => (prev) => {
1127
+ const prevQuery = prev.queries[key];
1128
+ return prevQuery ? {
1129
+ ...prev,
1130
+ queries: { ...prev.queries, [key]: { ...prevQuery, result: result ?? null, syncTags } }
1131
+ } : prev;
1132
+ }, setLastLiveEventId = (key, lastLiveEventId) => (prev) => {
1133
+ const prevQuery = prev.queries[key];
1134
+ return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, lastLiveEventId } } } : prev;
1135
+ }, addSubscriber = (key, subscriptionId) => (prev) => {
1136
+ const prevQuery = prev.queries[key], subscribers = [...prevQuery?.subscribers ?? [], subscriptionId];
1137
+ return { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, subscribers } } };
1138
+ }, removeSubscriber = (key, subscriptionId) => (prev) => {
1139
+ const prevQuery = prev.queries[key];
1140
+ if (!prevQuery) return prev;
1141
+ const subscribers = prevQuery.subscribers.filter((id) => id !== subscriptionId);
1142
+ return subscribers.length ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, subscribers } } } : { ...prev, queries: omit(prev.queries, key) };
1143
+ }, cancelQuery = (key) => (prev) => {
1144
+ const prevQuery = prev.queries[key];
1145
+ return !prevQuery || prevQuery.subscribers.length ? prev : { ...prev, queries: omit(prev.queries, key) };
1146
+ }, initializeQuery = (key) => (prev) => prev.queries[key] ? prev : { ...prev, queries: { ...prev.queries, [key]: { subscribers: [] } } }, EMPTY_ARRAY = [], getQueryKey = (options) => JSON.stringify(options), parseQueryKey = (key) => JSON.parse(key);
1147
+ function normalizeOptionsWithPerspective(instance, options) {
1148
+ if (options.perspective !== void 0) return options;
1149
+ const instancePerspective = instance.config.perspective;
1150
+ return {
1151
+ ...options,
1152
+ perspective: instancePerspective !== void 0 ? instancePerspective : QUERY_STORE_DEFAULT_PERSPECTIVE
1153
+ };
1154
+ }
1155
+ const queryStore = {
1156
+ name: "QueryStore",
1157
+ getInitialState: () => ({ queries: {} }),
1158
+ initialize(context) {
1159
+ const subscriptions = [
1160
+ listenForNewSubscribersAndFetch(context),
1161
+ listenToLiveClientAndSetLastLiveEventIds(context)
1162
+ ];
1163
+ return () => {
1164
+ for (const subscription of subscriptions)
1165
+ subscription.unsubscribe();
1166
+ };
1167
+ }
1168
+ }, errorHandler = (state) => (error) => state.set("setError", { error }), listenForNewSubscribersAndFetch = ({ state, instance }) => state.observable.pipe(
1169
+ map((s) => new Set(Object.keys(s.queries))),
1170
+ distinctUntilChanged((curr, next) => curr.size !== next.size ? !1 : Array.from(next).every((i) => curr.has(i))),
1171
+ startWith(/* @__PURE__ */ new Set()),
1172
+ pairwise(),
1173
+ mergeMap(([curr, next]) => {
1174
+ const added = Array.from(next).filter((i) => !curr.has(i)), removed = Array.from(curr).filter((i) => !next.has(i));
1175
+ return [
1176
+ ...added.map((key) => ({ key, added: !0 })),
1177
+ ...removed.map((key) => ({ key, added: !1 }))
1178
+ ];
1179
+ }),
1180
+ groupBy((i) => i.key),
1181
+ mergeMap(
1182
+ (group$) => group$.pipe(
1183
+ switchMap((e) => {
1184
+ if (!e.added) return EMPTY;
1185
+ const lastLiveEventId$ = state.observable.pipe(
1186
+ map((s) => s.queries[group$.key]?.lastLiveEventId),
1187
+ distinctUntilChanged()
1188
+ ), {
1189
+ query,
1190
+ params,
1191
+ projectId,
1192
+ dataset,
1193
+ tag,
1194
+ source,
1195
+ perspective: perspectiveFromOptions,
1196
+ ...restOptions
1197
+ } = parseQueryKey(group$.key), perspective$ = isReleasePerspective(perspectiveFromOptions) ? getPerspectiveState(instance, {
1198
+ perspective: perspectiveFromOptions
1199
+ }).observable.pipe(filter(Boolean)) : of(perspectiveFromOptions ?? QUERY_STORE_DEFAULT_PERSPECTIVE), client$ = getClientState(instance, {
1200
+ apiVersion: QUERY_STORE_API_VERSION,
1201
+ projectId,
1202
+ dataset,
1203
+ source
1204
+ }).observable;
1205
+ return combineLatest({
1206
+ lastLiveEventId: lastLiveEventId$,
1207
+ client: client$,
1208
+ perspective: perspective$
1209
+ }).pipe(
1210
+ switchMap(
1211
+ ({ lastLiveEventId, client, perspective }) => client.observable.fetch(query, params, {
1212
+ ...restOptions,
1213
+ perspective,
1214
+ filterResponse: !1,
1215
+ returnQuery: !1,
1216
+ lastLiveEventId,
1217
+ tag
1218
+ })
1219
+ )
1220
+ );
1221
+ }),
1222
+ catchError((error) => (state.set("setQueryError", setQueryError(group$.key, error)), EMPTY)),
1223
+ tap(({ result, syncTags }) => {
1224
+ state.set("setQueryData", setQueryData(group$.key, result, syncTags));
1225
+ })
1226
+ )
1227
+ )
1228
+ ).subscribe({ error: errorHandler(state) }), listenToLiveClientAndSetLastLiveEventIds = ({
1229
+ state,
1230
+ instance,
1231
+ key: { source }
1232
+ }) => {
1233
+ const liveMessages$ = getClientState(instance, {
1234
+ apiVersion: QUERY_STORE_API_VERSION,
1235
+ // temporary guard here until we're ready for everything to be queried via global api
1236
+ ...source && !isDatasetSource(source) ? { source } : {}
1237
+ }).observable.pipe(
1238
+ switchMap(
1239
+ (client) => defer(
1240
+ () => client.live.events({ includeDrafts: !!client.config().token, tag: "query-store" })
1241
+ ).pipe(
1242
+ catchError((error) => {
1243
+ if (error instanceof CorsOriginError)
1244
+ return state.set("setError", { error }), EMPTY;
1245
+ throw error;
1246
+ })
1247
+ )
1248
+ ),
1249
+ share(),
1250
+ filter((e) => e.type === "message")
1251
+ );
1252
+ return state.observable.pipe(
1253
+ mergeMap((s) => Object.entries(s.queries)),
1254
+ groupBy(([key]) => key),
1255
+ mergeMap((group$) => {
1256
+ const syncTags$ = group$.pipe(
1257
+ map(([, queryState]) => queryState),
1258
+ map((i) => i?.syncTags ?? EMPTY_ARRAY),
1259
+ distinctUntilChanged()
1260
+ );
1261
+ return combineLatest([liveMessages$, syncTags$]).pipe(
1262
+ filter(([message, syncTags]) => message.tags.some((tag) => syncTags.includes(tag))),
1263
+ tap(([message]) => {
1264
+ state.set("setLastLiveEventId", setLastLiveEventId(group$.key, message.id));
1265
+ })
1266
+ );
1267
+ })
1268
+ ).subscribe({ error: errorHandler(state) });
1269
+ };
1270
+ function getQueryState(...args) {
1271
+ return _getQueryState(...args);
1272
+ }
1273
+ const _getQueryState = bindActionBySource(
1274
+ queryStore,
1275
+ createStateSourceAction({
1276
+ selector: ({ state, instance }, options) => {
1277
+ if (state.error) throw state.error;
1278
+ const key = getQueryKey(normalizeOptionsWithPerspective(instance, options)), queryState = state.queries[key];
1279
+ if (queryState?.error) throw queryState.error;
1280
+ return queryState?.result;
1281
+ },
1282
+ onSubscribe: ({ state, instance }, options) => {
1283
+ const subscriptionId = insecureRandomId(), key = getQueryKey(normalizeOptionsWithPerspective(instance, options));
1284
+ return state.set("addSubscriber", addSubscriber(key, subscriptionId)), () => {
1285
+ setCleanupTimeout(
1286
+ () => state.set("removeSubscriber", removeSubscriber(key, subscriptionId)),
1287
+ QUERY_STATE_CLEAR_DELAY
1288
+ );
1289
+ };
1290
+ }
1291
+ })
1292
+ );
1293
+ function resolveQuery(...args) {
1294
+ return _resolveQuery(...args);
1295
+ }
1296
+ const _resolveQuery = bindActionBySource(
1297
+ queryStore,
1298
+ ({ state, instance }, { signal, ...options }) => {
1299
+ const normalized = normalizeOptionsWithPerspective(instance, options), { getCurrent } = getQueryState(instance, normalized), key = getQueryKey(normalized), aborted$ = signal ? new Observable((observer) => {
1300
+ const cleanup = () => {
1301
+ signal.removeEventListener("abort", listener);
1302
+ }, listener = () => {
1303
+ observer.error(new DOMException("The operation was aborted.", "AbortError")), observer.complete(), cleanup();
1304
+ };
1305
+ return signal.addEventListener("abort", listener), cleanup;
1306
+ }).pipe(
1307
+ catchError((error) => {
1308
+ throw error instanceof Error && error.name === "AbortError" && state.set("cancelQuery", cancelQuery(key)), error;
1309
+ })
1310
+ ) : NEVER;
1311
+ state.set("initializeQuery", initializeQuery(key));
1312
+ const resolved$ = state.observable.pipe(
1313
+ map(getCurrent),
1314
+ first((i) => i !== void 0)
1315
+ );
1316
+ return firstValueFrom(race([resolved$, aborted$]));
1317
+ }
1318
+ ), TITLE_CANDIDATES = ["title", "name", "label", "heading", "header", "caption"], SUBTITLE_CANDIDATES = ["description", "subtitle", ...TITLE_CANDIDATES], PREVIEW_PROJECTION = `{
1319
+ // Get all potential title fields
1320
+ "titleCandidates": {
1321
+ ${TITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(`,
1322
+ `)}
1323
+ },
1324
+ // Get all potential subtitle fields
1325
+ "subtitleCandidates": {
1326
+ ${SUBTITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(`,
1327
+ `)}
1328
+ },
1329
+ "media": coalesce(
1330
+ select(
1331
+ defined(asset) => {"type": "image-asset", "_ref": asset._ref},
1332
+ defined(image.asset) => {"type": "image-asset", "_ref": image.asset._ref},
1333
+ defined(mainImage.asset) => {"type": "image-asset", "_ref": mainImage.asset._ref},
1334
+ null
1335
+ )
1336
+ ),
1337
+ _type,
1338
+ _id,
1339
+ _updatedAt
1340
+ }`, API_VERSION = "v2025-05-06";
1341
+ function hasImageRef(value) {
1342
+ return isObject(value) && "_ref" in value && typeof value._ref == "string";
1343
+ }
1344
+ function normalizeMedia(media, client) {
1345
+ if (!media || !hasImageRef(media)) return null;
1346
+ const url = createImageUrlBuilder(client).image({ _ref: media._ref }).url();
1347
+ return {
1348
+ type: "image-asset",
1349
+ _ref: media._ref,
1350
+ url
1351
+ };
1352
+ }
1353
+ function findFirstDefined(fieldsToSearch, candidates, exclude) {
1354
+ if (candidates)
1355
+ for (const field of fieldsToSearch) {
1356
+ const value = candidates[field];
1357
+ if (typeof value == "string" && value.trim() !== "" && value !== exclude)
1358
+ return value;
1359
+ }
1360
+ }
1361
+ function transformProjectionToPreview(instance, projectionResult, source) {
1362
+ const title = findFirstDefined(TITLE_CANDIDATES, projectionResult.titleCandidates), subtitle = findFirstDefined(SUBTITLE_CANDIDATES, projectionResult.subtitleCandidates, title), client = getClient(instance, {
1363
+ apiVersion: API_VERSION,
1364
+ // TODO: remove in v3 when we're ready for everything to be queried via source
1365
+ source: source && !isDatasetSource(source) ? source : void 0
1366
+ });
1367
+ return {
1368
+ title: String(title || `${projectionResult._type}: ${projectionResult._id}`),
1369
+ subtitle: subtitle || void 0,
1370
+ media: normalizeMedia(projectionResult.media, client),
1371
+ ...projectionResult._status && { _status: projectionResult._status }
1372
+ };
1373
+ }
1374
+ const TOKEN_REGEX = /(?:[^\s"]+|"[^"]*")+/g;
1375
+ function isNegationToken(token) {
1376
+ return typeof token < "u" && token.trim().startsWith("-");
1377
+ }
1378
+ function isPrefixToken(token) {
1379
+ return typeof token < "u" && token.trim().endsWith("*");
1380
+ }
1381
+ function isExactMatchToken(token) {
1382
+ return !!token && token.length >= 2 && token.startsWith('"') && token.endsWith('"');
1383
+ }
1384
+ function createGroqSearchFilter(query) {
1385
+ const trimmedQuery = query.trim();
1386
+ if (!trimmedQuery)
1387
+ return "";
1388
+ const tokens = trimmedQuery.match(TOKEN_REGEX) ?? [], reversedIndex = [...tokens].reverse().findIndex(
1389
+ (token) => !isNegationToken(token) && !isExactMatchToken(token)
1390
+ ), finalIncrementalTokenIndex = reversedIndex === -1 ? -1 : tokens.length - 1 - reversedIndex, finalIncrementalToken = tokens[finalIncrementalTokenIndex], processedTokens = [...tokens];
1391
+ return finalIncrementalToken !== void 0 && !isPrefixToken(finalIncrementalToken) && processedTokens.splice(
1392
+ finalIncrementalTokenIndex,
1393
+ 1,
1394
+ `${finalIncrementalToken}*`
1395
+ ), `[@] match text::query("${processedTokens.join(" ").replace(/"/g, '\\"')}")`;
1396
+ }
1397
+ export {
1398
+ API_VERSION$1 as API_VERSION,
1399
+ AuthStateType,
1400
+ DEFAULT_API_VERSION$1 as DEFAULT_API_VERSION,
1401
+ PREVIEW_PROJECTION,
1402
+ PROJECT_API_VERSION,
1403
+ REQUEST_TAG_PREFIX,
1404
+ USERS_STATE_CLEAR_DELAY,
1405
+ addSubscription,
1406
+ authStore,
1407
+ authStore$1,
1408
+ bindActionByDataset,
1409
+ bindActionBySource,
1410
+ bindActionBySourceAndPerspective,
1411
+ bindActionGlobally,
1412
+ cancelRequest,
1413
+ clientStore$1 as clientStore,
1414
+ configureLogging,
1415
+ createGroqSearchFilter,
1416
+ createLoggedInAuthState,
1417
+ createLogger,
1418
+ createStateSourceAction,
1419
+ defineStore,
1420
+ getActiveReleasesState,
1421
+ getAuthCode,
1422
+ getAuthState,
1423
+ getCleanedUrl,
1424
+ getClient,
1425
+ getClientErrorApiBody,
1426
+ getClientErrorApiDescription,
1427
+ getClientErrorApiType,
1428
+ getClientState,
1429
+ getCurrentUserState,
1430
+ getDashboardOrganizationId,
1431
+ getDefaultLocation,
1432
+ getEnv,
1433
+ getIsInDashboardState,
1434
+ getLoginUrlState,
1435
+ getPerspectiveState,
1436
+ getQueryKey,
1437
+ getQueryState,
1438
+ getTokenFromLocation,
1439
+ getTokenState,
1440
+ getUsersKey,
1441
+ initializeRequest,
1442
+ insecureRandomId,
1443
+ isCanvasSource,
1444
+ isDatasetSource,
1445
+ isMediaLibrarySource,
1446
+ isProjectUserNotFoundClientError,
1447
+ isReleasePerspective,
1448
+ isStudioConfig,
1449
+ parseQueryKey,
1450
+ parseUsersKey,
1451
+ removeSubscription,
1452
+ resolveQuery,
1453
+ setAuthToken,
1454
+ setCleanupTimeout,
1455
+ setUsersData,
1456
+ setUsersError,
1457
+ transformProjectionToPreview,
1458
+ updateLastLoadMoreRequest
1459
+ };
1460
+ //# sourceMappingURL=createGroqSearchFilter.js.map