@sanity/sdk 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/_chunks-dts/utils.d.ts +2450 -0
  2. package/dist/_chunks-es/_internal.js +129 -0
  3. package/dist/_chunks-es/_internal.js.map +1 -0
  4. package/dist/_chunks-es/createGroqSearchFilter.js +1537 -0
  5. package/dist/_chunks-es/createGroqSearchFilter.js.map +1 -0
  6. package/dist/_chunks-es/telemetryManager.js +87 -0
  7. package/dist/_chunks-es/telemetryManager.js.map +1 -0
  8. package/dist/_chunks-es/version.js +7 -0
  9. package/dist/_chunks-es/version.js.map +1 -0
  10. package/dist/_exports/_internal.d.ts +64 -0
  11. package/dist/_exports/_internal.js +20 -0
  12. package/dist/_exports/_internal.js.map +1 -0
  13. package/dist/index.d.ts +2 -2343
  14. package/dist/index.js +465 -1813
  15. package/dist/index.js.map +1 -1
  16. package/package.json +17 -12
  17. package/src/_exports/_internal.ts +14 -0
  18. package/src/_exports/index.ts +18 -1
  19. package/src/auth/authStore.test.ts +150 -1
  20. package/src/auth/authStore.ts +11 -11
  21. package/src/auth/dashboardAuth.ts +2 -2
  22. package/src/auth/handleAuthCallback.ts +9 -3
  23. package/src/auth/logout.test.ts +1 -1
  24. package/src/auth/logout.ts +1 -1
  25. package/src/auth/refreshStampedToken.test.ts +118 -1
  26. package/src/auth/refreshStampedToken.ts +3 -2
  27. package/src/auth/standaloneAuth.ts +9 -3
  28. package/src/auth/studioAuth.ts +34 -7
  29. package/src/auth/studioModeAuth.ts +2 -1
  30. package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +10 -2
  31. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +5 -1
  32. package/src/auth/subscribeToStorageEventsAndSetToken.ts +2 -2
  33. package/src/auth/utils.ts +33 -0
  34. package/src/client/clientStore.test.ts +44 -30
  35. package/src/client/clientStore.ts +49 -48
  36. package/src/comlink/controller/actions/getOrCreateChannel.ts +2 -2
  37. package/src/comlink/node/actions/getOrCreateNode.ts +2 -2
  38. package/src/comlink/node/getNodeState.ts +2 -1
  39. package/src/config/sanityConfig.ts +78 -12
  40. package/src/document/actions.ts +18 -11
  41. package/src/document/applyDocumentActions.test.ts +7 -6
  42. package/src/document/applyDocumentActions.ts +10 -4
  43. package/src/document/documentStore.test.ts +542 -188
  44. package/src/document/documentStore.ts +142 -76
  45. package/src/document/events.ts +7 -2
  46. package/src/document/permissions.test.ts +18 -16
  47. package/src/document/permissions.ts +35 -11
  48. package/src/document/processActions.test.ts +359 -32
  49. package/src/document/processActions.ts +106 -78
  50. package/src/document/reducers.test.ts +117 -29
  51. package/src/document/reducers.ts +47 -40
  52. package/src/document/sharedListener.ts +16 -6
  53. package/src/document/util.ts +14 -0
  54. package/src/favorites/favorites.test.ts +9 -2
  55. package/src/presence/bifurTransport.test.ts +46 -6
  56. package/src/presence/bifurTransport.ts +19 -2
  57. package/src/presence/presenceStore.test.ts +96 -0
  58. package/src/presence/presenceStore.ts +96 -24
  59. package/src/preview/getPreviewState.test.ts +115 -98
  60. package/src/preview/getPreviewState.ts +38 -60
  61. package/src/preview/previewProjectionUtils.test.ts +179 -0
  62. package/src/preview/previewProjectionUtils.ts +93 -0
  63. package/src/preview/resolvePreview.test.ts +42 -25
  64. package/src/preview/resolvePreview.ts +33 -10
  65. package/src/preview/{previewStore.ts → types.ts} +8 -17
  66. package/src/projection/getProjectionState.test.ts +16 -16
  67. package/src/projection/getProjectionState.ts +6 -5
  68. package/src/projection/projectionQuery.ts +2 -3
  69. package/src/projection/projectionStore.test.ts +2 -2
  70. package/src/projection/resolveProjection.ts +2 -2
  71. package/src/projection/subscribeToStateAndFetchBatches.test.ts +1 -1
  72. package/src/projection/subscribeToStateAndFetchBatches.ts +12 -11
  73. package/src/projection/types.ts +1 -1
  74. package/src/query/queryStore.test.ts +12 -12
  75. package/src/query/queryStore.ts +12 -11
  76. package/src/query/reducers.ts +3 -3
  77. package/src/releases/getPerspectiveState.ts +7 -6
  78. package/src/releases/releasesStore.test.ts +20 -5
  79. package/src/releases/releasesStore.ts +20 -8
  80. package/src/store/createActionBinder.test.ts +31 -31
  81. package/src/store/createActionBinder.ts +43 -38
  82. package/src/store/createSanityInstance.ts +2 -3
  83. package/src/store/createStateSourceAction.test.ts +62 -0
  84. package/src/store/createStateSourceAction.ts +34 -39
  85. package/src/telemetry/__telemetry__/sdk.telemetry.ts +42 -0
  86. package/src/telemetry/devMode.test.ts +52 -0
  87. package/src/telemetry/devMode.ts +40 -0
  88. package/src/telemetry/initTelemetry.test.ts +225 -0
  89. package/src/telemetry/initTelemetry.ts +205 -0
  90. package/src/telemetry/telemetryManager.test.ts +263 -0
  91. package/src/telemetry/telemetryManager.ts +187 -0
  92. package/src/users/reducers.ts +3 -4
  93. package/src/users/usersStore.test.ts +1 -0
  94. package/src/users/usersStore.ts +5 -1
  95. package/src/utils/createFetcherStore.test.ts +6 -4
  96. package/src/utils/createFetcherStore.ts +8 -5
  97. package/src/utils/getStagingApiHost.test.ts +21 -0
  98. package/src/utils/getStagingApiHost.ts +14 -0
  99. package/src/utils/ids.test.ts +1 -29
  100. package/src/utils/ids.ts +0 -10
  101. package/src/utils/isImportError.test.ts +72 -0
  102. package/src/utils/isImportError.ts +34 -0
  103. package/src/utils/object.test.ts +95 -0
  104. package/src/utils/object.ts +142 -0
  105. package/src/utils/setCleanupTimeout.ts +24 -0
  106. package/src/preview/previewQuery.test.ts +0 -236
  107. package/src/preview/previewQuery.ts +0 -153
  108. package/src/preview/previewStore.test.ts +0 -36
  109. package/src/preview/subscribeToStateAndFetchBatches.test.ts +0 -221
  110. package/src/preview/subscribeToStateAndFetchBatches.ts +0 -112
  111. package/src/preview/util.ts +0 -13
package/dist/index.js CHANGED
@@ -1,13 +1,11 @@
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
- import { createClient, CorsOriginError } from "@sanity/client";
3
- import { pick, omit, isEqual, isObject } from "lodash-es";
4
- import { devtools } from "zustand/middleware";
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 } from "rxjs/operators";
1
+ import { switchMap, from, firstValueFrom, EMPTY, asapScheduler, distinctUntilChanged, map as map$1, combineLatest, of, concatMap, withLatestFrom, filter as filter$1, concat, timer, throwError, first as first$1, Subject, takeUntil, share, 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, skip, Observable, NEVER, fromEvent, Subscription, debounceTime, defer } from "rxjs";
2
+ import { createLogger, pickProperties, insecureRandomId, getClientState, bindActionGlobally, createStateSourceAction, setCleanupTimeout, omitProperty, defineStore, authStore, AuthStateType, getCleanedUrl, getTokenFromLocation, createLoggedInAuthState, getAuthCode, REQUEST_TAG_PREFIX, DEFAULT_API_VERSION, getDefaultLocation, isDeepEqual, configureLogging as configureLogging$1, isReleasePerspective, isDatasetResource, bindActionByResource, isMediaLibraryResource, isCanvasResource, getUsersKey, addSubscription, parseUsersKey, getClient, PROJECT_API_VERSION, setUsersError, setUsersData, API_VERSION as API_VERSION$6, getDashboardOrganizationId as getDashboardOrganizationId$1, USERS_STATE_CLEAR_DELAY, removeSubscription, updateLastLoadMoreRequest, cancelRequest, initializeRequest, getTokenState, getQueryState, resolveQuery, bindActionByResourceAndPerspective, PREVIEW_PROJECTION, transformProjectionToPreview } from "./_chunks-es/createGroqSearchFilter.js";
3
+ import { createGroqSearchFilter, getActiveReleasesState, getAuthState, getClientErrorApiBody, getClientErrorApiDescription, getClientErrorApiType, getCurrentUserState, getIsInDashboardState, getLoginUrlState, getPerspectiveState, getQueryKey, isCanvasSource, isDatasetSource, isMediaLibrarySource, isProjectUserNotFoundClientError, isStudioConfig, parseQueryKey, setAuthToken } from "./_chunks-es/createGroqSearchFilter.js";
4
+ import { first, switchMap as switchMap$1, groupBy, mergeMap, startWith, pairwise, filter, map, delay, tap, catchError, scan, share as share$1 } from "rxjs/operators";
7
5
  import { createController, createNode } from "@sanity/comlink";
8
6
  import { createSelector } from "reselect";
9
7
  import { SanityEncoder } from "@sanity/mutate";
10
- import { getPublishedId as getPublishedId$1 } from "@sanity/client/csm";
8
+ import { getVersionId, DocumentId, getPublishedId, getDraftId, isDraftId, isVersionId, isPublishedId } from "@sanity/id-utils";
11
9
  import { jsonMatch, stringifyPath, slicePath, getIndexForKey } from "@sanity/json-match";
12
10
  import { getIndexForKey as getIndexForKey2, getPathDepth, joinPaths, jsonMatch as jsonMatch2, slicePath as slicePath2, stringifyPath as stringifyPath2 } from "@sanity/json-match";
13
11
  import { evaluateSync, parse } from "groq-js";
@@ -17,142 +15,8 @@ import { isKeySegment, isKeyedObject } from "@sanity/types";
17
15
  import { createDocumentLoaderFromClient } from "@sanity/mutate/_unstable_store";
18
16
  import { SDK_CHANNEL_NAME, SDK_NODE_NAME } from "@sanity/message-protocol";
19
17
  import { fromUrl } from "@sanity/bifur-client";
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
- }
24
- function isMediaLibrarySource(source) {
25
- return "mediaLibraryId" in source;
26
- }
27
- function isCanvasSource(source) {
28
- return "canvasId" in source;
29
- }
30
- const isReleasePerspective = (perspective) => typeof perspective == "object" && perspective !== null && "releaseName" in perspective;
31
- function getPublishedId(id) {
32
- const draftsPrefix = "drafts.";
33
- return id.startsWith(draftsPrefix) ? id.slice(draftsPrefix.length) : id;
34
- }
35
- function getDraftId(id) {
36
- const draftsPrefix = "drafts.";
37
- return id.startsWith(draftsPrefix) ? id : `${draftsPrefix}${id}`;
38
- }
39
- function insecureRandomId() {
40
- return Array.from({ length: 16 }, () => Math.floor(Math.random() * 16).toString(16)).join("");
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
- }
18
+ import { CorsOriginError } from "@sanity/client";
19
+ import { CORE_SDK_VERSION } from "./_chunks-es/version.js";
156
20
  function createSanityInstance(config = {}) {
157
21
  const instanceId = crypto.randomUUID(), disposeListeners = /* @__PURE__ */ new Map(), disposed = { current: !1 }, instanceContext = {
158
22
  instanceId,
@@ -217,7 +81,7 @@ function createSanityInstance(config = {}) {
217
81
  }), child;
218
82
  },
219
83
  match: (targetConfig) => {
220
- if (Object.entries(pick(targetConfig, "auth", "projectId", "dataset")).every(
84
+ if (Object.entries(pickProperties(targetConfig, ["auth", "projectId", "dataset"])).every(
221
85
  ([key, value]) => config[key] === value
222
86
  ))
223
87
  return instance;
@@ -227,870 +91,38 @@ function createSanityInstance(config = {}) {
227
91
  };
228
92
  return instance;
229
93
  }
230
- function getEnv(key) {
231
- if (typeof import.meta < "u" && import.meta.env)
232
- return import.meta.env[key];
233
- if (typeof process < "u" && process.env)
234
- return process.env[key];
235
- if (typeof window < "u" && window.ENV)
236
- return window.ENV?.[key];
237
- }
238
- function createStoreState(initialState, devToolsOptions) {
239
- const store = createStore()(devtools(() => initialState, devToolsOptions));
240
- return {
241
- get: store.getState,
242
- set: (actionKey, updatedState) => {
243
- const currentState = store.getState(), nextState = typeof updatedState == "function" ? updatedState(currentState) : updatedState;
244
- currentState !== nextState && store.setState(nextState, !1, actionKey);
245
- },
246
- observable: new Observable((observer) => {
247
- const emit = () => observer.next(store.getState());
248
- emit();
249
- const unsubscribe = store.subscribe(emit);
250
- return () => unsubscribe();
251
- })
252
- };
253
- }
254
- function createStoreInstance(instance, key, { name, getInitialState: getInitialState2, initialize }) {
255
- const state = createStoreState(getInitialState2(instance, key), {
256
- enabled: !!getEnv("DEV"),
257
- name: `${name}-${key.name}`
258
- }), dispose = initialize?.({ state, instance, key }), disposed = { current: !1 };
259
- return {
260
- state,
261
- dispose: () => {
262
- disposed.current || (disposed.current = !0, dispose?.());
263
- },
264
- isDisposed: () => disposed.current
265
- };
266
- }
267
- function createActionBinder(keyFn) {
268
- const instanceRegistry = /* @__PURE__ */ new Map(), storeRegistry = /* @__PURE__ */ new Map();
269
- return function(storeDefinition, action) {
270
- return function(instance, ...params) {
271
- const key = keyFn(instance, ...params), compositeKey = storeDefinition.name + (key.name ? `:${key.name}` : "");
272
- let instances = instanceRegistry.get(compositeKey);
273
- instances || (instances = /* @__PURE__ */ new Set(), instanceRegistry.set(compositeKey, instances)), instances.has(instance.instanceId) || (instances.add(instance.instanceId), instance.onDispose(() => {
274
- instances.delete(instance.instanceId), instances.size === 0 && (storeRegistry.get(compositeKey)?.dispose(), storeRegistry.delete(compositeKey), instanceRegistry.delete(compositeKey));
275
- }));
276
- let storeInstance = storeRegistry.get(compositeKey);
277
- return storeInstance || (storeInstance = createStoreInstance(instance, key, storeDefinition), storeRegistry.set(compositeKey, storeInstance)), action({ instance, state: storeInstance.state, key }, ...params);
278
- };
279
- };
280
- }
281
- const bindActionByDataset = createActionBinder((instance, options) => {
282
- const projectId = options?.projectId ?? instance.config.projectId, dataset = options?.dataset ?? instance.config.dataset;
283
- if (!projectId || !dataset)
284
- throw new Error("This API requires a project ID and dataset configured.");
285
- return { name: `${projectId}.${dataset}`, projectId, dataset };
286
- }), createSourceKey = (instance, source) => {
287
- let name, sourceForKey;
288
- if (source) {
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 };
298
- }
299
- const { projectId, dataset } = instance.config;
300
- if (!projectId || !dataset)
301
- throw new Error("This API requires a project ID and dataset configured.");
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
- };
313
- }), bindActionGlobally = createActionBinder((..._rest) => ({ name: "global" }));
314
- function createStateSourceAction(options) {
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();
316
- function stateSourceAction(context, ...params) {
317
- const { state, instance } = context, getCurrent = () => {
318
- const currentState = state.get();
319
- if (typeof currentState != "object" || currentState === null)
320
- throw new Error(
321
- `Expected store state to be an object but got "${typeof currentState}" instead`
322
- );
323
- let instanceCache = selectorContextCache.get(currentState);
324
- instanceCache || (instanceCache = /* @__PURE__ */ new WeakMap(), selectorContextCache.set(currentState, instanceCache));
325
- let selectorContext = instanceCache.get(instance);
326
- return selectorContext || (selectorContext = { state: currentState, instance }, instanceCache.set(instance, selectorContext)), selector(selectorContext, ...params);
327
- }, subscribe = (onStoreChanged) => {
328
- const cleanup = subscribeHandler?.(context, ...params), subscription = state.observable.pipe(
329
- // Derive value from current state
330
- map(getCurrent),
331
- // Filter unchanged values using custom equality check
332
- distinctUntilChanged(isEqual2),
333
- // Skip initial emission since we only want changes
334
- skip(1)
335
- ).subscribe({
336
- next: () => onStoreChanged?.(),
337
- // Propagate selector errors to both subscription types
338
- error: () => onStoreChanged?.()
339
- });
340
- return () => {
341
- subscription.unsubscribe(), cleanup?.();
342
- };
343
- }, observable = new Observable((observer) => {
344
- const emitCurrent = () => {
345
- try {
346
- observer.next(getCurrent());
347
- } catch (error) {
348
- observer.error(error);
349
- }
350
- };
351
- return emitCurrent(), subscribe(emitCurrent);
352
- }).pipe(share());
353
- return {
354
- getCurrent,
355
- subscribe,
356
- observable
357
- };
358
- }
359
- return stateSourceAction;
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
- }
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 || {});
379
- const REFRESH_INTERVAL = 720 * 60 * 1e3, LOCK_NAME = "sanity-token-refresh-lock";
380
- function getLastRefreshTime(storageArea, storageKey) {
381
- try {
382
- const data = storageArea?.getItem(`${storageKey}_last_refresh`), parsed = data ? parseInt(data, 10) : 0;
383
- return isNaN(parsed) ? 0 : parsed;
384
- } catch {
385
- return 0;
386
- }
387
- }
388
- function setLastRefreshTime(storageArea, storageKey) {
389
- try {
390
- storageArea?.setItem(`${storageKey}_last_refresh`, Date.now().toString());
391
- } catch {
392
- }
393
- }
394
- function getNextRefreshDelay(storageArea, storageKey) {
395
- const lastRefresh = getLastRefreshTime(storageArea, storageKey);
396
- if (!lastRefresh) return 0;
397
- const now = Date.now(), nextRefreshTime = lastRefresh + REFRESH_INTERVAL;
398
- return Math.max(0, nextRefreshTime - now);
399
- }
400
- function createTokenRefreshStream(token, clientFactory, apiHost) {
401
- return new Observable((subscriber) => {
402
- const subscription = clientFactory({
403
- apiVersion: DEFAULT_API_VERSION$1,
404
- requestTagPrefix: "token-refresh",
405
- useProjectHostname: !1,
406
- useCdn: !1,
407
- token,
408
- ignoreBrowserTokenWarning: !0,
409
- ...apiHost && { apiHost }
410
- }).observable.request({
411
- uri: "auth/refresh-token",
412
- method: "POST",
413
- body: {
414
- token
415
- }
416
- }).subscribe(subscriber);
417
- return () => subscription.unsubscribe();
418
- });
419
- }
420
- async function acquireTokenRefreshLock(refreshFn, storageArea, storageKey) {
421
- if (!navigator.locks)
422
- return console.warn("Web Locks API not supported. Proceeding with uncoordinated refresh."), await refreshFn(), setLastRefreshTime(storageArea, storageKey), !0;
423
- try {
424
- return await navigator.locks.request(LOCK_NAME, { mode: "exclusive" }, async (lock) => {
425
- if (!lock) return !1;
426
- for (; ; ) {
427
- const delay2 = getNextRefreshDelay(storageArea, storageKey);
428
- delay2 > 0 && await new Promise((resolve) => setTimeout(resolve, delay2));
429
- try {
430
- await refreshFn(), setLastRefreshTime(storageArea, storageKey);
431
- } catch (error) {
432
- console.error("Token refresh failed within lock:", error);
433
- }
434
- await new Promise((resolve) => setTimeout(resolve, REFRESH_INTERVAL));
435
- }
436
- }) === !0;
437
- } catch (error) {
438
- return console.error("Failed to request token refresh lock:", error), !1;
439
- }
440
- }
441
- function shouldRefreshToken(lastRefresh) {
442
- return lastRefresh ? Date.now() - lastRefresh >= REFRESH_INTERVAL : !0;
443
- }
444
- const refreshStampedToken = ({ state }) => {
445
- const { clientFactory, apiHost, storageArea, storageKey } = state.get().options;
446
- return state.observable.pipe(
447
- map((storeState) => ({
448
- authState: storeState.authState,
449
- dashboardContext: storeState.dashboardContext
450
- })),
451
- filter(
452
- (storeState) => storeState.authState.type === AuthStateType.LOGGED_IN
453
- ),
454
- distinctUntilChanged(
455
- (prev, curr) => prev.authState.type === curr.authState.type && prev.authState.token === curr.authState.token && // Only care about token for distinctness here
456
- prev.dashboardContext === curr.dashboardContext
457
- ),
458
- // Make distinctness check explicit
459
- filter((storeState) => storeState.authState.token.includes("-st")),
460
- // Ensure we only try to refresh stamped tokens
461
- exhaustMap((storeState) => {
462
- const performRefresh = async () => {
463
- const currentState = state.get();
464
- if (currentState.authState.type !== AuthStateType.LOGGED_IN)
465
- throw new Error("User logged out before refresh could complete");
466
- const currentToken = currentState.authState.token, response = await firstValueFrom(
467
- createTokenRefreshStream(currentToken, clientFactory, apiHost)
468
- );
469
- state.set("setRefreshStampedToken", (prev) => ({
470
- authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, token: response.token } : prev.authState
471
- })), storageArea?.setItem(storageKey, JSON.stringify({ token: response.token }));
472
- };
473
- return storeState.dashboardContext ? new Observable((subscriber) => {
474
- const visibilityHandler = () => {
475
- const currentState = state.get();
476
- document.visibilityState === "visible" && currentState.authState.type === AuthStateType.LOGGED_IN && shouldRefreshToken(currentState.authState.lastTokenRefresh) && createTokenRefreshStream(
477
- currentState.authState.token,
478
- clientFactory,
479
- apiHost
480
- ).subscribe({
481
- next: (response) => {
482
- state.set("setRefreshStampedToken", (prev) => ({
483
- authState: prev.authState.type === AuthStateType.LOGGED_IN ? {
484
- ...prev.authState,
485
- token: response.token,
486
- lastTokenRefresh: Date.now()
487
- } : prev.authState
488
- })), subscriber.next(response);
489
- },
490
- error: (error) => subscriber.error(error)
491
- });
492
- }, timerSubscription = timer(REFRESH_INTERVAL, REFRESH_INTERVAL).pipe(
493
- filter(() => document.visibilityState === "visible"),
494
- switchMap(() => {
495
- const currentState = state.get().authState;
496
- if (currentState.type !== AuthStateType.LOGGED_IN)
497
- throw new Error("User logged out before refresh could complete");
498
- return createTokenRefreshStream(currentState.token, clientFactory, apiHost);
499
- })
500
- ).subscribe({
501
- next: (response) => {
502
- state.set("setRefreshStampedToken", (prev) => ({
503
- authState: prev.authState.type === AuthStateType.LOGGED_IN ? {
504
- ...prev.authState,
505
- token: response.token,
506
- lastTokenRefresh: Date.now()
507
- } : prev.authState
508
- })), subscriber.next(response);
509
- },
510
- error: (error) => subscriber.error(error)
511
- });
512
- return document.addEventListener("visibilitychange", visibilityHandler), () => {
513
- document.removeEventListener("visibilitychange", visibilityHandler), timerSubscription.unsubscribe();
514
- };
515
- }).pipe(
516
- takeWhile(() => state.get().authState.type === AuthStateType.LOGGED_IN),
517
- map((response) => ({ token: response.token }))
518
- ) : from(acquireTokenRefreshLock(performRefresh, storageArea, storageKey)).pipe(
519
- filter((hasLock) => hasLock),
520
- map(() => {
521
- const currentState = state.get().authState;
522
- if (currentState.type !== AuthStateType.LOGGED_IN)
523
- throw new Error("User logged out before refresh could complete");
524
- return { token: currentState.token };
525
- })
526
- );
527
- })
528
- ).subscribe({
529
- next: (response) => {
530
- state.set("setRefreshStampedToken", (prev) => ({
531
- authState: prev.authState.type === AuthStateType.LOGGED_IN ? {
532
- ...prev.authState,
533
- token: response.token,
534
- lastTokenRefresh: Date.now()
535
- } : prev.authState
536
- })), storageArea?.setItem(storageKey, JSON.stringify({ token: response.token }));
537
- },
538
- error: (error) => {
539
- state.set("setRefreshStampedTokenError", { authState: { type: AuthStateType.ERROR, error } });
540
- }
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
- });
583
- };
584
- function getAuthCode(callbackUrl, locationHref) {
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;
586
- let authCode = new URLSearchParams(loc.hash.slice(1)).get(AUTH_CODE_PARAM) || new URLSearchParams(loc.search).get(AUTH_CODE_PARAM);
587
- if (!authCode) {
588
- const contextParam = new URLSearchParams(loc.search).get("_context");
589
- if (contextParam)
590
- try {
591
- const parsedContext = JSON.parse(contextParam);
592
- parsedContext && typeof parsedContext == "object" && typeof parsedContext.sid == "string" && parsedContext.sid && (authCode = parsedContext.sid);
593
- } catch {
594
- }
595
- }
596
- return authCode && callbackLocationMatches ? authCode : null;
597
- }
598
- function getTokenFromLocation(locationHref) {
599
- const loc = new URL(locationHref);
600
- return new URLSearchParams(loc.hash.slice(1)).get("token") || null;
601
- }
602
- function getTokenFromStorage(storageArea, storageKey) {
603
- if (!storageArea) return null;
604
- const item = storageArea.getItem(storageKey);
605
- if (item === null) return null;
606
- try {
607
- const parsed = JSON.parse(item);
608
- if (typeof parsed != "object" || parsed === null || !("token" in parsed) || typeof parsed.token != "string")
609
- throw new Error("Invalid stored auth data structure");
610
- return parsed.token;
611
- } catch {
612
- return storageArea.removeItem(storageKey), null;
613
- }
614
- }
615
- function getStorageEvents() {
616
- return typeof window < "u" && typeof window.addEventListener == "function" ? fromEvent(window, "storage") : EMPTY;
617
- }
618
- function getDefaultStorage() {
619
- try {
620
- return typeof localStorage < "u" && typeof localStorage.getItem == "function" ? localStorage : void 0;
621
- } catch {
622
- return;
623
- }
624
- }
625
- function getDefaultLocation() {
626
- try {
627
- return typeof location > "u" ? DEFAULT_BASE : typeof location.href == "string" ? location.href : DEFAULT_BASE;
628
- } catch {
629
- return DEFAULT_BASE;
630
- }
631
- }
632
- function getCleanedUrl(locationUrl) {
633
- const loc = new URL(locationUrl), rawHash = loc.hash.startsWith("#") ? loc.hash.slice(1) : loc.hash;
634
- if (rawHash && rawHash.includes("=")) {
635
- const hashParams = new URLSearchParams(rawHash);
636
- hashParams.delete("token"), hashParams.delete("withSid");
637
- const nextHash = hashParams.toString();
638
- loc.hash = nextHash ? `#${nextHash}` : "";
639
- }
640
- return loc.searchParams.delete("sid"), loc.searchParams.delete("url"), loc.toString();
641
- }
642
- function getClientErrorApiBody(error) {
643
- const body = error.response?.body;
644
- return body && typeof body == "object" ? body : void 0;
645
- }
646
- function getClientErrorApiType(error) {
647
- const body = getClientErrorApiBody(error);
648
- return body?.error?.type ?? body?.type;
649
- }
650
- function getClientErrorApiDescription(error) {
651
- const body = getClientErrorApiBody(error);
652
- return body?.error?.description ?? body?.description;
653
- }
654
- function isProjectUserNotFoundClientError(error) {
655
- return getClientErrorApiType(error) === "projectUserNotFoundError";
656
- }
657
- function parseDashboardContext(locationHref) {
658
- try {
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);
667
- }
668
- return {};
669
- }
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
- };
691
- }
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();
699
- },
700
- tokenRefresherStarted: startedRefresher
701
- };
702
- }
703
- const subscribeToStorageEventsAndSetToken = ({
704
- state
705
- }) => {
706
- const { storageArea, storageKey } = state.get().options;
707
- return defer(getStorageEvents).pipe(
708
- filter(
709
- (e) => e.storageArea === storageArea && e.key === storageKey
710
- ),
711
- map(() => getTokenFromStorage(storageArea, storageKey)),
712
- distinctUntilChanged()
713
- ).subscribe((token) => {
714
- state.set("updateTokenFromStorageEvent", {
715
- authState: token ? { type: AuthStateType.LOGGED_IN, token, currentUser: null } : { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
716
- });
717
- });
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
- }
872
- let tokenRefresherRunning = !1;
873
- const authStore = {
874
- name: "Auth",
875
- getInitialState(instance) {
876
- const {
877
- apiHost,
878
- callbackUrl,
879
- providers: customProviders,
880
- token: providedToken,
881
- clientFactory = createClient,
882
- initialLocationHref = getDefaultLocation()
883
- } = instance.config.auth ?? {}, authConfig = instance.config.auth ?? {};
884
- let loginDomain = "https://www.sanity.io";
885
- try {
886
- apiHost && new URL(apiHost).hostname.endsWith(".sanity.work") && (loginDomain = "https://www.sanity.work");
887
- } catch {
888
- }
889
- const loginUrl = new URL("/login", loginDomain);
890
- loginUrl.searchParams.set("origin", getCleanedUrl(initialLocationHref)), loginUrl.searchParams.set("type", "stampedToken"), loginUrl.searchParams.set("withSid", "true");
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;
908
- }
909
- return {
910
- authState: result.authState,
911
- dashboardContext: result.dashboardContext,
912
- options: {
913
- apiHost,
914
- loginUrl: loginUrl.toString(),
915
- callbackUrl,
916
- customProviders,
917
- providedToken,
918
- clientFactory,
919
- initialLocationHref,
920
- storageKey: result.storageKey,
921
- storageArea: result.storageArea,
922
- authMethod: result.authMethod
923
- }
924
- };
925
- },
926
- initialize(context) {
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;
939
- }
940
- return initResult.tokenRefresherStarted && (tokenRefresherRunning = !0), initResult.dispose;
941
- }
942
- }, getCurrentUserState = bindActionGlobally(
943
- authStore,
944
- createStateSourceAction(
945
- ({ state: { authState } }) => authState.type === AuthStateType.LOGGED_IN ? authState.currentUser : null
946
- )
947
- ), getTokenState = bindActionGlobally(
948
- authStore,
949
- createStateSourceAction(
950
- ({ state: { authState } }) => authState.type === AuthStateType.LOGGED_IN ? authState.token : null
951
- )
952
- ), getAuthMethodState = bindActionGlobally(
953
- authStore,
954
- createStateSourceAction(({ state: { options } }) => options.authMethod)
955
- ), getLoginUrlState = bindActionGlobally(
956
- authStore,
957
- createStateSourceAction(({ state: { options } }) => options.loginUrl)
958
- ), getAuthState = bindActionGlobally(
959
- authStore,
960
- createStateSourceAction(({ state: { authState } }) => authState)
961
- ), getDashboardOrganizationId$1 = bindActionGlobally(
962
- authStore,
963
- createStateSourceAction(({ state: { dashboardContext } }) => dashboardContext?.orgId)
964
- ), getIsInDashboardState = bindActionGlobally(
965
- authStore,
966
- createStateSourceAction(
967
- ({ state: { dashboardContext } }) => (
968
- // Check if dashboardContext exists and is not empty
969
- !!dashboardContext && Object.keys(dashboardContext).length > 0
970
- )
971
- )
972
- ), setAuthToken = bindActionGlobally(authStore, ({ state }, token) => {
973
- const currentAuthState = state.get().authState;
974
- token ? (currentAuthState.type !== AuthStateType.LOGGED_IN || currentAuthState.token !== token) && state.set("setToken", {
975
- authState: {
976
- type: AuthStateType.LOGGED_IN,
977
- token,
978
- // Keep existing user or set to null? Setting to null forces refetch.
979
- // Keep existing user to avoid unnecessary refetches if user data is still valid.
980
- currentUser: currentAuthState.type === AuthStateType.LOGGED_IN ? currentAuthState.currentUser : null
981
- }
982
- }) : currentAuthState.type !== AuthStateType.LOGGED_OUT && state.set("setToken", {
983
- authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
984
- });
985
- }), DEFAULT_API_VERSION = "2024-11-12", DEFAULT_REQUEST_TAG_PREFIX = "sanity.sdk", allowedKeys = Object.keys({
986
- apiHost: null,
987
- useCdn: null,
988
- token: null,
989
- perspective: null,
990
- proxy: null,
991
- withCredentials: null,
992
- timeout: null,
993
- maxRetries: null,
994
- dataset: null,
995
- projectId: null,
996
- scope: null,
997
- apiVersion: null,
998
- requestTagPrefix: null,
999
- useProjectHostname: null,
1000
- "~experimental_resource": null,
1001
- source: null
1002
- }), DEFAULT_CLIENT_CONFIG = {
1003
- apiVersion: DEFAULT_API_VERSION,
1004
- useCdn: !1,
1005
- ignoreBrowserTokenWarning: !0,
1006
- allowReconfigure: !1,
1007
- requestTagPrefix: DEFAULT_REQUEST_TAG_PREFIX
1008
- }, clientStore = {
1009
- name: "clientStore",
1010
- getInitialState: (instance) => ({
1011
- clients: {},
1012
- token: getTokenState(instance).getCurrent()
1013
- }),
1014
- initialize(context) {
1015
- const subscription = listenToToken(context), authMethodSubscription = listenToAuthMethod(context);
1016
- return () => {
1017
- subscription.unsubscribe(), authMethodSubscription.unsubscribe();
1018
- };
1019
- }
1020
- }, listenToToken = ({ instance, state }) => getTokenState(instance).observable.subscribe((token) => {
1021
- state.set("setTokenAndResetClients", { token, clients: {} });
1022
- }), listenToAuthMethod = ({ instance, state }) => getAuthMethodState(instance).observable.subscribe((authMethod) => {
1023
- state.set("setAuthMethod", { authMethod });
1024
- }), getClientConfigKey = (options) => JSON.stringify(pick(options, ...allowedKeys)), getClient = bindActionGlobally(
1025
- clientStore,
1026
- ({ state, instance }, options) => {
1027
- if (!options || typeof options != "object")
1028
- throw new Error(
1029
- 'getClient() requires a configuration object with at least an "apiVersion" property. Example: getClient(instance, { apiVersion: "2024-11-12" })'
1030
- );
1031
- const disallowedKeys = Object.keys(options).filter((key2) => !allowedKeys.includes(key2));
1032
- if (disallowedKeys.length > 0) {
1033
- const listFormatter = new Intl.ListFormat("en", { style: "long", type: "conjunction" });
1034
- throw new Error(
1035
- `The client options provided contains unsupported properties: ${listFormatter.format(disallowedKeys)}. Allowed keys are: ${listFormatter.format(allowedKeys)}.`
1036
- );
1037
- }
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 }));
1041
- const projectId = options.projectId ?? instance.config.projectId, dataset = options.dataset ?? instance.config.dataset, apiHost = options.apiHost ?? instance.config.auth?.apiHost, effectiveOptions = {
1042
- ...DEFAULT_CLIENT_CONFIG,
1043
- ...(options.scope === "global" || !projectId || resource) && { useProjectHostname: !1 },
1044
- token: authMethod === "cookie" ? void 0 : tokenFromState ?? void 0,
1045
- ...options,
1046
- ...projectId && { projectId },
1047
- ...dataset && { dataset },
1048
- ...apiHost && { apiHost },
1049
- ...resource && { "~experimental_resource": resource }
1050
- };
1051
- resource && ((options.projectId || options.dataset) && console.warn(
1052
- "Both source and explicit projectId/dataset are provided. The source will be used and projectId/dataset will be ignored."
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;
1054
- const key = getClientConfigKey(effectiveOptions);
1055
- if (clients[key]) return clients[key];
1056
- const client = createClient(effectiveOptions);
1057
- return state.set("addClient", (prev) => ({ clients: { ...prev.clients, [key]: client } })), client;
1058
- }
1059
- ), getClientState = bindActionGlobally(
1060
- clientStore,
1061
- createStateSourceAction(({ instance }, options) => getClient(instance, options))
1062
- ), API_VERSION$6 = "vX";
94
+ const API_VERSION$5 = "vX";
1063
95
  function agentGenerate(instance, options) {
1064
96
  return getClientState(instance, {
1065
- apiVersion: API_VERSION$6,
97
+ apiVersion: API_VERSION$5,
1066
98
  projectId: instance.config.projectId,
1067
99
  dataset: instance.config.dataset
1068
100
  }).observable.pipe(switchMap((client) => client.observable.agent.action.generate(options)));
1069
101
  }
1070
102
  function agentTransform(instance, options) {
1071
103
  return getClientState(instance, {
1072
- apiVersion: API_VERSION$6,
104
+ apiVersion: API_VERSION$5,
1073
105
  projectId: instance.config.projectId,
1074
106
  dataset: instance.config.dataset
1075
107
  }).observable.pipe(switchMap((client) => client.observable.agent.action.transform(options)));
1076
108
  }
1077
109
  function agentTranslate(instance, options) {
1078
110
  return getClientState(instance, {
1079
- apiVersion: API_VERSION$6,
111
+ apiVersion: API_VERSION$5,
1080
112
  projectId: instance.config.projectId,
1081
113
  dataset: instance.config.dataset
1082
114
  }).observable.pipe(switchMap((client) => client.observable.agent.action.translate(options)));
1083
115
  }
1084
116
  function agentPrompt(instance, options) {
1085
117
  return getClientState(instance, {
1086
- apiVersion: API_VERSION$6,
118
+ apiVersion: API_VERSION$5,
1087
119
  projectId: instance.config.projectId,
1088
120
  dataset: instance.config.dataset
1089
121
  }).observable.pipe(switchMap((client) => from(client.agent.action.prompt(options))));
1090
122
  }
1091
123
  function agentPatch(instance, options) {
1092
124
  return getClientState(instance, {
1093
- apiVersion: API_VERSION$6,
125
+ apiVersion: API_VERSION$5,
1094
126
  projectId: instance.config.projectId,
1095
127
  dataset: instance.config.dataset
1096
128
  }).observable.pipe(switchMap((client) => from(client.agent.action.patch(options))));
@@ -1107,7 +139,7 @@ function createFetcherStore({
1107
139
  fetchThrottleInternal = 1e3,
1108
140
  stateExpirationDelay = 5e3
1109
141
  }) {
1110
- const store = {
142
+ const store = defineStore({
1111
143
  name,
1112
144
  getInitialState: () => ({
1113
145
  stateByParams: {}
@@ -1116,7 +148,7 @@ function createFetcherStore({
1116
148
  const subscription = subscribeToSubscriptionsAndFetch(context);
1117
149
  return () => subscription.unsubscribe();
1118
150
  }
1119
- }, subscribeToSubscriptionsAndFetch = ({
151
+ }), subscribeToSubscriptionsAndFetch = ({
1120
152
  state
1121
153
  }) => state.observable.pipe(
1122
154
  // Map the state to an array of [serialized, entry] pairs.
@@ -1132,13 +164,13 @@ function createFetcherStore({
1132
164
  startWith([group$.key, void 0]),
1133
165
  pairwise(),
1134
166
  // Trigger only when the subscriptions array grows.
1135
- filter$1(([[, prevEntry], [, currEntry]]) => {
167
+ filter(([[, prevEntry], [, currEntry]]) => {
1136
168
  const prevSubs = prevEntry?.subscriptions ?? [];
1137
169
  return (currEntry?.subscriptions ?? []).length > prevSubs.length;
1138
170
  }),
1139
- map$1(([, [, currEntry]]) => currEntry),
171
+ map(([, [, currEntry]]) => currEntry),
1140
172
  // Only trigger if we haven't fetched recently.
1141
- filter$1((entry) => {
173
+ filter((entry) => {
1142
174
  const lastFetch = entry?.lastFetchInitiatedAt;
1143
175
  return lastFetch ? Date.now() - new Date(lastFetch).getTime() >= fetchThrottleInternal : !0;
1144
176
  }),
@@ -1160,8 +192,8 @@ function createFetcherStore({
1160
192
  stateByParams: {
1161
193
  ...prev.stateByParams,
1162
194
  [entry.key]: {
1163
- ...omit(entry, "error"),
1164
- ...omit(prev.stateByParams[entry.key], "error"),
195
+ ...omitProperty(entry, "error"),
196
+ ...prev.stateByParams[entry.key] ? omitProperty(prev.stateByParams[entry.key], "error") : {},
1165
197
  data
1166
198
  }
1167
199
  }
@@ -1208,12 +240,12 @@ function createFetcherStore({
1208
240
  }
1209
241
  }
1210
242
  })), () => {
1211
- setTimeout(() => {
243
+ setCleanupTimeout(() => {
1212
244
  state.set("removeSubscription", (prev) => {
1213
245
  const entry = prev.stateByParams[key];
1214
246
  if (!entry) return prev;
1215
247
  const newSubs = (entry.subscriptions || []).filter((id) => id !== subscriptionId);
1216
- return newSubs.length === 0 ? { stateByParams: omit(prev.stateByParams, key) } : {
248
+ return newSubs.length === 0 ? { stateByParams: omitProperty(prev.stateByParams, key) } : {
1217
249
  stateByParams: {
1218
250
  ...prev.stateByParams,
1219
251
  [key]: {
@@ -1233,7 +265,7 @@ function createFetcherStore({
1233
265
  );
1234
266
  return { getState, resolveState };
1235
267
  }
1236
- const API_VERSION$5 = "v2025-02-19", project = createFetcherStore({
268
+ const API_VERSION$4 = "v2025-02-19", project = createFetcherStore({
1237
269
  name: "Project",
1238
270
  getKey: (instance, options) => {
1239
271
  const projectId = options?.projectId ?? instance.config.projectId;
@@ -1244,7 +276,7 @@ const API_VERSION$5 = "v2025-02-19", project = createFetcherStore({
1244
276
  fetcher: (instance) => (options = {}) => {
1245
277
  const projectId = options.projectId ?? instance.config.projectId;
1246
278
  return getClientState(instance, {
1247
- apiVersion: API_VERSION$5,
279
+ apiVersion: API_VERSION$4,
1248
280
  scope: "global",
1249
281
  projectId
1250
282
  }).observable.pipe(
@@ -1263,7 +295,7 @@ const API_VERSION$5 = "v2025-02-19", project = createFetcherStore({
1263
295
  function observeOrganizationVerificationState(instance, projectIds) {
1264
296
  const dashboardOrgId$ = getDashboardOrganizationId(instance).observable.pipe(distinctUntilChanged()), projectOrgIdObservables = projectIds.map(
1265
297
  (id) => getProjectState(instance, { projectId: id }).observable.pipe(
1266
- map((project2) => ({ projectId: id, orgId: project2?.organizationId ?? null })),
298
+ map$1((project2) => ({ projectId: id, orgId: project2?.organizationId ?? null })),
1267
299
  // Ensure we only proceed if the orgId is loaded, distinct prevents unnecessary checks
1268
300
  distinctUntilChanged((prev, curr) => prev.orgId === curr.orgId)
1269
301
  )
@@ -1299,7 +331,7 @@ const handleAuthCallback = bindActionGlobally(
1299
331
  const cleanedUrl = getCleanedUrl(locationHref), tokenFromUrl = getTokenFromLocation(locationHref);
1300
332
  if (tokenFromUrl)
1301
333
  return state.set("setTokenFromUrl", {
1302
- authState: { type: AuthStateType.LOGGED_IN, token: tokenFromUrl, currentUser: null }
334
+ authState: createLoggedInAuthState(tokenFromUrl, null)
1303
335
  }), cleanedUrl;
1304
336
  const authCode = getAuthCode(callbackUrl, locationHref);
1305
337
  if (!authCode) return !1;
@@ -1320,7 +352,7 @@ const handleAuthCallback = bindActionGlobally(
1320
352
  });
1321
353
  try {
1322
354
  const client = clientFactory({
1323
- apiVersion: DEFAULT_API_VERSION$1,
355
+ apiVersion: DEFAULT_API_VERSION,
1324
356
  requestTagPrefix: REQUEST_TAG_PREFIX,
1325
357
  useProjectHostname: !1,
1326
358
  useCdn: !1,
@@ -1331,7 +363,7 @@ const handleAuthCallback = bindActionGlobally(
1331
363
  query: { sid: authCode },
1332
364
  tag: "fetch-token"
1333
365
  });
1334
- return storageArea?.setItem(storageKey, JSON.stringify({ token })), state.set("setToken", { authState: { type: AuthStateType.LOGGED_IN, token, currentUser: null } }), cleanedUrl;
366
+ return storageArea?.setItem(storageKey, JSON.stringify({ token })), state.set("setToken", { authState: createLoggedInAuthState(token, null) }), cleanedUrl;
1335
367
  } catch (error) {
1336
368
  return state.set("exchangeSessionForTokenError", { authState: { type: AuthStateType.ERROR, error } }), cleanedUrl;
1337
369
  }
@@ -1348,11 +380,11 @@ const handleAuthCallback = bindActionGlobally(
1348
380
  }), await clientFactory({
1349
381
  token,
1350
382
  requestTagPrefix: REQUEST_TAG_PREFIX,
1351
- apiVersion: DEFAULT_API_VERSION$1,
383
+ apiVersion: DEFAULT_API_VERSION,
1352
384
  ...apiHost && { apiHost },
1353
385
  useProjectHostname: !1,
1354
386
  useCdn: !1
1355
- }).request({ uri: "/auth/logout", method: "POST" }));
387
+ }).request({ uri: "/auth/logout", method: "POST", tag: "logout" }));
1356
388
  } finally {
1357
389
  state.set("logoutSuccess", {
1358
390
  authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
@@ -1370,7 +402,7 @@ const handleAuthCallback = bindActionGlobally(
1370
402
  throw new Error("Controller must be initialized before using or creating channels");
1371
403
  const channels = state.get().channels, existing = channels.get(options.name);
1372
404
  if (existing) {
1373
- if (!isEqual(existing.options, options))
405
+ if (!isDeepEqual(existing.options, options))
1374
406
  throw new Error(`Channel "${options.name}" already exists with different options`);
1375
407
  return state.set("incrementChannelRefCount", {
1376
408
  channels: new Map(channels).set(options.name, {
@@ -1408,7 +440,7 @@ const handleAuthCallback = bindActionGlobally(
1408
440
  })
1409
441
  });
1410
442
  }
1411
- }, comlinkControllerStore = {
443
+ }, comlinkControllerStore = defineStore({
1412
444
  name: "connectionStore",
1413
445
  getInitialState: () => ({
1414
446
  controller: null,
@@ -1420,7 +452,7 @@ const handleAuthCallback = bindActionGlobally(
1420
452
  destroyController(instance);
1421
453
  };
1422
454
  }
1423
- }, destroyController = bindActionGlobally(
455
+ }), destroyController = bindActionGlobally(
1424
456
  comlinkControllerStore,
1425
457
  destroyController$1
1426
458
  ), getOrCreateChannel = bindActionGlobally(
@@ -1432,7 +464,7 @@ const handleAuthCallback = bindActionGlobally(
1432
464
  ), releaseChannel = bindActionGlobally(comlinkControllerStore, releaseChannel$1), getOrCreateNode$1 = ({ state }, options) => {
1433
465
  const nodes = state.get().nodes, existing = nodes.get(options.name);
1434
466
  if (existing) {
1435
- if (!isEqual(existing.options, options))
467
+ if (!isDeepEqual(existing.options, options))
1436
468
  throw new Error(`Node "${options.name}" already exists with different options`);
1437
469
  return existing.node.start(), existing.node;
1438
470
  }
@@ -1461,7 +493,7 @@ const handleAuthCallback = bindActionGlobally(
1461
493
  existing.statusUnsub && existing.statusUnsub(), existing.node.stop(), nodes.delete(name), state.set("removeNode", { nodes });
1462
494
  return;
1463
495
  }
1464
- }, comlinkNodeStore = {
496
+ }, comlinkNodeStore = defineStore({
1465
497
  name: "nodeStore",
1466
498
  getInitialState: () => ({
1467
499
  nodes: /* @__PURE__ */ new Map(),
@@ -1474,7 +506,7 @@ const handleAuthCallback = bindActionGlobally(
1474
506
  });
1475
507
  };
1476
508
  }
1477
- }, releaseNode = bindActionGlobally(comlinkNodeStore, releaseNode$1), getOrCreateNode = bindActionGlobally(comlinkNodeStore, getOrCreateNode$1), NODE_RELEASE_TIME = 5e3, selectNode = (context, nodeInput) => context.state.nodes.get(nodeInput.name), getNodeState = bindActionGlobally(
509
+ }), releaseNode = bindActionGlobally(comlinkNodeStore, releaseNode$1), getOrCreateNode = bindActionGlobally(comlinkNodeStore, getOrCreateNode$1), NODE_RELEASE_TIME = 5e3, selectNode = (context, nodeInput) => context.state.nodes.get(nodeInput.name), getNodeState = bindActionGlobally(
1478
510
  comlinkNodeStore,
1479
511
  createStateSourceAction({
1480
512
  selector: createSelector([selectNode], (nodeEntry) => nodeEntry?.status === "connected" ? {
@@ -1486,7 +518,7 @@ const handleAuthCallback = bindActionGlobally(
1486
518
  getOrCreateNode(instance, nodeInput);
1487
519
  let subs = state.get().subscriptions.get(nodeName);
1488
520
  return subs || (subs = /* @__PURE__ */ new Set(), state.get().subscriptions.set(nodeName, subs)), subs.add(subscriberId), () => {
1489
- setTimeout(() => {
521
+ setCleanupTimeout(() => {
1490
522
  const activeSubs = state.get().subscriptions.get(nodeName);
1491
523
  activeSubs && (activeSubs.delete(subscriberId), activeSubs.size === 0 && (state.get().subscriptions.delete(nodeName), releaseNode(instance, nodeName)));
1492
524
  }, NODE_RELEASE_TIME);
@@ -1521,7 +553,7 @@ function configureLogging(config) {
1521
553
  source: "programmatic"
1522
554
  });
1523
555
  }
1524
- const API_VERSION$4 = "v2025-02-19", datasets = createFetcherStore({
556
+ const API_VERSION$3 = "v2025-02-19", datasets = createFetcherStore({
1525
557
  name: "Datasets",
1526
558
  getKey: (instance, options) => {
1527
559
  const projectId = options?.projectId ?? instance.config.projectId;
@@ -1530,27 +562,31 @@ const API_VERSION$4 = "v2025-02-19", datasets = createFetcherStore({
1530
562
  return projectId;
1531
563
  },
1532
564
  fetcher: (instance) => (options) => getClientState(instance, {
1533
- apiVersion: API_VERSION$4,
565
+ apiVersion: API_VERSION$3,
1534
566
  // non-null assertion is fine because we check above
1535
567
  projectId: options?.projectId ?? instance.config.projectId,
1536
568
  useProjectHostname: !0
1537
569
  }).observable.pipe(switchMap((client) => client.observable.datasets.list()))
1538
- }), getDatasetsState = datasets.getState, resolveDatasets = datasets.resolveState, isSanityMutatePatch = (value) => !(typeof value != "object" || !value || !("type" in value) || typeof value.type != "string" || value.type !== "patch" || !("id" in value) || typeof value.id != "string" || !("patches" in value) || !Array.isArray(value.patches));
570
+ }), getDatasetsState = datasets.getState, resolveDatasets = datasets.resolveState;
571
+ function getEffectiveDocumentId(doc) {
572
+ return doc.liveEdit ? doc.documentId : isReleasePerspective(doc.perspective) ? getVersionId(DocumentId(doc.documentId), doc.perspective.releaseName) : getPublishedId(DocumentId(doc.documentId));
573
+ }
574
+ const isSanityMutatePatch = (value) => !(typeof value != "object" || !value || !("type" in value) || typeof value.type != "string" || value.type !== "patch" || !("id" in value) || typeof value.id != "string" || !("patches" in value) || !Array.isArray(value.patches));
1539
575
  function createDocument(doc, initialValue) {
1540
- return {
576
+ let effectiveDocumentId;
577
+ return typeof doc.documentId == "string" && (effectiveDocumentId = getEffectiveDocumentId({ ...doc, documentId: doc.documentId })), {
1541
578
  type: "document.create",
1542
579
  ...doc,
1543
- ...doc.documentId && {
1544
- documentId: doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId)
1545
- },
580
+ ...effectiveDocumentId && { documentId: effectiveDocumentId },
1546
581
  ...initialValue && { initialValue }
1547
582
  };
1548
583
  }
1549
584
  function deleteDocument(doc) {
585
+ const effectiveDocumentId = getEffectiveDocumentId(doc);
1550
586
  return {
1551
587
  type: "document.delete",
1552
588
  ...doc,
1553
- documentId: doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId)
589
+ documentId: effectiveDocumentId
1554
590
  };
1555
591
  }
1556
592
  function convertSanityMutatePatch(sanityPatchMutation) {
@@ -1560,45 +596,48 @@ function convertSanityMutatePatch(sanityPatchMutation) {
1560
596
  });
1561
597
  }
1562
598
  function editDocument(doc, patches) {
1563
- const documentId = doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId);
599
+ const effectiveDocumentId = getEffectiveDocumentId(doc);
1564
600
  if (isSanityMutatePatch(patches)) {
1565
601
  const converted = convertSanityMutatePatch(patches) ?? [];
1566
602
  return {
1567
603
  ...doc,
1568
604
  type: "document.edit",
1569
- documentId,
605
+ documentId: effectiveDocumentId,
1570
606
  patches: converted
1571
607
  };
1572
608
  }
1573
609
  return {
1574
610
  ...doc,
1575
611
  type: "document.edit",
1576
- documentId,
612
+ documentId: effectiveDocumentId,
1577
613
  ...patches && { patches: Array.isArray(patches) ? patches : [patches] }
1578
614
  };
1579
615
  }
1580
616
  function publishDocument(doc) {
617
+ const effectiveDocumentId = getEffectiveDocumentId(doc);
1581
618
  return {
1582
619
  type: "document.publish",
1583
620
  ...doc,
1584
- documentId: doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId)
621
+ documentId: effectiveDocumentId
1585
622
  };
1586
623
  }
1587
624
  function unpublishDocument(doc) {
625
+ const effectiveDocumentId = getEffectiveDocumentId(doc);
1588
626
  return {
1589
627
  type: "document.unpublish",
1590
628
  ...doc,
1591
- documentId: doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId)
629
+ documentId: effectiveDocumentId
1592
630
  };
1593
631
  }
1594
632
  function discardDocument(doc) {
633
+ const effectiveDocumentId = getEffectiveDocumentId(doc);
1595
634
  return {
1596
635
  type: "document.discard",
1597
636
  ...doc,
1598
- documentId: doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId)
637
+ documentId: effectiveDocumentId
1599
638
  };
1600
639
  }
1601
- const DOCUMENT_STATE_CLEAR_DELAY = 1e3, INITIAL_OUTGOING_THROTTLE_TIME = 1e3, API_VERSION$3 = "v2025-05-06";
640
+ const DOCUMENT_STATE_CLEAR_DELAY = 1e3, INITIAL_OUTGOING_THROTTLE_TIME = 1e3, API_VERSION$2 = "v2025-05-06";
1602
641
  function generateArrayKey(length = 12) {
1603
642
  const numBytes = Math.ceil(length / 2), bytes = crypto.getRandomValues(new Uint8Array(numBytes));
1604
643
  return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, length);
@@ -1826,7 +865,7 @@ function processMutations({
1826
865
  throw new Error(
1827
866
  `Cannot create document with \`_id\` \`${id}\` because another document with the same ID already exists.`
1828
867
  );
1829
- const document2 = {
868
+ const document = {
1830
869
  // > `_createdAt` and `_updatedAt` may be submitted and will override
1831
870
  // > the default which is of course the current time. This can be used
1832
871
  // > to reconstruct a data-set with its timestamp structure intact.
@@ -1839,11 +878,11 @@ function processMutations({
1839
878
  _rev: transactionId,
1840
879
  _id: id
1841
880
  };
1842
- dataset[id] = document2;
881
+ dataset[id] = document;
1843
882
  continue;
1844
883
  }
1845
884
  if ("createOrReplace" in mutation) {
1846
- const id = getId(mutation.createOrReplace._id), prev = dataset[id], document2 = {
885
+ const id = getId(mutation.createOrReplace._id), prev = dataset[id], document = {
1847
886
  ...mutation.createOrReplace,
1848
887
  // otherwise, if the mutation provided, a `_createdAt` time, use it,
1849
888
  // otherwise default to now
@@ -1870,13 +909,13 @@ function processMutations({
1870
909
  _rev: transactionId,
1871
910
  _id: id
1872
911
  };
1873
- dataset[id] = document2;
912
+ dataset[id] = document;
1874
913
  continue;
1875
914
  }
1876
915
  if ("createIfNotExists" in mutation) {
1877
916
  const id = getId(mutation.createIfNotExists._id);
1878
917
  if (dataset[id]) continue;
1879
- const document2 = {
918
+ const document = {
1880
919
  // same logic as `create`:
1881
920
  // prefer the user's `_createdAt` and `_updatedAt`
1882
921
  _createdAt: now,
@@ -1885,7 +924,7 @@ function processMutations({
1885
924
  _rev: transactionId,
1886
925
  _id: id
1887
926
  };
1888
- dataset[id] = document2;
927
+ dataset[id] = document;
1889
928
  continue;
1890
929
  }
1891
930
  if ("delete" in mutation) {
@@ -2002,17 +1041,17 @@ const listen = ({ state }, documentId) => {
2002
1041
  const { sharedListener, fetchDocument } = state.get();
2003
1042
  return sharedListener.events.pipe(
2004
1043
  concatMap((e) => e.type === "welcome" ? fetchDocument(documentId).pipe(
2005
- map((document2) => ({ type: "sync", document: document2 }))
1044
+ map$1((document) => ({ type: "sync", document }))
2006
1045
  ) : e.type === "mutation" && e.documentId === documentId ? of(e) : EMPTY),
2007
1046
  sortListenerEvents(),
2008
1047
  withLatestFrom(
2009
1048
  state.observable.pipe(
2010
- map((s) => s.documentStates[documentId]),
2011
- filter(Boolean),
1049
+ map$1((s) => s.documentStates[documentId]),
1050
+ filter$1(Boolean),
2012
1051
  distinctUntilChanged()
2013
1052
  )
2014
1053
  ),
2015
- map(([next, documentState]) => {
1054
+ map$1(([next, documentState]) => {
2016
1055
  if (next.type === "sync")
2017
1056
  return {
2018
1057
  type: "sync",
@@ -2021,7 +1060,7 @@ const listen = ({ state }, documentId) => {
2021
1060
  revision: next.document?._rev,
2022
1061
  timestamp: next.document?._updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
2023
1062
  };
2024
- const [document2] = Object.values(
1063
+ const [document] = Object.values(
2025
1064
  processMutations({
2026
1065
  documents: { [documentId]: documentState.remote },
2027
1066
  mutations: next.mutations,
@@ -2032,7 +1071,7 @@ const listen = ({ state }, documentId) => {
2032
1071
  return {
2033
1072
  type: "mutation",
2034
1073
  documentId,
2035
- document: document2 ?? null,
1074
+ document: document ?? null,
2036
1075
  revision: transactionId,
2037
1076
  timestamp,
2038
1077
  ...previousRev && { previousRev }
@@ -2128,7 +1167,15 @@ const documentsCache = new MultiKeyWeakMap(), actionsCache = /* @__PURE__ */ new
2128
1167
  ],
2129
1168
  (documentStates, actions) => {
2130
1169
  const documentIds = new Set(
2131
- actions.map((action) => typeof action.documentId != "string" ? [] : action.liveEdit ? [action.documentId] : [getPublishedId(action.documentId), getDraftId(action.documentId)]).flat()
1170
+ actions.map((action) => {
1171
+ if (typeof action.documentId != "string") return [];
1172
+ if (action.liveEdit) return [action.documentId];
1173
+ const ids = [
1174
+ getPublishedId(DocumentId(action.documentId)),
1175
+ getDraftId(DocumentId(action.documentId))
1176
+ ];
1177
+ return isReleasePerspective(action.perspective) && ids.push(getVersionId(DocumentId(action.documentId), action.perspective.releaseName)), ids;
1178
+ }).flat()
2132
1179
  ), documents = {};
2133
1180
  for (const documentId of documentIds) {
2134
1181
  const local = documentStates[documentId]?.local;
@@ -2155,8 +1202,8 @@ const documentsCache = new MultiKeyWeakMap(), actionsCache = /* @__PURE__ */ new
2155
1202
  return nestedCache.get(actionsKey) || (nestedCache.set(actionsKey, normalizedActions), normalizedActions);
2156
1203
  }
2157
1204
  );
2158
- function checkGrant$1(grantExpr, document2) {
2159
- const value = evaluateSync(grantExpr, { params: { document: document2 } });
1205
+ function checkGrant$1(grantExpr, document) {
1206
+ const value = evaluateSync(grantExpr, { params: { document } });
2160
1207
  return value.type === "boolean" && value.data;
2161
1208
  }
2162
1209
  const enNarrowConjunction = new Intl.ListFormat("en", { style: "narrow", type: "conjunction" });
@@ -2199,11 +1246,16 @@ const _calculatePermissions = createSelector(
2199
1246
  }
2200
1247
  for (const action of actions)
2201
1248
  if (action.type === "document.edit" && !action.patches?.length) {
2202
- const docId = action.documentId, doc = action.liveEdit ? documents[docId] : documents[getDraftId(docId)] ?? documents[getPublishedId(docId)];
2203
- doc ? checkGrant$1(grants.update, doc) || reasons.push({
1249
+ const docId = action.documentId;
1250
+ let doc;
1251
+ action.liveEdit ? doc = documents[docId] : isReleasePerspective(action.perspective) ? doc = documents[getVersionId(DocumentId(docId), action.perspective.releaseName)] : doc = documents[getDraftId(DocumentId(docId))] ?? documents[getPublishedId(DocumentId(docId))], doc ? checkGrant$1(grants.update, doc) || reasons.push({
2204
1252
  type: "access",
2205
1253
  message: `You are not allowed to edit the document with ID "${docId}".`,
2206
1254
  documentId: docId
1255
+ }) : isReleasePerspective(action.perspective) ? reasons.push({
1256
+ type: "precondition",
1257
+ message: `The version document with ID "${docId}" could not be found. Please create it or add it to the release first.`,
1258
+ documentId: docId
2207
1259
  }) : reasons.push({
2208
1260
  type: "precondition",
2209
1261
  message: `The document with ID "${docId}" could not be found. Please check that it exists before editing.`,
@@ -2220,8 +1272,8 @@ const _calculatePermissions = createSelector(
2220
1272
  };
2221
1273
  }
2222
1274
  );
2223
- function checkGrant(grantExpr, document2) {
2224
- const value = evaluateSync(grantExpr, { params: { document: document2 } });
1275
+ function checkGrant(grantExpr, document) {
1276
+ const value = evaluateSync(grantExpr, { params: { document } });
2225
1277
  return value.type === "boolean" && value.data;
2226
1278
  }
2227
1279
  class ActionError extends Error {
@@ -2254,7 +1306,11 @@ function processActions({
2254
1306
  transactionId,
2255
1307
  message: "This document already exists."
2256
1308
  });
2257
- const newDocBase2 = { _type: action.documentType, _id: documentId }, newDocWorking2 = { _type: action.documentType, _id: documentId }, mutations2 = [{ create: newDocWorking2 }];
1309
+ const newDocBase2 = { _type: action.documentType, _id: documentId, ...action.initialValue }, mutations2 = [{ create: {
1310
+ _type: action.documentType,
1311
+ _id: documentId,
1312
+ ...action.initialValue
1313
+ } }];
2258
1314
  if (base = processMutations({
2259
1315
  documents: base,
2260
1316
  transactionId,
@@ -2271,29 +1327,27 @@ function processActions({
2271
1327
  transactionId,
2272
1328
  message: `You do not have permission to create document "${documentId}".`
2273
1329
  });
2274
- outgoingMutations.push(...mutations2), outgoingActions.push({
2275
- actionType: "sanity.action.document.create",
2276
- publishedId: documentId,
2277
- attributes: newDocWorking2
2278
- });
1330
+ outgoingMutations.push(...mutations2);
2279
1331
  continue;
2280
1332
  }
2281
- const draftId = getDraftId(documentId), publishedId = getPublishedId(documentId);
2282
- if (working[draftId])
1333
+ const versionId = isReleasePerspective(action.perspective) ? getVersionId(DocumentId(documentId), action.perspective.releaseName) : void 0, draftId = getDraftId(DocumentId(documentId)), publishedId = getPublishedId(DocumentId(documentId));
1334
+ if (versionId ? working[versionId] : working[draftId]) {
1335
+ const errorDocType = versionId ? "release version" : "draft";
2283
1336
  throw new ActionError({
2284
1337
  documentId,
2285
1338
  transactionId,
2286
- message: "A draft version of this document already exists. Please use or discard the existing draft before creating a new one."
1339
+ message: `A ${errorDocType} of this document already exists. Please use or discard the existing ${errorDocType} before creating a new one.`
2287
1340
  });
1341
+ }
2288
1342
  const newDocBase = {
2289
- ...base[publishedId],
1343
+ ...base[draftId] ?? base[publishedId],
2290
1344
  _type: action.documentType,
2291
- _id: draftId,
1345
+ _id: versionId ?? draftId,
2292
1346
  ...action.initialValue
2293
1347
  }, newDocWorking = {
2294
- ...working[publishedId],
1348
+ ...working[draftId] ?? working[publishedId],
2295
1349
  _type: action.documentType,
2296
- _id: draftId,
1350
+ _id: versionId ?? draftId,
2297
1351
  ...action.initialValue
2298
1352
  }, mutations = [{ create: newDocWorking }];
2299
1353
  if (base = processMutations({
@@ -2306,7 +1360,13 @@ function processActions({
2306
1360
  transactionId,
2307
1361
  mutations,
2308
1362
  timestamp
2309
- }), !checkGrant(grants.create, working[draftId]))
1363
+ }), versionId && !checkGrant(grants.create, working[versionId]))
1364
+ throw new PermissionActionError({
1365
+ documentId,
1366
+ transactionId,
1367
+ message: `You do not have permission to create a release version for document "${documentId}".`
1368
+ });
1369
+ if (!versionId && !checkGrant(grants.create, working[draftId]))
2310
1370
  throw new PermissionActionError({
2311
1371
  documentId,
2312
1372
  transactionId,
@@ -2321,6 +1381,12 @@ function processActions({
2321
1381
  }
2322
1382
  case "document.delete": {
2323
1383
  const documentId = action.documentId;
1384
+ if (isReleasePerspective(action.perspective))
1385
+ throw new ActionError({
1386
+ documentId,
1387
+ transactionId,
1388
+ message: 'Cannot delete a version document. You may want to use the "unpublish" or "discard" actions instead.'
1389
+ });
2324
1390
  if (action.liveEdit) {
2325
1391
  if (!working[documentId])
2326
1392
  throw new ActionError({
@@ -2335,13 +1401,10 @@ function processActions({
2335
1401
  message: "You do not have permission to delete this document."
2336
1402
  });
2337
1403
  const mutations2 = [{ delete: { id: documentId } }];
2338
- base = processMutations({ documents: base, transactionId, mutations: mutations2, timestamp }), working = processMutations({ documents: working, transactionId, mutations: mutations2, timestamp }), outgoingMutations.push(...mutations2), outgoingActions.push({
2339
- actionType: "sanity.action.document.delete",
2340
- publishedId: documentId
2341
- });
1404
+ base = processMutations({ documents: base, transactionId, mutations: mutations2, timestamp }), working = processMutations({ documents: working, transactionId, mutations: mutations2, timestamp }), outgoingMutations.push(...mutations2);
2342
1405
  continue;
2343
1406
  }
2344
- const draftId = getDraftId(documentId), publishedId = getPublishedId(documentId);
1407
+ const draftId = getDraftId(DocumentId(documentId)), publishedId = getPublishedId(DocumentId(documentId));
2345
1408
  if (!working[publishedId])
2346
1409
  throw new ActionError({
2347
1410
  documentId,
@@ -2371,14 +1434,14 @@ function processActions({
2371
1434
  transactionId,
2372
1435
  message: `Cannot discard changes for liveEdit document "${documentId}". LiveEdit documents do not support drafts.`
2373
1436
  });
2374
- const draftId = getDraftId(documentId), mutations = [{ delete: { id: draftId } }];
2375
- if (!working[draftId])
1437
+ const versionId = isReleasePerspective(action.perspective) ? getVersionId(DocumentId(documentId), action.perspective.releaseName) : getDraftId(DocumentId(documentId)), mutations = [{ delete: { id: versionId } }];
1438
+ if (!working[versionId])
2376
1439
  throw new ActionError({
2377
1440
  documentId,
2378
1441
  transactionId,
2379
- message: `There is no draft available to discard for document "${documentId}".`
1442
+ message: `There is no draft or version available to discard for document "${documentId}".`
2380
1443
  });
2381
- if (!checkGrant(grants.update, working[draftId]))
1444
+ if (!checkGrant(grants.update, working[versionId]))
2382
1445
  throw new PermissionActionError({
2383
1446
  documentId,
2384
1447
  transactionId,
@@ -2386,7 +1449,7 @@ function processActions({
2386
1449
  });
2387
1450
  base = processMutations({ documents: base, transactionId, mutations, timestamp }), working = processMutations({ documents: working, transactionId, mutations, timestamp }), outgoingMutations.push(...mutations), outgoingActions.push({
2388
1451
  actionType: "sanity.action.document.version.discard",
2389
- versionId: draftId
1452
+ versionId
2390
1453
  });
2391
1454
  continue;
2392
1455
  }
@@ -2421,38 +1484,37 @@ function processActions({
2421
1484
  transactionId,
2422
1485
  mutations: workingMutations2,
2423
1486
  timestamp
2424
- }), outgoingMutations.push(...workingMutations2), outgoingActions.push(
2425
- ...patches2.map(
2426
- (patch) => ({
2427
- actionType: "sanity.action.document.edit",
2428
- // Server requires draftId to have drafts. prefix for validation, even for liveEdit
2429
- draftId: getDraftId(documentId),
2430
- publishedId: documentId,
2431
- patch
2432
- })
2433
- )
2434
- );
1487
+ }), outgoingMutations.push(...workingMutations2);
2435
1488
  continue;
2436
1489
  }
2437
- const draftId = getDraftId(documentId), publishedId = getPublishedId(documentId), userPatches = action.patches?.map((patch) => ({ patch: { id: draftId, ...patch } }));
1490
+ const versionId = isReleasePerspective(action.perspective) ? getVersionId(DocumentId(documentId), action.perspective.releaseName) : void 0, draftId = getDraftId(DocumentId(documentId)), publishedId = getPublishedId(DocumentId(documentId)), patchDocumentId = isReleasePerspective(action.perspective) ? versionId : draftId, userPatches = action.patches?.map((patch) => ({
1491
+ patch: { id: patchDocumentId, ...patch }
1492
+ }));
2438
1493
  if (!userPatches?.length) continue;
2439
- if (!working[draftId] && !working[publishedId] || !base[draftId] && !base[publishedId])
1494
+ if (isReleasePerspective(action.perspective)) {
1495
+ if (!working[versionId] && !base[versionId])
1496
+ throw new ActionError({
1497
+ documentId,
1498
+ transactionId,
1499
+ message: "This document does not exist in the release. Please create it or add it to the release first."
1500
+ });
1501
+ } else if (!working[draftId] && !working[publishedId] || !base[draftId] && !base[publishedId])
2440
1502
  throw new ActionError({
2441
1503
  documentId,
2442
1504
  transactionId,
2443
1505
  message: "Cannot edit document because it does not exist in draft or published form."
2444
1506
  });
2445
1507
  const baseMutations = [];
2446
- !base[draftId] && base[publishedId] && baseMutations.push({ create: { ...base[publishedId], _id: draftId } });
2447
- const baseBefore = base[draftId] ?? base[publishedId];
1508
+ !isReleasePerspective(action.perspective) && !base[draftId] && base[publishedId] && baseMutations.push({ create: { ...base[publishedId], _id: draftId } });
1509
+ const baseBefore = base[patchDocumentId] ?? base[publishedId];
2448
1510
  userPatches && baseMutations.push(...userPatches), base = processMutations({
2449
1511
  documents: base,
2450
1512
  transactionId,
2451
1513
  mutations: baseMutations,
2452
1514
  timestamp
2453
1515
  });
2454
- const baseAfter = base[draftId], patches = diffValue(baseBefore, baseAfter), workingMutations = [];
2455
- if (!working[draftId] && working[publishedId]) {
1516
+ const baseAfter = base[patchDocumentId], patches = diffValue(baseBefore, baseAfter), workingMutations = [];
1517
+ if (!isReleasePerspective(action.perspective) && !working[draftId] && working[publishedId]) {
2456
1518
  const newDraftFromPublished = { ...working[publishedId], _id: draftId };
2457
1519
  if (!checkGrant(grants.create, newDraftFromPublished))
2458
1520
  throw new PermissionActionError({
@@ -2462,46 +1524,44 @@ function processActions({
2462
1524
  });
2463
1525
  workingMutations.push({ create: newDraftFromPublished });
2464
1526
  }
2465
- const workingBefore = working[draftId] ?? working[publishedId];
1527
+ const workingBefore = working[patchDocumentId] ?? working[publishedId];
2466
1528
  if (!checkGrant(grants.update, workingBefore))
2467
1529
  throw new PermissionActionError({
2468
1530
  documentId,
2469
1531
  transactionId,
2470
1532
  message: `You do not have permission to edit document "${documentId}".`
2471
1533
  });
2472
- workingMutations.push(...patches.map((patch) => ({ patch: { id: draftId, ...patch } }))), working = processMutations({
1534
+ workingMutations.push(...patches.map((patch) => ({ patch: { id: patchDocumentId, ...patch } }))), working = processMutations({
2473
1535
  documents: working,
2474
1536
  transactionId,
2475
1537
  mutations: workingMutations,
2476
1538
  timestamp
2477
1539
  }), outgoingMutations.push(...workingMutations), outgoingActions.push(
2478
- ...patches.map(
2479
- (patch) => ({
2480
- actionType: "sanity.action.document.edit",
2481
- draftId,
2482
- publishedId,
2483
- patch
2484
- })
2485
- )
1540
+ ...patches.map((patch) => ({
1541
+ actionType: "sanity.action.document.edit",
1542
+ draftId: patchDocumentId,
1543
+ publishedId,
1544
+ patch
1545
+ }))
2486
1546
  );
2487
1547
  continue;
2488
1548
  }
2489
1549
  case "document.publish": {
2490
1550
  const documentId = getId(action.documentId);
2491
- if (action.liveEdit)
1551
+ if (action.liveEdit || isReleasePerspective(action.perspective))
2492
1552
  throw new ActionError({
2493
1553
  documentId,
2494
1554
  transactionId,
2495
- message: `Cannot publish liveEdit document "${documentId}". LiveEdit documents do not support drafts or publishing.`
1555
+ message: "Cannot publish this document. Publishing is not supported for liveEdit or version (release) documents."
2496
1556
  });
2497
- const draftId = getDraftId(documentId), publishedId = getPublishedId(documentId), workingDraft = working[draftId], baseDraft = base[draftId];
1557
+ const draftId = getDraftId(DocumentId(documentId)), publishedId = getPublishedId(DocumentId(documentId)), workingDraft = working[draftId], baseDraft = base[draftId];
2498
1558
  if (!workingDraft || !baseDraft)
2499
1559
  throw new ActionError({
2500
1560
  documentId,
2501
1561
  transactionId,
2502
1562
  message: `Cannot publish because no draft version was found for document "${documentId}".`
2503
1563
  });
2504
- if (!isEqual(workingDraft, baseDraft))
1564
+ if (!isDeepEqual(workingDraft, baseDraft))
2505
1565
  throw new ActionError({
2506
1566
  documentId,
2507
1567
  transactionId,
@@ -2538,13 +1598,13 @@ function processActions({
2538
1598
  }
2539
1599
  case "document.unpublish": {
2540
1600
  const documentId = getId(action.documentId);
2541
- if (action.liveEdit)
1601
+ if (action.liveEdit || isReleasePerspective(action.perspective))
2542
1602
  throw new ActionError({
2543
1603
  documentId,
2544
1604
  transactionId,
2545
- message: `Cannot unpublish liveEdit document "${documentId}". LiveEdit documents do not support drafts or publishing.`
1605
+ message: "Cannot unpublish this document. Unpublishing is not supported for liveEdit or version (release) documents."
2546
1606
  });
2547
- const draftId = getDraftId(documentId), publishedId = getPublishedId(documentId);
1607
+ const draftId = getDraftId(DocumentId(documentId)), publishedId = getPublishedId(DocumentId(documentId));
2548
1608
  if (!working[publishedId] && !base[publishedId])
2549
1609
  throw new ActionError({
2550
1610
  documentId,
@@ -2618,7 +1678,7 @@ const EMPTY_REVISIONS = {};
2618
1678
  function queueTransaction(prev, transaction) {
2619
1679
  const { transactionId, actions } = transaction;
2620
1680
  return {
2621
- ...getDocumentIdsFromActions(actions).reduce(
1681
+ ...getDocumentIdsFromHandleLikes(actions).reduce(
2622
1682
  (acc, id) => addSubscriptionIdToDocument(acc, id, transactionId),
2623
1683
  prev
2624
1684
  ),
@@ -2628,7 +1688,7 @@ function queueTransaction(prev, transaction) {
2628
1688
  function removeQueuedTransaction(prev, transactionId) {
2629
1689
  const transaction = prev.queued.find((t) => t.transactionId === transactionId);
2630
1690
  return transaction ? {
2631
- ...getDocumentIdsFromActions(transaction.actions).reduce(
1691
+ ...getDocumentIdsFromHandleLikes(transaction.actions).reduce(
2632
1692
  (acc, id) => removeSubscriptionIdFromDocument(acc, id, transactionId),
2633
1693
  prev
2634
1694
  ),
@@ -2638,7 +1698,7 @@ function removeQueuedTransaction(prev, transactionId) {
2638
1698
  function applyFirstQueuedTransaction(prev) {
2639
1699
  const queued = prev.queued.at(0);
2640
1700
  if (!queued || !prev.grants) return prev;
2641
- const ids = getDocumentIdsFromActions(queued.actions);
1701
+ const ids = getDocumentIdsFromHandleLikes(queued.actions);
2642
1702
  if (ids.some((id) => prev.documentStates[id]?.local === void 0)) return prev;
2643
1703
  const working = ids.reduce((acc, id) => (acc[id] = prev.documentStates[id]?.local, acc), {}), timestamp = (/* @__PURE__ */ new Date()).toISOString(), result = processActions({
2644
1704
  ...queued,
@@ -2690,7 +1750,7 @@ function batchAppliedTransactions([curr, ...rest]) {
2690
1750
  if (!rest.length) return editAction;
2691
1751
  const next = batchAppliedTransactions(rest);
2692
1752
  if (next)
2693
- return next.disableBatching ? editAction : {
1753
+ return next.disableBatching || !!action.liveEdit != !!next.actions[0]?.liveEdit ? editAction : {
2694
1754
  disableBatching: !1,
2695
1755
  // Use the transactionId from the later (next) transaction.
2696
1756
  transactionId: next.transactionId,
@@ -2748,7 +1808,7 @@ function cleanupOutgoingTransaction(prev) {
2748
1808
  const { outgoing } = prev;
2749
1809
  if (!outgoing) return prev;
2750
1810
  let next = prev;
2751
- const ids = getDocumentIdsFromActions(outgoing.actions);
1811
+ const ids = getDocumentIdsFromHandleLikes(outgoing.actions);
2752
1812
  for (const transactionId of outgoing.batchedTransactionIds)
2753
1813
  for (const documentId of ids)
2754
1814
  next = removeSubscriptionIdFromDocument(next, documentId, transactionId);
@@ -2780,20 +1840,20 @@ function revertOutgoingTransaction(prev) {
2780
1840
  const next = {
2781
1841
  ...documentState,
2782
1842
  local: documentId in working ? working[documentId] : local,
2783
- unverifiedRevisions: prev.outgoing && prev.outgoing.transactionId in unverifiedRevisions ? omit(unverifiedRevisions, prev.outgoing.transactionId) : unverifiedRevisions
1843
+ unverifiedRevisions: prev.outgoing && prev.outgoing.transactionId in unverifiedRevisions ? omitProperty(unverifiedRevisions, prev.outgoing.transactionId) : unverifiedRevisions
2784
1844
  };
2785
1845
  return [documentId, next];
2786
1846
  })
2787
1847
  )
2788
1848
  };
2789
1849
  }
2790
- function applyRemoteDocument(prev, { document: document2, documentId, previousRev, revision, timestamp, type }, events) {
1850
+ function applyRemoteDocument(prev, { document, documentId, previousRev, revision, timestamp, type }, events) {
2791
1851
  if (!prev.grants) return prev;
2792
1852
  const prevDocState = prev.documentStates[documentId];
2793
1853
  if (!prevDocState) return prev;
2794
1854
  const prevUnverifiedRevisions = prevDocState.unverifiedRevisions, revisionToVerify = revision ? prevUnverifiedRevisions?.[revision] : void 0;
2795
1855
  let unverifiedRevisions = prevUnverifiedRevisions ?? EMPTY_REVISIONS;
2796
- if (revision && revisionToVerify && (unverifiedRevisions = omit(prevUnverifiedRevisions, revision)), type === "sync" && (unverifiedRevisions = Object.fromEntries(
1856
+ if (revision && revisionToVerify && (unverifiedRevisions = omitProperty(prevUnverifiedRevisions, revision)), type === "sync" && (unverifiedRevisions = Object.fromEntries(
2797
1857
  Object.entries(unverifiedRevisions).filter(([, unverifiedRevision]) => unverifiedRevision ? new Date(timestamp).getTime() <= new Date(unverifiedRevision.timestamp).getTime() : !1)
2798
1858
  )), revisionToVerify && revisionToVerify.previousRev === previousRev)
2799
1859
  return {
@@ -2802,13 +1862,13 @@ function applyRemoteDocument(prev, { document: document2, documentId, previousRe
2802
1862
  ...prev.documentStates,
2803
1863
  [documentId]: {
2804
1864
  ...prevDocState,
2805
- remote: document2,
1865
+ remote: document,
2806
1866
  remoteRev: revision,
2807
1867
  unverifiedRevisions
2808
1868
  }
2809
1869
  }
2810
1870
  };
2811
- let working = { ...prev.applied.at(0)?.previous, [documentId]: document2 };
1871
+ let working = { ...prev.applied.at(0)?.previous, [documentId]: document };
2812
1872
  const nextApplied = [];
2813
1873
  for (const curr of prev.applied)
2814
1874
  try {
@@ -2834,7 +1894,7 @@ function applyRemoteDocument(prev, { document: document2, documentId, previousRe
2834
1894
  ...prev.documentStates,
2835
1895
  [documentId]: {
2836
1896
  ...prevDocState,
2837
- remote: document2,
1897
+ remote: document,
2838
1898
  remoteRev: revision,
2839
1899
  local: working[documentId],
2840
1900
  unverifiedRevisions
@@ -2864,17 +1924,10 @@ function removeSubscriptionIdFromDocument(prev, documentId, subscriptionId) {
2864
1924
  ...prev.documentStates,
2865
1925
  [documentId]: { ...prevDocState, subscriptions }
2866
1926
  }
2867
- } : { ...prev, documentStates: omit(prev.documentStates, documentId) } : prev;
1927
+ } : { ...prev, documentStates: omitProperty(prev.documentStates, documentId) } : prev;
2868
1928
  }
2869
- function manageSubscriberIds({ state }, documentId, options) {
2870
- const expandDraftPublished = options?.expandDraftPublished ?? !0, documentIds = Array.from(
2871
- new Set(
2872
- expandDraftPublished ? (Array.isArray(documentId) ? documentId : [documentId]).flatMap((id) => [
2873
- getPublishedId$1(id),
2874
- getDraftId(id)
2875
- ]) : Array.isArray(documentId) ? documentId : [documentId]
2876
- )
2877
- ), subscriptionId = insecureRandomId();
1929
+ function manageSubscriberIds({ state }, handles) {
1930
+ const documentIds = getDocumentIdsFromHandleLikes(handles), subscriptionId = insecureRandomId();
2878
1931
  return state.set(
2879
1932
  "addSubscribers",
2880
1933
  (prev) => documentIds.reduce(
@@ -2882,7 +1935,7 @@ function manageSubscriberIds({ state }, documentId, options) {
2882
1935
  prev
2883
1936
  )
2884
1937
  ), () => {
2885
- setTimeout(() => {
1938
+ setCleanupTimeout(() => {
2886
1939
  state.set(
2887
1940
  "removeSubscribers",
2888
1941
  (prev) => documentIds.reduce(
@@ -2893,12 +1946,13 @@ function manageSubscriberIds({ state }, documentId, options) {
2893
1946
  }, DOCUMENT_STATE_CLEAR_DELAY);
2894
1947
  };
2895
1948
  }
2896
- function getDocumentIdsFromActions(actions) {
2897
- return Array.from(
2898
- new Set(
2899
- actions.map((i) => i.documentId).filter((i) => typeof i == "string").flatMap((documentId) => [getPublishedId$1(documentId), getDraftId(documentId)])
2900
- )
2901
- );
1949
+ function getDocumentIdsFromHandleLikes(handles) {
1950
+ return handles.flatMap((handle) => {
1951
+ const idsForDocument = [];
1952
+ return handle.documentId ? handle.liveEdit ? [handle.documentId] : (isReleasePerspective(handle.perspective) && idsForDocument.push(
1953
+ getVersionId(DocumentId(handle.documentId), handle.perspective.releaseName)
1954
+ ), idsForDocument.push(getPublishedId(DocumentId(handle.documentId))), idsForDocument.push(getDraftId(DocumentId(handle.documentId))), idsForDocument) : [];
1955
+ });
2902
1956
  }
2903
1957
  function getDocumentEvents(outgoing) {
2904
1958
  const documentIdsByAction = Object.entries(
@@ -2923,10 +1977,12 @@ function getDocumentEvents(outgoing) {
2923
1977
  )
2924
1978
  );
2925
1979
  }
2926
- const API_VERSION$2 = "v2025-05-06";
2927
- function createSharedListener(instance) {
1980
+ const API_VERSION$1 = "v2025-05-06";
1981
+ function createSharedListener(instance, resource) {
2928
1982
  const dispose$ = new Subject(), events$ = getClientState(instance, {
2929
- apiVersion: API_VERSION$2
1983
+ apiVersion: API_VERSION$1,
1984
+ // TODO: remove in v3 when we're ready for everything to be queried via resource
1985
+ resource: resource && !isDatasetResource(resource) ? resource : void 0
2930
1986
  }).observable.pipe(
2931
1987
  switchMap(
2932
1988
  (client) => (
@@ -2960,11 +2016,15 @@ function createSharedListener(instance) {
2960
2016
  dispose: () => dispose$.next()
2961
2017
  };
2962
2018
  }
2963
- function createFetchDocument(instance) {
2019
+ function createFetchDocument(instance, resource) {
2964
2020
  return function(documentId) {
2965
- return getClientState(instance, { apiVersion: API_VERSION$2 }).observable.pipe(
2021
+ return getClientState(instance, {
2022
+ apiVersion: API_VERSION$1,
2023
+ // TODO: remove in v3 when we're ready for everything to be queried via resource
2024
+ resource: resource && !isDatasetResource(resource) ? resource : void 0
2025
+ }).observable.pipe(
2966
2026
  switchMap((client) => createDocumentLoaderFromClient(client)(documentId)),
2967
- map((result) => {
2027
+ map$1((result) => {
2968
2028
  if (!result.accessible) {
2969
2029
  if (result.reason === "existence") return null;
2970
2030
  throw new Error(`Document with ID \`${documentId}\` is inaccessible due to permissions.`);
@@ -2975,15 +2035,15 @@ function createFetchDocument(instance) {
2975
2035
  );
2976
2036
  };
2977
2037
  }
2978
- const documentStore = {
2038
+ const documentStore = defineStore({
2979
2039
  name: "Document",
2980
- getInitialState: (instance) => ({
2040
+ getInitialState: (instance, { resource }) => ({
2981
2041
  documentStates: {},
2982
2042
  // these can be emptied on refetch
2983
2043
  queued: [],
2984
2044
  applied: [],
2985
- sharedListener: createSharedListener(instance),
2986
- fetchDocument: createFetchDocument(instance),
2045
+ sharedListener: createSharedListener(instance, resource),
2046
+ fetchDocument: createFetchDocument(instance, resource),
2987
2047
  events: new Subject()
2988
2048
  }),
2989
2049
  initialize(context) {
@@ -2997,83 +2057,92 @@ const documentStore = {
2997
2057
  sharedListener.dispose(), subscriptions.forEach((subscription) => subscription.unsubscribe());
2998
2058
  };
2999
2059
  }
3000
- };
2060
+ });
3001
2061
  function getDocumentState(...args) {
3002
2062
  return _getDocumentState(...args);
3003
2063
  }
3004
- const _getDocumentState = bindActionByDataset(
2064
+ const _getDocumentState = bindActionByResource(
3005
2065
  documentStore,
3006
2066
  createStateSourceAction({
3007
2067
  selector: ({ state: { error, documentStates } }, options) => {
3008
- const { documentId, path, liveEdit } = options;
2068
+ const { documentId: docId, path, liveEdit, perspective } = options, documentId = DocumentId(docId);
3009
2069
  if (error) throw error;
3010
- if (liveEdit) {
3011
- const document22 = documentStates[documentId]?.local;
3012
- if (document22 === void 0) return;
3013
- if (!path) return document22;
3014
- const result2 = jsonMatch(document22, path).next();
3015
- if (result2.done) return;
3016
- const { value: value2 } = result2.value;
3017
- return value2;
2070
+ let document;
2071
+ if (liveEdit)
2072
+ document = documentStates[documentId]?.local;
2073
+ else {
2074
+ let version;
2075
+ if (isReleasePerspective(perspective)) {
2076
+ const versionId = getVersionId(documentId, perspective.releaseName);
2077
+ if (version = documentStates[versionId]?.local, version === void 0) return;
2078
+ }
2079
+ const draft = documentStates[getDraftId(documentId)]?.local, published = documentStates[getPublishedId(documentId)]?.local;
2080
+ if (draft === void 0 || published === void 0) return;
2081
+ document = version ?? draft ?? published;
3018
2082
  }
3019
- const draftId = getDraftId(documentId), publishedId = getPublishedId$1(documentId), draft = documentStates[draftId]?.local, published = documentStates[publishedId]?.local;
3020
- if (draft === void 0 || published === void 0) return;
3021
- const document2 = draft ?? published;
3022
- if (!path) return document2;
3023
- const result = jsonMatch(document2, path).next();
2083
+ if (!path) return document;
2084
+ const result = jsonMatch(document, path).next();
3024
2085
  if (result.done) return;
3025
2086
  const { value } = result.value;
3026
2087
  return value;
3027
2088
  },
3028
- onSubscribe: (context, options) => manageSubscriberIds(context, options.documentId, { expandDraftPublished: !options.liveEdit })
2089
+ onSubscribe: (context, options) => manageSubscriberIds(context, [options])
3029
2090
  })
3030
2091
  );
3031
2092
  function resolveDocument(...args) {
3032
2093
  return _resolveDocument(...args);
3033
2094
  }
3034
- const _resolveDocument = bindActionByDataset(
2095
+ const _resolveDocument = bindActionByResource(
3035
2096
  documentStore,
3036
2097
  ({ instance }, docHandle) => firstValueFrom(
3037
2098
  getDocumentState(instance, {
3038
2099
  ...docHandle,
3039
2100
  path: void 0
3040
- }).observable.pipe(filter((i) => i !== void 0))
2101
+ }).observable.pipe(filter$1((i) => i !== void 0))
3041
2102
  )
3042
- ), getDocumentSyncStatus = bindActionByDataset(
2103
+ ), getDocumentSyncStatus = bindActionByResource(
3043
2104
  documentStore,
3044
2105
  createStateSourceAction({
3045
2106
  selector: ({ state: { error, documentStates: documents, outgoing, applied, queued } }, doc) => {
3046
- const documentId = typeof doc == "string" ? doc : doc.documentId;
2107
+ const documentId = DocumentId(typeof doc == "string" ? doc : doc.documentId);
3047
2108
  if (error) throw error;
3048
- if (doc.liveEdit)
3049
- return documents[documentId] === void 0 ? void 0 : !queued.length && !applied.length && !outgoing;
3050
- const draftId = getDraftId(documentId), publishedId = getPublishedId$1(documentId), draft = documents[draftId], published = documents[publishedId];
3051
- if (!(draft === void 0 || published === void 0))
3052
- return !queued.length && !applied.length && !outgoing;
2109
+ if (doc.liveEdit) {
2110
+ if (documents[documentId] === void 0) return;
2111
+ } else {
2112
+ const version = isReleasePerspective(doc.perspective) ? documents[getVersionId(documentId, doc.perspective.releaseName)] : void 0;
2113
+ if (isReleasePerspective(doc.perspective) && version === void 0) return;
2114
+ const draft = documents[getDraftId(documentId)], published = documents[getPublishedId(documentId)];
2115
+ if (draft === void 0 || published === void 0) return;
2116
+ }
2117
+ return !queued.length && !applied.length && !outgoing;
3053
2118
  },
3054
- onSubscribe: (context, doc) => manageSubscriberIds(context, doc.documentId)
2119
+ onSubscribe: (context, doc) => manageSubscriberIds(context, [doc])
3055
2120
  })
3056
- ), getPermissionsState = bindActionByDataset(
2121
+ ), getPermissionsState = bindActionByResource(
3057
2122
  documentStore,
3058
2123
  createStateSourceAction({
3059
2124
  selector: calculatePermissions,
3060
- onSubscribe: (context, { actions }) => manageSubscriberIds(context, getDocumentIdsFromActions(actions))
2125
+ onSubscribe: (context, { actions }) => {
2126
+ manageSubscriberIds(context, actions);
2127
+ }
3061
2128
  })
3062
- ), resolvePermissions = bindActionByDataset(
2129
+ ), resolvePermissions = bindActionByResource(
3063
2130
  documentStore,
3064
2131
  ({ instance }, options) => firstValueFrom(
3065
- getPermissionsState(instance, options).observable.pipe(filter((i) => i !== void 0))
2132
+ getPermissionsState(instance, options).observable.pipe(filter$1((i) => i !== void 0))
3066
2133
  )
3067
- ), subscribeDocumentEvents = bindActionByDataset(
2134
+ ), subscribeDocumentEvents = bindActionByResource(
3068
2135
  documentStore,
3069
- ({ state }, eventHandler) => {
3070
- const { events } = state.get(), subscription = events.subscribe(eventHandler);
2136
+ ({ state }, options) => {
2137
+ const { events } = state.get(), subscription = events.subscribe(options.eventHandler);
3071
2138
  return () => subscription.unsubscribe();
3072
2139
  }
3073
- ), subscribeToQueuedAndApplyNextTransaction = ({ state }) => {
2140
+ ), subscribeToQueuedAndApplyNextTransaction = ({
2141
+ state
2142
+ }) => {
3074
2143
  const { events } = state.get();
3075
2144
  return state.observable.pipe(
3076
- map(applyFirstQueuedTransaction),
2145
+ map$1(applyFirstQueuedTransaction),
3077
2146
  distinctUntilChanged(),
3078
2147
  tap$1((next) => state.set("applyFirstQueuedTransaction", next)),
3079
2148
  catchError$1((error, caught) => {
@@ -3093,7 +2162,8 @@ const _resolveDocument = bindActionByDataset(
3093
2162
  ).subscribe({ error: (error) => state.set("setError", { error }) });
3094
2163
  }, subscribeToAppliedAndSubmitNextTransaction = ({
3095
2164
  state,
3096
- instance
2165
+ instance,
2166
+ key: { resource }
3097
2167
  }) => {
3098
2168
  const { events } = state.get();
3099
2169
  return state.observable.pipe(
@@ -3108,19 +2178,41 @@ const _resolveDocument = bindActionByDataset(
3108
2178
  ),
3109
2179
  { leading: !1, trailing: !0 }
3110
2180
  ),
3111
- map(transitionAppliedTransactionsToOutgoing),
2181
+ map$1(transitionAppliedTransactionsToOutgoing),
3112
2182
  distinctUntilChanged((a, b) => a.outgoing?.transactionId === b.outgoing?.transactionId),
3113
2183
  tap$1((next) => state.set("transitionAppliedTransactionsToOutgoing", next)),
3114
- map((s) => s.outgoing),
2184
+ map$1((s) => s.outgoing),
3115
2185
  distinctUntilChanged(),
3116
- withLatestFrom(getClientState(instance, { apiVersion: API_VERSION$3 }).observable),
3117
- concatMap(([outgoing, client]) => outgoing ? client.observable.action(outgoing.outgoingActions, {
3118
- transactionId: outgoing.transactionId,
3119
- skipCrossDatasetReferenceValidation: !0
3120
- }).pipe(
3121
- catchError$1((error) => (state.set("revertOutgoingTransaction", revertOutgoingTransaction), events.next({ type: "reverted", message: error.message, outgoing, error }), EMPTY)),
3122
- map((result) => ({ result, outgoing }))
3123
- ) : EMPTY),
2186
+ withLatestFrom(
2187
+ getClientState(instance, {
2188
+ apiVersion: API_VERSION$2,
2189
+ // TODO: remove in v3 when we're ready for everything to be queried via resource
2190
+ resource: resource && !isDatasetResource(resource) ? resource : void 0
2191
+ }).observable
2192
+ ),
2193
+ concatMap(([outgoing, client]) => {
2194
+ if (!outgoing) return EMPTY;
2195
+ const revertOnError = catchError$1((error) => {
2196
+ state.set("revertOutgoingTransaction", revertOutgoingTransaction);
2197
+ const message = error instanceof Error ? error.message : "Request failed";
2198
+ return events.next({ type: "reverted", message, outgoing, error }), EMPTY;
2199
+ }), toResult = map$1((result) => ({
2200
+ result,
2201
+ outgoing
2202
+ }));
2203
+ return outgoing.actions.some((action) => action.liveEdit) ? client.observable.mutate(outgoing.outgoingMutations, {
2204
+ transactionId: outgoing.transactionId,
2205
+ visibility: "async",
2206
+ returnDocuments: !1,
2207
+ returnFirst: !1,
2208
+ tag: "document.mutate",
2209
+ skipCrossDatasetReferenceValidation: !0
2210
+ }).pipe(revertOnError, toResult) : client.observable.action(outgoing.outgoingActions, {
2211
+ transactionId: outgoing.transactionId,
2212
+ skipCrossDatasetReferenceValidation: !0,
2213
+ tag: "document.action"
2214
+ }).pipe(revertOnError, toResult);
2215
+ }),
3124
2216
  tap$1(({ outgoing, result }) => {
3125
2217
  state.set("cleanupOutgoingTransaction", cleanupOutgoingTransaction);
3126
2218
  for (const e of getDocumentEvents(outgoing)) events.next(e);
@@ -3130,8 +2222,8 @@ const _resolveDocument = bindActionByDataset(
3130
2222
  }, subscribeToSubscriptionsAndListenToDocuments = (context) => {
3131
2223
  const { state } = context, { events } = state.get();
3132
2224
  return state.observable.pipe(
3133
- filter((s) => !!s.grants),
3134
- map((s) => Object.keys(s.documentStates)),
2225
+ filter$1((s) => !!s.grants),
2226
+ map$1((s) => Object.keys(s.documentStates)),
3135
2227
  distinctUntilChanged((curr, next) => {
3136
2228
  if (curr.length !== next.length) return !1;
3137
2229
  const currSet = new Set(curr);
@@ -3144,7 +2236,7 @@ const _resolveDocument = bindActionByDataset(
3144
2236
  ...added.map((id) => ({ id, add: !0 })),
3145
2237
  ...removed.map((id) => ({ id, add: !1 }))
3146
2238
  ].sort((a, b) => {
3147
- const aIsDraft = a.id === getDraftId(a.id), bIsDraft = b.id === getDraftId(b.id);
2239
+ const aIsDraft = a.id === getDraftId(DocumentId(a.id)), bIsDraft = b.id === getDraftId(DocumentId(b.id));
3148
2240
  return aIsDraft && bIsDraft ? a.id.localeCompare(b.id, "en-US") : aIsDraft ? -1 : bIsDraft ? 1 : a.id.localeCompare(b.id, "en-US");
3149
2241
  });
3150
2242
  return of(...changes);
@@ -3169,45 +2261,58 @@ const _resolveDocument = bindActionByDataset(
3169
2261
  }, subscribeToClientAndFetchDatasetAcl = ({
3170
2262
  instance,
3171
2263
  state,
3172
- key: { projectId, dataset }
3173
- }) => getClientState(instance, { apiVersion: API_VERSION$3 }).observable.pipe(
3174
- switchMap(
3175
- (client) => client.observable.request({
3176
- uri: `/projects/${projectId}/datasets/${dataset}/acl`,
3177
- tag: "acl.get",
3178
- withCredentials: !0
3179
- })
3180
- ),
3181
- tap$1((datasetAcl) => state.set("setGrants", { grants: createGrantsLookup(datasetAcl) }))
3182
- ).subscribe({
3183
- error: (error) => state.set("setError", { error })
3184
- });
2264
+ key: { resource }
2265
+ }) => {
2266
+ const clientOptions = { apiVersion: API_VERSION$2 };
2267
+ resource && !isDatasetResource(resource) && (clientOptions.resource = resource);
2268
+ let uri;
2269
+ if (resource && isDatasetResource(resource))
2270
+ uri = `/projects/${resource.projectId}/datasets/${resource.dataset}/acl`;
2271
+ else if (resource && isMediaLibraryResource(resource))
2272
+ uri = `/media-libraries/${resource.mediaLibraryId}/acl`;
2273
+ else if (resource && isCanvasResource(resource))
2274
+ uri = `/canvases/${resource.canvasId}/acl`;
2275
+ else
2276
+ throw new Error(`Received invalid resource: ${JSON.stringify(resource)}`);
2277
+ return getClientState(instance, clientOptions).observable.pipe(
2278
+ switchMap(
2279
+ (client) => client.observable.request({
2280
+ uri,
2281
+ tag: "acl.get",
2282
+ withCredentials: !0
2283
+ })
2284
+ ),
2285
+ tap$1((datasetAcl) => state.set("setGrants", { grants: createGrantsLookup(datasetAcl) }))
2286
+ ).subscribe({
2287
+ error: (error) => state.set("setError", { error })
2288
+ });
2289
+ };
3185
2290
  function applyDocumentActions(...args) {
3186
2291
  return boundApplyDocumentActions(...args);
3187
2292
  }
3188
- const boundApplyDocumentActions = bindActionByDataset(documentStore, _applyDocumentActions);
2293
+ const boundApplyDocumentActions = bindActionByResource(documentStore, _applyDocumentActions);
3189
2294
  async function _applyDocumentActions({ state }, { actions, transactionId = crypto.randomUUID(), disableBatching }) {
3190
2295
  const { events } = state.get(), transaction = {
3191
2296
  transactionId,
3192
2297
  actions,
3193
2298
  ...disableBatching && { disableBatching }
3194
2299
  }, fatalError$ = state.observable.pipe(
3195
- map((s) => s.error),
2300
+ map$1((s) => s.error),
3196
2301
  first$1(Boolean),
3197
- map((error) => ({ type: "error", error }))
2302
+ map$1((error) => ({ type: "error", error }))
3198
2303
  ), transactionError$ = events.pipe(
3199
- filter((e) => e.type === "error"),
2304
+ filter$1((e) => e.type === "error"),
3200
2305
  first$1((e) => e.transactionId === transactionId)
3201
2306
  ), appliedTransaction$ = state.observable.pipe(
3202
- map((s) => s.applied),
2307
+ map$1((s) => s.applied),
3203
2308
  distinctUntilChanged(),
3204
- map((applied) => applied.find((t) => t.transactionId === transactionId)),
2309
+ map$1((applied) => applied.find((t) => t.transactionId === transactionId)),
3205
2310
  first$1(Boolean)
3206
2311
  ), successfulTransaction$ = events.pipe(
3207
- filter((e) => e.type === "accepted"),
2312
+ filter$1((e) => e.type === "accepted"),
3208
2313
  first$1((e) => e.outgoing.batchedTransactionIds.includes(transactionId))
3209
2314
  ), rejectedTransaction$ = events.pipe(
3210
- filter((e) => e.type === "reverted"),
2315
+ filter$1((e) => e.type === "reverted"),
3211
2316
  first$1((e) => e.outgoing.batchedTransactionIds.includes(transactionId))
3212
2317
  ), appliedTransactionOrError = firstValueFrom(
3213
2318
  race([fatalError$, transactionError$, appliedTransaction$])
@@ -3262,7 +2367,7 @@ const favorites = createFetcherStore({
3262
2367
  }
3263
2368
  };
3264
2369
  return nodeStateSource.observable.pipe(
3265
- filter((nodeState) => !!nodeState),
2370
+ filter$1((nodeState) => !!nodeState),
3266
2371
  // Only proceed when connected
3267
2372
  shareReplay(1),
3268
2373
  switchMap((nodeState) => {
@@ -3274,55 +2379,21 @@ const favorites = createFetcherStore({
3274
2379
  payload
3275
2380
  )
3276
2381
  ).pipe(
3277
- map((response) => ({ isFavorited: response.isFavorited })),
2382
+ map$1((response) => ({ isFavorited: response.isFavorited })),
3278
2383
  catchError$1((err) => (console.error("Favorites service connection error", err), of({ isFavorited: !1 })))
3279
2384
  );
3280
2385
  })
3281
2386
  );
3282
2387
  }
3283
- }), getFavoritesState = favorites.getState, resolveFavoritesState = favorites.resolveState, API_VERSION$1 = "vX", PROJECT_API_VERSION = "2025-07-18", USERS_STATE_CLEAR_DELAY = 5e3, DEFAULT_USERS_BATCH_SIZE = 100, getUsersKey = (instance, {
3284
- resourceType,
3285
- organizationId,
3286
- batchSize = DEFAULT_USERS_BATCH_SIZE,
3287
- projectId = instance.config.projectId,
3288
- userId
3289
- } = {}) => JSON.stringify({
3290
- resourceType,
3291
- organizationId,
3292
- batchSize,
3293
- projectId,
3294
- userId
3295
- }), parseUsersKey = (key) => JSON.parse(key), addSubscription = (subscriptionId, key) => (prev) => {
3296
- const group = prev.users[key], subscriptions = [...group?.subscriptions ?? [], subscriptionId];
3297
- return { ...prev, users: { ...prev.users, [key]: { ...group, subscriptions } } };
3298
- }, removeSubscription = (subscriptionId, key) => (prev) => {
3299
- const group = prev.users[key];
3300
- if (!group) return prev;
3301
- const subscriptions = group.subscriptions.filter((id) => id !== subscriptionId);
3302
- return subscriptions.length ? { ...prev, users: { ...prev.users, [key]: { ...group, subscriptions } } } : { ...prev, users: omit(prev.users, key) };
3303
- }, setUsersData = (key, { data, nextCursor, totalCount }) => (prev) => {
3304
- const group = prev.users[key];
3305
- if (!group) return prev;
3306
- const users = [...group.users ?? [], ...data];
3307
- return { ...prev, users: { ...prev.users, [key]: { ...group, users, totalCount, nextCursor } } };
3308
- }, updateLastLoadMoreRequest = (timestamp, key) => (prev) => {
3309
- const group = prev.users[key];
3310
- return group ? { ...prev, users: { ...prev.users, [key]: { ...group, lastLoadMoreRequest: timestamp } } } : prev;
3311
- }, setUsersError = (key, error) => (prev) => {
3312
- const group = prev.users[key];
3313
- return group ? { ...prev, users: { ...prev.users, [key]: { ...group, error } } } : prev;
3314
- }, cancelRequest = (key) => (prev) => {
3315
- const group = prev.users[key];
3316
- return !group || group.subscriptions.length ? prev : { ...prev, users: omit(prev.users, key) };
3317
- }, initializeRequest = (key) => (prev) => prev.users[key] ? prev : { ...prev, users: { ...prev.users, [key]: { subscriptions: [] } } }, usersStore = {
2388
+ }), getFavoritesState = favorites.getState, resolveFavoritesState = favorites.resolveState, usersStore = defineStore({
3318
2389
  name: "UsersStore",
3319
2390
  getInitialState: () => ({ users: {} }),
3320
2391
  initialize: (context) => {
3321
2392
  const subscription = listenForLoadMoreAndFetch(context);
3322
2393
  return () => subscription.unsubscribe();
3323
2394
  }
3324
- }, errorHandler$1 = (state) => (error) => state.set("setError", { error }), listenForLoadMoreAndFetch = ({ state, instance }) => state.observable.pipe(
3325
- map((s) => new Set(Object.keys(s.users))),
2395
+ }), errorHandler = (state) => (error) => state.set("setError", { error }), listenForLoadMoreAndFetch = ({ state, instance }) => state.observable.pipe(
2396
+ map$1((s) => new Set(Object.keys(s.users))),
3326
2397
  distinctUntilChanged((curr, next) => curr.size !== next.size ? !1 : Array.from(next).every((i) => curr.has(i))),
3327
2398
  startWith$1(/* @__PURE__ */ new Set()),
3328
2399
  pairwise$1(),
@@ -3349,9 +2420,10 @@ const favorites = createFetcherStore({
3349
2420
  useProjectHostname: !0
3350
2421
  }).observable.request({
3351
2422
  method: "GET",
3352
- uri: `/users/${userId}`
2423
+ uri: `/users/${userId}`,
2424
+ tag: "users.get"
3353
2425
  }).pipe(
3354
- map((user) => ({
2426
+ map$1((user) => ({
3355
2427
  data: [{
3356
2428
  sanityUserId: user.sanityUserId,
3357
2429
  profile: {
@@ -3379,13 +2451,14 @@ const favorites = createFetcherStore({
3379
2451
  );
3380
2452
  const scope = userId.startsWith("g") ? "global" : void 0, client = getClient(instance, {
3381
2453
  scope,
3382
- apiVersion: API_VERSION$1
2454
+ apiVersion: API_VERSION$6
3383
2455
  }), resourceType2 = options.resourceType || "project", resourceId = resourceType2 === "organization" ? options.organizationId : options.projectId;
3384
2456
  return resourceId ? client.observable.request({
3385
2457
  method: "GET",
3386
- uri: `access/${resourceType2}/${resourceId}/users/${userId}`
2458
+ uri: `access/${resourceType2}/${resourceId}/users/${userId}`,
2459
+ tag: "users.get"
3387
2460
  }).pipe(
3388
- map((response) => "sanityUserId" in response ? {
2461
+ map$1((response) => "sanityUserId" in response ? {
3389
2462
  data: [response],
3390
2463
  totalCount: 1,
3391
2464
  nextCursor: null
@@ -3395,17 +2468,17 @@ const favorites = createFetcherStore({
3395
2468
  ) : throwError(() => new Error("An organizationId or a projectId is required"));
3396
2469
  }
3397
2470
  const projectId = options.projectId, resourceType = options.resourceType ?? (options.organizationId ? "organization" : projectId ? "project" : "organization"), organizationId$ = options.organizationId ? of(options.organizationId) : getDashboardOrganizationId$1(instance).observable.pipe(
3398
- filter((i) => typeof i == "string")
3399
- ), resource$ = resourceType === "project" ? projectId ? of({ type: "project", id: projectId }) : throwError(() => new Error("Project ID required for this API.")) : organizationId$.pipe(map((id) => ({ type: "organization", id }))), client$ = getClientState(instance, {
2471
+ filter$1((i) => typeof i == "string")
2472
+ ), resource$ = resourceType === "project" ? projectId ? of({ type: "project", id: projectId }) : throwError(() => new Error("Project ID required for this API.")) : organizationId$.pipe(map$1((id) => ({ type: "organization", id }))), client$ = getClientState(instance, {
3400
2473
  scope: "global",
3401
- apiVersion: API_VERSION$1
2474
+ apiVersion: API_VERSION$6
3402
2475
  }).observable, loadMore$ = state.observable.pipe(
3403
- map((s) => s.users[group$.key]?.lastLoadMoreRequest),
2476
+ map$1((s) => s.users[group$.key]?.lastLoadMoreRequest),
3404
2477
  distinctUntilChanged()
3405
2478
  ), cursor$ = state.observable.pipe(
3406
- map((s) => s.users[group$.key]?.nextCursor),
2479
+ map$1((s) => s.users[group$.key]?.nextCursor),
3407
2480
  distinctUntilChanged(),
3408
- filter((cursor) => cursor !== null)
2481
+ filter$1((cursor) => cursor !== null)
3409
2482
  );
3410
2483
  return combineLatest([resource$, client$, loadMore$]).pipe(
3411
2484
  withLatestFrom(cursor$),
@@ -3413,6 +2486,7 @@ const favorites = createFetcherStore({
3413
2486
  ([[resource, client], cursor]) => client.observable.request({
3414
2487
  method: "GET",
3415
2488
  uri: `access/${resource.type}/${resource.id}/users`,
2489
+ tag: "users.list",
3416
2490
  query: cursor ? { nextCursor: cursor, limit: batchSize.toString() } : { limit: batchSize.toString() }
3417
2491
  })
3418
2492
  ),
@@ -3422,7 +2496,7 @@ const favorites = createFetcherStore({
3422
2496
  })
3423
2497
  )
3424
2498
  )
3425
- ).subscribe({ error: errorHandler$1(state) }), getUsersState = bindActionGlobally(
2499
+ ).subscribe({ error: errorHandler(state) }), getUsersState = bindActionGlobally(
3426
2500
  usersStore,
3427
2501
  createStateSourceAction({
3428
2502
  selector: createSelector(
@@ -3441,7 +2515,7 @@ const favorites = createFetcherStore({
3441
2515
  onSubscribe: ({ instance, state }, options) => {
3442
2516
  const subscriptionId = insecureRandomId(), key = getUsersKey(instance, options);
3443
2517
  return state.set("addSubscription", addSubscription(subscriptionId, key)), () => {
3444
- setTimeout(
2518
+ setCleanupTimeout(
3445
2519
  () => state.set("removeSubscription", removeSubscription(subscriptionId, key)),
3446
2520
  USERS_STATE_CLEAR_DELAY
3447
2521
  );
@@ -3465,7 +2539,7 @@ const favorites = createFetcherStore({
3465
2539
  ) : NEVER;
3466
2540
  state.set("initializeRequest", initializeRequest(key));
3467
2541
  const resolved$ = state.observable.pipe(
3468
- map(getCurrent),
2542
+ map$1(getCurrent),
3469
2543
  first$1((i) => i !== void 0)
3470
2544
  );
3471
2545
  return firstValueFrom(race([resolved$, aborted$]));
@@ -3480,7 +2554,7 @@ const favorites = createFetcherStore({
3480
2554
  throw new Error("No more users available to load for this resource.");
3481
2555
  const promise = firstValueFrom(
3482
2556
  users.observable.pipe(
3483
- filter((i) => i !== void 0),
2557
+ filter$1((i) => i !== void 0),
3484
2558
  skip(1)
3485
2559
  )
3486
2560
  ), timestamp = (/* @__PURE__ */ new Date()).toISOString();
@@ -3489,7 +2563,7 @@ const favorites = createFetcherStore({
3489
2563
  ), getUserState = bindActionGlobally(
3490
2564
  usersStore,
3491
2565
  ({ instance }, { userId, ...options }) => getUsersState(instance, { userId, ...options }).observable.pipe(
3492
- map((res) => res?.data[0]),
2566
+ map$1((res) => res?.data[0]),
3493
2567
  distinctUntilChanged((a, b) => a?.profile.updatedAt === b?.profile.updatedAt)
3494
2568
  )
3495
2569
  ), resolveUser = bindActionGlobally(
@@ -3500,7 +2574,20 @@ const favorites = createFetcherStore({
3500
2574
  }))?.data[0]
3501
2575
  );
3502
2576
  function getBifurClient(client, token$) {
3503
- const bifurVersionedClient = client.withConfig({ apiVersion: "2022-06-30" }), { dataset, url: baseUrl, requestTagPrefix = "sanity.studio" } = bifurVersionedClient.config(), urlWithTag = `${`${baseUrl.replace(/\/+$/, "")}/socket/${dataset}`.replace(/^http/, "ws")}?tag=${requestTagPrefix}`;
2577
+ const bifurVersionedClient = client.withConfig({ apiVersion: "2022-06-30" }), {
2578
+ resource,
2579
+ dataset,
2580
+ url: baseUrl,
2581
+ requestTagPrefix = "sanity.sdk.presence"
2582
+ } = bifurVersionedClient.config();
2583
+ let resourcePath;
2584
+ if (resource?.type === "canvas")
2585
+ resourcePath = `canvases/${resource.id}`;
2586
+ else if (dataset)
2587
+ resourcePath = dataset;
2588
+ else
2589
+ throw new Error("Unable to determine presence URL: no canvas resource or dataset configured");
2590
+ const urlWithTag = `${`${baseUrl}/socket/${resourcePath}`.replace(/^http/, "ws")}?tag=${requestTagPrefix}`;
3504
2591
  return fromUrl(urlWithTag, { token$ });
3505
2592
  }
3506
2593
  const handleIncomingMessage = (event) => {
@@ -3532,7 +2619,7 @@ const handleIncomingMessage = (event) => {
3532
2619
  throw new Error(`Got unknown presence event: ${JSON.stringify(event)}`);
3533
2620
  }
3534
2621
  }, createBifurTransport = (options) => {
3535
- const { client, token$, sessionId } = options, bifur = getBifurClient(client, token$), incomingEvents$ = bifur.listen("presence").pipe(map$1(handleIncomingMessage)), dispatchMessage = (message) => {
2622
+ const { client, token$, sessionId } = options, bifur = getBifurClient(client, token$), incomingEvents$ = bifur.listen("presence").pipe(map(handleIncomingMessage)), dispatchMessage = (message) => {
3536
2623
  switch (message.type) {
3537
2624
  case "rollCall":
3538
2625
  return bifur.request("presence_rollcall", { session: sessionId });
@@ -3547,27 +2634,34 @@ const handleIncomingMessage = (event) => {
3547
2634
  }
3548
2635
  };
3549
2636
  return typeof window < "u" && fromEvent(window, "beforeunload").pipe(switchMap$1(() => dispatchMessage({ type: "disconnect" }))).subscribe(), [incomingEvents$.pipe(share$1()), dispatchMessage];
3550
- }, getInitialState = () => ({
2637
+ }, PRESENCE_API_VERSION = "2026-03-30", getInitialState = () => ({
3551
2638
  locations: /* @__PURE__ */ new Map(),
3552
2639
  users: {}
3553
- }), presenceStore = {
2640
+ }), presenceStore = defineStore({
3554
2641
  name: "presence",
3555
2642
  getInitialState,
3556
2643
  initialize: (context) => {
3557
2644
  const {
3558
2645
  instance,
3559
2646
  state,
3560
- key: { projectId, dataset }
3561
- } = context, sessionId = crypto.randomUUID(), client = getClient(instance, {
3562
- apiVersion: "2022-06-30",
3563
- projectId,
3564
- dataset
2647
+ key: { resource }
2648
+ } = context;
2649
+ if (isMediaLibraryResource(resource))
2650
+ throw new Error("Presence is not supported for media library resources.");
2651
+ const sessionId = crypto.randomUUID(), client = isDatasetResource(resource) ? getClient(instance, {
2652
+ apiVersion: PRESENCE_API_VERSION,
2653
+ projectId: resource.projectId,
2654
+ dataset: resource.dataset,
2655
+ useProjectHostname: !0
2656
+ }) : getClient(instance, {
2657
+ apiVersion: PRESENCE_API_VERSION,
2658
+ resource
3565
2659
  }), token$ = getTokenState(instance).observable.pipe(distinctUntilChanged()), [incomingEvents$, dispatch] = createBifurTransport({
3566
2660
  client,
3567
2661
  token$,
3568
2662
  sessionId
3569
2663
  }), subscription = new Subscription();
3570
- return subscription.add(
2664
+ if (subscription.add(
3571
2665
  incomingEvents$.subscribe((event) => {
3572
2666
  "sessionId" in event && event.sessionId === sessionId || (event.type === "state" ? state.set("presence/state", (prevState) => {
3573
2667
  const newLocations = new Map(prevState.locations);
@@ -3583,11 +2677,22 @@ const handleIncomingMessage = (event) => {
3583
2677
  return newLocations.delete(event.sessionId), { ...prevState, locations: newLocations };
3584
2678
  }));
3585
2679
  })
3586
- ), dispatch({ type: "rollCall" }).subscribe(), () => {
2680
+ ), dispatch({ type: "rollCall" }).subscribe(), isCanvasResource(resource)) {
2681
+ const globalClient = getClient(instance, { apiVersion: PRESENCE_API_VERSION });
2682
+ subscription.add(
2683
+ globalClient.observable.request({
2684
+ uri: `/canvases/${resource.canvasId}`,
2685
+ tag: "canvases.get"
2686
+ }).pipe(catchError$1(() => EMPTY)).subscribe(({ organizationId }) => {
2687
+ state.set("presence/organizationId", (prev) => ({ ...prev, organizationId }));
2688
+ })
2689
+ );
2690
+ }
2691
+ return () => {
3587
2692
  dispatch({ type: "disconnect" }).subscribe(), subscription.unsubscribe();
3588
2693
  };
3589
2694
  }
3590
- }, selectLocations = (state) => state.locations, selectUsers = (state) => state.users, selectPresence = createSelector(
2695
+ }), selectLocations = (state) => state.locations, selectUsers = (state) => state.users, selectPresence = createSelector(
3591
2696
  selectLocations,
3592
2697
  selectUsers,
3593
2698
  (locations, users) => Array.from(locations.entries()).map(([sessionId, { userId, locations: locs }]) => ({
@@ -3600,31 +2705,34 @@ const handleIncomingMessage = (event) => {
3600
2705
  sessionId,
3601
2706
  locations: locs
3602
2707
  }))
3603
- ), getPresence = bindActionByDataset(
2708
+ ), _getPresence = bindActionByResource(
3604
2709
  presenceStore,
3605
2710
  createStateSourceAction({
3606
- selector: (context, _) => selectPresence(context.state),
3607
- onSubscribe: (context, _) => {
3608
- const subscription = context.state.observable.pipe(
3609
- map(
2711
+ selector: (context) => selectPresence(context.state),
2712
+ onSubscribe: (context) => {
2713
+ const resource = context.key.resource, userIds$ = context.state.observable.pipe(
2714
+ map$1(
3610
2715
  (state) => Array.from(state.locations.values()).map((l) => l.userId).filter((id) => !!id)
3611
2716
  ),
3612
2717
  distinctUntilChanged((a, b) => a.length === b.length && a.every((v, i) => v === b[i]))
3613
- ).pipe(
3614
- switchMap((userIds) => {
2718
+ ), organizationId$ = isCanvasResource(resource) ? context.state.observable.pipe(
2719
+ map$1((s) => s.organizationId),
2720
+ filter$1((id) => id !== void 0),
2721
+ first$1()
2722
+ ) : of(void 0), subscription = combineLatest([userIds$, organizationId$]).pipe(
2723
+ switchMap(([userIds, organizationId]) => {
3615
2724
  if (userIds.length === 0)
3616
2725
  return of([]);
3617
2726
  const userObservables = userIds.map(
3618
2727
  (userId) => getUserState(context.instance, {
3619
2728
  userId,
3620
- resourceType: "project",
3621
- projectId: context.key.projectId
3622
- }).pipe(filter((v) => !!v))
2729
+ ...isDatasetResource(resource) ? { resourceType: "project", projectId: resource.projectId } : { resourceType: "organization", organizationId }
2730
+ }).pipe(filter$1((v) => !!v))
3623
2731
  );
3624
2732
  return combineLatest(userObservables);
3625
2733
  })
3626
2734
  ).subscribe((users) => {
3627
- users && context.state.set("presence/users", (prevState) => ({
2735
+ context.state.set("presence/users", (prevState) => ({
3628
2736
  ...prevState,
3629
2737
  users: {
3630
2738
  ...prevState.users,
@@ -3636,489 +2744,16 @@ const handleIncomingMessage = (event) => {
3636
2744
  }
3637
2745
  })
3638
2746
  );
3639
- function sortReleases(releases = []) {
3640
- return [...releases].sort((a, b) => {
3641
- if (a.metadata.releaseType === "undecided" && b.metadata.releaseType !== "undecided")
3642
- return -1;
3643
- if (a.metadata.releaseType !== "undecided" && b.metadata.releaseType === "undecided")
3644
- return 1;
3645
- if (a.metadata.releaseType === "undecided" && b.metadata.releaseType === "undecided")
3646
- return new Date(b._createdAt).getTime() - new Date(a._createdAt).getTime();
3647
- if (a.metadata.releaseType === "scheduled" && b.metadata.releaseType === "scheduled") {
3648
- const aPublishAt = a.publishAt || a.metadata.intendedPublishAt;
3649
- if (!aPublishAt)
3650
- return 1;
3651
- const bPublishAt = b.publishAt || b.metadata.intendedPublishAt;
3652
- return bPublishAt ? new Date(bPublishAt).getTime() - new Date(aPublishAt).getTime() : -1;
3653
- }
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;
3655
- });
2747
+ function getPresence(instance, params) {
2748
+ return _getPresence(instance, params ?? {});
3656
2749
  }
3657
- const ARCHIVED_RELEASE_STATES = ["archived", "published"], STABLE_EMPTY_RELEASES = [], releasesStore = {
3658
- name: "Releases",
3659
- getInitialState: () => ({
3660
- activeReleases: void 0
3661
- }),
3662
- initialize: (context) => {
3663
- const subscription = subscribeToReleases(context);
3664
- return () => subscription.unsubscribe();
3665
- }
3666
- }, getActiveReleasesState = bindActionByDataset(
3667
- releasesStore,
3668
- createStateSourceAction({
3669
- selector: ({ state }, _) => state.activeReleases
3670
- })
3671
- ), RELEASES_QUERY = "releases::all()", subscribeToReleases = ({
3672
- instance,
3673
- state,
3674
- key: { projectId, dataset }
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(
3691
- [selectActiveReleases, selectOptions],
3692
- (activeReleases, options) => {
3693
- if (!options || !activeReleases) return options;
3694
- const releaseIds = activeReleases.map((release) => release._id).join(",");
3695
- let nestedCache = optionsCache.get(releaseIds);
3696
- nestedCache || (nestedCache = /* @__PURE__ */ new Map(), optionsCache.set(releaseIds, nestedCache));
3697
- const optionsKey = JSON.stringify(options);
3698
- let cachedOptions = nestedCache.get(optionsKey);
3699
- return cachedOptions || (cachedOptions = options, nestedCache.set(optionsKey, cachedOptions)), cachedOptions;
3700
- }
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(
3717
- releasesStore,
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) => {
3720
- const prevQuery = prev.queries[key];
3721
- return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, error } } } : prev;
3722
- }, setQueryData = (key, result, syncTags) => (prev) => {
3723
- const prevQuery = prev.queries[key];
3724
- return prevQuery ? {
3725
- ...prev,
3726
- queries: { ...prev.queries, [key]: { ...prevQuery, result: result ?? null, syncTags } }
3727
- } : prev;
3728
- }, setLastLiveEventId = (key, lastLiveEventId) => (prev) => {
3729
- const prevQuery = prev.queries[key];
3730
- return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, lastLiveEventId } } } : prev;
3731
- }, addSubscriber = (key, subscriptionId) => (prev) => {
3732
- const prevQuery = prev.queries[key], subscribers = [...prevQuery?.subscribers ?? [], subscriptionId];
3733
- return { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, subscribers } } };
3734
- }, removeSubscriber = (key, subscriptionId) => (prev) => {
3735
- const prevQuery = prev.queries[key];
3736
- if (!prevQuery) return prev;
3737
- const subscribers = prevQuery.subscribers.filter((id) => id !== subscriptionId);
3738
- return subscribers.length ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, subscribers } } } : { ...prev, queries: omit(prev.queries, key) };
3739
- }, cancelQuery = (key) => (prev) => {
3740
- const prevQuery = prev.queries[key];
3741
- return !prevQuery || prevQuery.subscribers.length ? prev : { ...prev, queries: omit(prev.queries, key) };
3742
- }, initializeQuery = (key) => (prev) => prev.queries[key] ? prev : { ...prev, queries: { ...prev.queries, [key]: { subscribers: [] } } }, EMPTY_ARRAY = [], getQueryKey = (options) => JSON.stringify(options), parseQueryKey = (key) => JSON.parse(key);
3743
- function normalizeOptionsWithPerspective(instance, options) {
3744
- if (options.perspective !== void 0) return options;
3745
- const instancePerspective = instance.config.perspective;
3746
- return {
3747
- ...options,
3748
- perspective: instancePerspective !== void 0 ? instancePerspective : QUERY_STORE_DEFAULT_PERSPECTIVE
3749
- };
3750
- }
3751
- const queryStore = {
3752
- name: "QueryStore",
3753
- getInitialState: () => ({ queries: {} }),
3754
- initialize(context) {
3755
- const subscriptions = [
3756
- listenForNewSubscribersAndFetch(context),
3757
- listenToLiveClientAndSetLastLiveEventIds(context)
3758
- ];
3759
- return () => {
3760
- for (const subscription of subscriptions)
3761
- subscription.unsubscribe();
3762
- };
3763
- }
3764
- }, errorHandler = (state) => (error) => state.set("setError", { error }), listenForNewSubscribersAndFetch = ({ state, instance }) => state.observable.pipe(
3765
- map((s) => new Set(Object.keys(s.queries))),
3766
- distinctUntilChanged((curr, next) => curr.size !== next.size ? !1 : Array.from(next).every((i) => curr.has(i))),
3767
- startWith$1(/* @__PURE__ */ new Set()),
3768
- pairwise$1(),
3769
- mergeMap$1(([curr, next]) => {
3770
- const added = Array.from(next).filter((i) => !curr.has(i)), removed = Array.from(curr).filter((i) => !next.has(i));
3771
- return [
3772
- ...added.map((key) => ({ key, added: !0 })),
3773
- ...removed.map((key) => ({ key, added: !1 }))
3774
- ];
3775
- }),
3776
- groupBy$1((i) => i.key),
3777
- mergeMap$1(
3778
- (group$) => group$.pipe(
3779
- switchMap((e) => {
3780
- if (!e.added) return EMPTY;
3781
- const lastLiveEventId$ = state.observable.pipe(
3782
- map((s) => s.queries[group$.key]?.lastLiveEventId),
3783
- distinctUntilChanged()
3784
- ), {
3785
- query,
3786
- params,
3787
- projectId,
3788
- dataset,
3789
- tag,
3790
- source,
3791
- perspective: perspectiveFromOptions,
3792
- ...restOptions
3793
- } = parseQueryKey(group$.key), perspective$ = isReleasePerspective(perspectiveFromOptions) ? getPerspectiveState(instance, {
3794
- perspective: perspectiveFromOptions
3795
- }).observable.pipe(filter(Boolean)) : of(perspectiveFromOptions ?? QUERY_STORE_DEFAULT_PERSPECTIVE), client$ = getClientState(instance, {
3796
- apiVersion: QUERY_STORE_API_VERSION,
3797
- projectId,
3798
- dataset,
3799
- source
3800
- }).observable;
3801
- return combineLatest({
3802
- lastLiveEventId: lastLiveEventId$,
3803
- client: client$,
3804
- perspective: perspective$
3805
- }).pipe(
3806
- switchMap(
3807
- ({ lastLiveEventId, client, perspective }) => client.observable.fetch(query, params, {
3808
- ...restOptions,
3809
- perspective,
3810
- filterResponse: !1,
3811
- returnQuery: !1,
3812
- lastLiveEventId,
3813
- tag
3814
- })
3815
- )
3816
- );
3817
- }),
3818
- catchError$1((error) => (state.set("setQueryError", setQueryError(group$.key, error)), EMPTY)),
3819
- tap$1(({ result, syncTags }) => {
3820
- state.set("setQueryData", setQueryData(group$.key, result, syncTags));
3821
- })
3822
- )
3823
- )
3824
- ).subscribe({ error: errorHandler(state) }), listenToLiveClientAndSetLastLiveEventIds = ({
3825
- state,
3826
- instance,
3827
- key: { source }
3828
- }) => {
3829
- const liveMessages$ = getClientState(instance, {
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 } : {}
3833
- }).observable.pipe(
3834
- switchMap(
3835
- (client) => defer(
3836
- () => client.live.events({ includeDrafts: !!client.config().token, tag: "query-store" })
3837
- ).pipe(
3838
- catchError$1((error) => {
3839
- if (error instanceof CorsOriginError)
3840
- return state.set("setError", { error }), EMPTY;
3841
- throw error;
3842
- })
3843
- )
3844
- ),
3845
- share(),
3846
- filter((e) => e.type === "message")
3847
- );
3848
- return state.observable.pipe(
3849
- mergeMap$1((s) => Object.entries(s.queries)),
3850
- groupBy$1(([key]) => key),
3851
- mergeMap$1((group$) => {
3852
- const syncTags$ = group$.pipe(
3853
- map(([, queryState]) => queryState),
3854
- map((i) => i?.syncTags ?? EMPTY_ARRAY),
3855
- distinctUntilChanged()
3856
- );
3857
- return combineLatest([liveMessages$, syncTags$]).pipe(
3858
- filter(([message, syncTags]) => message.tags.some((tag) => syncTags.includes(tag))),
3859
- tap$1(([message]) => {
3860
- state.set("setLastLiveEventId", setLastLiveEventId(group$.key, message.id));
3861
- })
3862
- );
3863
- })
3864
- ).subscribe({ error: errorHandler(state) });
3865
- };
3866
- function getQueryState(...args) {
3867
- return _getQueryState(...args);
3868
- }
3869
- const _getQueryState = bindActionBySource(
3870
- queryStore,
3871
- createStateSourceAction({
3872
- selector: ({ state, instance }, options) => {
3873
- if (state.error) throw state.error;
3874
- const key = getQueryKey(normalizeOptionsWithPerspective(instance, options)), queryState = state.queries[key];
3875
- if (queryState?.error) throw queryState.error;
3876
- return queryState?.result;
3877
- },
3878
- onSubscribe: ({ state, instance }, options) => {
3879
- const subscriptionId = insecureRandomId(), key = getQueryKey(normalizeOptionsWithPerspective(instance, options));
3880
- return state.set("addSubscriber", addSubscriber(key, subscriptionId)), () => {
3881
- setTimeout(
3882
- () => state.set("removeSubscriber", removeSubscriber(key, subscriptionId)),
3883
- QUERY_STATE_CLEAR_DELAY
3884
- );
3885
- };
3886
- }
3887
- })
3888
- );
3889
- function resolveQuery(...args) {
3890
- return _resolveQuery(...args);
3891
- }
3892
- const _resolveQuery = bindActionBySource(
3893
- queryStore,
3894
- ({ state, instance }, { signal, ...options }) => {
3895
- const normalized = normalizeOptionsWithPerspective(instance, options), { getCurrent } = getQueryState(instance, normalized), key = getQueryKey(normalized), aborted$ = signal ? new Observable((observer) => {
3896
- const cleanup = () => {
3897
- signal.removeEventListener("abort", listener);
3898
- }, listener = () => {
3899
- observer.error(new DOMException("The operation was aborted.", "AbortError")), observer.complete(), cleanup();
3900
- };
3901
- return signal.addEventListener("abort", listener), cleanup;
3902
- }).pipe(
3903
- catchError$1((error) => {
3904
- throw error instanceof Error && error.name === "AbortError" && state.set("cancelQuery", cancelQuery(key)), error;
3905
- })
3906
- ) : NEVER;
3907
- state.set("initializeQuery", initializeQuery(key));
3908
- const resolved$ = state.observable.pipe(
3909
- map(getCurrent),
3910
- first$1((i) => i !== void 0)
3911
- );
3912
- return firstValueFrom(race([resolved$, aborted$]));
3913
- }
3914
- );
3915
2750
  function hashString(str) {
3916
2751
  let hash = 0;
3917
2752
  for (let i = 0; i < str.length; i++)
3918
2753
  hash = (hash * 31 + str.charCodeAt(i)) % 2147483647;
3919
2754
  return Math.abs(hash).toString(16).padStart(8, "0");
3920
2755
  }
3921
- const TITLE_CANDIDATES = ["title", "name", "label", "heading", "header", "caption"], SUBTITLE_CANDIDATES = ["description", "subtitle", ...TITLE_CANDIDATES], PREVIEW_PROJECTION = `{
3922
- // Get all potential title fields
3923
- "titleCandidates": {
3924
- ${TITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(`,
3925
- `)}
3926
- },
3927
- // Get all potential subtitle fields
3928
- "subtitleCandidates": {
3929
- ${SUBTITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(`,
3930
- `)}
3931
- },
3932
- "media": coalesce(
3933
- select(
3934
- defined(asset) => {"type": "image-asset", "_ref": asset._ref},
3935
- defined(image.asset) => {"type": "image-asset", "_ref": image.asset._ref},
3936
- defined(mainImage.asset) => {"type": "image-asset", "_ref": mainImage.asset._ref},
3937
- null
3938
- )
3939
- ),
3940
- _type,
3941
- _id,
3942
- _updatedAt
3943
- }`, PREVIEW_TAG = "preview", PREVIEW_PERSPECTIVE = "raw", STABLE_EMPTY_PREVIEW = { data: null, isPending: !1 }, STABLE_ERROR_PREVIEW = {
3944
- data: {
3945
- title: "Preview Error",
3946
- ...!!getEnv("DEV") && { subtitle: "Check the console for more details" }
3947
- },
3948
- isPending: !1
3949
- };
3950
- function assetIdToUrl(assetId, projectId, dataset) {
3951
- const pattern = /^image-(?<assetName>[A-Za-z0-9]+)-(?<dimensions>\d+x\d+)-(?<format>[a-z]+)$/, match = assetId.match(pattern);
3952
- if (!match?.groups)
3953
- throw new Error(
3954
- `Invalid asset ID \`${assetId}\`. Expected: image-{assetName}-{width}x{height}-{format}`
3955
- );
3956
- const { assetName, dimensions, format } = match.groups;
3957
- return `https://cdn.sanity.io/images/${projectId}/${dataset}/${assetName}-${dimensions}.${format}`;
3958
- }
3959
- function hasImageRef(value) {
3960
- return isObject(value) && "_ref" in value && typeof value._ref == "string";
3961
- }
3962
- function normalizeMedia(media, projectId, dataset) {
3963
- return !media || !hasImageRef(media) ? null : {
3964
- type: "image-asset",
3965
- _ref: media._ref,
3966
- url: assetIdToUrl(media._ref, projectId, dataset)
3967
- };
3968
- }
3969
- function findFirstDefined(fieldsToSearch, candidates, exclude) {
3970
- if (candidates)
3971
- for (const field of fieldsToSearch) {
3972
- const value = candidates[field];
3973
- if (typeof value == "string" && value.trim() !== "" && value !== exclude)
3974
- return value;
3975
- }
3976
- }
3977
- function processPreviewQuery({
3978
- projectId,
3979
- dataset,
3980
- ids,
3981
- results
3982
- }) {
3983
- const resultMap = results.reduce((acc, next) => (acc[next._id] = next, acc), {});
3984
- return Object.fromEntries(
3985
- Array.from(ids).map((id) => {
3986
- const publishedId = getPublishedId(id), draftId = getDraftId(id), draftResult = resultMap[draftId], publishedResult = resultMap[publishedId];
3987
- if (!draftResult && !publishedResult) return [id, STABLE_EMPTY_PREVIEW];
3988
- try {
3989
- const result = draftResult || publishedResult;
3990
- if (!result) return [id, STABLE_EMPTY_PREVIEW];
3991
- const title = findFirstDefined(TITLE_CANDIDATES, result.titleCandidates), subtitle = findFirstDefined(SUBTITLE_CANDIDATES, result.subtitleCandidates, title), preview = {
3992
- title: String(title || `${result._type}: ${result._id}`),
3993
- subtitle: subtitle || void 0,
3994
- media: normalizeMedia(result.media, projectId, dataset)
3995
- }, _status = {
3996
- ...draftResult?._updatedAt && { lastEditedDraftAt: draftResult._updatedAt },
3997
- ...publishedResult?._updatedAt && { lastEditedPublishedAt: publishedResult._updatedAt }
3998
- };
3999
- return [id, { data: { ...preview, _status }, isPending: !1 }];
4000
- } catch (e) {
4001
- return console.warn(e), [id, STABLE_ERROR_PREVIEW];
4002
- }
4003
- })
4004
- );
4005
- }
4006
- function createPreviewQuery(documentIds) {
4007
- const allIds = Array.from(documentIds).flatMap((id) => [getPublishedId(id), getDraftId(id)]), queryHash = hashString(PREVIEW_PROJECTION);
4008
- return {
4009
- query: `*[_id in $__ids_${queryHash}]${PREVIEW_PROJECTION}`,
4010
- params: {
4011
- [`__ids_${queryHash}`]: allIds
4012
- }
4013
- };
4014
- }
4015
- const BATCH_DEBOUNCE_TIME$1 = 50, isSetEqual$1 = (a, b) => a.size === b.size && Array.from(a).every((i) => b.has(i)), subscribeToStateAndFetchBatches$1 = ({
4016
- state,
4017
- instance,
4018
- key: { projectId, dataset }
4019
- }) => state.observable.pipe(
4020
- map(({ subscriptions }) => new Set(Object.keys(subscriptions))),
4021
- distinctUntilChanged(isSetEqual$1),
4022
- debounceTime(BATCH_DEBOUNCE_TIME$1),
4023
- startWith$1(/* @__PURE__ */ new Set()),
4024
- pairwise$1(),
4025
- tap$1(([prevIds, currIds]) => {
4026
- const newIds = [...currIds].filter((element) => !prevIds.has(element));
4027
- state.set("updatingPending", (prev) => {
4028
- const pendingValues = newIds.reduce((acc, id) => {
4029
- const prevValue = prev.values[id], value = prevValue?.data ? prevValue.data : null;
4030
- return acc[id] = { data: value, isPending: !0 }, acc;
4031
- }, {});
4032
- return { values: { ...prev.values, ...pendingValues } };
4033
- });
4034
- }),
4035
- map(([, ids]) => ids),
4036
- distinctUntilChanged(isSetEqual$1)
4037
- ).pipe(
4038
- switchMap((ids) => {
4039
- if (!ids.size) return EMPTY;
4040
- const { query, params } = createPreviewQuery(ids), controller = new AbortController();
4041
- return new Observable((observer) => {
4042
- const { getCurrent, observable } = getQueryState(instance, {
4043
- query,
4044
- params,
4045
- tag: PREVIEW_TAG,
4046
- perspective: PREVIEW_PERSPECTIVE,
4047
- projectId,
4048
- dataset
4049
- }), subscription = defer(() => getCurrent() === void 0 ? from(
4050
- resolveQuery(instance, {
4051
- query,
4052
- params,
4053
- tag: PREVIEW_TAG,
4054
- perspective: PREVIEW_PERSPECTIVE,
4055
- signal: controller.signal,
4056
- projectId,
4057
- dataset
4058
- })
4059
- ).pipe(switchMap(() => observable)) : observable).pipe(filter((result) => result !== void 0)).subscribe(observer);
4060
- return () => {
4061
- controller.signal.aborted || controller.abort(), subscription.unsubscribe();
4062
- };
4063
- }).pipe(map((data) => ({ data, ids })));
4064
- }),
4065
- map(({ ids, data }) => ({
4066
- values: processPreviewQuery({
4067
- projectId,
4068
- dataset,
4069
- ids,
4070
- results: data
4071
- })
4072
- }))
4073
- ).subscribe({
4074
- next: ({ values }) => {
4075
- state.set("updateResult", (prev) => ({ values: { ...prev.values, ...values } }));
4076
- }
4077
- }), previewStore = {
4078
- name: "Preview",
4079
- getInitialState() {
4080
- return {
4081
- subscriptions: {},
4082
- values: {}
4083
- };
4084
- },
4085
- initialize: (context) => {
4086
- const subscription = subscribeToStateAndFetchBatches$1(context);
4087
- return () => subscription.unsubscribe;
4088
- }
4089
- };
4090
- function getPreviewState(...args) {
4091
- return _getPreviewState(...args);
4092
- }
4093
- const _getPreviewState = bindActionByDataset(
4094
- previewStore,
4095
- createStateSourceAction({
4096
- selector: ({ state }, docHandle) => state.values[docHandle.documentId] ?? STABLE_EMPTY_PREVIEW,
4097
- onSubscribe: ({ state }, docHandle) => {
4098
- const subscriptionId = insecureRandomId(), documentId = getPublishedId(docHandle.documentId);
4099
- return state.set("addSubscription", (prev) => ({
4100
- subscriptions: {
4101
- ...prev.subscriptions,
4102
- [documentId]: {
4103
- ...prev.subscriptions[documentId],
4104
- [subscriptionId]: !0
4105
- }
4106
- }
4107
- })), () => {
4108
- state.set("removeSubscription", (prev) => {
4109
- const documentSubscriptions = omit(prev.subscriptions[documentId], subscriptionId), hasSubscribers = !!Object.keys(documentSubscriptions).length, prevValue = prev.values[documentId], previewValue = prevValue?.data ? prevValue.data : null;
4110
- return {
4111
- subscriptions: hasSubscribers ? { ...prev.subscriptions, [documentId]: documentSubscriptions } : omit(prev.subscriptions, documentId),
4112
- values: hasSubscribers ? prev.values : { ...prev.values, [documentId]: { data: previewValue, isPending: !1 } }
4113
- };
4114
- });
4115
- };
4116
- }
4117
- })
4118
- ), resolvePreview = bindActionByDataset(
4119
- previewStore,
4120
- ({ instance }, docHandle) => firstValueFrom(getPreviewState(instance, docHandle).observable.pipe(filter((i) => !!i.data)))
4121
- ), PROJECTION_TAG = "projection", PROJECTION_STATE_CLEAR_DELAY = 1e3, STABLE_EMPTY_PROJECTION = {
2756
+ const PROJECTION_TAG = "projection", PROJECTION_STATE_CLEAR_DELAY = 1e3, STABLE_EMPTY_PROJECTION = {
4122
2757
  data: null,
4123
2758
  isPending: !1
4124
2759
  };
@@ -4155,7 +2790,7 @@ function processProjectionQuery({
4155
2790
  }) {
4156
2791
  const groupedResults = {};
4157
2792
  for (const result of results) {
4158
- const originalId = getPublishedId(result._id), hash = result.__projectionHash;
2793
+ const originalId = getPublishedId(DocumentId(result._id)), hash = result.__projectionHash;
4159
2794
  ids.has(originalId) && (groupedResults[originalId] || (groupedResults[originalId] = {}), groupedResults[originalId][hash] || (groupedResults[originalId][hash] = void 0), groupedResults[originalId][hash] = result);
4160
2795
  }
4161
2796
  const finalValues = {};
@@ -4181,7 +2816,7 @@ function processProjectionQuery({
4181
2816
  function buildStatusQueryIds(documentIds, perspective) {
4182
2817
  const ids = [], releaseName = isReleasePerspective(perspective) ? perspective.releaseName : null;
4183
2818
  for (const id of documentIds) {
4184
- const publishedId = getPublishedId$2(DocumentId(id)), draftId = getDraftId$1(publishedId);
2819
+ const publishedId = getPublishedId(DocumentId(id)), draftId = getDraftId(publishedId);
4185
2820
  ids.push(draftId, publishedId), releaseName && ids.push(getVersionId(publishedId, releaseName));
4186
2821
  }
4187
2822
  return ids;
@@ -4189,7 +2824,7 @@ function buildStatusQueryIds(documentIds, perspective) {
4189
2824
  function processStatusQueryResults(results) {
4190
2825
  const documentStatuses = {};
4191
2826
  for (const result of results) {
4192
- const id = DocumentId(result._id), updatedAt = result._updatedAt, publishedId = getPublishedId$2(id), statusData = documentStatuses[publishedId] ?? {};
2827
+ const id = DocumentId(result._id), updatedAt = result._updatedAt, publishedId = getPublishedId(id), statusData = documentStatuses[publishedId] ?? {};
4193
2828
  isDraftId(id) ? statusData.lastEditedDraftAt = updatedAt : isVersionId(id) ? statusData.lastEditedVersionAt = updatedAt : isPublishedId(id) && (statusData.lastEditedPublishedAt = updatedAt), documentStatuses[publishedId] = statusData;
4194
2829
  }
4195
2830
  return documentStatuses;
@@ -4197,13 +2832,13 @@ function processStatusQueryResults(results) {
4197
2832
  const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Array.from(a).every((i) => b.has(i)), subscribeToStateAndFetchBatches = ({
4198
2833
  state,
4199
2834
  instance,
4200
- key: { source, perspective }
2835
+ key: { resource, perspective }
4201
2836
  }) => {
4202
2837
  const documentProjections$ = state.observable.pipe(
4203
- map((s) => s.documentProjections),
4204
- distinctUntilChanged(isEqual)
2838
+ map$1((s) => s.documentProjections),
2839
+ distinctUntilChanged(isDeepEqual)
4205
2840
  ), activeDocumentIds$ = state.observable.pipe(
4206
- map(({ subscriptions }) => new Set(Object.keys(subscriptions))),
2841
+ map$1(({ subscriptions }) => new Set(Object.keys(subscriptions).map((id) => DocumentId(id)))),
4207
2842
  distinctUntilChanged(isSetEqual)
4208
2843
  ), pendingUpdateSubscription = activeDocumentIds$.pipe(
4209
2844
  debounceTime(BATCH_DEBOUNCE_TIME),
@@ -4231,7 +2866,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
4231
2866
  })
4232
2867
  ).subscribe(), queryExecutionSubscription = combineLatest([activeDocumentIds$, documentProjections$]).pipe(
4233
2868
  debounceTime(BATCH_DEBOUNCE_TIME),
4234
- distinctUntilChanged(isEqual)
2869
+ distinctUntilChanged(isDeepEqual)
4235
2870
  ).pipe(
4236
2871
  switchMap(([ids, documentProjections]) => {
4237
2872
  if (!ids.size) return EMPTY;
@@ -4242,7 +2877,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
4242
2877
  tag: PROJECTION_TAG,
4243
2878
  perspective,
4244
2879
  // temporary guard here until we're ready for everything to be queried via global API
4245
- ...source && !isDatasetSource(source) ? { source } : {}
2880
+ ...resource && !isDatasetResource(resource) ? { resource } : {}
4246
2881
  }), subscription = defer(() => getCurrent() === void 0 ? from(
4247
2882
  resolveQuery(instance, {
4248
2883
  query,
@@ -4251,9 +2886,9 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
4251
2886
  signal: controller.signal,
4252
2887
  perspective,
4253
2888
  // temporary guard here until we're ready for everything to be queried via global API in v3
4254
- ...source && !isDatasetSource(source) ? { source } : {}
2889
+ ...resource && !isDatasetResource(resource) ? { resource } : {}
4255
2890
  })
4256
- ).pipe(switchMap(() => observable)) : observable).pipe(filter((result) => result !== void 0)).subscribe(observer);
2891
+ ).pipe(switchMap(() => observable)) : observable).pipe(filter$1((result) => result !== void 0)).subscribe(observer);
4257
2892
  return () => {
4258
2893
  controller.signal.aborted || controller.abort(), subscription.unsubscribe();
4259
2894
  };
@@ -4264,7 +2899,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
4264
2899
  tag: PROJECTION_TAG,
4265
2900
  perspective: "raw",
4266
2901
  // temporary guard here until we're ready for everything to be queried via global API
4267
- ...source && !isDatasetSource(source) ? { source } : {}
2902
+ ...resource && !isDatasetResource(resource) ? { resource } : {}
4268
2903
  }), subscription = defer(() => getCurrent() === void 0 ? from(
4269
2904
  resolveQuery(instance, {
4270
2905
  query: statusQuery,
@@ -4273,25 +2908,25 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
4273
2908
  signal: controller.signal,
4274
2909
  perspective: "raw",
4275
2910
  // temporary guard here until we're ready for everything to be queried via global API
4276
- ...source && !isDatasetSource(source) ? { source } : {}
2911
+ ...resource && !isDatasetResource(resource) ? { resource } : {}
4277
2912
  })
4278
- ).pipe(switchMap(() => observable)) : observable).pipe(filter((result) => result !== void 0)).subscribe(observer);
2913
+ ).pipe(switchMap(() => observable)) : observable).pipe(filter$1((result) => result !== void 0)).subscribe(observer);
4279
2914
  return () => {
4280
2915
  subscription.unsubscribe();
4281
2916
  };
4282
2917
  });
4283
2918
  return combineLatest([projectionQuery$, statusQuery$]).pipe(
4284
- filter(
2919
+ filter$1(
4285
2920
  (pair) => pair[0] !== void 0 && pair[1] !== void 0
4286
2921
  ),
4287
- map(([projection, status]) => ({
2922
+ map$1(([projection, status]) => ({
4288
2923
  data: projection,
4289
2924
  ids,
4290
2925
  statusResults: status
4291
2926
  }))
4292
2927
  );
4293
2928
  }),
4294
- map(({ ids, data, statusResults }) => {
2929
+ map$1(({ ids, data, statusResults }) => {
4295
2930
  const documentStatuses = processStatusQueryResults(statusResults);
4296
2931
  state.set("updateStatuses", (prev) => ({
4297
2932
  documentStatuses: {
@@ -4325,7 +2960,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
4325
2960
  return new Subscription(() => {
4326
2961
  pendingUpdateSubscription.unsubscribe(), queryExecutionSubscription.unsubscribe();
4327
2962
  });
4328
- }, projectionStore = {
2963
+ }, projectionStore = defineStore({
4329
2964
  name: "Projection",
4330
2965
  getInitialState() {
4331
2966
  return {
@@ -4339,19 +2974,19 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
4339
2974
  const batchSubscription = subscribeToStateAndFetchBatches(context);
4340
2975
  return () => batchSubscription.unsubscribe();
4341
2976
  }
4342
- };
2977
+ });
4343
2978
  function getProjectionState(...args) {
4344
2979
  return _getProjectionState(...args);
4345
2980
  }
4346
- const _getProjectionState = bindActionBySourceAndPerspective(
2981
+ const _getProjectionState = bindActionByResourceAndPerspective(
4347
2982
  projectionStore,
4348
2983
  createStateSourceAction({
4349
2984
  selector: ({ state }, options) => {
4350
- const documentId = getPublishedId$2(DocumentId(options.documentId)), projectionHash = hashString(options.projection);
2985
+ const documentId = getPublishedId(DocumentId(options.documentId)), projectionHash = hashString(options.projection);
4351
2986
  return state.values[documentId]?.[projectionHash] ?? STABLE_EMPTY_PROJECTION;
4352
2987
  },
4353
2988
  onSubscribe: ({ state }, options) => {
4354
- const { projection, ...docHandle } = options, subscriptionId = insecureRandomId(), documentId = getPublishedId$2(DocumentId(docHandle.documentId)), validProjection = validateProjection(projection), projectionHash = hashString(validProjection);
2989
+ const { projection, ...docHandle } = options, subscriptionId = insecureRandomId(), documentId = getPublishedId(DocumentId(docHandle.documentId)), validProjection = validateProjection(projection), projectionHash = hashString(validProjection);
4355
2990
  return state.set("addSubscription", (prev) => ({
4356
2991
  documentProjections: {
4357
2992
  ...prev.documentProjections,
@@ -4371,9 +3006,9 @@ const _getProjectionState = bindActionBySourceAndPerspective(
4371
3006
  }
4372
3007
  }
4373
3008
  })), () => {
4374
- setTimeout(() => {
3009
+ setCleanupTimeout(() => {
4375
3010
  state.set("removeSubscription", (prev) => {
4376
- const documentSubscriptionsForHash = omit(
3011
+ const documentSubscriptionsForHash = omitProperty(
4377
3012
  prev.subscriptions[documentId]?.[projectionHash],
4378
3013
  subscriptionId
4379
3014
  ), hasSubscribersForProjection = !!Object.keys(documentSubscriptionsForHash).length, nextSubscriptions = { ...prev.subscriptions }, nextDocumentProjections = { ...prev.documentProjections }, nextValues = { ...prev.values };
@@ -4400,17 +3035,46 @@ const _getProjectionState = bindActionBySourceAndPerspective(
4400
3035
  }
4401
3036
  })
4402
3037
  );
3038
+ function getPreviewState(instance, options) {
3039
+ const projectionState = getProjectionState(instance, {
3040
+ ...options,
3041
+ projection: PREVIEW_PROJECTION
3042
+ }), transformResult = (current) => !current || current.data === null ? { data: null, isPending: current?.isPending ?? !1 } : {
3043
+ data: transformProjectionToPreview(instance, current.data, options.resource),
3044
+ isPending: current.isPending
3045
+ };
3046
+ return {
3047
+ getCurrent: () => transformResult(projectionState.getCurrent()),
3048
+ subscribe: (callback) => projectionState.subscribe(callback),
3049
+ observable: projectionState.observable.pipe(map$1(transformResult))
3050
+ };
3051
+ }
4403
3052
  function resolveProjection(...args) {
4404
3053
  return _resolveProjection(...args);
4405
3054
  }
4406
- const _resolveProjection = bindActionBySourceAndPerspective(
3055
+ const _resolveProjection = bindActionByResourceAndPerspective(
4407
3056
  projectionStore,
4408
3057
  ({ instance }, options) => firstValueFrom(
4409
3058
  getProjectionState(instance, options).observable.pipe(
4410
- filter((state) => !!state?.data)
3059
+ filter$1((state) => !!state?.data)
4411
3060
  )
4412
3061
  )
4413
- ), API_VERSION = "v2025-02-19", projects = createFetcherStore({
3062
+ );
3063
+ async function resolvePreview(instance, options) {
3064
+ const projectionResult = await resolveProjection(instance, {
3065
+ ...options,
3066
+ projection: PREVIEW_PROJECTION
3067
+ });
3068
+ return projectionResult.data ? {
3069
+ data: transformProjectionToPreview(
3070
+ instance,
3071
+ projectionResult.data,
3072
+ options.resource
3073
+ ),
3074
+ isPending: projectionResult.isPending
3075
+ } : { data: null, isPending: projectionResult.isPending };
3076
+ }
3077
+ const API_VERSION = "v2025-02-19", projects = createFetcherStore({
4414
3078
  name: "Projects",
4415
3079
  getKey: (_instance, options) => {
4416
3080
  const orgKey = options?.organizationId ? `:org:${options.organizationId}` : "", membersKey = options?.includeMembers === !1 ? ":no-members" : "";
@@ -4430,29 +3094,7 @@ const _resolveProjection = bindActionBySourceAndPerspective(
4430
3094
  });
4431
3095
  })
4432
3096
  )
4433
- }), getProjectsState = projects.getState, resolveProjects = projects.resolveState, TOKEN_REGEX = /(?:[^\s"]+|"[^"]*")+/g;
4434
- function isNegationToken(token) {
4435
- return typeof token < "u" && token.trim().startsWith("-");
4436
- }
4437
- function isPrefixToken(token) {
4438
- return typeof token < "u" && token.trim().endsWith("*");
4439
- }
4440
- function isExactMatchToken(token) {
4441
- return !!token && token.length >= 2 && token.startsWith('"') && token.endsWith('"');
4442
- }
4443
- function createGroqSearchFilter(query) {
4444
- const trimmedQuery = query.trim();
4445
- if (!trimmedQuery)
4446
- return "";
4447
- const tokens = trimmedQuery.match(TOKEN_REGEX) ?? [], reversedIndex = [...tokens].reverse().findIndex(
4448
- (token) => !isNegationToken(token) && !isExactMatchToken(token)
4449
- ), finalIncrementalTokenIndex = reversedIndex === -1 ? -1 : tokens.length - 1 - reversedIndex, finalIncrementalToken = tokens[finalIncrementalTokenIndex], processedTokens = [...tokens];
4450
- return finalIncrementalToken !== void 0 && !isPrefixToken(finalIncrementalToken) && processedTokens.splice(
4451
- finalIncrementalTokenIndex,
4452
- 1,
4453
- `${finalIncrementalToken}*`
4454
- ), `[@] match text::query("${processedTokens.join(" ").replace(/"/g, '\\"')}")`;
4455
- }
3097
+ }), getProjectsState = projects.getState, resolveProjects = projects.resolveState;
4456
3098
  function defineIntent(intent) {
4457
3099
  if (!intent.id)
4458
3100
  throw new Error("Intent must have an id");
@@ -4511,11 +3153,16 @@ function getCorsErrorProjectId(error) {
4511
3153
  const projMatch = (error.message || "").match(/manage\/project\/([^/?#]+)/);
4512
3154
  return projMatch ? projMatch[1] : null;
4513
3155
  }
4514
- var version = "2.8.0";
4515
- const CORE_SDK_VERSION = getEnv("PKG_VERSION") || `${version}-development`;
3156
+ function isImportError(error) {
3157
+ if (!(error instanceof Error)) return !1;
3158
+ if (error.name === "ChunkLoadError") return !0;
3159
+ const message = error.message || "";
3160
+ return /Loading chunk [\w-]+ failed/i.test(message) || /Failed to fetch dynamically imported module/i.test(message) || /error loading dynamically imported module/i.test(message) || /Import(?:ing)? a module script failed/i.test(message) || /Unable to preload CSS/i.test(message);
3161
+ }
4516
3162
  export {
4517
3163
  AuthStateType,
4518
3164
  CORE_SDK_VERSION,
3165
+ PREVIEW_PROJECTION,
4519
3166
  agentGenerate,
4520
3167
  agentPatch,
4521
3168
  agentPrompt,
@@ -4571,8 +3218,12 @@ export {
4571
3218
  getUsersKey,
4572
3219
  getUsersState,
4573
3220
  handleAuthCallback,
3221
+ isCanvasResource,
4574
3222
  isCanvasSource,
3223
+ isDatasetResource,
4575
3224
  isDatasetSource,
3225
+ isImportError,
3226
+ isMediaLibraryResource,
4576
3227
  isMediaLibrarySource,
4577
3228
  isProjectUserNotFoundClientError,
4578
3229
  isStudioConfig,
@@ -4601,6 +3252,7 @@ export {
4601
3252
  slicePath2 as slicePath,
4602
3253
  stringifyPath2 as stringifyPath,
4603
3254
  subscribeDocumentEvents,
3255
+ transformProjectionToPreview,
4604
3256
  unpublishDocument
4605
3257
  };
4606
3258
  //# sourceMappingURL=index.js.map