@sanity/sdk 2.9.0 → 2.11.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 (73) hide show
  1. package/dist/_chunks-dts/utils.d.ts +295 -69
  2. package/dist/_chunks-es/_internal.js +3 -14
  3. package/dist/_chunks-es/_internal.js.map +1 -1
  4. package/dist/_chunks-es/createGroqSearchFilter.js +129 -59
  5. package/dist/_chunks-es/createGroqSearchFilter.js.map +1 -1
  6. package/dist/_chunks-es/version.js +1 -1
  7. package/dist/_exports/_internal.d.ts +16 -2
  8. package/dist/_exports/_internal.js +3 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +275 -149
  11. package/dist/index.js.map +1 -1
  12. package/package.json +11 -15
  13. package/src/_exports/_internal.ts +1 -0
  14. package/src/_exports/index.ts +33 -2
  15. package/src/agent/agentActions.ts +21 -25
  16. package/src/client/clientStore.test.ts +24 -60
  17. package/src/client/clientStore.ts +49 -56
  18. package/src/comlink/controller/actions/getOrCreateChannel.ts +2 -2
  19. package/src/comlink/node/actions/getOrCreateNode.test.ts +5 -2
  20. package/src/comlink/node/actions/getOrCreateNode.ts +2 -2
  21. package/src/comlink/node/actions/releaseNode.test.ts +3 -3
  22. package/src/config/sanityConfig.ts +72 -13
  23. package/src/document/applyDocumentActions.test.ts +7 -7
  24. package/src/document/applyDocumentActions.ts +5 -5
  25. package/src/document/documentStore.test.ts +68 -62
  26. package/src/document/documentStore.ts +33 -38
  27. package/src/document/processActions.ts +2 -2
  28. package/src/document/reducers.ts +4 -4
  29. package/src/document/sharedListener.ts +5 -7
  30. package/src/organization/organization.test-d.ts +102 -0
  31. package/src/organization/organization.test.ts +138 -0
  32. package/src/organization/organization.ts +166 -0
  33. package/src/organizations/organizations.test-d.ts +77 -0
  34. package/src/organizations/organizations.test.ts +150 -0
  35. package/src/organizations/organizations.ts +132 -0
  36. package/src/presence/bifurTransport.test.ts +46 -6
  37. package/src/presence/bifurTransport.ts +13 -1
  38. package/src/presence/presenceStore.test.ts +101 -5
  39. package/src/presence/presenceStore.ts +96 -24
  40. package/src/preview/getPreviewState.ts +1 -1
  41. package/src/preview/previewProjectionUtils.test.ts +4 -4
  42. package/src/preview/previewProjectionUtils.ts +6 -7
  43. package/src/preview/resolvePreview.ts +5 -1
  44. package/src/project/project.test-d.ts +93 -0
  45. package/src/project/project.test.ts +108 -10
  46. package/src/project/project.ts +152 -26
  47. package/src/projection/getProjectionState.ts +4 -4
  48. package/src/projection/projectionStore.test.ts +2 -2
  49. package/src/projection/resolveProjection.ts +2 -2
  50. package/src/projection/subscribeToStateAndFetchBatches.test.ts +1 -1
  51. package/src/projection/subscribeToStateAndFetchBatches.ts +11 -15
  52. package/src/projects/projects.test-d.ts +38 -0
  53. package/src/projects/projects.test.ts +104 -38
  54. package/src/projects/projects.ts +74 -14
  55. package/src/query/queryStore.test.ts +12 -12
  56. package/src/query/queryStore.ts +10 -11
  57. package/src/query/reducers.ts +3 -3
  58. package/src/releases/getPerspectiveState.ts +5 -5
  59. package/src/releases/releasesStore.test.ts +6 -6
  60. package/src/releases/releasesStore.ts +9 -9
  61. package/src/store/createActionBinder.test.ts +31 -31
  62. package/src/store/createActionBinder.ts +43 -38
  63. package/src/store/createSanityInstance.ts +5 -6
  64. package/src/telemetry/devMode.test.ts +8 -0
  65. package/src/telemetry/devMode.ts +10 -9
  66. package/src/telemetry/initTelemetry.test.ts +0 -17
  67. package/src/telemetry/initTelemetry.ts +2 -12
  68. package/src/users/reducers.ts +3 -4
  69. package/src/utils/createFetcherStore.ts +6 -4
  70. package/src/utils/isImportError.test.ts +72 -0
  71. package/src/utils/isImportError.ts +34 -0
  72. package/src/utils/object.test.ts +95 -0
  73. package/src/utils/object.ts +142 -0
package/dist/index.js CHANGED
@@ -1,12 +1,11 @@
1
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, insecureRandomId, getClientState, bindActionGlobally, defineStore, createStateSourceAction, setCleanupTimeout, authStore, getDefaultLocation, AuthStateType, getCleanedUrl, getTokenFromLocation, createLoggedInAuthState, getAuthCode, REQUEST_TAG_PREFIX, DEFAULT_API_VERSION, configureLogging as configureLogging$1, isReleasePerspective, isDatasetSource, bindActionBySource, isMediaLibrarySource, isCanvasSource, 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, bindActionByDataset, getTokenState, getQueryState, resolveQuery, bindActionBySourceAndPerspective, transformProjectionToPreview, PREVIEW_PROJECTION } from "./_chunks-es/createGroqSearchFilter.js";
3
- import { createGroqSearchFilter, getActiveReleasesState, getAuthState, getClientErrorApiBody, getClientErrorApiDescription, getClientErrorApiType, getCurrentUserState, getIsInDashboardState, getLoginUrlState, getPerspectiveState, getQueryKey, isProjectUserNotFoundClientError, isStudioConfig, parseQueryKey, setAuthToken } from "./_chunks-es/createGroqSearchFilter.js";
4
- import { pick, omit, isEqual } from "lodash-es";
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, bindActionByResource, isDatasetResource, isMediaLibraryResource, isCanvasResource, getUsersKey, addSubscription, parseUsersKey, getClient, PROJECT_API_VERSION, setUsersError, setUsersData, API_VERSION as API_VERSION$8, 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";
5
4
  import { first, switchMap as switchMap$1, groupBy, mergeMap, startWith, pairwise, filter, map, delay, tap, catchError, scan, share as share$1 } from "rxjs/operators";
6
5
  import { createController, createNode } from "@sanity/comlink";
7
6
  import { createSelector } from "reselect";
8
7
  import { SanityEncoder } from "@sanity/mutate";
9
- import { getVersionId, getPublishedId, DocumentId, getDraftId, isDraftId, isVersionId, isPublishedId } from "@sanity/id-utils";
8
+ import { getVersionId, DocumentId, getPublishedId, getDraftId, isDraftId, isVersionId, isPublishedId } from "@sanity/id-utils";
10
9
  import { jsonMatch, stringifyPath, slicePath, getIndexForKey } from "@sanity/json-match";
11
10
  import { getIndexForKey as getIndexForKey2, getPathDepth, joinPaths, jsonMatch as jsonMatch2, slicePath as slicePath2, stringifyPath as stringifyPath2 } from "@sanity/json-match";
12
11
  import { evaluateSync, parse } from "groq-js";
@@ -82,7 +81,7 @@ function createSanityInstance(config = {}) {
82
81
  }), child;
83
82
  },
84
83
  match: (targetConfig) => {
85
- if (Object.entries(pick(targetConfig, "auth", "projectId", "dataset")).every(
84
+ if (Object.entries(pickProperties(targetConfig, ["auth", "projectId", "dataset"])).every(
86
85
  ([key, value]) => config[key] === value
87
86
  ))
88
87
  return instance;
@@ -92,41 +91,31 @@ function createSanityInstance(config = {}) {
92
91
  };
93
92
  return instance;
94
93
  }
95
- const API_VERSION$5 = "vX";
96
- function agentGenerate(instance, options) {
97
- return getClientState(instance, {
98
- apiVersion: API_VERSION$5,
99
- projectId: instance.config.projectId,
100
- dataset: instance.config.dataset
101
- }).observable.pipe(switchMap((client) => client.observable.agent.action.generate(options)));
94
+ const API_VERSION$7 = "vX";
95
+ function agentGenerate(instance, options, resource) {
96
+ return getClientState(instance, { apiVersion: API_VERSION$7, resource }).observable.pipe(
97
+ switchMap((client) => client.observable.agent.action.generate(options))
98
+ );
102
99
  }
103
- function agentTransform(instance, options) {
104
- return getClientState(instance, {
105
- apiVersion: API_VERSION$5,
106
- projectId: instance.config.projectId,
107
- dataset: instance.config.dataset
108
- }).observable.pipe(switchMap((client) => client.observable.agent.action.transform(options)));
100
+ function agentTransform(instance, options, resource) {
101
+ return getClientState(instance, { apiVersion: API_VERSION$7, resource }).observable.pipe(
102
+ switchMap((client) => client.observable.agent.action.transform(options))
103
+ );
109
104
  }
110
- function agentTranslate(instance, options) {
111
- return getClientState(instance, {
112
- apiVersion: API_VERSION$5,
113
- projectId: instance.config.projectId,
114
- dataset: instance.config.dataset
115
- }).observable.pipe(switchMap((client) => client.observable.agent.action.translate(options)));
105
+ function agentTranslate(instance, options, resource) {
106
+ return getClientState(instance, { apiVersion: API_VERSION$7, resource }).observable.pipe(
107
+ switchMap((client) => client.observable.agent.action.translate(options))
108
+ );
116
109
  }
117
- function agentPrompt(instance, options) {
118
- return getClientState(instance, {
119
- apiVersion: API_VERSION$5,
120
- projectId: instance.config.projectId,
121
- dataset: instance.config.dataset
122
- }).observable.pipe(switchMap((client) => from(client.agent.action.prompt(options))));
110
+ function agentPrompt(instance, options, resource) {
111
+ return getClientState(instance, { apiVersion: API_VERSION$7, resource }).observable.pipe(
112
+ switchMap((client) => from(client.agent.action.prompt(options)))
113
+ );
123
114
  }
124
- function agentPatch(instance, options) {
125
- return getClientState(instance, {
126
- apiVersion: API_VERSION$5,
127
- projectId: instance.config.projectId,
128
- dataset: instance.config.dataset
129
- }).observable.pipe(switchMap((client) => from(client.agent.action.patch(options))));
115
+ function agentPatch(instance, options, resource) {
116
+ return getClientState(instance, { apiVersion: API_VERSION$7, resource }).observable.pipe(
117
+ switchMap((client) => from(client.agent.action.patch(options)))
118
+ );
130
119
  }
131
120
  function compareProjectOrganization(projectId, projectOrganizationId, currentDashboardOrgId) {
132
121
  return projectOrganizationId !== currentDashboardOrgId ? {
@@ -193,8 +182,8 @@ function createFetcherStore({
193
182
  stateByParams: {
194
183
  ...prev.stateByParams,
195
184
  [entry.key]: {
196
- ...omit(entry, "error"),
197
- ...omit(prev.stateByParams[entry.key], "error"),
185
+ ...omitProperty(entry, "error"),
186
+ ...prev.stateByParams[entry.key] ? omitProperty(prev.stateByParams[entry.key], "error") : {},
198
187
  data
199
188
  }
200
189
  }
@@ -246,7 +235,7 @@ function createFetcherStore({
246
235
  const entry = prev.stateByParams[key];
247
236
  if (!entry) return prev;
248
237
  const newSubs = (entry.subscriptions || []).filter((id) => id !== subscriptionId);
249
- return newSubs.length === 0 ? { stateByParams: omit(prev.stateByParams, key) } : {
238
+ return newSubs.length === 0 ? { stateByParams: omitProperty(prev.stateByParams, key) } : {
250
239
  stateByParams: {
251
240
  ...prev.stateByParams,
252
241
  [key]: {
@@ -266,27 +255,42 @@ function createFetcherStore({
266
255
  );
267
256
  return { getState, resolveState };
268
257
  }
269
- const API_VERSION$4 = "v2025-02-19", project = createFetcherStore({
258
+ const API_VERSION$6 = "v2025-02-19";
259
+ function normalizeProjectOptions(options) {
260
+ return {
261
+ includeMembers: options?.includeMembers ?? !0,
262
+ includeFeatures: options?.includeFeatures ?? !0
263
+ };
264
+ }
265
+ function resolveProjectId(instance, options) {
266
+ const projectId = options?.projectId ?? instance.config.projectId;
267
+ if (!projectId)
268
+ throw new Error("A projectId is required to use the project API.");
269
+ return projectId;
270
+ }
271
+ function getProjectCacheKey(instance, options) {
272
+ const projectId = resolveProjectId(instance, options), { includeMembers, includeFeatures } = normalizeProjectOptions(options);
273
+ return `project:${projectId}${includeMembers ? ":members" : ""}${includeFeatures ? ":features" : ""}`;
274
+ }
275
+ const project = createFetcherStore({
270
276
  name: "Project",
271
- getKey: (instance, options) => {
272
- const projectId = options?.projectId ?? instance.config.projectId;
273
- if (!projectId)
274
- throw new Error("A projectId is required to use the project API.");
275
- return projectId;
276
- },
277
- fetcher: (instance) => (options = {}) => {
278
- const projectId = options.projectId ?? instance.config.projectId;
277
+ getKey: getProjectCacheKey,
278
+ fetcher: (instance) => (options) => {
279
+ const projectId = resolveProjectId(instance, options);
279
280
  return getClientState(instance, {
280
- apiVersion: API_VERSION$4,
281
- scope: "global",
282
- projectId
281
+ apiVersion: API_VERSION$6,
282
+ scope: "global"
283
283
  }).observable.pipe(
284
- switchMap(
285
- (client) => client.observable.projects.getById(
286
- // non-null assertion is fine with the above throwing
287
- projectId ?? instance.config.projectId
288
- )
289
- )
284
+ switchMap((client) => {
285
+ const normalized = normalizeProjectOptions(options), query = Object.fromEntries(
286
+ Object.entries(normalized).filter(([, value]) => value !== void 0).map(([key, value]) => [key, String(value)])
287
+ );
288
+ return client.observable.request({
289
+ uri: `/projects/${projectId}`,
290
+ query,
291
+ tag: "project.get"
292
+ });
293
+ })
290
294
  );
291
295
  }
292
296
  }), getProjectState = project.getState, resolveProject = project.resolveState, getDashboardOrganizationId = bindActionGlobally(
@@ -403,7 +407,7 @@ const handleAuthCallback = bindActionGlobally(
403
407
  throw new Error("Controller must be initialized before using or creating channels");
404
408
  const channels = state.get().channels, existing = channels.get(options.name);
405
409
  if (existing) {
406
- if (!isEqual(existing.options, options))
410
+ if (!isDeepEqual(existing.options, options))
407
411
  throw new Error(`Channel "${options.name}" already exists with different options`);
408
412
  return state.set("incrementChannelRefCount", {
409
413
  channels: new Map(channels).set(options.name, {
@@ -465,7 +469,7 @@ const handleAuthCallback = bindActionGlobally(
465
469
  ), releaseChannel = bindActionGlobally(comlinkControllerStore, releaseChannel$1), getOrCreateNode$1 = ({ state }, options) => {
466
470
  const nodes = state.get().nodes, existing = nodes.get(options.name);
467
471
  if (existing) {
468
- if (!isEqual(existing.options, options))
472
+ if (!isDeepEqual(existing.options, options))
469
473
  throw new Error(`Node "${options.name}" already exists with different options`);
470
474
  return existing.node.start(), existing.node;
471
475
  }
@@ -554,7 +558,7 @@ function configureLogging(config) {
554
558
  source: "programmatic"
555
559
  });
556
560
  }
557
- const API_VERSION$3 = "v2025-02-19", datasets = createFetcherStore({
561
+ const API_VERSION$5 = "v2025-02-19", datasets = createFetcherStore({
558
562
  name: "Datasets",
559
563
  getKey: (instance, options) => {
560
564
  const projectId = options?.projectId ?? instance.config.projectId;
@@ -563,7 +567,7 @@ const API_VERSION$3 = "v2025-02-19", datasets = createFetcherStore({
563
567
  return projectId;
564
568
  },
565
569
  fetcher: (instance) => (options) => getClientState(instance, {
566
- apiVersion: API_VERSION$3,
570
+ apiVersion: API_VERSION$5,
567
571
  // non-null assertion is fine because we check above
568
572
  projectId: options?.projectId ?? instance.config.projectId,
569
573
  useProjectHostname: !0
@@ -638,7 +642,7 @@ function discardDocument(doc) {
638
642
  documentId: effectiveDocumentId
639
643
  };
640
644
  }
641
- const DOCUMENT_STATE_CLEAR_DELAY = 1e3, INITIAL_OUTGOING_THROTTLE_TIME = 1e3, API_VERSION$2 = "v2025-05-06";
645
+ const DOCUMENT_STATE_CLEAR_DELAY = 1e3, INITIAL_OUTGOING_THROTTLE_TIME = 1e3, API_VERSION$4 = "v2025-05-06";
642
646
  function generateArrayKey(length = 12) {
643
647
  const numBytes = Math.ceil(length / 2), bytes = crypto.getRandomValues(new Uint8Array(numBytes));
644
648
  return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, length);
@@ -1562,7 +1566,7 @@ function processActions({
1562
1566
  transactionId,
1563
1567
  message: `Cannot publish because no draft version was found for document "${documentId}".`
1564
1568
  });
1565
- if (!isEqual(workingDraft, baseDraft))
1569
+ if (!isDeepEqual(workingDraft, baseDraft))
1566
1570
  throw new ActionError({
1567
1571
  documentId,
1568
1572
  transactionId,
@@ -1841,7 +1845,7 @@ function revertOutgoingTransaction(prev) {
1841
1845
  const next = {
1842
1846
  ...documentState,
1843
1847
  local: documentId in working ? working[documentId] : local,
1844
- unverifiedRevisions: prev.outgoing && prev.outgoing.transactionId in unverifiedRevisions ? omit(unverifiedRevisions, prev.outgoing.transactionId) : unverifiedRevisions
1848
+ unverifiedRevisions: prev.outgoing && prev.outgoing.transactionId in unverifiedRevisions ? omitProperty(unverifiedRevisions, prev.outgoing.transactionId) : unverifiedRevisions
1845
1849
  };
1846
1850
  return [documentId, next];
1847
1851
  })
@@ -1854,7 +1858,7 @@ function applyRemoteDocument(prev, { document, documentId, previousRev, revision
1854
1858
  if (!prevDocState) return prev;
1855
1859
  const prevUnverifiedRevisions = prevDocState.unverifiedRevisions, revisionToVerify = revision ? prevUnverifiedRevisions?.[revision] : void 0;
1856
1860
  let unverifiedRevisions = prevUnverifiedRevisions ?? EMPTY_REVISIONS;
1857
- if (revision && revisionToVerify && (unverifiedRevisions = omit(prevUnverifiedRevisions, revision)), type === "sync" && (unverifiedRevisions = Object.fromEntries(
1861
+ if (revision && revisionToVerify && (unverifiedRevisions = omitProperty(prevUnverifiedRevisions, revision)), type === "sync" && (unverifiedRevisions = Object.fromEntries(
1858
1862
  Object.entries(unverifiedRevisions).filter(([, unverifiedRevision]) => unverifiedRevision ? new Date(timestamp).getTime() <= new Date(unverifiedRevision.timestamp).getTime() : !1)
1859
1863
  )), revisionToVerify && revisionToVerify.previousRev === previousRev)
1860
1864
  return {
@@ -1925,7 +1929,7 @@ function removeSubscriptionIdFromDocument(prev, documentId, subscriptionId) {
1925
1929
  ...prev.documentStates,
1926
1930
  [documentId]: { ...prevDocState, subscriptions }
1927
1931
  }
1928
- } : { ...prev, documentStates: omit(prev.documentStates, documentId) } : prev;
1932
+ } : { ...prev, documentStates: omitProperty(prev.documentStates, documentId) } : prev;
1929
1933
  }
1930
1934
  function manageSubscriberIds({ state }, handles) {
1931
1935
  const documentIds = getDocumentIdsFromHandleLikes(handles), subscriptionId = insecureRandomId();
@@ -1978,12 +1982,11 @@ function getDocumentEvents(outgoing) {
1978
1982
  )
1979
1983
  );
1980
1984
  }
1981
- const API_VERSION$1 = "v2025-05-06";
1982
- function createSharedListener(instance, source) {
1985
+ const API_VERSION$3 = "v2025-05-06";
1986
+ function createSharedListener(instance, resource) {
1983
1987
  const dispose$ = new Subject(), events$ = getClientState(instance, {
1984
- apiVersion: API_VERSION$1,
1985
- // TODO: remove in v3 when we're ready for everything to be queried via source
1986
- source: source && !isDatasetSource(source) ? source : void 0
1988
+ apiVersion: API_VERSION$3,
1989
+ resource
1987
1990
  }).observable.pipe(
1988
1991
  switchMap(
1989
1992
  (client) => (
@@ -2017,12 +2020,11 @@ function createSharedListener(instance, source) {
2017
2020
  dispose: () => dispose$.next()
2018
2021
  };
2019
2022
  }
2020
- function createFetchDocument(instance, source) {
2023
+ function createFetchDocument(instance, resource) {
2021
2024
  return function(documentId) {
2022
2025
  return getClientState(instance, {
2023
- apiVersion: API_VERSION$1,
2024
- // TODO: remove in v3 when we're ready for everything to be queried via source
2025
- source: source && !isDatasetSource(source) ? source : void 0
2026
+ apiVersion: API_VERSION$3,
2027
+ resource
2026
2028
  }).observable.pipe(
2027
2029
  switchMap((client) => createDocumentLoaderFromClient(client)(documentId)),
2028
2030
  map$1((result) => {
@@ -2038,13 +2040,13 @@ function createFetchDocument(instance, source) {
2038
2040
  }
2039
2041
  const documentStore = defineStore({
2040
2042
  name: "Document",
2041
- getInitialState: (instance, { source }) => ({
2043
+ getInitialState: (instance, { resource }) => ({
2042
2044
  documentStates: {},
2043
2045
  // these can be emptied on refetch
2044
2046
  queued: [],
2045
2047
  applied: [],
2046
- sharedListener: createSharedListener(instance, source),
2047
- fetchDocument: createFetchDocument(instance, source),
2048
+ sharedListener: createSharedListener(instance, resource),
2049
+ fetchDocument: createFetchDocument(instance, resource),
2048
2050
  events: new Subject()
2049
2051
  }),
2050
2052
  initialize(context) {
@@ -2062,7 +2064,7 @@ const documentStore = defineStore({
2062
2064
  function getDocumentState(...args) {
2063
2065
  return _getDocumentState(...args);
2064
2066
  }
2065
- const _getDocumentState = bindActionBySource(
2067
+ const _getDocumentState = bindActionByResource(
2066
2068
  documentStore,
2067
2069
  createStateSourceAction({
2068
2070
  selector: ({ state: { error, documentStates } }, options) => {
@@ -2093,7 +2095,7 @@ const _getDocumentState = bindActionBySource(
2093
2095
  function resolveDocument(...args) {
2094
2096
  return _resolveDocument(...args);
2095
2097
  }
2096
- const _resolveDocument = bindActionBySource(
2098
+ const _resolveDocument = bindActionByResource(
2097
2099
  documentStore,
2098
2100
  ({ instance }, docHandle) => firstValueFrom(
2099
2101
  getDocumentState(instance, {
@@ -2101,7 +2103,7 @@ const _resolveDocument = bindActionBySource(
2101
2103
  path: void 0
2102
2104
  }).observable.pipe(filter$1((i) => i !== void 0))
2103
2105
  )
2104
- ), getDocumentSyncStatus = bindActionBySource(
2106
+ ), getDocumentSyncStatus = bindActionByResource(
2105
2107
  documentStore,
2106
2108
  createStateSourceAction({
2107
2109
  selector: ({ state: { error, documentStates: documents, outgoing, applied, queued } }, doc) => {
@@ -2119,7 +2121,7 @@ const _resolveDocument = bindActionBySource(
2119
2121
  },
2120
2122
  onSubscribe: (context, doc) => manageSubscriberIds(context, [doc])
2121
2123
  })
2122
- ), getPermissionsState = bindActionBySource(
2124
+ ), getPermissionsState = bindActionByResource(
2123
2125
  documentStore,
2124
2126
  createStateSourceAction({
2125
2127
  selector: calculatePermissions,
@@ -2127,12 +2129,12 @@ const _resolveDocument = bindActionBySource(
2127
2129
  manageSubscriberIds(context, actions);
2128
2130
  }
2129
2131
  })
2130
- ), resolvePermissions = bindActionBySource(
2132
+ ), resolvePermissions = bindActionByResource(
2131
2133
  documentStore,
2132
2134
  ({ instance }, options) => firstValueFrom(
2133
2135
  getPermissionsState(instance, options).observable.pipe(filter$1((i) => i !== void 0))
2134
2136
  )
2135
- ), subscribeDocumentEvents = bindActionBySource(
2137
+ ), subscribeDocumentEvents = bindActionByResource(
2136
2138
  documentStore,
2137
2139
  ({ state }, options) => {
2138
2140
  const { events } = state.get(), subscription = events.subscribe(options.eventHandler);
@@ -2164,7 +2166,7 @@ const _resolveDocument = bindActionBySource(
2164
2166
  }, subscribeToAppliedAndSubmitNextTransaction = ({
2165
2167
  state,
2166
2168
  instance,
2167
- key: { source }
2169
+ key: { resource }
2168
2170
  }) => {
2169
2171
  const { events } = state.get();
2170
2172
  return state.observable.pipe(
@@ -2186,9 +2188,8 @@ const _resolveDocument = bindActionBySource(
2186
2188
  distinctUntilChanged(),
2187
2189
  withLatestFrom(
2188
2190
  getClientState(instance, {
2189
- apiVersion: API_VERSION$2,
2190
- // TODO: remove in v3 when we're ready for everything to be queried via source
2191
- source: source && !isDatasetSource(source) ? source : void 0
2191
+ apiVersion: API_VERSION$4,
2192
+ resource
2192
2193
  }).observable
2193
2194
  ),
2194
2195
  concatMap(([outgoing, client]) => {
@@ -2262,19 +2263,18 @@ const _resolveDocument = bindActionBySource(
2262
2263
  }, subscribeToClientAndFetchDatasetAcl = ({
2263
2264
  instance,
2264
2265
  state,
2265
- key: { source }
2266
+ key: { resource }
2266
2267
  }) => {
2267
- const clientOptions = { apiVersion: API_VERSION$2 };
2268
- source && !isDatasetSource(source) && (clientOptions.source = source);
2268
+ const clientOptions = { apiVersion: API_VERSION$4, resource };
2269
2269
  let uri;
2270
- if (source && isDatasetSource(source))
2271
- uri = `/projects/${source.projectId}/datasets/${source.dataset}/acl`;
2272
- else if (source && isMediaLibrarySource(source))
2273
- uri = `/media-libraries/${source.mediaLibraryId}/acl`;
2274
- else if (source && isCanvasSource(source))
2275
- uri = `/canvases/${source.canvasId}/acl`;
2270
+ if (resource && isDatasetResource(resource))
2271
+ uri = `/projects/${resource.projectId}/datasets/${resource.dataset}/acl`;
2272
+ else if (resource && isMediaLibraryResource(resource))
2273
+ uri = `/media-libraries/${resource.mediaLibraryId}/acl`;
2274
+ else if (resource && isCanvasResource(resource))
2275
+ uri = `/canvases/${resource.canvasId}/acl`;
2276
2276
  else
2277
- throw new Error(`Received invalid source: ${JSON.stringify(source)}`);
2277
+ throw new Error(`Received invalid resource: ${JSON.stringify(resource)}`);
2278
2278
  return getClientState(instance, clientOptions).observable.pipe(
2279
2279
  switchMap(
2280
2280
  (client) => client.observable.request({
@@ -2291,7 +2291,7 @@ const _resolveDocument = bindActionBySource(
2291
2291
  function applyDocumentActions(...args) {
2292
2292
  return boundApplyDocumentActions(...args);
2293
2293
  }
2294
- const boundApplyDocumentActions = bindActionBySource(documentStore, _applyDocumentActions);
2294
+ const boundApplyDocumentActions = bindActionByResource(documentStore, _applyDocumentActions);
2295
2295
  async function _applyDocumentActions({ state }, { actions, transactionId = crypto.randomUUID(), disableBatching }) {
2296
2296
  const { events } = state.get(), transaction = {
2297
2297
  transactionId,
@@ -2386,7 +2386,75 @@ const favorites = createFetcherStore({
2386
2386
  })
2387
2387
  );
2388
2388
  }
2389
- }), getFavoritesState = favorites.getState, resolveFavoritesState = favorites.resolveState, usersStore = defineStore({
2389
+ }), getFavoritesState = favorites.getState, resolveFavoritesState = favorites.resolveState, API_VERSION$2 = "v2025-02-19";
2390
+ function resolveOrganizationId(options) {
2391
+ const organizationId = options?.organizationId;
2392
+ if (!organizationId)
2393
+ throw new Error("An organizationId is required to use the organization API.");
2394
+ return organizationId;
2395
+ }
2396
+ function normalizeOrganizationOptions$1(options) {
2397
+ return {
2398
+ includeMembers: options?.includeMembers ?? !1,
2399
+ includeFeatures: options?.includeFeatures ?? !1
2400
+ };
2401
+ }
2402
+ function getOrganizationCacheKey(_instance, options) {
2403
+ const organizationId = resolveOrganizationId(options), { includeMembers, includeFeatures } = normalizeOrganizationOptions$1(options);
2404
+ return `organization:${organizationId}${includeMembers ? ":members" : ""}${includeFeatures ? ":features" : ""}`;
2405
+ }
2406
+ const organization = createFetcherStore({
2407
+ name: "Organization",
2408
+ getKey: getOrganizationCacheKey,
2409
+ fetcher: (instance) => (options) => {
2410
+ const organizationId = resolveOrganizationId(options);
2411
+ return getClientState(instance, {
2412
+ apiVersion: API_VERSION$2,
2413
+ scope: "global"
2414
+ }).observable.pipe(
2415
+ switchMap((client) => {
2416
+ const normalized = normalizeOrganizationOptions$1(options), query = Object.fromEntries(
2417
+ Object.entries(normalized).filter(([, value]) => value !== void 0).map(([key, value]) => [key, String(value)])
2418
+ );
2419
+ return client.observable.request({
2420
+ uri: `/organizations/${organizationId}`,
2421
+ query,
2422
+ tag: "organization.get"
2423
+ });
2424
+ })
2425
+ );
2426
+ }
2427
+ }), getOrganizationState = organization.getState, resolveOrganization = organization.resolveState, API_VERSION$1 = "v2025-02-19";
2428
+ function normalizeOrganizationOptions(options) {
2429
+ return {
2430
+ includeImplicitMemberships: options?.includeImplicitMemberships ?? !1,
2431
+ includeMembers: options?.includeMembers ?? !1,
2432
+ includeFeatures: options?.includeFeatures ?? !1
2433
+ };
2434
+ }
2435
+ function getOrganizationsCacheKey(_instance, options) {
2436
+ const { includeMembers, includeFeatures, includeImplicitMemberships } = normalizeOrganizationOptions(options);
2437
+ return `organizations${includeMembers ? ":members" : ""}${includeFeatures ? ":features" : ""}${includeImplicitMemberships ? ":implicit" : ""}`;
2438
+ }
2439
+ const organizations = createFetcherStore({
2440
+ name: "Organizations",
2441
+ getKey: getOrganizationsCacheKey,
2442
+ fetcher: (instance) => (options) => getClientState(instance, {
2443
+ apiVersion: API_VERSION$1,
2444
+ scope: "global"
2445
+ }).observable.pipe(
2446
+ switchMap((client) => {
2447
+ const normalized = normalizeOrganizationOptions(options), query = Object.fromEntries(
2448
+ Object.entries(normalized).filter(([, value]) => value !== void 0).map(([key, value]) => [key, String(value)])
2449
+ );
2450
+ return client.observable.request({
2451
+ uri: "/organizations",
2452
+ query,
2453
+ tag: "organizations.get"
2454
+ });
2455
+ })
2456
+ )
2457
+ }), getOrganizationsState = organizations.getState, resolveOrganizations = organizations.resolveState, usersStore = defineStore({
2390
2458
  name: "UsersStore",
2391
2459
  getInitialState: () => ({ users: {} }),
2392
2460
  initialize: (context) => {
@@ -2452,7 +2520,7 @@ const favorites = createFetcherStore({
2452
2520
  );
2453
2521
  const scope = userId.startsWith("g") ? "global" : void 0, client = getClient(instance, {
2454
2522
  scope,
2455
- apiVersion: API_VERSION$6
2523
+ apiVersion: API_VERSION$8
2456
2524
  }), resourceType2 = options.resourceType || "project", resourceId = resourceType2 === "organization" ? options.organizationId : options.projectId;
2457
2525
  return resourceId ? client.observable.request({
2458
2526
  method: "GET",
@@ -2472,7 +2540,7 @@ const favorites = createFetcherStore({
2472
2540
  filter$1((i) => typeof i == "string")
2473
2541
  ), 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, {
2474
2542
  scope: "global",
2475
- apiVersion: API_VERSION$6
2543
+ apiVersion: API_VERSION$8
2476
2544
  }).observable, loadMore$ = state.observable.pipe(
2477
2545
  map$1((s) => s.users[group$.key]?.lastLoadMoreRequest),
2478
2546
  distinctUntilChanged()
@@ -2576,10 +2644,19 @@ const favorites = createFetcherStore({
2576
2644
  );
2577
2645
  function getBifurClient(client, token$) {
2578
2646
  const bifurVersionedClient = client.withConfig({ apiVersion: "2022-06-30" }), {
2647
+ resource,
2579
2648
  dataset,
2580
2649
  url: baseUrl,
2581
2650
  requestTagPrefix = "sanity.sdk.presence"
2582
- } = bifurVersionedClient.config(), urlWithTag = `${`${baseUrl.replace(/\/+$/, "")}/socket/${dataset}`.replace(/^http/, "ws")}?tag=${requestTagPrefix}`;
2651
+ } = bifurVersionedClient.config();
2652
+ let resourcePath;
2653
+ if (resource?.type === "canvas")
2654
+ resourcePath = `canvases/${resource.id}`;
2655
+ else if (dataset)
2656
+ resourcePath = dataset;
2657
+ else
2658
+ throw new Error("Unable to determine presence URL: no canvas resource or dataset configured");
2659
+ const urlWithTag = `${`${baseUrl}/socket/${resourcePath}`.replace(/^http/, "ws")}?tag=${requestTagPrefix}`;
2583
2660
  return fromUrl(urlWithTag, { token$ });
2584
2661
  }
2585
2662
  const handleIncomingMessage = (event) => {
@@ -2626,7 +2703,7 @@ const handleIncomingMessage = (event) => {
2626
2703
  }
2627
2704
  };
2628
2705
  return typeof window < "u" && fromEvent(window, "beforeunload").pipe(switchMap$1(() => dispatchMessage({ type: "disconnect" }))).subscribe(), [incomingEvents$.pipe(share$1()), dispatchMessage];
2629
- }, getInitialState = () => ({
2706
+ }, PRESENCE_API_VERSION = "2026-03-30", getInitialState = () => ({
2630
2707
  locations: /* @__PURE__ */ new Map(),
2631
2708
  users: {}
2632
2709
  }), presenceStore = defineStore({
@@ -2636,17 +2713,24 @@ const handleIncomingMessage = (event) => {
2636
2713
  const {
2637
2714
  instance,
2638
2715
  state,
2639
- key: { projectId, dataset }
2640
- } = context, sessionId = crypto.randomUUID(), client = getClient(instance, {
2641
- apiVersion: "2022-06-30",
2642
- projectId,
2643
- dataset
2716
+ key: { resource }
2717
+ } = context;
2718
+ if (isMediaLibraryResource(resource))
2719
+ throw new Error("Presence is not supported for media library resources.");
2720
+ const sessionId = crypto.randomUUID(), client = isDatasetResource(resource) ? getClient(instance, {
2721
+ apiVersion: PRESENCE_API_VERSION,
2722
+ projectId: resource.projectId,
2723
+ dataset: resource.dataset,
2724
+ useProjectHostname: !0
2725
+ }) : getClient(instance, {
2726
+ apiVersion: PRESENCE_API_VERSION,
2727
+ resource
2644
2728
  }), token$ = getTokenState(instance).observable.pipe(distinctUntilChanged()), [incomingEvents$, dispatch] = createBifurTransport({
2645
2729
  client,
2646
2730
  token$,
2647
2731
  sessionId
2648
2732
  }), subscription = new Subscription();
2649
- return subscription.add(
2733
+ if (subscription.add(
2650
2734
  incomingEvents$.subscribe((event) => {
2651
2735
  "sessionId" in event && event.sessionId === sessionId || (event.type === "state" ? state.set("presence/state", (prevState) => {
2652
2736
  const newLocations = new Map(prevState.locations);
@@ -2662,7 +2746,18 @@ const handleIncomingMessage = (event) => {
2662
2746
  return newLocations.delete(event.sessionId), { ...prevState, locations: newLocations };
2663
2747
  }));
2664
2748
  })
2665
- ), dispatch({ type: "rollCall" }).subscribe(), () => {
2749
+ ), dispatch({ type: "rollCall" }).subscribe(), isCanvasResource(resource)) {
2750
+ const globalClient = getClient(instance, { apiVersion: PRESENCE_API_VERSION });
2751
+ subscription.add(
2752
+ globalClient.observable.request({
2753
+ uri: `/canvases/${resource.canvasId}`,
2754
+ tag: "canvases.get"
2755
+ }).pipe(catchError$1(() => EMPTY)).subscribe(({ organizationId }) => {
2756
+ state.set("presence/organizationId", (prev) => ({ ...prev, organizationId }));
2757
+ })
2758
+ );
2759
+ }
2760
+ return () => {
2666
2761
  dispatch({ type: "disconnect" }).subscribe(), subscription.unsubscribe();
2667
2762
  };
2668
2763
  }
@@ -2679,31 +2774,34 @@ const handleIncomingMessage = (event) => {
2679
2774
  sessionId,
2680
2775
  locations: locs
2681
2776
  }))
2682
- ), getPresence = bindActionByDataset(
2777
+ ), _getPresence = bindActionByResource(
2683
2778
  presenceStore,
2684
2779
  createStateSourceAction({
2685
- selector: (context, _) => selectPresence(context.state),
2686
- onSubscribe: (context, _) => {
2687
- const subscription = context.state.observable.pipe(
2780
+ selector: (context) => selectPresence(context.state),
2781
+ onSubscribe: (context) => {
2782
+ const resource = context.key.resource, userIds$ = context.state.observable.pipe(
2688
2783
  map$1(
2689
2784
  (state) => Array.from(state.locations.values()).map((l) => l.userId).filter((id) => !!id)
2690
2785
  ),
2691
2786
  distinctUntilChanged((a, b) => a.length === b.length && a.every((v, i) => v === b[i]))
2692
- ).pipe(
2693
- switchMap((userIds) => {
2787
+ ), organizationId$ = isCanvasResource(resource) ? context.state.observable.pipe(
2788
+ map$1((s) => s.organizationId),
2789
+ filter$1((id) => id !== void 0),
2790
+ first$1()
2791
+ ) : of(void 0), subscription = combineLatest([userIds$, organizationId$]).pipe(
2792
+ switchMap(([userIds, organizationId]) => {
2694
2793
  if (userIds.length === 0)
2695
2794
  return of([]);
2696
2795
  const userObservables = userIds.map(
2697
2796
  (userId) => getUserState(context.instance, {
2698
2797
  userId,
2699
- resourceType: "project",
2700
- projectId: context.key.projectId
2798
+ ...isDatasetResource(resource) ? { resourceType: "project", projectId: resource.projectId } : { resourceType: "organization", organizationId }
2701
2799
  }).pipe(filter$1((v) => !!v))
2702
2800
  );
2703
2801
  return combineLatest(userObservables);
2704
2802
  })
2705
2803
  ).subscribe((users) => {
2706
- users && context.state.set("presence/users", (prevState) => ({
2804
+ context.state.set("presence/users", (prevState) => ({
2707
2805
  ...prevState,
2708
2806
  users: {
2709
2807
  ...prevState.users,
@@ -2715,6 +2813,9 @@ const handleIncomingMessage = (event) => {
2715
2813
  }
2716
2814
  })
2717
2815
  );
2816
+ function getPresence(instance, params) {
2817
+ return _getPresence(instance, params ?? {});
2818
+ }
2718
2819
  function hashString(str) {
2719
2820
  let hash = 0;
2720
2821
  for (let i = 0; i < str.length; i++)
@@ -2800,13 +2901,13 @@ function processStatusQueryResults(results) {
2800
2901
  const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Array.from(a).every((i) => b.has(i)), subscribeToStateAndFetchBatches = ({
2801
2902
  state,
2802
2903
  instance,
2803
- key: { source, perspective }
2904
+ key: { resource, perspective }
2804
2905
  }) => {
2805
2906
  const documentProjections$ = state.observable.pipe(
2806
2907
  map$1((s) => s.documentProjections),
2807
- distinctUntilChanged(isEqual)
2908
+ distinctUntilChanged(isDeepEqual)
2808
2909
  ), activeDocumentIds$ = state.observable.pipe(
2809
- map$1(({ subscriptions }) => new Set(Object.keys(subscriptions))),
2910
+ map$1(({ subscriptions }) => new Set(Object.keys(subscriptions).map((id) => DocumentId(id)))),
2810
2911
  distinctUntilChanged(isSetEqual)
2811
2912
  ), pendingUpdateSubscription = activeDocumentIds$.pipe(
2812
2913
  debounceTime(BATCH_DEBOUNCE_TIME),
@@ -2834,7 +2935,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
2834
2935
  })
2835
2936
  ).subscribe(), queryExecutionSubscription = combineLatest([activeDocumentIds$, documentProjections$]).pipe(
2836
2937
  debounceTime(BATCH_DEBOUNCE_TIME),
2837
- distinctUntilChanged(isEqual)
2938
+ distinctUntilChanged(isDeepEqual)
2838
2939
  ).pipe(
2839
2940
  switchMap(([ids, documentProjections]) => {
2840
2941
  if (!ids.size) return EMPTY;
@@ -2844,8 +2945,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
2844
2945
  params,
2845
2946
  tag: PROJECTION_TAG,
2846
2947
  perspective,
2847
- // temporary guard here until we're ready for everything to be queried via global API
2848
- ...source && !isDatasetSource(source) ? { source } : {}
2948
+ resource
2849
2949
  }), subscription = defer(() => getCurrent() === void 0 ? from(
2850
2950
  resolveQuery(instance, {
2851
2951
  query,
@@ -2853,8 +2953,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
2853
2953
  tag: PROJECTION_TAG,
2854
2954
  signal: controller.signal,
2855
2955
  perspective,
2856
- // temporary guard here until we're ready for everything to be queried via global API in v3
2857
- ...source && !isDatasetSource(source) ? { source } : {}
2956
+ resource
2858
2957
  })
2859
2958
  ).pipe(switchMap(() => observable)) : observable).pipe(filter$1((result) => result !== void 0)).subscribe(observer);
2860
2959
  return () => {
@@ -2866,8 +2965,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
2866
2965
  params: statusParams,
2867
2966
  tag: PROJECTION_TAG,
2868
2967
  perspective: "raw",
2869
- // temporary guard here until we're ready for everything to be queried via global API
2870
- ...source && !isDatasetSource(source) ? { source } : {}
2968
+ resource
2871
2969
  }), subscription = defer(() => getCurrent() === void 0 ? from(
2872
2970
  resolveQuery(instance, {
2873
2971
  query: statusQuery,
@@ -2875,8 +2973,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
2875
2973
  tag: PROJECTION_TAG,
2876
2974
  signal: controller.signal,
2877
2975
  perspective: "raw",
2878
- // temporary guard here until we're ready for everything to be queried via global API
2879
- ...source && !isDatasetSource(source) ? { source } : {}
2976
+ resource
2880
2977
  })
2881
2978
  ).pipe(switchMap(() => observable)) : observable).pipe(filter$1((result) => result !== void 0)).subscribe(observer);
2882
2979
  return () => {
@@ -2946,7 +3043,7 @@ const BATCH_DEBOUNCE_TIME = 50, isSetEqual = (a, b) => a.size === b.size && Arra
2946
3043
  function getProjectionState(...args) {
2947
3044
  return _getProjectionState(...args);
2948
3045
  }
2949
- const _getProjectionState = bindActionBySourceAndPerspective(
3046
+ const _getProjectionState = bindActionByResourceAndPerspective(
2950
3047
  projectionStore,
2951
3048
  createStateSourceAction({
2952
3049
  selector: ({ state }, options) => {
@@ -2976,7 +3073,7 @@ const _getProjectionState = bindActionBySourceAndPerspective(
2976
3073
  })), () => {
2977
3074
  setCleanupTimeout(() => {
2978
3075
  state.set("removeSubscription", (prev) => {
2979
- const documentSubscriptionsForHash = omit(
3076
+ const documentSubscriptionsForHash = omitProperty(
2980
3077
  prev.subscriptions[documentId]?.[projectionHash],
2981
3078
  subscriptionId
2982
3079
  ), hasSubscribersForProjection = !!Object.keys(documentSubscriptionsForHash).length, nextSubscriptions = { ...prev.subscriptions }, nextDocumentProjections = { ...prev.documentProjections }, nextValues = { ...prev.values };
@@ -3008,7 +3105,7 @@ function getPreviewState(instance, options) {
3008
3105
  ...options,
3009
3106
  projection: PREVIEW_PROJECTION
3010
3107
  }), transformResult = (current) => !current || current.data === null ? { data: null, isPending: current?.isPending ?? !1 } : {
3011
- data: transformProjectionToPreview(instance, current.data, options.source),
3108
+ data: transformProjectionToPreview(instance, current.data, options.resource),
3012
3109
  isPending: current.isPending
3013
3110
  };
3014
3111
  return {
@@ -3020,7 +3117,7 @@ function getPreviewState(instance, options) {
3020
3117
  function resolveProjection(...args) {
3021
3118
  return _resolveProjection(...args);
3022
3119
  }
3023
- const _resolveProjection = bindActionBySourceAndPerspective(
3120
+ const _resolveProjection = bindActionByResourceAndPerspective(
3024
3121
  projectionStore,
3025
3122
  ({ instance }, options) => firstValueFrom(
3026
3123
  getProjectionState(instance, options).observable.pipe(
@@ -3034,27 +3131,42 @@ async function resolvePreview(instance, options) {
3034
3131
  projection: PREVIEW_PROJECTION
3035
3132
  });
3036
3133
  return projectionResult.data ? {
3037
- data: transformProjectionToPreview(instance, projectionResult.data, options.source),
3134
+ data: transformProjectionToPreview(
3135
+ instance,
3136
+ projectionResult.data,
3137
+ options.resource
3138
+ ),
3038
3139
  isPending: projectionResult.isPending
3039
3140
  } : { data: null, isPending: projectionResult.isPending };
3040
3141
  }
3041
- const API_VERSION = "v2025-02-19", projects = createFetcherStore({
3142
+ const API_VERSION = "v2025-02-19";
3143
+ function normalizeProjectsOptions(options) {
3144
+ return {
3145
+ organizationId: options?.organizationId,
3146
+ includeMembers: options?.includeMembers ?? !1,
3147
+ includeFeatures: options?.includeFeatures ?? !0,
3148
+ onlyExplicitMembership: options?.onlyExplicitMembership ?? !1
3149
+ };
3150
+ }
3151
+ function getProjectsCacheKey(_instance, options) {
3152
+ const { organizationId, includeMembers, includeFeatures, onlyExplicitMembership } = normalizeProjectsOptions(options);
3153
+ return `projects${organizationId ? `:org:${organizationId}` : ""}${includeMembers ? ":members" : ""}${includeFeatures ? ":features" : ""}${onlyExplicitMembership ? ":explicit" : ""}`;
3154
+ }
3155
+ const projects = createFetcherStore({
3042
3156
  name: "Projects",
3043
- getKey: (_instance, options) => {
3044
- const orgKey = options?.organizationId ? `:org:${options.organizationId}` : "", membersKey = options?.includeMembers === !1 ? ":no-members" : "";
3045
- return `projects${orgKey}${membersKey}`;
3046
- },
3157
+ getKey: getProjectsCacheKey,
3047
3158
  fetcher: (instance) => (options) => getClientState(instance, {
3048
3159
  apiVersion: API_VERSION,
3049
- scope: "global",
3050
- requestTagPrefix: "sanity.sdk.projects"
3160
+ scope: "global"
3051
3161
  }).observable.pipe(
3052
3162
  switchMap((client) => {
3053
- const organizationId = options?.organizationId;
3054
- return client.observable.projects.list({
3055
- // client method has a type that expects false | undefined
3056
- includeMembers: options?.includeMembers ? void 0 : !1,
3057
- organizationId
3163
+ const normalized = normalizeProjectsOptions(options), query = Object.fromEntries(
3164
+ Object.entries(normalized).filter(([, value]) => value !== void 0).map(([key, value]) => [key, String(value)])
3165
+ );
3166
+ return client.observable.request({
3167
+ uri: "/projects",
3168
+ query,
3169
+ tag: "projects.get"
3058
3170
  });
3059
3171
  })
3060
3172
  )
@@ -3117,6 +3229,12 @@ function getCorsErrorProjectId(error) {
3117
3229
  const projMatch = (error.message || "").match(/manage\/project\/([^/?#]+)/);
3118
3230
  return projMatch ? projMatch[1] : null;
3119
3231
  }
3232
+ function isImportError(error) {
3233
+ if (!(error instanceof Error)) return !1;
3234
+ if (error.name === "ChunkLoadError") return !0;
3235
+ const message = error.message || "";
3236
+ 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);
3237
+ }
3120
3238
  export {
3121
3239
  AuthStateType,
3122
3240
  CORE_SDK_VERSION,
@@ -3161,6 +3279,8 @@ export {
3161
3279
  getOrCreateChannel,
3162
3280
  getOrCreateController,
3163
3281
  getOrCreateNode,
3282
+ getOrganizationState,
3283
+ getOrganizationsState,
3164
3284
  getPathDepth,
3165
3285
  getPermissionsState,
3166
3286
  getPerspectiveState,
@@ -3176,8 +3296,12 @@ export {
3176
3296
  getUsersKey,
3177
3297
  getUsersState,
3178
3298
  handleAuthCallback,
3299
+ isCanvasResource,
3179
3300
  isCanvasSource,
3301
+ isDatasetResource,
3180
3302
  isDatasetSource,
3303
+ isImportError,
3304
+ isMediaLibraryResource,
3181
3305
  isMediaLibrarySource,
3182
3306
  isProjectUserNotFoundClientError,
3183
3307
  isStudioConfig,
@@ -3194,6 +3318,8 @@ export {
3194
3318
  resolveDatasets,
3195
3319
  resolveDocument,
3196
3320
  resolveFavoritesState,
3321
+ resolveOrganization,
3322
+ resolveOrganizations,
3197
3323
  resolvePermissions,
3198
3324
  resolvePreview,
3199
3325
  resolveProject,