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