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