@sanity/sdk 2.5.0 → 2.7.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 (46) hide show
  1. package/dist/index.d.ts +429 -27
  2. package/dist/index.js +657 -266
  3. package/dist/index.js.map +1 -1
  4. package/package.json +4 -3
  5. package/src/_exports/index.ts +18 -3
  6. package/src/auth/authMode.test.ts +56 -0
  7. package/src/auth/authMode.ts +71 -0
  8. package/src/auth/authStore.test.ts +85 -4
  9. package/src/auth/authStore.ts +63 -125
  10. package/src/auth/authStrategy.ts +39 -0
  11. package/src/auth/dashboardAuth.ts +132 -0
  12. package/src/auth/standaloneAuth.ts +109 -0
  13. package/src/auth/studioAuth.ts +217 -0
  14. package/src/auth/studioModeAuth.test.ts +43 -1
  15. package/src/auth/studioModeAuth.ts +10 -1
  16. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +21 -6
  17. package/src/client/clientStore.test.ts +45 -43
  18. package/src/client/clientStore.ts +23 -9
  19. package/src/config/loggingConfig.ts +149 -0
  20. package/src/config/sanityConfig.ts +82 -22
  21. package/src/projection/getProjectionState.ts +6 -5
  22. package/src/projection/projectionQuery.test.ts +38 -55
  23. package/src/projection/projectionQuery.ts +27 -31
  24. package/src/projection/projectionStore.test.ts +4 -4
  25. package/src/projection/projectionStore.ts +3 -2
  26. package/src/projection/resolveProjection.ts +2 -2
  27. package/src/projection/statusQuery.test.ts +35 -0
  28. package/src/projection/statusQuery.ts +71 -0
  29. package/src/projection/subscribeToStateAndFetchBatches.test.ts +63 -50
  30. package/src/projection/subscribeToStateAndFetchBatches.ts +106 -27
  31. package/src/projection/types.ts +12 -0
  32. package/src/projection/util.ts +0 -1
  33. package/src/query/queryStore.test.ts +64 -0
  34. package/src/query/queryStore.ts +33 -11
  35. package/src/releases/getPerspectiveState.test.ts +17 -14
  36. package/src/releases/getPerspectiveState.ts +58 -38
  37. package/src/releases/releasesStore.test.ts +59 -61
  38. package/src/releases/releasesStore.ts +21 -35
  39. package/src/releases/utils/isReleasePerspective.ts +7 -0
  40. package/src/store/createActionBinder.test.ts +211 -1
  41. package/src/store/createActionBinder.ts +102 -13
  42. package/src/store/createSanityInstance.test.ts +85 -1
  43. package/src/store/createSanityInstance.ts +55 -4
  44. package/src/utils/logger-usage-example.md +141 -0
  45. package/src/utils/logger.test.ts +757 -0
  46. package/src/utils/logger.ts +537 -0
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { Observable, share, map, distinctUntilChanged, skip, filter, exhaustMap, from, timer, switchMap, takeWhile, firstValueFrom, fromEvent, EMPTY, defer, asapScheduler, combineLatest, of, concatMap, withLatestFrom, concat, throwError, first as first$1, Subject, takeUntil, partition, merge, shareReplay, tap as tap$1, catchError as catchError$1, startWith as startWith$1, pairwise as pairwise$1, groupBy as groupBy$1, mergeMap as mergeMap$1, throttle, race, NEVER, Subscription, retry, debounceTime as debounceTime$1 } from "rxjs";
1
+ import { Observable, share, map, distinctUntilChanged, skip, filter, exhaustMap, from, timer, switchMap, takeWhile, firstValueFrom, fromEvent, EMPTY, defer, asapScheduler, combineLatest, of, concatMap, withLatestFrom, concat, throwError, first as first$1, Subject, takeUntil, partition, merge, shareReplay, tap as tap$1, catchError as catchError$1, startWith as startWith$1, pairwise as pairwise$1, groupBy as groupBy$1, mergeMap as mergeMap$1, throttle, race, NEVER, Subscription, debounceTime } from "rxjs";
2
2
  import { createClient, CorsOriginError } from "@sanity/client";
3
3
  import { pick, omit, isEqual, isObject } from "lodash-es";
4
4
  import { devtools } from "zustand/middleware";
5
5
  import { createStore } from "zustand/vanilla";
6
- import { first, switchMap as switchMap$1, groupBy, mergeMap, startWith, pairwise, filter as filter$1, map as map$1, delay, tap, catchError, scan, share as share$1, take, debounceTime } from "rxjs/operators";
6
+ import { first, switchMap as switchMap$1, groupBy, mergeMap, startWith, pairwise, filter as filter$1, map as map$1, delay, tap, catchError, scan, share as share$1 } from "rxjs/operators";
7
7
  import { createController, createNode } from "@sanity/comlink";
8
8
  import { createSelector } from "reselect";
9
9
  import { SanityEncoder } from "@sanity/mutate";
@@ -17,16 +17,17 @@ import { isKeySegment, isKeyedObject } from "@sanity/types";
17
17
  import { createDocumentLoaderFromClient } from "@sanity/mutate/_unstable_store";
18
18
  import { SDK_CHANNEL_NAME, SDK_NODE_NAME } from "@sanity/message-protocol";
19
19
  import { fromUrl } from "@sanity/bifur-client";
20
- const SOURCE_ID = "__sanity_internal_sourceId";
21
- function datasetSource(projectId, dataset) {
22
- return { [SOURCE_ID]: { projectId, dataset } };
20
+ import { DocumentId, getPublishedId as getPublishedId$2, getDraftId as getDraftId$1, getVersionId, isDraftId, isVersionId, isPublishedId } from "@sanity/id-utils";
21
+ function isDatasetSource(source) {
22
+ return "projectId" in source && "dataset" in source;
23
23
  }
24
- function mediaLibrarySource(id) {
25
- return { [SOURCE_ID]: ["media-library", id] };
24
+ function isMediaLibrarySource(source) {
25
+ return "mediaLibraryId" in source;
26
26
  }
27
- function canvasSource(id) {
28
- return { [SOURCE_ID]: ["canvas", id] };
27
+ function isCanvasSource(source) {
28
+ return "canvasId" in source;
29
29
  }
30
+ const isReleasePerspective = (perspective) => typeof perspective == "object" && perspective !== null && "releaseName" in perspective;
30
31
  function getPublishedId(id) {
31
32
  const draftsPrefix = "drafts.";
32
33
  return id.startsWith(draftsPrefix) ? id.slice(draftsPrefix.length) : id;
@@ -38,13 +39,154 @@ function getDraftId(id) {
38
39
  function insecureRandomId() {
39
40
  return Array.from({ length: 16 }, () => Math.floor(Math.random() * 16).toString(16)).join("");
40
41
  }
42
+ const LOG_LEVEL_PRIORITY = {
43
+ error: 0,
44
+ warn: 1,
45
+ info: 2,
46
+ debug: 3,
47
+ trace: 4
48
+ }, DEFAULT_CONFIG = {
49
+ level: "warn",
50
+ namespaces: [],
51
+ internal: !1,
52
+ timestamps: !0,
53
+ enableInProduction: !1,
54
+ handler: {
55
+ // eslint-disable-next-line no-console
56
+ error: console.error.bind(console),
57
+ // eslint-disable-next-line no-console
58
+ warn: console.warn.bind(console),
59
+ // eslint-disable-next-line no-console
60
+ info: console.info.bind(console),
61
+ // eslint-disable-next-line no-console
62
+ debug: console.debug.bind(console),
63
+ // eslint-disable-next-line no-console
64
+ trace: console.debug.bind(console)
65
+ // trace uses console.debug
66
+ }
67
+ };
68
+ function parseDebugEnvVar() {
69
+ if (typeof process > "u" || !process.env?.DEBUG)
70
+ return null;
71
+ const debug = process.env.DEBUG;
72
+ if (!debug.includes("sanity"))
73
+ return null;
74
+ const config = {}, levelMatch = debug.match(/sanity:(trace|debug|info|warn|error):/), hasLevelSpecifier = !!levelMatch;
75
+ if (levelMatch ? config.level = levelMatch[1] : config.level = "debug", debug === "sanity")
76
+ config.namespaces = ["*"];
77
+ else if (hasLevelSpecifier && debug.match(/sanity:(trace|debug|info|warn|error):\*/))
78
+ config.namespaces = ["*"];
79
+ else if (!hasLevelSpecifier && debug.includes("sanity:*"))
80
+ config.namespaces = ["*"];
81
+ else {
82
+ const namespaces = debug.split(",").filter((s) => s.includes("sanity:")).map((s) => {
83
+ const cleaned = s.replace(/^sanity:/, "");
84
+ return hasLevelSpecifier && cleaned.match(/^(trace|debug|info|warn|error):/) ? cleaned.split(":").slice(1).join(":") : cleaned.split(":")[0];
85
+ }).filter(Boolean).filter((ns) => ns !== "*");
86
+ namespaces.length > 0 && (config.namespaces = namespaces);
87
+ }
88
+ return debug.includes(":internal") && (config.internal = !0), config;
89
+ }
90
+ const envConfig = parseDebugEnvVar();
91
+ let globalConfig = {
92
+ ...DEFAULT_CONFIG,
93
+ ...envConfig ?? {}
94
+ };
95
+ envConfig && (["info", "debug", "trace"].includes(globalConfig.level) || globalConfig.level === "warn") && console.info(
96
+ `[${(/* @__PURE__ */ new Date()).toISOString()}] [INFO] [sdk] Logging auto-configured from DEBUG environment variable`,
97
+ {
98
+ level: globalConfig.level,
99
+ namespaces: globalConfig.namespaces,
100
+ internal: globalConfig.internal,
101
+ source: "env:DEBUG",
102
+ value: typeof process < "u" ? process.env?.DEBUG : void 0
103
+ }
104
+ );
105
+ function configureLogging$1(config) {
106
+ globalConfig = {
107
+ ...globalConfig,
108
+ ...config,
109
+ handler: config.handler ?? globalConfig.handler
110
+ };
111
+ }
112
+ function isLoggingEnabled() {
113
+ return typeof process < "u" && process.env?.NODE_ENV === "production" ? globalConfig.enableInProduction : !0;
114
+ }
115
+ function isNamespaceEnabled(namespace) {
116
+ return isLoggingEnabled() ? globalConfig.namespaces.includes("*") ? !0 : globalConfig.namespaces.includes(namespace) : !1;
117
+ }
118
+ function isLevelEnabled(level) {
119
+ return isLoggingEnabled() ? LOG_LEVEL_PRIORITY[level] <= LOG_LEVEL_PRIORITY[globalConfig.level] : !1;
120
+ }
121
+ function formatMessage(namespace, level, message, context) {
122
+ const parts = [];
123
+ if (globalConfig.timestamps) {
124
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
125
+ parts.push(`[${timestamp}]`);
126
+ }
127
+ parts.push(`[${level.toUpperCase()}]`), parts.push(`[${namespace}]`);
128
+ const instanceContext = context?.instanceContext;
129
+ 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];
130
+ }
131
+ function sanitizeContext(context) {
132
+ if (!context || Object.keys(context).length === 0) return;
133
+ const sanitized = { ...context }, sensitiveKeys = ["token", "password", "secret", "apiKey", "authorization"];
134
+ for (const key of Object.keys(sanitized))
135
+ sensitiveKeys.some((sensitive) => key.toLowerCase().includes(sensitive)) && (sanitized[key] = "[REDACTED]");
136
+ return sanitized;
137
+ }
138
+ function createLogger(namespace, baseContext) {
139
+ const logAtLevel = (level, message, context) => {
140
+ if (!isNamespaceEnabled(namespace) || !isLevelEnabled(level) || context?.internal && !globalConfig.internal) return;
141
+ const mergedContext = { ...baseContext, ...context }, sanitized = sanitizeContext(mergedContext), [formatted, finalContext] = formatMessage(namespace, level, message, sanitized);
142
+ globalConfig.handler[level](formatted, finalContext);
143
+ };
144
+ return {
145
+ namespace,
146
+ error: (message, context) => logAtLevel("error", message, context),
147
+ warn: (message, context) => logAtLevel("warn", message, context),
148
+ info: (message, context) => logAtLevel("info", message, context),
149
+ debug: (message, context) => logAtLevel("debug", message, context),
150
+ trace: (message, context) => logAtLevel("trace", message, { ...context, internal: !0 }),
151
+ isLevelEnabled: (level) => isNamespaceEnabled(namespace) && isLevelEnabled(level),
152
+ child: (childContext) => createLogger(namespace, { ...baseContext, ...childContext }),
153
+ getInstanceContext: () => baseContext?.instanceContext
154
+ };
155
+ }
41
156
  function createSanityInstance(config = {}) {
42
- const instanceId = crypto.randomUUID(), disposeListeners = /* @__PURE__ */ new Map(), disposed = { current: !1 }, instance = {
157
+ const instanceId = crypto.randomUUID(), disposeListeners = /* @__PURE__ */ new Map(), disposed = { current: !1 }, instanceContext = {
158
+ instanceId,
159
+ projectId: config.projectId,
160
+ dataset: config.dataset
161
+ }, logger = createLogger("sdk", { instanceContext });
162
+ logger.info("Sanity instance created", {
163
+ hasProjectId: !!config.projectId,
164
+ hasDataset: !!config.dataset,
165
+ hasAuth: !!config.auth,
166
+ hasPerspective: !!config.perspective
167
+ }), logger.debug("Instance configuration", {
168
+ projectId: config.projectId,
169
+ dataset: config.dataset,
170
+ perspective: config.perspective,
171
+ hasStudioConfig: !!config.studio,
172
+ hasStudioTokenSource: !!config.studio?.auth?.token,
173
+ legacyStudioMode: config.studioMode?.enabled,
174
+ hasAuthProviders: !!config.auth?.providers,
175
+ hasAuthToken: !!config.auth?.token
176
+ });
177
+ const instance = {
43
178
  instanceId,
44
179
  config,
45
180
  isDisposed: () => disposed.current,
46
181
  dispose: () => {
47
- disposed.current || (disposed.current = !0, disposeListeners.forEach((listener) => listener()), disposeListeners.clear());
182
+ if (disposed.current) {
183
+ logger.trace("Dispose called on already disposed instance", { internal: !0 });
184
+ return;
185
+ }
186
+ logger.trace("Disposing instance", {
187
+ internal: !0,
188
+ listenerCount: disposeListeners.size
189
+ }), disposed.current = !0, disposeListeners.forEach((listener) => listener()), disposeListeners.clear(), logger.info("Instance disposed");
48
190
  },
49
191
  onDispose: (cb) => {
50
192
  const listenerId = insecureRandomId();
@@ -54,14 +196,26 @@ function createSanityInstance(config = {}) {
54
196
  },
55
197
  getParent: () => {
56
198
  },
57
- createChild: (next) => Object.assign(
58
- createSanityInstance({
59
- ...config,
60
- ...next,
61
- ...config.auth === next.auth ? config.auth : config.auth && next.auth && { auth: { ...config.auth, ...next.auth } }
62
- }),
63
- { getParent: () => instance }
64
- ),
199
+ createChild: (next) => {
200
+ logger.debug("Creating child instance", {
201
+ parentInstanceId: instanceId.slice(0, 8),
202
+ overridingProjectId: !!next.projectId,
203
+ overridingDataset: !!next.dataset,
204
+ overridingAuth: !!next.auth
205
+ });
206
+ const child = Object.assign(
207
+ createSanityInstance({
208
+ ...config,
209
+ ...next,
210
+ ...config.auth === next.auth ? config.auth : config.auth && next.auth && { auth: { ...config.auth, ...next.auth } }
211
+ }),
212
+ { getParent: () => instance }
213
+ );
214
+ return logger.trace("Child instance created", {
215
+ internal: !0,
216
+ childInstanceId: child.instanceId.slice(0, 8)
217
+ }), child;
218
+ },
65
219
  match: (targetConfig) => {
66
220
  if (Object.entries(pick(targetConfig, "auth", "projectId", "dataset")).every(
67
221
  ([key, value]) => config[key] === value
@@ -129,16 +283,33 @@ const bindActionByDataset = createActionBinder((instance, options) => {
129
283
  if (!projectId || !dataset)
130
284
  throw new Error("This API requires a project ID and dataset configured.");
131
285
  return { name: `${projectId}.${dataset}`, projectId, dataset };
132
- }), bindActionBySource = createActionBinder((instance, { source }) => {
286
+ }), createSourceKey = (instance, source) => {
287
+ let name, sourceForKey;
133
288
  if (source) {
134
- const id = source[SOURCE_ID];
135
- if (!id) throw new Error("Invalid source (missing ID information)");
136
- return Array.isArray(id) ? { name: id.join(":") } : { name: `${id.projectId}.${id.dataset}` };
289
+ if (sourceForKey = source, isDatasetSource(source))
290
+ name = `${source.projectId}.${source.dataset}`;
291
+ else if (isMediaLibrarySource(source))
292
+ name = `media-library:${source.mediaLibraryId}`;
293
+ else if (isCanvasSource(source))
294
+ name = `canvas:${source.canvasId}`;
295
+ else
296
+ throw new Error(`Received invalid source: ${JSON.stringify(source)}`);
297
+ return { name, source: sourceForKey };
137
298
  }
138
299
  const { projectId, dataset } = instance.config;
139
300
  if (!projectId || !dataset)
140
301
  throw new Error("This API requires a project ID and dataset configured.");
141
- return { name: `${projectId}.${dataset}` };
302
+ return { name: `${projectId}.${dataset}`, source: { projectId, dataset } };
303
+ }, bindActionBySource = createActionBinder((instance, { source }) => createSourceKey(instance, source)), bindActionBySourceAndPerspective = createActionBinder((instance, options) => {
304
+ const { source, perspective } = options, utilizedPerspective = perspective ?? instance.config.perspective ?? "drafts";
305
+ let perspectiveKey;
306
+ isReleasePerspective(utilizedPerspective) ? perspectiveKey = utilizedPerspective.releaseName : typeof utilizedPerspective == "string" ? perspectiveKey = utilizedPerspective : perspectiveKey = JSON.stringify(utilizedPerspective);
307
+ const sourceKey = createSourceKey(instance, source);
308
+ return {
309
+ name: `${sourceKey.name}:${perspectiveKey}`,
310
+ source: sourceKey.source,
311
+ perspective: utilizedPerspective
312
+ };
142
313
  }), bindActionGlobally = createActionBinder((..._rest) => ({ name: "global" }));
143
314
  function createStateSourceAction(options) {
144
315
  const selector = typeof options == "function" ? options : options.selector, subscribeHandler = options && "onSubscribe" in options ? options.onSubscribe : void 0, isEqual2 = options && "isEqual" in options ? options.isEqual ?? Object.is : Object.is, selectorContextCache = /* @__PURE__ */ new WeakMap();
@@ -187,8 +358,25 @@ function createStateSourceAction(options) {
187
358
  }
188
359
  return stateSourceAction;
189
360
  }
361
+ const DEFAULT_BASE = "http://localhost", AUTH_CODE_PARAM = "sid", DEFAULT_API_VERSION$1 = "2021-06-07", REQUEST_TAG_PREFIX = "sanity.sdk.auth";
362
+ function resolveAuthMode(config, locationHref) {
363
+ return isStudioConfig(config) ? "studio" : detectDashboardContext(locationHref) ? "dashboard" : "standalone";
364
+ }
365
+ function isStudioConfig(config) {
366
+ return !!config.studio || !!config.studioMode?.enabled;
367
+ }
368
+ function detectDashboardContext(locationHref) {
369
+ try {
370
+ const contextParam = new URL(locationHref, DEFAULT_BASE).searchParams.get("_context");
371
+ if (!contextParam) return !1;
372
+ const parsed = JSON.parse(contextParam);
373
+ return typeof parsed == "object" && parsed !== null && !Array.isArray(parsed) && Object.keys(parsed).length > 0;
374
+ } catch (err) {
375
+ return console.error("Failed to parse dashboard context from initial location:", err), !1;
376
+ }
377
+ }
190
378
  var AuthStateType = /* @__PURE__ */ ((AuthStateType2) => (AuthStateType2.LOGGED_IN = "logged-in", AuthStateType2.LOGGING_IN = "logging-in", AuthStateType2.ERROR = "error", AuthStateType2.LOGGED_OUT = "logged-out", AuthStateType2))(AuthStateType || {});
191
- const DEFAULT_BASE = "http://localhost", AUTH_CODE_PARAM = "sid", DEFAULT_API_VERSION$1 = "2021-06-07", REQUEST_TAG_PREFIX = "sanity.sdk.auth", REFRESH_INTERVAL = 720 * 60 * 1e3, LOCK_NAME = "sanity-token-refresh-lock";
379
+ const REFRESH_INTERVAL = 720 * 60 * 1e3, LOCK_NAME = "sanity-token-refresh-lock";
192
380
  function getLastRefreshTime(storageArea, storageKey) {
193
381
  try {
194
382
  const data = storageArea?.getItem(`${storageKey}_last_refresh`), parsed = data ? parseInt(data, 10) : 0;
@@ -351,6 +539,47 @@ const refreshStampedToken = ({ state }) => {
351
539
  state.set("setRefreshStampedTokenError", { authState: { type: AuthStateType.ERROR, error } });
352
540
  }
353
541
  });
542
+ }, subscribeToStateAndFetchCurrentUser = ({ state, instance }, fetchOptions) => {
543
+ const { clientFactory, apiHost } = state.get().options, useProjectHostname = fetchOptions?.useProjectHostname ?? isStudioConfig(instance.config), projectId = instance.config.projectId;
544
+ return state.observable.pipe(
545
+ map(({ authState, options: storeOptions }) => ({
546
+ authState,
547
+ authMethod: storeOptions.authMethod
548
+ })),
549
+ filter(
550
+ (value) => value.authState.type === AuthStateType.LOGGED_IN && !value.authState.currentUser
551
+ ),
552
+ map((value) => ({ token: value.authState.token, authMethod: value.authMethod })),
553
+ distinctUntilChanged(
554
+ (prev, curr) => prev.token === curr.token && prev.authMethod === curr.authMethod
555
+ )
556
+ ).pipe(
557
+ map(
558
+ ({ token, authMethod }) => clientFactory({
559
+ apiVersion: DEFAULT_API_VERSION$1,
560
+ requestTagPrefix: REQUEST_TAG_PREFIX,
561
+ token: authMethod === "cookie" ? void 0 : token,
562
+ ignoreBrowserTokenWarning: !0,
563
+ useProjectHostname,
564
+ useCdn: !1,
565
+ ...authMethod === "cookie" ? { withCredentials: !0 } : {},
566
+ ...useProjectHostname && projectId ? { projectId } : {},
567
+ ...apiHost && { apiHost }
568
+ })
569
+ ),
570
+ switchMap(
571
+ (client) => client.observable.request({ uri: "/users/me", method: "GET" })
572
+ )
573
+ ).subscribe({
574
+ next: (currentUser) => {
575
+ state.set("setCurrentUser", (prev) => ({
576
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, currentUser } : prev.authState
577
+ }));
578
+ },
579
+ error: (error) => {
580
+ state.set("setError", { authState: { type: AuthStateType.ERROR, error } });
581
+ }
582
+ });
354
583
  };
355
584
  function getAuthCode(callbackUrl, locationHref) {
356
585
  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;
@@ -425,66 +654,53 @@ function getClientErrorApiDescription(error) {
425
654
  function isProjectUserNotFoundClientError(error) {
426
655
  return getClientErrorApiType(error) === "projectUserNotFoundError";
427
656
  }
428
- async function checkForCookieAuth(projectId, clientFactory) {
429
- if (!projectId) return !1;
657
+ function parseDashboardContext(locationHref) {
430
658
  try {
431
- return typeof (await clientFactory({
432
- projectId,
433
- useCdn: !1
434
- }).request({
435
- uri: "/users/me",
436
- withCredentials: !0,
437
- tag: "users.get-current"
438
- }))?.id == "string";
439
- } catch {
440
- return !1;
659
+ const contextParam = new URL(locationHref, DEFAULT_BASE).searchParams.get("_context");
660
+ if (contextParam) {
661
+ const parsedContext = JSON.parse(contextParam);
662
+ if (parsedContext && typeof parsedContext == "object" && !Array.isArray(parsedContext) && Object.keys(parsedContext).length > 0)
663
+ return delete parsedContext.sid, parsedContext;
664
+ }
665
+ } catch (err) {
666
+ console.error("Failed to parse dashboard context from initial location:", err);
441
667
  }
668
+ return {};
442
669
  }
443
- function getStudioTokenFromLocalStorage(storageArea, storageKey) {
444
- return !storageArea || !storageKey ? null : getTokenFromStorage(storageArea, storageKey) || null;
670
+ function getDashboardInitialState(options) {
671
+ const { authConfig, initialLocationHref } = options, providedToken = authConfig.token, callbackUrl = authConfig.callbackUrl, storageKey = "__sanity_auth_token", dashboardContext = parseDashboardContext(initialLocationHref), storageArea = void 0;
672
+ return providedToken ? {
673
+ authState: { type: AuthStateType.LOGGED_IN, token: providedToken, currentUser: null },
674
+ storageKey,
675
+ storageArea,
676
+ authMethod: void 0,
677
+ dashboardContext
678
+ } : getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref) ? {
679
+ authState: { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 },
680
+ storageKey,
681
+ storageArea,
682
+ authMethod: void 0,
683
+ dashboardContext
684
+ } : {
685
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 },
686
+ storageKey,
687
+ storageArea,
688
+ authMethod: void 0,
689
+ dashboardContext
690
+ };
445
691
  }
446
- const subscribeToStateAndFetchCurrentUser = ({
447
- state,
448
- instance
449
- }) => {
450
- const { clientFactory, apiHost } = state.get().options, useProjectHostname = !!instance.config.studioMode?.enabled, projectId = instance.config.projectId;
451
- return state.observable.pipe(
452
- map(({ authState, options }) => ({ authState, authMethod: options.authMethod })),
453
- filter(
454
- (value) => value.authState.type === AuthStateType.LOGGED_IN && !value.authState.currentUser
455
- ),
456
- map((value) => ({ token: value.authState.token, authMethod: value.authMethod })),
457
- distinctUntilChanged(
458
- (prev, curr) => prev.token === curr.token && prev.authMethod === curr.authMethod
459
- )
460
- ).pipe(
461
- map(
462
- ({ token, authMethod }) => clientFactory({
463
- apiVersion: DEFAULT_API_VERSION$1,
464
- requestTagPrefix: REQUEST_TAG_PREFIX,
465
- token: authMethod === "cookie" ? void 0 : token,
466
- ignoreBrowserTokenWarning: !0,
467
- useProjectHostname,
468
- useCdn: !1,
469
- ...authMethod === "cookie" ? { withCredentials: !0 } : {},
470
- ...useProjectHostname && projectId ? { projectId } : {},
471
- ...apiHost && { apiHost }
472
- })
473
- ),
474
- switchMap(
475
- (client) => client.observable.request({ uri: "/users/me", method: "GET" })
476
- )
477
- ).subscribe({
478
- next: (currentUser) => {
479
- state.set("setCurrentUser", (prev) => ({
480
- authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, currentUser } : prev.authState
481
- }));
692
+ function initializeDashboardAuth(context, tokenRefresherRunning2) {
693
+ const subscriptions = [];
694
+ let startedRefresher = !1;
695
+ return subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !1 })), tokenRefresherRunning2 || (startedRefresher = !0, subscriptions.push(refreshStampedToken(context))), {
696
+ dispose: () => {
697
+ for (const subscription of subscriptions)
698
+ subscription.unsubscribe();
482
699
  },
483
- error: (error) => {
484
- state.set("setError", { authState: { type: AuthStateType.ERROR, error } });
485
- }
486
- });
487
- }, subscribeToStorageEventsAndSetToken = ({
700
+ tokenRefresherStarted: startedRefresher
701
+ };
702
+ }
703
+ const subscribeToStorageEventsAndSetToken = ({
488
704
  state
489
705
  }) => {
490
706
  const { storageArea, storageKey } = state.get().options;
@@ -500,6 +716,159 @@ const subscribeToStateAndFetchCurrentUser = ({
500
716
  });
501
717
  });
502
718
  };
719
+ function getStandaloneInitialState(options) {
720
+ const { authConfig, initialLocationHref } = options, providedToken = authConfig.token, callbackUrl = authConfig.callbackUrl, storageKey = "__sanity_auth_token", storageArea = authConfig.storageArea ?? getDefaultStorage();
721
+ if (providedToken)
722
+ return {
723
+ authState: { type: AuthStateType.LOGGED_IN, token: providedToken, currentUser: null },
724
+ storageKey,
725
+ storageArea,
726
+ authMethod: void 0,
727
+ dashboardContext: {}
728
+ };
729
+ if (getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref))
730
+ return {
731
+ authState: { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 },
732
+ storageKey,
733
+ storageArea,
734
+ authMethod: void 0,
735
+ dashboardContext: {}
736
+ };
737
+ const token = getTokenFromStorage(storageArea, storageKey);
738
+ return token ? {
739
+ authState: { type: AuthStateType.LOGGED_IN, token, currentUser: null },
740
+ storageKey,
741
+ storageArea,
742
+ authMethod: "localstorage",
743
+ dashboardContext: {}
744
+ } : {
745
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 },
746
+ storageKey,
747
+ storageArea,
748
+ authMethod: void 0,
749
+ dashboardContext: {}
750
+ };
751
+ }
752
+ function initializeStandaloneAuth(context, tokenRefresherRunning2) {
753
+ const subscriptions = [];
754
+ let startedRefresher = !1;
755
+ return subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !1 })), context.state.get().options?.storageArea && subscriptions.push(subscribeToStorageEventsAndSetToken(context)), tokenRefresherRunning2 || (startedRefresher = !0, subscriptions.push(refreshStampedToken(context))), {
756
+ dispose: () => {
757
+ for (const subscription of subscriptions)
758
+ subscription.unsubscribe();
759
+ },
760
+ tokenRefresherStarted: startedRefresher
761
+ };
762
+ }
763
+ const COOKIE_AUTH_TIMEOUT_MS = 1e4;
764
+ async function checkForCookieAuth(projectId, clientFactory) {
765
+ if (!projectId) return !1;
766
+ try {
767
+ const user = await clientFactory({
768
+ projectId,
769
+ useCdn: !1,
770
+ requestTagPrefix: "sdk",
771
+ timeout: COOKIE_AUTH_TIMEOUT_MS
772
+ }).request({
773
+ uri: "/users/me",
774
+ withCredentials: !0,
775
+ tag: "users.get-current"
776
+ });
777
+ return user != null && typeof user == "object" && typeof user.id == "string";
778
+ } catch {
779
+ return !1;
780
+ }
781
+ }
782
+ function getStudioTokenFromLocalStorage(storageArea, storageKey) {
783
+ return !storageArea || !storageKey ? null : getTokenFromStorage(storageArea, storageKey) || null;
784
+ }
785
+ function getStudioInitialState(options) {
786
+ const { authConfig, projectId, tokenSource } = options, storageArea = authConfig.storageArea ?? getDefaultStorage(), studioStorageKey = `__studio_auth_token_${projectId ?? ""}`;
787
+ if (tokenSource)
788
+ return {
789
+ authState: { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 },
790
+ storageKey: studioStorageKey,
791
+ storageArea,
792
+ authMethod: void 0,
793
+ dashboardContext: {}
794
+ };
795
+ const providedToken = authConfig.token;
796
+ let authMethod;
797
+ const token = getStudioTokenFromLocalStorage(storageArea, studioStorageKey);
798
+ return token && (authMethod = "localstorage"), providedToken ? {
799
+ authState: { type: AuthStateType.LOGGED_IN, token: providedToken, currentUser: null },
800
+ storageKey: studioStorageKey,
801
+ storageArea,
802
+ authMethod,
803
+ dashboardContext: {}
804
+ } : token ? {
805
+ authState: { type: AuthStateType.LOGGED_IN, token, currentUser: null },
806
+ storageKey: studioStorageKey,
807
+ storageArea,
808
+ authMethod: "localstorage",
809
+ dashboardContext: {}
810
+ } : {
811
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 },
812
+ storageKey: studioStorageKey,
813
+ storageArea,
814
+ authMethod: void 0,
815
+ dashboardContext: {}
816
+ };
817
+ }
818
+ function initializeStudioAuth(context, tokenRefresherRunning2) {
819
+ const tokenSource = context.instance.config.studio?.auth?.token;
820
+ return tokenSource ? initializeWithTokenSource(context, tokenSource) : initializeWithFallback(context, tokenRefresherRunning2);
821
+ }
822
+ function initializeWithTokenSource(context, tokenSource) {
823
+ const subscriptions = [];
824
+ subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !0 }));
825
+ const tokenSub = tokenSource.subscribe({
826
+ next: (token) => {
827
+ const { state } = context;
828
+ token ? state.set("studioTokenSource", (prev) => ({
829
+ options: { ...prev.options, authMethod: void 0 },
830
+ authState: { type: AuthStateType.LOGGED_IN, token, currentUser: null }
831
+ })) : state.set("studioTokenSourceLoggedOut", (prev) => ({
832
+ options: { ...prev.options, authMethod: void 0 },
833
+ authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
834
+ }));
835
+ }
836
+ });
837
+ return {
838
+ dispose: () => {
839
+ tokenSub.unsubscribe();
840
+ for (const subscription of subscriptions)
841
+ subscription.unsubscribe();
842
+ },
843
+ // Studio handles token refresh — do not start the SDK's refresher
844
+ tokenRefresherStarted: !1
845
+ };
846
+ }
847
+ function initializeWithFallback(context, tokenRefresherRunning2) {
848
+ const subscriptions = [];
849
+ let startedRefresher = !1;
850
+ subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !0 })), context.state.get().options?.storageArea && subscriptions.push(subscribeToStorageEventsAndSetToken(context));
851
+ try {
852
+ const { instance, state } = context;
853
+ if (!(state.get().authState?.type === AuthStateType.LOGGED_IN && state.get().authState.token)) {
854
+ const projectIdValue = instance.config.projectId, clientFactory = state.get().options.clientFactory;
855
+ checkForCookieAuth(projectIdValue, clientFactory).then((isCookieAuthEnabled) => {
856
+ isCookieAuthEnabled && state.set("enableCookieAuth", (prev) => ({
857
+ options: { ...prev.options, authMethod: "cookie" },
858
+ authState: prev.authState.type === AuthStateType.LOGGED_IN ? prev.authState : { type: AuthStateType.LOGGED_IN, token: "", currentUser: null }
859
+ }));
860
+ });
861
+ }
862
+ } catch {
863
+ }
864
+ return tokenRefresherRunning2 || (startedRefresher = !0, subscriptions.push(refreshStampedToken(context))), {
865
+ dispose: () => {
866
+ for (const subscription of subscriptions)
867
+ subscription.unsubscribe();
868
+ },
869
+ tokenRefresherStarted: startedRefresher
870
+ };
871
+ }
503
872
  let tokenRefresherRunning = !1;
504
873
  const authStore = {
505
874
  name: "Auth",
@@ -511,9 +880,7 @@ const authStore = {
511
880
  token: providedToken,
512
881
  clientFactory = createClient,
513
882
  initialLocationHref = getDefaultLocation()
514
- } = instance.config.auth ?? {};
515
- let storageArea = instance.config.auth?.storageArea, storageKey = "__sanity_auth_token";
516
- const studioModeEnabled = instance.config.studioMode?.enabled;
883
+ } = instance.config.auth ?? {}, authConfig = instance.config.auth ?? {};
517
884
  let loginDomain = "https://www.sanity.io";
518
885
  try {
519
886
  apiHost && new URL(apiHost).hostname.endsWith(".sanity.work") && (loginDomain = "https://www.sanity.work");
@@ -521,27 +888,27 @@ const authStore = {
521
888
  }
522
889
  const loginUrl = new URL("/login", loginDomain);
523
890
  loginUrl.searchParams.set("origin", getCleanedUrl(initialLocationHref)), loginUrl.searchParams.set("type", "stampedToken"), loginUrl.searchParams.set("withSid", "true");
524
- let dashboardContext = {}, isInDashboard = !1;
525
- try {
526
- const contextParam = new URL(initialLocationHref).searchParams.get("_context");
527
- if (contextParam) {
528
- const parsedContext = JSON.parse(contextParam);
529
- parsedContext && typeof parsedContext == "object" && Object.keys(parsedContext).length > 0 && (delete parsedContext.sid, dashboardContext = parsedContext, isInDashboard = !0);
530
- }
531
- } catch (err) {
532
- console.error("Failed to parse dashboard context from initial location:", err);
891
+ const mode = resolveAuthMode(instance.config, initialLocationHref), strategyOptions = {
892
+ authConfig,
893
+ projectId: instance.config.projectId,
894
+ initialLocationHref,
895
+ tokenSource: instance.config.studio?.auth?.token
896
+ };
897
+ let result;
898
+ switch (mode) {
899
+ case "studio":
900
+ result = getStudioInitialState(strategyOptions);
901
+ break;
902
+ case "dashboard":
903
+ result = getDashboardInitialState(strategyOptions);
904
+ break;
905
+ case "standalone":
906
+ result = getStandaloneInitialState(strategyOptions);
907
+ break;
533
908
  }
534
- (!isInDashboard || studioModeEnabled) && (storageArea = storageArea ?? getDefaultStorage());
535
- let token, authMethod;
536
- if (studioModeEnabled) {
537
- const studioStorageKey = `__studio_auth_token_${instance.config.projectId ?? ""}`;
538
- storageKey = studioStorageKey, token = getStudioTokenFromLocalStorage(storageArea, studioStorageKey), token && (authMethod = "localstorage");
539
- } else
540
- token = getTokenFromStorage(storageArea, storageKey), token && (authMethod = "localstorage");
541
- let authState;
542
- return providedToken ? authState = { type: AuthStateType.LOGGED_IN, token: providedToken, currentUser: null } : token && studioModeEnabled ? authState = { type: AuthStateType.LOGGED_IN, token: token ?? "", currentUser: null } : getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref) ? authState = { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 } : token && !isInDashboard && !studioModeEnabled ? authState = { type: AuthStateType.LOGGED_IN, token, currentUser: null } : authState = { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }, {
543
- authState,
544
- dashboardContext,
909
+ return {
910
+ authState: result.authState,
911
+ dashboardContext: result.dashboardContext,
545
912
  options: {
546
913
  apiHost,
547
914
  loginUrl: loginUrl.toString(),
@@ -550,32 +917,27 @@ const authStore = {
550
917
  providedToken,
551
918
  clientFactory,
552
919
  initialLocationHref,
553
- storageKey,
554
- storageArea,
555
- authMethod
920
+ storageKey: result.storageKey,
921
+ storageArea: result.storageArea,
922
+ authMethod: result.authMethod
556
923
  }
557
924
  };
558
925
  },
559
926
  initialize(context) {
560
- const subscriptions = [];
561
- subscriptions.push(subscribeToStateAndFetchCurrentUser(context)), context.state.get().options?.storageArea && subscriptions.push(subscribeToStorageEventsAndSetToken(context));
562
- try {
563
- const { instance, state } = context, studioModeEnabled = !!instance.config.studioMode?.enabled, token = state.get().authState?.type === AuthStateType.LOGGED_IN ? state.get().authState.token : null;
564
- if (studioModeEnabled && !token) {
565
- const projectId = instance.config.projectId, clientFactory = state.get().options.clientFactory;
566
- checkForCookieAuth(projectId, clientFactory).then((isCookieAuthEnabled) => {
567
- isCookieAuthEnabled && state.set("enableCookieAuth", (prev) => ({
568
- options: { ...prev.options, authMethod: "cookie" },
569
- authState: prev.authState.type === AuthStateType.LOGGED_IN ? prev.authState : { type: AuthStateType.LOGGED_IN, token: "", currentUser: null }
570
- }));
571
- });
572
- }
573
- } catch {
927
+ const initialLocationHref = context.state.get().options?.initialLocationHref ?? getDefaultLocation(), mode = resolveAuthMode(context.instance.config, initialLocationHref);
928
+ let initResult;
929
+ switch (mode) {
930
+ case "studio":
931
+ initResult = initializeStudioAuth(context, tokenRefresherRunning);
932
+ break;
933
+ case "dashboard":
934
+ initResult = initializeDashboardAuth(context, tokenRefresherRunning);
935
+ break;
936
+ case "standalone":
937
+ initResult = initializeStandaloneAuth(context, tokenRefresherRunning);
938
+ break;
574
939
  }
575
- return tokenRefresherRunning || (tokenRefresherRunning = !0, subscriptions.push(refreshStampedToken(context))), () => {
576
- for (const subscription of subscriptions)
577
- subscription.unsubscribe();
578
- };
940
+ return initResult.tokenRefresherStarted && (tokenRefresherRunning = !0), initResult.dispose;
579
941
  }
580
942
  }, getCurrentUserState = bindActionGlobally(
581
943
  authStore,
@@ -673,12 +1035,12 @@ const authStore = {
673
1035
  `The client options provided contains unsupported properties: ${listFormatter.format(disallowedKeys)}. Allowed keys are: ${listFormatter.format(allowedKeys)}.`
674
1036
  );
675
1037
  }
676
- const tokenFromState = state.get().token, { clients, authMethod } = state.get(), hasSource = !!options.source;
677
- let sourceId = options.source?.[SOURCE_ID], resource;
678
- Array.isArray(sourceId) && (resource = { type: sourceId[0], id: sourceId[1] }, sourceId = void 0);
1038
+ const tokenFromState = state.get().token, { clients, authMethod } = state.get();
1039
+ let resource;
1040
+ options.source && (isDatasetSource(options.source) ? resource = { type: "dataset", id: `${options.source.projectId}.${options.source.dataset}` } : isMediaLibrarySource(options.source) ? resource = { type: "media-library", id: options.source.mediaLibraryId } : isCanvasSource(options.source) && (resource = { type: "canvas", id: options.source.canvasId }));
679
1041
  const projectId = options.projectId ?? instance.config.projectId, dataset = options.dataset ?? instance.config.dataset, apiHost = options.apiHost ?? instance.config.auth?.apiHost, effectiveOptions = {
680
1042
  ...DEFAULT_CLIENT_CONFIG,
681
- ...(options.scope === "global" || !projectId || hasSource) && { useProjectHostname: !1 },
1043
+ ...(options.scope === "global" || !projectId || resource) && { useProjectHostname: !1 },
682
1044
  token: authMethod === "cookie" ? void 0 : tokenFromState ?? void 0,
683
1045
  ...options,
684
1046
  ...projectId && { projectId },
@@ -686,7 +1048,7 @@ const authStore = {
686
1048
  ...apiHost && { apiHost },
687
1049
  ...resource && { "~experimental_resource": resource }
688
1050
  };
689
- hasSource && ((options.projectId || options.dataset) && console.warn(
1051
+ resource && ((options.projectId || options.dataset) && console.warn(
690
1052
  "Both source and explicit projectId/dataset are provided. The source will be used and projectId/dataset will be ignored."
691
1053
  ), delete effectiveOptions.projectId, delete effectiveOptions.dataset), effectiveOptions.token === null || typeof effectiveOptions.token > "u" ? (delete effectiveOptions.token, authMethod === "cookie" && (effectiveOptions.withCredentials = !0)) : delete effectiveOptions.withCredentials;
692
1054
  const key = getClientConfigKey(effectiveOptions);
@@ -1144,6 +1506,21 @@ function createProjectHandle(handle) {
1144
1506
  function createDatasetHandle(handle) {
1145
1507
  return handle;
1146
1508
  }
1509
+ function configureLogging(config) {
1510
+ configureLogging$1(config);
1511
+ const configLevel = config.level || "warn", shouldLog = ["info", "debug", "trace"].includes(configLevel) || configLevel === "warn";
1512
+ shouldLog && config.handler?.info ? config.handler.info(`[${(/* @__PURE__ */ new Date()).toISOString()}] [INFO] [sdk] Logging configured`, {
1513
+ level: configLevel,
1514
+ namespaces: config.namespaces || [],
1515
+ internal: config.internal || !1,
1516
+ source: "programmatic"
1517
+ }) : shouldLog && console.info(`[${(/* @__PURE__ */ new Date()).toISOString()}] [INFO] [sdk] Logging configured`, {
1518
+ level: configLevel,
1519
+ namespaces: config.namespaces || [],
1520
+ internal: config.internal || !1,
1521
+ source: "programmatic"
1522
+ });
1523
+ }
1147
1524
  const API_VERSION$4 = "v2025-02-19", datasets = createFetcherStore({
1148
1525
  name: "Datasets",
1149
1526
  getKey: (instance, options) => {
@@ -1621,7 +1998,7 @@ function sortListenerEvents(options) {
1621
1998
  mergeMap((state) => of(...state.emitEvents))
1622
1999
  );
1623
2000
  }
1624
- const listen$1 = ({ state }, documentId) => {
2001
+ const listen = ({ state }, documentId) => {
1625
2002
  const { sharedListener, fetchDocument } = state.get();
1626
2003
  return sharedListener.events.pipe(
1627
2004
  concatMap((e) => e.type === "welcome" ? fetchDocument(documentId).pipe(
@@ -2775,9 +3152,9 @@ const _resolveDocument = bindActionByDataset(
2775
3152
  groupBy$1((i) => i.id),
2776
3153
  mergeMap$1(
2777
3154
  (group) => group.pipe(
2778
- switchMap((e) => e.add ? listen$1(context, e.id).pipe(
3155
+ switchMap((e) => e.add ? listen(context, e.id).pipe(
2779
3156
  catchError$1((error) => {
2780
- throw error instanceof OutOfSyncError && listen$1(context, e.id), error;
3157
+ throw error instanceof OutOfSyncError && listen(context, e.id), error;
2781
3158
  }),
2782
3159
  tap$1(
2783
3160
  (remote) => state.set(
@@ -3258,40 +3635,7 @@ const handleIncomingMessage = (event) => {
3258
3635
  return () => subscription.unsubscribe();
3259
3636
  }
3260
3637
  })
3261
- ), fetch = (client, query, params, options) => defer(
3262
- () => client.observable.fetch(query, params, {
3263
- tag: options.tag,
3264
- filterResponse: !0
3265
- })
3266
- ), listen = (client, query, params, options) => defer(
3267
- () => client.listen(query, params, {
3268
- events: ["welcome", "mutation", "reconnect"],
3269
- includeResult: !1,
3270
- visibility: "query",
3271
- tag: options.tag
3272
- })
3273
3638
  );
3274
- function isWelcomeEvent(event) {
3275
- return event.type === "welcome";
3276
- }
3277
- const listenQuery = (client, query, params = {}, options = {}) => {
3278
- const fetchQuery = query, listenerQuery = query, fetchOnce$ = fetch(client, fetchQuery, params, options), events$ = listen(client, listenerQuery, params, options).pipe(
3279
- mergeMap((ev, i) => i === 0 && !isWelcomeEvent(ev) ? throwError(
3280
- () => new Error(
3281
- ev.type === "reconnect" ? "Could not establish EventSource connection" : `Received unexpected type of first event "${ev.type}"`
3282
- )
3283
- ) : of(ev)),
3284
- share$1()
3285
- ), [welcome$, mutationAndReconnect$] = partition(events$, isWelcomeEvent), isRelevantEvent = (event) => !options.transitions || event.type !== "mutation" ? !0 : options.transitions.includes(event.transition);
3286
- return merge(
3287
- welcome$.pipe(take(1)),
3288
- mutationAndReconnect$.pipe(filter$1(isRelevantEvent), debounceTime(options.throttleTime || 1e3))
3289
- ).pipe(
3290
- // will cancel any in-flight request when a new one comes in
3291
- // but ensures we always get the latest data
3292
- switchMap(() => fetchOnce$)
3293
- );
3294
- };
3295
3639
  function sortReleases(releases = []) {
3296
3640
  return [...releases].sort((a, b) => {
3297
3641
  if (a.metadata.releaseType === "undecided" && b.metadata.releaseType !== "undecided")
@@ -3310,7 +3654,7 @@ function sortReleases(releases = []) {
3310
3654
  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;
3311
3655
  });
3312
3656
  }
3313
- const ARCHIVED_RELEASE_STATES = ["archived", "published"], releasesStore = {
3657
+ const ARCHIVED_RELEASE_STATES = ["archived", "published"], STABLE_EMPTY_RELEASES = [], releasesStore = {
3314
3658
  name: "Releases",
3315
3659
  getInitialState: () => ({
3316
3660
  activeReleases: void 0
@@ -3324,43 +3668,26 @@ const ARCHIVED_RELEASE_STATES = ["archived", "published"], releasesStore = {
3324
3668
  createStateSourceAction({
3325
3669
  selector: ({ state }, _) => state.activeReleases
3326
3670
  })
3327
- ), RELEASES_QUERY = "releases::all()", QUERY_PARAMS = {}, subscribeToReleases = ({
3671
+ ), RELEASES_QUERY = "releases::all()", subscribeToReleases = ({
3328
3672
  instance,
3329
3673
  state,
3330
3674
  key: { projectId, dataset }
3331
- }) => getClientState(instance, {
3332
- apiVersion: "2025-04-10",
3333
- perspective: "raw",
3334
- projectId,
3335
- dataset
3336
- }).observable.pipe(
3337
- switchMap(
3338
- (client) => (
3339
- // releases are system documents, and are not supported by useQueryState
3340
- listenQuery(client, RELEASES_QUERY, QUERY_PARAMS, {
3341
- tag: "releases-listener",
3342
- throttleTime: 1e3,
3343
- transitions: ["update", "appear", "disappear"]
3344
- }).pipe(
3345
- retry({
3346
- count: 3,
3347
- delay: (error, retryCount) => (console.error("[releases] Error in subscription:", error, "Retry count:", retryCount), timer(Math.min(1e3 * Math.pow(2, retryCount), 1e4)))
3348
- }),
3349
- catchError$1((error) => (state.set("setError", { error }), EMPTY))
3350
- )
3351
- )
3352
- )
3353
- ).subscribe({
3354
- next: (releases) => {
3355
- state.set("setActiveReleases", {
3356
- activeReleases: sortReleases(releases ?? []).filter((release) => !ARCHIVED_RELEASE_STATES.includes(release.state)).reverse()
3357
- });
3358
- }
3359
- });
3360
- function isReleasePerspective(perspective) {
3361
- return typeof perspective == "object" && perspective !== null && "releaseName" in perspective;
3362
- }
3363
- const DEFAULT_PERSPECTIVE = "drafts", optionsCache = /* @__PURE__ */ new Map(), selectInstancePerspective = (context, _) => context.instance.config.perspective, selectActiveReleases = (context) => context.state.activeReleases, selectOptions = (_context, options) => options, memoizedOptionsSelector = createSelector(
3675
+ }) => {
3676
+ const { observable: releases$ } = getQueryState(instance, {
3677
+ query: RELEASES_QUERY,
3678
+ perspective: "raw",
3679
+ projectId,
3680
+ dataset,
3681
+ tag: "releases"
3682
+ });
3683
+ return releases$.pipe(
3684
+ map((releases) => {
3685
+ state.set("setActiveReleases", {
3686
+ activeReleases: sortReleases(releases ?? STABLE_EMPTY_RELEASES).filter((release) => !ARCHIVED_RELEASE_STATES.includes(release.state)).reverse()
3687
+ });
3688
+ })
3689
+ ).subscribe({ error: (error) => state.set("setError", { error }) });
3690
+ }, DEFAULT_PERSPECTIVE = "drafts", optionsCache = /* @__PURE__ */ new Map(), selectInstancePerspective = (context, _) => context.instance.config.perspective, selectActiveReleases = (context) => context.state.activeReleases, selectOptions = (_context, options) => options, memoizedOptionsSelector = createSelector(
3364
3691
  [selectActiveReleases, selectOptions],
3365
3692
  (activeReleases, options) => {
3366
3693
  if (!options || !activeReleases) return options;
@@ -3371,25 +3698,25 @@ const DEFAULT_PERSPECTIVE = "drafts", optionsCache = /* @__PURE__ */ new Map(),
3371
3698
  let cachedOptions = nestedCache.get(optionsKey);
3372
3699
  return cachedOptions || (cachedOptions = options, nestedCache.set(optionsKey, cachedOptions)), cachedOptions;
3373
3700
  }
3374
- ), getPerspectiveState = bindActionByDataset(
3701
+ ), _getPerspectiveStateSelector = createStateSourceAction({
3702
+ selector: createSelector(
3703
+ [selectInstancePerspective, selectActiveReleases, memoizedOptionsSelector],
3704
+ (instancePerspective, activeReleases, memoizedOptions) => {
3705
+ const perspective = memoizedOptions?.perspective ?? instancePerspective ?? DEFAULT_PERSPECTIVE;
3706
+ if (!isReleasePerspective(perspective)) return perspective;
3707
+ if (!activeReleases || activeReleases.length === 0) return;
3708
+ const releaseNames = sortReleases(activeReleases).map((release) => release.name), index = releaseNames.findIndex((name) => name === perspective.releaseName);
3709
+ if (index < 0)
3710
+ throw new Error(`Release "${perspective.releaseName}" not found in active releases`);
3711
+ return ["drafts", ...releaseNames.slice(0, index + 1)].filter((name) => !perspective.excludedPerspectives?.includes(name)).reverse();
3712
+ }
3713
+ )
3714
+ });
3715
+ let _boundGetPerspectiveState;
3716
+ const getPerspectiveState = (...args) => (_boundGetPerspectiveState || (_boundGetPerspectiveState = bindActionByDataset(
3375
3717
  releasesStore,
3376
- createStateSourceAction({
3377
- selector: createSelector(
3378
- [selectInstancePerspective, selectActiveReleases, memoizedOptionsSelector],
3379
- (instancePerspective, activeReleases, memoizedOptions) => {
3380
- const perspective = memoizedOptions?.perspective ?? instancePerspective ?? DEFAULT_PERSPECTIVE;
3381
- if (!isReleasePerspective(perspective)) return perspective;
3382
- if (!activeReleases || activeReleases.length === 0) return;
3383
- const releaseNames = sortReleases(activeReleases).map((release) => release.name), index = releaseNames.findIndex((name) => name === perspective.releaseName);
3384
- if (index < 0)
3385
- throw new Error(`Release "${perspective.releaseName}" not found in active releases`);
3386
- return ["drafts", ...releaseNames.slice(0, index + 1)].filter(
3387
- (name) => !perspective.excludedPerspectives?.includes(name)
3388
- );
3389
- }
3390
- )
3391
- })
3392
- ), QUERY_STATE_CLEAR_DELAY = 1e3, QUERY_STORE_API_VERSION = "v2025-05-06", QUERY_STORE_DEFAULT_PERSPECTIVE = "drafts", setQueryError = (key, error) => (prev) => {
3718
+ _getPerspectiveStateSelector
3719
+ )), _boundGetPerspectiveState(...args)), QUERY_STATE_CLEAR_DELAY = 1e3, QUERY_STORE_API_VERSION = "v2025-05-06", QUERY_STORE_DEFAULT_PERSPECTIVE = "drafts", setQueryError = (key, error) => (prev) => {
3393
3720
  const prevQuery = prev.queries[key];
3394
3721
  return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, error } } } : prev;
3395
3722
  }, setQueryData = (key, result, syncTags) => (prev) => {
@@ -3463,17 +3790,21 @@ const queryStore = {
3463
3790
  source,
3464
3791
  perspective: perspectiveFromOptions,
3465
3792
  ...restOptions
3466
- } = parseQueryKey(group$.key), perspective$ = getPerspectiveState(instance, {
3793
+ } = parseQueryKey(group$.key), perspective$ = isReleasePerspective(perspectiveFromOptions) ? getPerspectiveState(instance, {
3467
3794
  perspective: perspectiveFromOptions
3468
- }).observable.pipe(filter(Boolean)), client$ = getClientState(instance, {
3795
+ }).observable.pipe(filter(Boolean)) : of(perspectiveFromOptions ?? QUERY_STORE_DEFAULT_PERSPECTIVE), client$ = getClientState(instance, {
3469
3796
  apiVersion: QUERY_STORE_API_VERSION,
3470
3797
  projectId,
3471
3798
  dataset,
3472
3799
  source
3473
3800
  }).observable;
3474
- return combineLatest([lastLiveEventId$, client$, perspective$]).pipe(
3801
+ return combineLatest({
3802
+ lastLiveEventId: lastLiveEventId$,
3803
+ client: client$,
3804
+ perspective: perspective$
3805
+ }).pipe(
3475
3806
  switchMap(
3476
- ([lastLiveEventId, client, perspective]) => client.observable.fetch(query, params, {
3807
+ ({ lastLiveEventId, client, perspective }) => client.observable.fetch(query, params, {
3477
3808
  ...restOptions,
3478
3809
  perspective,
3479
3810
  filterResponse: !1,
@@ -3492,10 +3823,13 @@ const queryStore = {
3492
3823
  )
3493
3824
  ).subscribe({ error: errorHandler(state) }), listenToLiveClientAndSetLastLiveEventIds = ({
3494
3825
  state,
3495
- instance
3826
+ instance,
3827
+ key: { source }
3496
3828
  }) => {
3497
3829
  const liveMessages$ = getClientState(instance, {
3498
- apiVersion: QUERY_STORE_API_VERSION
3830
+ apiVersion: QUERY_STORE_API_VERSION,
3831
+ // temporary guard here until we're ready for everything to be queried via global api
3832
+ ...source && !isDatasetSource(source) ? { source } : {}
3499
3833
  }).observable.pipe(
3500
3834
  switchMap(
3501
3835
  (client) => defer(
@@ -3685,7 +4019,7 @@ const BATCH_DEBOUNCE_TIME$1 = 50, isSetEqual$1 = (a, b) => a.size === b.size &&
3685
4019
  }) => state.observable.pipe(
3686
4020
  map(({ subscriptions }) => new Set(Object.keys(subscriptions))),
3687
4021
  distinctUntilChanged(isSetEqual$1),
3688
- debounceTime$1(BATCH_DEBOUNCE_TIME$1),
4022
+ debounceTime(BATCH_DEBOUNCE_TIME$1),
3689
4023
  startWith$1(/* @__PURE__ */ new Set()),
3690
4024
  pairwise$1(),
3691
4025
  tap$1(([prevIds, currIds]) => {
@@ -3784,7 +4118,7 @@ const _getPreviewState = bindActionByDataset(
3784
4118
  ), resolvePreview = bindActionByDataset(
3785
4119
  previewStore,
3786
4120
  ({ instance }, docHandle) => firstValueFrom(getPreviewState(instance, docHandle).observable.pipe(filter((i) => !!i.data)))
3787
- ), PROJECTION_TAG = "projection", PROJECTION_PERSPECTIVE = "raw", PROJECTION_STATE_CLEAR_DELAY = 1e3, STABLE_EMPTY_PROJECTION = {
4121
+ ), PROJECTION_TAG = "projection", PROJECTION_STATE_CLEAR_DELAY = 1e3, STABLE_EMPTY_PROJECTION = {
3788
4122
  data: null,
3789
4123
  isPending: !1
3790
4124
  };
@@ -3808,20 +4142,21 @@ function createProjectionQuery(documentIds, documentProjections) {
3808
4142
  return obj.documentIds.add(documentId), acc[projectionHash] = obj, acc;
3809
4143
  }, {}), query = `[${Object.entries(projections).map(([projectionHash, { projection }]) => `...*[_id in $__ids_${projectionHash}]{_id,_type,_updatedAt,"__projectionHash":"${projectionHash}","result":{...${projection}}}`).join(",")}]`, params = Object.fromEntries(
3810
4144
  Object.entries(projections).map(([projectionHash, value]) => {
3811
- const idsInProjection = Array.from(value.documentIds).flatMap((id) => [
3812
- getPublishedId(id),
3813
- getDraftId(id)
3814
- ]);
4145
+ const idsInProjection = Array.from(value.documentIds).flatMap((id) => DocumentId(id));
3815
4146
  return [`__ids_${projectionHash}`, Array.from(idsInProjection)];
3816
4147
  })
3817
4148
  );
3818
4149
  return { query, params };
3819
4150
  }
3820
- function processProjectionQuery({ ids, results }) {
4151
+ function processProjectionQuery({
4152
+ ids,
4153
+ results,
4154
+ documentStatuses
4155
+ }) {
3821
4156
  const groupedResults = {};
3822
4157
  for (const result of results) {
3823
- const originalId = getPublishedId(result._id), hash = result.__projectionHash, isDraft = result._id.startsWith("drafts.");
3824
- ids.has(originalId) && (groupedResults[originalId] || (groupedResults[originalId] = {}), groupedResults[originalId][hash] || (groupedResults[originalId][hash] = {}), isDraft ? groupedResults[originalId][hash].draft = result : groupedResults[originalId][hash].published = result);
4158
+ const originalId = getPublishedId(result._id), hash = result.__projectionHash;
4159
+ ids.has(originalId) && (groupedResults[originalId] || (groupedResults[originalId] = {}), groupedResults[originalId][hash] || (groupedResults[originalId][hash] = void 0), groupedResults[originalId][hash] = result);
3825
4160
  }
3826
4161
  const finalValues = {};
3827
4162
  for (const originalId of ids) {
@@ -3829,27 +4164,40 @@ function processProjectionQuery({ ids, results }) {
3829
4164
  const projectionsForDoc = groupedResults[originalId];
3830
4165
  if (projectionsForDoc)
3831
4166
  for (const hash in projectionsForDoc) {
3832
- const { draft, published } = projectionsForDoc[hash], projectionResultData = draft?.result ?? published?.result;
4167
+ const projectionResultData = projectionsForDoc[hash]?.result;
3833
4168
  if (!projectionResultData) {
3834
4169
  finalValues[originalId][hash] = { data: null, isPending: !1 };
3835
4170
  continue;
3836
4171
  }
3837
- const _status = {
3838
- ...draft?._updatedAt && { lastEditedDraftAt: draft._updatedAt },
3839
- ...published?._updatedAt && { lastEditedPublishedAt: published._updatedAt }
3840
- };
4172
+ const statusFromStore = documentStatuses?.[originalId];
3841
4173
  finalValues[originalId][hash] = {
3842
- data: { ...projectionResultData, _status },
4174
+ data: { ...projectionResultData, _status: statusFromStore },
3843
4175
  isPending: !1
3844
4176
  };
3845
4177
  }
3846
4178
  }
3847
4179
  return finalValues;
3848
4180
  }
4181
+ function buildStatusQueryIds(documentIds, perspective) {
4182
+ const ids = [], releaseName = isReleasePerspective(perspective) ? perspective.releaseName : null;
4183
+ for (const id of documentIds) {
4184
+ const publishedId = getPublishedId$2(DocumentId(id)), draftId = getDraftId$1(publishedId);
4185
+ ids.push(draftId, publishedId), releaseName && ids.push(getVersionId(publishedId, releaseName));
4186
+ }
4187
+ return ids;
4188
+ }
4189
+ function processStatusQueryResults(results) {
4190
+ const documentStatuses = {};
4191
+ for (const result of results) {
4192
+ const id = DocumentId(result._id), updatedAt = result._updatedAt, publishedId = getPublishedId$2(id), statusData = documentStatuses[publishedId] ?? {};
4193
+ isDraftId(id) ? statusData.lastEditedDraftAt = updatedAt : isVersionId(id) ? statusData.lastEditedVersionAt = updatedAt : isPublishedId(id) && (statusData.lastEditedPublishedAt = updatedAt), documentStatuses[publishedId] = statusData;
4194
+ }
4195
+ return documentStatuses;
4196
+ }
3849
4197
  const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Array.from(a).every((i) => b.has(i)), subscribeToStateAndFetchBatches = ({
3850
4198
  state,
3851
4199
  instance,
3852
- key: { projectId, dataset }
4200
+ key: { source, perspective }
3853
4201
  }) => {
3854
4202
  const documentProjections$ = state.observable.pipe(
3855
4203
  map((s) => s.documentProjections),
@@ -3858,7 +4206,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
3858
4206
  map(({ subscriptions }) => new Set(Object.keys(subscriptions))),
3859
4207
  distinctUntilChanged(isSetEqual)
3860
4208
  ), pendingUpdateSubscription = activeDocumentIds$.pipe(
3861
- debounceTime$1(BATCH_DEBOUNCE_TIME),
4209
+ debounceTime(BATCH_DEBOUNCE_TIME),
3862
4210
  startWith$1(/* @__PURE__ */ new Set()),
3863
4211
  pairwise$1(),
3864
4212
  tap$1(([prevIds, currIds]) => {
@@ -3882,42 +4230,82 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
3882
4230
  });
3883
4231
  })
3884
4232
  ).subscribe(), queryExecutionSubscription = combineLatest([activeDocumentIds$, documentProjections$]).pipe(
3885
- debounceTime$1(BATCH_DEBOUNCE_TIME),
4233
+ debounceTime(BATCH_DEBOUNCE_TIME),
3886
4234
  distinctUntilChanged(isEqual)
3887
4235
  ).pipe(
3888
4236
  switchMap(([ids, documentProjections]) => {
3889
4237
  if (!ids.size) return EMPTY;
3890
- const { query, params } = createProjectionQuery(ids, documentProjections), controller = new AbortController();
3891
- return new Observable((observer) => {
4238
+ const { query, params } = createProjectionQuery(ids, documentProjections), controller = new AbortController(), statusQueryIds = buildStatusQueryIds(ids, perspective), statusQuery = "*[_id in $statusIds]{_id, _updatedAt}", statusParams = { statusIds: statusQueryIds }, projectionQuery$ = new Observable((observer) => {
3892
4239
  const { getCurrent, observable } = getQueryState(instance, {
3893
4240
  query,
3894
4241
  params,
3895
- projectId,
3896
- dataset,
3897
4242
  tag: PROJECTION_TAG,
3898
- perspective: PROJECTION_PERSPECTIVE
4243
+ perspective,
4244
+ // temporary guard here until we're ready for everything to be queried via global API
4245
+ ...source && !isDatasetSource(source) ? { source } : {}
3899
4246
  }), subscription = defer(() => getCurrent() === void 0 ? from(
3900
4247
  resolveQuery(instance, {
3901
4248
  query,
3902
4249
  params,
3903
- projectId,
3904
- dataset,
3905
4250
  tag: PROJECTION_TAG,
3906
- perspective: PROJECTION_PERSPECTIVE,
3907
- signal: controller.signal
4251
+ signal: controller.signal,
4252
+ perspective,
4253
+ // temporary guard here until we're ready for everything to be queried via global API in v3
4254
+ ...source && !isDatasetSource(source) ? { source } : {}
3908
4255
  })
3909
4256
  ).pipe(switchMap(() => observable)) : observable).pipe(filter((result) => result !== void 0)).subscribe(observer);
3910
4257
  return () => {
3911
4258
  controller.signal.aborted || controller.abort(), subscription.unsubscribe();
3912
4259
  };
3913
- }).pipe(map((data) => ({ data, ids })));
4260
+ }), statusQuery$ = new Observable((observer) => {
4261
+ const { getCurrent, observable } = getQueryState(instance, {
4262
+ query: statusQuery,
4263
+ params: statusParams,
4264
+ tag: PROJECTION_TAG,
4265
+ perspective: "raw",
4266
+ // temporary guard here until we're ready for everything to be queried via global API
4267
+ ...source && !isDatasetSource(source) ? { source } : {}
4268
+ }), subscription = defer(() => getCurrent() === void 0 ? from(
4269
+ resolveQuery(instance, {
4270
+ query: statusQuery,
4271
+ params: statusParams,
4272
+ tag: PROJECTION_TAG,
4273
+ signal: controller.signal,
4274
+ perspective: "raw",
4275
+ // temporary guard here until we're ready for everything to be queried via global API
4276
+ ...source && !isDatasetSource(source) ? { source } : {}
4277
+ })
4278
+ ).pipe(switchMap(() => observable)) : observable).pipe(filter((result) => result !== void 0)).subscribe(observer);
4279
+ return () => {
4280
+ subscription.unsubscribe();
4281
+ };
4282
+ });
4283
+ return combineLatest([projectionQuery$, statusQuery$]).pipe(
4284
+ filter(
4285
+ (pair) => pair[0] !== void 0 && pair[1] !== void 0
4286
+ ),
4287
+ map(([projection, status]) => ({
4288
+ data: projection,
4289
+ ids,
4290
+ statusResults: status
4291
+ }))
4292
+ );
3914
4293
  }),
3915
- map(
3916
- ({ ids, data }) => processProjectionQuery({
4294
+ map(({ ids, data, statusResults }) => {
4295
+ const documentStatuses = processStatusQueryResults(statusResults);
4296
+ state.set("updateStatuses", (prev) => ({
4297
+ documentStatuses: {
4298
+ ...prev.documentStatuses,
4299
+ ...documentStatuses
4300
+ }
4301
+ }));
4302
+ const currentState = state.get();
4303
+ return processProjectionQuery({
3917
4304
  ids,
3918
- results: data
3919
- })
3920
- )
4305
+ results: data,
4306
+ documentStatuses: currentState.documentStatuses
4307
+ });
4308
+ })
3921
4309
  ).subscribe({
3922
4310
  next: (processedValues) => {
3923
4311
  state.set("updateResult", (prev) => {
@@ -3943,7 +4331,8 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
3943
4331
  return {
3944
4332
  values: {},
3945
4333
  documentProjections: {},
3946
- subscriptions: {}
4334
+ subscriptions: {},
4335
+ documentStatuses: {}
3947
4336
  };
3948
4337
  },
3949
4338
  initialize(context) {
@@ -3954,15 +4343,15 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
3954
4343
  function getProjectionState(...args) {
3955
4344
  return _getProjectionState(...args);
3956
4345
  }
3957
- const _getProjectionState = bindActionByDataset(
4346
+ const _getProjectionState = bindActionBySourceAndPerspective(
3958
4347
  projectionStore,
3959
4348
  createStateSourceAction({
3960
4349
  selector: ({ state }, options) => {
3961
- const documentId = getPublishedId(options.documentId), projectionHash = hashString(options.projection);
4350
+ const documentId = getPublishedId$2(DocumentId(options.documentId)), projectionHash = hashString(options.projection);
3962
4351
  return state.values[documentId]?.[projectionHash] ?? STABLE_EMPTY_PROJECTION;
3963
4352
  },
3964
4353
  onSubscribe: ({ state }, options) => {
3965
- const { projection, ...docHandle } = options, subscriptionId = insecureRandomId(), documentId = getPublishedId(docHandle.documentId), validProjection = validateProjection(projection), projectionHash = hashString(validProjection);
4354
+ const { projection, ...docHandle } = options, subscriptionId = insecureRandomId(), documentId = getPublishedId$2(DocumentId(docHandle.documentId)), validProjection = validateProjection(projection), projectionHash = hashString(validProjection);
3966
4355
  return state.set("addSubscription", (prev) => ({
3967
4356
  documentProjections: {
3968
4357
  ...prev.documentProjections,
@@ -4014,7 +4403,7 @@ const _getProjectionState = bindActionByDataset(
4014
4403
  function resolveProjection(...args) {
4015
4404
  return _resolveProjection(...args);
4016
4405
  }
4017
- const _resolveProjection = bindActionByDataset(
4406
+ const _resolveProjection = bindActionBySourceAndPerspective(
4018
4407
  projectionStore,
4019
4408
  ({ instance }, options) => firstValueFrom(
4020
4409
  getProjectionState(instance, options).observable.pipe(
@@ -4122,7 +4511,7 @@ function getCorsErrorProjectId(error) {
4122
4511
  const projMatch = (error.message || "").match(/manage\/project\/([^/?#]+)/);
4123
4512
  return projMatch ? projMatch[1] : null;
4124
4513
  }
4125
- var version = "2.5.0";
4514
+ var version = "2.7.0";
4126
4515
  const CORE_SDK_VERSION = getEnv("PKG_VERSION") || `${version}-development`;
4127
4516
  export {
4128
4517
  AuthStateType,
@@ -4133,7 +4522,7 @@ export {
4133
4522
  agentTransform,
4134
4523
  agentTranslate,
4135
4524
  applyDocumentActions,
4136
- canvasSource,
4525
+ configureLogging,
4137
4526
  createDatasetHandle,
4138
4527
  createDocument,
4139
4528
  createDocumentHandle,
@@ -4141,7 +4530,6 @@ export {
4141
4530
  createGroqSearchFilter,
4142
4531
  createProjectHandle,
4143
4532
  createSanityInstance,
4144
- datasetSource,
4145
4533
  defineIntent,
4146
4534
  deleteDocument,
4147
4535
  destroyController,
@@ -4183,12 +4571,15 @@ export {
4183
4571
  getUsersKey,
4184
4572
  getUsersState,
4185
4573
  handleAuthCallback,
4574
+ isCanvasSource,
4575
+ isDatasetSource,
4576
+ isMediaLibrarySource,
4186
4577
  isProjectUserNotFoundClientError,
4578
+ isStudioConfig,
4187
4579
  joinPaths,
4188
4580
  jsonMatch2 as jsonMatch,
4189
4581
  loadMoreUsers,
4190
4582
  logout,
4191
- mediaLibrarySource,
4192
4583
  observeOrganizationVerificationState,
4193
4584
  parseQueryKey,
4194
4585
  parseUsersKey,