@sanity/sdk 3.0.0-rc.0 → 3.0.0-rc.2

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 (241) hide show
  1. package/README.md +12 -0
  2. package/dist/_exports/_internal.d.ts +163 -0
  3. package/dist/_exports/_internal.d.ts.map +1 -0
  4. package/dist/_exports/_internal.js +332 -0
  5. package/dist/_exports/_internal.js.map +1 -0
  6. package/dist/_exports/agent.d.ts +65 -0
  7. package/dist/_exports/agent.d.ts.map +1 -0
  8. package/dist/_exports/agent.js +71 -0
  9. package/dist/_exports/agent.js.map +1 -0
  10. package/dist/_exports/comlink.d.ts +118 -0
  11. package/dist/_exports/comlink.d.ts.map +1 -0
  12. package/dist/_exports/comlink.js +69 -0
  13. package/dist/_exports/comlink.js.map +1 -0
  14. package/dist/authStore-CtE9bLHW.js +754 -0
  15. package/dist/authStore-CtE9bLHW.js.map +1 -0
  16. package/dist/authStore-DKFX8fn7.d.ts +3179 -0
  17. package/dist/authStore-DKFX8fn7.d.ts.map +1 -0
  18. package/dist/clientStore-BtE2-q2i.js +90 -0
  19. package/dist/clientStore-BtE2-q2i.js.map +1 -0
  20. package/dist/createSanityInstance-DUI1bGIg.d.ts +278 -0
  21. package/dist/createSanityInstance-DUI1bGIg.d.ts.map +1 -0
  22. package/dist/createStateSourceAction-BOKtqFNm.js +300 -0
  23. package/dist/createStateSourceAction-BOKtqFNm.js.map +1 -0
  24. package/dist/getEnv-D5RGkQLu.js +8 -0
  25. package/dist/getEnv-D5RGkQLu.js.map +1 -0
  26. package/dist/getNodeState-CR3__B2D.js +67 -0
  27. package/dist/getNodeState-CR3__B2D.js.map +1 -0
  28. package/dist/index.d.ts +3 -2332
  29. package/dist/index.js +4171 -4332
  30. package/dist/index.js.map +1 -1
  31. package/dist/logger-DAtJb5RQ.js +173 -0
  32. package/dist/logger-DAtJb5RQ.js.map +1 -0
  33. package/dist/object-CxXlSVg7.js +83 -0
  34. package/dist/object-CxXlSVg7.js.map +1 -0
  35. package/dist/queryStore-DPf9sN3V.js +1346 -0
  36. package/dist/queryStore-DPf9sN3V.js.map +1 -0
  37. package/dist/rolldown-runtime-vyAXikos.js +9 -0
  38. package/dist/setCleanupTimeout-BiM6q1KF.js +31 -0
  39. package/dist/setCleanupTimeout-BiM6q1KF.js.map +1 -0
  40. package/dist/telemetryManager-Dq_qCkeI.js +127 -0
  41. package/dist/telemetryManager-Dq_qCkeI.js.map +1 -0
  42. package/dist/version-BChjsi4u.js +9 -0
  43. package/dist/version-BChjsi4u.js.map +1 -0
  44. package/package.json +47 -52
  45. package/src/_exports/_internal.ts +27 -0
  46. package/src/_exports/agent.ts +19 -0
  47. package/src/_exports/comlink.ts +16 -0
  48. package/src/_exports/index.ts +125 -64
  49. package/src/access/checkPermissions.test.ts +55 -0
  50. package/src/access/checkPermissions.ts +54 -0
  51. package/src/agent/agentActions.test.ts +16 -60
  52. package/src/agent/agentActions.ts +25 -38
  53. package/src/applications/applications.test-d.ts +88 -0
  54. package/src/applications/applications.test.ts +130 -0
  55. package/src/applications/applications.ts +367 -0
  56. package/src/auth/authLogger.ts +30 -0
  57. package/src/auth/authStore.test.ts +194 -13
  58. package/src/auth/authStore.ts +58 -26
  59. package/src/auth/getOrganizationVerificationState.test.ts +18 -17
  60. package/src/auth/getOrganizationVerificationState.ts +4 -4
  61. package/src/auth/handleAuthCallback.test.ts +35 -1
  62. package/src/auth/handleAuthCallback.ts +25 -6
  63. package/src/auth/logout.test.ts +75 -2
  64. package/src/auth/logout.ts +23 -4
  65. package/src/auth/refreshStampedToken.test.ts +219 -469
  66. package/src/auth/refreshStampedToken.ts +79 -195
  67. package/src/auth/studioAuth.ts +1 -1
  68. package/src/auth/studioModeAuth.ts +2 -1
  69. package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +146 -13
  70. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +37 -6
  71. package/src/auth/subscribeToStorageEventsAndSetToken.test.ts +2 -0
  72. package/src/client/clientStore.test.ts +62 -37
  73. package/src/client/clientStore.ts +45 -75
  74. package/src/client/liveEvents.test.ts +151 -0
  75. package/src/client/liveEvents.ts +107 -0
  76. package/src/comlink/controller/actions/destroyController.test.ts +4 -1
  77. package/src/comlink/controller/actions/getOrCreateChannel.test.ts +4 -1
  78. package/src/comlink/controller/actions/getOrCreateChannel.ts +2 -2
  79. package/src/comlink/controller/actions/getOrCreateController.test.ts +4 -1
  80. package/src/comlink/controller/actions/releaseChannel.test.ts +1 -1
  81. package/src/comlink/controller/comlinkControllerStore.test.ts +4 -1
  82. package/src/comlink/node/actions/getOrCreateNode.test.ts +9 -3
  83. package/src/comlink/node/actions/getOrCreateNode.ts +2 -2
  84. package/src/comlink/node/actions/releaseNode.test.ts +7 -4
  85. package/src/comlink/node/comlinkNodeStore.test.ts +2 -2
  86. package/src/comlink/node/getNodeState.test.ts +1 -1
  87. package/src/comlink/node/getNodeState.ts +2 -1
  88. package/src/comments/addonDatasetStore.test.ts +215 -0
  89. package/src/comments/addonDatasetStore.ts +249 -0
  90. package/src/comments/buildCommentThreads.test.ts +83 -0
  91. package/src/comments/buildCommentThreads.ts +54 -0
  92. package/src/comments/commentActions.test.ts +540 -0
  93. package/src/comments/commentActions.ts +555 -0
  94. package/src/comments/commentFieldPath.test.ts +40 -0
  95. package/src/comments/commentFieldPath.ts +44 -0
  96. package/src/comments/commentsConstants.ts +80 -0
  97. package/src/comments/commentsStore.test.ts +419 -0
  98. package/src/comments/commentsStore.ts +483 -0
  99. package/src/comments/normalizeComment.test.ts +116 -0
  100. package/src/comments/normalizeComment.ts +45 -0
  101. package/src/comments/observeComments.test.ts +193 -0
  102. package/src/comments/observeComments.ts +113 -0
  103. package/src/comments/reducers.test.ts +277 -0
  104. package/src/comments/reducers.ts +316 -0
  105. package/src/comments/types.ts +249 -0
  106. package/src/comments/weakenReferences.test.ts +47 -0
  107. package/src/comments/weakenReferences.ts +29 -0
  108. package/src/config/__tests__/handles.test.ts +18 -12
  109. package/src/config/handles.ts +25 -7
  110. package/src/config/sanityConfig.ts +40 -82
  111. package/src/datasets/datasets.test.ts +2 -2
  112. package/src/datasets/datasets.ts +10 -4
  113. package/src/document/actions.test.ts +115 -33
  114. package/src/document/actions.ts +212 -15
  115. package/src/document/applyDocumentActions.test.ts +35 -13
  116. package/src/document/applyDocumentActions.ts +30 -9
  117. package/src/document/documentConstants.ts +15 -0
  118. package/src/document/documentStore.concurrency.test.ts +1306 -0
  119. package/src/document/documentStore.test.ts +753 -273
  120. package/src/document/documentStore.ts +197 -75
  121. package/src/document/events.test.ts +57 -2
  122. package/src/document/events.ts +82 -26
  123. package/src/document/listen.test.ts +56 -0
  124. package/src/document/listen.ts +74 -21
  125. package/src/document/listenerEventOperators.test.ts +311 -0
  126. package/src/document/listenerEventOperators.ts +217 -0
  127. package/src/document/patchOperations.test.ts +76 -2
  128. package/src/document/patchOperations.ts +60 -1
  129. package/src/document/permissions.test.ts +107 -60
  130. package/src/document/permissions.ts +44 -19
  131. package/src/document/processActions/create.ts +138 -0
  132. package/src/document/processActions/delete.ts +100 -0
  133. package/src/document/processActions/discard.ts +63 -0
  134. package/src/document/processActions/edit.ts +154 -0
  135. package/src/document/processActions/processActions.ts +218 -0
  136. package/src/document/processActions/publish.ts +120 -0
  137. package/src/document/processActions/releaseArchive.ts +77 -0
  138. package/src/document/processActions/releaseCreate.ts +59 -0
  139. package/src/document/processActions/releaseDelete.ts +65 -0
  140. package/src/document/processActions/releaseEdit.ts +37 -0
  141. package/src/document/processActions/releasePublish.ts +45 -0
  142. package/src/document/processActions/releaseSchedule.ts +87 -0
  143. package/src/document/processActions/releaseUtil.ts +31 -0
  144. package/src/document/processActions/shared.ts +308 -0
  145. package/src/document/processActions/unpublish.ts +85 -0
  146. package/src/document/processActions.test.ts +1129 -121
  147. package/src/document/reducers.test.ts +772 -64
  148. package/src/document/reducers.ts +205 -51
  149. package/src/document/resourceRules.test.ts +178 -0
  150. package/src/document/resourceRules.ts +117 -0
  151. package/src/document/sharedListener.test.ts +16 -14
  152. package/src/document/sharedListener.ts +24 -8
  153. package/src/document/util.test.ts +46 -0
  154. package/src/document/util.ts +50 -0
  155. package/src/favorites/favorites.test.ts +5 -6
  156. package/src/installations/installations.test-d.ts +73 -0
  157. package/src/installations/installations.test.ts +62 -0
  158. package/src/installations/installations.ts +206 -0
  159. package/src/organization/organization.test-d.ts +36 -0
  160. package/src/organization/organization.test.ts +138 -0
  161. package/src/organization/organization.ts +138 -0
  162. package/src/organizations/organizations.test-d.ts +56 -0
  163. package/src/organizations/organizations.test.ts +150 -0
  164. package/src/organizations/organizations.ts +107 -0
  165. package/src/presence/bifurTransport.test.ts +201 -9
  166. package/src/presence/bifurTransport.ts +98 -14
  167. package/src/presence/paths.test.ts +70 -0
  168. package/src/presence/paths.ts +41 -0
  169. package/src/presence/presenceStore.test.ts +915 -24
  170. package/src/presence/presenceStore.ts +576 -104
  171. package/src/presence/types.ts +175 -3
  172. package/src/preview/previewProjectionUtils.test.ts +9 -22
  173. package/src/preview/previewProjectionUtils.ts +7 -3
  174. package/src/preview/types.ts +0 -15
  175. package/src/project/project.test-d.ts +37 -0
  176. package/src/project/project.test.ts +157 -12
  177. package/src/project/project.ts +138 -25
  178. package/src/projection/getProjectionState.test.ts +18 -20
  179. package/src/projection/getProjectionState.ts +23 -3
  180. package/src/projection/projectionQuery.ts +5 -5
  181. package/src/projection/projectionStore.test.ts +1 -9
  182. package/src/projection/resolveProjection.test.ts +1 -2
  183. package/src/projection/resolveProjection.ts +16 -0
  184. package/src/projection/subscribeToStateAndFetchBatches.test.ts +1 -1
  185. package/src/projection/subscribeToStateAndFetchBatches.ts +32 -23
  186. package/src/projects/projects.test-d.ts +32 -0
  187. package/src/projects/projects.test.ts +108 -42
  188. package/src/projects/projects.ts +63 -27
  189. package/src/query/queryStore.test.ts +259 -123
  190. package/src/query/queryStore.ts +85 -69
  191. package/src/query/reducers.test.ts +0 -42
  192. package/src/query/reducers.ts +2 -18
  193. package/src/releases/getPerspectiveState.test.ts +17 -23
  194. package/src/releases/getPerspectiveState.ts +8 -20
  195. package/src/releases/observeReleases.test.ts +127 -0
  196. package/src/releases/observeReleases.ts +102 -0
  197. package/src/releases/releasesStore.test.ts +100 -53
  198. package/src/releases/releasesStore.ts +69 -44
  199. package/src/releases/utils/sortReleases.test.ts +38 -2
  200. package/src/releases/utils/sortReleases.ts +15 -10
  201. package/src/store/createActionBinder.test.ts +109 -90
  202. package/src/store/createActionBinder.ts +36 -28
  203. package/src/store/createSanityInstance.test.ts +15 -13
  204. package/src/store/createSanityInstance.ts +14 -2
  205. package/src/store/createStateSourceAction.test.ts +64 -2
  206. package/src/store/createStateSourceAction.ts +38 -43
  207. package/src/store/createStoreInstance.test.ts +4 -2
  208. package/src/store/fetcherStore.test-d.ts +121 -0
  209. package/src/store/fetcherStore.test.ts +299 -0
  210. package/src/store/fetcherStore.ts +801 -0
  211. package/src/telemetry/environment.test.ts +119 -0
  212. package/src/telemetry/environment.ts +92 -0
  213. package/src/telemetry/events.ts +42 -0
  214. package/src/telemetry/initTelemetry.test.ts +432 -0
  215. package/src/telemetry/initTelemetry.ts +218 -0
  216. package/src/telemetry/telemetryManager.test.ts +327 -0
  217. package/src/telemetry/telemetryManager.ts +199 -0
  218. package/src/users/reducers.test.ts +3 -1
  219. package/src/users/reducers.ts +5 -6
  220. package/src/users/types.ts +4 -4
  221. package/src/users/usersStore.test.ts +16 -12
  222. package/src/users/usersStore.ts +5 -1
  223. package/src/utils/buildQuery.test.ts +14 -0
  224. package/src/utils/buildQuery.ts +17 -0
  225. package/src/utils/createFetcherStore.test.ts +7 -5
  226. package/src/utils/createFetcherStore.ts +8 -5
  227. package/src/utils/getStagingApiHost.test.ts +21 -0
  228. package/src/utils/getStagingApiHost.ts +14 -0
  229. package/src/utils/ids.test.ts +1 -29
  230. package/src/utils/ids.ts +0 -10
  231. package/src/utils/includeShape.ts +36 -0
  232. package/src/utils/isImportError.test.ts +72 -0
  233. package/src/utils/isImportError.ts +34 -0
  234. package/src/utils/logger.test.ts +12 -0
  235. package/src/utils/logger.ts +8 -3
  236. package/src/utils/object.test.ts +95 -0
  237. package/src/utils/object.ts +142 -0
  238. package/src/utils/setCleanupTimeout.ts +37 -0
  239. package/src/document/processActions.ts +0 -707
  240. package/src/utils/defineIntent.test.ts +0 -477
  241. package/src/utils/defineIntent.ts +0 -244
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/config/sanityConfig.ts","../src/releases/utils/isReleasePerspective.ts","../src/utils/ids.ts","../src/utils/logger.ts","../src/store/createSanityInstance.ts","../src/utils/getEnv.ts","../src/store/createStoreState.ts","../src/store/createStoreInstance.ts","../src/store/createActionBinder.ts","../src/store/createStateSourceAction.ts","../src/auth/authConstants.ts","../src/auth/authMode.ts","../src/auth/authStateType.ts","../src/auth/refreshStampedToken.ts","../src/auth/subscribeToStateAndFetchCurrentUser.ts","../src/auth/utils.ts","../src/auth/dashboardAuth.ts","../src/auth/subscribeToStorageEventsAndSetToken.ts","../src/auth/standaloneAuth.ts","../src/auth/studioModeAuth.ts","../src/auth/studioAuth.ts","../src/auth/authStore.ts","../src/client/clientStore.ts","../src/agent/agentActions.ts","../src/project/organizationVerification.ts","../src/utils/createFetcherStore.ts","../src/project/project.ts","../src/auth/dashboardUtils.ts","../src/auth/getOrganizationVerificationState.ts","../src/auth/handleAuthCallback.ts","../src/auth/logout.ts","../src/comlink/controller/actions/destroyController.ts","../src/comlink/controller/actions/getOrCreateChannel.ts","../src/comlink/controller/actions/getOrCreateController.ts","../src/comlink/controller/actions/releaseChannel.ts","../src/comlink/controller/comlinkControllerStore.ts","../src/comlink/node/actions/getOrCreateNode.ts","../src/comlink/node/actions/releaseNode.ts","../src/comlink/node/comlinkNodeStore.ts","../src/comlink/node/getNodeState.ts","../src/config/handles.ts","../src/config/loggingConfig.ts","../src/datasets/datasets.ts","../src/document/actions.ts","../src/document/documentConstants.ts","../src/document/patchOperations.ts","../src/document/processMutations.ts","../src/document/listen.ts","../src/utils/MultiKeyWeakMap.ts","../src/document/permissions.ts","../src/document/processActions.ts","../src/document/reducers.ts","../src/document/events.ts","../src/document/sharedListener.ts","../src/document/documentStore.ts","../src/document/applyDocumentActions.ts","../src/favorites/favorites.ts","../src/users/usersConstants.ts","../src/users/reducers.ts","../src/users/usersStore.ts","../src/presence/bifurTransport.ts","../src/presence/presenceStore.ts","../src/preview/previewConstants.ts","../src/preview/previewProjectionUtils.ts","../src/utils/hashString.ts","../src/releases/utils/sortReleases.ts","../src/releases/releasesStore.ts","../src/releases/getPerspectiveState.ts","../src/query/queryStoreConstants.ts","../src/query/reducers.ts","../src/query/queryStore.ts","../src/projection/util.ts","../src/projection/projectionQuery.ts","../src/projection/statusQuery.ts","../src/projection/subscribeToStateAndFetchBatches.ts","../src/projection/projectionStore.ts","../src/projection/getProjectionState.ts","../src/projection/resolveProjection.ts","../src/projects/projects.ts","../src/utils/createGroqSearchFilter.ts","../src/utils/defineIntent.ts","../src/utils/getCorsErrorProjectId.ts","../src/version.ts"],"sourcesContent":["import {type ClientPerspective, type StackablePerspective} from '@sanity/client'\n\nimport {type AuthConfig} from './authConfig'\n\n/**\n * A minimal Observable-compatible interface for subscribing to token changes.\n * Any object with a `subscribe` method that follows this contract will work,\n * including RxJS Observables. This avoids coupling the SDK to a specific\n * reactive library.\n *\n * @public\n */\nexport interface TokenSource {\n /** Subscribe to token emissions. Emits `null` when logged out. */\n subscribe(observer: {next: (token: string | null) => void}): {unsubscribe(): void}\n}\n\n/**\n * Studio-specific configuration for the SDK.\n * When present, the SDK operates in studio mode and derives auth from the\n * provided token source instead of discovering tokens independently.\n *\n * @public\n */\nexport interface StudioConfig {\n /**\n * Whether the Studio has already determined the user is authenticated.\n * When `true` and the token source emits `null`, the SDK infers\n * cookie-based auth is in use rather than transitioning to logged-out.\n */\n authenticated?: boolean\n /** Reactive auth token source from the Studio's auth store. */\n auth?: {\n /**\n * A reactive token source. The SDK subscribes and stays in sync — the\n * Studio is the single authority for auth and handles token refresh.\n *\n * Optional because older Studios may not expose it. When absent, the\n * SDK falls back to localStorage/cookie discovery.\n */\n token?: TokenSource\n }\n /**\n * The project ID for this Studio workspace.\n * Used to derive the localStorage key for studio auth token discovery\n * (`__studio_auth_token_<projectId>`) and for project-specific API hostname requests.\n */\n projectId?: string\n}\n\n/**\n * @public\n */\nexport type ReleasePerspective = {\n releaseName: string\n excludedPerspectives?: StackablePerspective[]\n}\n\n/**\n * @public\n */\nexport interface PerspectiveHandle {\n /**\n * The perspective to use for this operation.\n * Note that the SDK stacks perspectives for you when querying.\n * The SDK automatically fetches all of your content releases, and orders them the way the Sanity Studio does: usually by scheduled date, with ASAP releases coming first.\n * @public\n */\n perspective?: Exclude<ClientPerspective, readonly unknown[]> | ReleasePerspective\n}\n\n/**\n * @public\n */\nexport interface ResourceHandle<\n TProjectId extends string = string,\n TDataset extends string = string,\n> extends PerspectiveHandle {\n /**\n * Explicit resource object to use for this operation.\n * @public\n */\n resource: DocumentResource<TProjectId, TDataset>\n}\n\n/**\n * Identifies a specific document type within a Sanity dataset and project.\n * Includes `projectId`, `dataset`, and `documentType`.\n * Optionally includes a `documentId` and `liveEdit` flag.\n * @public\n */\nexport interface DocumentTypeHandle<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends ResourceHandle<TDataset, TProjectId> {\n documentId?: string\n documentType: TDocumentType\n /**\n * Indicates whether this document uses liveEdit mode.\n * When `true`, the document does not use the draft/published model and edits are applied directly to the document.\n * @see https://www.sanity.io/docs/content-lake/drafts#ca0663a8f002\n */\n liveEdit?: boolean\n}\n\n/**\n * Uniquely identifies a specific document within a Sanity dataset and project.\n * Includes `projectId`, `dataset`, `documentType`, and the required `documentId`.\n * Commonly used by document-related hooks and components to reference a document without fetching its full content initially.\n * @public\n */\nexport interface DocumentHandle<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentTypeHandle<TDocumentType, TDataset, TProjectId> {\n documentId: string\n}\n\n/**\n * The key used to identify the default resource in a resources map.\n * When no `resource` or `resourceName` is specified, the SDK resolves\n * the resource registered under this name.\n *\n * @public\n */\nexport const DEFAULT_RESOURCE_NAME = 'default'\n\n/**\n * Represents the complete configuration for a Sanity SDK instance.\n *\n * Most apps configure resources via the `resources` prop on `SanityApp`:\n *\n * @example Typical React usage\n * ```tsx\n * <SanityApp\n * resources={{ default: { projectId: 'abc123', dataset: 'production' } }}\n * fallback={<Loading />}\n * >\n * <App />\n * </SanityApp>\n * ```\n *\n * The `defaultResource` field is set automatically by the React layer from\n * `resources['default']`. It can also be set directly when using the core\n * SDK without React (e.g. in a Node.js script):\n *\n * @example Direct core usage (without React)\n * ```ts\n * const instance = createSanityInstance({\n * defaultResource: { projectId: 'abc123', dataset: 'production' },\n * })\n * ```\n * @public\n */\nexport interface SanityConfig extends PerspectiveHandle {\n /**\n * Authentication configuration for the instance\n */\n auth?: AuthConfig\n /**\n * Studio configuration provided by a Sanity Studio workspace.\n * When present, the SDK operates in studio mode and derives auth from the\n * workspace's reactive token source — no manual configuration needed.\n *\n * @remarks Typically set automatically by `SanityApp` when it detects an\n * `SDKStudioContext` provider. Can also be set explicitly for programmatic use.\n */\n studio?: StudioConfig\n /**\n * The default document resource for this instance. Used by bound actions\n * when no explicit resource is provided.\n *\n * @public\n */\n defaultResource?: DocumentResource\n}\n\n/**\n * A document resource identifies where data is stored and queried from.\n * Can be a dataset (project + dataset pair), a media library, or a canvas.\n *\n * @public\n */\nexport type DocumentResource<\n TProjectId extends string = string,\n TDataset extends string = string,\n> = DatasetResource<TProjectId, TDataset> | MediaLibraryResource | CanvasResource\n\n/**\n * A resource that targets a specific project and dataset.\n * @public\n */\nexport type DatasetResource<\n TProjectId extends string = string,\n TDataset extends string = string,\n> = {projectId: TProjectId; dataset: TDataset}\n\n/**\n * A resource that targets a media library.\n * @public\n */\nexport type MediaLibraryResource = {mediaLibraryId: string}\n\n/**\n * A resource that targets a canvas.\n * @public\n */\nexport type CanvasResource = {canvasId: string}\n\n/**\n * Type guard that checks whether a {@link DocumentResource} is a {@link DatasetResource}.\n * @public\n */\nexport function isDatasetResource(resource: DocumentResource): resource is DatasetResource {\n return 'projectId' in resource && 'dataset' in resource\n}\n\n/**\n * Type guard that checks whether a {@link DocumentResource} is a {@link MediaLibraryResource}.\n * @public\n */\nexport function isMediaLibraryResource(\n resource: DocumentResource,\n): resource is MediaLibraryResource {\n return 'mediaLibraryId' in resource\n}\n\n/**\n * Type guard that checks whether a {@link DocumentResource} is a {@link CanvasResource}.\n * @public\n */\nexport function isCanvasResource(resource: DocumentResource): resource is CanvasResource {\n return 'canvasId' in resource\n}\n","import {type PerspectiveHandle, type ReleasePerspective} from '../../config/sanityConfig'\n\nexport const isReleasePerspective = (\n perspective: PerspectiveHandle['perspective'],\n): perspective is ReleasePerspective => {\n return typeof perspective === 'object' && perspective !== null && 'releaseName' in perspective\n}\n","export function getPublishedId(id: string): string {\n const draftsPrefix = 'drafts.'\n return id.startsWith(draftsPrefix) ? id.slice(draftsPrefix.length) : id\n}\n\nexport function getDraftId(id: string): string {\n const draftsPrefix = 'drafts.'\n return id.startsWith(draftsPrefix) ? id : `${draftsPrefix}${id}`\n}\n\nexport function insecureRandomId(): string {\n return Array.from({length: 16}, () => Math.floor(Math.random() * 16).toString(16)).join('')\n}\n","/**\n * Logging infrastructure for the Sanity SDK\n *\n * Provides multi-level, namespace-based logging for both SDK users and maintainers.\n * In production builds, all logging can be stripped via tree-shaking.\n *\n * @example SDK User\n * ```ts\n * import {configureLogging} from '@sanity/sdk'\n *\n * configureLogging({\n * level: 'info',\n * namespaces: ['auth', 'document']\n * })\n * ```\n *\n * @example SDK Maintainer\n * ```ts\n * configureLogging({\n * level: 'trace',\n * namespaces: ['*'],\n * internal: true\n * })\n * ```\n */\n\n/**\n * Log levels in order of verbosity (least to most)\n * - error: Critical failures that prevent operation\n * - warn: Issues that may cause problems but don't stop execution\n * - info: High-level informational messages (SDK user level)\n * - debug: Detailed debugging information (maintainer level)\n * - trace: Very detailed tracing (maintainer level, includes RxJS streams)\n * @public\n */\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace'\n\n/**\n * Log namespaces organize logs by functional domain\n *\n * @remarks\n * This is an extensible string type. As logging is added to more modules,\n * additional namespaces will be recognized. Currently implemented namespaces\n * will be documented as they are added.\n * @internal\n */\nexport type LogNamespace = string\n\n/**\n * Configuration for the logging system\n * @public\n */\nexport interface LoggerConfig {\n /**\n * Minimum log level to output\n * @defaultValue 'warn'\n */\n level?: LogLevel\n\n /**\n * Namespaces to enable. Use ['*'] for all namespaces\n * @defaultValue []\n * @remarks\n * Available namespaces depend on which modules have logging integrated.\n * Check the SDK documentation for the current list of instrumented modules.\n * @example ['auth', 'document']\n */\n namespaces?: string[]\n\n /**\n * Enable internal/maintainer-level logging\n * Shows RxJS streams, store internals, etc.\n * @defaultValue false\n */\n internal?: boolean\n\n /**\n * Custom log handler (for testing or custom output)\n * @defaultValue console methods\n */\n handler?: LogHandler\n\n /**\n * Enable timestamps in log output\n * @defaultValue true\n */\n timestamps?: boolean\n\n /**\n * Enable in production builds\n * @defaultValue false\n */\n enableInProduction?: boolean\n}\n\n/**\n * Custom log handler interface\n *\n * @internal\n */\nexport interface LogHandler {\n error: (message: string, context?: LogContext) => void\n warn: (message: string, context?: LogContext) => void\n info: (message: string, context?: LogContext) => void\n debug: (message: string, context?: LogContext) => void\n trace: (message: string, context?: LogContext) => void\n}\n\n/**\n * Context object attached to log messages\n *\n * This interface allows you to attach arbitrary contextual data to log messages.\n * The index signature `[key: string]: unknown` enables you to add any custom\n * properties relevant to your log entry (e.g., `userId`, `documentId`, `action`, etc.).\n *\n * **Sensitive data sanitization:**\n * Top-level keys containing sensitive names (`token`, `password`, `secret`, `apiKey`,\n * `authorization`) are automatically redacted to `[REDACTED]` in log output.\n *\n * @example\n * ```ts\n * logger.info('User logged in', {\n * userId: '123', // Custom context\n * action: 'login', // Custom context\n * token: 'secret' // Will be redacted to [REDACTED]\n * })\n * ```\n *\n * @internal\n */\nexport interface LogContext {\n /**\n * Custom context properties that provide additional information about the log entry.\n * Any key-value pairs can be added here (e.g., userId, documentId, requestId, etc.).\n * Keys with sensitive names (token, password, secret, apiKey, authorization) are\n * automatically sanitized.\n */\n [key: string]: unknown\n /** Error object if logging an error */\n error?: Error | unknown\n /** Duration in milliseconds for timed operations */\n duration?: number\n /** Stack trace for debugging */\n stack?: string\n /** Instance context (automatically added when available) */\n instanceContext?: InstanceContext\n}\n\n/**\n * Instance context information automatically added to logs\n * @internal\n */\nexport interface InstanceContext {\n /** Unique instance ID */\n instanceId?: string\n /** Project ID (derived from default resource) */\n projectId?: string\n /** Dataset name (derived from default resource) */\n dataset?: string\n}\n\n/**\n * Logger instance for a specific namespace\n * @internal\n */\nexport interface Logger {\n readonly namespace: string\n error: (message: string, context?: LogContext) => void\n warn: (message: string, context?: LogContext) => void\n info: (message: string, context?: LogContext) => void\n debug: (message: string, context?: LogContext) => void\n trace: (message: string, context?: LogContext) => void\n /** Check if a log level is enabled (for performance-sensitive code) */\n isLevelEnabled: (level: LogLevel) => boolean\n /** Create a child logger with extended context */\n child: (context: LogContext) => Logger\n /** Get the instance context if available */\n getInstanceContext: () => InstanceContext | undefined\n}\n\n// Log level priority (lower number = higher priority)\nconst LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n}\n\n// Default logging configuration\nconst DEFAULT_CONFIG: Required<LoggerConfig> = {\n level: 'warn',\n namespaces: [],\n internal: false,\n timestamps: true,\n enableInProduction: false,\n handler: {\n // eslint-disable-next-line no-console\n error: console.error.bind(console),\n // eslint-disable-next-line no-console\n warn: console.warn.bind(console),\n // eslint-disable-next-line no-console\n info: console.info.bind(console),\n // eslint-disable-next-line no-console\n debug: console.debug.bind(console),\n // eslint-disable-next-line no-console\n trace: console.debug.bind(console), // trace uses console.debug\n },\n}\n\n/**\n * Parse DEBUG environment variable for automatic logging configuration\n *\n * Supports patterns similar to Sanity CLI/Studio:\n * - DEBUG=sanity:* (all namespaces, debug level)\n * - DEBUG=sanity:auth,sanity:document (specific namespaces)\n * - DEBUG=sanity:trace:* (all namespaces, trace level)\n * - DEBUG=sanity:*:internal (enable internal logs)\n *\n * @internal\n */\nexport function parseDebugEnvVar(): Partial<LoggerConfig> | null {\n if (typeof process === 'undefined' || !process.env?.['DEBUG']) {\n return null\n }\n\n const debug = process.env['DEBUG']\n\n // Only process if it includes 'sanity'\n if (!debug.includes('sanity')) {\n return null\n }\n\n const config: Partial<LoggerConfig> = {}\n\n // Parse level from pattern like \"sanity:trace:*\" or \"sanity:debug:*\"\n const levelMatch = debug.match(/sanity:(trace|debug|info|warn|error):/)\n const hasLevelSpecifier = !!levelMatch\n if (levelMatch) {\n config.level = levelMatch[1] as LogLevel\n } else {\n // Default to debug level if just \"sanity:*\" or \"sanity:namespace\"\n config.level = 'debug'\n }\n\n // Parse namespaces\n if (debug === 'sanity') {\n config.namespaces = ['*']\n } else if (hasLevelSpecifier && debug.match(/sanity:(trace|debug|info|warn|error):\\*/)) {\n // Pattern like \"sanity:trace:*\" - wildcard after level\n config.namespaces = ['*']\n } else if (!hasLevelSpecifier && debug.includes('sanity:*')) {\n // Pattern like \"sanity:*\" - wildcard without level\n config.namespaces = ['*']\n } else {\n // Extract specific namespaces like \"sanity:auth,sanity:document\"\n const namespaces = debug\n .split(',')\n .filter((s) => s.includes('sanity:'))\n .map((s) => {\n // Remove 'sanity:' prefix\n const cleaned = s.replace(/^sanity:/, '')\n // If there's a level specifier, skip it\n if (hasLevelSpecifier && cleaned.match(/^(trace|debug|info|warn|error):/)) {\n // Get the part after the level: \"trace:auth\" -> \"auth\"\n return cleaned.split(':').slice(1).join(':')\n }\n // Otherwise get the first part: \"auth:something\" -> \"auth\"\n return cleaned.split(':')[0]\n })\n .filter(Boolean)\n .filter((ns) => ns !== '*') // Filter out wildcards\n\n if (namespaces.length > 0) {\n config.namespaces = namespaces\n }\n }\n\n // Check for internal flag: DEBUG=sanity:*:internal\n if (debug.includes(':internal')) {\n config.internal = true\n }\n\n return config\n}\n\n// Global configuration - initialized with env var settings if present\nconst envConfig = parseDebugEnvVar()\nlet globalConfig: Required<LoggerConfig> = {\n ...DEFAULT_CONFIG,\n ...(envConfig ?? {}),\n}\n\n// Log that env var configuration was detected (only if DEBUG is set)\n// Note: This runs at module initialization, difficult to test without complex module mocking\n/* c8 ignore next 14 */\nif (envConfig) {\n const shouldLog =\n ['info', 'debug', 'trace'].includes(globalConfig.level) || globalConfig.level === 'warn'\n if (shouldLog) {\n // eslint-disable-next-line no-console\n console.info(\n `[${new Date().toISOString()}] [INFO] [sdk] Logging auto-configured from DEBUG environment variable`,\n {\n level: globalConfig.level,\n namespaces: globalConfig.namespaces,\n internal: globalConfig.internal,\n source: 'env:DEBUG',\n value: typeof process !== 'undefined' ? process.env?.['DEBUG'] : undefined,\n },\n )\n }\n}\n\n/**\n * Configure the global logging system\n * @public\n */\nexport function configureLogging(config: LoggerConfig): void {\n globalConfig = {\n ...globalConfig,\n ...config,\n handler: config.handler ?? globalConfig.handler,\n }\n}\n\n/**\n * Get the current logging configuration\n * @internal\n */\nexport function getLoggingConfig(): Readonly<Required<LoggerConfig>> {\n return globalConfig\n}\n\n/**\n * Reset logging to default configuration\n * @internal\n */\nexport function resetLogging(): void {\n globalConfig = {...DEFAULT_CONFIG}\n}\n\n/**\n * Check if logging is enabled in the current environment\n * @internal\n */\nfunction isLoggingEnabled(): boolean {\n // In production, only log if explicitly enabled\n if (typeof process !== 'undefined' && process.env?.['NODE_ENV'] === 'production') {\n return globalConfig.enableInProduction\n }\n return true\n}\n\n/**\n * Check if a namespace is enabled\n * @internal\n */\nfunction isNamespaceEnabled(namespace: string): boolean {\n if (!isLoggingEnabled()) return false\n if (globalConfig.namespaces.includes('*')) return true\n return globalConfig.namespaces.includes(namespace)\n}\n\n/**\n * Check if a log level is enabled\n * @internal\n */\nfunction isLevelEnabled(level: LogLevel): boolean {\n if (!isLoggingEnabled()) return false\n return LOG_LEVEL_PRIORITY[level] <= LOG_LEVEL_PRIORITY[globalConfig.level]\n}\n\n/**\n * Format a log message with timestamp, namespace, and instance context\n * @internal\n */\nfunction formatMessage(\n namespace: LogNamespace,\n level: LogLevel,\n message: string,\n context?: LogContext,\n): [string, LogContext | undefined] {\n const parts: string[] = []\n\n if (globalConfig.timestamps) {\n const timestamp = new Date().toISOString()\n parts.push(`[${timestamp}]`)\n }\n\n parts.push(`[${level.toUpperCase()}]`)\n parts.push(`[${namespace}]`)\n\n // Add instance context if available\n const instanceContext = context?.instanceContext\n if (instanceContext) {\n if (instanceContext.projectId) {\n parts.push(`[project:${instanceContext.projectId}]`)\n }\n if (instanceContext.dataset) {\n parts.push(`[dataset:${instanceContext.dataset}]`)\n }\n if (instanceContext.instanceId) {\n parts.push(`[instance:${instanceContext.instanceId.slice(0, 8)}]`)\n }\n }\n\n parts.push(message)\n\n return [parts.join(' '), context]\n}\n\n/**\n * Sanitize context for logging (remove sensitive data)\n * @internal\n * @remarks\n * This performs shallow sanitization only - it redacts top-level keys that contain\n * sensitive names (token, password, secret, apiKey, authorization).\n * Nested sensitive data (e.g., `\\{auth: \\{token: 'secret'\\}\\}`) will NOT be redacted.\n * If deep sanitization is needed in the future, this can be enhanced to recursively\n * traverse nested objects.\n */\nfunction sanitizeContext(context?: LogContext): LogContext | undefined {\n if (!context || Object.keys(context).length === 0) return undefined\n\n const sanitized = {...context}\n\n // Remove or redact sensitive fields at the top level\n const sensitiveKeys = ['token', 'password', 'secret', 'apiKey', 'authorization']\n for (const key of Object.keys(sanitized)) {\n if (sensitiveKeys.some((sensitive) => key.toLowerCase().includes(sensitive))) {\n sanitized[key] = '[REDACTED]'\n }\n }\n\n return sanitized\n}\n\n/**\n * Create a logger for a specific namespace\n * @param namespace - A string identifier for the logging domain (e.g., 'auth', 'document')\n * @param baseContext - Optional base context to include in all log messages\n * @remarks\n * If baseContext includes an `instanceContext` property (with projectId, dataset, instanceId),\n * it will be automatically formatted into the log output for easier debugging of\n * multi-instance scenarios.\n * @public\n */\nexport function createLogger(namespace: string, baseContext?: LogContext): Logger {\n const logAtLevel = (level: LogLevel, message: string, context?: LogContext) => {\n // Early return if namespace or level not enabled\n if (!isNamespaceEnabled(namespace)) return\n if (!isLevelEnabled(level)) return\n\n // Skip internal logs if not enabled\n if (context?.['internal'] && !globalConfig.internal) return\n\n const mergedContext = {...baseContext, ...context}\n const sanitized = sanitizeContext(mergedContext)\n const [formatted, finalContext] = formatMessage(namespace, level, message, sanitized)\n\n globalConfig.handler[level](formatted, finalContext)\n }\n\n const logger: Logger = {\n namespace,\n error: (message, context) => logAtLevel('error', message, context),\n warn: (message, context) => logAtLevel('warn', message, context),\n info: (message, context) => logAtLevel('info', message, context),\n debug: (message, context) => logAtLevel('debug', message, context),\n trace: (message, context) => logAtLevel('trace', message, {...context, internal: true}),\n isLevelEnabled: (level) => isNamespaceEnabled(namespace) && isLevelEnabled(level),\n child: (childContext) => createLogger(namespace, {...baseContext, ...childContext}),\n getInstanceContext: () => baseContext?.instanceContext,\n }\n\n return logger\n}\n\n/**\n * Create a performance timer for measuring operation duration\n * @internal\n */\nexport function createTimer(\n namespace: string,\n operation: string,\n): {end: (message?: string, context?: LogContext) => number} {\n const logger = createLogger(namespace)\n const start = performance.now()\n\n return {\n end: (message?: string, context?: LogContext): number => {\n const duration = performance.now() - start\n logger.debug(message ?? `${operation} completed`, {\n ...context,\n operation,\n duration,\n })\n return duration\n },\n }\n}\n\n/**\n * Utility to log RxJS operator execution (for maintainers)\n * Will be exported in future PR when logging is added to stores\n * @internal\n */\n/* c8 ignore next 4 */\nfunction logRxJSOperator(namespace: string, operator: string, context?: LogContext): void {\n const logger = createLogger(namespace)\n logger.trace(`RxJS: ${operator}`, {...context, internal: true, operator})\n}\n\n/**\n * Extract instance context from a SanityInstance for logging\n * Will be exported in future PR when logging is added to stores\n * @param instance - The SanityInstance to extract context from\n * @returns Instance context suitable for logging\n * @internal\n */\n/* c8 ignore next 7 */\nfunction getInstanceContext(instance: {instanceId?: string}): InstanceContext {\n return {\n instanceId: instance.instanceId,\n }\n}\n\n// Prevent unused function warnings - these will be exported and used in future PRs\n/* c8 ignore next 2 */\nvoid logRxJSOperator\nvoid getInstanceContext\n","import {type SanityConfig} from '../config/sanityConfig'\nimport {insecureRandomId} from '../utils/ids'\nimport {createLogger, type InstanceContext} from '../utils/logger'\n\n/**\n * Represents a Sanity.io resource instance with its own configuration and lifecycle.\n *\n * @public\n */\nexport interface SanityInstance {\n /**\n * Unique identifier for this instance\n * @remarks Generated using crypto.randomUUID()\n */\n readonly instanceId: string\n\n /** Resolved configuration for this instance */\n readonly config: SanityConfig\n\n /**\n * Checks if the instance has been disposed\n * @returns true if dispose() has been called\n */\n isDisposed(): boolean\n\n /**\n * Disposes the instance and cleans up associated resources\n * @remarks Triggers all registered onDispose callbacks\n */\n dispose(): void\n\n /**\n * Registers a callback to be invoked when the instance is disposed\n * @param cb - Callback to execute on disposal\n * @returns Function to unsubscribe the callback\n */\n onDispose(cb: () => void): () => void\n}\n\n/**\n * Creates a new Sanity resource instance\n * @param config - Configuration for the instance (optional)\n * @returns A configured SanityInstance\n *\n * @public\n */\nexport function createSanityInstance(config: SanityConfig = {}): SanityInstance {\n const instanceId = crypto.randomUUID()\n const disposeListeners = new Map<string, () => void>()\n const disposed = {current: false}\n\n const instanceContext: InstanceContext = {\n instanceId,\n }\n\n const logger = createLogger('sdk', {instanceContext})\n\n logger.info('Sanity instance created', {\n hasAuth: !!config.auth,\n hasPerspective: !!config.perspective,\n })\n\n logger.debug('Instance configuration', {\n perspective: config.perspective,\n hasStudioConfig: !!config.studio,\n hasStudioTokenSource: !!config.studio?.auth?.token,\n hasAuthProviders: !!config.auth?.providers,\n hasAuthToken: !!config.auth?.token,\n })\n\n const instance: SanityInstance = {\n instanceId,\n config,\n isDisposed: () => disposed.current,\n dispose: () => {\n if (disposed.current) {\n logger.trace('Dispose called on already disposed instance', {internal: true})\n return\n }\n logger.trace('Disposing instance', {\n internal: true,\n listenerCount: disposeListeners.size,\n })\n disposed.current = true\n disposeListeners.forEach((listener) => listener())\n disposeListeners.clear()\n logger.info('Instance disposed')\n },\n onDispose: (cb) => {\n const listenerId = insecureRandomId()\n disposeListeners.set(listenerId, cb)\n return () => {\n disposeListeners.delete(listenerId)\n }\n },\n }\n\n return instance\n}\n","// Local type declaration for Remix\ntype WindowWithEnv = Window &\n typeof globalThis & {\n ENV?: Record<string, unknown>\n }\n\ntype KnownEnvVar = 'DEV' | 'PKG_VERSION'\n\nexport function getEnv(key: KnownEnvVar): unknown {\n if (typeof import.meta !== 'undefined' && import.meta.env) {\n // Vite environment variables\n return (import.meta.env as unknown as Record<string, unknown>)[key]\n } else if (typeof process !== 'undefined' && process.env) {\n // Node.js or server-side environment variables\n return process.env[key]\n } else if (typeof window !== 'undefined' && (window as WindowWithEnv).ENV) {\n // Remix-style client-side environment variables\n return (window as WindowWithEnv).ENV?.[key]\n }\n return undefined\n}\n","import {Observable} from 'rxjs'\nimport {devtools, type DevtoolsOptions} from 'zustand/middleware'\nimport {createStore} from 'zustand/vanilla'\n\n/**\n * Represents a reactive store state container with multiple access patterns\n */\nexport interface StoreState<TState> {\n /**\n * Gets the current state value\n *\n * @remarks\n * This is a direct synchronous accessor that doesn't trigger subscriptions\n */\n get: () => TState\n\n /**\n * Updates the store state\n * @param name - Action name for devtools tracking\n * @param updatedState - New state value or updater function\n *\n * @remarks\n * When providing a partial object, previous top-level keys not included in\n * the update will be preserved.\n */\n set: (name: string, updatedState: Partial<TState> | ((s: TState) => Partial<TState>)) => void\n\n /**\n * Observable stream of state changes\n * @remarks\n * - Emits immediately with current state on subscription\n * - Shares underlying subscription between observers\n * - Only emits when state reference changes\n * - Completes when store is disposed\n */\n observable: Observable<TState>\n}\n\n/**\n * Creates a reactive store state container with multiple access patterns\n * @param initialState - Initial state value for the store\n * @param devToolsOptions - Configuration for Zustand devtools integration\n * @returns StoreState instance with get/set/observable interface\n *\n * @example\n * ```typescript\n * // Create a simple counter store\n * const counterStore = createStoreState({ count: 0 });\n *\n * // Update state\n * counterStore.set('increment', { count: 1 });\n *\n * // Observe changes\n * counterStore.observable.subscribe(console.log);\n * ```\n *\n * @remarks\n * Uses Zustand for state management under the hood with RxJS for observable interface.\n * Designed to work with both imperative and reactive programming patterns.\n */\nexport function createStoreState<TState>(\n initialState: TState,\n devToolsOptions?: DevtoolsOptions,\n): StoreState<TState> {\n // Create underlying Zustand store with devtools integration\n const store = createStore<TState>()(devtools(() => initialState, devToolsOptions))\n\n return {\n get: store.getState,\n set: (actionKey, updatedState) => {\n const currentState = store.getState()\n const nextState =\n typeof updatedState === 'function' ? updatedState(currentState) : updatedState\n\n // Optimization: Skip update if state reference remains the same\n if (currentState !== nextState) {\n store.setState(nextState, false, actionKey)\n }\n },\n observable: new Observable((observer) => {\n // Emit current state immediately on subscription\n const emit = () => observer.next(store.getState())\n emit()\n\n // Subscribe to Zustand store changes\n const unsubscribe = store.subscribe(emit)\n\n // Cleanup when observable unsubscribed\n return () => unsubscribe()\n }),\n }\n}\n","import {getEnv} from '../utils/getEnv'\nimport {type SanityInstance} from './createSanityInstance'\nimport {createStoreState, type StoreState} from './createStoreState'\nimport {type StoreDefinition} from './defineStore'\n\n/**\n * Represents a running instance of a store with its own state and lifecycle\n *\n * @remarks\n * Each StoreInstance is tied to a specific SanityInstance, manages its own state,\n * and can be independently disposed when no longer needed.\n */\nexport interface StoreInstance<TState> {\n /**\n * Access to the reactive state container for this store instance\n */\n state: StoreState<TState>\n\n /**\n * Checks if this store instance has been disposed\n * @returns Boolean indicating disposed state\n */\n isDisposed: () => void\n\n /**\n * Cleans up this store instance and runs any initialization cleanup functions\n * @remarks Triggers the cleanup function returned from the initialize method\n */\n dispose: () => void\n}\n\n/**\n * Creates a new instance of a store from a store definition\n *\n * @param instance - The Sanity instance this store will be associated with\n * @param storeDefinition - The store definition containing initial state and initialization logic\n * @returns A store instance with state management and lifecycle methods\n *\n * @remarks\n * The store instance maintains its own state that is scoped to the given Sanity instance.\n * If the store definition includes an initialize function, it will be called during\n * instance creation, and its cleanup function will be called during disposal.\n *\n * @example\n * ```ts\n * const counterStore = defineStore({\n * name: 'Counter',\n * getInitialState: () => ({ count: 0 }),\n * initialize: ({state}) => {\n * console.log('Counter store initialized')\n * return () => console.log('Counter store disposed')\n * }\n * })\n *\n * const instance = createStoreInstance(sanityInstance, counterStore)\n * // Later when done with the store:\n * instance.dispose()\n * ```\n */\nexport function createStoreInstance<TState, TKey extends {name: string}>(\n instance: SanityInstance,\n key: TKey,\n {name, getInitialState, initialize}: StoreDefinition<TState, TKey>,\n): StoreInstance<TState> {\n const state = createStoreState(getInitialState(instance, key), {\n enabled: !!getEnv('DEV'),\n name: `${name}-${key.name}`,\n })\n const dispose = initialize?.({state, instance, key})\n const disposed = {current: false}\n\n return {\n state,\n dispose: () => {\n if (disposed.current) return\n disposed.current = true\n dispose?.()\n },\n isDisposed: () => disposed.current,\n }\n}\n","import {\n type DocumentResource,\n isCanvasResource,\n isDatasetResource,\n isMediaLibraryResource,\n type PerspectiveHandle,\n type ResourceHandle,\n} from '../config/sanityConfig'\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\nimport {type SanityInstance} from './createSanityInstance'\nimport {createStoreInstance, type StoreInstance} from './createStoreInstance'\nimport {type StoreState} from './createStoreState'\nimport {type StoreContext, type StoreDefinition} from './defineStore'\n\nexport interface BoundResourceKey {\n name: string\n resource: DocumentResource\n}\nexport interface BoundPerspectiveKey extends BoundResourceKey {\n perspective: NonNullable<PerspectiveHandle['perspective']>\n}\n/**\n * Defines a store action that operates on a specific state type\n */\nexport type StoreAction<TState, TParams extends unknown[], TReturn, TKey = unknown> = (\n context: StoreContext<TState, TKey>,\n ...params: TParams\n) => TReturn\n\n/**\n * Represents a store action that has been bound to a specific store instance\n */\nexport type BoundStoreAction<_TState, TParams extends unknown[], TReturn> = (\n instance: SanityInstance,\n ...params: TParams\n) => TReturn\n\n/**\n * Creates an action binder function that uses the provided key function\n * to determine how store instances are shared between Sanity instances\n *\n * @param keyFn - Function that generates a key from a Sanity config\n * @returns A function that binds store actions to Sanity instances\n *\n * @remarks\n * Action binders determine how store instances are shared across multiple\n * Sanity instances. The key function determines which instances share state.\n *\n * @example\n * ```ts\n * // Create a custom binder that uses a tenant ID for isolation\n * const bindActionByTenant = createActionBinder(config => config.tenantId || 'default')\n *\n * // Use the custom binder with a store definition\n * const getTenantUsers = bindActionByTenant(\n * userStore,\n * ({state}) => state.get().users\n * )\n * ```\n */\nexport function createActionBinder<\n TKey extends {name: string},\n TKeyParams extends unknown[] = unknown[],\n>(keyFn: (instance: SanityInstance, ...params: TKeyParams) => TKey) {\n const instanceRegistry = new Map<string, Set<string>>()\n const storeRegistry = new Map<string, StoreInstance<unknown>>()\n\n /**\n * Binds a store action to a store definition\n *\n * @param storeDefinition - The store definition\n * @param action - The action to bind\n * @returns A function that executes the action with a Sanity instance\n */\n return function bindAction<TState, TParams extends TKeyParams, TReturn>(\n storeDefinition: StoreDefinition<TState, TKey>,\n action: StoreAction<TState, TParams, TReturn, TKey>,\n ): BoundStoreAction<TState, TParams, TReturn> {\n return function boundAction(instance: SanityInstance, ...params: TParams) {\n const key = keyFn(instance, ...params)\n const compositeKey = storeDefinition.name + (key.name ? `:${key.name}` : '')\n\n // Get or create instance set for this composite key\n let instances = instanceRegistry.get(compositeKey)\n if (!instances) {\n instances = new Set<string>()\n instanceRegistry.set(compositeKey, instances)\n }\n\n // Register instance for disposal tracking\n if (!instances.has(instance.instanceId)) {\n instances.add(instance.instanceId)\n instance.onDispose(() => {\n instances.delete(instance.instanceId)\n\n // Clean up when last instance is disposed\n if (instances.size === 0) {\n storeRegistry.get(compositeKey)?.dispose()\n storeRegistry.delete(compositeKey)\n instanceRegistry.delete(compositeKey)\n }\n })\n }\n\n // Get or create store instance\n let storeInstance = storeRegistry.get(compositeKey)\n if (!storeInstance) {\n storeInstance = createStoreInstance(instance, key, storeDefinition)\n storeRegistry.set(compositeKey, storeInstance)\n }\n\n // Execute action with store context\n return action({instance, state: storeInstance.state as StoreState<TState>, key}, ...params)\n }\n }\n}\n\nconst resourceKeyName = (resource: DocumentResource): string => {\n if (isDatasetResource(resource)) return `${resource.projectId}.${resource.dataset}`\n if (isMediaLibraryResource(resource)) return `media-library:${resource.mediaLibraryId}`\n if (isCanvasResource(resource)) return `canvas:${resource.canvasId}`\n throw new Error(`Received invalid resource: ${JSON.stringify(resource)}`)\n}\n\nconst createResourceKey = (\n instance: SanityInstance,\n resource?: DocumentResource,\n): BoundResourceKey => {\n if (resource) {\n return {name: resourceKeyName(resource), resource}\n }\n\n const defaultResource = instance.config.defaultResource\n if (!defaultResource) {\n throw new Error(\n 'No resource provided and no default resource configured. ' +\n 'Provide a \"default\" resource in your resources map, or pass an explicit resource.',\n )\n }\n return {name: resourceKeyName(defaultResource), resource: defaultResource}\n}\n\n/**\n * Binds an action to a store that's scoped to a specific document resource.\n **/\nexport const bindActionByResource = createActionBinder<\n BoundResourceKey,\n [{resource?: DocumentResource}, ...unknown[]]\n>((instance, {resource}) => {\n return createResourceKey(instance, resource)\n})\n\n/**\n * Binds an action to a store that's scoped to a specific document resource and perspective.\n *\n * @remarks\n * This creates actions that operate on state isolated to a specific document resource and perspective.\n * Different document resources and perspectives will have separate states.\n *\n * This is mostly useful for stores that do batch fetching operations, since the query store\n * can isolate single queries by perspective.\n *\n * @throws Error if resource or perspective is missing from the Sanity instance config\n * @throws Error if a stackable perspective (array) is provided, as they are not supported\n *\n * @example\n * ```ts\n * // Define a store\n * const documentStore = defineStore<DocumentState>({\n * name: 'Document',\n * getInitialState: () => ({ documents: {} }),\n * // ...\n * })\n *\n * // Create resource-and-perspective-specific actions\n * export const fetchDocuments = bindActionByResourceAndPerspective(\n * documentStore,\n * ({instance, state}, documentId) => {\n * // This state is isolated to the specific document resource and perspective\n * // ...fetch logic...\n * }\n * )\n *\n * // Usage\n * fetchDocument(sanityInstance, 'doc123')\n * ```\n */\nexport const bindActionByResourceAndPerspective = createActionBinder<\n BoundPerspectiveKey,\n [ResourceHandle, ...unknown[]]\n>((instance, options): BoundPerspectiveKey => {\n const {resource, perspective} = options\n // TODO: remove reference to instance.config.perspective when we get to v3\n const utilizedPerspective = perspective ?? instance.config.perspective ?? 'drafts'\n let perspectiveKey: string\n if (isReleasePerspective(utilizedPerspective)) {\n perspectiveKey = utilizedPerspective.releaseName\n } else if (typeof utilizedPerspective === 'string') {\n perspectiveKey = utilizedPerspective\n } else {\n throw new Error(\n `Stackable perspectives are not supported. Received perspective: ${JSON.stringify(utilizedPerspective)}`,\n )\n }\n const resourceKey = createResourceKey(instance, resource)\n\n return {\n name: `${resourceKey.name}:${perspectiveKey}`,\n resource: resourceKey.resource,\n perspective: utilizedPerspective,\n }\n})\n\n/**\n * Binds an action to a global store that's shared across all Sanity instances\n *\n * @remarks\n * This creates actions that operate on state shared globally across all Sanity instances.\n * Use this for features like authentication where the state should be the same\n * regardless of which project or dataset is being used.\n *\n * @example\n * ```ts\n * // Define a store\n * const authStore = defineStore<AuthState>({\n * name: 'Auth',\n * getInitialState: () => ({\n * user: null,\n * isAuthenticated: false\n * }),\n * // ...\n * })\n *\n * // Create global actions\n * export const getCurrentUser = bindActionGlobally(\n * authStore,\n * ({state}) => state.get().user\n * )\n *\n * export const login = bindActionGlobally(\n * authStore,\n * ({state, instance}, credentials) => {\n * // Login logic that affects global state\n * // ...\n * }\n * )\n *\n * // Usage with any instance\n * getCurrentUser(sanityInstance)\n * ```\n */\nexport const bindActionGlobally = createActionBinder((..._rest) => ({name: 'global'}))\n","import {distinctUntilChanged, map, Observable, share, skip} from 'rxjs'\n\nimport {type StoreAction} from './createActionBinder'\nimport {type SanityInstance} from './createSanityInstance'\nimport {type StoreContext} from './defineStore'\n\n/**\n * Represents a reactive state source that provides synchronized access to store data\n *\n * @remarks\n * Designed to work with React's useSyncExternalStore hook. Provides three ways to access data:\n * 1. `getCurrent()` for synchronous current value access\n * 2. `subscribe()` for imperative change notifications\n * 3. `observable` for reactive stream access\n *\n * @public\n */\nexport interface StateSource<T> {\n /**\n * Subscribes to state changes with optional callback\n * @param onStoreChanged - Called whenever relevant state changes occur\n * @returns Unsubscribe function to clean up the subscription\n */\n subscribe: (onStoreChanged?: () => void) => () => void\n\n /**\n * Gets the current derived state value\n *\n * @remarks\n * Safe to call without subscription. Will always return the latest value\n * based on the current store state and selector parameters.\n */\n getCurrent: () => T\n\n /**\n * Observable stream of state values\n *\n * @remarks\n * Shares a single underlying subscription between all observers. Emits:\n * - Immediately with current value on subscription\n * - On every relevant state change\n * - Errors if selector throws\n */\n observable: Observable<T>\n}\n\n/**\n * Context passed to selectors when deriving state\n *\n * @remarks\n * Provides access to both the current state value and the Sanity instance,\n * allowing selectors to use configuration values when computing derived state.\n * The context is memoized for each state object and instance combination\n * to optimize performance and prevent unnecessary recalculations.\n *\n * @example\n * ```ts\n * // Using both state and instance in a selector (psuedo example)\n * const getUserByProjectId = createStateSourceAction(\n * ({ state, instance }: SelectorContext<UsersState>, options?: ResourceHandle) => {\n * const allUsers = state.users\n * const projectId = options?.projectId ?? instance.config.defaultResource?.projectId\n * return allUsers.filter(user => user.projectId === projectId)\n * }\n * )\n * ```\n */\nexport interface SelectorContext<TState> {\n /**\n * The current state object from the store\n */\n state: TState\n\n /**\n * The Sanity instance associated with this state\n */\n instance: SanityInstance\n}\n\n/**\n * Function type for selecting derived state from store state and parameters\n * @public\n */\nexport type Selector<TState, TParams extends unknown[], TReturn> = (\n context: SelectorContext<TState>,\n ...params: TParams\n) => TReturn\n\n/**\n * Configuration options for creating a state source action\n */\ninterface StateSourceOptions<TState, TParams extends unknown[], TReturn, TKey> {\n /**\n * Selector function that derives the desired value from store state\n *\n * @remarks\n * Will be called on every store change. Should be pure function.\n * Thrown errors will propagate to observable subscribers.\n */\n selector: Selector<TState, TParams, TReturn>\n\n /**\n * Optional setup/cleanup handler for subscriptions\n *\n * @param context - Store context containing state and instance\n * @param params - Action parameters provided during invocation\n * @returns Optional cleanup function called when subscription ends\n */\n onSubscribe?: (context: StoreContext<TState, TKey>, ...params: TParams) => void | (() => void)\n\n /**\n * Equality function to prevent unnecessary updates\n */\n isEqual?: (prev: TReturn, curr: TReturn) => boolean\n}\n\n/**\n * Creates a state source action that generates StateSource instances\n *\n * @remarks\n * The returned action can be bound to a store using createActionBinder.\n * When invoked, returns a StateSource that stays synchronized with the store.\n *\n * Key performance features:\n * - Memoizes selector contexts to prevent redundant object creation\n * - Only runs selectors when the underlying state changes\n *\n * For complex data transformations, consider using memoized selectors\n * (like those from Reselect) to prevent expensive recalculations.\n *\n * @example\n * ```ts\n * // Create a simple counter source\n * const getCount = createStateSourceAction(({state}: SelectorContext<CounterState>) => state.count)\n * ```\n *\n * @example\n * ```ts\n * // Create a parameterized source with setup/cleanup\n * const getItem = createStateSourceAction({\n * selector: ({state}, index: number) => state.items[index],\n * onSubscribe: (context, index) => {\n * trackItemSubscription(index)\n * return () => untrackItem(index)\n * }\n * })\n * ```\n *\n * @example\n * ```ts\n * // Binding a state source to a specific store\n * const documentStore = defineStore<DocumentState>({\n * name: 'Documents',\n * getInitialState: () => ({ documents: {} }),\n * // ...\n * })\n *\n * const getDocument = bindActionByResource(\n * documentStore,\n * createStateSourceAction(({state}, _options, documentId: string) => state.documents[documentId])\n * )\n *\n * // Usage\n * const documentSource = getDocument(sanityInstance, {}, 'doc123')\n * const doc = documentSource.getCurrent()\n * const subscription = documentSource.observable.subscribe(updatedDoc => {\n * console.log('Document changed:', updatedDoc)\n * })\n * ```\n */\nexport function createStateSourceAction<TState, TParams extends unknown[], TReturn, TKey = unknown>(\n options: Selector<TState, TParams, TReturn> | StateSourceOptions<TState, TParams, TReturn, TKey>,\n): StoreAction<TState, TParams, StateSource<TReturn>, TKey> {\n const selector = typeof options === 'function' ? options : options.selector\n const subscribeHandler = options && 'onSubscribe' in options ? options.onSubscribe : undefined\n const isEqual = options && 'isEqual' in options ? (options.isEqual ?? Object.is) : Object.is\n const selectorContextCache = new WeakMap<\n object,\n WeakMap<SanityInstance, SelectorContext<TState>>\n >()\n\n /**\n * The state source action implementation\n * @param context - Store context providing access to state and instance\n * @param params - Parameters provided when invoking the bound action\n */\n function stateSourceAction(context: StoreContext<TState, TKey>, ...params: TParams) {\n const {state, instance} = context\n\n const getCurrent = () => {\n const currentState = state.get()\n if (typeof currentState !== 'object' || currentState === null) {\n throw new Error(\n `Expected store state to be an object but got \"${typeof currentState}\" instead`,\n )\n }\n\n let instanceCache = selectorContextCache.get(currentState)\n if (!instanceCache) {\n instanceCache = new WeakMap<SanityInstance, SelectorContext<TState>>()\n selectorContextCache.set(currentState, instanceCache)\n }\n let selectorContext = instanceCache.get(instance)\n if (!selectorContext) {\n selectorContext = {state: currentState, instance}\n instanceCache.set(instance, selectorContext)\n }\n return selector(selectorContext, ...params)\n }\n\n // Subscription manager handles both RxJS and direct subscriptions\n const subscribe = (onStoreChanged?: () => void) => {\n // Run setup handler if provided\n const cleanup = subscribeHandler?.(context, ...params)\n\n // Set up state change subscription\n const subscription = state.observable\n .pipe(\n // Derive value from current state\n map(getCurrent),\n // Filter unchanged values using custom equality check\n distinctUntilChanged(isEqual),\n // Skip initial emission since we only want changes\n skip(1),\n )\n .subscribe({\n next: () => onStoreChanged?.(),\n // Propagate selector errors to both subscription types\n error: () => onStoreChanged?.(),\n })\n\n return () => {\n subscription.unsubscribe()\n cleanup?.()\n }\n }\n\n // Create shared observable that handles multiple subscribers efficiently\n const observable = new Observable<TReturn>((observer) => {\n const emitCurrent = () => {\n try {\n observer.next(getCurrent())\n } catch (error) {\n observer.error(error)\n }\n }\n // Emit immediately on subscription\n emitCurrent()\n return subscribe(emitCurrent)\n }).pipe(share())\n\n return {\n getCurrent,\n subscribe,\n observable,\n }\n }\n\n return stateSourceAction\n}\n","export const DEFAULT_BASE = 'http://localhost'\nexport const AUTH_CODE_PARAM = 'sid'\nexport const DEFAULT_API_VERSION = '2021-06-07'\nexport const REQUEST_TAG_PREFIX = 'sanity.sdk.auth'\n","import {type SanityConfig} from '../config/sanityConfig'\nimport {DEFAULT_BASE} from './authConstants'\n\n/**\n * The runtime auth mode determines which authentication strategy the SDK uses.\n *\n * - `studio` — Running inside Sanity Studio. Token is discovered from\n * Studio's localStorage entry or via cookie auth.\n * - `dashboard` — Running inside the Sanity Dashboard iframe. Token is\n * provided by the parent frame via Comlink.\n * - `standalone` — Running as an independent app. Token comes from\n * localStorage or the OAuth login flow.\n *\n * @internal\n */\ntype AuthMode = 'studio' | 'dashboard' | 'standalone'\n\n/**\n * Determines the auth mode from instance config and environment.\n *\n * Priority:\n * 1. `studio` config provided → `'studio'`\n * 2. Dashboard context detected (`_context` URL param with content) → `'dashboard'`\n * 3. Otherwise → `'standalone'`\n *\n * @internal\n */\nexport function resolveAuthMode(config: SanityConfig, locationHref: string): AuthMode {\n if (isStudioConfig(config)) return 'studio'\n if (detectDashboardContext(locationHref)) return 'dashboard'\n return 'standalone'\n}\n\n/**\n * Returns `true` when the config indicates the SDK is running inside a Studio.\n *\n * @internal\n */\nexport function isStudioConfig(config: SanityConfig): boolean {\n return !!config.studio\n}\n\n/**\n * Checks whether the given location href contains a `_context` URL parameter\n * with a non-empty JSON object, indicating the SDK is running inside the\n * Sanity Dashboard.\n *\n * @internal\n */\nfunction detectDashboardContext(locationHref: string): boolean {\n try {\n const parsedUrl = new URL(locationHref, DEFAULT_BASE)\n const contextParam = parsedUrl.searchParams.get('_context')\n if (!contextParam) return false\n\n const parsed: unknown = JSON.parse(contextParam)\n return (\n typeof parsed === 'object' &&\n parsed !== null &&\n !Array.isArray(parsed) &&\n Object.keys(parsed as Record<string, unknown>).length > 0\n )\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('Failed to parse dashboard context from initial location:', err)\n return false\n }\n}\n","/**\n * Represents the various states the authentication type can be in.\n *\n * @public\n */\nexport enum AuthStateType {\n LOGGED_IN = 'logged-in',\n LOGGING_IN = 'logging-in',\n ERROR = 'error',\n LOGGED_OUT = 'logged-out',\n}\n","import {\n distinctUntilChanged,\n exhaustMap,\n filter,\n firstValueFrom,\n from,\n map,\n Observable,\n type Subscription,\n switchMap,\n takeWhile,\n timer,\n} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {DEFAULT_API_VERSION} from './authConstants'\nimport {AuthStateType} from './authStateType'\nimport {type AuthState, type AuthStoreState} from './authStore'\n\nconst REFRESH_INTERVAL = 12 * 60 * 60 * 1000 // 12 hours in milliseconds\nconst LOCK_NAME = 'sanity-token-refresh-lock'\n\n/** @internal */\nexport function getLastRefreshTime(storageArea: Storage | undefined, storageKey: string): number {\n try {\n const data = storageArea?.getItem(`${storageKey}_last_refresh`)\n const parsed = data ? parseInt(data, 10) : 0\n return isNaN(parsed) ? 0 : parsed\n } catch {\n return 0\n }\n}\n\n/** @internal */\nexport function setLastRefreshTime(storageArea: Storage | undefined, storageKey: string): void {\n try {\n storageArea?.setItem(`${storageKey}_last_refresh`, Date.now().toString())\n } catch {\n // Ignore storage errors\n }\n}\n\n/** @internal */\nexport function getNextRefreshDelay(storageArea: Storage | undefined, storageKey: string): number {\n const lastRefresh = getLastRefreshTime(storageArea, storageKey)\n if (!lastRefresh) return 0\n\n const now = Date.now()\n const nextRefreshTime = lastRefresh + REFRESH_INTERVAL\n return Math.max(0, nextRefreshTime - now)\n}\n\nfunction createTokenRefreshStream(\n token: string,\n clientFactory: AuthStoreState['options']['clientFactory'],\n apiHost: string | undefined,\n): Observable<{token: string}> {\n return new Observable((subscriber) => {\n const client = clientFactory({\n apiVersion: DEFAULT_API_VERSION,\n requestTagPrefix: 'token-refresh',\n useProjectHostname: false,\n useCdn: false,\n token,\n ignoreBrowserTokenWarning: true,\n ...(apiHost && {apiHost}),\n })\n\n const subscription = client.observable\n .request<{token: string}>({\n uri: 'auth/refresh-token',\n method: 'POST',\n body: {\n token,\n },\n })\n .subscribe(subscriber)\n\n return () => subscription.unsubscribe()\n })\n}\n\nasync function acquireTokenRefreshLock(\n refreshFn: () => Promise<void>,\n storageArea: Storage | undefined,\n storageKey: string,\n): Promise<boolean> {\n if (!navigator.locks) {\n // If Web Locks API is not supported, perform an immediate, uncoordinated refresh.\n // eslint-disable-next-line no-console\n console.warn('Web Locks API not supported. Proceeding with uncoordinated refresh.')\n await refreshFn()\n setLastRefreshTime(storageArea, storageKey)\n return true // Indicate success to allow stream processing, though it won't loop.\n }\n\n try {\n // Attempt to acquire an exclusive lock for token refresh coordination.\n // The callback handles the continuous refresh cycle while the lock is held.\n const result = await navigator.locks.request(LOCK_NAME, {mode: 'exclusive'}, async (lock) => {\n if (!lock) return false // Lock not granted\n\n // Problematic infinite loop - needs redesign for graceful termination.\n // This loop continuously refreshes the token at REFRESH_INTERVAL.\n while (true) {\n const delay = getNextRefreshDelay(storageArea, storageKey)\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, delay))\n }\n try {\n await refreshFn()\n setLastRefreshTime(storageArea, storageKey)\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Token refresh failed within lock:', error)\n // Decide how to handle errors - break, retry, etc.? Currently logs and continues.\n }\n // Wait for the next interval\n await new Promise((resolve) => setTimeout(resolve, REFRESH_INTERVAL))\n }\n // Unreachable due to while(true)\n })\n // The promise from navigator.locks.request resolves with the callback's return value,\n // but only if the callback finishes. The infinite loop prevents this.\n return result === true\n } catch (error) {\n // Handle potential errors during the initial lock request itself.\n // eslint-disable-next-line no-console\n console.error('Failed to request token refresh lock:', error)\n return false // Indicate lock acquisition failure.\n }\n}\n\nfunction shouldRefreshToken(lastRefresh: number | undefined): boolean {\n if (!lastRefresh) return true\n const timeSinceLastRefresh = Date.now() - lastRefresh\n return timeSinceLastRefresh >= REFRESH_INTERVAL\n}\n\n/**\n * @internal\n */\nexport const refreshStampedToken = ({state}: StoreContext<AuthStoreState>): Subscription => {\n const {clientFactory, apiHost, storageArea, storageKey} = state.get().options\n\n const refreshToken$ = state.observable.pipe(\n map((storeState) => ({\n authState: storeState.authState,\n dashboardContext: storeState.dashboardContext,\n })),\n filter(\n (\n storeState,\n ): storeState is {\n authState: Extract<AuthState, {type: AuthStateType.LOGGED_IN}>\n dashboardContext: AuthStoreState['dashboardContext']\n } => storeState.authState.type === AuthStateType.LOGGED_IN,\n ),\n distinctUntilChanged(\n (prev, curr) =>\n prev.authState.type === curr.authState.type &&\n prev.authState.token === curr.authState.token && // Only care about token for distinctness here\n prev.dashboardContext === curr.dashboardContext,\n ), // Make distinctness check explicit\n filter((storeState) => storeState.authState.token.includes('-st')), // Ensure we only try to refresh stamped tokens\n exhaustMap((storeState) => {\n // USE exhaustMap instead of switchMap\n // Create a function that performs a single refresh and updates state/storage\n const performRefresh = async () => {\n // Read the latest token directly from state inside refresh\n const currentState = state.get()\n if (currentState.authState.type !== AuthStateType.LOGGED_IN) {\n throw new Error('User logged out before refresh could complete') // Abort refresh\n }\n const currentToken = currentState.authState.token\n\n const response = await firstValueFrom(\n createTokenRefreshStream(currentToken, clientFactory, apiHost),\n )\n\n state.set('setRefreshStampedToken', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {...prev.authState, token: response.token}\n : prev.authState,\n }))\n storageArea?.setItem(storageKey, JSON.stringify({token: response.token}))\n }\n\n if (storeState.dashboardContext) {\n return new Observable<{token: string}>((subscriber) => {\n const visibilityHandler = () => {\n const currentState = state.get()\n if (\n document.visibilityState === 'visible' &&\n currentState.authState.type === AuthStateType.LOGGED_IN &&\n shouldRefreshToken(currentState.authState.lastTokenRefresh)\n ) {\n createTokenRefreshStream(\n currentState.authState.token,\n clientFactory,\n apiHost,\n ).subscribe({\n next: (response) => {\n state.set('setRefreshStampedToken', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {\n ...prev.authState,\n token: response.token,\n lastTokenRefresh: Date.now(),\n }\n : prev.authState,\n }))\n subscriber.next(response)\n },\n error: (error) => subscriber.error(error),\n })\n }\n }\n\n const timerSubscription = timer(REFRESH_INTERVAL, REFRESH_INTERVAL)\n .pipe(\n filter(() => document.visibilityState === 'visible'),\n switchMap(() => {\n const currentState = state.get().authState\n if (currentState.type !== AuthStateType.LOGGED_IN) {\n throw new Error('User logged out before refresh could complete')\n }\n return createTokenRefreshStream(currentState.token, clientFactory, apiHost)\n }),\n )\n .subscribe({\n next: (response) => {\n state.set('setRefreshStampedToken', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {\n ...prev.authState,\n token: response.token,\n lastTokenRefresh: Date.now(),\n }\n : prev.authState,\n }))\n subscriber.next(response)\n },\n error: (error) => subscriber.error(error),\n })\n\n document.addEventListener('visibilitychange', visibilityHandler)\n\n return () => {\n document.removeEventListener('visibilitychange', visibilityHandler)\n timerSubscription.unsubscribe()\n }\n }).pipe(\n takeWhile(() => state.get().authState.type === AuthStateType.LOGGED_IN),\n map((response: {token: string}) => ({token: response.token})),\n )\n }\n\n // If not in dashboard context, use lock-based refresh\n return from(acquireTokenRefreshLock(performRefresh, storageArea, storageKey)).pipe(\n filter((hasLock) => hasLock),\n map(() => {\n const currentState = state.get().authState\n if (currentState.type !== AuthStateType.LOGGED_IN) {\n throw new Error('User logged out before refresh could complete')\n }\n return {token: currentState.token} as const\n }),\n )\n }),\n )\n\n return refreshToken$.subscribe({\n next: (response: {token: string}) => {\n state.set('setRefreshStampedToken', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {\n ...prev.authState,\n token: response.token,\n lastTokenRefresh: Date.now(),\n }\n : prev.authState,\n }))\n storageArea?.setItem(storageKey, JSON.stringify({token: response.token}))\n },\n error: (error) => {\n state.set('setRefreshStampedTokenError', {authState: {type: AuthStateType.ERROR, error}})\n },\n })\n}\n","import {type CurrentUser} from '@sanity/types'\nimport {distinctUntilChanged, filter, map, type Subscription, switchMap} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {DEFAULT_API_VERSION, REQUEST_TAG_PREFIX} from './authConstants'\nimport {isStudioConfig} from './authMode'\nimport {AuthStateType} from './authStateType'\nimport {type AuthMethodOptions, type AuthState, type AuthStoreState} from './authStore'\n\n/**\n * Subscribes to auth state changes and fetches the current user when\n * the state transitions to `LOGGED_IN` without a `currentUser`.\n *\n * @param context - The store context for the auth store.\n * @param fetchOptions - Configuration options. When `useProjectHostname` is\n * `true`, requests use the project-specific hostname (required for Studio\n * cookie auth). Set to `true` for studio mode, `false` otherwise.\n *\n * @internal\n */\nexport const subscribeToStateAndFetchCurrentUser = (\n {state, instance}: StoreContext<AuthStoreState>,\n fetchOptions?: {useProjectHostname?: boolean},\n): Subscription => {\n const {clientFactory, apiHost} = state.get().options\n const useProjectHostname = fetchOptions?.useProjectHostname ?? isStudioConfig(instance.config)\n const projectId = instance.config.studio?.projectId\n\n const currentUser$ = state.observable\n .pipe(\n map(({authState, options: storeOptions}) => ({\n authState,\n authMethod: storeOptions.authMethod,\n })),\n filter(\n (\n value,\n ): value is {\n authState: Extract<AuthState, {type: AuthStateType.LOGGED_IN}>\n authMethod: AuthMethodOptions\n } => value.authState.type === AuthStateType.LOGGED_IN && !value.authState.currentUser,\n ),\n map((value) => ({token: value.authState.token, authMethod: value.authMethod})),\n distinctUntilChanged(\n (prev, curr) => prev.token === curr.token && prev.authMethod === curr.authMethod,\n ),\n )\n .pipe(\n map(({token, authMethod}) =>\n clientFactory({\n apiVersion: DEFAULT_API_VERSION,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n token: authMethod === 'cookie' ? undefined : token,\n ignoreBrowserTokenWarning: true,\n useProjectHostname,\n useCdn: false,\n ...(authMethod === 'cookie' ? {withCredentials: true} : {}),\n ...(useProjectHostname && projectId ? {projectId} : {}),\n ...(apiHost && {apiHost}),\n }),\n ),\n switchMap((client) =>\n client.observable.request<CurrentUser>({uri: '/users/me', method: 'GET'}),\n ),\n )\n\n return currentUser$.subscribe({\n next: (currentUser) => {\n state.set('setCurrentUser', (prev) => ({\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? {...prev.authState, currentUser}\n : prev.authState,\n }))\n },\n error: (error) => {\n state.set('setError', {authState: {type: AuthStateType.ERROR, error}})\n },\n })\n}\n","import {type ClientError} from '@sanity/client'\nimport {type CurrentUser} from '@sanity/types'\nimport {EMPTY, fromEvent, Observable} from 'rxjs'\n\nimport {AUTH_CODE_PARAM, DEFAULT_BASE} from './authConstants'\nimport {AuthStateType} from './authStateType'\nimport {type LoggedInAuthState} from './authStore'\n\n/**\n * Creates a properly initialized {@link LoggedInAuthState}.\n *\n * For stamped tokens (containing `\"-st\"`), `lastTokenRefresh` is set to\n * `Date.now()` so that the visibility-change handler in\n * {@link refreshStampedToken} does not trigger an unnecessary refresh the\n * first time the tab becomes visible.\n *\n * @param token - The auth token.\n * @param currentUser - The current user, or `null` if not yet fetched.\n * @param existingLastTokenRefresh - An existing timestamp to preserve\n * (e.g. when updating a token while keeping the previous refresh time).\n * @internal\n */\nexport function createLoggedInAuthState(\n token: string,\n currentUser: CurrentUser | null,\n existingLastTokenRefresh?: number,\n): LoggedInAuthState {\n const isStampedToken = token.includes('-st')\n const lastTokenRefresh = existingLastTokenRefresh ?? (isStampedToken ? Date.now() : undefined)\n\n return {\n type: AuthStateType.LOGGED_IN,\n token,\n currentUser,\n ...(lastTokenRefresh !== undefined && {lastTokenRefresh}),\n }\n}\n\nexport function getAuthCode(callbackUrl: string | undefined, locationHref: string): string | null {\n const loc = new URL(locationHref, DEFAULT_BASE)\n const callbackLocation = callbackUrl ? new URL(callbackUrl, DEFAULT_BASE) : undefined\n const callbackLocationMatches = callbackLocation\n ? loc.pathname.toLowerCase().startsWith(callbackLocation.pathname.toLowerCase())\n : true\n\n // First, try getting the auth code (sid) from hash or search params directly\n let authCode =\n new URLSearchParams(loc.hash.slice(1)).get(AUTH_CODE_PARAM) ||\n new URLSearchParams(loc.search).get(AUTH_CODE_PARAM)\n\n // If not found directly, try extracting it from the _context parameter as a fallback\n if (!authCode) {\n const contextParam = new URLSearchParams(loc.search).get('_context')\n if (contextParam) {\n try {\n const parsedContext = JSON.parse(contextParam)\n if (\n parsedContext &&\n typeof parsedContext === 'object' &&\n typeof parsedContext.sid === 'string' &&\n parsedContext.sid // Ensure it's not an empty string\n ) {\n authCode = parsedContext.sid\n }\n } catch {\n // Silently ignore _context JSON parsing errors; authCode remains null/empty\n }\n }\n }\n\n return authCode && callbackLocationMatches ? authCode : null\n}\n\nexport function getTokenFromLocation(locationHref: string): string | null {\n const loc = new URL(locationHref)\n const token = new URLSearchParams(loc.hash.slice(1)).get('token')\n return token ? token : null\n}\n\n/**\n * Attempts to retrieve a token from the configured storage.\n * If invalid or not present, returns null.\n */\nexport function getTokenFromStorage(\n storageArea: Storage | undefined,\n storageKey: string,\n): string | null {\n if (!storageArea) return null\n const item = storageArea.getItem(storageKey)\n if (item === null) return null\n\n try {\n const parsed: unknown = JSON.parse(item)\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n !('token' in parsed) ||\n typeof parsed.token !== 'string'\n ) {\n throw new Error('Invalid stored auth data structure')\n }\n return parsed.token\n } catch {\n storageArea.removeItem(storageKey)\n return null\n }\n}\n\n/**\n * Creates an observable stream of storage events. If not in a browser environment,\n * returns an EMPTY observable.\n */\nexport function getStorageEvents(): Observable<StorageEvent> {\n const isBrowser = typeof window !== 'undefined' && typeof window.addEventListener === 'function'\n\n if (!isBrowser) {\n return EMPTY\n }\n\n return fromEvent<StorageEvent>(window, 'storage')\n}\n\n/**\n * Returns a default storage instance (localStorage) if available.\n * If not available or an error occurs, returns undefined.\n */\nexport function getDefaultStorage(): Storage | undefined {\n try {\n if (typeof localStorage !== 'undefined' && typeof localStorage.getItem === 'function') {\n return localStorage\n }\n return undefined\n } catch {\n return undefined\n }\n}\n\n/**\n * Returns the default location to use.\n * Tries accessing `location.href`, falls back to a default base if not available or on error.\n */\nexport function getDefaultLocation(): string {\n try {\n if (typeof location === 'undefined') return DEFAULT_BASE\n if (typeof location.href === 'string') return location.href\n return DEFAULT_BASE\n } catch {\n return DEFAULT_BASE\n }\n}\n\n/**\n * Cleans up the URL by removing the `token` from the hash and the `sid` and `url` search params.\n * @internal\n */\nexport function getCleanedUrl(locationUrl: string): string {\n const loc = new URL(locationUrl)\n // Remove only the `token` param from the hash while preserving other fragments\n const rawHash = loc.hash.startsWith('#') ? loc.hash.slice(1) : loc.hash\n if (rawHash && rawHash.includes('=')) {\n const hashParams = new URLSearchParams(rawHash)\n hashParams.delete('token')\n hashParams.delete('withSid')\n const nextHash = hashParams.toString()\n loc.hash = nextHash ? `#${nextHash}` : ''\n }\n loc.searchParams.delete('sid')\n loc.searchParams.delete('url')\n return loc.toString()\n}\n\n// -----------------------------------------------------------------------------\n// ClientError helpers (shared)\n// -----------------------------------------------------------------------------\n\n/** @internal */\nexport type ApiErrorBody = {\n error?: {type?: string; description?: string}\n type?: string\n description?: string\n message?: string\n}\n\n/** @internal Extracts the structured API error body from a ClientError, if present. */\nexport function getClientErrorApiBody(error: ClientError): ApiErrorBody | undefined {\n const body: unknown = (error as ClientError).response?.body\n return body && typeof body === 'object' ? (body as ApiErrorBody) : undefined\n}\n\n/** @internal Returns the error type string from an API error body, if available. */\nexport function getClientErrorApiType(error: ClientError): string | undefined {\n const body = getClientErrorApiBody(error)\n return body?.error?.type ?? body?.type\n}\n\n/** @internal Returns the error description string from an API error body, if available. */\nexport function getClientErrorApiDescription(error: ClientError): string | undefined {\n const body = getClientErrorApiBody(error)\n return body?.error?.description ?? body?.description\n}\n\n/** @internal True if the error represents a projectUserNotFoundError. */\nexport function isProjectUserNotFoundClientError(error: ClientError): boolean {\n return getClientErrorApiType(error) === 'projectUserNotFoundError'\n}\n","import {type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {DEFAULT_BASE} from './authConstants'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState, type DashboardContext} from './authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from './authStrategy'\nimport {refreshStampedToken} from './refreshStampedToken'\nimport {subscribeToStateAndFetchCurrentUser} from './subscribeToStateAndFetchCurrentUser'\nimport {createLoggedInAuthState, getAuthCode, getTokenFromLocation} from './utils'\n\n/**\n * Parses the dashboard context from a location href's `_context` URL parameter.\n * Strips the `sid` property from the parsed context (it's handled separately).\n *\n * @internal\n */\nfunction parseDashboardContext(locationHref: string): DashboardContext {\n try {\n const parsedUrl = new URL(locationHref, DEFAULT_BASE)\n const contextParam = parsedUrl.searchParams.get('_context')\n if (contextParam) {\n const parsedContext = JSON.parse(contextParam)\n\n if (\n parsedContext &&\n typeof parsedContext === 'object' &&\n !Array.isArray(parsedContext) &&\n Object.keys(parsedContext).length > 0\n ) {\n // Explicitly remove the 'sid' property before assigning\n delete parsedContext.sid\n return parsedContext as DashboardContext\n }\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('Failed to parse dashboard context from initial location:', err)\n }\n return {} // Empty dashboard context if parsing fails\n}\n\n/**\n * Resolves the initial auth state for Dashboard mode.\n *\n * In dashboard mode the token is provided by the parent frame via Comlink,\n * so the SDK starts in a `LOGGED_OUT` state and waits for the token to arrive.\n * The `_context` URL parameter provides dashboard metadata (orgId, mode, env).\n *\n * A provided token (`auth.token`) or an auth code/callback still takes\n * precedence, even when running inside the dashboard.\n *\n * @internal\n */\nexport function getDashboardInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, initialLocationHref} = options\n const providedToken = authConfig.token\n const callbackUrl = authConfig.callbackUrl\n const storageKey = '__sanity_auth_token'\n\n const dashboardContext = parseDashboardContext(initialLocationHref)\n\n // Dashboard does NOT use localStorage — token comes from the parent frame\n const storageArea = undefined\n\n // Provided token always wins, even in dashboard\n if (providedToken) {\n return {\n authState: createLoggedInAuthState(providedToken, null),\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext,\n }\n }\n\n // Check for auth code or token-from-location (callback handling)\n if (getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref)) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext,\n }\n }\n\n // Default: logged out, waiting for Comlink to provide token\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext,\n }\n}\n\n/**\n * Initialize Dashboard auth subscriptions:\n * - Subscribe to state changes and fetch current user\n * - Start stamped token refresh\n *\n * Note: storage events are NOT subscribed in dashboard mode since\n * the dashboard does not use localStorage for token persistence.\n *\n * @internal\n */\nexport function initializeDashboardAuth(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n let startedRefresher = false\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: false}))\n\n // Dashboard does not subscribe to storage events\n\n if (!tokenRefresherRunning) {\n startedRefresher = true\n subscriptions.push(refreshStampedToken(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: startedRefresher,\n }\n}\n","import {defer, distinctUntilChanged, filter, map, type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState} from './authStore'\nimport {createLoggedInAuthState, getStorageEvents, getTokenFromStorage} from './utils'\n\nexport const subscribeToStorageEventsAndSetToken = ({\n state,\n}: StoreContext<AuthStoreState>): Subscription => {\n const {storageArea, storageKey} = state.get().options\n\n const tokenFromStorage$ = defer(getStorageEvents).pipe(\n filter(\n (e): e is StorageEvent & {newValue: string} =>\n e.storageArea === storageArea && e.key === storageKey,\n ),\n map(() => getTokenFromStorage(storageArea, storageKey)),\n distinctUntilChanged(),\n )\n\n return tokenFromStorage$.subscribe((token) => {\n state.set('updateTokenFromStorageEvent', {\n authState: token\n ? createLoggedInAuthState(token, null)\n : {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n })\n })\n}\n","import {type Subscription} from 'rxjs'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState} from './authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from './authStrategy'\nimport {refreshStampedToken} from './refreshStampedToken'\nimport {subscribeToStateAndFetchCurrentUser} from './subscribeToStateAndFetchCurrentUser'\nimport {subscribeToStorageEventsAndSetToken} from './subscribeToStorageEventsAndSetToken'\nimport {\n createLoggedInAuthState,\n getAuthCode,\n getDefaultStorage,\n getTokenFromLocation,\n getTokenFromStorage,\n} from './utils'\n\n/**\n * Resolves the initial auth state for Standalone mode.\n *\n * Token discovery order:\n * 1. Provided token (`auth.token` in config)\n * 2. Auth code or token from location (OAuth callback)\n * 3. localStorage: `__sanity_auth_token`\n * 4. Falls back to `LOGGED_OUT`\n *\n * @internal\n */\nexport function getStandaloneInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, initialLocationHref} = options\n const providedToken = authConfig.token\n const callbackUrl = authConfig.callbackUrl\n const storageKey = '__sanity_auth_token'\n const storageArea = authConfig.storageArea ?? getDefaultStorage()\n\n // Provided token always wins\n if (providedToken) {\n return {\n authState: createLoggedInAuthState(providedToken, null),\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n\n // Check for auth code or token-from-location (OAuth callback)\n if (getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref)) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n\n // Try localStorage\n const token = getTokenFromStorage(storageArea, storageKey)\n if (token) {\n return {\n authState: createLoggedInAuthState(token, null),\n storageKey,\n storageArea,\n authMethod: 'localstorage',\n dashboardContext: {},\n }\n }\n\n // No token found\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n}\n\n/**\n * Initialize Standalone auth subscriptions:\n * - Subscribe to state changes and fetch current user\n * - Subscribe to storage events for token key\n * - Start stamped token refresh\n *\n * @internal\n */\nexport function initializeStandaloneAuth(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n let startedRefresher = false\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: false}))\n\n const storageArea = context.state.get().options?.storageArea\n if (storageArea) {\n subscriptions.push(subscribeToStorageEventsAndSetToken(context))\n }\n\n if (!tokenRefresherRunning) {\n startedRefresher = true\n subscriptions.push(refreshStampedToken(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: startedRefresher,\n }\n}\n","import {type ClientConfig, type SanityClient} from '@sanity/client'\n\nimport {getTokenFromStorage} from './utils'\n\n/**\n * Cookie auth is a best-effort probe — if the API doesn't respond quickly,\n * the user likely isn't cookie-authenticated and we should move on rather\n * than block the auth flow indefinitely.\n */\nconst COOKIE_AUTH_TIMEOUT_MS = 10_000\n\n/**\n * Attempts to check for cookie auth by making a withCredentials request to the users endpoint.\n * @param projectId - The project ID to check for cookie auth.\n * @param clientFactory - A factory function that creates a Sanity client.\n * @returns True if the user is authenticated, false otherwise.\n * @internal\n */\nexport async function checkForCookieAuth(\n projectId: string | undefined,\n clientFactory: (config: ClientConfig) => SanityClient,\n): Promise<boolean> {\n if (!projectId) return false\n try {\n const client = clientFactory({\n projectId,\n useCdn: false,\n requestTagPrefix: 'sdk',\n timeout: COOKIE_AUTH_TIMEOUT_MS,\n })\n const user = await client.request({\n uri: '/users/me',\n withCredentials: true,\n tag: 'users.get-current',\n })\n return user != null && typeof user === 'object' && typeof user.id === 'string'\n } catch {\n return false\n }\n}\n\n/**\n * Attempts to retrieve a studio token from local storage.\n * @param storageArea - The storage area to retrieve the token from.\n * @param storageKey - The storage key to retrieve the token from.\n * @returns The studio token or null if it does not exist.\n * @internal\n */\nexport function getStudioTokenFromLocalStorage(\n storageArea: Storage | undefined,\n storageKey: string | undefined,\n): string | null {\n if (!storageArea || !storageKey) return null\n const token = getTokenFromStorage(storageArea, storageKey)\n if (token) {\n return token\n }\n return null\n}\n","import {type Subscription} from 'rxjs'\n\nimport {type TokenSource} from '../config/sanityConfig'\nimport {type StoreContext} from '../store/defineStore'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStoreState, type LoggedInAuthState} from './authStore'\nimport {type AuthStrategyOptions, type AuthStrategyResult} from './authStrategy'\nimport {refreshStampedToken} from './refreshStampedToken'\nimport {checkForCookieAuth, getStudioTokenFromLocalStorage} from './studioModeAuth'\nimport {subscribeToStateAndFetchCurrentUser} from './subscribeToStateAndFetchCurrentUser'\nimport {subscribeToStorageEventsAndSetToken} from './subscribeToStorageEventsAndSetToken'\nimport {createLoggedInAuthState, getDefaultStorage} from './utils'\n\n/**\n * Resolves the initial auth state for Studio mode.\n *\n * When a `tokenSource` is provided (via `config.studio.auth.token`), the\n * initial state is `LOGGING_IN` — the actual token arrives asynchronously\n * via the subscription set up in `initializeStudioAuth`.\n *\n * Fallback token discovery order (no tokenSource):\n * 1. Provided token (`auth.token` in config)\n * 2. localStorage: `__studio_auth_token_${projectId}`\n * 3. Falls back to `LOGGED_OUT` (cookie auth is checked async in `initializeStudioAuth`)\n *\n * @internal\n */\nexport function getStudioInitialState(options: AuthStrategyOptions): AuthStrategyResult {\n const {authConfig, projectId, tokenSource} = options\n const storageArea = authConfig.storageArea ?? getDefaultStorage()\n const studioStorageKey = `__studio_auth_token_${projectId ?? ''}`\n\n // When a reactive token source is available, start in LOGGING_IN state.\n // The actual token will arrive via subscription in initializeStudioAuth.\n if (tokenSource) {\n return {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: false},\n storageKey: studioStorageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n }\n\n // Fallback: discover token from config or localStorage\n const providedToken = authConfig.token\n\n // Check localStorage first — mirrors original authStore behavior where\n // the localStorage read always runs before the providedToken check.\n let authMethod: AuthStrategyResult['authMethod'] = undefined\n const token = getStudioTokenFromLocalStorage(storageArea, studioStorageKey)\n if (token) {\n authMethod = 'localstorage'\n }\n\n if (providedToken) {\n return {\n authState: createLoggedInAuthState(providedToken, null),\n storageKey: studioStorageKey,\n storageArea,\n authMethod,\n dashboardContext: {},\n }\n }\n\n if (token) {\n return {\n authState: createLoggedInAuthState(token, null),\n storageKey: studioStorageKey,\n storageArea,\n authMethod: 'localstorage',\n dashboardContext: {},\n }\n }\n\n // No token found — start logged out, cookie auth will be checked asynchronously\n return {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n storageKey: studioStorageKey,\n storageArea,\n authMethod: undefined,\n dashboardContext: {},\n }\n}\n\n/**\n * Initialize Studio auth subscriptions.\n *\n * When a `tokenSource` is available (reactive path), subscribes to it for\n * ongoing token sync. The Studio is the token authority — no independent\n * token refresh or cookie auth probing is needed.\n *\n * Fallback path (no tokenSource):\n * - Subscribe to state changes and fetch current user\n * - Subscribe to storage events for studio token key\n * - Check for cookie auth asynchronously if no token was found\n * - Start stamped token refresh\n *\n * @internal\n */\nexport function initializeStudioAuth(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const tokenSource = context.instance.config.studio?.auth?.token\n\n // Reactive token path — Studio provides the token\n if (tokenSource) {\n return initializeWithTokenSource(context, tokenSource)\n }\n\n // Fallback path — discover token from localStorage/cookies\n return initializeWithFallback(context, tokenRefresherRunning)\n}\n\n/**\n * Subscribe to a reactive token source from the Studio workspace.\n *\n * When the token source emits a non-null token, the SDK uses it directly.\n * When it emits `null`, the behavior depends on the `authenticated` flag\n * from the Studio's workspace config:\n *\n * - `authenticated: true` — the Studio has already verified the user is\n * logged in (e.g. via cookie auth). The SDK treats the null token as\n * cookie-based auth and stays in the LOGGED_IN state.\n *\n * - `authenticated` absent/false — the user is genuinely not authenticated;\n * transition to LOGGED_OUT.\n *\n * No async cookie probing is needed here because this code path only runs\n * when a Studio provides SDKStudioContext, and the Studio's Workspace type\n * always includes `authenticated`. The async `checkForCookieAuth` fallback\n * remains in `initializeWithFallback` for the non-Studio path.\n */\nfunction initializeWithTokenSource(\n context: StoreContext<AuthStoreState>,\n tokenSource: TokenSource,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n const studioAuthenticated = context.instance.config.studio?.authenticated === true\n\n // Subscribe to the current user fetcher — runs whenever auth state changes\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: true}))\n\n // Subscribe to the Studio's token stream\n const tokenSub = tokenSource.subscribe({\n next: (token) => {\n const {state} = context\n if (token) {\n // Studio provided a real token — use it directly\n state.set('studioTokenSource', (prev) => ({\n options: {...prev.options, authMethod: undefined},\n authState: createLoggedInAuthState(token, null),\n }))\n } else if (studioAuthenticated) {\n // The Studio says the user is authenticated — null token means\n // cookie-based auth is in use. Stay logged in with cookie method.\n state.set('studioTokenSourceCookieAuth', (prev) => ({\n options: {...prev.options, authMethod: 'cookie'},\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? prev.authState\n : createLoggedInAuthState('', null),\n }))\n } else {\n // No token and Studio doesn't confirm authentication — logged out\n state.set('studioTokenSourceLoggedOut', (prev) => ({\n options: {...prev.options, authMethod: undefined},\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n }))\n }\n },\n })\n\n return {\n dispose: () => {\n tokenSub.unsubscribe()\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n // Studio handles token refresh — do not start the SDK's refresher\n tokenRefresherStarted: false,\n }\n}\n\n/**\n * Fallback initialization when no reactive token source is available.\n * Uses localStorage/cookie discovery (existing behavior).\n */\nfunction initializeWithFallback(\n context: StoreContext<AuthStoreState>,\n tokenRefresherRunning: boolean,\n): {dispose: () => void; tokenRefresherStarted: boolean} {\n const subscriptions: Subscription[] = []\n let startedRefresher = false\n\n subscriptions.push(subscribeToStateAndFetchCurrentUser(context, {useProjectHostname: true}))\n\n const storageArea = context.state.get().options?.storageArea\n if (storageArea) {\n subscriptions.push(subscribeToStorageEventsAndSetToken(context))\n }\n\n // If no token found during getInitialState, try cookie auth asynchronously\n try {\n const {instance, state} = context\n const token: string | null =\n state.get().authState?.type === AuthStateType.LOGGED_IN\n ? (state.get().authState as LoggedInAuthState).token\n : null\n\n if (!token) {\n const projectIdValue = instance.config.studio?.projectId\n const clientFactory = state.get().options.clientFactory\n checkForCookieAuth(projectIdValue, clientFactory).then((isCookieAuthEnabled) => {\n if (!isCookieAuthEnabled) return\n state.set('enableCookieAuth', (prev) => ({\n options: {...prev.options, authMethod: 'cookie'},\n authState:\n prev.authState.type === AuthStateType.LOGGED_IN\n ? prev.authState\n : createLoggedInAuthState('', null),\n }))\n })\n }\n } catch {\n // best-effort cookie detection\n }\n\n if (!tokenRefresherRunning) {\n startedRefresher = true\n subscriptions.push(refreshStampedToken(context))\n }\n\n return {\n dispose: () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n },\n tokenRefresherStarted: startedRefresher,\n }\n}\n","import {type ClientConfig, createClient, type SanityClient} from '@sanity/client'\nimport {type CurrentUser} from '@sanity/types'\n\nimport {type AuthConfig, type AuthProvider} from '../config/authConfig'\nimport {bindActionGlobally} from '../store/createActionBinder'\nimport {createStateSourceAction} from '../store/createStateSourceAction'\nimport {defineStore} from '../store/defineStore'\nimport {resolveAuthMode} from './authMode'\nimport {AuthStateType} from './authStateType'\nimport {type AuthStrategyOptions} from './authStrategy'\nimport {getDashboardInitialState, initializeDashboardAuth} from './dashboardAuth'\nimport {getStandaloneInitialState, initializeStandaloneAuth} from './standaloneAuth'\nimport {getStudioInitialState, initializeStudioAuth} from './studioAuth'\nimport {createLoggedInAuthState, getCleanedUrl, getDefaultLocation} from './utils'\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Represents the various states the authentication can be in.\n *\n * @public\n */\nexport type AuthState = LoggedInAuthState | LoggedOutAuthState | LoggingInAuthState | ErrorAuthState\n\n/**\n * Logged-in state from the auth state.\n * @public\n */\nexport type LoggedInAuthState = {\n type: AuthStateType.LOGGED_IN\n token: string\n currentUser: CurrentUser | null\n lastTokenRefresh?: number\n}\n\n/**\n * Logged-out state from the auth state.\n * @public\n */\nexport type LoggedOutAuthState = {type: AuthStateType.LOGGED_OUT; isDestroyingSession: boolean}\n\n/**\n * Logging-in state from the auth state.\n * @public\n */\nexport type LoggingInAuthState = {type: AuthStateType.LOGGING_IN; isExchangingToken: boolean}\n\n/**\n * Error state from the auth state.\n * @public\n */\nexport type ErrorAuthState = {type: AuthStateType.ERROR; error: unknown}\n\n/**\n * Represents the various states the authentication can be in.\n *\n * @public\n */\nexport interface DashboardContext {\n mode?: string\n env?: string\n orgId?: string\n}\n\n/**\n * The method of authentication used.\n * @internal\n */\nexport type AuthMethodOptions = 'localstorage' | 'cookie' | undefined\n\nlet tokenRefresherRunning = false\n\n/**\n * @public\n */\nexport interface AuthStoreState {\n authState: AuthState\n providers?: AuthProvider[]\n options: {\n initialLocationHref: string\n clientFactory: (config: ClientConfig) => SanityClient\n customProviders: AuthConfig['providers']\n storageKey: string\n storageArea: Storage | undefined\n apiHost: string | undefined\n loginUrl: string\n callbackUrl: string | undefined\n providedToken: string | undefined\n authMethod: AuthMethodOptions\n }\n dashboardContext?: DashboardContext\n}\n\n// ---------------------------------------------------------------------------\n// Store definition — thin orchestrator\n// ---------------------------------------------------------------------------\n\nexport const authStore = defineStore<AuthStoreState>({\n name: 'Auth',\n\n getInitialState(instance) {\n const {\n apiHost,\n callbackUrl,\n providers: customProviders,\n token: providedToken,\n clientFactory = createClient,\n initialLocationHref = getDefaultLocation(),\n } = instance.config.auth ?? {}\n\n const authConfig = instance.config.auth ?? {}\n\n // Build login URL (used by standalone mode, but always computed for the\n // public `getLoginUrlState` accessor)\n let loginDomain = 'https://www.sanity.io'\n try {\n if (apiHost && new URL(apiHost).hostname.endsWith('.sanity.work')) {\n loginDomain = 'https://www.sanity.work'\n }\n } catch {\n /* empty */\n }\n const loginUrl = new URL('/login', loginDomain)\n loginUrl.searchParams.set('origin', getCleanedUrl(initialLocationHref))\n loginUrl.searchParams.set('type', 'stampedToken') // Token must be stamped to have an sid passed back\n loginUrl.searchParams.set('withSid', 'true')\n\n // Resolve auth mode and delegate to the appropriate strategy\n const mode = resolveAuthMode(instance.config, initialLocationHref)\n\n const strategyOptions: AuthStrategyOptions = {\n authConfig,\n projectId: instance.config.studio?.projectId,\n initialLocationHref,\n clientFactory,\n tokenSource: instance.config.studio?.auth?.token,\n }\n\n let result\n switch (mode) {\n case 'studio':\n result = getStudioInitialState(strategyOptions)\n break\n case 'dashboard':\n result = getDashboardInitialState(strategyOptions)\n break\n case 'standalone':\n result = getStandaloneInitialState(strategyOptions)\n break\n }\n\n return {\n authState: result.authState,\n dashboardContext: result.dashboardContext,\n options: {\n apiHost,\n loginUrl: loginUrl.toString(),\n callbackUrl,\n customProviders,\n providedToken,\n clientFactory,\n initialLocationHref,\n storageKey: result.storageKey,\n storageArea: result.storageArea,\n authMethod: result.authMethod,\n },\n }\n },\n\n initialize(context) {\n const initialLocationHref =\n context.state.get().options?.initialLocationHref ?? getDefaultLocation()\n const mode = resolveAuthMode(context.instance.config, initialLocationHref)\n\n let initResult\n switch (mode) {\n case 'studio':\n initResult = initializeStudioAuth(context, tokenRefresherRunning)\n break\n case 'dashboard':\n initResult = initializeDashboardAuth(context, tokenRefresherRunning)\n break\n case 'standalone':\n initResult = initializeStandaloneAuth(context, tokenRefresherRunning)\n break\n }\n\n if (initResult.tokenRefresherStarted) {\n tokenRefresherRunning = true\n }\n\n return initResult.dispose\n },\n})\n\n// ---------------------------------------------------------------------------\n// Public bound actions\n// ---------------------------------------------------------------------------\n\n/**\n * @public\n */\nexport const getCurrentUserState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {authState}}) =>\n authState.type === AuthStateType.LOGGED_IN ? authState.currentUser : null,\n ),\n)\n\n/**\n * @public\n */\nexport const getTokenState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {authState}}) =>\n authState.type === AuthStateType.LOGGED_IN ? authState.token : null,\n ),\n)\n\n/**\n * @internal\n */\nexport const getAuthMethodState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {options}}) => options.authMethod),\n)\n\n/**\n * @public\n */\nexport const getLoginUrlState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {options}}) => options.loginUrl),\n)\n\n/**\n * @public\n */\nexport const getAuthState = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {authState}}) => authState),\n)\n\n/**\n * @public\n */\nexport const getDashboardOrganizationId = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {dashboardContext}}) => dashboardContext?.orgId),\n)\n\n/**\n * Returns a state source indicating if the SDK is running within a dashboard context.\n * @public\n */\nexport const getIsInDashboardState = bindActionGlobally(\n authStore,\n createStateSourceAction(\n ({state: {dashboardContext}}) =>\n // Check if dashboardContext exists and is not empty\n !!dashboardContext && Object.keys(dashboardContext).length > 0,\n ),\n)\n\n/**\n * Action to explicitly set the authentication token.\n * Used internally by the Comlink token refresh.\n * @internal\n */\nexport const setAuthToken = bindActionGlobally(authStore, ({state}, token: string | null) => {\n const currentAuthState = state.get().authState\n if (token) {\n // Update state only if the new token is different or currently logged out\n if (currentAuthState.type !== AuthStateType.LOGGED_IN || currentAuthState.token !== token) {\n const currentUser =\n currentAuthState.type === AuthStateType.LOGGED_IN ? currentAuthState.currentUser : null\n const preservedLastTokenRefresh =\n currentAuthState.type === AuthStateType.LOGGED_IN\n ? currentAuthState.lastTokenRefresh\n : undefined\n state.set('setToken', {\n authState: createLoggedInAuthState(token, currentUser, preservedLastTokenRefresh),\n })\n }\n } else {\n // Handle setting token to null (logging out)\n if (currentAuthState.type !== AuthStateType.LOGGED_OUT) {\n state.set('setToken', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n })\n }\n }\n})\n","import {\n type ClientConfig,\n type ClientPerspective,\n createClient,\n type SanityClient,\n} from '@sanity/client'\nimport {pick} from 'lodash-es'\n\nimport {getAuthMethodState, getTokenState} from '../auth/authStore'\nimport {\n type DocumentResource,\n isCanvasResource,\n isDatasetResource,\n isMediaLibraryResource,\n} from '../config/sanityConfig'\nimport {bindActionGlobally} from '../store/createActionBinder'\nimport {createStateSourceAction} from '../store/createStateSourceAction'\nimport {defineStore, type StoreContext} from '../store/defineStore'\n\nconst DEFAULT_API_VERSION = '2024-11-12'\nconst DEFAULT_REQUEST_TAG_PREFIX = 'sanity.sdk'\n\ntype AllowedClientConfigKey =\n | 'useCdn'\n | 'token'\n | 'perspective'\n | 'apiHost'\n | 'proxy'\n | 'withCredentials'\n | 'timeout'\n | 'maxRetries'\n | 'dataset'\n | 'projectId'\n | 'requestTagPrefix'\n | 'useProjectHostname'\n\nconst allowedKeys = Object.keys({\n 'apiHost': null,\n 'useCdn': null,\n 'token': null,\n 'perspective': null,\n 'proxy': null,\n 'withCredentials': null,\n 'timeout': null,\n 'maxRetries': null,\n 'dataset': null,\n 'projectId': null,\n 'scope': null,\n 'apiVersion': null,\n 'requestTagPrefix': null,\n 'useProjectHostname': null,\n '~experimental_resource': null,\n 'resource': null,\n} satisfies Record<keyof ClientOptions, null>) as (keyof ClientOptions)[]\n\nconst DEFAULT_CLIENT_CONFIG = {\n apiVersion: DEFAULT_API_VERSION,\n useCdn: false,\n ignoreBrowserTokenWarning: true,\n allowReconfigure: false,\n requestTagPrefix: DEFAULT_REQUEST_TAG_PREFIX,\n} satisfies ClientConfig\n\n/**\n * States tracked by the client store\n * @public\n */\nexport interface ClientStoreState {\n token: string | null\n clients: {[TKey in string]?: SanityClient}\n authMethod?: 'localstorage' | 'cookie'\n}\n\ninterface ClientResource {\n type: 'dataset' | 'media-library' | 'canvas'\n id: string\n}\n\n/**\n * Options used when retrieving a client instance from the client store.\n *\n * This interface extends the base {@link ClientConfig} and adds:\n *\n * - **apiVersion:** A required string indicating the API version for the client.\n * - **scope:** An optional flag to choose between the project-specific client\n * ('project') and the global client ('global'). When set to `'global'`, the\n * global client is used.\n *\n * These options are utilized by `getClient` and `getClientState` to configure and\n * return appropriate client instances that automatically handle authentication\n * updates and configuration changes.\n *\n * @public\n */\nexport interface ClientOptions extends Omit<\n Pick<ClientConfig, AllowedClientConfigKey>,\n 'resource'\n> {\n /**\n * Narrows the inherited `perspective` to exclude stackable perspectives,\n * which are not supported by the SDK.\n */\n 'perspective'?: Exclude<ClientPerspective, readonly unknown[]>\n /**\n * An optional flag to choose between the default client (typically project-level)\n * and the global client ('global'). When set to `'global'`, the global client\n * is used.\n */\n 'scope'?: 'default' | 'global'\n /**\n * A required string indicating the API version for the client.\n */\n 'apiVersion': string\n /**\n * @internal\n */\n '~experimental_resource'?: ClientConfig['~experimental_resource']\n\n /**\n * @internal\n */\n 'resource'?: DocumentResource\n}\n\nconst clientStore = defineStore<ClientStoreState>({\n name: 'clientStore',\n\n getInitialState: (instance) => ({\n clients: {},\n token: getTokenState(instance).getCurrent(),\n }),\n\n initialize(context) {\n const subscription = listenToToken(context)\n const authMethodSubscription = listenToAuthMethod(context)\n return () => {\n subscription.unsubscribe()\n authMethodSubscription.unsubscribe()\n }\n },\n})\n\n/**\n * Updates the client store state when a token is received.\n * @internal\n */\nconst listenToToken = ({instance, state}: StoreContext<ClientStoreState>) => {\n return getTokenState(instance).observable.subscribe((token) => {\n state.set('setTokenAndResetClients', {token, clients: {}})\n })\n}\n\nconst listenToAuthMethod = ({instance, state}: StoreContext<ClientStoreState>) => {\n return getAuthMethodState(instance).observable.subscribe((authMethod) => {\n state.set('setAuthMethod', {authMethod})\n })\n}\n\nconst getClientConfigKey = (options: ClientOptions) => JSON.stringify(pick(options, ...allowedKeys))\n\n/**\n * Retrieves a Sanity client instance configured with the provided options.\n *\n * This function returns a client instance configured for the project or as a\n * global client based on the options provided. It ensures efficient reuse of\n * client instances by returning the same instance for the same options.\n * For automatic handling of authentication token updates, consider using\n * `getClientState`.\n *\n * @public\n */\nexport const getClient = bindActionGlobally(\n clientStore,\n ({state, instance}, options: ClientOptions) => {\n if (!options || typeof options !== 'object') {\n throw new Error(\n 'getClient() requires a configuration object with at least an \"apiVersion\" property. ' +\n 'Example: getClient(instance, { apiVersion: \"2024-11-12\" })',\n )\n }\n\n // Check for disallowed keys\n const providedKeys = Object.keys(options) as (keyof ClientOptions)[]\n const disallowedKeys = providedKeys.filter((key) => !allowedKeys.includes(key))\n\n if (disallowedKeys.length > 0) {\n const listFormatter = new Intl.ListFormat('en', {style: 'long', type: 'conjunction'})\n throw new Error(\n `The client options provided contains unsupported properties: ${listFormatter.format(disallowedKeys)}. ` +\n `Allowed keys are: ${listFormatter.format(allowedKeys)}.`,\n )\n }\n\n const tokenFromState = state.get().token\n const {clients, authMethod} = state.get()\n\n let resource: ClientResource | undefined\n let projectId: string | undefined = options.projectId\n let dataset: string | undefined = options.dataset\n\n if (options.resource) {\n if (isMediaLibraryResource(options.resource)) {\n resource = {type: 'media-library', id: options.resource.mediaLibraryId}\n } else if (isCanvasResource(options.resource)) {\n resource = {type: 'canvas', id: options.resource.canvasId}\n } else if (isDatasetResource(options.resource)) {\n projectId = options.resource.projectId\n dataset = options.resource.dataset\n }\n // temporarily excluding dataset resource as a resource for now. Many of the global API endpoints require vX api version.\n // When ready, remove the above check and uncomment the below check.\n // } else if (isDatasetResource(options.resource)) {\n // resource = {type: 'dataset', id: `${options.resource.projectId}.${options.resource.dataset}`}\n }\n\n const apiHost = options.apiHost ?? instance.config.auth?.apiHost\n\n const effectiveOptions = {\n ...DEFAULT_CLIENT_CONFIG,\n ...((options.scope === 'global' || !projectId || resource) && {useProjectHostname: false}),\n token: authMethod === 'cookie' ? undefined : (tokenFromState ?? undefined),\n ...options,\n ...(projectId && {projectId}),\n ...(dataset && {dataset}),\n ...(apiHost && {apiHost}),\n ...(resource && {'~experimental_resource': resource}),\n } as ClientOptions\n\n // When a MediaLibrary or Canvas resource is provided, don't use projectId/dataset - the client should be \"projectless\"\n // The client code itself will ignore the non-resource config, so we do this to prevent confusing the user.\n // (ref: https://github.com/sanity-io/client/blob/5c23f81f5ab93a53f5b22b39845c867988508d84/src/data/dataMethods.ts#L691)\n // Note: DatasetResource is handled differently - it extracts projectId/dataset from the resource and uses those\n if (options.resource) {\n if (options.projectId || options.dataset) {\n // eslint-disable-next-line no-console\n console.warn(\n 'Both resource and explicit projectId/dataset are provided. The resource will be used and projectId/dataset will be ignored.',\n )\n }\n if (resource) {\n delete effectiveOptions.projectId\n delete effectiveOptions.dataset\n }\n }\n\n if (effectiveOptions.token === null || typeof effectiveOptions.token === 'undefined') {\n delete effectiveOptions.token\n if (authMethod === 'cookie') {\n effectiveOptions.withCredentials = true\n }\n } else {\n delete effectiveOptions.withCredentials\n }\n\n // Don't pass our DocumentResource to createClient - we've already derived projectId/dataset or ~experimental_resource\n const {resource: _omitResource, ...clientConfig} = effectiveOptions\n\n const key = getClientConfigKey(effectiveOptions)\n\n if (clients[key]) return clients[key]\n\n const client = createClient(clientConfig as ClientConfig)\n state.set('addClient', (prev) => ({clients: {...prev.clients, [key]: client}}))\n\n return client\n },\n)\n\n/**\n * Returns a state source for the Sanity client instance.\n *\n * This function provides a subscribable state source that emits updated client\n * instances whenever relevant configurations change (such as authentication tokens).\n * Use this when you need to react to client configuration changes in your application.\n *\n * @public\n */\nexport const getClientState = bindActionGlobally(\n clientStore,\n createStateSourceAction(({instance}, options: ClientOptions) => getClient(instance, options)),\n)\n","import {type SanityClient} from '@sanity/client'\nimport {from, Observable, switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {type DocumentResource} from '../config/sanityConfig'\nimport {type SanityInstance} from '../store/createSanityInstance'\n\nconst API_VERSION = 'vX'\n\n/**\n * Options that all agent actions accept for targeting a specific resource.\n * @alpha\n */\nexport interface AgentResourceOptions {\n resource: DocumentResource\n}\n\n/** @alpha */\nexport type AgentGenerateOptions = Parameters<\n SanityClient['observable']['agent']['action']['generate']\n>[0]\n\n/** @alpha */\nexport type AgentTransformOptions = Parameters<\n SanityClient['observable']['agent']['action']['transform']\n>[0]\n\n/** @alpha */\nexport type AgentTranslateOptions = Parameters<\n SanityClient['observable']['agent']['action']['translate']\n>[0]\n\n/** @alpha */\nexport type AgentPromptOptions = Parameters<SanityClient['agent']['action']['prompt']>[0]\n\n/** @alpha */\nexport type AgentPatchOptions = Parameters<SanityClient['agent']['action']['patch']>[0]\n\n/** @alpha */\nexport type AgentGenerateResult = Awaited<\n ReturnType<SanityClient['observable']['agent']['action']['generate']>\n>\n\n/** @alpha */\nexport type AgentTransformResult = Awaited<\n ReturnType<SanityClient['observable']['agent']['action']['transform']>\n>\n\n/** @alpha */\nexport type AgentTranslateResult = Awaited<\n ReturnType<SanityClient['observable']['agent']['action']['translate']>\n>\n\n/** @alpha */\nexport type AgentPromptResult = Awaited<ReturnType<SanityClient['agent']['action']['prompt']>>\n\n/** @alpha */\nexport type AgentPatchResult = Awaited<ReturnType<SanityClient['agent']['action']['patch']>>\n\n/**\n * Generates a new document using the agent.\n * @param instance - The Sanity instance.\n * @param options - The options for the agent generate action. See the [Agent Actions API](https://www.sanity.io/docs/agent-actions/introduction) for more details.\n * @returns An Observable emitting the result of the agent generate action.\n * @alpha\n */\nexport function agentGenerate(\n instance: SanityInstance,\n options: AgentGenerateOptions & AgentResourceOptions,\n): AgentGenerateResult {\n const {resource, ...agentOptions} = options\n return getClientState(instance, {\n apiVersion: API_VERSION,\n resource,\n }).observable.pipe(switchMap((client) => client.observable.agent.action.generate(agentOptions)))\n}\n\n/**\n * Transforms a document using the agent.\n * @param instance - The Sanity instance.\n * @param options - The options for the agent transform action. See the [Agent Actions API](https://www.sanity.io/docs/agent-actions/introduction) for more details.\n * @returns An Observable emitting the result of the agent transform action.\n * @alpha\n */\nexport function agentTransform(\n instance: SanityInstance,\n options: AgentTransformOptions & AgentResourceOptions,\n): AgentTransformResult {\n const {resource, ...agentOptions} = options\n return getClientState(instance, {\n apiVersion: API_VERSION,\n resource,\n }).observable.pipe(switchMap((client) => client.observable.agent.action.transform(agentOptions)))\n}\n\n/**\n * Translates a document using the agent.\n * @param instance - The Sanity instance.\n * @param options - The options for the agent translate action. See the [Agent Actions API](https://www.sanity.io/docs/agent-actions/introduction) for more details.\n * @returns An Observable emitting the result of the agent translate action.\n * @alpha\n */\nexport function agentTranslate(\n instance: SanityInstance,\n options: AgentTranslateOptions & AgentResourceOptions,\n): AgentTranslateResult {\n const {resource, ...agentOptions} = options\n return getClientState(instance, {\n apiVersion: API_VERSION,\n resource,\n }).observable.pipe(switchMap((client) => client.observable.agent.action.translate(agentOptions)))\n}\n\n/**\n * Prompts the agent using the same instruction template format as the other actions, but returns text or json instead of acting on a document.\n * @param instance - The Sanity instance.\n * @param options - The options for the agent prompt action. See the [Agent Actions API](https://www.sanity.io/docs/agent-actions/introduction) for more details.\n * @returns An Observable emitting the result of the agent prompt action.\n * @alpha\n */\nexport function agentPrompt(\n instance: SanityInstance,\n options: AgentPromptOptions & AgentResourceOptions,\n): Observable<AgentPromptResult> {\n const {resource, ...agentOptions} = options\n return getClientState(instance, {\n apiVersion: API_VERSION,\n resource,\n }).observable.pipe(switchMap((client) => from(client.agent.action.prompt(agentOptions))))\n}\n\n/**\n * Patches a document using the agent.\n * @param instance - The Sanity instance.\n * @param options - The options for the agent patch action. See the [Agent Actions API](https://www.sanity.io/docs/agent-actions/introduction) for more details.\n * @returns An Observable emitting the result of the agent patch action.\n * @alpha\n */\nexport function agentPatch(\n instance: SanityInstance,\n options: AgentPatchOptions & AgentResourceOptions,\n): Observable<AgentPatchResult> {\n const {resource, ...agentOptions} = options\n return getClientState(instance, {\n apiVersion: API_VERSION,\n resource,\n }).observable.pipe(switchMap((client) => from(client.agent.action.patch(agentOptions))))\n}\n","/**\n * Error message returned by the organization verification\n * @public\n */\nexport interface OrgVerificationResult {\n error: string | null\n}\n\n/**\n * Compares a project's actual organization ID with the expected organization ID.\n * @public\n */\nexport function compareProjectOrganization(\n projectId: string,\n projectOrganizationId: string | null | undefined,\n currentDashboardOrgId: string,\n): OrgVerificationResult {\n if (projectOrganizationId !== currentDashboardOrgId) {\n return {\n error:\n `Project ${projectId} belongs to Organization ${projectOrganizationId ?? 'unknown'}, ` +\n `but the Dashboard has Organization ${currentDashboardOrgId} selected`,\n }\n }\n return {error: null}\n}\n","import {omit} from 'lodash-es'\nimport {asapScheduler, EMPTY, firstValueFrom, from, Observable} from 'rxjs'\nimport {\n catchError,\n delay,\n filter,\n first,\n groupBy,\n map,\n mergeMap,\n pairwise,\n startWith,\n switchMap,\n tap,\n} from 'rxjs/operators'\n\nimport {bindActionGlobally, type BoundStoreAction} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {\n createStateSourceAction,\n type SelectorContext,\n type StateSource,\n} from '../store/createStateSourceAction'\nimport {defineStore, type StoreContext} from '../store/defineStore'\nimport {insecureRandomId} from '../utils/ids'\n\ninterface CreateFetcherStoreOptions<TParams extends unknown[], TData> {\n /**\n * A unique name for this store (for devtools)\n */\n name: string\n /**\n * A function that creates the observable that will be used to fetch the data.\n */\n fetcher: (instance: SanityInstance) => (...params: TParams) => Observable<TData>\n /**\n * The function used to convert the params into keys that state related to\n * those params will be stored.\n */\n getKey: (instance: SanityInstance, ...params: TParams) => string\n /**\n * Delay in ms before clearing state after the last subscription is removed.\n * This results in react components suspending again due to no previous state\n * to show.\n */\n stateExpirationDelay?: number\n /**\n * The minimum time (ms) that must elapse since the last fetch for the same key\n */\n fetchThrottleInternal?: number\n}\n\ninterface StoreEntry<TParams extends unknown[], TData> {\n params: TParams\n instance: SanityInstance\n key: string\n data?: TData\n error?: unknown\n subscriptions: string[]\n lastFetchInitiatedAt?: string\n}\n\n/**\n * Internal helper type\n * @public\n */\nexport interface FetcherStoreState<TParams extends unknown[], TData> {\n stateByParams: {[TSerializedKey in string]?: StoreEntry<TParams, TData>}\n error?: unknown\n}\n\n/**\n * Internal helper type\n * @public\n */\nexport interface FetcherStore<TParams extends unknown[], TData> {\n getState: BoundStoreAction<\n FetcherStoreState<TParams, TData>,\n TParams,\n StateSource<TData | undefined>\n >\n resolveState: BoundStoreAction<FetcherStoreState<TParams, TData>, TParams, Promise<TData>>\n}\n\n/**\n * Creates a store from a function that returns an observable that fetches data\n * that supports parameterized state caching.\n *\n * This function creates a resource store keyed by parameter values (using the\n * provided `getKey` function) and returns a state source (via `getState`)\n * that components can subscribe to. When a new subscription is added, and if\n * enough time has passed since the last fetch (controlled by\n * `fetchThrottleInternal`), it invokes the observable factory (via\n * `getObservable`) to fetch fresh data. The data is stored in state and can be\n * accessed reactively.\n *\n * Additionally, the store provides a `resolveState` function that returns a\n * Promise resolving with the next non-undefined value from the state source.\n *\n * State expiration is implemented: after the last subscription for a key is\n * removed, its state is cleared after `stateExpirationDelay` ms, causing\n * components to suspend until fresh data is fetched.\n */\nexport function createFetcherStore<TParams extends unknown[], TData>({\n name,\n fetcher: getObservable,\n getKey,\n fetchThrottleInternal = 1000,\n stateExpirationDelay = 5000,\n}: CreateFetcherStoreOptions<TParams, TData>): FetcherStore<TParams, TData> {\n const store = defineStore<FetcherStoreState<TParams, TData>>({\n name,\n getInitialState: () => ({\n stateByParams: {},\n }),\n initialize: (context) => {\n const subscription = subscribeToSubscriptionsAndFetch(context)\n return () => subscription.unsubscribe()\n },\n })\n\n /**\n * For each key in state.stateByParams we set up a grouped stream.\n * When a subscription is added (i.e. the subscriptions array length increases)\n * and if enough time has elapsed since the last fetch, we update the timestamp\n * and call the factory function for that key.\n */\n const subscribeToSubscriptionsAndFetch = ({\n state,\n }: StoreContext<FetcherStoreState<TParams, TData>>) => {\n return state.observable\n .pipe(\n // Map the state to an array of [serialized, entry] pairs.\n switchMap((s: FetcherStoreState<TParams, TData>) => {\n const entries = Object.entries(s.stateByParams)\n return entries.length > 0 ? from(entries) : EMPTY\n }),\n // Group by the serialized key.\n groupBy(([key]) => key),\n mergeMap((group$) =>\n group$.pipe(\n // Emit an initial value for pairwise comparisons.\n startWith<[string, StoreEntry<TParams, TData> | undefined]>([group$.key, undefined]),\n pairwise(),\n // Trigger only when the subscriptions array grows.\n filter(([[, prevEntry], [, currEntry]]) => {\n const prevSubs = prevEntry?.subscriptions ?? []\n const currSubs = currEntry?.subscriptions ?? []\n return currSubs.length > prevSubs.length\n }),\n map(([, [, currEntry]]) => currEntry),\n\n // Only trigger if we haven't fetched recently.\n filter((entry) => {\n const lastFetch = entry?.lastFetchInitiatedAt\n if (!lastFetch) return true\n return Date.now() - new Date(lastFetch).getTime() >= fetchThrottleInternal\n }),\n switchMap((entry) => {\n // Retrieve params from the entry\n if (!entry) return EMPTY\n\n // Record that a fetch is being initiated.\n state.set('setLastFetchInitiatedAt', (prev: FetcherStoreState<TParams, TData>) => ({\n stateByParams: {\n ...prev.stateByParams,\n [entry.key]: {\n ...entry,\n ...prev.stateByParams[entry.key],\n lastFetchInitiatedAt: new Date().toISOString(),\n },\n },\n }))\n\n const factoryFn = getObservable(entry.instance)\n return factoryFn(...entry.params).pipe(\n // the `createStateSourceAction` util requires the update\n // to\n delay(0, asapScheduler),\n tap((data: TData) =>\n state.set('setData', (prev: FetcherStoreState<TParams, TData>) => ({\n stateByParams: {\n ...prev.stateByParams,\n [entry.key]: {\n ...omit(entry, 'error'),\n ...omit(prev.stateByParams[entry.key], 'error'),\n data,\n },\n },\n })),\n ),\n catchError((error) => {\n state.set('setError', (prev) => ({\n stateByParams: {\n ...prev.stateByParams,\n [entry.key]: {\n ...entry,\n ...prev.stateByParams[entry.key],\n error,\n },\n },\n }))\n\n return EMPTY\n }),\n )\n }),\n ),\n ),\n )\n .subscribe({\n error: (error) => state.set('setError', {error}),\n })\n }\n\n const getState = bindActionGlobally(\n store,\n createStateSourceAction({\n selector: (\n {\n instance,\n state: {stateByParams, error},\n }: SelectorContext<FetcherStoreState<TParams, TData>>,\n ...params: TParams\n ) => {\n if (error) throw error\n const key = getKey(instance, ...params)\n const entry = stateByParams[key]\n if (entry?.error) throw entry.error\n return entry?.data\n },\n onSubscribe: ({instance, state}, ...params: TParams) => {\n const subscriptionId = insecureRandomId()\n const key = getKey(instance, ...params)\n\n state.set('addSubscription', (prev: FetcherStoreState<TParams, TData>) => ({\n stateByParams: {\n ...prev.stateByParams,\n [key]: {\n ...prev.stateByParams[key],\n instance,\n key,\n params: prev.stateByParams[key]?.params || params,\n subscriptions: [...(prev.stateByParams[key]?.subscriptions || []), subscriptionId],\n },\n },\n }))\n\n return () => {\n setTimeout(() => {\n state.set('removeSubscription', (prev: FetcherStoreState<TParams, TData>) => {\n const entry = prev.stateByParams[key]\n if (!entry) return prev\n\n const newSubs = (entry.subscriptions || []).filter((id) => id !== subscriptionId)\n if (newSubs.length === 0) {\n return {stateByParams: omit(prev.stateByParams, key)}\n }\n\n return {\n stateByParams: {\n ...prev.stateByParams,\n [key]: {\n ...entry,\n subscriptions: newSubs,\n },\n },\n }\n })\n }, stateExpirationDelay)\n }\n },\n }),\n )\n\n const resolveState = bindActionGlobally(store, ({instance}, ...params: TParams) =>\n firstValueFrom(getState(instance, ...params).observable.pipe(first((i) => i !== undefined))),\n )\n\n return {getState, resolveState}\n}\n","import {switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {createFetcherStore} from '../utils/createFetcherStore'\n\nconst API_VERSION = 'v2025-02-19'\n\n/** @public */\nexport type ProjectHandle = {\n projectId: string\n}\nconst project = createFetcherStore({\n name: 'Project',\n getKey: (_instance, options: ProjectHandle) => {\n const projectId = options?.projectId\n if (!projectId) {\n throw new Error('A projectId is required to use the project API.')\n }\n return projectId\n },\n fetcher: (instance) => (options: ProjectHandle) => {\n const projectId = options.projectId\n\n return getClientState(instance, {\n apiVersion: API_VERSION,\n scope: 'global',\n projectId,\n }).observable.pipe(switchMap((client) => client.observable.projects.getById(projectId!)))\n },\n})\n\n/** @public */\nexport const getProjectState = project.getState\n/** @public */\nexport const resolveProject = project.resolveState\n","import {bindActionGlobally} from '../store/createActionBinder'\nimport {createStateSourceAction} from '../store/createStateSourceAction'\nimport {authStore} from './authStore'\n\n/**\n * Gets the dashboard organization ID from the auth store\n * @internal\n */\nexport const getDashboardOrganizationId = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {dashboardContext}}) => dashboardContext?.orgId),\n)\n","import {combineLatest, distinctUntilChanged, map, type Observable, of, switchMap} from 'rxjs'\n\nimport {\n compareProjectOrganization,\n type OrgVerificationResult,\n} from '../project/organizationVerification'\nimport {getProjectState} from '../project/project'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {getDashboardOrganizationId} from './dashboardUtils'\n\n/**\n * Creates an observable that emits the organization verification state for a given instance.\n * It combines the dashboard organization ID (from auth context) with the\n * project's actual organization ID (fetched via getProjectState) and compares them.\n * @public\n */\nexport function observeOrganizationVerificationState(\n instance: SanityInstance,\n projectIds: string[],\n): Observable<OrgVerificationResult> {\n // Observable for the dashboard org ID (potentially null)\n const dashboardOrgId$ =\n getDashboardOrganizationId(instance).observable.pipe(distinctUntilChanged())\n\n // Create observables for each project's org ID\n const projectOrgIdObservables = projectIds.map((id) =>\n getProjectState(instance, {projectId: id}).observable.pipe(\n map((project) => ({projectId: id, orgId: project?.organizationId ?? null})),\n // Ensure we only proceed if the orgId is loaded, distinct prevents unnecessary checks\n distinctUntilChanged((prev, curr) => prev.orgId === curr.orgId),\n ),\n )\n\n // Combine observables to get all project org IDs\n const allProjectOrgIds$ =\n projectOrgIdObservables.length > 0 ? combineLatest(projectOrgIdObservables) : of([])\n\n // Combine the sources\n return combineLatest([dashboardOrgId$, allProjectOrgIds$]).pipe(\n switchMap(([dashboardOrgId, projectOrgDataArray]) => {\n // If no dashboard org ID is set, or no project IDs provided, verification isn't applicable/possible\n if (!dashboardOrgId || projectOrgDataArray.length === 0) {\n return of<OrgVerificationResult>({error: null}) // Return success (no error)\n }\n\n // Iterate through all projects and check organization IDs\n for (const projectData of projectOrgDataArray) {\n // If a project doesn't have an orgId, we can't verify, treat as non-blocking for now\n // (Matches original logic where null projectOrgId resulted in {error: null})\n if (!projectData.orgId) {\n continue\n }\n\n // Perform the comparison for the current project\n const result = compareProjectOrganization(\n projectData.projectId,\n projectData.orgId,\n dashboardOrgId,\n )\n\n // If any project fails verification, immediately return the error\n if (result.error) {\n return of(result)\n }\n }\n\n // If all projects passed verification (or had no orgId to check)\n return of<OrgVerificationResult>({error: null})\n }),\n // Only emit when the overall error status actually changes\n distinctUntilChanged((prev, curr) => prev.error === curr.error),\n )\n}\n","import {bindActionGlobally} from '../store/createActionBinder'\nimport {DEFAULT_API_VERSION, REQUEST_TAG_PREFIX} from './authConstants'\nimport {AuthStateType} from './authStateType'\nimport {authStore, type AuthStoreState, type DashboardContext} from './authStore'\nimport {\n createLoggedInAuthState,\n getAuthCode,\n getCleanedUrl,\n getDefaultLocation,\n getTokenFromLocation,\n} from './utils'\n\n/**\n * @public\n */\nexport const handleAuthCallback = bindActionGlobally(\n authStore,\n async ({state}, locationHref: string = getDefaultLocation()) => {\n const {providedToken, callbackUrl, clientFactory, apiHost, storageArea, storageKey} =\n state.get().options\n\n // If a token is provided, no need to handle callback\n if (providedToken) return false\n\n // Don't handle the callback if already in flight.\n const {authState} = state.get()\n if (authState.type === AuthStateType.LOGGING_IN && authState.isExchangingToken) return false\n\n // Prepare the cleaned-up URL early. It will be returned on both success and error if an authCode/token was processed.\n const cleanedUrl = getCleanedUrl(locationHref)\n\n // Check if there is a token in the is in the Dashboard iframe url hash\n const tokenFromUrl = getTokenFromLocation(locationHref)\n if (tokenFromUrl) {\n state.set('setTokenFromUrl', {\n authState: createLoggedInAuthState(tokenFromUrl, null),\n })\n return cleanedUrl\n }\n\n // If there is no matching `authCode` then we can't handle the callback\n const authCode = getAuthCode(callbackUrl, locationHref)\n if (!authCode) return false\n\n // Get the SanityOS dashboard context from the url\n const parsedUrl = new URL(locationHref)\n let dashboardContext: DashboardContext = {}\n try {\n const contextParam = parsedUrl.searchParams.get('_context')\n if (contextParam) {\n const parsedContext = JSON.parse(contextParam)\n if (parsedContext && typeof parsedContext === 'object') {\n delete parsedContext.sid\n dashboardContext = parsedContext\n }\n }\n } catch (err) {\n // If JSON parsing fails, use empty context\n // eslint-disable-next-line no-console\n console.error('Failed to parse dashboard context:', err)\n }\n\n // Otherwise, start the exchange\n state.set('exchangeSessionForToken', {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: true},\n dashboardContext,\n } as Partial<AuthStoreState>)\n\n try {\n const client = clientFactory({\n apiVersion: DEFAULT_API_VERSION,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n useProjectHostname: false,\n useCdn: false,\n ...(apiHost && {apiHost}),\n })\n\n const {token} = await client.request<{token: string; label: string}>({\n method: 'GET',\n uri: '/auth/fetch',\n query: {sid: authCode},\n tag: 'fetch-token',\n })\n\n storageArea?.setItem(storageKey, JSON.stringify({token}))\n state.set('setToken', {authState: createLoggedInAuthState(token, null)})\n\n return cleanedUrl\n } catch (error) {\n state.set('exchangeSessionForTokenError', {authState: {type: AuthStateType.ERROR, error}})\n return cleanedUrl\n }\n },\n)\n","import {bindActionGlobally} from '../store/createActionBinder'\nimport {DEFAULT_API_VERSION, REQUEST_TAG_PREFIX} from './authConstants'\nimport {AuthStateType} from './authStateType'\nimport {authStore} from './authStore'\n\n/**\n * @public\n */\nexport const logout = bindActionGlobally(authStore, async ({state}) => {\n const {clientFactory, apiHost, providedToken, storageArea, storageKey} = state.get().options\n\n // If a token is statically provided, logout does nothing\n if (providedToken) return\n\n const {authState} = state.get()\n\n // If we already have an inflight request, no-op\n if (authState.type === AuthStateType.LOGGED_OUT && authState.isDestroyingSession) return\n const token = authState.type === AuthStateType.LOGGED_IN && authState.token\n\n try {\n if (token) {\n state.set('loggingOut', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: true},\n })\n\n const client = clientFactory({\n token,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n apiVersion: DEFAULT_API_VERSION,\n ...(apiHost && {apiHost}),\n useProjectHostname: false,\n useCdn: false,\n })\n\n await client.request<void>({uri: '/auth/logout', method: 'POST'})\n }\n } finally {\n state.set('logoutSuccess', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n })\n storageArea?.removeItem(storageKey)\n storageArea?.removeItem(`${storageKey}_last_refresh`)\n }\n})\n","import {type StoreContext} from '../../../store/defineStore'\nimport {type ComlinkControllerState} from '../comlinkControllerStore'\n\n/**\n * Calls the destroy method on the controller and resets the controller state.\n * @public\n */\nexport const destroyController = ({state}: StoreContext<ComlinkControllerState>): void => {\n const {controller} = state.get()\n\n if (controller) {\n controller.destroy()\n state.set('destroyController', {\n controller: null,\n channels: new Map(),\n })\n }\n}\n","import {type ChannelInput, type ChannelInstance} from '@sanity/comlink'\nimport {isEqual} from 'lodash-es'\n\nimport {type StoreContext} from '../../../store/defineStore'\nimport {type FrameMessage, type WindowMessage} from '../../types'\nimport {type ComlinkControllerState} from '../comlinkControllerStore'\n\n/**\n * Retrieve or create a channel to be used for communication between\n * an application and the controller.\n * @public\n */\nexport const getOrCreateChannel = (\n {state}: StoreContext<ComlinkControllerState>,\n options: ChannelInput,\n): ChannelInstance<FrameMessage, WindowMessage> => {\n const controller = state.get().controller\n\n if (!controller) {\n throw new Error('Controller must be initialized before using or creating channels')\n }\n\n const channels = state.get().channels\n const existing = channels.get(options.name)\n\n // limit channels to one per name\n if (existing) {\n if (!isEqual(existing.options, options)) {\n throw new Error(`Channel \"${options.name}\" already exists with different options`)\n }\n\n state.set('incrementChannelRefCount', {\n channels: new Map(channels).set(options.name, {\n ...existing,\n refCount: existing.refCount + 1,\n }),\n })\n existing.channel.start()\n return existing.channel\n }\n\n const channel = controller.createChannel(options)\n channel.start()\n state.set('createChannel', {\n channels: new Map(channels).set(options.name, {\n channel,\n options,\n refCount: 1,\n }),\n })\n\n return channel\n}\n","import {type Controller, createController} from '@sanity/comlink'\n\nimport {type StoreContext} from '../../../store/defineStore'\nimport {type ComlinkControllerState} from '../comlinkControllerStore'\nimport {destroyController} from './destroyController'\n\n/**\n * Initializes or fetches a controller to handle communication\n * between an application and iframes.\n * @public\n */\nexport const getOrCreateController = (\n {state, instance}: StoreContext<ComlinkControllerState>,\n targetOrigin: string,\n): Controller => {\n const {controller, controllerOrigin} = state.get()\n if (controller && controllerOrigin === targetOrigin) {\n return controller\n }\n\n // if the target origin has changed, we'll create a new controller,\n // but need to clean up first\n if (controller) {\n destroyController({state, instance, key: undefined})\n }\n\n const newController = createController({targetOrigin})\n state.set('initializeController', {\n controllerOrigin: targetOrigin,\n controller: newController,\n })\n\n return newController\n}\n","import {type StoreContext} from '../../../store/defineStore'\nimport {type ComlinkControllerState} from '../comlinkControllerStore'\n\n/**\n * Signals to the store that the consumer has stopped using the channel\n * @public\n */\nexport const releaseChannel = (\n {state}: StoreContext<ComlinkControllerState>,\n name: string,\n): void => {\n const channels = state.get().channels\n const channelEntry = channels.get(name)\n\n if (channelEntry) {\n const newRefCount = channelEntry.refCount === 0 ? 0 : channelEntry.refCount - 1\n\n if (newRefCount === 0) {\n channelEntry.channel.stop()\n channels.delete(name)\n state.set('releaseChannel', {channels: new Map(channels)})\n } else {\n state.set('releaseChannel', {\n channels: new Map(channels).set(name, {\n ...channelEntry,\n refCount: newRefCount,\n }),\n })\n }\n }\n}\n","import {type ChannelInput, type ChannelInstance, type Controller} from '@sanity/comlink'\n\nimport {bindActionGlobally} from '../../store/createActionBinder'\nimport {defineStore} from '../../store/defineStore'\nimport {type FrameMessage, type WindowMessage} from '../types'\nimport {destroyController as unboundDestroyController} from './actions/destroyController'\nimport {getOrCreateChannel as unboundGetOrCreateChannel} from './actions/getOrCreateChannel'\nimport {getOrCreateController as unboundGetOrCreateController} from './actions/getOrCreateController'\nimport {releaseChannel as unboundReleaseChannel} from './actions/releaseChannel'\n\n/**\n * Individual channel with its relevant options\n * @public\n */\nexport interface ChannelEntry {\n channel: ChannelInstance<FrameMessage, WindowMessage>\n // we store options to ensure that channels remain as unique / consistent as possible\n options: ChannelInput\n // we store refCount to ensure channels remain open only as long as they are in use\n refCount: number\n}\n\n/**\n * Internal state tracking comlink connections\n * @public\n */\nexport interface ComlinkControllerState {\n controller: Controller | null\n controllerOrigin: string | null\n channels: Map<string, ChannelEntry>\n}\n\nexport const comlinkControllerStore = defineStore<ComlinkControllerState>({\n name: 'connectionStore',\n getInitialState: () => {\n const initialState = {\n controller: null,\n controllerOrigin: null,\n channels: new Map(),\n }\n return initialState\n },\n initialize({instance}) {\n return () => {\n // destroying controller also destroys channels\n destroyController(instance)\n }\n },\n})\n\n/**\n * Calls the destroy method on the controller and resets the controller state.\n * @public\n */\nexport const destroyController = bindActionGlobally(\n comlinkControllerStore,\n unboundDestroyController,\n)\n\n/**\n * Retrieve or create a channel to be used for communication between\n * an application and the controller.\n * @public\n */\nexport const getOrCreateChannel = bindActionGlobally(\n comlinkControllerStore,\n unboundGetOrCreateChannel,\n)\n\n/**\n * Initializes or fetches a controller to handle communication\n * between an application and iframes.\n * @public\n */\nexport const getOrCreateController = bindActionGlobally(\n comlinkControllerStore,\n unboundGetOrCreateController,\n)\n\n/**\n * Signals to the store that the consumer has stopped using the channel\n * @public\n */\nexport const releaseChannel = bindActionGlobally(comlinkControllerStore, unboundReleaseChannel)\n","import {createNode, type Node, type NodeInput} from '@sanity/comlink'\nimport {isEqual} from 'lodash-es'\n\nimport {type StoreContext} from '../../../store/defineStore'\nimport {type FrameMessage, type WindowMessage} from '../../types'\nimport {type ComlinkNodeState} from '../comlinkNodeStore'\n\nexport const getOrCreateNode = (\n {state}: StoreContext<ComlinkNodeState>,\n options: NodeInput,\n): Node<WindowMessage, FrameMessage> => {\n const nodes = state.get().nodes\n const existing = nodes.get(options.name)\n\n // limit nodes to one per name\n if (existing) {\n if (!isEqual(existing.options, options)) {\n throw new Error(`Node \"${options.name}\" already exists with different options`)\n }\n\n existing.node.start()\n return existing.node\n }\n\n const node: Node<WindowMessage, FrameMessage> = createNode(options)\n node.start()\n\n // Subscribe to status changes\n const statusUnsub = node.onStatus((status) => {\n const currentNodes = state.get().nodes\n const currentEntry = currentNodes.get(options.name)\n if (!currentEntry) return\n const updatedEntry = {\n ...currentEntry,\n status,\n }\n state.set('updateNodeStatus', {\n nodes: new Map(currentNodes).set(options.name, updatedEntry),\n })\n })\n\n // Set up initial entry with status, error, and statusUnsub\n const entry = {\n node,\n options,\n status: 'idle' as const,\n statusUnsub,\n }\n\n nodes.set(options.name, entry)\n\n state.set('createNode', {nodes})\n\n return node\n}\n","import {type StoreContext} from '../../../store/defineStore'\nimport {type ComlinkNodeState} from '../comlinkNodeStore'\n\nexport const releaseNode = ({state}: StoreContext<ComlinkNodeState>, name: string): void => {\n const nodes = state.get().nodes\n const existing = nodes.get(name)\n\n if (existing) {\n if (existing.statusUnsub) {\n existing.statusUnsub()\n }\n existing.node.stop()\n nodes.delete(name)\n state.set('removeNode', {nodes})\n return\n }\n}\n","import {type Node, type NodeInput, type Status} from '@sanity/comlink'\n\nimport {bindActionGlobally} from '../../store/createActionBinder'\nimport {defineStore} from '../../store/defineStore'\nimport {type FrameMessage, type WindowMessage} from '../types'\nimport {getOrCreateNode as unboundGetOrCreateNode} from './actions/getOrCreateNode'\nimport {releaseNode as unboundReleaseNode} from './actions/releaseNode'\n\n/**\n * Individual node with its relevant options\n * @public\n */\nexport interface NodeEntry {\n node: Node<WindowMessage, FrameMessage>\n // we store options to ensure that channels remain as unique / consistent as possible\n options: NodeInput\n // status of the node connection\n status: Status\n statusUnsub?: () => void\n}\n\n/**\n * Internal state tracking comlink connections\n * @public\n */\nexport interface ComlinkNodeState {\n nodes: Map<string, NodeEntry>\n // Map of node name to set of active subscriber symbols\n subscriptions: Map<string, Set<symbol>>\n}\n\nexport const comlinkNodeStore = defineStore<ComlinkNodeState>({\n name: 'nodeStore',\n getInitialState: () => ({\n nodes: new Map(),\n subscriptions: new Map(),\n }),\n\n initialize({state}) {\n return () => {\n state.get().nodes.forEach(({node}) => {\n node.stop()\n })\n }\n },\n})\n\n/**\n * Signals to the store that the consumer has stopped using the node\n * @public\n */\nexport const releaseNode = bindActionGlobally(comlinkNodeStore, unboundReleaseNode)\n\n/**\n * Retrieve or create a node to be used for communication between\n * an application and the controller -- specifically, a node should\n * be created within a frame / window to communicate with the controller.\n * @public\n */\nexport const getOrCreateNode = bindActionGlobally(comlinkNodeStore, unboundGetOrCreateNode)\n","import {type Node, type NodeInput, type Status} from '@sanity/comlink'\nimport {createSelector} from 'reselect'\n\nimport {bindActionGlobally} from '../../store/createActionBinder'\nimport {createStateSourceAction, type SelectorContext} from '../../store/createStateSourceAction'\nimport {type FrameMessage, type WindowMessage} from '../types'\nimport {\n type ComlinkNodeState,\n comlinkNodeStore,\n getOrCreateNode,\n releaseNode,\n} from './comlinkNodeStore'\n\nconst NODE_RELEASE_TIME = 5000\n\n// Public shape for node state\n/**\n * @public\n */\nexport interface NodeState {\n node: Node<WindowMessage, FrameMessage>\n status: Status | undefined\n}\nconst selectNode = (context: SelectorContext<ComlinkNodeState>, nodeInput: NodeInput) =>\n context.state.nodes.get(nodeInput.name)\n\n/**\n * Provides a subscribable state source for a node by name\n * @param instance - The Sanity instance to get the node state for\n * @param nodeInput - The configuration for the node to get the state for\n\n * @returns A subscribable state source for the node\n * @public\n */\nexport const getNodeState = bindActionGlobally(\n comlinkNodeStore,\n createStateSourceAction<ComlinkNodeState, [NodeInput], NodeState | undefined>({\n selector: createSelector([selectNode], (nodeEntry) => {\n return nodeEntry?.status === 'connected'\n ? {\n node: nodeEntry.node,\n status: nodeEntry.status,\n }\n : undefined\n }),\n onSubscribe: ({state, instance}, nodeInput) => {\n const nodeName = nodeInput.name\n const subscriberId = Symbol('comlink-node-subscriber')\n getOrCreateNode(instance, nodeInput)\n\n // Add subscriber to the set for this node\n let subs = state.get().subscriptions.get(nodeName)\n if (!subs) {\n subs = new Set()\n state.get().subscriptions.set(nodeName, subs)\n }\n subs.add(subscriberId)\n\n return () => {\n setTimeout(() => {\n const activeSubs = state.get().subscriptions.get(nodeName)\n if (activeSubs) {\n activeSubs.delete(subscriberId)\n if (activeSubs.size === 0) {\n state.get().subscriptions.delete(nodeName)\n releaseNode(instance, nodeName)\n }\n }\n }, NODE_RELEASE_TIME)\n }\n },\n }),\n)\n","import {type DocumentHandle, type DocumentTypeHandle, type ResourceHandle} from './sanityConfig'\n\n/**\n * Creates or validates a `DocumentHandle` object.\n * Ensures the provided object conforms to the `DocumentHandle` interface.\n * @param handle - The object containing document identification properties.\n * @returns The validated `DocumentHandle` object.\n * @public\n */\nexport function createDocumentHandle<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n handle: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): DocumentHandle<TDocumentType, TDataset, TProjectId> {\n return handle\n}\n\n/**\n * Creates or validates a `DocumentTypeHandle` object.\n * Ensures the provided object conforms to the `DocumentTypeHandle` interface.\n * @param handle - The object containing document type identification properties.\n * @returns The validated `DocumentTypeHandle` object.\n * @public\n */\nexport function createDocumentTypeHandle<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n handle: DocumentTypeHandle<TDocumentType, TDataset, TProjectId>,\n): DocumentTypeHandle<TDocumentType, TDataset, TProjectId> {\n return handle\n}\n\n/**\n * Creates or validates a `ResourceHandle` object.\n * Ensures the provided object conforms to the `ResourceHandle` interface.\n * @param handle - The object containing resource identification properties.\n * @returns The validated `ResourceHandle` object.\n * @public\n */\nexport function createResourceHandle<\n TDataset extends string = string,\n TProjectId extends string = string,\n>(handle: ResourceHandle<TProjectId, TDataset>): ResourceHandle<TProjectId, TDataset> {\n return handle\n}\n","/**\n * Public API for configuring SDK logging\n *\n * @module loggingConfig\n */\n\nimport {configureLogging as _configureLogging, type LoggerConfig} from '../utils/logger'\n\n/**\n * Configure logging for the Sanity SDK\n *\n * This function allows you to control what logs are output by the SDK,\n * making it easier to debug issues in development or production.\n *\n * @remarks\n * **Zero-Config via Environment Variable (Recommended):**\n *\n * The SDK automatically reads the `DEBUG` environment variable, making it\n * easy to enable logging without code changes:\n *\n * ```bash\n * # Enable all SDK logging at debug level\n * DEBUG=sanity:* npm start\n *\n * # Enable specific namespaces\n * DEBUG=sanity:auth,sanity:document npm start\n *\n * # Enable trace level for all namespaces\n * DEBUG=sanity:trace:* npm start\n *\n * # Enable internal/maintainer logs\n * DEBUG=sanity:*:internal npm start\n * ```\n *\n * This matches the pattern used by Sanity CLI and Studio, making it familiar\n * and easy for support teams to help troubleshoot issues.\n *\n * **Programmatic Configuration (Advanced):**\n *\n * For more control (custom handlers, dynamic configuration), call this function\n * explicitly. Programmatic configuration overrides environment variables.\n *\n * **For Application Developers:**\n * Use `info`, `warn`, or `error` levels to see high-level SDK activity\n * without being overwhelmed by internal details.\n *\n * **For SDK Maintainers:**\n * Use `debug` or `trace` levels with `internal: true` to see detailed\n * information about store operations, RxJS streams, and state transitions.\n *\n * **Instance Context:**\n * Logs automatically include instance information (projectId, dataset, instanceId)\n * when available, making it easier to debug multi-instance scenarios:\n * ```\n * [INFO] [auth] [project:abc] [dataset:production] User logged in\n * ```\n *\n * **Available Namespaces:**\n * - `sdk` - SDK initialization, configuration, and lifecycle\n * - `auth` - Authentication and authorization (when instrumented in the future)\n * - And more as logging is added to modules\n *\n * @example Zero-config via environment variable (recommended for debugging)\n * ```bash\n * # Just set DEBUG and run your app - no code changes needed!\n * DEBUG=sanity:* npm start\n * ```\n *\n * @example Programmatic configuration (application developer)\n * ```ts\n * import {configureLogging} from '@sanity/sdk'\n *\n * // Log warnings and errors for auth and document operations\n * configureLogging({\n * level: 'warn',\n * namespaces: ['auth', 'document']\n * })\n * ```\n *\n * @example Programmatic configuration (SDK maintainer)\n * ```ts\n * import {configureLogging} from '@sanity/sdk'\n *\n * // Enable all logs including internal traces\n * configureLogging({\n * level: 'trace',\n * namespaces: ['*'],\n * internal: true\n * })\n * ```\n *\n * @example Custom handler (for testing)\n * ```ts\n * import {configureLogging} from '@sanity/sdk'\n *\n * const logs: string[] = []\n * configureLogging({\n * level: 'info',\n * namespaces: ['*'],\n * handler: {\n * error: (msg) => logs.push(msg),\n * warn: (msg) => logs.push(msg),\n * info: (msg) => logs.push(msg),\n * debug: (msg) => logs.push(msg),\n * trace: (msg) => logs.push(msg),\n * }\n * })\n * ```\n *\n * @public\n */\nexport function configureLogging(config: LoggerConfig): void {\n _configureLogging(config)\n\n // Always log configuration (bypasses namespace filtering)\n // This ensures users see the message regardless of which namespaces they enable\n const configLevel = config.level || 'warn'\n const shouldLog = ['info', 'debug', 'trace'].includes(configLevel) || configLevel === 'warn'\n\n if (shouldLog && config.handler?.info) {\n config.handler.info(`[${new Date().toISOString()}] [INFO] [sdk] Logging configured`, {\n level: configLevel,\n namespaces: config.namespaces || [],\n internal: config.internal || false,\n source: 'programmatic',\n })\n } else if (shouldLog) {\n // eslint-disable-next-line no-console\n console.info(`[${new Date().toISOString()}] [INFO] [sdk] Logging configured`, {\n level: configLevel,\n namespaces: config.namespaces || [],\n internal: config.internal || false,\n source: 'programmatic',\n })\n }\n}\n\n/**\n * Re-export types for public API\n * @public\n */\nexport type {\n InstanceContext,\n LogContext,\n Logger,\n LoggerConfig,\n LogLevel,\n LogNamespace,\n} from '../utils/logger'\n","import {switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {createFetcherStore} from '../utils/createFetcherStore'\n\nconst API_VERSION = 'v2025-02-19'\n\n/** @public */\nexport const datasets = createFetcherStore({\n name: 'Datasets',\n getKey: (_instance, options: {projectId: string}) => {\n return options.projectId\n },\n fetcher: (instance) => (options: {projectId: string}) => {\n return getClientState(instance, {\n apiVersion: API_VERSION,\n projectId: options.projectId,\n useProjectHostname: true,\n }).observable.pipe(switchMap((client) => client.observable.datasets.list()))\n },\n})\n\n/** @public */\nexport const getDatasetsState = datasets.getState\n\n/** @public */\nexport const resolveDatasets = datasets.resolveState\n","import {SanityEncoder} from '@sanity/mutate'\nimport {type PatchMutation as SanityMutatePatchMutation} from '@sanity/mutate/_unstable_store'\nimport {type PatchMutation, type PatchOperations, type SanityDocument} from '@sanity/types'\n\nimport {type DocumentHandle, type DocumentTypeHandle} from '../config/sanityConfig'\nimport {getPublishedId} from '../utils/ids'\n\nconst isSanityMutatePatch = (value: unknown): value is SanityMutatePatchMutation => {\n if (typeof value !== 'object' || !value) return false\n if (!('type' in value) || typeof value.type !== 'string' || value.type !== 'patch') return false\n if (!('id' in value) || typeof value.id !== 'string') return false\n if (!('patches' in value) || !Array.isArray(value.patches)) return false\n return true\n}\n\n/**\n * Represents an action to create a new document.\n * Specifies the document type and optionally a document ID (which will be treated as the published ID).\n * @beta\n */\nexport interface CreateDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentTypeHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.create'\n /**\n * Optional initial field values for the document.\n * These values will be set when the document is created.\n * System fields (_id, _type, _rev, _createdAt, _updatedAt) are omitted as they are set automatically.\n */\n initialValue?: Partial<\n Omit<SanityDocument, '_id' | '_type' | '_rev' | '_createdAt' | '_updatedAt'>\n >\n}\n\n/**\n * Represents an action to delete an existing document.\n * Requires the full document handle including the document ID.\n * @beta\n */\nexport interface DeleteDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.delete'\n}\n\n/**\n * Represents an action to edit an existing document using patches.\n * Requires the full document handle and an array of patch operations.\n * @beta\n */\nexport interface EditDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.edit'\n patches?: PatchOperations[]\n}\n\n/**\n * Represents an action to publish the draft version of a document.\n * Requires the full document handle.\n * @beta\n */\nexport interface PublishDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.publish'\n}\n\n/**\n * Represents an action to unpublish a document, moving its published content to a draft.\n * Requires the full document handle.\n * @beta\n */\nexport interface UnpublishDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.unpublish'\n}\n\n/**\n * Represents an action to discard the draft changes of a document.\n * Requires the full document handle.\n * @beta\n */\nexport interface DiscardDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.discard'\n}\n\n/**\n * Union type representing all possible document actions within the SDK.\n * @beta\n */\nexport type DocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> =\n | CreateDocumentAction<TDocumentType, TDataset, TProjectId>\n | DeleteDocumentAction<TDocumentType, TDataset, TProjectId>\n | EditDocumentAction<TDocumentType, TDataset, TProjectId>\n | PublishDocumentAction<TDocumentType, TDataset, TProjectId>\n | UnpublishDocumentAction<TDocumentType, TDataset, TProjectId>\n | DiscardDocumentAction<TDocumentType, TDataset, TProjectId>\n\n/**\n * Creates a `CreateDocumentAction` object.\n * @param doc - A handle identifying the document type, dataset, and project. An optional `documentId` can be provided.\n * @param initialValue - Optional initial field values for the document. (System fields are omitted as they are set automatically.)\n * @returns A `CreateDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function createDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentTypeHandle<TDocumentType, TDataset, TProjectId>,\n initialValue?: Partial<\n Omit<SanityDocument, '_id' | '_type' | '_rev' | '_createdAt' | '_updatedAt'>\n >,\n): CreateDocumentAction<TDocumentType, TDataset, TProjectId> {\n return {\n type: 'document.create',\n ...doc,\n ...(doc.documentId && {\n documentId: doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId),\n }),\n ...(initialValue && {initialValue}),\n }\n}\n\n/**\n * Creates a `DeleteDocumentAction` object.\n * @param doc - A handle uniquely identifying the document to be deleted.\n * @returns A `DeleteDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function deleteDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): DeleteDocumentAction<TDocumentType, TDataset, TProjectId> {\n return {\n type: 'document.delete',\n ...doc,\n documentId: doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId),\n }\n}\n\nfunction convertSanityMutatePatch(\n sanityPatchMutation: SanityMutatePatchMutation,\n): EditDocumentAction['patches'] {\n const encoded = SanityEncoder.encode(sanityPatchMutation) as PatchMutation[]\n return encoded.map((i) => {\n const copy: PatchOperations = {...i.patch}\n if ('id' in copy) delete copy.id\n return copy\n })\n}\n\n/**\n * Creates an `EditDocumentAction` object with patches for modifying a document.\n * Accepts patches in either the standard `PatchOperations` format or as a `SanityMutatePatchMutation` from `@sanity/mutate`.\n *\n * @param doc - A handle uniquely identifying the document to be edited.\n * @param sanityMutatePatch - A patch mutation object from `@sanity/mutate`.\n * @returns An `EditDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function editDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n sanityMutatePatch: SanityMutatePatchMutation,\n): EditDocumentAction<TDocumentType, TDataset, TProjectId>\n/**\n * Creates an `EditDocumentAction` object with patches for modifying a document.\n *\n * @param doc - A handle uniquely identifying the document to be edited.\n * @param patches - A single patch operation or an array of patch operations.\n * @returns An `EditDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function editDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n patches?: PatchOperations | PatchOperations[],\n): EditDocumentAction<TDocumentType, TDataset, TProjectId>\n/**\n * Creates an `EditDocumentAction` object with patches for modifying a document.\n * This is the implementation signature and handles the different patch input types.\n *\n * @param doc - A handle uniquely identifying the document to be edited.\n * @param patches - Patches in various formats (`PatchOperations`, `PatchOperations[]`, or `SanityMutatePatchMutation`).\n * @returns An `EditDocumentAction` object ready for dispatch.\n */\nexport function editDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n patches?: PatchOperations | PatchOperations[] | SanityMutatePatchMutation,\n): EditDocumentAction<TDocumentType, TDataset, TProjectId> {\n const documentId = doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId)\n\n if (isSanityMutatePatch(patches)) {\n const converted = convertSanityMutatePatch(patches) ?? []\n return {\n ...doc,\n type: 'document.edit',\n documentId,\n patches: converted,\n }\n }\n\n return {\n ...doc,\n type: 'document.edit',\n documentId,\n ...(patches && {patches: Array.isArray(patches) ? patches : [patches]}),\n }\n}\n\n/**\n * Creates a `PublishDocumentAction` object.\n * @param doc - A handle uniquely identifying the document to be published.\n * @returns A `PublishDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function publishDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): PublishDocumentAction<TDocumentType, TDataset, TProjectId> {\n return {\n type: 'document.publish',\n ...doc,\n documentId: doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId),\n }\n}\n\n/**\n * Creates an `UnpublishDocumentAction` object.\n * @param doc - A handle uniquely identifying the document to be unpublished.\n * @returns An `UnpublishDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function unpublishDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): UnpublishDocumentAction<TDocumentType, TDataset, TProjectId> {\n return {\n type: 'document.unpublish',\n ...doc,\n documentId: doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId),\n }\n}\n\n/**\n * Creates a `DiscardDocumentAction` object.\n * @param doc - A handle uniquely identifying the document whose draft changes are to be discarded.\n * @returns A `DiscardDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function discardDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): DiscardDocumentAction<TDocumentType, TDataset, TProjectId> {\n return {\n type: 'document.discard',\n ...doc,\n documentId: doc.liveEdit ? doc.documentId : getPublishedId(doc.documentId),\n }\n}\n","/**\n * When a document has no more subscribers, its state is cleaned up and removed\n * from the store. A delay used to prevent re-creating resources when the last\n * subscriber is removed quickly before another one is added. This is helpful\n * when used in a frontend where components may suspend or transition to\n * different views quickly.\n */\nexport const DOCUMENT_STATE_CLEAR_DELAY = 1000\nexport const INITIAL_OUTGOING_THROTTLE_TIME = 1000\nexport const API_VERSION = 'v2025-05-06'\n","import {applyPatches, parsePatch} from '@sanity/diff-match-patch'\nimport {getIndexForKey, jsonMatch, slicePath, stringifyPath} from '@sanity/json-match'\nimport {\n type IndexTuple,\n type InsertPatch,\n isKeyedObject,\n isKeySegment,\n type PathSegment,\n} from '@sanity/types'\n\ntype SingleValuePath = Exclude<PathSegment, IndexTuple>[]\n\ntype ToNumber<TInput extends string> = TInput extends `${infer TNumber extends number}`\n ? TNumber\n : TInput\n\n/**\n * Parse a single \"segment\" that may include bracket parts.\n *\n * For example, the literal\n *\n * ```\n * \"friends[0][1]\"\n * ```\n *\n * is parsed as:\n *\n * ```\n * [\"friends\", 0, 1]\n * ```\n */\ntype ParseSegment<TInput extends string> = TInput extends `${infer TProp}[${infer TRest}`\n ? TProp extends ''\n ? [...ParseBracket<`[${TRest}`>] // no property name before '['\n : [TProp, ...ParseBracket<`[${TRest}`>]\n : TInput extends ''\n ? []\n : [TInput]\n\n/**\n * Parse one or more bracketed parts from a segment.\n *\n * It recursively \"peels off\" a bracketed part and then continues.\n *\n * For example, given the string:\n *\n * ```\n * \"[0][foo]\"\n * ```\n *\n * it produces:\n *\n * ```\n * [ToNumber<\"0\">, \"foo\"]\n * ```\n */\ntype ParseBracket<TInput extends string> = TInput extends `[${infer TPart}]${infer TRest}`\n ? [ToNumber<TPart>, ...ParseSegment<TRest>]\n : [] // no leading bracket → end of this segment\n\n/**\n * Split the entire path string on dots \"outside\" of any brackets.\n *\n * For example:\n * ```\n * \"friends[0].name\"\n * ```\n *\n * becomes:\n *\n * ```\n * [...ParseSegment<\"friends[0]\">, ...ParseSegment<\"name\">]\n * ```\n *\n * (We use a simple recursion that splits on the first dot.)\n */\ntype PathParts<TPath extends string> = TPath extends `${infer Head}.${infer Tail}`\n ? [Head, ...PathParts<Tail>]\n : TPath extends ''\n ? []\n : [TPath]\n\n/**\n * Given a type T and an array of \"access keys\" Parts, recursively index into T.\n *\n * If a part is a key, it looks up that property.\n * If T is an array and the part is a number, it \"indexes\" into the element type.\n */\ntype DeepGet<TValue, TPath extends readonly (string | number)[]> = TPath extends []\n ? TValue\n : TPath extends readonly [infer THead, ...infer TTail]\n ? // Handle traversing into optional properties\n DeepGet<\n TValue extends undefined | null\n ? undefined // Stop traversal if current value is null/undefined\n : THead extends keyof TValue // Access property if key exists\n ? TValue[THead]\n : // Handle array indexing\n THead extends number\n ? TValue extends readonly (infer TElement)[]\n ? TElement | undefined // Array element or undefined if out of bounds\n : undefined // Cannot index non-array with number\n : undefined, // Key/index doesn't exist\n TTail extends readonly (string | number)[] ? TTail : [] // Continue with the rest of the path\n >\n : never // Should be unreachable\n\n/**\n * Given a document type TDocument and a JSON Match path string TPath,\n * compute the type found at that path.\n * @beta\n */\nexport type JsonMatch<TDocument, TPath extends string> = DeepGet<TDocument, PathParts<TPath>>\n\n// this is a similar array key to the studio:\n// https://github.com/sanity-io/sanity/blob/v3.74.1/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/createProtoArrayValue.ts\nfunction generateArrayKey(length: number = 12): string {\n // Each byte gives two hex characters, so generate enough bytes.\n const numBytes = Math.ceil(length / 2)\n const bytes = crypto.getRandomValues(new Uint8Array(numBytes))\n // Convert each byte to a 2-digit hex string and join them.\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0'))\n .join('')\n .slice(0, length)\n}\n\nfunction memoize<TFunction extends (input: unknown) => unknown>(fn: TFunction): TFunction {\n const cache = new WeakMap<object, unknown>()\n return ((input) => {\n if (!input || typeof input !== 'object') return fn(input)\n\n const cached = cache.get(input)\n if (cached) return cached\n\n const result = fn(input)\n cache.set(input, result)\n return result\n }) as TFunction\n}\n\n/**\n * Recursively traverse a value. When an array is encountered, ensure that\n * each object item has a _key property. Memoized such that sub-objects that\n * have not changed aren't re-computed.\n */\nexport const ensureArrayKeysDeep = memoize(<R>(input: R): R => {\n if (!input || typeof input !== 'object') return input\n\n if (Array.isArray(input)) {\n // if the array is empty then just return the input\n if (!input.length) return input\n const first = input[0]\n // if the first input in the array isn't an object (null is allowed) then\n // assume that this is an array of primitives, just return the input\n if (typeof first !== 'object') return input\n\n // if all the items already have a key, then return the input\n if (input.every(isKeyedObject)) return input\n\n // otherwise return a new object item with a new key\n return input.map((item: unknown) => {\n if (!item || typeof item !== 'object') return item\n if (isKeyedObject(item)) return ensureArrayKeysDeep(item)\n const next = ensureArrayKeysDeep(item)\n return {...next, _key: generateArrayKey()}\n }) as R\n }\n\n const entries = Object.entries(input).map(([key, value]) => [key, ensureArrayKeysDeep(value)])\n\n if (entries.every(([key, value]) => input[key as keyof typeof input] === value)) {\n return input\n }\n\n return Object.fromEntries(entries) as R\n})\n\n/**\n * Given an input object and a record of path expressions to values, this\n * function will set each match with the given value.\n *\n * ```js\n * const output = set(\n * {name: {first: 'initial', last: 'initial'}},\n * {'name.first': 'changed'}\n * );\n *\n * // { name: { first: 'changed', last: 'initial' } }\n * console.log(output);\n * ```\n */\nexport function set<R>(input: unknown, pathExpressionValues: Record<string, unknown>): R\nexport function set(input: unknown, pathExpressionValues: Record<string, unknown>): unknown {\n const result = Object.entries(pathExpressionValues)\n .flatMap(([pathExpression, replacementValue]) =>\n Array.from(jsonMatch(input, pathExpression)).map((matchEntry) => ({\n ...matchEntry,\n replacementValue,\n })),\n )\n .reduce((acc, {path, replacementValue}) => setDeep(acc, path, replacementValue), input)\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object and a record of path expressions to values, this\n * function will set each match with the given value **if the value at the current\n * path is missing** (i.e. `null` or `undefined`).\n *\n * ```js\n * const output = setIfMissing(\n * {items: [null, 'initial']},\n * {'items[:]': 'changed'}\n * );\n *\n * // { items: ['changed', 'initial'] }\n * console.log(output);\n * ```\n */\nexport function setIfMissing<R>(input: unknown, pathExpressionValues: Record<string, unknown>): R\nexport function setIfMissing(\n input: unknown,\n pathExpressionValues: Record<string, unknown>,\n): unknown {\n const result = Object.entries(pathExpressionValues)\n .flatMap(([pathExpression, replacementValue]) => {\n return Array.from(jsonMatch(input, pathExpression)).map((matchEntry) => ({\n ...matchEntry,\n replacementValue,\n }))\n })\n .filter((matchEntry) => matchEntry.value === null || matchEntry.value === undefined)\n .reduce((acc, {path, replacementValue}) => setDeep(acc, path, replacementValue), input)\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object and an array of path expressions, this function will\n * remove each match from the input object.\n *\n * ```js\n * const output = unset(\n * {name: {first: 'one', last: 'two'}},\n * ['name.last']\n * );\n *\n * // { name: { first: 'one' } }\n * console.log(output);\n * ```\n */\nexport function unset<R>(input: unknown, pathExpressions: string[]): R\nexport function unset(input: unknown, pathExpressions: string[]): unknown {\n const result = pathExpressions\n .flatMap((pathExpression) => Array.from(jsonMatch(input, pathExpression)))\n // ensure that we remove in the reverse order the paths were found in\n // this is necessary for array unsets so the indexes don't change as we unset\n .reverse()\n .reduce((acc, {path}) => unsetDeep(acc, path), input)\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object, a path expression (inside the insert patch object), and an array of items,\n * this function will insert or replace the matched items.\n *\n * **Insert before:**\n *\n * ```js\n * const input = {some: {array: ['a', 'b', 'c']}}\n * const output = insert(\n * input,\n * {\n * before: 'some.array[1]',\n * items: ['!']\n * }\n * );\n * // { some: { array: ['a', '!', 'b', 'c'] } }\n * console.log(output);\n * ```\n *\n * **Insert before with negative index (append):**\n *\n * ```js\n * const input = {some: {array: ['a', 'b', 'c']}}\n * const output = insert(\n * input,\n * {\n * before: 'some.array[-1]',\n * items: ['!']\n * }\n * );\n * // { some: { array: ['a', 'b', 'c', '!'] } }\n * console.log(output);\n * ```\n *\n * **Insert after:**\n *\n * ```js\n * const input = {some: {array: ['a', 'b', 'c']}}\n * const output = insert(\n * input,\n * {\n * after: 'some.array[1]',\n * items: ['!']\n * }\n * );\n * // { some: { array: ['a', 'b', '!', 'c'] } }\n * console.log(output);\n * ```\n *\n * **Replace:**\n *\n * ```js\n * const output = insert(\n * { some: { array: ['a', 'b', 'c'] } },\n * {\n * replace: 'some.array[1]',\n * items: ['!']\n * }\n * );\n * // { some: { array: ['a', '!', 'c'] } }\n * console.log(output);\n * ```\n *\n * **Replace many:**\n *\n * ```js\n * const input = {some: {array: ['a', 'b', 'c', 'd']}}\n * const output = insert(\n * input,\n * {\n * replace: 'some.array[1:3]',\n * items: ['!', '?']\n * }\n * );\n * // { some: { array: ['a', '!', '?', 'd'] } }\n * console.log(output);\n * ```\n */\nexport function insert<R>(input: unknown, insertPatch: InsertPatch): R\nexport function insert(input: unknown, {items, ...insertPatch}: InsertPatch): unknown {\n let operation\n let pathExpression\n\n // behavior observed from content-lake when inserting:\n // 1. if the operation is before, out of all the matches, it will use the\n // insert the items before the first match that appears in the array\n // 2. if the operation is after, it will insert the items after the first\n // match that appears in the array\n // 3. if the operation is replace, then insert the items before the first\n // match and then delete the rest\n if ('before' in insertPatch) {\n operation = 'before' as const\n pathExpression = insertPatch.before\n } else if ('after' in insertPatch) {\n operation = 'after' as const\n pathExpression = insertPatch.after\n } else if ('replace' in insertPatch) {\n operation = 'replace' as const\n pathExpression = insertPatch.replace\n }\n if (!operation) return input\n if (typeof pathExpression !== 'string') return input\n\n // in order to do an insert patch, you need to provide at least one path segment\n if (!pathExpression.length) return input\n\n const arrayPath = slicePath(pathExpression, 0, -1)\n const positionPath = slicePath(pathExpression, -1)\n\n let result = input\n\n for (const {path, value} of jsonMatch(input, arrayPath)) {\n if (!Array.isArray(value)) continue\n let arr = value\n\n switch (operation) {\n case 'replace': {\n const indexesToRemove = new Set<number>()\n let position = Infinity\n\n for (const itemMatch of jsonMatch(arr, positionPath)) {\n // there should only be one path segment for an insert patch, invalid otherwise\n if (itemMatch.path.length !== 1) continue\n const [segment] = itemMatch.path\n if (typeof segment === 'string') continue\n\n let index\n\n if (typeof segment === 'number') index = segment\n if (typeof index === 'number' && index < 0) index = arr.length + index\n if (isKeySegment(segment)) index = getIndexForKey(arr, segment._key)\n if (typeof index !== 'number') continue\n if (index < 0) index = arr.length + index\n\n indexesToRemove.add(index)\n if (index < position) position = index\n }\n\n if (position === Infinity) continue\n\n // remove all other indexes\n arr = arr\n .map((item, index) => ({item, index}))\n .filter(({index}) => !indexesToRemove.has(index))\n .map(({item}) => item)\n\n // insert at the min index\n arr = [...arr.slice(0, position), ...items, ...arr.slice(position, arr.length)]\n\n break\n }\n case 'before': {\n let position = Infinity\n\n for (const itemMatch of jsonMatch(arr, positionPath)) {\n if (itemMatch.path.length !== 1) continue\n const [segment] = itemMatch.path\n\n if (typeof segment === 'string') continue\n\n let index\n\n if (typeof segment === 'number') index = segment\n if (typeof index === 'number' && index < 0) index = arr.length + index\n if (isKeySegment(segment)) index = getIndexForKey(arr, segment._key)\n if (typeof index !== 'number') continue\n if (index < 0) index = arr.length - index\n if (index < position) position = index\n }\n\n if (position === Infinity) continue\n\n arr = [...arr.slice(0, position), ...items, ...arr.slice(position, arr.length)]\n\n break\n }\n case 'after': {\n let position = -Infinity\n\n for (const itemMatch of jsonMatch(arr, positionPath)) {\n if (itemMatch.path.length !== 1) continue\n const [segment] = itemMatch.path\n\n if (typeof segment === 'string') continue\n\n let index\n\n if (typeof segment === 'number') index = segment\n if (typeof index === 'number' && index < 0) index = arr.length + index\n if (isKeySegment(segment)) index = getIndexForKey(arr, segment._key)\n if (typeof index !== 'number') continue\n if (index > position) position = index\n }\n\n if (position === -Infinity) continue\n\n arr = [...arr.slice(0, position + 1), ...items, ...arr.slice(position + 1, arr.length)]\n\n break\n }\n\n default: {\n continue\n }\n }\n\n result = setDeep(result, path, arr)\n }\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object and a record of path expressions to numeric values,\n * this function will increment each match with the given value.\n *\n * ```js\n * const output = inc(\n * {foo: {first: 3, second: 4.5}},\n * {'foo.first': 3, 'foo.second': 4}\n * );\n *\n * // { foo: { first: 6, second: 8.5 } }\n * console.log(output);\n * ```\n */\nexport function inc<R>(input: unknown, pathExpressionValues: Record<string, number>): R\nexport function inc(input: unknown, pathExpressionValues: Record<string, number>): unknown {\n const result = Object.entries(pathExpressionValues)\n .flatMap(([pathExpression, valueToAdd]) =>\n Array.from(jsonMatch(input, pathExpression)).map((matchEntry) => ({\n ...matchEntry,\n valueToAdd,\n })),\n )\n .filter(\n <T extends {value: unknown}>(matchEntry: T): matchEntry is T & {value: number} =>\n typeof matchEntry.value === 'number',\n )\n .reduce((acc, {path, value, valueToAdd}) => setDeep(acc, path, value + valueToAdd), input)\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object and a record of path expressions to numeric values,\n * this function will decrement each match with the given value.\n *\n * ```js\n * const output = dec(\n * {foo: {first: 3, second: 4.5}},\n * {'foo.first': 3, 'foo.second': 4}\n * );\n *\n * // { foo: { first: 0, second: 0.5 } }\n * console.log(output);\n * ```\n */\nexport function dec<R>(input: unknown, pathExpressionValues: Record<string, number>): R\nexport function dec(input: unknown, pathExpressionValues: Record<string, number>): unknown {\n const result = inc(\n input,\n Object.fromEntries(\n Object.entries(pathExpressionValues)\n .filter(([, value]) => typeof value === 'number')\n .map(([key, value]) => [key, -value]),\n ),\n )\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object and a record of paths to [diff match patches][0], this\n * function will apply the diff match patch for the string at each match.\n *\n * [0]: https://www.sanity.io/docs/http-patches#aTbJhlAJ\n *\n * ```js\n * const output = diffMatchPatch(\n * {foo: 'the quick brown fox'},\n * {'foo': '@@ -13,7 +13,7 @@\\n own \\n-fox\\n+cat\\n'}\n * );\n *\n * // { foo: 'the quick brown cat' }\n * console.log(output);\n * ```\n */\nexport function diffMatchPatch<R>(input: unknown, pathExpressionValues: Record<string, string>): R\nexport function diffMatchPatch(\n input: unknown,\n pathExpressionValues: Record<string, string>,\n): unknown {\n const result = Object.entries(pathExpressionValues)\n .flatMap(([pathExpression, dmp]) =>\n Array.from(jsonMatch(input, pathExpression)).map((m) => ({...m, dmp})),\n )\n .filter((i) => i.value !== undefined)\n .map(({path, value, dmp}) => {\n if (typeof value !== 'string') {\n throw new Error(\n `Can't diff-match-patch \\`${JSON.stringify(value)}\\` at path \\`${stringifyPath(path)}\\`, because it is not a string`,\n )\n }\n\n const [nextValue] = applyPatches(parsePatch(dmp), value)\n return {path, value: nextValue}\n })\n .reduce((acc, {path, value}) => setDeep(acc, path, value), input)\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Simply checks if the given document input has a `_rev` that matches the given\n * `revisionId` and throws otherwise.\n *\n * (No code example provided.)\n */\nexport function ifRevisionID<R>(input: unknown, revisionId: string): R\nexport function ifRevisionID(input: unknown, revisionId: string): unknown {\n const inputRev =\n typeof input === 'object' && !!input && '_rev' in input && typeof input._rev === 'string'\n ? input._rev\n : undefined\n\n if (typeof inputRev !== 'string') {\n throw new Error(`Patch specified \\`ifRevisionID\\` but could not find document's revision ID.`)\n }\n\n if (revisionId !== inputRev) {\n throw new Error(\n `Patch's \\`ifRevisionID\\` \\`${revisionId}\\` does not match document's revision ID \\`${inputRev}\\``,\n )\n }\n\n return input\n}\n\n/**\n * Gets a value deep inside of an object given a path. If the path does not\n * exist in the object, `undefined` will be returned.\n */\nexport function getDeep<R>(input: unknown, path: SingleValuePath): R\nexport function getDeep(input: unknown, path: SingleValuePath): unknown {\n const [currentSegment, ...restOfPath] = path\n if (currentSegment === undefined) return input\n if (typeof input !== 'object' || input === null) return undefined\n\n let key\n if (isKeySegment(currentSegment)) {\n key = getIndexForKey(input, currentSegment._key)\n } else if (typeof currentSegment === 'string') {\n key = currentSegment\n } else if (typeof currentSegment === 'number') {\n key = currentSegment\n }\n\n if (key === undefined) return undefined\n\n // Use .at() to support negative indexes on arrays.\n const nestedInput =\n typeof key === 'number' && Array.isArray(input)\n ? input.at(key)\n : (input as Record<string, unknown>)[key]\n\n return getDeep(nestedInput, restOfPath)\n}\n\n/**\n * Sets a value deep inside of an object given a path. If the path does not\n * exist in the object, it will be created.\n */\nexport function setDeep<R>(input: unknown, path: SingleValuePath, value: unknown): R\nexport function setDeep(input: unknown, path: SingleValuePath, value: unknown): unknown {\n const [currentSegment, ...restOfPath] = path\n if (currentSegment === undefined) return value\n\n // If the current input is not an object, create a new container.\n if (typeof input !== 'object' || input === null) {\n if (typeof currentSegment === 'string') {\n return {[currentSegment]: setDeep(null, restOfPath, value)}\n }\n\n let index: number | undefined\n if (isKeySegment(currentSegment)) {\n // When creating a new array via a keyed segment, use index 0.\n index = 0\n } else if (typeof currentSegment === 'number' && currentSegment >= 0) {\n index = currentSegment\n } else {\n // For negative numbers in a non‐object we simply return input.\n return input\n }\n\n return [\n // fill until index\n ...Array.from({length: index}).fill(null),\n // then set deep here\n setDeep(null, restOfPath, value),\n ]\n }\n\n // When input is an array…\n if (Array.isArray(input)) {\n let index: number | undefined\n if (isKeySegment(currentSegment)) {\n index = getIndexForKey(input, currentSegment._key) ?? input.length\n } else if (typeof currentSegment === 'number') {\n // Support negative indexes by computing the proper positive index.\n index = currentSegment < 0 ? input.length + currentSegment : currentSegment\n }\n if (index === undefined) return input\n\n if (index in input) {\n // Update the element at the resolved index.\n return input.map((nestedInput, i) =>\n i === index ? setDeep(nestedInput, restOfPath, value) : nestedInput,\n )\n }\n\n // Expand the array if needed.\n return [\n ...input,\n ...Array.from({length: index - input.length}).fill(null),\n setDeep(null, restOfPath, value),\n ]\n }\n\n // For keyed segments that aren't arrays, do nothing.\n if (typeof currentSegment === 'object') return input\n\n // For plain objects, update an existing property if it exists…\n if (currentSegment in input) {\n return Object.fromEntries(\n Object.entries(input).map(([key, nestedInput]) =>\n key === currentSegment\n ? [key, setDeep(nestedInput, restOfPath, value)]\n : [key, nestedInput],\n ),\n )\n }\n\n // ...otherwise create the new nested path.\n return {...input, [currentSegment]: setDeep(null, restOfPath, value)}\n}\n\n/**\n * Given an object and an exact path as an array, this unsets the value at the\n * given path.\n */\nexport function unsetDeep<R>(input: unknown, path: SingleValuePath): R\nexport function unsetDeep(input: unknown, path: SingleValuePath): unknown {\n const [currentSegment, ...restOfPath] = path\n if (currentSegment === undefined) return input\n if (typeof input !== 'object' || input === null) return input\n\n let _segment: string | number | undefined\n if (isKeySegment(currentSegment)) {\n _segment = getIndexForKey(input, currentSegment._key)\n } else if (typeof currentSegment === 'string' || typeof currentSegment === 'number') {\n _segment = currentSegment\n }\n if (_segment === undefined) return input\n\n // For numeric segments in arrays, compute the positive index.\n let segment: string | number = _segment\n if (typeof segment === 'number' && Array.isArray(input)) {\n segment = segment < 0 ? input.length + segment : segment\n }\n if (!(segment in input)) return input\n\n // If we're at the final segment, remove the property/element.\n if (!restOfPath.length) {\n if (Array.isArray(input)) {\n return input.filter((_nestedInput, index) => index !== segment)\n }\n return Object.fromEntries(Object.entries(input).filter(([key]) => key !== segment.toString()))\n }\n\n // Otherwise, recurse into the nested value.\n if (Array.isArray(input)) {\n return input.map((nestedInput, index) =>\n index === segment ? unsetDeep(nestedInput, restOfPath) : nestedInput,\n )\n }\n\n return Object.fromEntries(\n Object.entries(input).map(([key, value]) =>\n key === segment ? [key, unsetDeep(value, restOfPath)] : [key, value],\n ),\n )\n}\n","import {\n type Mutation,\n type MutationSelection,\n type PatchOperations,\n type SanityDocument,\n} from '@sanity/types'\n\nimport {\n dec,\n diffMatchPatch,\n ifRevisionID,\n inc,\n insert,\n set,\n setIfMissing,\n unset,\n} from './patchOperations'\n\n/**\n * Represents a set of document that will go into `applyMutations`. Before\n * applying a mutation, it's expected that all relevant documents that the\n * mutations affect are included, including those that do not exist yet.\n * Documents that don't exist have a `null` value.\n */\nexport type DocumentSet<TDocument extends SanityDocument = SanityDocument> = {\n [TDocumentId in string]?: TDocument | null\n}\n\ntype SupportedPatchOperation = Exclude<keyof PatchOperations, 'merge'>\n\n// > If multiple patches are included, then the order of execution is as follows:\n// > - set, setIfMissing, unset, inc, dec, insert.\n// > https://www.sanity.io/docs/http-mutations#5b4db1396e56\nconst patchOperations = {\n ifRevisionID,\n set,\n setIfMissing,\n unset,\n inc,\n dec,\n insert,\n diffMatchPatch,\n} satisfies {\n [K in SupportedPatchOperation]: (\n input: unknown,\n pathExpressions: NonNullable<PatchOperations[K]>,\n ) => unknown\n}\n\n/**\n * Implements ID generation:\n *\n * A create mutation creates a new document. It takes the literal document\n * content as its argument. The rules for the new document's identifier are as\n * follows:\n *\n * - If the `_id` attribute is missing, then a new, random, unique ID is\n * generated.\n * - If the `_id` attribute is present but ends with `.`, then it is used as a\n * prefix for a new, random, unique ID.\n * - If the _id attribute is present, it is used as-is.\n *\n * [- source](https://www.sanity.io/docs/http-mutations#c732f27330a4)\n */\nexport function getId(id?: string): string {\n if (!id || typeof id !== 'string') return crypto.randomUUID()\n if (id.endsWith('.')) return `${id}${crypto.randomUUID()}`\n return id\n}\n\ninterface ProcessMutationsOptions {\n /**\n * The transaction ID that will become the next `_rev` for documents mutated\n * by the given mutations.\n */\n transactionId: string\n /**\n * The input document set that the mutations will be applied to.\n */\n documents: DocumentSet\n /**\n * A list of mutations to apply to the given document set.\n */\n mutations: Mutation[]\n /**\n * An optional timestamp that will be used for `_createdAt` and `_updatedAt`\n * timestamp when applicable.\n */\n timestamp?: string\n}\n\nexport function getDocumentIds(selection: MutationSelection): string[] {\n if ('id' in selection) {\n // NOTE: the `MutationSelection` type within `@sanity/client` (instead of\n // `@sanity/types`) allows for the ID field to be an array of strings so we\n // support that as well\n const array = Array.isArray(selection.id) ? selection.id : [selection.id]\n const ids = array.filter((id): id is string => typeof id === 'string')\n return Array.from(new Set(ids))\n }\n\n if ('query' in selection) {\n throw new Error(`'query' in mutations is not supported.`)\n }\n\n return []\n}\n\n/**\n * Applies the given mutation to the given document set. Note, it is expected\n * that all relevant documents that the mutations affect should be within the\n * given `document` set. If a document does not exist, it should have the value\n * `null`. If a document is deleted as a result of the mutations, it will still\n * have its document ID present in the returns documents, but it will have a\n * value of `null`.\n *\n * The given `transactionId` will be used as the resulting `_rev` for documents\n * affected by the given set of mutations.\n *\n * If a `timestamp` is given, that will be used as for the relevant `_updatedAt`\n * and `_createdAt` timestamps.\n */\nexport function processMutations({\n documents,\n mutations,\n transactionId,\n timestamp,\n}: ProcessMutationsOptions): DocumentSet {\n // early return if there are no mutations given\n if (!mutations.length) return documents\n\n const dataset = {...documents}\n const now = timestamp || new Date().toISOString()\n\n for (const mutation of mutations) {\n if ('create' in mutation) {\n const id = getId(mutation.create._id)\n\n if (dataset[id]) {\n throw new Error(\n `Cannot create document with \\`_id\\` \\`${id}\\` because another document with the same ID already exists.`,\n )\n }\n\n const document: SanityDocument = {\n // > `_createdAt` and `_updatedAt` may be submitted and will override\n // > the default which is of course the current time. This can be used\n // > to reconstruct a data-set with its timestamp structure intact.\n // >\n // > [- source](https://www.sanity.io/docs/http-mutations#c732f27330a4)\n _createdAt: now,\n _updatedAt: now,\n ...mutation.create, // prefer the user's `_createdAt` and `_updatedAt`\n _rev: transactionId,\n _id: id,\n }\n\n dataset[id] = document\n\n continue\n }\n\n if ('createOrReplace' in mutation) {\n const id = getId(mutation.createOrReplace._id)\n const prev = dataset[id]\n\n const document: SanityDocument = {\n ...mutation.createOrReplace,\n // otherwise, if the mutation provided, a `_createdAt` time, use it,\n // otherwise default to now\n _createdAt:\n // if there was an existing document, use the previous `_createdAt`\n // since we're replacing the current document\n prev?._createdAt ||\n // if there was no previous document, then we're creating this\n // document for the first time so we should use the `_createdAt` from\n // the mutation if the user included it\n (typeof mutation.createOrReplace['_createdAt'] === 'string' &&\n mutation.createOrReplace['_createdAt']) ||\n // otherwise, default to now\n now,\n\n _updatedAt:\n // if there was an existing document, then set the `_updatedAt` to now\n // since we're replacing the current document\n prev\n ? now\n : // otherwise, we're creating this document for the first time,\n // in that case, use the user's `_updatedAt` if included in the\n // mutation\n (typeof mutation.createOrReplace['_updatedAt'] === 'string' &&\n mutation.createOrReplace['_updatedAt']) ||\n // otherwise default to now\n now,\n _rev: transactionId,\n _id: id,\n }\n\n dataset[id] = document\n\n continue\n }\n\n if ('createIfNotExists' in mutation) {\n const id = getId(mutation.createIfNotExists._id)\n const prev = dataset[id]\n if (prev) continue\n\n const document: SanityDocument = {\n // same logic as `create`:\n // prefer the user's `_createdAt` and `_updatedAt`\n _createdAt: now,\n _updatedAt: now,\n ...mutation.createIfNotExists,\n _rev: transactionId,\n _id: id,\n }\n\n dataset[id] = document\n\n continue\n }\n\n if ('delete' in mutation) {\n for (const id of getDocumentIds(mutation.delete)) {\n dataset[id] = null\n }\n\n continue\n }\n\n if ('patch' in mutation) {\n const {patch} = mutation\n const ids = getDocumentIds(patch)\n\n const patched = ids.map((id) => {\n if (!dataset[id]) {\n throw new Error(`Cannot patch document with ID \\`${id}\\` because it was not found.`)\n }\n\n type Entries<T> = {[K in keyof T]: [K, T[K]]}[keyof T][]\n const entries = Object.entries(patchOperations) as Entries<typeof patchOperations>\n\n return entries.reduce((acc, [type, operation]) => {\n if (patch[type]) {\n return operation(\n acc,\n // @ts-expect-error TS doesn't handle this union very well\n patch[type],\n )\n }\n return acc\n }, dataset[id])\n })\n\n for (const result of patched) {\n dataset[result._id] = {\n ...result,\n _rev: transactionId,\n _updatedAt: now,\n }\n }\n\n continue\n }\n }\n\n return dataset\n}\n","import {type MutationEvent} from '@sanity/client'\nimport {type Mutation, type SanityDocument} from '@sanity/types'\nimport {\n concat,\n concatMap,\n distinctUntilChanged,\n EMPTY,\n filter,\n map,\n type Observable,\n of,\n switchMap,\n throwError,\n timer,\n withLatestFrom,\n} from 'rxjs'\nimport {mergeMap, scan} from 'rxjs/operators'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {type DocumentStoreState} from './documentStore'\nimport {processMutations} from './processMutations'\n\nconst DEFAULT_MAX_BUFFER_SIZE = 20\nconst DEFAULT_DEADLINE_MS = 30000\n\nexport interface RemoteDocument {\n type: 'sync' | 'mutation'\n documentId: string\n document: SanityDocument | null\n revision?: string\n previousRev?: string\n timestamp: string\n}\n\nexport interface SyncEvent {\n type: 'sync'\n document: SanityDocument | null\n}\n\nexport type ListenerEvent = SyncEvent | MutationEvent\n\ninterface ListenerSequenceState {\n /**\n * Tracks the latest revision from the server that can be applied locally\n * Once we receive a mutation event that has a `previousRev` that equals `base.revision`\n * we will move `base.revision` to the event's `resultRev`\n * `base.revision` will be undefined if document doesn't exist.\n * `base` is `undefined` until the snapshot event is received\n */\n base: {revision: string | undefined} | undefined\n /**\n * Array of events to pass on to the stream, e.g. when mutation applies to current head revision, or a chain is complete\n */\n emitEvents: ListenerEvent[]\n /**\n * Buffer to keep track of events that doesn't line up in a [previousRev, resultRev] -- [previousRev, resultRev] sequence\n * This can happen if events arrive out of order, or if an event in the middle for some reason gets lost\n */\n buffer: MutationEvent[]\n}\n\nexport class OutOfSyncError extends Error {\n /**\n * Attach state to the error for debugging/reporting\n */\n state: ListenerSequenceState\n constructor(message: string, state: ListenerSequenceState) {\n super(message)\n this.name = 'OutOfSyncError'\n this.state = state\n }\n}\n\nexport class DeadlineExceededError extends OutOfSyncError {\n constructor(message: string, state: ListenerSequenceState) {\n super(message, state)\n this.name = 'DeadlineExceededError'\n }\n}\n\nexport class MaxBufferExceededError extends OutOfSyncError {\n constructor(message: string, state: ListenerSequenceState) {\n super(message, state)\n this.name = 'MaxBufferExceededError'\n }\n}\n\ninterface SortListenerEventsOptions {\n maxBufferSize?: number\n resolveChainDeadline?: number\n}\n\n/**\n * Takes an input observable of listener events that might arrive out of order, and emits them in sequence\n * If we receive mutation events that doesn't line up in [previousRev, resultRev] pairs we'll put them in a buffer and\n * check if we have an unbroken chain every time we receive a new event\n *\n * If the buffer grows beyond `maxBufferSize`, or if `resolveChainDeadline` milliseconds passes before the chain resolves\n * an OutOfSyncError will be thrown on the stream\n *\n * @internal\n */\nexport function sortListenerEvents(options?: SortListenerEventsOptions) {\n const {resolveChainDeadline = DEFAULT_DEADLINE_MS, maxBufferSize = DEFAULT_MAX_BUFFER_SIZE} =\n options || {}\n\n return (input$: Observable<ListenerEvent>): Observable<ListenerEvent> => {\n return input$.pipe(\n // Maintain state: current base revision, a buffer of pending mutation events,\n // and a list of events to emit.\n scan(\n (state: ListenerSequenceState, event: ListenerEvent): ListenerSequenceState => {\n // When a sync event is received, reset the base and clear any pending mutations.\n if (event.type === 'sync') {\n return {\n base: {revision: event.document?._rev},\n buffer: [],\n emitEvents: [event],\n }\n }\n // For mutation events we must have a base revision (from a prior sync event)\n if (event.type === 'mutation') {\n if (!state.base) {\n throw new Error(\n 'Invalid state. Cannot process mutation event without a base sync event',\n )\n }\n // Add the new mutation event into the buffer\n const buffer = state.buffer.concat(event)\n const emitEvents: MutationEvent[] = []\n let baseRevision = state.base.revision\n let progress = true\n\n // Try to apply as many buffered mutations as possible.\n while (progress) {\n progress = false\n // Look for a mutation whose previousRev matches the current base.\n const idx = buffer.findIndex((e) => e.previousRev === baseRevision)\n if (idx !== -1) {\n // Remove the event from the buffer and “apply” it.\n const [next] = buffer.splice(idx, 1)\n emitEvents.push(next)\n // If the mutation is a deletion, the new base revision is undefined.\n baseRevision = next.transition === 'disappear' ? undefined : next.resultRev\n progress = true\n }\n }\n\n if (buffer.length >= maxBufferSize) {\n throw new MaxBufferExceededError(\n `Too many unchainable mutation events (${buffer.length}) waiting to resolve.`,\n {base: {revision: baseRevision}, buffer, emitEvents},\n )\n }\n\n return {\n base: {revision: baseRevision},\n buffer,\n emitEvents,\n }\n }\n // Any other event is simply forwarded.\n return {...state, emitEvents: [event]}\n },\n {\n base: undefined,\n buffer: [] as MutationEvent[],\n emitEvents: [] as ListenerEvent[],\n },\n ),\n switchMap((state) => {\n if (state.buffer.length > 0) {\n return concat(\n of(state),\n timer(resolveChainDeadline).pipe(\n mergeMap(() =>\n throwError(\n () =>\n new DeadlineExceededError(\n `Did not resolve chain within a deadline of ${resolveChainDeadline}ms`,\n state,\n ),\n ),\n ),\n ),\n )\n }\n return of(state)\n }),\n // Emit all events that are ready to be applied.\n mergeMap((state) => of(...state.emitEvents)),\n )\n }\n}\n\nexport const listen = (\n {state}: StoreContext<DocumentStoreState>,\n documentId: string,\n): Observable<RemoteDocument> => {\n const {sharedListener, fetchDocument} = state.get()\n\n return sharedListener.events.pipe(\n concatMap((e) => {\n if (e.type === 'welcome') {\n return fetchDocument(documentId).pipe(\n map((document): SyncEvent => ({type: 'sync', document})),\n )\n }\n if (e.type === 'mutation' && e.documentId === documentId) return of(e)\n return EMPTY\n }),\n sortListenerEvents(),\n withLatestFrom(\n state.observable.pipe(\n map((s) => s.documentStates[documentId]),\n filter(Boolean),\n distinctUntilChanged(),\n ),\n ),\n map(([next, documentState]): RemoteDocument => {\n if (next.type === 'sync') {\n return {\n type: 'sync',\n documentId,\n document: next.document,\n revision: next.document?._rev,\n timestamp: next.document?._updatedAt ?? new Date().toISOString(),\n }\n }\n\n // TODO: from manual testing, mendoza patches seem to be applying\n // let document\n // if (next.effects?.apply) {\n // document = applyPatch(omit(documentState.remote, '_rev'), next.effects?.apply)\n // }\n\n const [document] = Object.values(\n processMutations({\n documents: {[documentId]: documentState.remote},\n mutations: next.mutations as Mutation[],\n transactionId: next.transactionId,\n timestamp: next.timestamp,\n }),\n )\n\n const {previousRev, transactionId, timestamp} = next\n\n return {\n type: 'mutation',\n documentId,\n document: document ?? null,\n revision: transactionId,\n timestamp,\n ...(previousRev && {previousRev}),\n }\n }),\n )\n}\n","interface MultiKeyWeakMapNode {\n value: unknown\n next: WeakMap<object, MultiKeyWeakMapNode>\n}\n\nexport class MultiKeyWeakMap<T = unknown> {\n // The root of our nested WeakMap structure.\n #rootMap = new WeakMap<object, MultiKeyWeakMapNode>()\n\n // Instead of random IDs, we use a counter for deterministic IDs.\n static #globalIdCounter = 0\n // Each instance keeps a cache mapping a key to its assigned ID.\n #idCache = new WeakMap<object, number>()\n\n /**\n * Assigns a numeric ID to the key.\n */\n #assignId(key: object): number {\n const cachedId = this.#idCache.get(key)\n if (cachedId !== undefined) return cachedId\n\n const id = MultiKeyWeakMap.#globalIdCounter\n this.#idCache.set(key, id)\n MultiKeyWeakMap.#globalIdCounter++\n return id\n }\n\n /**\n * Remove duplicate keys and arrange them in a consistent order\n * by sorting according to their assigned IDs.\n */\n #arrangeKeys(keys: object[]): object[] {\n const uniqueKeys = Array.from(new Set(keys))\n const keyed = uniqueKeys.map((key) => [this.#assignId(key), key] as const)\n keyed.sort((a, b) => a[0] - b[0])\n return keyed.map(([, key]) => key)\n }\n\n /**\n * Recursively search the nested WeakMap structure for the value.\n */\n #getDeep(keys: object[], map: WeakMap<object, MultiKeyWeakMapNode>): unknown {\n if (keys.length === 0) return undefined\n\n const [firstKey, ...restKeys] = keys\n const node = map.get(firstKey)\n if (!node) return undefined\n if (restKeys.length === 0) return node.value\n return this.#getDeep(restKeys, node.next)\n }\n\n /**\n * Recursively create nodes along the key chain until the final key\n * is reached, then assign the value.\n */\n #setDeep(keys: object[], map: WeakMap<object, MultiKeyWeakMapNode>, value: unknown): void {\n if (keys.length === 0) return\n\n const [firstKey, ...restKeys] = keys\n let node = map.get(firstKey)\n if (!node) {\n node = {\n value: undefined,\n next: new WeakMap(),\n }\n map.set(firstKey, node)\n }\n\n if (restKeys.length === 0) {\n node.value = value\n } else {\n this.#setDeep(restKeys, node.next, value)\n }\n }\n\n /**\n * Retrieves the value associated with the array of keys.\n * The keys are de-duplicated and sorted so that the order does not matter.\n */\n get(keys: object[]): T | undefined {\n const arrangedKeys = this.#arrangeKeys(keys)\n return this.#getDeep(arrangedKeys, this.#rootMap) as T | undefined\n }\n\n /**\n * Associates the value with the given array of keys.\n */\n set(keys: object[], value: T): void {\n const arrangedKeys = this.#arrangeKeys(keys)\n this.#setDeep(arrangedKeys, this.#rootMap, value)\n }\n}\n","import {type SanityDocument} from '@sanity/types'\nimport {evaluateSync, type ExprNode, parse} from 'groq-js'\nimport {createSelector} from 'reselect'\n\nimport {type SelectorContext} from '../store/createStateSourceAction'\nimport {getDraftId, getPublishedId} from '../utils/ids'\nimport {MultiKeyWeakMap} from '../utils/MultiKeyWeakMap'\nimport {type DocumentAction} from './actions'\nimport {ActionError, PermissionActionError, processActions} from './processActions'\nimport {type DocumentSet} from './processMutations'\nimport {type SyncTransactionState} from './reducers'\n\nexport type Grant = 'read' | 'update' | 'create' | 'history'\n\nexport type DatasetAcl = {\n filter: string\n permissions: Grant[]\n}[]\n\nexport function createGrantsLookup(datasetAcl: DatasetAcl): Record<Grant, ExprNode> {\n const filtersByGrant: Record<Grant, Set<string>> = {\n create: new Set(),\n history: new Set(),\n read: new Set(),\n update: new Set(),\n }\n\n for (const entry of datasetAcl) {\n for (const grant of entry.permissions) {\n const set = filtersByGrant[grant]\n set.add(entry.filter)\n filtersByGrant[grant] = set\n }\n }\n\n return Object.fromEntries(\n Object.entries(filtersByGrant).map(([grant, filters]) => {\n const combinedFilter = Array.from(filters)\n .map((i) => `(${i})`)\n .join('||')\n\n if (!combinedFilter) return [grant, parse('false')]\n return [grant, parse(`$document {\"_\": ${combinedFilter}}._`)]\n }),\n ) as Record<Grant, ExprNode>\n}\n\n// Cache for documents based on an array of document objects.\nconst documentsCache = new MultiKeyWeakMap<DocumentSet>()\n// Use a WeakMap so that when a computed DocumentSet is no longer in use,\n// its nested cache for actions can be garbage-collected.\nconst actionsCache = new WeakMap<DocumentSet, Map<string, DocumentAction[]>>()\n\nconst nullReplacer: object = {}\n\n// Compute documents from state and actions.\n// (If the same documents are computed, the MultiKeyWeakMap will return the same instance.)\nconst documentsSelector = createSelector(\n [\n ({state: {documentStates}}: SelectorContext<SyncTransactionState>) => documentStates,\n (_context: SelectorContext<SyncTransactionState>, {actions}: {actions: DocumentAction[]}) =>\n actions,\n ],\n (documentStates, actions) => {\n // Collect all document IDs needed for permission checks.\n // Important: liveEdit documents don't have drafts, so we only fetch the single document to avoid waiting for non-existent draft documents.\n const documentIds = new Set(\n actions\n .map((action) => {\n if (typeof action.documentId !== 'string') return []\n // For liveEdit documents, only fetch the single document\n if (action.liveEdit) return [action.documentId]\n // For standard documents, fetch both draft and published\n return [getPublishedId(action.documentId), getDraftId(action.documentId)]\n })\n .flat(),\n )\n\n const documents: DocumentSet = {}\n\n for (const documentId of documentIds) {\n const local = documentStates[documentId]?.local\n\n // early exit if we don't have all the documents yet\n if (local === undefined) return undefined\n documents[documentId] = local\n }\n\n // Create a key from the documents values (using a nullReplacer when needed).\n const keys = Object.values(\n // value in this record will be `undefined` because\n // of the early return if undefined is found above\n documents as Record<string, SanityDocument | null>,\n ).map((doc) => (doc === null ? nullReplacer : doc))\n const cached = documentsCache.get(keys)\n if (cached) return cached\n\n documentsCache.set(keys, documents)\n return documents\n },\n)\n\n// Cache the actions array based on a serialized version, but “attach” the cache\n// to the computed documents. That way if the computed documents object is no longer in use,\n// the cache is eligible for GC.\nconst memoizedActionsSelector = createSelector(\n [\n documentsSelector,\n (_state: SelectorContext<SyncTransactionState>, {actions}: {actions: DocumentAction[]}) =>\n actions,\n ],\n (documents, actions) => {\n if (!documents) return undefined\n\n // Get (or create) the nested Map for this computed documents.\n let nestedCache = actionsCache.get(documents)\n if (!nestedCache) {\n nestedCache = new Map<string, DocumentAction[]>()\n actionsCache.set(documents, nestedCache)\n }\n\n const normalizedActions = Array.isArray(actions) ? actions : [actions]\n\n // Use JSON.stringify to get a serialized key for the actions.\n // TODO: considering swapping thisfor a more efficient or stable hash\n const actionsKey = JSON.stringify(normalizedActions)\n const cached = nestedCache.get(actionsKey)\n if (cached) return cached\n\n nestedCache.set(actionsKey, normalizedActions)\n return normalizedActions\n },\n)\n\nfunction checkGrant(grantExpr: ExprNode, document: SanityDocument): boolean {\n const value = evaluateSync(grantExpr, {params: {document}})\n return value.type === 'boolean' && value.data\n}\n\n/** @beta */\nexport interface PermissionDeniedReason {\n type: 'precondition' | 'access'\n message: string\n documentId?: string\n}\n\n/** @beta */\nexport type DocumentPermissionsResult =\n | {\n allowed: false\n message: string\n reasons: PermissionDeniedReason[]\n }\n | {allowed: true; message?: undefined; reasons?: undefined}\n\nconst enNarrowConjunction = new Intl.ListFormat('en', {style: 'narrow', type: 'conjunction'})\n\nexport function calculatePermissions(\n ...args: Parameters<typeof _calculatePermissions>\n): ReturnType<typeof _calculatePermissions> {\n return _calculatePermissions(...args)\n}\n\nconst _calculatePermissions = createSelector(\n [\n ({state: {grants}}: SelectorContext<SyncTransactionState>) => grants,\n documentsSelector,\n memoizedActionsSelector,\n ],\n (\n grants: Record<Grant, ExprNode> | undefined,\n documents: DocumentSet | undefined,\n actions: DocumentAction[] | undefined,\n ): DocumentPermissionsResult | undefined => {\n if (!documents) return undefined\n if (!grants) return undefined\n if (!actions) return undefined\n\n const timestamp = new Date().toISOString()\n const reasons: PermissionDeniedReason[] = []\n\n try {\n processActions({\n actions,\n transactionId: crypto.randomUUID(),\n working: documents,\n base: documents,\n timestamp,\n grants,\n })\n } catch (error) {\n if (error instanceof PermissionActionError) {\n reasons.push({\n message: error.message,\n documentId: error.documentId,\n type: 'access',\n })\n } else if (error instanceof ActionError) {\n reasons.push({\n message: error.message,\n documentId: error.documentId,\n type: 'precondition',\n })\n } else {\n throw error\n }\n }\n\n for (const action of actions) {\n // Check edit actions with no patches\n if (action.type === 'document.edit' && !action.patches?.length) {\n const docId = action.documentId\n // For liveEdit documents, only check the single document\n const doc = action.liveEdit\n ? documents[docId]\n : (documents[getDraftId(docId)] ?? documents[getPublishedId(docId)])\n if (!doc) {\n reasons.push({\n type: 'precondition',\n message: `The document with ID \"${docId}\" could not be found. Please check that it exists before editing.`,\n documentId: docId,\n })\n } else if (!checkGrant(grants.update, doc)) {\n reasons.push({\n type: 'access',\n message: `You are not allowed to edit the document with ID \"${docId}\".`,\n documentId: docId,\n })\n }\n }\n }\n\n const allowed = reasons.length === 0\n if (allowed) return {allowed}\n\n const sortedReasons = reasons\n .map((reason, index) => ({...reason, index}))\n .sort((a, b) => {\n if (a.type !== b.type) return a.type === 'access' ? -1 : 1\n return a.message.localeCompare(b.message, 'en-US')\n })\n .map(({index: _index, ...reason}) => reason)\n\n return {\n allowed,\n reasons: sortedReasons,\n message: enNarrowConjunction.format(sortedReasons.map((i) => i.message)),\n }\n },\n)\n","import {diffValue} from '@sanity/diff-patch'\nimport {\n type Mutation,\n type PatchOperations,\n type Reference,\n type SanityDocument,\n} from '@sanity/types'\nimport {evaluateSync, type ExprNode} from 'groq-js'\nimport {isEqual} from 'lodash-es'\n\nimport {getDraftId, getPublishedId} from '../utils/ids'\nimport {type DocumentAction} from './actions'\nimport {type Grant} from './permissions'\nimport {type DocumentSet, getId, processMutations} from './processMutations'\nimport {type HttpAction} from './reducers'\n\nfunction checkGrant(grantExpr: ExprNode, document: SanityDocument): boolean {\n const value = evaluateSync(grantExpr, {params: {document}})\n return value.type === 'boolean' && value.data\n}\n\ninterface ProcessActionsOptions {\n /**\n * The ID of this transaction. This will become the resulting `_rev` for all\n * documents affected by changes derived from the current set of actions.\n */\n transactionId: string\n\n /**\n * The actions to apply to the given documents\n */\n actions: DocumentAction[]\n\n /**\n * The set of documents these actions were intended to be applied to. These\n * set of documents should be captured right before a queued action is\n * applied.\n */\n base: DocumentSet\n\n /**\n * The current \"working\" set of documents. A patch will be created by applying\n * the actions to the base. This patch will then be applied to the working\n * set for conflict resolution. Initially, this value should match the base\n * set.\n */\n working: DocumentSet\n\n /**\n * The timestamp to use for `_updateAt` and other similar timestamps for this\n * transaction\n */\n timestamp: string\n\n /**\n * the lookup with pre-parsed GROQ expressions\n */\n grants: Record<Grant, ExprNode>\n\n // // TODO: implement initial values from the schema?\n // initialValues?: {[TDocumentType in string]?: {_type: string}}\n}\n\ninterface ProcessActionsResult {\n /**\n * The resulting document set after the actions have been applied. This is\n * derived from the working documents.\n */\n working: DocumentSet\n /**\n * The document set before the actions have been applied. This is simply the\n * input of the `working` document set.\n */\n previous: DocumentSet\n /**\n * The outgoing action that were collected when applying the actions. These\n * are sent to the Actions HTTP API\n */\n outgoingActions: HttpAction[]\n /**\n * The outgoing mutations that were collected when applying the actions. These\n * are here for debugging purposes.\n */\n outgoingMutations: Mutation[]\n /**\n * The previous revisions of the given documents before the actions were applied.\n */\n previousRevs: {[TDocumentId in string]?: string}\n}\n\ninterface ActionErrorOptions {\n message: string\n documentId: string\n transactionId: string\n}\n\n/**\n * Thrown when a precondition for an action failed.\n */\nexport class ActionError extends Error implements ActionErrorOptions {\n documentId!: string\n transactionId!: string\n\n constructor(options: ActionErrorOptions) {\n super(options.message)\n Object.assign(this, options)\n }\n}\n\nexport class PermissionActionError extends ActionError {}\n\n/**\n * Applies the given set of actions to the working set of documents and converts\n * high-level actions into lower-level outgoing mutations/actions that respect\n * the current state of the working documents.\n *\n * Supports a \"base\" and \"working\" set of documents to allow actions to be\n * applied on top of a different working set of documents in a 3-way merge\n *\n * Actions are applied to the base set of documents first. The difference\n * between the base before and after is used to create a patch. This patch is\n * then applied to the working set of documents and is set as the outgoing patch\n * sent to the server.\n */\nexport function processActions({\n actions,\n transactionId,\n working: initialWorking,\n base: initialBase,\n timestamp,\n grants,\n}: ProcessActionsOptions): ProcessActionsResult {\n let working: DocumentSet = {...initialWorking}\n let base: DocumentSet = {...initialBase}\n\n const outgoingActions: HttpAction[] = []\n const outgoingMutations: Mutation[] = []\n\n for (const action of actions) {\n switch (action.type) {\n case 'document.create': {\n const documentId = getId(action.documentId)\n\n if (action.liveEdit) {\n // For liveEdit documents, create directly without draft/published logic\n if (working[documentId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `This document already exists.`,\n })\n }\n\n const newDocBase = {_type: action.documentType, _id: documentId}\n const newDocWorking = {_type: action.documentType, _id: documentId}\n const mutations: Mutation[] = [{create: newDocWorking}]\n\n base = processMutations({\n documents: base,\n transactionId,\n mutations: [{create: newDocBase}],\n timestamp,\n })\n working = processMutations({\n documents: working,\n transactionId,\n mutations,\n timestamp,\n })\n\n if (!checkGrant(grants.create, working[documentId] as SanityDocument)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to create document \"${documentId}\".`,\n })\n }\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.create',\n publishedId: documentId,\n attributes: newDocWorking,\n })\n continue\n }\n\n // Standard draft/published logic\n const draftId = getDraftId(documentId)\n const publishedId = getPublishedId(documentId)\n\n if (working[draftId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `A draft version of this document already exists. Please use or discard the existing draft before creating a new one.`,\n })\n }\n\n // Spread the (possibly undefined) published version directly.\n const newDocBase = {\n ...base[publishedId],\n _type: action.documentType,\n _id: draftId,\n ...action.initialValue,\n }\n const newDocWorking = {\n ...working[publishedId],\n _type: action.documentType,\n _id: draftId,\n ...action.initialValue,\n }\n const mutations: Mutation[] = [{create: newDocWorking}]\n\n base = processMutations({\n documents: base,\n transactionId,\n mutations: [{create: newDocBase}],\n timestamp,\n })\n working = processMutations({\n documents: working,\n transactionId,\n mutations,\n timestamp,\n })\n\n if (!checkGrant(grants.create, working[draftId] as SanityDocument)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to create a draft for document \"${documentId}\".`,\n })\n }\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.version.create',\n publishedId,\n attributes: newDocWorking,\n })\n continue\n }\n\n case 'document.delete': {\n const documentId = action.documentId\n\n if (action.liveEdit) {\n // For liveEdit documents, delete directly\n if (!working[documentId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: 'The document you are trying to delete does not exist.',\n })\n }\n\n if (!checkGrant(grants.update, working[documentId])) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to delete this document.`,\n })\n }\n\n const mutations: Mutation[] = [{delete: {id: documentId}}]\n\n base = processMutations({documents: base, transactionId, mutations, timestamp})\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.delete',\n publishedId: documentId,\n })\n continue\n }\n\n // Standard draft/published logic\n const draftId = getDraftId(documentId)\n const publishedId = getPublishedId(documentId)\n\n if (!working[publishedId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: working[draftId]\n ? 'Cannot delete a document without a published version.'\n : 'The document you are trying to delete does not exist.',\n })\n }\n\n const cantDeleteDraft = working[draftId] && !checkGrant(grants.update, working[draftId])\n const cantDeletePublished =\n working[publishedId] && !checkGrant(grants.update, working[publishedId])\n\n if (cantDeleteDraft || cantDeletePublished) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to delete this document.`,\n })\n }\n\n const mutations: Mutation[] = [{delete: {id: publishedId}}, {delete: {id: draftId}}]\n const includeDrafts = working[draftId] ? [draftId] : undefined\n\n base = processMutations({documents: base, transactionId, mutations, timestamp})\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.delete',\n publishedId,\n ...(includeDrafts ? {includeDrafts} : {}),\n })\n continue\n }\n\n case 'document.discard': {\n const documentId = getId(action.documentId)\n\n if (action.liveEdit) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot discard changes for liveEdit document \"${documentId}\". LiveEdit documents do not support drafts.`,\n })\n }\n\n // Standard draft/published logic\n const draftId = getDraftId(documentId)\n const mutations: Mutation[] = [{delete: {id: draftId}}]\n\n if (!working[draftId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `There is no draft available to discard for document \"${documentId}\".`,\n })\n }\n\n if (!checkGrant(grants.update, working[draftId])) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to discard changes for document \"${documentId}\".`,\n })\n }\n\n base = processMutations({documents: base, transactionId, mutations, timestamp})\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.version.discard',\n versionId: draftId,\n })\n continue\n }\n\n case 'document.edit': {\n const documentId = getId(action.documentId)\n\n if (action.liveEdit) {\n // For liveEdit documents, edit directly without draft logic\n const userPatches = action.patches?.map((patch) => ({patch: {id: documentId, ...patch}}))\n\n // skip this action if there are no associated patches\n if (!userPatches?.length) continue\n\n if (!working[documentId] || !base[documentId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot edit document because it does not exist.`,\n })\n }\n\n const baseBefore = base[documentId] as SanityDocument\n if (userPatches) {\n base = processMutations({\n documents: base,\n transactionId,\n mutations: userPatches,\n timestamp,\n })\n }\n\n const baseAfter = base[documentId] as SanityDocument\n const patches = diffValue(baseBefore, baseAfter)\n\n const workingBefore = working[documentId] as SanityDocument\n if (!checkGrant(grants.update, workingBefore)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to edit document \"${documentId}\".`,\n })\n }\n\n const workingMutations = patches.map((patch) => ({patch: {id: documentId, ...patch}}))\n\n working = processMutations({\n documents: working,\n transactionId,\n mutations: workingMutations,\n timestamp,\n })\n\n outgoingMutations.push(...workingMutations)\n outgoingActions.push(\n ...patches.map(\n (patch): HttpAction => ({\n actionType: 'sanity.action.document.edit',\n // Server requires draftId to have drafts. prefix for validation, even for liveEdit\n draftId: getDraftId(documentId),\n publishedId: documentId,\n patch: patch as PatchOperations,\n }),\n ),\n )\n\n continue\n }\n\n // Standard draft/published logic\n const draftId = getDraftId(documentId)\n const publishedId = getPublishedId(documentId)\n const userPatches = action.patches?.map((patch) => ({patch: {id: draftId, ...patch}}))\n\n // skip this action if there are no associated patches\n if (!userPatches?.length) continue\n\n if (\n (!working[draftId] && !working[publishedId]) ||\n (!base[draftId] && !base[publishedId])\n ) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot edit document because it does not exist in draft or published form.`,\n })\n }\n\n const baseMutations: Mutation[] = []\n if (!base[draftId] && base[publishedId]) {\n baseMutations.push({create: {...base[publishedId], _id: draftId}})\n }\n\n // the first if statement should make this never be null or undefined\n const baseBefore = (base[draftId] ?? base[publishedId]) as SanityDocument\n if (userPatches) {\n baseMutations.push(...userPatches)\n }\n\n base = processMutations({\n documents: base,\n transactionId,\n mutations: baseMutations,\n timestamp,\n })\n // this one will always be defined because a patch mutation will never\n // delete an input document\n const baseAfter = base[draftId] as SanityDocument\n const patches = diffValue(baseBefore, baseAfter)\n\n const workingMutations: Mutation[] = []\n if (!working[draftId] && working[publishedId]) {\n const newDraftFromPublished = {...working[publishedId], _id: draftId}\n\n if (!checkGrant(grants.create, newDraftFromPublished)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to create a draft for editing this document.`,\n })\n }\n\n workingMutations.push({create: newDraftFromPublished})\n }\n\n // the first if statement should make this never be null or undefined\n const workingBefore = (working[draftId] ?? working[publishedId]) as SanityDocument\n if (!checkGrant(grants.update, workingBefore)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to edit document \"${documentId}\".`,\n })\n }\n workingMutations.push(...patches.map((patch) => ({patch: {id: draftId, ...patch}})))\n\n working = processMutations({\n documents: working,\n transactionId,\n mutations: workingMutations,\n timestamp,\n })\n\n outgoingMutations.push(...workingMutations)\n outgoingActions.push(\n ...patches.map(\n (patch): HttpAction => ({\n actionType: 'sanity.action.document.edit',\n draftId,\n publishedId,\n patch: patch as PatchOperations,\n }),\n ),\n )\n\n continue\n }\n\n case 'document.publish': {\n const documentId = getId(action.documentId)\n\n if (action.liveEdit) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot publish liveEdit document \"${documentId}\". LiveEdit documents do not support drafts or publishing.`,\n })\n }\n\n // Standard draft/published logic\n const draftId = getDraftId(documentId)\n const publishedId = getPublishedId(documentId)\n\n const workingDraft = working[draftId]\n const baseDraft = base[draftId]\n if (!workingDraft || !baseDraft) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot publish because no draft version was found for document \"${documentId}\".`,\n })\n }\n\n // Before proceeding, verify that the working draft is identical to the base draft.\n // TODO: is it enough just to check for the _rev or nah?\n if (!isEqual(workingDraft, baseDraft)) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Publish aborted: The document has changed elsewhere. Please try again.`,\n })\n }\n\n const newPublishedFromDraft = {...strengthenOnPublish(workingDraft), _id: publishedId}\n\n const mutations: Mutation[] = [\n {delete: {id: draftId}},\n {createOrReplace: newPublishedFromDraft},\n ]\n\n if (working[draftId] && !checkGrant(grants.update, working[draftId])) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `Publish failed: You do not have permission to update the draft for \"${documentId}\".`,\n })\n }\n\n if (working[publishedId] && !checkGrant(grants.update, newPublishedFromDraft)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `Publish failed: You do not have permission to update the published version of \"${documentId}\".`,\n })\n } else if (!working[publishedId] && !checkGrant(grants.create, newPublishedFromDraft)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `Publish failed: You do not have permission to publish a new version of \"${documentId}\".`,\n })\n }\n\n base = processMutations({documents: base, transactionId, mutations, timestamp})\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.publish',\n draftId,\n publishedId,\n })\n continue\n }\n\n case 'document.unpublish': {\n const documentId = getId(action.documentId)\n\n if (action.liveEdit) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot unpublish liveEdit document \"${documentId}\". LiveEdit documents do not support drafts or publishing.`,\n })\n }\n\n // Standard draft/published logic\n const draftId = getDraftId(documentId)\n const publishedId = getPublishedId(documentId)\n\n if (!working[publishedId] && !base[publishedId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot unpublish because the document \"${documentId}\" is not currently published.`,\n })\n }\n\n const sourceDoc = working[publishedId] ?? (base[publishedId] as SanityDocument)\n const newDraftFromPublished = {...sourceDoc, _id: draftId}\n const mutations: Mutation[] = [\n {delete: {id: publishedId}},\n {createIfNotExists: newDraftFromPublished},\n ]\n\n if (!checkGrant(grants.update, sourceDoc)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to unpublish the document \"${documentId}\".`,\n })\n }\n\n if (!working[draftId] && !checkGrant(grants.create, newDraftFromPublished)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to create a draft from the published version of \"${documentId}\".`,\n })\n }\n\n base = processMutations({\n documents: base,\n transactionId,\n mutations: [\n {delete: {id: publishedId}},\n {createIfNotExists: {...(base[publishedId] ?? sourceDoc), _id: draftId}},\n ],\n timestamp,\n })\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.unpublish',\n draftId,\n publishedId,\n })\n continue\n }\n\n default: {\n throw new Error(\n `Unknown action type: \"${\n // @ts-expect-error invalid input\n action.type\n }\". Please contact support if this issue persists.`,\n )\n }\n }\n }\n\n const previousRevs = Object.fromEntries(\n Object.entries(initialWorking).map(([id, doc]) => [id, doc?._rev]),\n )\n\n return {\n working,\n outgoingActions,\n outgoingMutations,\n previous: initialWorking,\n previousRevs,\n }\n}\n\nfunction strengthenOnPublish(draft: SanityDocument): SanityDocument {\n const isStrengthenReference = (\n value: object,\n ): value is Reference & Required<Pick<Reference, '_strengthenOnPublish'>> =>\n '_strengthenOnPublish' in value\n\n function strengthen(value: unknown): unknown {\n if (typeof value !== 'object' || !value) return value\n\n if (isStrengthenReference(value)) {\n const {_strengthenOnPublish, _weak, ...rest} = value\n return {\n ...rest,\n ...(_strengthenOnPublish.weak && {_weak: true}),\n }\n }\n\n if (Array.isArray(value)) {\n return value.map(strengthen)\n }\n\n return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, strengthen(v)]))\n }\n\n return strengthen(draft) as SanityDocument\n}\n","import {getPublishedId} from '@sanity/client/csm'\nimport {type Mutation, type PatchOperations, type SanityDocumentLike} from '@sanity/types'\nimport {omit} from 'lodash-es'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {getDraftId, insecureRandomId} from '../utils/ids'\nimport {type DocumentAction} from './actions'\nimport {DOCUMENT_STATE_CLEAR_DELAY} from './documentConstants'\nimport {type DocumentState, type DocumentStoreState} from './documentStore'\nimport {type RemoteDocument} from './listen'\nimport {ActionError, processActions} from './processActions'\nimport {type DocumentSet} from './processMutations'\n\nconst EMPTY_REVISIONS: NonNullable<Required<DocumentState['unverifiedRevisions']>> = {}\n\nexport type SyncTransactionState = Pick<\n DocumentStoreState,\n 'queued' | 'applied' | 'documentStates' | 'outgoing' | 'grants'\n>\n\ntype ActionMap = {\n create: 'sanity.action.document.version.create'\n createLiveEdit: 'sanity.action.document.create'\n discard: 'sanity.action.document.version.discard'\n unpublish: 'sanity.action.document.unpublish'\n delete: 'sanity.action.document.delete'\n edit: 'sanity.action.document.edit'\n publish: 'sanity.action.document.publish'\n}\n\ntype OptimisticLock = {\n ifDraftRevisionId?: string\n ifPublishedRevisionId?: string\n}\n\nexport type HttpAction =\n | {actionType: ActionMap['create']; publishedId: string; attributes: SanityDocumentLike}\n | {actionType: ActionMap['createLiveEdit']; publishedId: string; attributes: SanityDocumentLike}\n | {actionType: ActionMap['discard']; versionId: string; purge?: boolean}\n | {actionType: ActionMap['unpublish']; draftId: string; publishedId: string}\n | {actionType: ActionMap['delete']; publishedId: string; includeDrafts?: string[]}\n | {actionType: ActionMap['edit']; draftId: string; publishedId: string; patch: PatchOperations}\n | ({actionType: ActionMap['publish']; draftId: string; publishedId: string} & OptimisticLock)\n\n/**\n * Represents a transaction that is queued to be applied but has not yet been\n * applied. A transaction will remain in a queued state until all required\n * documents for the transactions are available locally.\n */\nexport interface QueuedTransaction {\n /**\n * the ID of this transaction. this is generated client-side.\n */\n transactionId: string\n /**\n * the high-level actions associated with this transaction. note that these\n * actions don't mention draft IDs and is meant to abstract away the draft\n * model from users.\n */\n actions: DocumentAction[]\n /**\n * An optional flag set to disable this transaction from being batched with\n * other transactions.\n */\n disableBatching?: boolean\n}\n\n/**\n * Represents a transaction that has been applied locally but has not been\n * committed/transitioned-to-outgoing. These transactions are visible to the\n * user but may be rebased upon a new working document set. Applied transactions\n * also contain the resulting `outgoingActions` that will be submitted to\n * Content Lake. These `outgoingActions` depend on the state of the working\n * documents so they are recomputed on rebase and are only relevant to applied\n * actions (we cannot compute `outgoingActions` for queued transactions because\n * we haven't resolved the set of documents the actions are dependent on yet).\n *\n * In order to support better conflict resolution, the original `previous` set\n * is saved as the `base` set.\n */\nexport interface AppliedTransaction extends QueuedTransaction {\n /**\n * the resulting set of documents after the actions have been applied\n */\n working: DocumentSet\n\n /**\n * the previous set of documents before the action was applied\n */\n previous: DocumentSet\n\n /**\n * the original `previous` document set captured when this action was\n * originally applied. this is used as a reference point to do a 3-way merge\n * if this applied transaction ever needs to be reapplied on a different\n * set of documents.\n */\n base: DocumentSet\n\n /**\n * the `_rev`s from `previous` document set\n */\n previousRevs: {[TDocumentId in string]?: string}\n\n /**\n * a timestamp for when this transaction was applied locally\n */\n timestamp: string\n\n /**\n * the resulting HTTP actions derived from the state of the `working` document\n * set. these are sent to Content Lake as-is when this transaction is batched\n * and transitioned into an outgoing transaction.\n */\n outgoingActions: HttpAction[]\n\n /**\n * similar to `outgoingActions` but comprised of mutations instead of action.\n * this left here for debugging purposes but could be used to send mutations\n * to Content Lake instead of actions.\n */\n outgoingMutations: Mutation[]\n}\n\n/**\n * Represents a set of applied transactions batched into a single outgoing\n * transaction. An outgoing transaction is the result of batching many applied\n * actions. An outgoing transaction may be reverted locally if the server\n * does not accept it.\n */\nexport interface OutgoingTransaction extends AppliedTransaction {\n disableBatching: boolean\n batchedTransactionIds: string[]\n}\n\nexport interface UnverifiedDocumentRevision {\n transactionId: string\n documentId: string\n previousRev: string | undefined\n timestamp: string\n}\n\nexport function queueTransaction(\n prev: SyncTransactionState,\n transaction: QueuedTransaction,\n): SyncTransactionState {\n const {transactionId, actions} = transaction\n const prevWithSubscriptionIds = getDocumentIdsFromActions(actions).reduce(\n (acc, id) => addSubscriptionIdToDocument(acc, id, transactionId),\n prev,\n )\n\n return {\n ...prevWithSubscriptionIds,\n queued: [...prev.queued, transaction],\n }\n}\n\nexport function removeQueuedTransaction(\n prev: SyncTransactionState,\n transactionId: string,\n): SyncTransactionState {\n const transaction = prev.queued.find((t) => t.transactionId === transactionId)\n if (!transaction) return prev\n\n const prevWithSubscriptionIds = getDocumentIdsFromActions(transaction.actions).reduce(\n (acc, id) => removeSubscriptionIdFromDocument(acc, id, transactionId),\n prev,\n )\n\n return {\n ...prevWithSubscriptionIds,\n queued: prev.queued.filter((t) => transactionId !== t.transactionId),\n }\n}\n\nexport function applyFirstQueuedTransaction(prev: SyncTransactionState): SyncTransactionState {\n const queued = prev.queued.at(0)\n if (!queued) return prev\n if (!prev.grants) return prev\n\n const ids = getDocumentIdsFromActions(queued.actions)\n // the local value is only ever `undefined` if it has not been loaded yet\n // we can't get the next applied state unless all relevant documents are ready\n if (ids.some((id) => prev.documentStates[id]?.local === undefined)) return prev\n\n const working = ids.reduce<DocumentSet>((acc, id) => {\n acc[id] = prev.documentStates[id]?.local\n return acc\n }, {})\n\n const timestamp = new Date().toISOString()\n\n const result = processActions({\n ...queued,\n working,\n base: working,\n timestamp,\n grants: prev.grants,\n })\n const applied: AppliedTransaction = {\n ...queued,\n ...result,\n base: result.previous,\n timestamp,\n }\n\n return {\n ...prev,\n applied: [...prev.applied, applied],\n queued: prev.queued.filter((t) => t.transactionId !== queued.transactionId),\n documentStates: Object.entries(result.working).reduce(\n (acc, [id, next]) => {\n const prevDoc = acc[id]\n if (!prevDoc) return acc\n acc[id] = {...prevDoc, local: next}\n return acc\n },\n {...prev.documentStates},\n ),\n }\n}\n\nexport function batchAppliedTransactions([curr, ...rest]: AppliedTransaction[]):\n | OutgoingTransaction\n | undefined {\n // No transactions? Nothing to batch.\n if (!curr) return undefined\n\n // Skip transactions with no actions.\n if (!curr.actions.length) return batchAppliedTransactions(rest)\n\n // If there are multiple actions, we cannot batch further.\n if (curr.actions.length > 1) {\n return {\n ...curr,\n disableBatching: true,\n batchedTransactionIds: [curr.transactionId],\n }\n }\n\n const [action] = curr.actions\n\n // If the single action isn't a document.edit or batching is disabled,\n // mark this transaction as non-batchable.\n if (action.type !== 'document.edit' || curr.disableBatching) {\n return {\n ...curr,\n disableBatching: true,\n batchedTransactionIds: [curr.transactionId],\n }\n }\n\n // Create an outgoing transaction for the single edit action.\n // At this point, batching is allowed.\n const editAction: OutgoingTransaction = {\n ...curr,\n actions: [action],\n disableBatching: false,\n batchedTransactionIds: [curr.transactionId],\n }\n if (!rest.length) return editAction\n\n const next = batchAppliedTransactions(rest)\n if (!next) return undefined\n if (next.disableBatching) return editAction\n\n return {\n disableBatching: false,\n // Use the transactionId from the later (next) transaction.\n transactionId: next.transactionId,\n // Accumulate actions: current action first, then later ones.\n actions: [action, ...next.actions],\n // Merge outgoingActions in order.\n outgoingActions: [...curr.outgoingActions, ...next.outgoingActions],\n // Batched transaction IDs: preserve order by placing curr first.\n batchedTransactionIds: [curr.transactionId, ...next.batchedTransactionIds],\n // Merge outgoingMutations in order.\n outgoingMutations: [...curr.outgoingMutations, ...next.outgoingMutations],\n // Working state reflects the latest optimistic changes: later transactions override earlier.\n working: {...curr.working, ...next.working},\n // Base state (base, previous, previousRevs) must reflect the original state.\n // Use curr values (the earliest transaction) to override later ones.\n previousRevs: {...next.previousRevs, ...curr.previousRevs},\n previous: {...next.previous, ...curr.previous},\n base: {...next.base, ...curr.base},\n // Use the earliest timestamp from curr.\n timestamp: curr.timestamp ?? next.timestamp,\n }\n}\n\nexport function transitionAppliedTransactionsToOutgoing(\n prev: SyncTransactionState,\n): SyncTransactionState {\n if (prev.outgoing) return prev\n\n const transaction = batchAppliedTransactions(prev.applied)\n if (!transaction) return prev\n\n const {\n transactionId,\n previousRevs,\n working,\n batchedTransactionIds: consumedTransactions,\n } = transaction\n const timestamp = new Date().toISOString()\n\n return {\n ...prev,\n outgoing: transaction,\n applied: prev.applied.filter((i) => !consumedTransactions.includes(i.transactionId)),\n documentStates: Object.entries(previousRevs).reduce(\n (acc, [documentId, previousRev]) => {\n if (working[documentId]?._rev === previousRev) return acc\n\n const documentState = prev.documentStates[documentId]\n if (!documentState) return acc\n\n acc[documentId] = {\n ...documentState,\n unverifiedRevisions: {\n ...documentState.unverifiedRevisions,\n // add unverified revision\n [transactionId]: {documentId, previousRev, transactionId, timestamp},\n },\n }\n\n return acc\n },\n {...prev.documentStates},\n ),\n }\n}\n\nexport function cleanupOutgoingTransaction(prev: SyncTransactionState): SyncTransactionState {\n const {outgoing} = prev\n if (!outgoing) return prev\n\n let next = prev\n const ids = getDocumentIdsFromActions(outgoing.actions)\n for (const transactionId of outgoing.batchedTransactionIds) {\n for (const documentId of ids) {\n next = removeSubscriptionIdFromDocument(next, documentId, transactionId)\n }\n }\n\n return {...next, outgoing: undefined}\n}\n\nexport function revertOutgoingTransaction(prev: SyncTransactionState): SyncTransactionState {\n if (!prev.grants) return prev\n let working = Object.fromEntries(\n Object.entries(prev.documentStates).map(([documentId, documentState]) => [\n documentId,\n documentState?.remote,\n ]),\n )\n const nextApplied: AppliedTransaction[] = []\n\n for (const t of prev.applied) {\n try {\n const next = processActions({...t, working, grants: prev.grants})\n working = next.working\n nextApplied.push({...t, ...next})\n } catch (error) {\n // if we're already reverting a transaction, skip any applied actions if\n // they throw while we rebuild the state\n if (error instanceof ActionError) continue\n throw error\n }\n }\n\n return {\n ...prev,\n applied: nextApplied,\n outgoing: undefined,\n documentStates: Object.fromEntries(\n Object.entries(prev.documentStates)\n .filter((e): e is [string, DocumentState] => !!e[1])\n .map(([documentId, {unverifiedRevisions = {}, local, ...documentState}]) => {\n const next: DocumentState = {\n ...documentState,\n local: documentId in working ? working[documentId] : local,\n unverifiedRevisions:\n prev.outgoing && prev.outgoing.transactionId in unverifiedRevisions\n ? omit(unverifiedRevisions, prev.outgoing.transactionId)\n : unverifiedRevisions,\n }\n return [documentId, next] as const\n }),\n ),\n }\n}\n\nexport function applyRemoteDocument(\n prev: SyncTransactionState,\n {document, documentId, previousRev, revision, timestamp, type}: RemoteDocument,\n events: DocumentStoreState['events'],\n): SyncTransactionState {\n if (!prev.grants) return prev\n const prevDocState = prev.documentStates[documentId]\n\n // document state is deleted when there are no more subscribers so we can\n // simply skip if there is no state\n if (!prevDocState) return prev\n\n // we send out transactions with IDs generated client-side to identify them\n // when they are observed through the listener. here we can check if this\n // incoming remote document is the result of one of our transactions\n const prevUnverifiedRevisions = prevDocState.unverifiedRevisions\n const revisionToVerify = revision ? prevUnverifiedRevisions?.[revision] : undefined\n let unverifiedRevisions = prevUnverifiedRevisions ?? EMPTY_REVISIONS\n if (revision && revisionToVerify) {\n unverifiedRevisions = omit(prevUnverifiedRevisions, revision)\n }\n\n // if this remote document is from a `'sync'` event (meaning that the whole\n // thing was just fetched and not re-created from mutations)\n if (type === 'sync') {\n // then remove unverified revisions that are older than our sync time. we\n // don't need to verify them for a rebase any more because we synced and\n // grabbed the latest document\n unverifiedRevisions = Object.fromEntries(\n Object.entries(unverifiedRevisions).filter(([, unverifiedRevision]) => {\n if (!unverifiedRevision) return false\n return new Date(timestamp).getTime() <= new Date(unverifiedRevision.timestamp).getTime()\n }),\n )\n }\n\n // if there is a revision to verify and the previous revision from remote\n // matches the previous revision we expected, we can \"fast-forward\" and skip\n // rebasing local changes on top of this new base\n if (revisionToVerify && revisionToVerify.previousRev === previousRev) {\n return {\n ...prev,\n documentStates: {\n ...prev.documentStates,\n [documentId]: {\n ...prevDocState,\n remote: document,\n remoteRev: revision,\n unverifiedRevisions,\n },\n },\n }\n }\n\n // if we got this far, this means that we could not fast-forward this revision\n // for this document. now we can rebase our local changes (if any) on top of\n // this new base from remote. in order to do that we grab the set of documents\n // captured before the earliest local transaction\n const previous = prev.applied.at(0)?.previous\n // our initial working set now is the state of the documents before any of our\n // local transactions plus the newly updated document from remote\n let working = {...previous, [documentId]: document}\n const nextApplied: AppliedTransaction[] = []\n\n // now we can iterate through our applied (but not yet committed) transactions\n // starting with the updated working set and re-apply each transaction in\n // order creating a new set of applied transactions as we go.\n //\n // NOTE: we don't want to rebase over the outgoing transaction because that\n // transaction is already on its way to the server. if an outgoing transaction\n // needs to be rebased, then it eventually will be when we see that\n // transaction again through the listener and this same flow will run then\n for (const curr of prev.applied) {\n try {\n const next = processActions({...curr, working, grants: prev.grants})\n working = next.working\n // next includes an updated `previous` set and `working` set and updates\n // the `outgoingAction` and `outgoingMutations`. the `base` set from the\n // original applied transaction gets put back into the updated transaction\n // as-is to preserve the intended base for a 3-way merge\n nextApplied.push({...curr, ...next})\n } catch (error) {\n // if processing the action ever throws a related error, we can skip this\n // local transaction and report the error to the user\n if (error instanceof ActionError) {\n events.next({\n type: 'rebase-error',\n transactionId: error.transactionId,\n documentId: error.documentId,\n message: error.message,\n error,\n })\n continue\n }\n throw error\n }\n }\n\n return {\n ...prev,\n applied: nextApplied,\n documentStates: {\n ...prev.documentStates,\n [documentId]: {\n ...prevDocState,\n remote: document,\n remoteRev: revision,\n local: working[documentId],\n unverifiedRevisions,\n },\n },\n }\n}\n\nexport function addSubscriptionIdToDocument(\n prev: SyncTransactionState,\n documentId: string,\n subscriptionId: string,\n): SyncTransactionState {\n const prevDocState = prev.documentStates?.[documentId]\n const prevSubscriptions = prevDocState?.subscriptions ?? []\n\n return {\n ...prev,\n documentStates: {\n ...prev.documentStates,\n [documentId]: {\n ...prevDocState,\n id: documentId,\n subscriptions: [...prevSubscriptions, subscriptionId],\n },\n },\n }\n}\n\nexport function removeSubscriptionIdFromDocument(\n prev: SyncTransactionState,\n documentId: string,\n subscriptionId: string,\n): SyncTransactionState {\n const prevDocState = prev.documentStates?.[documentId]\n const prevSubscriptions = prevDocState?.subscriptions ?? []\n const subscriptions = prevSubscriptions.filter((id) => id !== subscriptionId)\n\n if (!prevDocState) return prev\n if (!subscriptions.length) {\n return {...prev, documentStates: omit(prev.documentStates, documentId)}\n }\n return {\n ...prev,\n documentStates: {\n ...prev.documentStates,\n [documentId]: {...prevDocState, subscriptions: subscriptions},\n },\n }\n}\n\nexport function manageSubscriberIds(\n {state}: StoreContext<SyncTransactionState>,\n documentId: string | string[],\n options?: {expandDraftPublished?: boolean},\n): () => void {\n const expandDraftPublished = options?.expandDraftPublished ?? true\n const documentIds = Array.from(\n new Set(\n expandDraftPublished\n ? (Array.isArray(documentId) ? documentId : [documentId]).flatMap((id) => [\n getPublishedId(id),\n getDraftId(id),\n ])\n : Array.isArray(documentId)\n ? documentId\n : [documentId],\n ),\n )\n const subscriptionId = insecureRandomId()\n state.set('addSubscribers', (prev) =>\n documentIds.reduce(\n (acc, id) => addSubscriptionIdToDocument(acc, id, subscriptionId),\n prev as SyncTransactionState,\n ),\n )\n\n return () => {\n setTimeout(() => {\n state.set('removeSubscribers', (prev) =>\n documentIds.reduce(\n (acc, id) => removeSubscriptionIdFromDocument(acc, id, subscriptionId),\n prev as SyncTransactionState,\n ),\n )\n }, DOCUMENT_STATE_CLEAR_DELAY)\n }\n}\n\nexport function getDocumentIdsFromActions(actions: DocumentAction[]): string[] {\n return Array.from(\n new Set(\n actions\n .map((i) => i.documentId)\n .filter((i) => typeof i === 'string')\n .flatMap((documentId) => [getPublishedId(documentId), getDraftId(documentId)]),\n ),\n )\n}\n","import {type SanityClient} from '@sanity/client'\n\nimport {type DocumentAction} from './actions'\nimport {type OutgoingTransaction} from './reducers'\n\n/** @beta */\nexport type DocumentEvent =\n | ActionErrorEvent\n | TransactionRevertedEvent\n | TransactionAcceptedEvent\n | DocumentRebaseErrorEvent\n | DocumentEditedEvent\n | DocumentCreatedEvent\n | DocumentDeletedEvent\n | DocumentPublishedEvent\n | DocumentUnpublishedEvent\n | DocumentDiscardedEvent\n\n/**\n * @beta\n * Event emitted when a precondition to applying an action fails.\n * (For example: when trying to edit a document that no longer exists.)\n */\nexport interface ActionErrorEvent {\n type: 'error'\n documentId: string\n transactionId: string\n message: string\n error: unknown\n}\n/**\n * @beta\n * Event emitted when a transaction is accepted.\n */\nexport interface TransactionAcceptedEvent {\n type: 'accepted'\n outgoing: OutgoingTransaction\n result: Awaited<ReturnType<SanityClient['action']>>\n}\n/**\n * @beta\n * Event emitted when a transaction is reverted.\n */\nexport interface TransactionRevertedEvent {\n type: 'reverted'\n message: string\n error: unknown\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when an attempt to apply local changes to a modified remote document fails.\n */\nexport interface DocumentRebaseErrorEvent {\n type: 'rebase-error'\n documentId: string\n transactionId: string\n message: string\n error: unknown\n}\n/**\n * @beta\n * Event emitted when a document is edited.\n */\nexport interface DocumentEditedEvent {\n type: 'edited'\n documentId: string\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when a document is created.\n */\nexport interface DocumentCreatedEvent {\n type: 'created'\n documentId: string\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when a document is deleted.\n */\nexport interface DocumentDeletedEvent {\n type: 'deleted'\n documentId: string\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when a document is published.\n */\nexport interface DocumentPublishedEvent {\n type: 'published'\n documentId: string\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when a document is unpublished.\n */\nexport interface DocumentUnpublishedEvent {\n type: 'unpublished'\n documentId: string\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when a document version is discarded.\n */\nexport interface DocumentDiscardedEvent {\n type: 'discarded'\n documentId: string\n outgoing: OutgoingTransaction\n}\n\nexport function getDocumentEvents(outgoing: OutgoingTransaction): DocumentEvent[] {\n const documentIdsByAction = Object.entries(\n outgoing.actions.reduce(\n (acc, {type, documentId}) => {\n const ids = acc[type] || new Set()\n if (documentId) ids.add(documentId)\n acc[type] = ids\n return acc\n },\n {} as Record<DocumentAction['type'], Set<string>>,\n ),\n ) as [DocumentAction['type'], Set<string>][]\n\n const actionMap = {\n 'document.create': 'created',\n 'document.delete': 'deleted',\n 'document.discard': 'discarded',\n 'document.edit': 'edited',\n 'document.publish': 'published',\n 'document.unpublish': 'unpublished',\n } satisfies Record<DocumentAction['type'], DocumentEvent['type']>\n\n return documentIdsByAction.flatMap(([actionType, documentIds]) =>\n Array.from(documentIds).map(\n (documentId): DocumentEvent => ({type: actionMap[actionType], documentId, outgoing}),\n ),\n )\n}\n","import {type ListenEvent, type SanityDocument} from '@sanity/client'\nimport {createDocumentLoaderFromClient} from '@sanity/mutate/_unstable_store'\nimport {\n first,\n map,\n merge,\n Observable,\n partition,\n share,\n shareReplay,\n Subject,\n switchMap,\n takeUntil,\n} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {type DocumentResource} from '../config/sanityConfig'\nimport {type SanityInstance} from '../store/createSanityInstance'\n\nconst API_VERSION = 'v2025-05-06'\n\nexport interface SharedListener {\n events: Observable<ListenEvent<SanityDocument>>\n dispose: () => void\n}\n\nexport function createSharedListener(\n instance: SanityInstance,\n resource: DocumentResource,\n): SharedListener {\n const dispose$ = new Subject<void>()\n const events$ = getClientState(instance, {\n apiVersion: API_VERSION,\n ...(resource ? {resource} : {}),\n }).observable.pipe(\n switchMap((client) =>\n // TODO: it seems like the client.listen method is not emitting disconnected\n // events. this is important to ensure we have an up to date version of the\n // doc. probably should introduce our own events for when the user goes offline\n client.listen(\n '*',\n {},\n {\n events: ['mutation', 'welcome', 'reconnect'],\n includeResult: false,\n tag: 'document-listener',\n // // from manual testing, it seems like mendoza patches may be\n // // causing some ambiguity/wonkiness\n // includeMutations: false,\n // effectFormat: 'mendoza',\n },\n ),\n ),\n takeUntil(dispose$),\n share(),\n )\n\n const [welcome$, mutation$] = partition(events$, (e) => e.type === 'welcome')\n\n return {\n events: merge(\n // we replay the welcome event because that event kicks off fetching the document\n welcome$.pipe(shareReplay(1)),\n mutation$,\n ),\n dispose: () => dispose$.next(),\n }\n}\n\nexport function createFetchDocument(instance: SanityInstance, resource: DocumentResource) {\n return function (documentId: string): Observable<SanityDocument | null> {\n return getClientState(instance, {apiVersion: API_VERSION, resource}).observable.pipe(\n switchMap((client) => {\n // TODO: remove this once the client is updated to v7 the new type is available in @sanity/mutate/_unstable_store\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const loadDocument = createDocumentLoaderFromClient(client as any)\n return loadDocument(documentId)\n }),\n map((result) => {\n if (!result.accessible) {\n if (result.reason === 'existence') return null\n throw new Error(`Document with ID \\`${documentId}\\` is inaccessible due to permissions.`)\n }\n return result.document as SanityDocument\n }),\n first(),\n )\n }\n}\n","import {type Action} from '@sanity/client'\nimport {getPublishedId} from '@sanity/client/csm'\nimport {jsonMatch} from '@sanity/json-match'\nimport {type SanityDocument} from '@sanity/types'\nimport {type ExprNode} from 'groq-js'\nimport {\n catchError,\n concatMap,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n groupBy,\n map,\n mergeMap,\n Observable,\n of,\n pairwise,\n startWith,\n Subject,\n switchMap,\n tap,\n throttle,\n timer,\n withLatestFrom,\n} from 'rxjs'\n\nimport {type ClientOptions, getClientState} from '../client/clientStore'\nimport {\n type DocumentHandle,\n type DocumentResource,\n isCanvasResource,\n isDatasetResource,\n isMediaLibraryResource,\n} from '../config/sanityConfig'\nimport {\n bindActionByResource,\n type BoundResourceKey,\n type StoreAction,\n} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {createStateSourceAction, type StateSource} from '../store/createStateSourceAction'\nimport {defineStore, type StoreContext} from '../store/defineStore'\nimport {getDraftId} from '../utils/ids'\nimport {type DocumentAction} from './actions'\nimport {API_VERSION, INITIAL_OUTGOING_THROTTLE_TIME} from './documentConstants'\nimport {type DocumentEvent, getDocumentEvents} from './events'\nimport {listen, OutOfSyncError} from './listen'\nimport {\n calculatePermissions,\n createGrantsLookup,\n type DatasetAcl,\n type DocumentPermissionsResult,\n type Grant,\n} from './permissions'\nimport {ActionError} from './processActions'\nimport {\n type AppliedTransaction,\n applyFirstQueuedTransaction,\n applyRemoteDocument,\n cleanupOutgoingTransaction,\n getDocumentIdsFromActions,\n manageSubscriberIds,\n type OutgoingTransaction,\n type QueuedTransaction,\n removeQueuedTransaction,\n revertOutgoingTransaction,\n transitionAppliedTransactionsToOutgoing,\n type UnverifiedDocumentRevision,\n} from './reducers'\nimport {createFetchDocument, createSharedListener, type SharedListener} from './sharedListener'\n\nexport interface DocumentStoreState {\n documentStates: {[TDocumentId in string]?: DocumentState}\n queued: QueuedTransaction[]\n applied: AppliedTransaction[]\n outgoing?: OutgoingTransaction\n grants?: Record<Grant, ExprNode>\n error?: unknown\n sharedListener: SharedListener\n fetchDocument: (documentId: string) => Observable<SanityDocument | null>\n events: Subject<DocumentEvent>\n}\n\nexport interface DocumentState {\n id: string\n /**\n * the \"remote\" local copy that matches the server. represents the last known\n * server state. this gets updated every time we confirm remote patches\n */\n remote?: SanityDocument | null\n /**\n * the current ephemeral working copy that includes local optimistic changes\n * that have not yet been confirmed by the server\n */\n local?: SanityDocument | null\n /**\n * the revision that our remote document is at\n */\n remoteRev?: string | null\n /**\n * Array of subscription IDs. This document state will be deleted if there are\n * no subscribers.\n */\n subscriptions: string[]\n /**\n * An object keyed by transaction ID of revisions sent out but that have not\n * yet been verified yet. When an applied transaction is transitioned to an\n * outgoing transaction, it also adds unverified revisions for each document\n * that is part of that outgoing transaction. Transactions are submitted to\n * the server with a locally generated transaction ID. This way we can observe\n * when our transaction comes back through the shared listener. Each listener\n * event that comes back contains a `previousRev`. If we see our own\n * transaction with a different `previousRev` than expected, we can rebase our\n * local transactions on top of this new remote.\n */\n unverifiedRevisions?: {[TTransactionId in string]?: UnverifiedDocumentRevision}\n}\n\nexport const documentStore = defineStore<DocumentStoreState, BoundResourceKey>({\n name: 'Document',\n getInitialState: (instance, {resource}) => ({\n documentStates: {},\n // these can be emptied on refetch\n queued: [],\n applied: [],\n sharedListener: createSharedListener(instance, resource),\n fetchDocument: createFetchDocument(instance, resource),\n events: new Subject(),\n }),\n initialize(context) {\n const {sharedListener} = context.state.get()\n const subscriptions = [\n subscribeToQueuedAndApplyNextTransaction(context),\n subscribeToSubscriptionsAndListenToDocuments(context),\n subscribeToAppliedAndSubmitNextTransaction(context),\n subscribeToClientAndFetchDatasetAcl(context),\n ]\n\n return () => {\n sharedListener.dispose()\n subscriptions.forEach((subscription) => subscription.unsubscribe())\n }\n },\n})\n\n/**\n * @beta\n * Options for specifying a document and optionally a path within it.\n */\nexport interface DocumentOptions<\n TPath extends string | undefined = undefined,\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n path?: TPath\n}\n\n/** @beta */\nexport function getDocumentState<TData>(\n instance: SanityInstance,\n options: DocumentOptions<string | undefined>,\n): StateSource<TData | undefined | null>\n\n/** @beta */\nexport function getDocumentState(\n ...args: Parameters<typeof _getDocumentState>\n): StateSource<unknown> {\n return _getDocumentState(...args)\n}\n\nconst _getDocumentState = bindActionByResource(\n documentStore,\n createStateSourceAction({\n selector: ({state: {error, documentStates}}, options: DocumentOptions<string | undefined>) => {\n const {documentId, path, liveEdit} = options\n if (error) throw error\n\n if (liveEdit) {\n // For liveEdit documents, only look at the single document\n const document = documentStates[documentId]?.local\n if (document === undefined) return undefined\n if (!path) return document\n const result = jsonMatch(document, path).next()\n if (result.done) return undefined\n const {value} = result.value\n return value\n }\n\n // Standard draft/published logic\n const draftId = getDraftId(documentId)\n const publishedId = getPublishedId(documentId)\n const draft = documentStates[draftId]?.local\n const published = documentStates[publishedId]?.local\n\n // wait for draft and published to be loaded before returning a value\n if (draft === undefined || published === undefined) return undefined\n const document = draft ?? published\n if (!path) return document\n const result = jsonMatch(document, path).next()\n if (result.done) return undefined\n const {value} = result.value\n return value\n },\n onSubscribe: (context, options: DocumentOptions<string | undefined>) =>\n manageSubscriberIds(context, options.documentId, {expandDraftPublished: !options.liveEdit}),\n }),\n)\n\n/** @beta */\nexport function resolveDocument<TData extends SanityDocument>(\n instance: SanityInstance,\n docHandle: DocumentHandle,\n): Promise<TData | null>\n/** @beta */\nexport function resolveDocument(\n instance: SanityInstance,\n docHandle: DocumentHandle,\n): Promise<SanityDocument | null>\n/** @beta */\nexport function resolveDocument(\n ...args: Parameters<typeof _resolveDocument>\n): Promise<SanityDocument | null> {\n return _resolveDocument(...args)\n}\nconst _resolveDocument = bindActionByResource(\n documentStore,\n ({instance}, docHandle: DocumentHandle<string, string, string>) => {\n return firstValueFrom(\n getDocumentState(instance, {\n ...docHandle,\n path: undefined,\n }).observable.pipe(filter((i) => i !== undefined)),\n ) as Promise<SanityDocument | null>\n },\n)\n\n/** @beta */\nexport const getDocumentSyncStatus = bindActionByResource(\n documentStore,\n createStateSourceAction({\n selector: (\n {state: {error, documentStates: documents, outgoing, applied, queued}},\n doc: DocumentHandle,\n ) => {\n const documentId = typeof doc === 'string' ? doc : doc.documentId\n if (error) throw error\n\n if (doc.liveEdit) {\n // For liveEdit documents, only check the single document\n const document = documents[documentId]\n if (document === undefined) return undefined\n return !queued.length && !applied.length && !outgoing\n }\n\n // Standard draft/published logic\n const draftId = getDraftId(documentId)\n const publishedId = getPublishedId(documentId)\n\n const draft = documents[draftId]\n const published = documents[publishedId]\n\n if (draft === undefined || published === undefined) return undefined\n return !queued.length && !applied.length && !outgoing\n },\n onSubscribe: (context, doc: DocumentHandle) => manageSubscriberIds(context, doc.documentId),\n }),\n)\n\ntype PermissionsStateOptions = {\n resource: DocumentResource\n actions: DocumentAction[]\n}\n\n/** @beta */\nexport const getPermissionsState = bindActionByResource(\n documentStore,\n createStateSourceAction({\n selector: calculatePermissions,\n onSubscribe: (context, {actions}: PermissionsStateOptions) =>\n manageSubscriberIds(context, getDocumentIdsFromActions(actions)),\n }) as StoreAction<\n DocumentStoreState,\n [PermissionsStateOptions],\n StateSource<DocumentPermissionsResult>\n >,\n)\n\n/** @beta */\nexport const resolvePermissions = bindActionByResource(\n documentStore,\n ({instance}, options: PermissionsStateOptions) => {\n return firstValueFrom(\n getPermissionsState(instance, options).observable.pipe(filter((i) => i !== undefined)),\n )\n },\n)\n\n/** @beta */\nexport const subscribeDocumentEvents = bindActionByResource(\n documentStore,\n ({state}, options: {resource: DocumentResource; eventHandler: (e: DocumentEvent) => void}) => {\n const {events} = state.get()\n const subscription = events.subscribe(options.eventHandler)\n return () => subscription.unsubscribe()\n },\n)\n\nconst subscribeToQueuedAndApplyNextTransaction = ({\n state,\n}: StoreContext<DocumentStoreState, BoundResourceKey>) => {\n const {events} = state.get()\n return state.observable\n .pipe(\n map(applyFirstQueuedTransaction),\n distinctUntilChanged(),\n tap((next) => state.set('applyFirstQueuedTransaction', next)),\n catchError((error, caught) => {\n if (error instanceof ActionError) {\n state.set('removeQueuedTransaction', (prev) =>\n removeQueuedTransaction(prev, error.transactionId),\n )\n events.next({\n type: 'error',\n message: error.message,\n documentId: error.documentId,\n transactionId: error.transactionId,\n error,\n })\n return caught\n }\n\n throw error\n }),\n )\n .subscribe({error: (error) => state.set('setError', {error})})\n}\n\nconst subscribeToAppliedAndSubmitNextTransaction = ({\n state,\n instance,\n key: {resource},\n}: StoreContext<DocumentStoreState, BoundResourceKey>) => {\n const {events} = state.get()\n\n return state.observable\n .pipe(\n throttle(\n (s) =>\n // if there is no outgoing transaction, we can throttle by the\n // initial outgoing throttle time…\n !s.outgoing\n ? timer(INITIAL_OUTGOING_THROTTLE_TIME)\n : // …otherwise, wait until the outgoing has been cleared\n state.observable.pipe(first(({outgoing}) => !outgoing)),\n {leading: false, trailing: true},\n ),\n map(transitionAppliedTransactionsToOutgoing),\n distinctUntilChanged((a, b) => a.outgoing?.transactionId === b.outgoing?.transactionId),\n tap((next) => state.set('transitionAppliedTransactionsToOutgoing', next)),\n map((s) => s.outgoing),\n distinctUntilChanged(),\n withLatestFrom(\n getClientState(instance, {\n apiVersion: API_VERSION,\n ...(resource ? {resource} : {}),\n }).observable,\n ),\n concatMap(([outgoing, client]) => {\n if (!outgoing) return EMPTY\n return client.observable\n .action(outgoing.outgoingActions as Action[], {\n transactionId: outgoing.transactionId,\n skipCrossDatasetReferenceValidation: true,\n })\n .pipe(\n catchError((error) => {\n state.set('revertOutgoingTransaction', revertOutgoingTransaction)\n events.next({type: 'reverted', message: error.message, outgoing, error})\n return EMPTY\n }),\n map((result) => ({result, outgoing})),\n )\n }),\n tap(({outgoing, result}) => {\n state.set('cleanupOutgoingTransaction', cleanupOutgoingTransaction)\n for (const e of getDocumentEvents(outgoing)) events.next(e)\n events.next({type: 'accepted', outgoing, result})\n }),\n )\n .subscribe({error: (error) => state.set('setError', {error})})\n}\n\nconst subscribeToSubscriptionsAndListenToDocuments = (\n context: StoreContext<DocumentStoreState, BoundResourceKey>,\n) => {\n const {state} = context\n const {events} = state.get()\n\n return state.observable\n .pipe(\n filter((s) => !!s.grants),\n map((s) => Object.keys(s.documentStates)),\n distinctUntilChanged((curr, next) => {\n if (curr.length !== next.length) return false\n const currSet = new Set(curr)\n return next.every((i) => currSet.has(i))\n }),\n startWith(new Set<string>()),\n pairwise(),\n switchMap((pair) => {\n const [curr, next] = pair.map((ids) => new Set(ids))\n const added = Array.from(next).filter((i) => !curr.has(i))\n const removed = Array.from(curr).filter((i) => !next.has(i))\n\n // NOTE: the order of which these go out is somewhat important\n // because that determines the order `applyRemoteDocument` is called\n // which in turn determines which document version get populated\n // first. because we prefer drafts, it's better to have those go out\n // first so that the published document doesn't flash for a frame\n const changes = [\n ...added.map((id) => ({id, add: true})),\n ...removed.map((id) => ({id, add: false})),\n ].sort((a, b) => {\n const aIsDraft = a.id === getDraftId(a.id)\n const bIsDraft = b.id === getDraftId(b.id)\n\n if (aIsDraft && bIsDraft) return a.id.localeCompare(b.id, 'en-US')\n if (aIsDraft) return -1\n if (bIsDraft) return 1\n return a.id.localeCompare(b.id, 'en-US')\n })\n\n return of<{id: string; add: boolean}[]>(...changes)\n }),\n groupBy((i) => i.id),\n mergeMap((group) =>\n group.pipe(\n switchMap((e) => {\n if (!e.add) return EMPTY\n return listen(context, e.id).pipe(\n catchError((error) => {\n // retry on `OutOfSyncError`\n if (error instanceof OutOfSyncError) listen(context, e.id)\n throw error\n }),\n tap((remote) =>\n state.set('applyRemoteDocument', (prev) =>\n applyRemoteDocument(prev, remote, events),\n ),\n ),\n )\n }),\n ),\n ),\n )\n .subscribe({error: (error) => state.set('setError', {error})})\n}\n\nconst subscribeToClientAndFetchDatasetAcl = ({\n instance,\n state,\n key: {resource},\n}: StoreContext<DocumentStoreState, BoundResourceKey>) => {\n const clientOptions: ClientOptions = {apiVersion: API_VERSION}\n if (resource) {\n clientOptions.resource = resource\n }\n\n let uri: string\n if (resource && isDatasetResource(resource)) {\n uri = `/projects/${resource.projectId}/datasets/${resource.dataset}/acl`\n } else if (resource && isMediaLibraryResource(resource)) {\n uri = `/media-libraries/${resource.mediaLibraryId}/acl`\n } else if (resource && isCanvasResource(resource)) {\n uri = `/canvases/${resource.canvasId}/acl`\n } else {\n throw new Error(`Received invalid resource: ${JSON.stringify(resource)}`)\n }\n\n return getClientState(instance, clientOptions)\n .observable.pipe(\n switchMap((client) =>\n client.observable.request<DatasetAcl>({\n uri,\n tag: 'acl.get',\n withCredentials: true,\n }),\n ),\n tap((datasetAcl) => state.set('setGrants', {grants: createGrantsLookup(datasetAcl)})),\n )\n .subscribe({\n error: (error) => state.set('setError', {error}),\n })\n}\n","import {type SanityClient} from '@sanity/client'\nimport {type SanityDocument} from '@sanity/types'\nimport {distinctUntilChanged, filter, first, firstValueFrom, map, race} from 'rxjs'\n\nimport {type DocumentResource} from '../config/sanityConfig'\nimport {bindActionByResource} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {type StoreContext} from '../store/defineStore'\nimport {type DocumentAction} from './actions'\nimport {documentStore, type DocumentStoreState} from './documentStore'\nimport {type DocumentSet} from './processMutations'\nimport {type AppliedTransaction, type QueuedTransaction, queueTransaction} from './reducers'\n\n/** @beta */\nexport interface ActionsResult<TDocument extends SanityDocument = SanityDocument> {\n transactionId: string\n documents: DocumentSet<TDocument>\n previous: DocumentSet<TDocument>\n previousRevs: {[documentId: string]: string | undefined}\n appeared: string[]\n updated: string[]\n disappeared: string[]\n submitted: () => ReturnType<SanityClient['action']>\n}\n\n/** @beta */\nexport interface ApplyDocumentActionsOptions {\n /**\n * List of actions to apply.\n */\n actions: DocumentAction[]\n\n /**\n * The resource to which the documents being acted on belong.\n */\n resource: DocumentResource\n\n /**\n * Optionally provide an ID to be used as this transaction ID\n */\n transactionId?: string\n /**\n * Set this to true to prevent this action from being batched with others.\n */\n disableBatching?: boolean\n}\n\n/** @beta */\nexport function applyDocumentActions(\n instance: SanityInstance,\n options: ApplyDocumentActionsOptions,\n): Promise<ActionsResult>\n\n/** @beta */\nexport function applyDocumentActions(\n ...args: Parameters<typeof boundApplyDocumentActions>\n): ReturnType<typeof boundApplyDocumentActions> {\n return boundApplyDocumentActions(...args)\n}\n\nconst boundApplyDocumentActions = bindActionByResource(documentStore, _applyDocumentActions)\n\n/** @internal */\nasync function _applyDocumentActions(\n {state}: StoreContext<DocumentStoreState>,\n {actions, transactionId = crypto.randomUUID(), disableBatching}: ApplyDocumentActionsOptions,\n): Promise<ActionsResult> {\n const {events} = state.get()\n\n const transaction: QueuedTransaction = {\n transactionId,\n actions,\n ...(disableBatching && {disableBatching}),\n }\n\n const fatalError$ = state.observable.pipe(\n map((s) => s.error),\n first(Boolean),\n map((error) => ({type: 'error', error}) as const),\n )\n\n const transactionError$ = events.pipe(\n filter((e) => e.type === 'error'),\n first((e) => e.transactionId === transactionId),\n )\n\n const appliedTransaction$ = state.observable.pipe(\n map((s) => s.applied),\n distinctUntilChanged(),\n map((applied) => applied.find((t) => t.transactionId === transactionId)),\n first(Boolean),\n )\n\n const successfulTransaction$ = events.pipe(\n filter((e) => e.type === 'accepted'),\n first((e) => e.outgoing.batchedTransactionIds.includes(transactionId)),\n )\n\n const rejectedTransaction$ = events.pipe(\n filter((e) => e.type === 'reverted'),\n first((e) => e.outgoing.batchedTransactionIds.includes(transactionId)),\n )\n\n const appliedTransactionOrError = firstValueFrom(\n race([fatalError$, transactionError$, appliedTransaction$]),\n )\n const acceptedOrRejectedTransaction = firstValueFrom(\n race([successfulTransaction$, rejectedTransaction$, transactionError$]),\n )\n\n state.set('queueTransaction', (prev) => queueTransaction(prev, transaction))\n\n const result = await appliedTransactionOrError\n if ('type' in result && result.type === 'error') throw result.error\n\n const {working: documents, previous, previousRevs} = result as AppliedTransaction\n const existingIds = new Set(\n Object.entries(previous)\n .filter(([, value]) => !!value)\n .map(([key]) => key),\n )\n const resultingIds = new Set(\n Object.entries(documents)\n .filter(([, value]) => !!value)\n .map(([key]) => key),\n )\n const allIds = new Set([...existingIds, ...resultingIds])\n\n const updated: string[] = []\n const appeared: string[] = []\n const disappeared: string[] = []\n\n for (const id of allIds) {\n if (existingIds.has(id) && resultingIds.has(id)) {\n updated.push(id)\n } else if (!existingIds.has(id) && resultingIds.has(id)) {\n appeared.push(id)\n } else if (!resultingIds.has(id) && existingIds.has(id)) {\n disappeared.push(id)\n }\n }\n\n async function submitted() {\n const raceResult = await acceptedOrRejectedTransaction\n if (raceResult.type !== 'accepted') throw raceResult.error\n return raceResult.result\n }\n\n return {\n transactionId,\n documents,\n previous,\n previousRevs,\n appeared,\n updated,\n disappeared,\n submitted,\n }\n}\n","import {\n type CanvasResource,\n type MediaResource,\n SDK_CHANNEL_NAME,\n SDK_NODE_NAME,\n type StudioResource,\n} from '@sanity/message-protocol'\nimport {catchError, filter, from, map, Observable, of, shareReplay, switchMap} from 'rxjs'\n\nimport {getNodeState} from '../comlink/node/getNodeState'\nimport {type DocumentHandle} from '../config/sanityConfig'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {createFetcherStore} from '../utils/createFetcherStore'\n\n/**\n * @public\n */\nexport interface FavoriteStatusResponse {\n isFavorited: boolean\n}\n\n/**\n * @public\n */\ninterface FavoriteDocumentContext extends DocumentHandle {\n resourceId: string\n resourceType: StudioResource['type'] | MediaResource['type'] | CanvasResource['type']\n schemaName?: string\n}\n\n// Helper to create a stable key for the store\nfunction createFavoriteKey(context: FavoriteDocumentContext): string {\n return `${context.documentId}:${context.documentType}:${context.resourceId}:${context.resourceType}${\n context.schemaName ? `:${context.schemaName}` : ''\n }`\n}\n\nconst favorites = createFetcherStore<[FavoriteDocumentContext], FavoriteStatusResponse>({\n name: 'Favorites',\n getKey: (_instance: SanityInstance, context: FavoriteDocumentContext) => {\n return createFavoriteKey(context)\n },\n fetcher: (instance: SanityInstance) => {\n return (context: FavoriteDocumentContext): Observable<FavoriteStatusResponse> => {\n const nodeStateSource = getNodeState(instance, {\n name: SDK_NODE_NAME,\n connectTo: SDK_CHANNEL_NAME,\n })\n const payload = {\n document: {\n id: context.documentId,\n type: context.documentType,\n resource: {\n id: context.resourceId,\n type: context.resourceType,\n schemaName: context.schemaName,\n },\n },\n }\n\n return nodeStateSource.observable.pipe(\n filter((nodeState) => !!nodeState), // Only proceed when connected\n shareReplay(1),\n switchMap((nodeState) => {\n const node = nodeState!.node\n return from(\n node.fetch(\n // @ts-expect-error -- getOrCreateNode should be refactored to take type arguments\n 'dashboard/v1/events/favorite/query',\n payload,\n ) as Promise<FavoriteStatusResponse>,\n ).pipe(\n map((response) => ({isFavorited: response.isFavorited})),\n catchError((err) => {\n // eslint-disable-next-line no-console\n console.error('Favorites service connection error', err)\n return of({isFavorited: false})\n }),\n )\n }),\n )\n }\n },\n})\n\n/**\n * Gets a StateSource for the favorite status of a document.\n * @param instance - The Sanity instance.\n * @param context - The document context including ID, type, and resource information.\n * @returns A StateSource emitting `{ isFavorited: boolean }`.\n * @public\n */\nexport const getFavoritesState = favorites.getState\n\n/**\n * Resolves the favorite status for a document.\n * @param instance - The Sanity instance.\n * @param context - The document context including ID, type, and resource information.\n * @returns A Promise resolving to `{ isFavorited: boolean }`.\n * @public\n */\nexport const resolveFavoritesState = favorites.resolveState\n","// NOTE: currently this API is only available on vX\nexport const API_VERSION = 'vX'\nexport const PROJECT_API_VERSION = '2025-07-18'\nexport const USERS_STATE_CLEAR_DELAY = 5000\nexport const DEFAULT_USERS_BATCH_SIZE = 100\n","import {omit} from 'lodash-es'\n\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {type GetUsersOptions, type SanityUserResponse, type UsersStoreState} from './types'\nimport {DEFAULT_USERS_BATCH_SIZE} from './usersConstants'\n\n/** @internal */\nexport const getUsersKey = (\n _instance: SanityInstance,\n {\n resourceType,\n organizationId,\n batchSize = DEFAULT_USERS_BATCH_SIZE,\n projectId,\n userId,\n }: GetUsersOptions = {},\n): string =>\n JSON.stringify({\n resourceType,\n organizationId,\n batchSize,\n projectId,\n userId,\n } satisfies ReturnType<typeof parseUsersKey>)\n\n/** @internal */\nexport const parseUsersKey = (\n key: string,\n): {\n batchSize: number\n resourceType?: 'organization' | 'project'\n projectId?: string\n organizationId?: string\n userId?: string\n} => JSON.parse(key)\n\nexport const addSubscription =\n (subscriptionId: string, key: string) =>\n (prev: UsersStoreState): UsersStoreState => {\n const group = prev.users[key]\n const subscriptions = [...(group?.subscriptions ?? []), subscriptionId]\n return {...prev, users: {...prev.users, [key]: {...group, subscriptions}}}\n }\n\nexport const removeSubscription =\n (subscriptionId: string, key: string) =>\n (prev: UsersStoreState): UsersStoreState => {\n const group = prev.users[key]\n if (!group) return prev\n const subscriptions = group.subscriptions.filter((id) => id !== subscriptionId)\n if (!subscriptions.length) return {...prev, users: omit(prev.users, key)}\n return {...prev, users: {...prev.users, [key]: {...group, subscriptions}}}\n }\n\nexport const setUsersData =\n (key: string, {data, nextCursor, totalCount}: SanityUserResponse) =>\n (prev: UsersStoreState): UsersStoreState => {\n const group = prev.users[key]\n if (!group) return prev\n const users = [...(group.users ?? []), ...data]\n return {...prev, users: {...prev.users, [key]: {...group, users, totalCount, nextCursor}}}\n }\n\nexport const updateLastLoadMoreRequest =\n (timestamp: string, key: string) =>\n (prev: UsersStoreState): UsersStoreState => {\n const group = prev.users[key]\n if (!group) return prev\n return {...prev, users: {...prev.users, [key]: {...group, lastLoadMoreRequest: timestamp}}}\n }\n\nexport const setUsersError =\n (key: string, error: unknown) =>\n (prev: UsersStoreState): UsersStoreState => {\n const group = prev.users[key]\n if (!group) return prev\n return {...prev, users: {...prev.users, [key]: {...group, error}}}\n }\n\nexport const cancelRequest =\n (key: string) =>\n (prev: UsersStoreState): UsersStoreState => {\n const group = prev.users[key]\n if (!group) return prev\n if (group.subscriptions.length) return prev\n return {...prev, users: omit(prev.users, key)}\n }\n\nexport const initializeRequest =\n (key: string) =>\n (prev: UsersStoreState): UsersStoreState => {\n if (prev.users[key]) return prev\n return {...prev, users: {...prev.users, [key]: {subscriptions: []}}}\n }\n","import {type SanityUser as SanityUserFromClient} from '@sanity/client'\nimport {createSelector} from 'reselect'\nimport {\n catchError,\n combineLatest,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n groupBy,\n map,\n mergeMap,\n NEVER,\n Observable,\n of,\n pairwise,\n race,\n skip,\n startWith,\n switchMap,\n tap,\n throwError,\n withLatestFrom,\n} from 'rxjs'\n\nimport {getDashboardOrganizationId} from '../auth/authStore'\nimport {getClient, getClientState} from '../client/clientStore'\nimport {bindActionGlobally} from '../store/createActionBinder'\nimport {createStateSourceAction, type SelectorContext} from '../store/createStateSourceAction'\nimport {type StoreState} from '../store/createStoreState'\nimport {defineStore, type StoreContext} from '../store/defineStore'\nimport {insecureRandomId} from '../utils/ids'\nimport {\n addSubscription,\n cancelRequest,\n getUsersKey,\n initializeRequest,\n parseUsersKey,\n removeSubscription,\n setUsersData,\n setUsersError,\n updateLastLoadMoreRequest,\n} from './reducers'\nimport {\n type GetUserOptions,\n type GetUsersOptions,\n type ResolveUserOptions,\n type ResolveUsersOptions,\n type SanityUser,\n type SanityUserResponse,\n type UsersStoreState,\n} from './types'\nimport {API_VERSION, PROJECT_API_VERSION, USERS_STATE_CLEAR_DELAY} from './usersConstants'\n\n/** @internal */\nexport type PatchedSanityUserFromClient = Omit<SanityUserFromClient, 'id'> & {\n id: string\n sanityUserId: string\n email: string\n provider: string\n}\n\n/**\n * The users store resource that manages user data fetching and state.\n *\n * This store handles fetching, caching, and managing user data. It provides functionality for\n * retrieving users associated with specific resources and supports pagination through the\n * `loadMoreUsers` action.\n *\n * @internal\n */\nconst usersStore = defineStore<UsersStoreState>({\n name: 'UsersStore',\n getInitialState: () => ({users: {}}),\n initialize: (context) => {\n const subscription = listenForLoadMoreAndFetch(context)\n return () => subscription.unsubscribe()\n },\n})\n\nconst errorHandler =\n (state: StoreState<{error?: unknown}>) =>\n (error: unknown): void =>\n state.set('setError', {error})\n\n/**\n * Internal action that listens for new user subscriptions and load more requests.\n * Fetches user data when new subscriptions are added or when loadMoreUsers is called.\n */\nconst listenForLoadMoreAndFetch = ({state, instance}: StoreContext<UsersStoreState>) => {\n return state.observable\n .pipe(\n map((s) => new Set(Object.keys(s.users))),\n distinctUntilChanged((curr, next) => {\n if (curr.size !== next.size) return false\n return Array.from(next).every((i) => curr.has(i))\n }),\n startWith(new Set<string>()),\n pairwise(),\n mergeMap(([curr, next]) => {\n const added = Array.from(next).filter((i) => !curr.has(i))\n const removed = Array.from(curr).filter((i) => !next.has(i))\n\n return [\n ...added.map((key) => ({key, added: true})),\n ...removed.map((key) => ({key, added: false})),\n ]\n }),\n groupBy((i) => i.key),\n mergeMap((group$) =>\n group$.pipe(\n switchMap((e) => {\n if (!e.added) return EMPTY\n const {userId, batchSize, ...options} = parseUsersKey(group$.key)\n\n if (userId) {\n // In the future we will be able to fetch a user from the global API using the resourceUserId,\n // but for now we need to use the project subdomain to fetch a user if the userId is a project user (starts with \"p\")\n if (userId.startsWith('p')) {\n const client = getClient(instance, {\n apiVersion: PROJECT_API_VERSION,\n // this is a global store, so we need to use the projectId from the options when we're fetching\n // users from a project subdomain\n projectId: options.projectId,\n useProjectHostname: true,\n })\n\n return client.observable\n .request<PatchedSanityUserFromClient>({\n method: 'GET',\n uri: `/users/${userId}`,\n })\n .pipe(\n map((user) => {\n // We need to convert the user to the format we expect\n const convertedUser: SanityUser = {\n sanityUserId: user.sanityUserId,\n profile: {\n id: user.id,\n displayName: user.displayName,\n familyName: user.familyName ?? undefined,\n givenName: user.givenName ?? undefined,\n middleName: user.middleName ?? undefined,\n imageUrl: user.imageUrl ?? undefined,\n createdAt: user.createdAt,\n updatedAt: user.updatedAt,\n isCurrentUser: user.isCurrentUser,\n email: user.email,\n provider: user.provider,\n },\n memberships: [],\n }\n return {\n data: [convertedUser],\n totalCount: 1,\n nextCursor: null,\n }\n }),\n catchError((error) => {\n state.set('setUsersError', setUsersError(group$.key, error))\n return EMPTY\n }),\n tap((response) =>\n state.set('setUsersData', setUsersData(group$.key, response)),\n ),\n )\n }\n\n // Fetch the user from the global API\n const scope = userId.startsWith('g') ? 'global' : undefined\n const client = getClient(instance, {\n scope,\n apiVersion: API_VERSION,\n })\n const resourceType = options.resourceType || 'project'\n const resourceId =\n resourceType === 'organization' ? options.organizationId : options.projectId\n if (!resourceId) {\n return throwError(() => new Error('An organizationId or a projectId is required'))\n }\n return client.observable\n .request<SanityUser | SanityUserResponse>({\n method: 'GET',\n uri: `access/${resourceType}/${resourceId}/users/${userId}`,\n })\n .pipe(\n map((response) => {\n // If the response is a single user object (has sanityUserId), wrap it in the expected format\n if ('sanityUserId' in response) {\n return {\n data: [response],\n totalCount: 1,\n nextCursor: null,\n } as SanityUserResponse\n }\n return response as SanityUserResponse\n }),\n catchError((error) => {\n state.set('setUsersError', setUsersError(group$.key, error))\n return EMPTY\n }),\n tap((response) => state.set('setUsersData', setUsersData(group$.key, response))),\n )\n }\n const projectId = options.projectId\n\n // the resource type this request will use\n // If resourceType is explicitly provided, use it\n // Otherwise, infer from context: organization if organizationId exists,\n // project if projectId exists, or default to organization\n const resourceType =\n options.resourceType ??\n (options.organizationId ? 'organization' : projectId ? 'project' : 'organization')\n\n const organizationId$ = options.organizationId\n ? of(options.organizationId)\n : getDashboardOrganizationId(instance).observable.pipe(\n filter((i) => typeof i === 'string'),\n )\n\n const resource$: Observable<{\n type: 'project' | 'organization'\n id: string\n }> =\n resourceType === 'project'\n ? projectId\n ? of({type: 'project', id: projectId})\n : throwError(() => new Error('Project ID required for this API.'))\n : organizationId$.pipe(map((id) => ({type: 'organization', id})))\n\n const client$ = getClientState(instance, {\n scope: 'global',\n apiVersion: API_VERSION,\n }).observable\n\n const loadMore$ = state.observable.pipe(\n map((s) => s.users[group$.key]?.lastLoadMoreRequest),\n distinctUntilChanged(),\n )\n\n const cursor$ = state.observable.pipe(\n map((s) => s.users[group$.key]?.nextCursor),\n distinctUntilChanged(),\n filter((cursor) => cursor !== null),\n )\n\n return combineLatest([resource$, client$, loadMore$]).pipe(\n withLatestFrom(cursor$),\n switchMap(([[resource, client], cursor]) =>\n client.observable.request<SanityUserResponse>({\n method: 'GET',\n uri: `access/${resource.type}/${resource.id}/users`,\n query: cursor\n ? {nextCursor: cursor, limit: batchSize.toString()}\n : {limit: batchSize.toString()},\n }),\n ),\n catchError((error) => {\n state.set('setUsersError', setUsersError(group$.key, error))\n return EMPTY\n }),\n tap((response) => state.set('setUsersData', setUsersData(group$.key, response))),\n )\n }),\n ),\n ),\n )\n .subscribe({error: errorHandler(state)})\n}\n\n/**\n * Returns the state source for users associated with a specific resource.\n *\n * This function returns a state source that represents the current list of users for a given\n * resource. Subscribing to the state source will instruct the SDK to fetch the users (if not\n * already fetched) and will load more from this state source as well. When the last subscriber is\n * removed, the users state is automatically cleaned up from the store after a delay.\n *\n * Note: This functionality is for advanced users who want to build their own framework\n * integrations. Our SDK also provides a React integration for convenient usage.\n *\n * @beta\n */\nexport const getUsersState = bindActionGlobally(\n usersStore,\n createStateSourceAction({\n selector: createSelector(\n [\n ({instance, state}: SelectorContext<UsersStoreState>, options?: GetUsersOptions) =>\n state.error ?? state.users[getUsersKey(instance, options)]?.error,\n ({instance, state}: SelectorContext<UsersStoreState>, options: GetUsersOptions) =>\n state.users[getUsersKey(instance, options)]?.users,\n ({instance, state}: SelectorContext<UsersStoreState>, options: GetUsersOptions) =>\n state.users[getUsersKey(instance, options)]?.totalCount,\n ({instance, state}: SelectorContext<UsersStoreState>, options: GetUsersOptions) =>\n state.users[getUsersKey(instance, options)]?.nextCursor,\n ],\n (error, data, totalCount, nextCursor) => {\n if (error) throw error\n if (data === undefined || totalCount === undefined || nextCursor === undefined) {\n return undefined\n }\n\n return {data, totalCount, hasMore: nextCursor !== null}\n },\n ),\n onSubscribe: ({instance, state}, options?: GetUsersOptions) => {\n const subscriptionId = insecureRandomId()\n const key = getUsersKey(instance, options)\n state.set('addSubscription', addSubscription(subscriptionId, key))\n return () => {\n setTimeout(\n () => state.set('removeSubscription', removeSubscription(subscriptionId, key)),\n USERS_STATE_CLEAR_DELAY,\n )\n }\n },\n }),\n)\n\n/**\n * Resolves the users for a specific resource without registering a lasting subscriber.\n *\n * This function fetches the users for a given resource and returns a promise that resolves with\n * the users result. Unlike `getUsersState`, which registers subscribers to keep the data live and\n * performs automatic cleanup, `resolveUsers` does not track subscribers. This makes it ideal for\n * use with React Suspense, where the returned promise is thrown to delay rendering until the users\n * result becomes available. Once the promise resolves, it is expected that a real subscriber will\n * be added via `getUsersState` to manage ongoing updates.\n *\n * Additionally, an optional AbortSignal can be provided to cancel the request and immediately\n * clear the associated state if there are no active subscribers.\n *\n * @beta\n */\nexport const resolveUsers = bindActionGlobally(\n usersStore,\n async ({state, instance}, {signal, ...options}: ResolveUsersOptions) => {\n const key = getUsersKey(instance, options)\n const {getCurrent} = getUsersState(instance, options)\n\n const aborted$ = signal\n ? new Observable<never>((observer) => {\n const cleanup = () => {\n signal.removeEventListener('abort', listener)\n }\n\n const listener = () => {\n observer.error(new DOMException('The operation was aborted.', 'AbortError'))\n observer.complete()\n cleanup()\n }\n signal.addEventListener('abort', listener)\n\n return cleanup\n }).pipe(\n catchError((error) => {\n if (error instanceof Error && error.name === 'AbortError') {\n state.set('cancelRequest', cancelRequest(key))\n }\n throw error\n }),\n )\n : NEVER\n\n state.set('initializeRequest', initializeRequest(key))\n\n const resolved$ = state.observable.pipe(\n map(getCurrent),\n first((i) => i !== undefined),\n )\n\n return firstValueFrom(race([resolved$, aborted$]))\n },\n)\n\n/**\n * Loads more users for a specific resource.\n *\n * This function triggers a request to fetch the next page of users for a given resource. It\n * requires that users have already been loaded for the resource (via `resolveUsers` or\n * `getUsersState`), and that there are more users available to load (as indicated by the `hasMore`\n * property).\n *\n * The function returns a promise that resolves when the next page of users has been loaded.\n *\n * @beta\n */\nexport const loadMoreUsers = bindActionGlobally(\n usersStore,\n async ({state, instance}, options?: GetUsersOptions) => {\n const key = getUsersKey(instance, options)\n const users = getUsersState(instance, options)\n const usersState = users.getCurrent()\n if (!usersState) {\n throw new Error('Users not loaded for specified resource. Please call resolveUsers first.')\n }\n\n if (!usersState.hasMore) {\n throw new Error('No more users available to load for this resource.')\n }\n\n const promise = firstValueFrom(\n users.observable.pipe(\n filter((i) => i !== undefined),\n skip(1),\n ),\n )\n\n const timestamp = new Date().toISOString()\n state.set('updateLastLoadMoreRequest', updateLastLoadMoreRequest(timestamp, key))\n\n return await promise\n },\n)\n\n/**\n * @beta\n */\nexport const getUserState = bindActionGlobally(\n usersStore,\n ({instance}, {userId, ...options}: GetUserOptions) => {\n return getUsersState(instance, {userId, ...options}).observable.pipe(\n map((res) => res?.data[0]),\n distinctUntilChanged((a, b) => a?.profile.updatedAt === b?.profile.updatedAt),\n )\n },\n)\n\n/**\n * @beta\n */\nexport const resolveUser = bindActionGlobally(\n usersStore,\n async ({instance}, {signal, ...options}: ResolveUserOptions) => {\n const result = await resolveUsers(instance, {\n signal,\n ...options,\n })\n return result?.data[0]\n },\n)\n","import {type BifurClient, fromUrl} from '@sanity/bifur-client'\nimport {type SanityClient} from '@sanity/client'\nimport {EMPTY, fromEvent, type Observable} from 'rxjs'\nimport {map, share, switchMap} from 'rxjs/operators'\n\nimport {\n type BifurTransportOptions,\n type PresenceLocation,\n type PresenceTransport,\n type TransportEvent,\n type TransportMessage,\n} from './types'\n\ntype BifurStateMessage = {\n type: 'state'\n i: string\n m: {\n sessionId: string\n locations: PresenceLocation[]\n }\n}\n\ntype BifurDisconnectMessage = {\n type: 'disconnect'\n i: string\n m: {session: string}\n}\n\ntype RollCallEvent = {\n type: 'rollCall'\n i: string\n session: string\n}\n\ntype IncomingBifurEvent = RollCallEvent | BifurStateMessage | BifurDisconnectMessage\n\nfunction getBifurClient(client: SanityClient, token$: Observable<string | null>): BifurClient {\n const bifurVersionedClient = client.withConfig({apiVersion: '2022-06-30'})\n const {dataset, url: baseUrl, requestTagPrefix = 'sanity.studio'} = bifurVersionedClient.config()\n const url = `${baseUrl.replace(/\\/+$/, '')}/socket/${dataset}`.replace(/^http/, 'ws')\n const urlWithTag = `${url}?tag=${requestTagPrefix}`\n\n return fromUrl(urlWithTag, {token$})\n}\n\nconst handleIncomingMessage = (event: IncomingBifurEvent): TransportEvent => {\n switch (event.type) {\n case 'rollCall':\n return {\n type: 'rollCall',\n userId: event.i,\n sessionId: event.session,\n }\n case 'state': {\n const {sessionId, locations} = event.m\n return {\n type: 'state',\n userId: event.i,\n sessionId,\n timestamp: new Date().toISOString(),\n locations,\n }\n }\n case 'disconnect':\n return {\n type: 'disconnect',\n userId: event.i,\n sessionId: event.m.session,\n timestamp: new Date().toISOString(),\n }\n default: {\n throw new Error(`Got unknown presence event: ${JSON.stringify(event)}`)\n }\n }\n}\n\nexport const createBifurTransport = (options: BifurTransportOptions): PresenceTransport => {\n const {client, token$, sessionId} = options\n const bifur = getBifurClient(client, token$)\n\n const incomingEvents$: Observable<TransportEvent> = bifur\n .listen<IncomingBifurEvent>('presence')\n .pipe(map(handleIncomingMessage))\n\n const dispatchMessage = (message: TransportMessage): Observable<void> => {\n switch (message.type) {\n case 'rollCall':\n return bifur.request('presence_rollcall', {session: sessionId})\n case 'state':\n return bifur.request('presence_announce', {\n data: {locations: message.locations, sessionId},\n })\n case 'disconnect':\n return bifur.request('presence_disconnect', {session: sessionId})\n default: {\n return EMPTY\n }\n }\n }\n\n if (typeof window !== 'undefined') {\n fromEvent(window, 'beforeunload')\n .pipe(switchMap(() => dispatchMessage({type: 'disconnect'})))\n .subscribe()\n }\n\n return [incomingEvents$.pipe(share()), dispatchMessage]\n}\n","import {createSelector} from 'reselect'\nimport {combineLatest, distinctUntilChanged, filter, map, of, Subscription, switchMap} from 'rxjs'\n\nimport {getTokenState} from '../auth/authStore'\nimport {getClient} from '../client/clientStore'\nimport {isCanvasResource, isDatasetResource, isMediaLibraryResource} from '../config/sanityConfig'\nimport {bindActionByResource, type BoundResourceKey} from '../store/createActionBinder'\nimport {createStateSourceAction, type SelectorContext} from '../store/createStateSourceAction'\nimport {defineStore, type StoreContext} from '../store/defineStore'\nimport {type SanityUser} from '../users/types'\nimport {getUserState} from '../users/usersStore'\nimport {createBifurTransport} from './bifurTransport'\nimport {type PresenceLocation, type TransportEvent, type UserPresence} from './types'\n\ntype PresenceStoreState = {\n locations: Map<string, {userId: string; locations: PresenceLocation[]}>\n users: Record<string, SanityUser | undefined>\n}\n\nconst getInitialState = (): PresenceStoreState => ({\n locations: new Map<string, {userId: string; locations: PresenceLocation[]}>(),\n users: {},\n})\n\n/** @public */\nexport const presenceStore = defineStore<PresenceStoreState, BoundResourceKey>({\n name: 'presence',\n getInitialState,\n initialize: (context: StoreContext<PresenceStoreState, BoundResourceKey>) => {\n const {\n instance,\n state,\n key: {resource},\n } = context\n\n // Presence is only supported for dataset resources\n if (isMediaLibraryResource(resource)) {\n throw new Error(\n 'Presence is not supported for media library resources. Presence tracking requires a dataset resource with a projectId.',\n )\n }\n\n if (isCanvasResource(resource)) {\n throw new Error(\n 'Presence is not supported for canvas resources. Presence tracking requires a dataset resource with a projectId.',\n )\n }\n\n const sessionId = crypto.randomUUID()\n\n const client = getClient(instance, {\n apiVersion: '2022-06-30',\n resource,\n })\n\n const token$ = getTokenState(instance).observable.pipe(distinctUntilChanged())\n\n const [incomingEvents$, dispatch] = createBifurTransport({\n client,\n token$,\n sessionId,\n })\n\n const subscription = new Subscription()\n\n subscription.add(\n incomingEvents$.subscribe((event: TransportEvent) => {\n if ('sessionId' in event && event.sessionId === sessionId) {\n return\n }\n\n if (event.type === 'state') {\n state.set('presence/state', (prevState: PresenceStoreState) => {\n const newLocations = new Map(prevState.locations)\n newLocations.set(event.sessionId, {\n userId: event.userId,\n locations: event.locations,\n })\n\n return {\n ...prevState,\n locations: newLocations,\n }\n })\n } else if (event.type === 'disconnect') {\n state.set('presence/disconnect', (prevState: PresenceStoreState) => {\n const newLocations = new Map(prevState.locations)\n newLocations.delete(event.sessionId)\n return {...prevState, locations: newLocations}\n })\n }\n }),\n )\n\n dispatch({type: 'rollCall'}).subscribe()\n\n return () => {\n dispatch({type: 'disconnect'}).subscribe()\n subscription.unsubscribe()\n }\n },\n})\n\nconst selectLocations = (state: PresenceStoreState) => state.locations\nconst selectUsers = (state: PresenceStoreState) => state.users\n\nconst selectPresence = createSelector(\n selectLocations,\n selectUsers,\n (locations, users): UserPresence[] => {\n return Array.from(locations.entries()).map(([sessionId, {userId, locations: locs}]) => {\n const user = users[userId]\n\n return {\n user:\n user ||\n ({\n id: userId,\n displayName: 'Unknown user',\n name: 'Unknown user',\n email: '',\n } as unknown as SanityUser),\n sessionId,\n locations: locs,\n }\n })\n },\n)\n\n/** @beta */\nexport const getPresence = bindActionByResource(\n presenceStore,\n createStateSourceAction({\n selector: (context: SelectorContext<PresenceStoreState>): UserPresence[] =>\n selectPresence(context.state),\n onSubscribe: (context: StoreContext<PresenceStoreState, BoundResourceKey>) => {\n const userIds$ = context.state.observable.pipe(\n map((state) =>\n Array.from(state.locations.values())\n .map((l) => l.userId)\n .filter((id): id is string => !!id),\n ),\n distinctUntilChanged((a, b) => a.length === b.length && a.every((v, i) => v === b[i])),\n )\n\n const subscription = userIds$\n .pipe(\n switchMap((userIds) => {\n if (userIds.length === 0) {\n return of([])\n }\n const userObservables = userIds.map((userId) =>\n getUserState(context.instance, {\n userId,\n resourceType: 'project',\n projectId:\n context.key.resource && isDatasetResource(context.key.resource)\n ? context.key.resource.projectId\n : undefined,\n }).pipe(filter((v): v is NonNullable<typeof v> => !!v)),\n )\n return combineLatest(userObservables)\n }),\n )\n .subscribe((users) => {\n if (!users) {\n return\n }\n context.state.set('presence/users', (prevState) => ({\n ...prevState,\n users: {\n ...prevState.users,\n ...users.reduce<Record<string, SanityUser>>((acc, user) => {\n if (user) {\n acc[user.profile.id] = user\n }\n return acc\n }, {}),\n },\n }))\n })\n return () => subscription.unsubscribe()\n },\n }),\n)\n","/**\n * The fields to check for a title.\n * The order of the items in the array defines the priority.\n *\n * @internal\n */\nexport const TITLE_CANDIDATES = ['title', 'name', 'label', 'heading', 'header', 'caption']\n\n/**\n * The fields to check for a subtitle.\n * The order of the items in the array defines the priority.\n *\n * @internal\n */\nexport const SUBTITLE_CANDIDATES = ['description', 'subtitle', ...TITLE_CANDIDATES]\n\n/**\n * Generates a GROQ projection for preview data without requiring a schema.\n * Uses common field names to make educated guesses about which fields to use.\n *\n * @internal\n */\nexport const PREVIEW_PROJECTION = `{\n // Get all potential title fields\n \"titleCandidates\": {\n ${TITLE_CANDIDATES.map((field) => `\"${field}\": ${field}`).join(',\\n ')}\n },\n // Get all potential subtitle fields\n \"subtitleCandidates\": {\n ${SUBTITLE_CANDIDATES.map((field) => `\"${field}\": ${field}`).join(',\\n ')}\n },\n \"media\": coalesce(\n select(\n defined(asset) => {\"type\": \"image-asset\", \"_ref\": asset._ref},\n defined(image.asset) => {\"type\": \"image-asset\", \"_ref\": image.asset._ref},\n defined(mainImage.asset) => {\"type\": \"image-asset\", \"_ref\": mainImage.asset._ref},\n null\n )\n ),\n _type,\n _id,\n _updatedAt\n}`\n","import {type SanityClient} from '@sanity/client'\nimport {createImageUrlBuilder} from '@sanity/image-url'\nimport {isObject} from 'lodash-es'\n\nimport {getClient} from '../client/clientStore'\nimport {type DocumentResource} from '../config/sanityConfig'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {SUBTITLE_CANDIDATES, TITLE_CANDIDATES} from './previewConstants'\nimport {type PreviewQueryResult, type PreviewValue} from './types'\n\nconst API_VERSION = 'v2025-05-06'\n\n/**\n * Checks if the provided value has `_ref` property that is a string and starts with `image-`\n */\nfunction hasImageRef<T>(value: unknown): value is T & {_ref: string} {\n return isObject(value) && '_ref' in value && typeof (value as {_ref: unknown})._ref === 'string'\n}\n\n/**\n * Normalizes a media asset to a preview value.\n * Adds a url to a media asset reference using `@sanity/image-url`.\n *\n * @internal\n */\nexport function normalizeMedia(media: unknown, client: SanityClient): PreviewValue['media'] {\n if (!media) return null\n if (!hasImageRef(media)) return null\n\n const builder = createImageUrlBuilder(client)\n const url = builder.image({_ref: media._ref}).url()\n\n return {\n type: 'image-asset',\n _ref: media._ref,\n url,\n }\n}\n\n/**\n * Finds a single field value from a set of candidates based on a priority list of field names.\n * Returns the first non-empty string value found from the candidates matching the priority list order.\n *\n * @internal\n */\nfunction findFirstDefined(\n fieldsToSearch: string[],\n candidates: Record<string, unknown>,\n exclude?: unknown,\n): string | undefined {\n if (!candidates) return undefined\n\n for (const field of fieldsToSearch) {\n const value = candidates[field]\n if (typeof value === 'string' && value.trim() !== '' && value !== exclude) {\n return value\n }\n }\n\n return undefined\n}\n\n/**\n * Transforms a projection result (with titleCandidates, subtitleCandidates, media)\n * into a PreviewValue (with title, subtitle, media).\n *\n * @param projectionResult - The raw projection result from GROQ\n * @param instance - The Sanity instance to use for client configuration\n * @param resource - Data resource for the preview\n * @internal\n */\nexport function transformProjectionToPreview(\n instance: SanityInstance,\n resource: DocumentResource,\n projectionResult: PreviewQueryResult,\n): PreviewValue {\n const title = findFirstDefined(TITLE_CANDIDATES, projectionResult.titleCandidates)\n const subtitle = findFirstDefined(SUBTITLE_CANDIDATES, projectionResult.subtitleCandidates, title)\n\n const client = getClient(instance, {apiVersion: API_VERSION, resource})\n\n return {\n title: String(title || `${projectionResult._type}: ${projectionResult._id}`),\n subtitle: subtitle || undefined,\n media: normalizeMedia(projectionResult.media, client),\n ...(projectionResult._status && {_status: projectionResult._status}),\n }\n}\n","export function hashString(str: string): string {\n // Using a large prime number for the hash\n const PRIME = 31\n // Using a max 32-bit integer to prevent overflow\n const MOD = 2147483647\n\n let hash = 0\n\n // Process chunks of the string to reduce complexity\n for (let i = 0; i < str.length; i++) {\n // Rolling hash computation\n hash = (hash * PRIME + str.charCodeAt(i)) % MOD\n }\n\n // Ensure we return a positive hash\n return Math.abs(hash).toString(16).padStart(8, '0')\n}\n","import {type ReleaseDocument} from '../releasesStore'\n\n// mirrors the order of the releases in the releases list in Studio\n// https://github.com/sanity-io/sanity/blob/main/packages/sanity/src/core/releases/hooks/utils.ts\nexport function sortReleases(releases: ReleaseDocument[] = []): ReleaseDocument[] {\n // The order should always be:\n // [undecided (sortByCreatedAt), scheduled(sortBy publishAt || metadata.intendedPublishAt), asap(sortByCreatedAt)]\n return [...releases].sort((a, b) => {\n // undecided are always first, then by createdAt descending\n if (a.metadata.releaseType === 'undecided' && b.metadata.releaseType !== 'undecided') {\n return -1\n }\n if (a.metadata.releaseType !== 'undecided' && b.metadata.releaseType === 'undecided') {\n return 1\n }\n if (a.metadata.releaseType === 'undecided' && b.metadata.releaseType === 'undecided') {\n // Sort by createdAt\n return new Date(b._createdAt).getTime() - new Date(a._createdAt).getTime()\n }\n\n // Scheduled are always at the middle, then by publishAt descending\n if (a.metadata.releaseType === 'scheduled' && b.metadata.releaseType === 'scheduled') {\n const aPublishAt = a['publishAt'] || a.metadata['intendedPublishAt']\n if (!aPublishAt) {\n return 1\n }\n const bPublishAt = b['publishAt'] || b.metadata['intendedPublishAt']\n if (!bPublishAt) {\n return -1\n }\n return new Date(bPublishAt).getTime() - new Date(aPublishAt).getTime()\n }\n\n // ASAP are always last, then by createdAt descending\n if (a.metadata.releaseType === 'asap' && b.metadata.releaseType !== 'asap') {\n return 1\n }\n if (a.metadata.releaseType !== 'asap' && b.metadata.releaseType === 'asap') {\n return -1\n }\n if (a.metadata.releaseType === 'asap' && b.metadata.releaseType === 'asap') {\n // Sort by createdAt\n return new Date(b._createdAt).getTime() - new Date(a._createdAt).getTime()\n }\n\n return 0\n })\n}\n","import {type SanityDocument} from '@sanity/types'\nimport {map} from 'rxjs'\n\nimport {type DocumentResource} from '../config/sanityConfig'\n/*\n * Although this is an import dependency cycle, it is not a logical cycle:\n * 1. releasesStore uses queryStore as a data source\n * 2. queryStore calls getPerspectiveState for computing release perspectives\n * 3. getPerspectiveState uses releasesStore as a data source\n * 4. however, queryStore does not use getPerspectiveState for the perspective used in releasesStore (\"raw\")\n */\n// eslint-disable-next-line import/no-cycle\nimport {getQueryState} from '../query/queryStore'\nimport {bindActionByResource, type BoundResourceKey} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {createStateSourceAction, type StateSource} from '../store/createStateSourceAction'\nimport {defineStore, type StoreContext} from '../store/defineStore'\nimport {sortReleases} from './utils/sortReleases'\n\nconst ARCHIVED_RELEASE_STATES = ['archived', 'published']\nconst STABLE_EMPTY_RELEASES: ReleaseDocument[] = []\n\n/**\n * Represents a document in a Sanity dataset that represents release options.\n * @internal\n */\nexport type ReleaseDocument = SanityDocument & {\n name: string\n publishAt?: string\n state: 'active' | 'scheduled'\n metadata: {\n title: string\n releaseType: 'asap' | 'scheduled' | 'undecided'\n intendedPublishAt?: string\n description?: string\n }\n}\n\nexport interface ReleasesStoreState {\n activeReleases?: ReleaseDocument[]\n error?: unknown\n}\n\nexport const releasesStore = defineStore<ReleasesStoreState, BoundResourceKey>({\n name: 'Releases',\n getInitialState: (): ReleasesStoreState => ({\n activeReleases: undefined,\n }),\n initialize: (context) => {\n const subscription = subscribeToReleases(context)\n return () => subscription.unsubscribe()\n },\n})\n\n/**\n * Get the active releases from the store.\n * @internal\n */\nconst _getActiveReleasesState = bindActionByResource(\n releasesStore,\n createStateSourceAction({\n selector: ({state}, _?) => state.activeReleases,\n }),\n)\n\n/**\n * Get the active releases from the store.\n * @internal\n */\nexport const getActiveReleasesState = (\n instance: SanityInstance,\n options: {resource: DocumentResource},\n): StateSource<ReleaseDocument[] | undefined> => _getActiveReleasesState(instance, options)\n\nconst RELEASES_QUERY = 'releases::all()'\n\nconst subscribeToReleases = ({\n instance,\n state,\n key: {resource},\n}: StoreContext<ReleasesStoreState, BoundResourceKey>) => {\n const {observable: releases$} = getQueryState<ReleaseDocument[]>(instance, {\n query: RELEASES_QUERY,\n perspective: 'raw',\n resource,\n tag: 'releases',\n })\n return releases$\n .pipe(\n map((releases) => {\n // logic here mirrors that of studio:\n // https://github.com/sanity-io/sanity/blob/156e8fa482703d99219f08da7bacb384517f1513/packages/sanity/src/core/releases/store/useActiveReleases.ts#L29\n state.set('setActiveReleases', {\n activeReleases: sortReleases(releases ?? STABLE_EMPTY_RELEASES)\n .filter((release) => !ARCHIVED_RELEASE_STATES.includes(release.state))\n .reverse(),\n })\n }),\n )\n .subscribe({error: (error) => state.set('setError', {error})})\n}\n","import {createSelector} from 'reselect'\n\nimport {type DocumentResource, type PerspectiveHandle} from '../config/sanityConfig'\nimport {bindActionByResource, type BoundStoreAction} from '../store/createActionBinder'\nimport {createStateSourceAction, type SelectorContext} from '../store/createStateSourceAction'\n/*\n * Although this is an import dependency cycle, it is not a logical cycle:\n * 1. getPerspectiveState uses releasesStore as a data source\n * 2. releasesStore uses queryStore as a data source\n * 3. queryStore calls getPerspectiveState for computing release perspectives\n * 4. however, queryStore does not use getPerspectiveState for the perspective used in releasesStore (\"raw\")\n */\n// eslint-disable-next-line import/no-cycle\nimport {releasesStore, type ReleasesStoreState} from './releasesStore'\nimport {isReleasePerspective} from './utils/isReleasePerspective'\nimport {sortReleases} from './utils/sortReleases'\n\nconst DEFAULT_PERSPECTIVE = 'drafts'\n\n// Cache for options\nconst optionsCache = new Map<string, Map<string, PerspectiveHandle>>()\n\nconst selectInstancePerspective = (context: SelectorContext<ReleasesStoreState>, _?: unknown) =>\n context.instance.config.perspective\nconst selectActiveReleases = (context: SelectorContext<ReleasesStoreState>) =>\n context.state.activeReleases\nconst selectOptions = (\n _context: SelectorContext<ReleasesStoreState>,\n options: PerspectiveHandle & {resource?: DocumentResource},\n) => options\n\nconst memoizedOptionsSelector = createSelector(\n [selectActiveReleases, selectOptions],\n (activeReleases, options) => {\n if (!options || !activeReleases) return options\n\n // Use release document IDs as the cache key\n const releaseIds = activeReleases.map((release) => release._id).join(',')\n let nestedCache = optionsCache.get(releaseIds)\n if (!nestedCache) {\n nestedCache = new Map<string, PerspectiveHandle>()\n optionsCache.set(releaseIds, nestedCache)\n }\n\n const optionsKey = JSON.stringify(options)\n let cachedOptions = nestedCache.get(optionsKey)\n\n if (!cachedOptions) {\n cachedOptions = options\n nestedCache.set(optionsKey, cachedOptions)\n }\n return cachedOptions\n },\n)\n\n// Lazily bind the action itself to avoid circular import initialization issues with `releasesStore`\nconst _getPerspectiveStateSelector = createStateSourceAction({\n selector: createSelector(\n [selectInstancePerspective, selectActiveReleases, memoizedOptionsSelector],\n (instancePerspective, activeReleases, memoizedOptions) => {\n const perspective = memoizedOptions?.perspective ?? instancePerspective ?? DEFAULT_PERSPECTIVE\n\n if (!isReleasePerspective(perspective)) return perspective\n\n // if there are no active releases we can't compute the release perspective\n if (!activeReleases || activeReleases.length === 0) return undefined\n\n const releaseNames = sortReleases(activeReleases).map((release) => release.name)\n const index = releaseNames.findIndex((name) => name === perspective.releaseName)\n\n if (index < 0) {\n throw new Error(`Release \"${perspective.releaseName}\" not found in active releases`)\n }\n\n const filteredReleases = releaseNames.slice(0, index + 1) // Include the release itself\n\n return ['drafts', ...filteredReleases]\n .filter((name) => !perspective.excludedPerspectives?.includes(name))\n .reverse()\n },\n ),\n})\n\ntype OmitFirst<T extends unknown[]> = T extends [unknown, ...infer R] ? R : never\ntype SelectorParams = OmitFirst<Parameters<typeof _getPerspectiveStateSelector>>\ntype BoundGetPerspectiveState = BoundStoreAction<\n ReleasesStoreState,\n SelectorParams,\n ReturnType<typeof _getPerspectiveStateSelector>\n>\n\nlet _boundGetPerspectiveState: BoundGetPerspectiveState | undefined\n\n/**\n * Provides a subscribable state source for a \"perspective\" for the Sanity client,\n * which is used to fetch documents as though certain Content Releases are active.\n *\n * @param instance - The Sanity instance to get the perspective for\n * @param options - The options for the perspective -- usually a release name\n *\n * @returns A subscribable perspective value, usually a list of applicable release names,\n * or a single release name / default perspective (such as 'drafts').\n *\n * @public\n */\nexport const getPerspectiveState: BoundGetPerspectiveState = (instance, ...rest) => {\n if (!_boundGetPerspectiveState) {\n _boundGetPerspectiveState = bindActionByResource(\n releasesStore,\n _getPerspectiveStateSelector,\n ) as BoundGetPerspectiveState\n }\n return _boundGetPerspectiveState(instance, ...rest)\n}\n","/**\n * When a query has no more subscribers, its state is cleaned up and removed\n * from the store. A delay used to prevent re-creating resources when the last\n * subscriber is removed quickly before another one is added. This is helpful\n * when used in a frontend where components may suspend or transition to\n * different views quickly.\n */\nexport const QUERY_STATE_CLEAR_DELAY = 1000\nexport const QUERY_STORE_API_VERSION = 'v2025-05-06'\nexport const QUERY_STORE_DEFAULT_PERSPECTIVE = 'drafts'\n","import {omit} from 'lodash-es'\n\ninterface QueryState {\n syncTags?: string[]\n result?: unknown\n error?: unknown\n lastLiveEventId?: string\n subscribers: string[]\n}\n\nexport interface QueryStoreState {\n queries: {[key: string]: QueryState | undefined}\n error?: unknown\n}\n\nexport const setQueryError =\n (key: string, error: unknown) =>\n (prev: QueryStoreState): QueryStoreState => {\n const prevQuery = prev.queries[key]\n if (!prevQuery) return prev\n return {...prev, queries: {...prev.queries, [key]: {...prevQuery, error}}}\n }\n\nexport const setQueryData =\n (key: string, result: unknown, syncTags?: string[]) =>\n (prev: QueryStoreState): QueryStoreState => {\n const prevQuery = prev.queries[key]\n if (!prevQuery) return prev\n return {\n ...prev,\n queries: {...prev.queries, [key]: {...prevQuery, result: result ?? null, syncTags}},\n }\n }\n\nexport const setLastLiveEventId =\n (key: string, lastLiveEventId: string) =>\n (prev: QueryStoreState): QueryStoreState => {\n const prevQuery = prev.queries[key]\n if (!prevQuery) return prev\n return {...prev, queries: {...prev.queries, [key]: {...prevQuery, lastLiveEventId}}}\n }\n\nexport const addSubscriber =\n (key: string, subscriptionId: string) =>\n (prev: QueryStoreState): QueryStoreState => {\n const prevQuery = prev.queries[key]\n const subscribers = [...(prevQuery?.subscribers ?? []), subscriptionId]\n return {...prev, queries: {...prev.queries, [key]: {...prevQuery, subscribers}}}\n }\n\nexport const removeSubscriber =\n (key: string, subscriptionId: string) =>\n (prev: QueryStoreState): QueryStoreState => {\n const prevQuery = prev.queries[key]\n if (!prevQuery) return prev\n const subscribers = prevQuery.subscribers.filter((id) => id !== subscriptionId)\n if (!subscribers.length) return {...prev, queries: omit(prev.queries, key)}\n return {...prev, queries: {...prev.queries, [key]: {...prevQuery, subscribers}}}\n }\n\nexport const cancelQuery =\n (key: string) =>\n (prev: QueryStoreState): QueryStoreState => {\n const prevQuery = prev.queries[key]\n if (!prevQuery) return prev\n if (prevQuery.subscribers.length) return prev\n return {...prev, queries: omit(prev.queries, key)}\n }\n\nexport const initializeQuery =\n (key: string) =>\n (prev: QueryStoreState): QueryStoreState => {\n if (prev.queries[key]) return prev\n return {...prev, queries: {...prev.queries, [key]: {subscribers: []}}}\n }\n","import {CorsOriginError, type ResponseQueryOptions} from '@sanity/client'\nimport {\n catchError,\n combineLatest,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n groupBy,\n map,\n mergeMap,\n NEVER,\n Observable,\n of,\n pairwise,\n race,\n share,\n startWith,\n switchMap,\n tap,\n} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {type ResourceHandle} from '../config/sanityConfig'\n/*\n * Although this is an import dependency cycle, it is not a logical cycle:\n * 1. queryStore uses getPerspectiveState when resolving release perspectives\n * 2. getPerspectiveState uses releasesStore as a data source\n * 3. releasesStore uses queryStore as a data source\n * 4. however, queryStore does not use getPerspectiveState for the perspective used in releasesStore (\"raw\")\n */\n// eslint-disable-next-line import/no-cycle\nimport {getPerspectiveState} from '../releases/getPerspectiveState'\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\nimport {bindActionByResource, type BoundResourceKey} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {\n createStateSourceAction,\n type SelectorContext,\n type StateSource,\n} from '../store/createStateSourceAction'\nimport {type StoreState} from '../store/createStoreState'\nimport {defineStore, type StoreContext} from '../store/defineStore'\nimport {insecureRandomId} from '../utils/ids'\nimport {\n QUERY_STATE_CLEAR_DELAY,\n QUERY_STORE_API_VERSION,\n QUERY_STORE_DEFAULT_PERSPECTIVE,\n} from './queryStoreConstants'\nimport {\n addSubscriber,\n cancelQuery,\n initializeQuery,\n type QueryStoreState,\n removeSubscriber,\n setLastLiveEventId,\n setQueryData,\n setQueryError,\n} from './reducers'\n\n/**\n * @beta\n */\nexport interface QueryOptions<\n TQuery extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>\n extends\n Pick<ResponseQueryOptions, 'useCdn' | 'cache' | 'next' | 'cacheMode' | 'tag'>,\n ResourceHandle<TDataset, TProjectId> {\n query: TQuery\n params?: Record<string, unknown>\n}\n\n/**\n * @beta\n */\nexport interface ResolveQueryOptions<\n TQuery extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends QueryOptions<TQuery, TDataset, TProjectId> {\n signal?: AbortSignal\n}\n\nconst EMPTY_ARRAY: never[] = []\n\n/** @beta */\nexport const getQueryKey = (options: QueryOptions): string => JSON.stringify(options)\n/** @beta */\nexport const parseQueryKey = (key: string): QueryOptions => JSON.parse(key)\n\n/**\n * Ensures the query key includes an effective perspective so that\n * implicit differences (e.g. different instance.config.perspective)\n * don't collide in the dataset-scoped store.\n *\n * Since perspectives are unique, we can depend on the release stacks\n * to be correct when we retrieve the results.\n *\n */\nfunction normalizeOptionsWithPerspective(\n instance: SanityInstance,\n options: QueryOptions,\n): QueryOptions {\n if (options.perspective !== undefined) return options\n const instancePerspective = instance.config.perspective\n return {\n ...options,\n perspective:\n instancePerspective !== undefined ? instancePerspective : QUERY_STORE_DEFAULT_PERSPECTIVE,\n }\n}\n\nconst queryStore = defineStore<QueryStoreState, BoundResourceKey>({\n name: 'QueryStore',\n getInitialState: () => ({queries: {}}),\n initialize(context) {\n const subscriptions = [\n listenForNewSubscribersAndFetch(context),\n listenToLiveClientAndSetLastLiveEventIds(context),\n ]\n\n return () => {\n for (const subscription of subscriptions) {\n subscription.unsubscribe()\n }\n }\n },\n})\n\nconst errorHandler = (state: StoreState<{error?: unknown}>) => {\n return (error: unknown): void => state.set('setError', {error})\n}\n\nconst listenForNewSubscribersAndFetch = ({\n state,\n instance,\n key: {resource: boundResource},\n}: StoreContext<QueryStoreState, BoundResourceKey>) => {\n return state.observable\n .pipe(\n map((s) => new Set(Object.keys(s.queries))),\n distinctUntilChanged((curr, next) => {\n if (curr.size !== next.size) return false\n return Array.from(next).every((i) => curr.has(i))\n }),\n startWith(new Set<string>()),\n pairwise(),\n mergeMap(([curr, next]) => {\n const added = Array.from(next).filter((i) => !curr.has(i))\n const removed = Array.from(curr).filter((i) => !next.has(i))\n\n return [\n ...added.map((key) => ({key, added: true})),\n ...removed.map((key) => ({key, added: false})),\n ]\n }),\n groupBy((i) => i.key),\n mergeMap((group$) =>\n group$.pipe(\n switchMap((e) => {\n if (!e.added) return EMPTY\n\n const lastLiveEventId$ = state.observable.pipe(\n map((s) => s.queries[group$.key]?.lastLiveEventId),\n distinctUntilChanged(),\n )\n const {\n query,\n params,\n tag,\n resource,\n perspective: perspectiveFromOptions,\n ...restOptions\n } = parseQueryKey(group$.key)\n\n // Short-circuit perspective resolution for non-release perspectives to avoid\n // touching the releases store (and its initialization) unnecessarily.\n const perspective$ = isReleasePerspective(perspectiveFromOptions)\n ? getPerspectiveState(instance, {\n perspective: perspectiveFromOptions,\n resource: resource ?? boundResource,\n }).observable.pipe(filter(Boolean))\n : of(perspectiveFromOptions ?? QUERY_STORE_DEFAULT_PERSPECTIVE)\n\n // Use the store's bound resource as fallback when the query key\n // doesn't include an explicit resource. The store is scoped to a\n // specific resource via bindActionByResource, but the captured\n // `instance` may have a different default resource (e.g. when the\n // store was first created by a caller that passed an explicit\n // resource while using the root app instance).\n const client$ = getClientState(instance, {\n apiVersion: QUERY_STORE_API_VERSION,\n resource: resource ?? boundResource,\n }).observable\n\n return combineLatest({\n lastLiveEventId: lastLiveEventId$,\n client: client$,\n perspective: perspective$,\n }).pipe(\n switchMap(({lastLiveEventId, client, perspective}) =>\n client.observable.fetch(query, params, {\n ...restOptions,\n perspective,\n filterResponse: false,\n returnQuery: false,\n lastLiveEventId,\n tag,\n }),\n ),\n )\n }),\n catchError((error) => {\n state.set('setQueryError', setQueryError(group$.key, error))\n return EMPTY\n }),\n tap(({result, syncTags}) => {\n state.set('setQueryData', setQueryData(group$.key, result, syncTags))\n }),\n ),\n ),\n )\n .subscribe({error: errorHandler(state)})\n}\n\nconst listenToLiveClientAndSetLastLiveEventIds = ({\n state,\n instance,\n key: {resource},\n}: StoreContext<QueryStoreState, BoundResourceKey>) => {\n const liveMessages$ = getClientState(instance, {\n apiVersion: QUERY_STORE_API_VERSION,\n resource,\n }).observable.pipe(\n switchMap((client) =>\n defer(() =>\n client.live.events({includeDrafts: !!client.config().token, tag: 'query-store'}),\n ).pipe(\n catchError((error) => {\n if (error instanceof CorsOriginError) {\n // Swallow only CORS errors in store without bubbling up so that they are handled by the Cors Error component\n state.set('setError', {error})\n return EMPTY\n }\n throw error\n }),\n ),\n ),\n share(),\n filter((e) => e.type === 'message'),\n )\n\n return state.observable\n .pipe(\n mergeMap((s) => Object.entries(s.queries)),\n groupBy(([key]) => key),\n mergeMap((group$) => {\n const syncTags$ = group$.pipe(\n map(([, queryState]) => queryState),\n map((i) => i?.syncTags ?? EMPTY_ARRAY),\n distinctUntilChanged(),\n )\n\n return combineLatest([liveMessages$, syncTags$]).pipe(\n filter(([message, syncTags]) => message.tags.some((tag) => syncTags.includes(tag))),\n tap(([message]) => {\n state.set('setLastLiveEventId', setLastLiveEventId(group$.key, message.id))\n }),\n )\n }),\n )\n .subscribe({error: errorHandler(state)})\n}\n\n/**\n * Returns the state source for a query.\n *\n * This function returns a state source that represents the current result of a GROQ query.\n * Subscribing to the state source will instruct the SDK to fetch the query (if not already fetched)\n * and will keep the query live using the Live content API (considering sync tags) to provide up-to-date results.\n * When the last subscriber is removed, the query state is automatically cleaned up from the store.\n *\n * Note: This functionality is for advanced users who want to build their own framework integrations.\n * Our SDK also provides a React integration (useQuery hook) for convenient usage.\n *\n * Note: Automatic cleanup can interfere with React Suspense because if a component suspends while being the only subscriber,\n * cleanup might occur unexpectedly. In such cases, consider using `resolveQuery` instead.\n *\n * @beta\n */\nexport function getQueryState<TData>(\n instance: SanityInstance,\n queryOptions: QueryOptions,\n): StateSource<TData | undefined>\n\n/** @beta */\nexport function getQueryState(\n instance: SanityInstance,\n queryOptions: QueryOptions,\n): StateSource<unknown>\n\n/** @beta */\nexport function getQueryState(\n ...args: Parameters<typeof _getQueryState>\n): ReturnType<typeof _getQueryState> {\n return _getQueryState(...args)\n}\nconst _getQueryState = bindActionByResource(\n queryStore,\n createStateSourceAction({\n selector: ({state, instance}: SelectorContext<QueryStoreState>, options: QueryOptions) => {\n if (state.error) throw state.error\n const key = getQueryKey(normalizeOptionsWithPerspective(instance, options))\n const queryState = state.queries[key]\n if (queryState?.error) throw queryState.error\n return queryState?.result\n },\n onSubscribe: ({state, instance}, options: QueryOptions) => {\n const subscriptionId = insecureRandomId()\n const key = getQueryKey(normalizeOptionsWithPerspective(instance, options))\n\n state.set('addSubscriber', addSubscriber(key, subscriptionId))\n\n return () => {\n // this runs on unsubscribe\n setTimeout(\n () => state.set('removeSubscriber', removeSubscriber(key, subscriptionId)),\n QUERY_STATE_CLEAR_DELAY,\n )\n }\n },\n }),\n)\n\n/**\n * Resolves the result of a query without registering a lasting subscriber.\n *\n * This function fetches the result of a GROQ query and returns a promise that resolves with the query result.\n * Unlike `getQueryState`, which registers subscribers to keep the query live and performs automatic cleanup,\n * `resolveQuery` does not track subscribers. This makes it ideal for use with React Suspense, where the returned\n * promise is thrown to delay rendering until the query result becomes available.\n * Once the promise resolves, it is expected that a real subscriber will be added via `getQueryState` to manage ongoing updates.\n *\n * Additionally, an optional AbortSignal can be provided to cancel the query and immediately clear the associated state\n * if there are no active subscribers.\n *\n * @beta\n */\nexport function resolveQuery<TData>(\n instance: SanityInstance,\n queryOptions: ResolveQueryOptions,\n): Promise<TData>\n/** @beta */\nexport function resolveQuery(...args: Parameters<typeof _resolveQuery>): Promise<unknown> {\n return _resolveQuery(...args)\n}\nconst _resolveQuery = bindActionByResource(\n queryStore,\n ({state, instance}, {signal, ...options}: ResolveQueryOptions) => {\n const normalized = normalizeOptionsWithPerspective(instance, options)\n const {getCurrent} = getQueryState(instance, normalized)\n const key = getQueryKey(normalized)\n\n const aborted$ = signal\n ? new Observable<void>((observer) => {\n const cleanup = () => {\n signal.removeEventListener('abort', listener)\n }\n\n const listener = () => {\n observer.error(new DOMException('The operation was aborted.', 'AbortError'))\n observer.complete()\n cleanup()\n }\n signal.addEventListener('abort', listener)\n\n return cleanup\n }).pipe(\n catchError((error) => {\n if (error instanceof Error && error.name === 'AbortError') {\n state.set('cancelQuery', cancelQuery(key))\n }\n throw error\n }),\n )\n : NEVER\n\n state.set('initializeQuery', initializeQuery(key))\n\n const resolved$ = state.observable.pipe(\n map(getCurrent),\n first((i) => i !== undefined),\n )\n\n return firstValueFrom(race([resolved$, aborted$]))\n },\n)\n","export const PROJECTION_TAG = 'projection'\nexport const PROJECTION_STATE_CLEAR_DELAY = 1000\n\nexport const STABLE_EMPTY_PROJECTION = {\n data: null,\n isPending: false,\n}\n\nexport function validateProjection(projection: string): string {\n if (!projection.startsWith('{') || !projection.endsWith('}')) {\n throw new Error(\n `Invalid projection format: \"${projection}\". Projections must be enclosed in curly braces, e.g. \"{title, 'author': author.name}\"`,\n )\n }\n return projection\n}\n","import {DocumentId} from '@sanity/id-utils'\n\nimport {type PerspectiveHandle} from '../config/sanityConfig'\nimport {getPublishedId} from '../utils/ids'\nimport {\n type DocumentProjections,\n type DocumentProjectionValues,\n type ProjectionStoreState,\n} from './types'\nimport {validateProjection} from './util'\n\nexport type ProjectionQueryResult = {\n _id: string\n _type: string\n _updatedAt: string\n result: Record<string, unknown>\n __projectionHash: string\n}\n\ninterface CreateProjectionQueryResult {\n query: string\n params: Record<string, unknown>\n}\n\ntype ProjectionMap = Record<string, {projection: string; documentIds: Set<string>}>\n\nexport function createProjectionQuery(\n documentIds: Set<DocumentId>,\n documentProjections: {[TDocumentId in DocumentId]?: DocumentProjections},\n): CreateProjectionQueryResult {\n const projections = Array.from(documentIds)\n .flatMap((id) => {\n const projectionsForDoc = documentProjections[id]\n if (!projectionsForDoc) return []\n\n return Object.entries(projectionsForDoc).map(([projectionHash, projection]) => ({\n documentId: id,\n projection: validateProjection(projection),\n projectionHash,\n }))\n })\n .reduce<ProjectionMap>((acc, {documentId, projection, projectionHash}) => {\n const obj = acc[projectionHash] ?? {documentIds: new Set(), projection}\n obj.documentIds.add(documentId)\n\n acc[projectionHash] = obj\n return acc\n }, {})\n\n const query = `[${Object.entries(projections)\n .map(([projectionHash, {projection}]) => {\n return `...*[_id in $__ids_${projectionHash}]{_id,_type,_updatedAt,\"__projectionHash\":\"${projectionHash}\",\"result\":{...${projection}}}`\n })\n .join(',')}]`\n\n const params = Object.fromEntries(\n Object.entries(projections).map(([projectionHash, value]) => {\n const idsInProjection = Array.from(value.documentIds).flatMap((id) => DocumentId(id))\n return [`__ids_${projectionHash}`, Array.from(idsInProjection)]\n }),\n )\n\n return {query, params}\n}\n\ninterface ProcessProjectionQueryOptions {\n ids: Set<string>\n results: ProjectionQueryResult[]\n documentStatuses?: ProjectionStoreState['documentStatuses']\n perspective: NonNullable<PerspectiveHandle['perspective']>\n}\n\nexport function processProjectionQuery({\n ids,\n results,\n documentStatuses,\n}: ProcessProjectionQueryOptions): {\n [TDocumentId in string]?: DocumentProjectionValues<Record<string, unknown>>\n} {\n const groupedResults: {\n [docId: string]: {\n [hash: string]: ProjectionQueryResult | undefined\n }\n } = {}\n\n for (const result of results) {\n const originalId = getPublishedId(result._id)\n const hash = result.__projectionHash\n\n if (!ids.has(originalId)) continue\n\n if (!groupedResults[originalId]) {\n groupedResults[originalId] = {}\n }\n if (!groupedResults[originalId][hash]) {\n groupedResults[originalId][hash] = undefined\n }\n\n groupedResults[originalId][hash] = result\n }\n\n const finalValues: {\n [docId: string]: DocumentProjectionValues<Record<string, unknown>>\n } = {}\n\n for (const originalId of ids) {\n finalValues[originalId] = {}\n\n const projectionsForDoc = groupedResults[originalId]\n if (!projectionsForDoc) continue\n\n for (const hash in projectionsForDoc) {\n const projectionResult = projectionsForDoc[hash]\n const projectionResultData = projectionResult?.result\n\n if (!projectionResultData) {\n finalValues[originalId][hash] = {data: null, isPending: false}\n continue\n }\n\n const statusFromStore = documentStatuses?.[originalId]\n\n finalValues[originalId][hash] = {\n data: {...projectionResultData, _status: statusFromStore},\n isPending: false,\n }\n }\n }\n\n return finalValues\n}\n","import {\n DocumentId,\n getDraftId,\n getPublishedId,\n getVersionId,\n isDraftId,\n isPublishedId,\n isVersionId,\n} from '@sanity/id-utils'\n\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\nimport {type BoundPerspectiveKey} from '../store/createActionBinder'\nimport {type ProjectionStoreState} from './types'\n\ninterface StatusQueryResult {\n _id: string\n _updatedAt: string\n}\n\n/**\n * Builds an array of document IDs to query for status information using the \"raw\" perspective.\n * Includes draft, published, and version IDs as needed.\n */\nexport function buildStatusQueryIds(\n documentIds: Set<string>,\n perspective: BoundPerspectiveKey['perspective'],\n): string[] {\n const ids: string[] = []\n const releaseName = isReleasePerspective(perspective) ? perspective.releaseName : null\n\n for (const id of documentIds) {\n const publishedId = getPublishedId(DocumentId(id))\n const draftId = getDraftId(publishedId)\n\n // Always query for draft and published versions\n ids.push(draftId, publishedId)\n\n // If it's a release perspective, also query for the version\n if (releaseName) {\n ids.push(getVersionId(publishedId, releaseName))\n }\n }\n\n return ids\n}\n\n/**\n * Processes status query results into documentStatuses (same shape as _status returned to users).\n */\nexport function processStatusQueryResults(\n results: StatusQueryResult[],\n): ProjectionStoreState['documentStatuses'] {\n const documentStatuses: ProjectionStoreState['documentStatuses'] = {}\n\n for (const result of results) {\n const id = DocumentId(result._id)\n const updatedAt = result._updatedAt\n const publishedId = getPublishedId(id)\n const statusData = documentStatuses[publishedId] ?? {}\n if (isDraftId(id)) {\n statusData.lastEditedDraftAt = updatedAt\n } else if (isVersionId(id)) {\n statusData.lastEditedVersionAt = updatedAt\n } else if (isPublishedId(id)) {\n statusData.lastEditedPublishedAt = updatedAt\n }\n documentStatuses[publishedId] = statusData\n }\n\n return documentStatuses\n}\n","import {isEqual} from 'lodash-es'\nimport {\n combineLatest,\n debounceTime,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n from,\n map,\n Observable,\n pairwise,\n startWith,\n Subscription,\n switchMap,\n tap,\n} from 'rxjs'\n\nimport {getQueryState, resolveQuery} from '../query/queryStore'\nimport {type BoundPerspectiveKey} from '../store/createActionBinder'\nimport {type StoreContext} from '../store/defineStore'\nimport {\n createProjectionQuery,\n processProjectionQuery,\n type ProjectionQueryResult,\n} from './projectionQuery'\nimport {buildStatusQueryIds, processStatusQueryResults} from './statusQuery'\nimport {type ProjectionStoreState} from './types'\nimport {PROJECTION_TAG} from './util'\n\nconst BATCH_DEBOUNCE_TIME = 50\n\nconst isSetEqual = <T>(a: Set<T>, b: Set<T>) =>\n a.size === b.size && Array.from(a).every((i) => b.has(i))\n\ninterface StatusQueryResult {\n _id: string\n _updatedAt: string\n}\n\nexport const subscribeToStateAndFetchBatches = ({\n state,\n instance,\n key: {resource, perspective},\n}: StoreContext<ProjectionStoreState, BoundPerspectiveKey>): Subscription => {\n const documentProjections$ = state.observable.pipe(\n map((s) => s.documentProjections),\n distinctUntilChanged(isEqual),\n )\n\n const activeDocumentIds$ = state.observable.pipe(\n map(({subscriptions}) => new Set(Object.keys(subscriptions))),\n distinctUntilChanged(isSetEqual),\n )\n\n const pendingUpdateSubscription = activeDocumentIds$\n .pipe(\n debounceTime(BATCH_DEBOUNCE_TIME),\n startWith(new Set<string>()),\n pairwise(),\n tap(([prevIds, currIds]) => {\n const newIds = [...currIds].filter((id) => !prevIds.has(id))\n if (newIds.length === 0) return\n\n state.set('updatingPending', (prev) => {\n const nextValues = {...prev.values}\n for (const id of newIds) {\n const projectionsForDoc = prev.documentProjections[id]\n if (!projectionsForDoc) continue\n\n const currentValuesForDoc = prev.values[id] ?? {}\n const updatedValuesForDoc = {...currentValuesForDoc}\n\n for (const hash in projectionsForDoc) {\n const currentValue = updatedValuesForDoc[hash]\n updatedValuesForDoc[hash] = {\n data: currentValue?.data ?? null,\n isPending: true,\n }\n }\n nextValues[id] = updatedValuesForDoc\n }\n return {values: nextValues}\n })\n }),\n )\n .subscribe()\n\n const queryTrigger$ = combineLatest([activeDocumentIds$, documentProjections$]).pipe(\n debounceTime(BATCH_DEBOUNCE_TIME),\n distinctUntilChanged(isEqual),\n )\n\n const queryExecutionSubscription = queryTrigger$\n .pipe(\n switchMap(([ids, documentProjections]) => {\n if (!ids.size) return EMPTY\n const {query, params} = createProjectionQuery(ids, documentProjections)\n const controller = new AbortController()\n\n // Build status query IDs and query\n const statusQueryIds = buildStatusQueryIds(ids, perspective)\n const statusQuery = `*[_id in $statusIds]{_id, _updatedAt}`\n const statusParams = {statusIds: statusQueryIds}\n\n const projectionQuery$ = new Observable<ProjectionQueryResult[]>((observer) => {\n const {getCurrent, observable} = getQueryState<ProjectionQueryResult[]>(instance, {\n query,\n params,\n tag: PROJECTION_TAG,\n perspective,\n resource,\n })\n\n const querySource$ = defer(() => {\n if (getCurrent() === undefined) {\n return from(\n resolveQuery<ProjectionQueryResult[]>(instance, {\n query,\n params,\n tag: PROJECTION_TAG,\n signal: controller.signal,\n perspective,\n resource,\n }),\n ).pipe(switchMap(() => observable))\n }\n return observable\n }).pipe(filter((result): result is ProjectionQueryResult[] => result !== undefined))\n\n const subscription = querySource$.subscribe(observer)\n\n return () => {\n if (!controller.signal.aborted) {\n controller.abort()\n }\n subscription.unsubscribe()\n }\n })\n\n const statusQuery$ = new Observable<StatusQueryResult[]>((observer) => {\n const {getCurrent, observable} = getQueryState<StatusQueryResult[]>(instance, {\n query: statusQuery,\n params: statusParams,\n tag: PROJECTION_TAG,\n perspective: 'raw',\n resource,\n })\n\n const statusQuerySource$ = defer(() => {\n if (getCurrent() === undefined) {\n return from(\n resolveQuery<StatusQueryResult[]>(instance, {\n query: statusQuery,\n params: statusParams,\n tag: PROJECTION_TAG,\n signal: controller.signal,\n perspective: 'raw',\n resource,\n }),\n ).pipe(switchMap(() => observable))\n }\n return observable\n }).pipe(filter((result): result is StatusQueryResult[] => result !== undefined))\n\n const subscription = statusQuerySource$.subscribe(observer)\n\n return () => {\n subscription.unsubscribe()\n }\n })\n\n // Combine both streams: emit whenever either has a new value (after both have\n // emitted at least one defined value). This keeps reacting to query store updates.\n return combineLatest([projectionQuery$, statusQuery$]).pipe(\n filter(\n (pair): pair is [ProjectionQueryResult[], StatusQueryResult[]] =>\n pair[0] !== undefined && pair[1] !== undefined,\n ),\n map(([projection, status]) => ({\n data: projection,\n ids,\n statusResults: status,\n })),\n )\n }),\n map(({ids, data, statusResults}) => {\n // Process status results into documentStatuses (same shape as _status returned to users)\n const documentStatuses = processStatusQueryResults(statusResults)\n state.set('updateStatuses', (prev) => ({\n documentStatuses: {\n ...prev.documentStatuses,\n ...documentStatuses,\n },\n }))\n\n // Assemble projection values with _status (buildStatusForDocument in statusQuery)\n const currentState = state.get()\n return processProjectionQuery({\n ids,\n results: data,\n documentStatuses: currentState.documentStatuses,\n perspective: perspective,\n })\n }),\n )\n .subscribe({\n next: (processedValues) => {\n state.set('updateResult', (prev) => {\n const nextValues = {...prev.values}\n for (const docId in processedValues) {\n if (processedValues[docId]) {\n nextValues[docId] = {\n ...(prev.values[docId] ?? {}),\n ...processedValues[docId],\n }\n }\n }\n return {values: nextValues}\n })\n },\n error: (err) => {\n // eslint-disable-next-line no-console\n console.error('Error fetching projection batches:', err)\n // TODO: Potentially update state to reflect error state for affected projections?\n },\n })\n\n return new Subscription(() => {\n pendingUpdateSubscription.unsubscribe()\n queryExecutionSubscription.unsubscribe()\n })\n}\n","import {type BoundPerspectiveKey} from '../store/createActionBinder'\nimport {defineStore} from '../store/defineStore'\nimport {subscribeToStateAndFetchBatches} from './subscribeToStateAndFetchBatches'\nimport {type ProjectionStoreState} from './types'\n\nexport const projectionStore = defineStore<ProjectionStoreState, BoundPerspectiveKey>({\n name: 'Projection',\n getInitialState() {\n return {\n values: {},\n documentProjections: {},\n subscriptions: {},\n documentStatuses: {},\n }\n },\n initialize(context) {\n const batchSubscription = subscribeToStateAndFetchBatches(context)\n return () => batchSubscription.unsubscribe()\n },\n})\n","import {DocumentId, getPublishedId} from '@sanity/id-utils'\nimport {omit} from 'lodash-es'\n\nimport {type DocumentHandle} from '../config/sanityConfig'\nimport {bindActionByResourceAndPerspective} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {\n createStateSourceAction,\n type SelectorContext,\n type StateSource,\n} from '../store/createStateSourceAction'\nimport {hashString} from '../utils/hashString'\nimport {insecureRandomId} from '../utils/ids'\nimport {projectionStore} from './projectionStore'\nimport {type ProjectionStoreState, type ProjectionValuePending} from './types'\nimport {PROJECTION_STATE_CLEAR_DELAY, STABLE_EMPTY_PROJECTION, validateProjection} from './util'\n\nexport interface ProjectionOptions<\n TProjection extends string = string,\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n projection: TProjection\n}\n\n/**\n * @beta\n */\nexport function getProjectionState<TData extends object>(\n instance: SanityInstance,\n options: ProjectionOptions,\n): StateSource<ProjectionValuePending<TData> | undefined>\n\n/**\n * @beta\n */\nexport function getProjectionState(\n instance: SanityInstance,\n options: ProjectionOptions,\n): StateSource<ProjectionValuePending<Record<string, unknown>> | undefined>\n\n/**\n * @beta\n */\nexport function getProjectionState(\n ...args: Parameters<typeof _getProjectionState>\n): ReturnType<typeof _getProjectionState> {\n return _getProjectionState(...args)\n}\n\n/**\n * @beta\n */\nexport const _getProjectionState = bindActionByResourceAndPerspective(\n projectionStore,\n createStateSourceAction({\n selector: (\n {state}: SelectorContext<ProjectionStoreState>,\n options: ProjectionOptions<string, string, string, string>,\n ): ProjectionValuePending<object> | undefined => {\n const documentId = getPublishedId(DocumentId(options.documentId))\n const projectionHash = hashString(options.projection)\n return state.values[documentId]?.[projectionHash] ?? STABLE_EMPTY_PROJECTION\n },\n onSubscribe: ({state}, options: ProjectionOptions<string, string, string, string>) => {\n const {projection, ...docHandle} = options\n const subscriptionId = insecureRandomId()\n const documentId = getPublishedId(DocumentId(docHandle.documentId))\n const validProjection = validateProjection(projection)\n const projectionHash = hashString(validProjection)\n\n state.set('addSubscription', (prev) => ({\n documentProjections: {\n ...prev.documentProjections,\n [documentId]: {\n ...prev.documentProjections[documentId],\n [projectionHash]: validProjection,\n },\n },\n subscriptions: {\n ...prev.subscriptions,\n [documentId]: {\n ...prev.subscriptions[documentId],\n [projectionHash]: {\n ...prev.subscriptions[documentId]?.[projectionHash],\n [subscriptionId]: true,\n },\n },\n },\n }))\n\n return () => {\n setTimeout(() => {\n state.set('removeSubscription', (prev): Partial<ProjectionStoreState> => {\n const documentSubscriptionsForHash = omit(\n prev.subscriptions[documentId]?.[projectionHash],\n subscriptionId,\n )\n const hasSubscribersForProjection = !!Object.keys(documentSubscriptionsForHash).length\n\n const nextSubscriptions = {...prev.subscriptions}\n const nextDocumentProjections = {...prev.documentProjections}\n const nextValues = {...prev.values}\n\n // clean up the subscription and documentProjection if there are no subscribers\n if (!hasSubscribersForProjection) {\n delete nextSubscriptions[documentId]![projectionHash]\n delete nextDocumentProjections[documentId]![projectionHash]\n\n const currentProjectionValue = prev.values[documentId]?.[projectionHash]\n if (currentProjectionValue && nextValues[documentId]) {\n nextValues[documentId]![projectionHash] = {\n data: currentProjectionValue.data,\n isPending: false,\n }\n }\n } else {\n if (nextSubscriptions[documentId]) {\n nextSubscriptions[documentId]![projectionHash] = documentSubscriptionsForHash\n }\n }\n\n const hasAnySubscribersForDocument = Object.values(\n nextSubscriptions[documentId] ?? {},\n ).some((subs) => Object.keys(subs).length > 0)\n\n if (!hasAnySubscribersForDocument) {\n delete nextSubscriptions[documentId]\n delete nextDocumentProjections[documentId]\n // Keep nextValues[documentId] as cache\n }\n\n return {\n subscriptions: nextSubscriptions,\n documentProjections: nextDocumentProjections,\n values: nextValues,\n }\n })\n }, PROJECTION_STATE_CLEAR_DELAY)\n }\n },\n }),\n)\n","import {filter, firstValueFrom} from 'rxjs'\n\nimport {bindActionByResourceAndPerspective} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {getProjectionState, type ProjectionOptions} from './getProjectionState'\nimport {projectionStore} from './projectionStore'\nimport {type ProjectionValuePending} from './types'\n\n/** @beta */\nexport function resolveProjection<TData extends object>(\n instance: SanityInstance,\n options: ProjectionOptions,\n): Promise<ProjectionValuePending<TData>>\n\n/** @beta */\nexport function resolveProjection(\n ...args: Parameters<typeof _resolveProjection>\n): ReturnType<typeof _resolveProjection> {\n return _resolveProjection(...args)\n}\n\n/**\n * @beta\n */\nconst _resolveProjection = bindActionByResourceAndPerspective(\n projectionStore,\n (\n {instance}: {instance: SanityInstance},\n options: ProjectionOptions,\n ): Promise<ProjectionValuePending<Record<string, unknown>>> =>\n firstValueFrom(\n getProjectionState<Record<string, unknown>>(instance, options).observable.pipe(\n filter((state): state is ProjectionValuePending<Record<string, unknown>> => !!state?.data),\n ),\n ),\n)\n","import {switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {createFetcherStore} from '../utils/createFetcherStore'\n\nconst API_VERSION = 'v2025-02-19'\n\nconst projects = createFetcherStore({\n name: 'Projects',\n getKey: (_instance, options?: {organizationId?: string; includeMembers?: boolean}) => {\n const orgKey = options?.organizationId ? `:org:${options.organizationId}` : ''\n const membersKey = options?.includeMembers === false ? ':no-members' : ''\n return `projects${orgKey}${membersKey}`\n },\n fetcher: (instance) => (options?: {organizationId?: string; includeMembers?: boolean}) =>\n getClientState(instance, {\n apiVersion: API_VERSION,\n scope: 'global',\n requestTagPrefix: 'sanity.sdk.projects',\n }).observable.pipe(\n switchMap((client) => {\n const organizationId = options?.organizationId\n return client.observable.projects.list({\n // client method has a type that expects false | undefined\n includeMembers: !options?.includeMembers ? false : undefined,\n organizationId,\n })\n }),\n ),\n})\n\n/** @public */\nexport const getProjectsState = projects.getState\n/** @public */\nexport const resolveProjects = projects.resolveState\n","const WILDCARD_TOKEN = '*'\nconst NEGATION_TOKEN = '-'\n// This regex handles simple cases including quoted phrases.\n// More complex query syntaxes might need a more robust parser.\nconst TOKEN_REGEX = /(?:[^\\s\"]+|\"[^\"]*\")+/g\n\n/**\n * @internal\n * Checks if a token starts with the negation character.\n */\nfunction isNegationToken(token: string | undefined): boolean {\n return typeof token !== 'undefined' && token.trim().startsWith(NEGATION_TOKEN)\n}\n\n/**\n * @internal\n * Checks if a token ends with the wildcard character.\n */\nfunction isPrefixToken(token: string | undefined): boolean {\n return typeof token !== 'undefined' && token.trim().endsWith(WILDCARD_TOKEN)\n}\n\n/**\n * @internal\n * Checks if a token is enclosed in double quotes.\n */\nfunction isExactMatchToken(token: string | undefined): boolean {\n // Ensure the token exists, has at least 2 characters, and starts/ends with \"\n return !!token && token.length >= 2 && token.startsWith('\"') && token.endsWith('\"')\n}\n\n/**\n * Creates a GROQ search filter string (`[@] match text::query(\"...\")`)\n * from a raw search query string.\n *\n * It applies wildcard ('*') logic to the last eligible token and escapes\n * double quotes within the search term.\n *\n * If the input query is empty or only whitespace, it returns an empty string.\n *\n * @param query - The raw input search string.\n * @returns The GROQ search filter string, or an empty string.\n * @internal\n */\nexport function createGroqSearchFilter(query: string): string {\n // Trim leading/trailing whitespace from the overall query first\n const trimmedQuery = query.trim()\n if (!trimmedQuery) {\n return '' // Return empty if query is empty or just whitespace\n }\n\n // Extract tokens using the regex\n const tokens = trimmedQuery.match(TOKEN_REGEX) ?? []\n\n // Find the index of the last token eligible for wildcard appending\n const reversedTokens = [...tokens].reverse()\n const reversedIndex = reversedTokens.findIndex(\n (token: string) => !isNegationToken(token) && !isExactMatchToken(token),\n )\n const finalIncrementalTokenIndex = reversedIndex === -1 ? -1 : tokens.length - 1 - reversedIndex\n\n // Get the actual token based on the found index\n const finalIncrementalToken = tokens[finalIncrementalTokenIndex]\n\n const processedTokens = [...tokens]\n // If a suitable token was found and it doesn't already end with a wildcard,\n // apply the wildcard.\n if (finalIncrementalToken !== undefined && !isPrefixToken(finalIncrementalToken)) {\n // Replace the identified token with its wildcarded version\n processedTokens.splice(\n finalIncrementalTokenIndex,\n 1,\n `${finalIncrementalToken}${WILDCARD_TOKEN}`,\n )\n }\n\n // Join the tokens back into a space-separated string\n const wildcardSearch = processedTokens.join(' ')\n\n // Escape double quotes within the final search term for the GROQ query\n const escapedSearch = wildcardSearch.replace(/\"/g, '\\\\\"')\n\n // Construct the final GROQ filter clause\n return `[@] match text::query(\"${escapedSearch}\")`\n}\n","/**\n * Filter criteria for intent matching. Can be combined to create more specific intents.\n *\n * @example\n * ```typescript\n * // matches only geopoints in the travel-project project, production dataset\n * const filter: IntentFilter = {\n * projectId: 'travel-project',\n * dataset: 'production',\n * types: ['geopoint']\n * }\n *\n * // matches all documents in the travel-project project\n * const filter: IntentFilter = {\n * projectId: 'travel-project',\n * types: ['*']\n * }\n *\n * // matches geopoints in the travel-project production dataset and map pins in all projects in the org\n * const filters: IntentFilter[] = [\n * {\n * projectId: 'travel-project',\n * dataset: 'production',\n * types: ['geopoint']\n * },\n * {\n * types: ['map-pin']\n * }\n * ]\n * ```\n * @public\n */\nexport interface IntentFilter {\n /**\n * Project ID to match against\n * @remarks When specified, the intent will only match for the specified project.\n */\n projectId?: string\n\n /**\n * Dataset to match against\n * @remarks When specified, the intent will only match for the specified dataset. Requires projectId to be specified.\n */\n dataset?: string\n\n /**\n * Document types that this intent can handle\n * @remarks This is required for all filters. Use ['*'] to match all document types.\n */\n types: string[]\n}\n\n/**\n * Intent definition structure for registering user intents\n * @public\n */\nexport interface Intent {\n /**\n * Unique identifier for this intent\n * @remarks Should be unique across all registered intents in an org for proper matching\n */\n id: string\n\n /**\n * The action that this intent performs\n * @remarks Examples: \"view\", \"edit\", \"create\", \"delete\"\n */\n action: 'view' | 'edit' | 'create' | 'delete'\n\n /**\n * Human-readable title for this intent\n * @remarks Used for display purposes in UI or logs\n */\n title: string\n\n /**\n * Detailed description of what this intent does\n * @remarks Helps users understand the purpose and behavior of the intent\n */\n description?: string\n\n /**\n * Array of filter criteria for intent matching\n * @remarks At least one filter is required. Use `{types: ['*']}` to match everything\n */\n filters: IntentFilter[]\n}\n\n/**\n * Creates a properly typed intent definition for registration with the backend.\n *\n * This utility function provides TypeScript support and validation for intent declarations.\n * It is also used in the CLI if intents are declared as bare objects in an intents file.\n *\n * @param intent - The intent definition object\n * @returns The same intent object with proper typing\n *\n * @example\n * ```typescript\n * // Specific filter for a document type\n * const viewGeopointInMapApp = defineIntent({\n * id: 'viewGeopointInMapApp',\n * action: 'view',\n * title: 'View a geopoint in the map app',\n * description: 'This lets you view a geopoint in the map app',\n * filters: [\n * {\n * projectId: 'travel-project',\n * dataset: 'production',\n * types: ['geopoint']\n * }\n * ]\n * })\n *\n * export default viewGeopointInMapApp\n * ```\n *\n * If your intent is asynchronous, resolve the promise before defining / returning the intent\n * ```typescript\n * async function createAsyncIntent() {\n * const currentProject = await asyncProjectFunction()\n * const currentDataset = await asyncDatasetFunction()\n *\n * return defineIntent({\n * id: 'dynamicIntent',\n * action: 'view',\n * title: 'Dynamic Intent',\n * description: 'Intent with dynamically resolved values',\n * filters: [\n * {\n * projectId: currentProject, // Resolved value\n * dataset: currentDataset, // Resolved value\n * types: ['document']\n * }\n * ]\n * })\n * }\n *\n * const intent = await createAsyncIntent()\n * export default intent\n * ```\n *\n * @public\n */\nexport function defineIntent(intent: Intent): Intent {\n // Validate required fields\n if (!intent.id) {\n throw new Error('Intent must have an id')\n }\n if (!intent.action) {\n throw new Error('Intent must have an action')\n }\n if (!intent.title) {\n throw new Error('Intent must have a title')\n }\n if (!Array.isArray(intent.filters)) {\n throw new Error('Intent must have a filters array')\n }\n if (intent.filters.length === 0) {\n throw new Error(\n \"Intent must have at least one filter. If you want to match everything, use {types: ['*']}\",\n )\n }\n\n // Validate each filter\n intent.filters.forEach((filter, index) => {\n validateFilter(filter, index)\n })\n\n // Return the intent as-is, providing type safety and runtime validation\n return intent\n}\n\n/**\n * Validates an individual filter object\n * @param filter - The filter to validate\n * @param index - The filter's index in the array (for error messages)\n * @internal\n */\nfunction validateFilter(filter: IntentFilter, index: number): void {\n const filterContext = `Filter at index ${index}`\n\n // Check that filter is an object\n if (!filter || typeof filter !== 'object') {\n throw new Error(`${filterContext} must be an object`)\n }\n\n // Check that types is required\n if (filter.types === undefined) {\n throw new Error(\n `${filterContext} must have a types property. Use ['*'] to match all document types.`,\n )\n }\n\n // Validate projectId\n if (filter.projectId !== undefined) {\n if (typeof filter.projectId !== 'string') {\n throw new Error(`${filterContext}: projectId must be a string`)\n }\n if (filter.projectId.trim() === '') {\n throw new Error(`${filterContext}: projectId cannot be empty`)\n }\n }\n\n // Validate dataset\n if (filter.dataset !== undefined) {\n if (typeof filter.dataset !== 'string') {\n throw new Error(`${filterContext}: dataset must be a string`)\n }\n if (filter.dataset.trim() === '') {\n throw new Error(`${filterContext}: dataset cannot be empty`)\n }\n // Dataset requires projectId to be specified\n if (filter.projectId === undefined) {\n throw new Error(`${filterContext}: dataset cannot be specified without projectId`)\n }\n }\n\n // Validate types (now required)\n if (!Array.isArray(filter.types)) {\n throw new Error(`${filterContext}: types must be an array`)\n }\n if (filter.types.length === 0) {\n throw new Error(`${filterContext}: types array cannot be empty`)\n }\n\n // Validate each type\n filter.types.forEach((type, typeIndex) => {\n if (typeof type !== 'string') {\n throw new Error(`${filterContext}: types[${typeIndex}] must be a string`)\n }\n if (type.trim() === '') {\n throw new Error(`${filterContext}: types[${typeIndex}] cannot be empty`)\n }\n })\n\n // Check for wildcard exclusivity\n const hasWildcard = filter.types.includes('*')\n if (hasWildcard && filter.types.length > 1) {\n throw new Error(\n `${filterContext}: when using wildcard '*', it must be the only type in the array`,\n )\n }\n}\n","import {CorsOriginError} from '@sanity/client'\n\n/**\n * @public\n * Extracts the project ID from a CorsOriginError message.\n * @param error - The error to extract the project ID from.\n * @returns The project ID or null if the error is not a CorsOriginError.\n */\nexport function getCorsErrorProjectId(error: Error): string | null {\n if (!(error instanceof CorsOriginError)) return null\n\n const message = (error as unknown as {message?: string}).message || ''\n const projMatch = message.match(/manage\\/project\\/([^/?#]+)/)\n return projMatch ? projMatch[1] : null\n}\n","import {version} from '../package.json'\nimport {getEnv} from './utils/getEnv'\n\n/**\n * This version is provided by pkg-utils at build time\n * @internal\n */\nexport const CORE_SDK_VERSION = getEnv('PKG_VERSION') || `${version}-development`\n"],"names":["configureLogging","getInitialState","isEqual","DEFAULT_API_VERSION","AuthStateType","delay","tokenRefresherRunning","getDashboardOrganizationId","key","API_VERSION","switchMap","filter","map","project","destroyController","getOrCreateChannel","getOrCreateController","releaseChannel","unboundDestroyController","unboundGetOrCreateChannel","unboundGetOrCreateController","unboundReleaseChannel","getOrCreateNode","releaseNode","unboundReleaseNode","unboundGetOrCreateNode","_configureLogging","document","set","checkGrant","newDocBase","newDocWorking","mutations","userPatches","baseBefore","baseAfter","patches","workingBefore","workingMutations","getPublishedId","first","result","value","tap","catchError","startWith","pairwise","groupBy","mergeMap","errorHandler","resourceType","share","getDraftId"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["API_VERSION","API_VERSION","serializeInclude","API_VERSION","API_VERSION","getDashboardOrganizationId","getDashboardOrganizationId","switchMap","groupBy","mergeMap","startWith","pairwise","filter","map","tap","catchError","first","API_VERSION","API_VERSION","getIndexForKey","jsonMatch","slicePath","stringifyPath","mergeMap","jsonMatch","stringifyPath","API_VERSION","jsonMatch","API_VERSION","API_VERSION","API_VERSION","map","retry","distinctUntilChanged","share","switchMap","catchError"],"sources":["../src/store/createSanityInstance.ts","../src/access/checkPermissions.ts","../src/utils/buildQuery.ts","../src/applications/applications.ts","../src/project/organizationVerification.ts","../src/projects/projects.ts","../src/project/project.ts","../src/auth/dashboardUtils.ts","../src/auth/getOrganizationVerificationState.ts","../src/auth/handleAuthCallback.ts","../src/auth/logout.ts","../src/comments/weakenReferences.ts","../src/comments/commentActions.ts","../src/config/handles.ts","../src/config/loggingConfig.ts","../src/utils/createFetcherStore.ts","../src/datasets/datasets.ts","../src/document/util.ts","../src/document/actions.ts","../src/document/documentConstants.ts","../src/document/processActions/releaseUtil.ts","../src/document/patchOperations.ts","../src/document/processMutations.ts","../src/document/listen.ts","../src/utils/MultiKeyWeakMap.ts","../src/document/processActions/shared.ts","../src/document/permissions.ts","../src/document/processActions/create.ts","../src/document/processActions/delete.ts","../src/document/processActions/discard.ts","../src/document/processActions/edit.ts","../src/document/processActions/publish.ts","../src/document/processActions/releaseArchive.ts","../src/document/processActions/releaseCreate.ts","../src/document/processActions/releaseDelete.ts","../src/document/processActions/releaseEdit.ts","../src/document/processActions/releasePublish.ts","../src/document/processActions/releaseSchedule.ts","../src/document/processActions/unpublish.ts","../src/document/processActions/processActions.ts","../src/document/reducers.ts","../src/document/events.ts","../src/document/listenerEventOperators.ts","../src/document/sharedListener.ts","../src/document/documentStore.ts","../src/document/resourceRules.ts","../src/document/applyDocumentActions.ts","../src/favorites/favorites.ts","../src/installations/installations.ts","../src/organization/organization.ts","../src/organizations/organizations.ts","../src/users/usersStore.ts","../src/presence/bifurTransport.ts","../src/presence/paths.ts","../src/presence/presenceStore.ts","../src/utils/hashString.ts","../src/projection/util.ts","../src/projection/projectionQuery.ts","../src/projection/statusQuery.ts","../src/projection/subscribeToStateAndFetchBatches.ts","../src/projection/projectionStore.ts","../src/projection/getProjectionState.ts","../src/projection/resolveProjection.ts","../src/utils/getCorsErrorProjectId.ts","../src/utils/isImportError.ts"],"sourcesContent":["import {type SanityConfig} from '../config/sanityConfig'\nimport {insecureRandomId} from '../utils/ids'\nimport {createLogger, type InstanceContext} from '../utils/logger'\n\n/**\n * Represents a Sanity.io resource instance with its own configuration and lifecycle\n *\n * @public\n */\nexport interface SanityInstance {\n /**\n * Unique identifier for this instance\n * @remarks Generated using crypto.randomUUID()\n */\n readonly instanceId: string\n\n /**\n * Resolved configuration for this instance\n */\n readonly config: SanityConfig\n\n /**\n * Checks if the instance has been disposed\n * @returns true if dispose() has been called\n */\n isDisposed(): boolean\n\n /**\n * Disposes the instance and cleans up associated resources\n * @remarks Triggers all registered onDispose callbacks\n */\n dispose(): void\n\n /**\n * Registers a callback to be invoked when the instance is disposed\n * @param cb - Callback to execute on disposal\n * @returns Function to unsubscribe the callback\n */\n onDispose(cb: () => void): () => void\n}\n\n/**\n * Creates a new Sanity resource instance\n * @param config - Configuration for the instance (optional)\n * @returns A configured SanityInstance\n *\n * @public\n */\nexport function createSanityInstance(config: SanityConfig = {}): SanityInstance {\n const instanceId = crypto.randomUUID()\n const disposeListeners = new Map<string, () => void>()\n const disposed = {current: false}\n\n // Create instance context for logging\n const instanceContext: InstanceContext = {\n instanceId,\n projectId: config.projectId,\n dataset: config.dataset,\n }\n\n // Create logger with instance context\n const logger = createLogger('sdk', {instanceContext})\n\n // Log instance creation\n logger.info('Sanity instance created', {\n hasProjectId: !!config.projectId,\n hasDataset: !!config.dataset,\n hasAuth: !!config.auth,\n hasPerspective: !!config.perspective,\n })\n\n // Log configuration details at debug level\n logger.debug('Instance configuration', {\n projectId: config.projectId,\n dataset: config.dataset,\n perspective: config.perspective,\n hasStudioConfig: !!config.studio,\n hasStudioTokenSource: !!config.studio?.auth?.token,\n hasAuthProviders: !!config.auth?.providers,\n hasAuthToken: !!config.auth?.token,\n })\n\n const instance: SanityInstance = {\n instanceId,\n config,\n isDisposed: () => disposed.current,\n dispose: () => {\n if (disposed.current) {\n logger.trace('Dispose called on already disposed instance', {internal: true})\n return\n }\n logger.trace('Disposing instance', {\n internal: true,\n listenerCount: disposeListeners.size,\n })\n disposed.current = true\n disposeListeners.forEach((listener) => listener())\n disposeListeners.clear()\n logger.info('Instance disposed')\n },\n onDispose: (cb) => {\n const listenerId = insecureRandomId()\n disposeListeners.set(listenerId, cb)\n return () => {\n disposeListeners.delete(listenerId)\n }\n },\n }\n\n return instance\n}\n","import {map, switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {defineFetcher} from '../store/fetcherStore'\n\nconst API_VERSION = 'v2025-07-11'\n\n/**\n * The resource types the Access API can scope a permission check to.\n *\n * @see https://www.sanity.io/docs/http-reference/access-api\n * @public\n */\nexport type AccessResourceType =\n | 'organization'\n | 'project'\n | 'media-library'\n | 'canvas'\n | 'dashboard'\n | 'view'\n\n/**\n * Fetcher checking whether the current user holds the given permissions on a\n * resource (`GET /access/:resourceType/:resourceId/user-permissions/me/check`),\n * on the shared fetcher cache. Resolves to a map of each requested permission\n * to whether the user has it. The key sorts the permission list, so permission\n * order doesn't create distinct cache entries.\n *\n * @see https://www.sanity.io/docs/http-reference/access-api\n * @internal\n */\nexport const checkPermissions = defineFetcher<\n [resourceType: AccessResourceType, resourceId: string, permissions: string[]],\n Record<string, boolean>\n>({\n name: 'checkPermissions',\n getKey: (_instance, resourceType, resourceId, permissions) =>\n `${resourceType}:${resourceId}:${[...permissions].sort().join(',')}`,\n fetch: (instance) => (resourceType, resourceId, permissions) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable\n .request<{data: Record<string, boolean>}>({\n uri: `/access/${resourceType}/${resourceId}/user-permissions/me/check`,\n query: {permissions},\n tag: 'access.check',\n })\n .pipe(map((response) => response.data)),\n ),\n ),\n tags: (_data, resourceType, resourceId) => [\n {type: 'access', id: `${resourceType}:${resourceId}`},\n ],\n})\n","/**\n * Serialises store options into a `@sanity/client` request query object.\n * Scalars are stringified and `undefined` values dropped; string arrays pass\n * through untouched so the client serialises them as repeated keys\n * (`permissions=a&permissions=b`).\n *\n * @internal\n */\nexport function buildQuery(\n params: Record<string, string | number | boolean | string[] | undefined>,\n): Record<string, string | string[]> {\n return Object.fromEntries(\n Object.entries(params)\n .filter(([, value]) => value !== undefined)\n .map(([key, value]) => [key, Array.isArray(value) ? value : String(value)]),\n )\n}\n","import {switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {defineFetcher, defineMutation} from '../store/fetcherStore'\nimport {buildQuery} from '../utils/buildQuery'\nimport {type Included, type IncludesAny} from '../utils/includeShape'\n\n// The Applications API is currently only available on vX.\nconst API_VERSION = 'vX'\n\n/**\n * Related data the Applications API can embed in a response. `interfaces`,\n * `workspaces` and `access` are children of the active deployment and are\n * embedded under {@link Application.activeDeployment}; `config.studio` and\n * `config.mfManifest` are embedded under {@link Application.config}.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport type ApplicationInclude =\n | 'interfaces'\n | 'workspaces'\n | 'access'\n | 'config.studio'\n | 'config.mfManifest'\n | 'activeDeployment'\n\n/**\n * An interface exposed by a deployment, embedded when `interfaces` is included.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface ApplicationInterface {\n id: string\n type: 'app' | 'worker' | 'asset_source' | 'panel'\n name: string\n title: string\n version: string\n /** Module federation module ID; resolved from the host mf-manifest at runtime */\n moduleId: string\n metadata: {group?: string; priority?: number} | null\n}\n\n/**\n * A studio workspace of a deployment, embedded when `workspaces` is included.\n * Studio applications only.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface ApplicationWorkspace {\n id: string\n name: string\n title: string | null\n subtitle: string | null\n projectId: string\n dataset: string\n schemaDescriptorId: string | null\n basePath: string | null\n /** Sanitized SVG icon markup */\n icon: string | null\n}\n\n/**\n * A resource an application accesses, embedded when `access` is included.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface ApplicationAccess {\n id: string\n resourceType: 'datasets' | 'canvases' | 'dashboards' | 'media-libraries'\n resourceId: string\n}\n\n/**\n * Studio configuration, embedded under `config` when `config.studio` is included.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface ApplicationStudioConfig {\n projectId: string\n /** Release channel (`next`, `stable`, `latest`) or a pinned semver; null if unset */\n autoUpdatingVersion: string | null\n}\n\n/**\n * The active deployment as embedded under {@link Application.activeDeployment}.\n * Its `interfaces`, `workspaces` and `access` children are each present only\n * when the matching {@link ApplicationInclude} token was requested. `workspaces`\n * is omitted (not `null`) for non-studio applications even when requested.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport type ApplicationDeployment<Include extends ApplicationInclude = never> = {\n id: string\n applicationId: string\n size: number | null\n version: string | null\n isAutoUpdating: boolean | null\n isActiveDeployment: boolean\n deployedBy: string | null\n createdAt: string\n updatedAt: string\n} & Included<ApplicationInclude, 'interfaces', Include, {interfaces: ApplicationInterface[]}> &\n Included<ApplicationInclude, 'workspaces', Include, {workspaces?: ApplicationWorkspace[]}> &\n Included<ApplicationInclude, 'access', Include, {access: ApplicationAccess[]}>\n\n/**\n * The always-present fields of an org-owned application returned by the\n * Applications API (`/applications`), before any {@link ApplicationInclude}.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface ApplicationBase {\n id: string\n type: 'studio' | 'coreApp'\n title: string\n /** Stable, immutable identity, distinct from the mutable `slug` address. */\n name: string\n /** Qualified, globally-unique handle: `sanity/<name>` for singletons, `<organizationId>/<name>` otherwise. */\n reference: string\n icon: string | null\n isSingleton: boolean\n visibility: 'default' | 'unlisted' | 'disabled'\n slug: string | null\n externalUrl: string | null\n organizationId: string\n createdAt: string\n updatedAt: string\n}\n\n// Requesting any of these tokens forces the deployment summary into the response.\ntype DeploymentToken = 'activeDeployment' | 'interfaces' | 'workspaces' | 'access'\n\n// `config` is present when either config child was requested; each child is\n// gated on its own token.\ntype ApplicationConfigShape<Include extends ApplicationInclude> = Included<\n ApplicationInclude,\n 'config.studio',\n Include,\n {config: {studio: ApplicationStudioConfig}}\n> &\n Included<ApplicationInclude, 'config.mfManifest', Include, {config: {mfManifest: unknown}}>\n\n// `activeDeployment` is present when any deployment-related token was requested;\n// a wide include array makes it optional.\ntype ApplicationDeploymentShape<Include extends ApplicationInclude> = [ApplicationInclude] extends [\n Include,\n]\n ? {activeDeployment?: ApplicationDeployment<Include> | null}\n : IncludesAny<Include, DeploymentToken> extends true\n ? {activeDeployment: ApplicationDeployment<Include> | null}\n : unknown\n\n/**\n * An org-owned application as returned by the Applications API\n * (`/applications`). `config` and `activeDeployment` (with its\n * `interfaces`/`workspaces`/`access` children) are present only when the\n * corresponding {@link ApplicationInclude} tokens were requested.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport type Application<Include extends ApplicationInclude = never> = ApplicationBase &\n ApplicationConfigShape<Include> &\n ApplicationDeploymentShape<Include>\n\n/**\n * Options for listing an organization's applications.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface ApplicationsOptions<Include extends ApplicationInclude = ApplicationInclude> {\n organizationId: string\n /** Filter by application type */\n type?: string\n include?: Include[]\n /** Page size (1-100, default 50), or `'none'` to disable pagination */\n limit?: number | 'none'\n /** Cursor from a previous response's `nextCursor` */\n cursor?: string\n}\n\n/**\n * The cursor-paginated envelope returned by `GET /applications`.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface ApplicationsResponse<Include extends ApplicationInclude = never> {\n nextCursor: string | null\n data: Application<Include>[]\n}\n\n/** The API takes `include` as a comma-separated list; sorted so key and query agree */\nfunction serializeInclude(include: ApplicationInclude[] | undefined): string | undefined {\n return include?.length ? [...include].sort().join(',') : undefined\n}\n\n/**\n * Fetcher for an organization's applications (`GET /applications`), on the\n * shared fetcher cache.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @internal\n */\nexport const applications = defineFetcher<\n [options: ApplicationsOptions],\n ApplicationsResponse<ApplicationInclude>\n>({\n name: 'applications',\n getKey: (_instance, options) =>\n [\n options.organizationId,\n options.type ?? '',\n serializeInclude(options.include) ?? '',\n options.limit ?? '',\n options.cursor ?? '',\n ].join(':'),\n fetch: (instance) => (options) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable.request<ApplicationsResponse<ApplicationInclude>>({\n uri: '/applications',\n query: buildQuery({\n organizationId: options.organizationId,\n type: options.type,\n include: serializeInclude(options.include),\n limit: options.limit,\n cursor: options.cursor,\n }),\n tag: 'applications.list',\n }),\n ),\n ),\n tags: (data) => [\n {type: 'application', id: 'LIST'},\n ...data.data.map((app) => ({type: 'application', id: app.id})),\n ],\n})\n\n/**\n * Fetcher for a single application (`GET /applications/:id`), on the shared\n * fetcher cache. No pre-seeding from {@link applications}: its list keys\n * include the organization, which this fetcher's params can't reconstruct.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @internal\n */\nexport const application = defineFetcher<\n [applicationId: string, options?: {include?: ApplicationInclude[]}],\n Application<ApplicationInclude>\n>({\n name: 'application',\n getKey: (_instance, applicationId, options) =>\n `${applicationId}:${serializeInclude(options?.include) ?? ''}`,\n fetch: (instance) => (applicationId, options) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable.request<Application<ApplicationInclude>>({\n uri: `/applications/${applicationId}`,\n query: buildQuery({include: serializeInclude(options?.include)}),\n tag: 'applications.get',\n }),\n ),\n ),\n tags: (data) => [{type: 'application', id: data.id}],\n})\n\n/**\n * Confirmation returned by the API's soft-delete endpoints.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @internal\n */\nexport interface DeletedResult {\n deleted: boolean\n}\n\n/**\n * Dashboard visibility for an application.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @internal\n */\nexport type ApplicationVisibility = ApplicationBase['visibility']\n\n/**\n * Mutable properties of an application (`PATCH /applications/:id`) — the\n * writable subset of {@link ApplicationBase}, each optional, keyed by id.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @internal\n */\nexport type UpdateApplicationInput = {applicationId: string} & Partial<\n Pick<ApplicationBase, 'title' | 'icon' | 'visibility'>\n>\n\n/**\n * Mutation to update an application (`PATCH /applications/:id`). Invalidates the\n * updated application and the list so active entries reconverge on server truth.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @internal\n */\nexport const updateApplication = defineMutation<UpdateApplicationInput, Application>({\n name: 'updateApplication',\n mutationFn:\n (instance) =>\n ({applicationId, ...body}) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable.request<Application>({\n uri: `/applications/${applicationId}`,\n method: 'PATCH',\n body,\n tag: 'applications.update',\n }),\n ),\n ),\n invalidates: (_result, {applicationId}) => [\n {type: 'application', id: 'LIST'},\n {type: 'application', id: applicationId},\n ],\n})\n\n/**\n * Input for {@link deleteApplication}.\n *\n * @internal\n */\nexport interface DeleteApplicationInput {\n applicationId: string\n}\n\n/**\n * Mutation to soft-delete an application (`DELETE /applications/:id`).\n * Invalidates the deleted application and the list.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @internal\n */\nexport const deleteApplication = defineMutation<DeleteApplicationInput, DeletedResult>({\n name: 'deleteApplication',\n mutationFn:\n (instance) =>\n ({applicationId}) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable.request<DeletedResult>({\n uri: `/applications/${applicationId}`,\n method: 'DELETE',\n tag: 'applications.delete',\n }),\n ),\n ),\n invalidates: (_result, {applicationId}) => [\n {type: 'application', id: 'LIST'},\n {type: 'application', id: applicationId},\n ],\n})\n","/**\n * Error message returned by the organization verification\n * @public\n */\nexport interface OrgVerificationResult {\n error: string | null\n}\n\n/**\n * Compares a project's actual organization ID with the expected organization ID.\n * @public\n */\nexport function compareProjectOrganization(\n projectId: string,\n projectOrganizationId: string | null | undefined,\n currentDashboardOrgId: string,\n): OrgVerificationResult {\n if (projectOrganizationId !== currentDashboardOrgId) {\n return {\n error:\n `Project ${projectId} belongs to Organization ${projectOrganizationId ?? 'unknown'}, ` +\n `but the Dashboard has Organization ${currentDashboardOrgId} selected`,\n }\n }\n return {error: null}\n}\n","import {switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {type Project} from '../project/project'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {defineFetcher} from '../store/fetcherStore'\nimport {buildQuery} from '../utils/buildQuery'\n\nconst API_VERSION = 'v2025-02-19'\n\n/** @public */\nexport interface ProjectsOptions<\n IncludeMembers extends boolean = false,\n IncludeFeatures extends boolean = true,\n> {\n organizationId?: string\n includeMembers?: IncludeMembers\n includeFeatures?: IncludeFeatures\n onlyExplicitMembership?: boolean\n}\n\nfunction normalizeProjectsOptions(options?: ProjectsOptions<boolean, boolean>) {\n return {\n organizationId: options?.organizationId,\n includeMembers: options?.includeMembers ?? false,\n includeFeatures: options?.includeFeatures ?? true,\n onlyExplicitMembership: options?.onlyExplicitMembership ?? false,\n }\n}\n\n/** @internal */\nexport function getProjectsCacheKey(\n _instance: SanityInstance,\n options?: ProjectsOptions<boolean, boolean>,\n): string {\n const {organizationId, includeMembers, includeFeatures, onlyExplicitMembership} =\n normalizeProjectsOptions(options)\n const orgKey = organizationId ? `:org:${organizationId}` : ''\n const membersKey = includeMembers ? ':members' : ''\n const featuresKey = includeFeatures ? ':features' : ''\n const explicitKey = onlyExplicitMembership ? ':explicit' : ''\n return `projects${orgKey}${membersKey}${featuresKey}${explicitKey}`\n}\n\n/**\n * Fetcher for the current user's projects (`GET /projects`), on the shared\n * fetcher cache.\n *\n * @internal\n */\nexport const projects = defineFetcher<\n [options?: ProjectsOptions<boolean, boolean>],\n Project<boolean, boolean>[]\n>({\n name: 'projects',\n getKey: getProjectsCacheKey,\n fetch: (instance) => (options) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable.request<Project<boolean, boolean>[]>({\n uri: '/projects',\n query: buildQuery(normalizeProjectsOptions(options)),\n tag: 'projects.list',\n }),\n ),\n ),\n tags: (data) => [\n {type: 'project', id: 'LIST'},\n ...data.map((project) => ({type: 'project', id: project.id})),\n ],\n})\n","import {switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {type ProjectHandle} from '../config/sanityConfig'\nimport {projects} from '../projects/projects'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {defineFetcher} from '../store/fetcherStore'\nimport {buildQuery} from '../utils/buildQuery'\n\nconst API_VERSION = 'v2025-02-19'\n\n/** @public */\nexport interface ProjectMemberRole {\n name: string\n title: string\n description: string\n}\n\n/** @public */\nexport interface ProjectMember {\n id: string\n createdAt: string\n updatedAt: string\n isCurrentUser: boolean\n isRobot: boolean\n roles: ProjectMemberRole[]\n}\n\n/** @public */\nexport interface ProjectMetadata {\n color?: string\n externalStudioHost?: string\n initialTemplate?: string\n cliInitializedAt?: string\n integration: 'manage' | 'cli'\n}\n\n/**\n * The base fields returned from `/projects` for every project.\n * @public\n */\nexport interface ProjectBase {\n id: string\n displayName: string\n studioHost: string | null\n organizationId: string\n metadata: ProjectMetadata\n isBlocked: boolean\n isDisabled: boolean\n isDisabledByUser: boolean\n activityFeedEnabled: boolean\n createdAt: string\n updatedAt: string\n}\n\n/**\n * A `Project` with `members` and/or `features` conditionally included\n * based on the query options used to fetch it.\n * @public\n */\nexport type Project<\n IncludeMembers extends boolean = true,\n IncludeFeatures extends boolean = true,\n> = ProjectBase &\n // `boolean extends T` is non-distributive — true only when T is the wide\n // `boolean`, in which case the field is optional. Literal `true`/`false`\n // fall through to the strict branch.\n (boolean extends IncludeMembers\n ? {members?: ProjectMember[]}\n : IncludeMembers extends true\n ? {members: ProjectMember[]}\n : unknown) &\n (boolean extends IncludeFeatures\n ? {features?: string[]}\n : IncludeFeatures extends true\n ? {features: string[]}\n : unknown)\n\n/** @public */\nexport interface ProjectOptions<\n IncludeMembers extends boolean = true,\n IncludeFeatures extends boolean = true,\n> extends ProjectHandle {\n includeMembers?: IncludeMembers\n includeFeatures?: IncludeFeatures\n}\n\nfunction normalizeProjectOptions(options?: ProjectOptions<boolean, boolean>) {\n return {\n includeMembers: options?.includeMembers ?? true,\n includeFeatures: options?.includeFeatures ?? true,\n }\n}\n\nfunction resolveProjectId(instance: SanityInstance, options?: ProjectOptions<boolean, boolean>) {\n const projectId = options?.projectId ?? instance.config.projectId\n if (!projectId) {\n throw new Error('A projectId is required to use the project API.')\n }\n return projectId\n}\n\n/** @internal */\nexport function getProjectCacheKey(\n instance: SanityInstance,\n options?: ProjectOptions<boolean, boolean>,\n): string {\n const projectId = resolveProjectId(instance, options)\n const {includeMembers, includeFeatures} = normalizeProjectOptions(options)\n const membersKey = includeMembers ? ':members' : ''\n const featuresKey = includeFeatures ? ':features' : ''\n return `project:${projectId}${membersKey}${featuresKey}`\n}\n\n/**\n * Fetcher for a single project (`GET /projects/:id`), on the shared fetcher\n * cache. Pre-seeds from the default {@link projects} list entry when it can\n * satisfy the read — the default list carries features but not members, so\n * only `includeMembers: false` reads seed.\n *\n * @internal\n */\nexport const project = defineFetcher<\n [options?: ProjectOptions<boolean, boolean>],\n Project<boolean, boolean>\n>({\n name: 'project',\n getKey: getProjectCacheKey,\n fetch: (instance) => (options) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable.request<Project<boolean, boolean>>({\n uri: `/projects/${resolveProjectId(instance, options)}`,\n query: buildQuery(normalizeProjectOptions(options)),\n tag: 'projects.get',\n }),\n ),\n ),\n tags: (data) => [{type: 'project', id: data.id}],\n initialData: (instance, options) => {\n if (normalizeProjectOptions(options).includeMembers) return undefined\n const snapshot = projects.getState(instance).getCurrent()\n if (snapshot.status !== 'success') return undefined\n const projectId = resolveProjectId(instance, options)\n const match = snapshot.data.find((item) => item.id === projectId)\n return match && {data: match, dataUpdatedAt: snapshot.dataUpdatedAt}\n },\n})\n","import {bindActionGlobally} from '../store/createActionBinder'\nimport {createStateSourceAction} from '../store/createStateSourceAction'\nimport {authStore} from './authStore'\n\n/**\n * Gets the dashboard organization ID from the auth store\n * @internal\n */\nexport const getDashboardOrganizationId = bindActionGlobally(\n authStore,\n createStateSourceAction(({state: {dashboardContext}}) => dashboardContext?.orgId),\n)\n","import {combineLatest, distinctUntilChanged, map, type Observable, of, switchMap} from 'rxjs'\n\nimport {\n compareProjectOrganization,\n type OrgVerificationResult,\n} from '../project/organizationVerification'\nimport {project} from '../project/project'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {getDashboardOrganizationId} from './dashboardUtils'\n\n/**\n * Creates an observable that emits the organization verification state for a given instance.\n * It combines the dashboard organization ID (from auth context) with the\n * project's actual organization ID (fetched via the project fetcher) and compares them.\n * @public\n */\nexport function observeOrganizationVerificationState(\n instance: SanityInstance,\n projectIds: string[],\n): Observable<OrgVerificationResult> {\n // Observable for the dashboard org ID (potentially null)\n const dashboardOrgId$ =\n getDashboardOrganizationId(instance).observable.pipe(distinctUntilChanged())\n\n // Create observables for each project's org ID\n const projectOrgIdObservables = projectIds.map((id) =>\n project.getState(instance, {projectId: id}).observable.pipe(\n map((snapshot) => ({projectId: id, orgId: snapshot.data?.organizationId ?? null})),\n // Ensure we only proceed if the orgId is loaded, distinct prevents unnecessary checks\n distinctUntilChanged((prev, curr) => prev.orgId === curr.orgId),\n ),\n )\n\n // Combine observables to get all project org IDs\n const allProjectOrgIds$ =\n projectOrgIdObservables.length > 0 ? combineLatest(projectOrgIdObservables) : of([])\n\n // Combine the sources\n return combineLatest([dashboardOrgId$, allProjectOrgIds$]).pipe(\n switchMap(([dashboardOrgId, projectOrgDataArray]) => {\n // If no dashboard org ID is set, or no project IDs provided, verification isn't applicable/possible\n if (!dashboardOrgId || projectOrgDataArray.length === 0) {\n return of<OrgVerificationResult>({error: null}) // Return success (no error)\n }\n\n // Iterate through all projects and check organization IDs\n for (const projectData of projectOrgDataArray) {\n // If a project doesn't have an orgId, we can't verify, treat as non-blocking for now\n // (Matches original logic where null projectOrgId resulted in {error: null})\n if (!projectData.orgId) {\n continue\n }\n\n // Perform the comparison for the current project\n const result = compareProjectOrganization(\n projectData.projectId,\n projectData.orgId,\n dashboardOrgId,\n )\n\n // If any project fails verification, immediately return the error\n if (result.error) {\n return of(result)\n }\n }\n\n // If all projects passed verification (or had no orgId to check)\n return of<OrgVerificationResult>({error: null})\n }),\n // Only emit when the overall error status actually changes\n distinctUntilChanged((prev, curr) => prev.error === curr.error),\n )\n}\n","import {bindActionGlobally} from '../store/createActionBinder'\nimport {DEFAULT_API_VERSION, REQUEST_TAG_PREFIX} from './authConstants'\nimport {getAuthLogger} from './authLogger'\nimport {AuthStateType} from './authStateType'\nimport {authStore, type AuthStoreState, type DashboardContext} from './authStore'\nimport {\n createLoggedInAuthState,\n getAuthCode,\n getCleanedUrl,\n getDefaultLocation,\n getTokenFromLocation,\n} from './utils'\n\n/**\n * @public\n */\nexport const handleAuthCallback = bindActionGlobally(\n authStore,\n async ({state, instance}, locationHref: string = getDefaultLocation()) => {\n const logger = getAuthLogger(instance)\n\n const {providedToken, callbackUrl, clientFactory, apiHost, storageArea, storageKey} =\n state.get().options\n\n // If a token is provided, no need to handle callback\n if (providedToken) {\n logger.debug('Skipping auth callback - token already provided')\n return false\n }\n\n // Don't handle the callback if already in flight.\n const {authState} = state.get()\n if (authState.type === AuthStateType.LOGGING_IN && authState.isExchangingToken) {\n logger.debug('Skipping auth callback - token exchange already in progress')\n return false\n }\n\n // Prepare the cleaned-up URL early. It will be returned on both success and error if an authCode/token was processed.\n const cleanedUrl = getCleanedUrl(locationHref)\n\n // Check if there is a token in the is in the Dashboard iframe url hash\n const tokenFromUrl = getTokenFromLocation(locationHref)\n if (tokenFromUrl) {\n logger.info('Auth token found in URL, logging in')\n state.set('setTokenFromUrl', {\n authState: createLoggedInAuthState(tokenFromUrl, null),\n })\n return cleanedUrl\n }\n\n // If there is no matching `authCode` then we can't handle the callback\n const authCode = getAuthCode(callbackUrl, locationHref)\n if (!authCode) {\n logger.debug('No auth code found in callback URL')\n return false\n }\n\n // Get the SanityOS dashboard context from the url\n const parsedUrl = new URL(locationHref)\n let dashboardContext: DashboardContext = {}\n try {\n const contextParam = parsedUrl.searchParams.get('_context')\n if (contextParam) {\n const parsedContext = JSON.parse(contextParam)\n if (parsedContext && typeof parsedContext === 'object') {\n delete parsedContext.sid\n dashboardContext = parsedContext\n logger.debug('Dashboard context parsed from callback URL', {\n hasDashboardContext: true,\n })\n }\n }\n } catch (err) {\n // If JSON parsing fails, use empty context\n logger.warn('Failed to parse dashboard context from callback URL', {error: err})\n }\n\n // Otherwise, start the exchange\n logger.info('Exchanging auth code for token')\n state.set('exchangeSessionForToken', {\n authState: {type: AuthStateType.LOGGING_IN, isExchangingToken: true},\n dashboardContext,\n } as Partial<AuthStoreState>)\n\n try {\n const client = clientFactory({\n apiVersion: DEFAULT_API_VERSION,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n useProjectHostname: false,\n useCdn: false,\n ...(apiHost && {apiHost}),\n })\n\n logger.debug('Fetching token from auth endpoint')\n const {token} = await client.request<{token: string; label: string}>({\n method: 'GET',\n uri: '/auth/fetch',\n query: {sid: authCode},\n tag: 'fetch-token',\n })\n\n logger.info('Auth token obtained successfully, user logged in')\n storageArea?.setItem(storageKey, JSON.stringify({token}))\n state.set('setToken', {authState: createLoggedInAuthState(token, null)})\n\n return cleanedUrl\n } catch (error) {\n logger.error('Failed to exchange auth code for token', {error})\n state.set('exchangeSessionForTokenError', {authState: {type: AuthStateType.ERROR, error}})\n return cleanedUrl\n }\n },\n)\n","import {bindActionGlobally} from '../store/createActionBinder'\nimport {DEFAULT_API_VERSION, REQUEST_TAG_PREFIX} from './authConstants'\nimport {getAuthLogger} from './authLogger'\nimport {AuthStateType} from './authStateType'\nimport {authStore} from './authStore'\n\n/**\n * @public\n */\nexport const logout = bindActionGlobally(authStore, async ({state, instance}) => {\n const logger = getAuthLogger(instance)\n\n const {clientFactory, apiHost, providedToken, storageArea, storageKey} = state.get().options\n\n // If a token is statically provided, logout does nothing\n if (providedToken) {\n logger.debug('Skipping logout - token is statically provided')\n return\n }\n\n const {authState} = state.get()\n\n // If we already have an inflight request, no-op\n if (authState.type === AuthStateType.LOGGED_OUT && authState.isDestroyingSession) {\n logger.debug('Skipping logout - already in progress')\n return\n }\n const token = authState.type === AuthStateType.LOGGED_IN && authState.token\n\n try {\n if (token) {\n logger.info('Logging out user')\n state.set('loggingOut', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: true},\n })\n\n const client = clientFactory({\n token,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n apiVersion: DEFAULT_API_VERSION,\n ...(apiHost && {apiHost}),\n useProjectHostname: false,\n useCdn: false,\n })\n\n logger.debug('Calling logout endpoint')\n await client.request<void>({uri: '/auth/logout', method: 'POST', tag: 'logout'})\n } else {\n logger.debug('No token to logout - already logged out')\n }\n } catch (error) {\n // Re-throw to preserve the existing contract: logout rejects when the\n // request fails. Local state is still cleared in the finally block.\n logger.error('Logout request failed', {error})\n throw error\n } finally {\n logger.info('User logged out, clearing stored tokens')\n state.set('logoutSuccess', {\n authState: {type: AuthStateType.LOGGED_OUT, isDestroyingSession: false},\n })\n storageArea?.removeItem(storageKey)\n storageArea?.removeItem(`${storageKey}_last_refresh`)\n }\n})\n","function weaken(node: unknown): unknown {\n if (Array.isArray(node)) {\n return node.map(weaken)\n }\n\n if (node && typeof node === 'object') {\n if ('_ref' in node) {\n return {...node, _weak: true}\n }\n\n return Object.fromEntries(Object.entries(node).map(([key, value]) => [key, weaken(value)]))\n }\n\n return node\n}\n\n/**\n * Marks every reference in a content snapshot weak.\n *\n * A comment's snapshot is written into the addon dataset, but its references\n * point at documents in the main one. Left strong, Content Lake would refuse to\n * delete any document a snapshot happens to mention, so an old comment could\n * pin a document forever.\n *\n * @internal\n */\nexport function weakenReferencesInContentSnapshot(snapshot: unknown): unknown {\n return weaken(snapshot)\n}\n","import {type SanityClient} from '@sanity/client'\nimport {DocumentId, getPublishedId} from '@sanity/id-utils'\nimport {type Path} from '@sanity/types'\nimport {filter, firstValueFrom, take} from 'rxjs'\n\nimport {getCurrentUserState} from '../auth/authStore'\nimport {getClient} from '../client/clientStore'\nimport {\n type DatasetHandle,\n type DatasetResource,\n type DocumentHandle,\n type DocumentResource,\n} from '../config/sanityConfig'\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\nimport {bindActionByResource, type BoundResourceKey} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {type StoreState} from '../store/createStoreState'\nimport {type StoreContext} from '../store/defineStore'\nimport {\n assertDatasetResource,\n getAddonDatasetState,\n provisionAddonDataset,\n} from './addonDatasetStore'\nimport {toCommentFieldPath} from './commentFieldPath'\nimport {COMMENTS_API_VERSION} from './commentsConstants'\nimport {type CommentsOptions, commentsStore, toCommentsKeyParts} from './commentsStore'\nimport {normalizeComment} from './normalizeComment'\nimport {\n addComment,\n applyCommentUpdate,\n clearPendingTransaction,\n type CommentsStoreState,\n getCommentsKey,\n receiveComment,\n removeCommentById,\n restoreComments,\n rollbackCommentUpdate,\n setCommentCreateError,\n setPendingTransaction,\n} from './reducers'\nimport {\n type Comment,\n type CommentMessage,\n type CommentPostPayload,\n type CommentStatus,\n type CommentTextSelection,\n type StoredComment,\n} from './types'\nimport {weakenReferencesInContentSnapshot} from './weakenReferences'\n\n/** @beta */\nexport interface CreateCommentOptions extends DocumentHandle {\n message: CommentMessage\n /**\n * Which field the thread hangs off, for example `title` or\n * `body[_key==\"intro\"].content`.\n *\n * Required, and it has to resolve to a real path. There is no such thing as a\n * comment on a document as a whole: the Studio only ever creates field\n * comments, and its comment inspector throws on an empty path rather than\n * ignoring it, so a pathless comment takes the inspector down for everyone\n * looking at that document.\n */\n fieldPath: string | Path\n /**\n * Anchors the comment to a run of text inside a Portable Text field. Building\n * one needs a live editor, so this comes from\n * `@portabletext/plugin-sdk-value` rather than being constructed by hand.\n */\n selection?: CommentTextSelection\n /** Reuse the id of a failed comment to retry it. Defaults to a new id. */\n commentId?: string\n /** Defaults to a new id, which starts a new thread. */\n threadId?: string\n /** @defaultValue `'open'` */\n status?: CommentStatus\n /**\n * The `_rev` of the document when the comment was written.\n *\n * Not filled in automatically: the SDK's local document revision is replaced\n * by a transaction id while an edit is in flight, so it can name a revision\n * that never reached the server. Nothing in the Studio reads this today.\n */\n documentRevisionId?: string\n /**\n * Ambient information stored alongside the comment, merged over the defaults.\n *\n * The Studio writes `tool`, `payload`, `intent`, and `notification` here for\n * its notification backend. The SDK has no source for any of them, so\n * mentions in comments created this way do not send email unless you supply\n * `notification` yourself. Deliberately loose: the organization-level store\n * treats this as free-form, so no shape is worth promising.\n */\n context?: Record<string, unknown>\n /** A copy of the content being discussed. References in it are weakened. */\n contentSnapshot?: unknown\n}\n\n/** @beta */\nexport interface ReplyToCommentOptions extends DocumentHandle {\n /** The comment being replied to. Replies to a reply join the same thread. */\n parentCommentId: string\n message: CommentMessage\n commentId?: string\n /** Only needed when the parent is not loaded, such as following a deep link. */\n threadId?: string\n /** Only needed when the parent is not loaded. */\n fieldPath?: string | Path\n /** Required when the parent is not loaded. */\n status?: CommentStatus\n}\n\n/** @beta */\nexport interface UpdateCommentOptions extends DatasetHandle {\n commentId: string\n message: CommentMessage\n}\n\n/** @beta */\nexport interface SetCommentStatusOptions extends DatasetHandle {\n /** The thread's first comment. Replies follow their parent. */\n commentId: string\n status: CommentStatus\n}\n\n/** @beta */\nexport interface RemoveCommentOptions extends DatasetHandle {\n commentId: string\n}\n\n/**\n * Refuses to write a comment that points at nothing.\n *\n * The type already requires `fieldPath`, but an empty string or an empty path\n * array both survive that and normalise to `''`. Such a comment is not merely\n * useless: the Studio's comment inspector calls `fromString` on the stored\n * path, which throws on `''`, so the inspector crashes for everyone viewing\n * that document until the comment is deleted. Cheaper to refuse the write.\n */\nfunction requireFieldPath(fieldPath: string | Path): string {\n const normalized = toCommentFieldPath(fieldPath)\n if (!normalized) {\n throw new Error(\n 'A comment needs a field path. Comments attach to a field, not to a document as a whole.',\n )\n }\n return normalized\n}\n\nfunction requireCurrentUserId(instance: SanityInstance): string {\n const userId = getCurrentUserState(instance).getCurrent()?.id\n if (!userId) {\n throw new Error('Writing a comment requires a logged in user.')\n }\n return userId\n}\n\n/** Waits out discovery, then insists the addon dataset exists. */\nasync function requireAddonDataset(\n instance: SanityInstance,\n resource: DocumentResource,\n): Promise<string> {\n const datasetName = await firstValueFrom(\n getAddonDatasetState(instance, {resource}).observable.pipe(\n filter((value) => value !== undefined),\n take(1),\n ),\n )\n\n if (!datasetName) {\n throw new Error('This project has no comments dataset, so there is no comment to change.')\n }\n\n return datasetName\n}\n\nasync function getWritableClient(\n instance: SanityInstance,\n resource: DocumentResource,\n {createIfMissing}: {createIfMissing: boolean},\n): Promise<SanityClient> {\n const {projectId} = assertDatasetResource(resource)\n\n // Provisioning is a project-wide side effect, so only the create path may\n // trigger it. Editing or deleting a comment implies the dataset is there.\n const dataset = createIfMissing\n ? await provisionAddonDataset(instance, {resource})\n : await requireAddonDataset(instance, resource)\n\n return getClient(instance, {apiVersion: COMMENTS_API_VERSION, projectId, dataset})\n}\n\nfunction buildCommentPayload(options: {\n authorId: string\n commentId: string\n contentSnapshot?: unknown\n context?: Record<string, unknown>\n documentRevisionId?: string\n handle: DocumentHandle\n message: CommentMessage\n parentCommentId?: string\n resource: DatasetResource\n fieldPath: string\n selection?: CommentTextSelection\n status: CommentStatus\n threadId: string\n documentVersionId?: string\n}): CommentPostPayload {\n const {handle, resource} = options\n\n return {\n _id: options.commentId,\n _type: 'comment',\n authorId: options.authorId,\n message: options.message,\n threadId: options.threadId,\n ...(options.parentCommentId ? {parentCommentId: options.parentCommentId} : {}),\n status: options.status,\n reactions: null,\n // The Studio writes an empty tool name when no tool is active, and reads\n // this nowhere in its UI.\n context: {tool: '', ...options.context},\n ...(options.contentSnapshot === undefined\n ? {}\n : {contentSnapshot: weakenReferencesInContentSnapshot(options.contentSnapshot)}),\n target: {\n documentRevisionId: options.documentRevisionId ?? '',\n path: {\n field: options.fieldPath,\n ...(options.selection ? {selection: options.selection} : {}),\n },\n // The comment lives in the addon dataset, so this points across to the\n // dataset holding the document. Weak, or Content Lake would refuse to\n // delete a commented document.\n document: {\n _dataset: resource.dataset,\n _projectId: resource.projectId,\n _ref: getPublishedId(DocumentId(handle.documentId)),\n _type: 'crossDatasetReference',\n _weak: true,\n },\n documentType: handle.documentType,\n ...(options.documentVersionId ? {documentVersionId: options.documentVersionId} : {}),\n },\n }\n}\n\nfunction findComment(\n state: StoreState<CommentsStoreState>,\n commentsKey: string,\n commentId: string,\n): StoredComment | undefined {\n const comments = state.get().entries[commentsKey]?.comments\n return comments && Object.hasOwn(comments, commentId) ? comments[commentId] : undefined\n}\n\nfunction findCommentById(\n state: StoreState<CommentsStoreState>,\n commentId: string,\n): StoredComment | undefined {\n for (const entry of Object.values(state.get().entries)) {\n const comments = entry?.comments\n const comment = comments && Object.hasOwn(comments, commentId) ? comments[commentId] : undefined\n if (comment) return comment\n }\n return undefined\n}\n\nasync function postComment(\n context: StoreContext<CommentsStoreState, BoundResourceKey>,\n handle: DocumentHandle & CommentsOptions,\n payload: CommentPostPayload,\n): Promise<Comment> {\n const {state, instance, key} = context\n const commentsKey = getCommentsKey(toCommentsKeyParts(instance, handle))\n\n // Show it before the round trip, so a thread feels immediate.\n state.set('addComment', addComment(commentsKey, payload))\n\n try {\n const client = await getWritableClient(instance, key.resource, {createIfMissing: true})\n // `createIfNotExists` makes duplicate writes of the same id harmless, which\n // covers both a retry after a lost response and two concurrent calls with\n // the same comment id.\n const created = await client.createIfNotExists(payload, {tag: 'comments.create'})\n state.set('receiveComment', receiveComment(commentsKey, created))\n return normalizeComment(created)\n } catch (error) {\n // Keep it on screen carrying the failure, so an app can offer a retry with\n // the same id rather than silently losing what someone typed.\n state.set(\n 'setCommentCreateError',\n setCommentCreateError(payload._id, error instanceof Error ? error : new Error(String(error))),\n )\n throw error\n }\n}\n\n/**\n * Starts a thread on a document, or on one of its fields.\n *\n * Creates the project's comments dataset if this is the first comment anywhere\n * in it. The comment appears locally before the server confirms it; if the\n * write fails it stays, carrying `_state.createError`, and retrying with the\n * same `commentId` replaces it.\n *\n * @beta\n */\nexport const createComment: (\n instance: SanityInstance,\n options: CreateCommentOptions,\n) => Promise<Comment> = bindActionByResource(\n commentsStore,\n // `async` so a validation failure rejects rather than throwing at the call\n // site, which would slip past a `.catch()`.\n async (\n context: StoreContext<CommentsStoreState, BoundResourceKey>,\n options: CreateCommentOptions,\n ) => {\n const {instance, key} = context\n const perspective = options.perspective ?? instance.config.perspective\n const fieldPath = requireFieldPath(options.fieldPath)\n\n return postComment(\n context,\n options,\n buildCommentPayload({\n authorId: requireCurrentUserId(instance),\n commentId: options.commentId ?? crypto.randomUUID(),\n contentSnapshot: options.contentSnapshot,\n context: options.context,\n documentRevisionId: options.documentRevisionId,\n handle: options,\n message: options.message,\n resource: assertDatasetResource(key.resource),\n fieldPath,\n selection: options.selection,\n status: options.status ?? 'open',\n threadId: options.threadId ?? crypto.randomUUID(),\n ...(isReleasePerspective(perspective) ? {documentVersionId: perspective.releaseName} : {}),\n }),\n )\n },\n)\n\n/**\n * Adds a reply to an existing thread.\n *\n * The thread and field are taken from the parent comment, so a reply always\n * matches the same list as the comment it answers. Supply them only when the\n * parent is not loaded.\n *\n * @beta\n */\nexport const replyToComment: (\n instance: SanityInstance,\n options: ReplyToCommentOptions,\n) => Promise<Comment> = bindActionByResource(\n commentsStore,\n async (\n context: StoreContext<CommentsStoreState, BoundResourceKey>,\n options: ReplyToCommentOptions,\n ) => {\n const {instance, key, state} = context\n const commentsKey = getCommentsKey(toCommentsKeyParts(instance, options))\n const parent = findComment(state, commentsKey, options.parentCommentId)\n\n const threadId = options.threadId ?? parent?.threadId\n if (!threadId) {\n throw new Error(\n `Cannot reply to \"${options.parentCommentId}\": it is not loaded, so pass its threadId.`,\n )\n }\n\n const status = parent?.status ?? options.status\n if (!status) {\n throw new Error(\n `Cannot reply to \"${options.parentCommentId}\": it is not loaded, so pass its status.`,\n )\n }\n\n const perspective = options.perspective ?? instance.config.perspective\n\n return postComment(\n context,\n options,\n buildCommentPayload({\n authorId: requireCurrentUserId(instance),\n commentId: options.commentId ?? crypto.randomUUID(),\n handle: options,\n message: options.message,\n // Replies to a reply belong to the thread's first comment, matching how\n // the Studio flattens threads.\n parentCommentId: parent?.parentCommentId ?? options.parentCommentId,\n resource: assertDatasetResource(key.resource),\n // Inherited from the parent unless the caller names one, and checked\n // either way: a reply with no path crashes the Studio inspector exactly\n // as a pathless thread would.\n fieldPath: requireFieldPath(options.fieldPath ?? parent?.target.path?.field ?? ''),\n // A reply into a resolved thread stays consistent with its parent.\n status,\n threadId,\n ...(isReleasePerspective(perspective) ? {documentVersionId: perspective.releaseName} : {}),\n }),\n )\n },\n)\n\n/**\n * Rewrites a comment's message and stamps `lastEditedAt`.\n * @beta\n */\nexport const updateComment: (\n instance: SanityInstance,\n options: UpdateCommentOptions,\n) => Promise<void> = bindActionByResource(\n commentsStore,\n async (\n {state, instance, key}: StoreContext<CommentsStoreState, BoundResourceKey>,\n {commentId, message}: UpdateCommentOptions,\n ) => {\n const lastEditedAt = new Date().toISOString()\n const transactionId = crypto.randomUUID()\n const previous = findCommentById(state, commentId)\n\n if (previous) {\n state.set('setPendingTransaction', setPendingTransaction(commentId, transactionId))\n state.set('updateComment', applyCommentUpdate(commentId, {message, lastEditedAt}))\n }\n\n try {\n const client = await getWritableClient(instance, key.resource, {createIfMissing: false})\n await client\n .transaction()\n .transactionId(transactionId)\n .patch(client.patch(commentId).set({message, lastEditedAt}))\n .commit({tag: 'comments.update'})\n if (previous) {\n state.set('clearPendingTransaction', clearPendingTransaction(commentId))\n }\n } catch (error) {\n if (previous) {\n state.set(\n 'rollbackCommentUpdate',\n rollbackCommentUpdate(commentId, transactionId, previous),\n )\n }\n throw error\n }\n },\n)\n\n/**\n * Resolves or reopens a thread.\n *\n * Pass the thread's first comment: replies follow it, patched server-side in\n * one query so a reply created by someone else at the same moment is caught\n * too.\n *\n * @beta\n */\nexport const setCommentStatus: (\n instance: SanityInstance,\n options: SetCommentStatusOptions,\n) => Promise<void> = bindActionByResource(\n commentsStore,\n async (\n {state, instance, key}: StoreContext<CommentsStoreState, BoundResourceKey>,\n {commentId, status}: SetCommentStatusOptions,\n ) => {\n const transactionId = crypto.randomUUID()\n const previousComments: StoredComment[] = []\n\n for (const entry of Object.values(state.get().entries)) {\n for (const candidate of Object.values(entry?.comments ?? {})) {\n if (candidate._id !== commentId && candidate.parentCommentId !== commentId) continue\n previousComments.push(candidate)\n state.set('setPendingTransaction', setPendingTransaction(candidate._id, transactionId))\n state.set('updateCommentStatus', applyCommentUpdate(candidate._id, {status}))\n }\n }\n\n try {\n const client = await getWritableClient(instance, key.resource, {createIfMissing: false})\n\n await client.mutate(\n [\n {patch: {id: commentId, set: {status}}},\n {\n patch: {\n query: '*[_type == \"comment\" && parentCommentId == $commentId]',\n params: {commentId},\n set: {status},\n },\n },\n ],\n {transactionId, tag: 'comments.set-status'},\n )\n for (const previous of previousComments) {\n state.set('clearPendingTransaction', clearPendingTransaction(previous._id))\n }\n } catch (error) {\n for (const previous of previousComments) {\n state.set(\n 'rollbackCommentUpdate',\n rollbackCommentUpdate(previous._id, transactionId, previous),\n )\n }\n throw error\n }\n },\n)\n\n/**\n * Deletes a comment, and its replies when it starts a thread.\n * @beta\n */\nexport const removeComment: (\n instance: SanityInstance,\n options: RemoveCommentOptions,\n) => Promise<void> = bindActionByResource(\n commentsStore,\n async (\n {state, instance, key}: StoreContext<CommentsStoreState, BoundResourceKey>,\n {commentId}: RemoveCommentOptions,\n ) => {\n const removed = Object.entries(state.get().entries).flatMap(([entryKey, entry]) => {\n const comments = Object.values(entry?.comments ?? {}).filter(\n (comment) => comment._id === commentId || comment.parentCommentId === commentId,\n )\n return comments.length ? [{key: entryKey, comments}] : []\n })\n\n state.set('removeComment', removeCommentById(commentId))\n\n try {\n const client = await getWritableClient(instance, key.resource, {createIfMissing: false})\n await client.mutate(\n [\n {\n delete: {\n query: '*[_type == \"comment\" && parentCommentId == $commentId]',\n params: {commentId},\n },\n },\n {delete: {id: commentId}},\n ],\n {tag: 'comments.remove'},\n )\n } catch (error) {\n state.set('restoreComments', restoreComments(removed))\n throw error\n }\n },\n)\n","import {\n type DatasetHandle,\n type DocumentHandle,\n type DocumentTypeHandle,\n type ProjectHandle,\n} from './sanityConfig'\n\n/**\n * Creates or validates a `DocumentHandle` object.\n * Ensures the provided object conforms to the `DocumentHandle` interface.\n * @param handle - The object containing document identification properties.\n * @returns The validated `DocumentHandle` object.\n * @public\n */\nexport function createDocumentHandle<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n handle: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): DocumentHandle<TDocumentType, TDataset, TProjectId> {\n return handle\n}\n\n/**\n * Creates or validates a `DocumentTypeHandle` object.\n * Ensures the provided object conforms to the `DocumentTypeHandle` interface.\n * @param handle - The object containing document type identification properties.\n * @returns The validated `DocumentTypeHandle` object.\n * @public\n */\nexport function createDocumentTypeHandle<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n handle: DocumentTypeHandle<TDocumentType, TDataset, TProjectId>,\n): DocumentTypeHandle<TDocumentType, TDataset, TProjectId> {\n return handle\n}\n\n/**\n * Creates or validates a `ProjectHandle` object.\n * Ensures the provided object conforms to the `ProjectHandle` interface.\n * @param handle - The object containing project identification properties.\n * @returns The validated `ProjectHandle` object.\n * @public\n */\nexport function createProjectHandle<TProjectId extends string = string>(\n handle: ProjectHandle<TProjectId>,\n): ProjectHandle<TProjectId> {\n return handle\n}\n\n/**\n * Creates or validates a `DatasetHandle` object.\n * Ensures the provided object conforms to the `DatasetHandle` interface.\n * @param handle - The object containing dataset identification properties.\n * @returns The validated `DatasetHandle` object.\n * @public\n */\nexport function createDatasetHandle<\n TDataset extends string = string,\n TProjectId extends string = string,\n>(handle: DatasetHandle<TDataset, TProjectId>): DatasetHandle<TDataset, TProjectId> {\n return handle\n}\n","/**\n * Public API for configuring SDK logging\n *\n * @module loggingConfig\n */\n\nimport {configureLogging as _configureLogging, type LoggerConfig} from '../utils/logger'\n\n/**\n * Configure logging for the Sanity SDK\n *\n * This function allows you to control what logs are output by the SDK,\n * making it easier to debug issues in development or production.\n *\n * @remarks\n * **Zero-Config via Environment Variable (Recommended):**\n *\n * The SDK automatically reads the `DEBUG` environment variable, making it\n * easy to enable logging without code changes:\n *\n * ```bash\n * # Enable all SDK logging at debug level\n * DEBUG=sanity:* npm start\n *\n * # Enable specific namespaces\n * DEBUG=sanity:auth,sanity:document npm start\n *\n * # Enable trace level for all namespaces\n * DEBUG=sanity:trace:* npm start\n *\n * # Enable internal/maintainer logs\n * DEBUG=sanity:*:internal npm start\n * ```\n *\n * This matches the pattern used by Sanity CLI and Studio, making it familiar\n * and easy for support teams to help troubleshoot issues.\n *\n * **Programmatic Configuration (Advanced):**\n *\n * For more control (custom handlers, dynamic configuration), call this function\n * explicitly. Programmatic configuration overrides environment variables.\n *\n * **For Application Developers:**\n * Use `info`, `warn`, or `error` levels to see high-level SDK activity\n * without being overwhelmed by internal details.\n *\n * **For SDK Maintainers:**\n * Use `debug` or `trace` levels with `internal: true` to see detailed\n * information about store operations, RxJS streams, and state transitions.\n *\n * **Instance Context:**\n * Logs automatically include instance information (projectId, dataset, instanceId)\n * when available, making it easier to debug multi-instance scenarios:\n * ```\n * [INFO] [auth] [project:abc] [dataset:production] User logged in\n * ```\n *\n * **Available Namespaces:**\n * - `sdk` - SDK initialization, configuration, and lifecycle\n * - `auth` - Authentication and authorization (when instrumented in the future)\n * - And more as logging is added to modules\n *\n * @example Zero-config via environment variable (recommended for debugging)\n * ```bash\n * # Just set DEBUG and run your app - no code changes needed!\n * DEBUG=sanity:* npm start\n * ```\n *\n * @example Programmatic configuration (application developer)\n * ```ts\n * import {configureLogging} from '@sanity/sdk'\n *\n * // Log warnings and errors for auth and document operations\n * configureLogging({\n * level: 'warn',\n * namespaces: ['auth', 'document']\n * })\n * ```\n *\n * @example Programmatic configuration (SDK maintainer)\n * ```ts\n * import {configureLogging} from '@sanity/sdk'\n *\n * // Enable all logs including internal traces\n * configureLogging({\n * level: 'trace',\n * namespaces: ['*'],\n * internal: true\n * })\n * ```\n *\n * @example Custom handler (for testing)\n * ```ts\n * import {configureLogging} from '@sanity/sdk'\n *\n * const logs: string[] = []\n * configureLogging({\n * level: 'info',\n * namespaces: ['*'],\n * handler: {\n * error: (msg) => logs.push(msg),\n * warn: (msg) => logs.push(msg),\n * info: (msg) => logs.push(msg),\n * debug: (msg) => logs.push(msg),\n * trace: (msg) => logs.push(msg),\n * }\n * })\n * ```\n *\n * @public\n */\nexport function configureLogging(config: LoggerConfig): void {\n _configureLogging(config)\n\n // Always log configuration (bypasses namespace filtering)\n // This ensures users see the message regardless of which namespaces they enable\n const configLevel = config.level || 'warn'\n const shouldLog = ['info', 'debug', 'trace'].includes(configLevel) || configLevel === 'warn'\n\n if (shouldLog && config.handler?.info) {\n config.handler.info(`[${new Date().toISOString()}] [INFO] [sdk] Logging configured`, {\n level: configLevel,\n namespaces: config.namespaces || [],\n internal: config.internal || false,\n source: 'programmatic',\n })\n } else if (shouldLog) {\n // eslint-disable-next-line no-console\n console.info(`[${new Date().toISOString()}] [INFO] [sdk] Logging configured`, {\n level: configLevel,\n namespaces: config.namespaces || [],\n internal: config.internal || false,\n source: 'programmatic',\n })\n }\n}\n\n/**\n * Re-export types for public API\n * @public\n */\nexport type {\n InstanceContext,\n LogContext,\n Logger,\n LoggerConfig,\n LogLevel,\n LogNamespace,\n} from '../utils/logger'\n","import {asapScheduler, EMPTY, firstValueFrom, from, Observable} from 'rxjs'\nimport {\n catchError,\n delay,\n filter,\n first,\n groupBy,\n map,\n mergeMap,\n pairwise,\n startWith,\n switchMap,\n tap,\n} from 'rxjs/operators'\n\nimport {bindActionGlobally, type BoundStoreAction} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {\n createStateSourceAction,\n type SelectorContext,\n type StateSource,\n} from '../store/createStateSourceAction'\nimport {defineStore, type StoreContext} from '../store/defineStore'\nimport {insecureRandomId} from '../utils/ids'\nimport {omitProperty} from '../utils/object'\nimport {setCleanupTimeout} from './setCleanupTimeout'\n\ninterface CreateFetcherStoreOptions<TParams extends unknown[], TData> {\n /**\n * A unique name for this store (for devtools)\n */\n name: string\n /**\n * A function that creates the observable that will be used to fetch the data.\n */\n fetcher: (instance: SanityInstance) => (...params: TParams) => Observable<TData>\n /**\n * The function used to convert the params into keys that state related to\n * those params will be stored.\n */\n getKey: (instance: SanityInstance, ...params: TParams) => string\n /**\n * Delay in ms before clearing state after the last subscription is removed.\n * This results in react components suspending again due to no previous state\n * to show.\n */\n stateExpirationDelay?: number\n /**\n * The minimum time (ms) that must elapse since the last fetch for the same key\n */\n fetchThrottleInternal?: number\n}\n\ninterface StoreEntry<TParams extends unknown[], TData> {\n params: TParams\n instance: SanityInstance\n key: string\n data?: TData\n error?: unknown\n subscriptions: string[]\n lastFetchInitiatedAt?: string\n}\n\n/**\n * Internal helper type\n * @public\n */\nexport interface FetcherStoreState<TParams extends unknown[], TData> {\n stateByParams: {[TSerializedKey in string]?: StoreEntry<TParams, TData>}\n error?: unknown\n}\n\n/**\n * Internal helper type\n * @public\n */\nexport interface FetcherStore<TParams extends unknown[], TData> {\n getState: BoundStoreAction<\n FetcherStoreState<TParams, TData>,\n TParams,\n StateSource<TData | undefined>\n >\n resolveState: BoundStoreAction<FetcherStoreState<TParams, TData>, TParams, Promise<TData>>\n}\n\n/**\n * Creates a store from a function that returns an observable that fetches data\n * that supports parameterized state caching.\n *\n * This function creates a resource store keyed by parameter values (using the\n * provided `getKey` function) and returns a state source (via `getState`)\n * that components can subscribe to. When a new subscription is added, and if\n * enough time has passed since the last fetch (controlled by\n * `fetchThrottleInternal`), it invokes the observable factory (via\n * `getObservable`) to fetch fresh data. The data is stored in state and can be\n * accessed reactively.\n *\n * Additionally, the store provides a `resolveState` function that returns a\n * Promise resolving with the next non-undefined value from the state source.\n *\n * State expiration is implemented: after the last subscription for a key is\n * removed, its state is cleared after `stateExpirationDelay` ms, causing\n * components to suspend until fresh data is fetched.\n */\nexport function createFetcherStore<TParams extends unknown[], TData>({\n name,\n fetcher: getObservable,\n getKey,\n fetchThrottleInternal = 1000,\n stateExpirationDelay = 5000,\n}: CreateFetcherStoreOptions<TParams, TData>): FetcherStore<TParams, TData> {\n const store = defineStore<FetcherStoreState<TParams, TData>>({\n name,\n getInitialState: () => ({\n stateByParams: {},\n }),\n initialize: (context) => {\n const subscription = subscribeToSubscriptionsAndFetch(context)\n return () => subscription.unsubscribe()\n },\n })\n\n /**\n * For each key in state.stateByParams we set up a grouped stream.\n * When a subscription is added (i.e. the subscriptions array length increases)\n * and if enough time has elapsed since the last fetch, we update the timestamp\n * and call the factory function for that key.\n */\n const subscribeToSubscriptionsAndFetch = ({\n state,\n }: StoreContext<FetcherStoreState<TParams, TData>>) => {\n return state.observable\n .pipe(\n // Map the state to an array of [serialized, entry] pairs.\n switchMap((s: FetcherStoreState<TParams, TData>) => {\n const entries = Object.entries(s.stateByParams)\n return entries.length > 0 ? from(entries) : EMPTY\n }),\n // Group by the serialized key.\n groupBy(([key]) => key),\n mergeMap((group$) =>\n group$.pipe(\n // Emit an initial value for pairwise comparisons.\n startWith<[string, StoreEntry<TParams, TData> | undefined]>([group$.key, undefined]),\n pairwise(),\n // Trigger only when the subscriptions array grows.\n filter(([[, prevEntry], [, currEntry]]) => {\n const prevSubs = prevEntry?.subscriptions ?? []\n const currSubs = currEntry?.subscriptions ?? []\n return currSubs.length > prevSubs.length\n }),\n map(([, [, currEntry]]) => currEntry),\n\n // Only trigger if we haven't fetched recently.\n filter((entry) => {\n const lastFetch = entry?.lastFetchInitiatedAt\n if (!lastFetch) return true\n return Date.now() - new Date(lastFetch).getTime() >= fetchThrottleInternal\n }),\n switchMap((entry) => {\n // Retrieve params from the entry\n if (!entry) return EMPTY\n\n // Record that a fetch is being initiated.\n state.set('setLastFetchInitiatedAt', (prev: FetcherStoreState<TParams, TData>) => ({\n stateByParams: {\n ...prev.stateByParams,\n [entry.key]: {\n ...entry,\n ...prev.stateByParams[entry.key],\n lastFetchInitiatedAt: new Date().toISOString(),\n },\n },\n }))\n\n const factoryFn = getObservable(entry.instance)\n return factoryFn(...entry.params).pipe(\n // the `createStateSourceAction` util requires the update\n // to\n delay(0, asapScheduler),\n tap((data: TData) =>\n state.set('setData', (prev: FetcherStoreState<TParams, TData>) => ({\n stateByParams: {\n ...prev.stateByParams,\n [entry.key]: {\n ...omitProperty(entry, 'error'),\n ...(prev.stateByParams[entry.key]\n ? omitProperty(prev.stateByParams[entry.key], 'error')\n : {}),\n data,\n },\n },\n })),\n ),\n catchError((error) => {\n state.set('setError', (prev) => ({\n stateByParams: {\n ...prev.stateByParams,\n [entry.key]: {\n ...entry,\n ...prev.stateByParams[entry.key],\n error,\n },\n },\n }))\n\n return EMPTY\n }),\n )\n }),\n ),\n ),\n )\n .subscribe({\n error: (error) => state.set('setError', {error}),\n })\n }\n\n const getState = bindActionGlobally(\n store,\n createStateSourceAction({\n selector: (\n {\n instance,\n state: {stateByParams, error},\n }: SelectorContext<FetcherStoreState<TParams, TData>>,\n ...params: TParams\n ) => {\n if (error) throw error\n const key = getKey(instance, ...params)\n const entry = stateByParams[key]\n if (entry?.error) throw entry.error\n return entry?.data\n },\n onSubscribe: ({instance, state}, ...params: TParams) => {\n const subscriptionId = insecureRandomId()\n const key = getKey(instance, ...params)\n\n state.set('addSubscription', (prev: FetcherStoreState<TParams, TData>) => ({\n stateByParams: {\n ...prev.stateByParams,\n [key]: {\n ...prev.stateByParams[key],\n instance,\n key,\n params: prev.stateByParams[key]?.params || params,\n subscriptions: [...(prev.stateByParams[key]?.subscriptions || []), subscriptionId],\n },\n },\n }))\n\n return () => {\n setCleanupTimeout(() => {\n state.set('removeSubscription', (prev: FetcherStoreState<TParams, TData>) => {\n const entry = prev.stateByParams[key]\n if (!entry) return prev\n\n const newSubs = (entry.subscriptions || []).filter((id) => id !== subscriptionId)\n if (newSubs.length === 0) {\n return {stateByParams: omitProperty(prev.stateByParams, key)}\n }\n\n return {\n stateByParams: {\n ...prev.stateByParams,\n [key]: {\n ...entry,\n subscriptions: newSubs,\n },\n },\n }\n })\n }, stateExpirationDelay)\n }\n },\n }),\n )\n\n const resolveState = bindActionGlobally(store, ({instance}, ...params: TParams) =>\n firstValueFrom(getState(instance, ...params).observable.pipe(first((i) => i !== undefined))),\n )\n\n return {getState, resolveState}\n}\n","import {switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {type ProjectHandle} from '../config/sanityConfig'\nimport {createFetcherStore} from '../utils/createFetcherStore'\n\nconst API_VERSION = 'v2025-02-19'\n\n/** @public */\nexport const datasets = createFetcherStore({\n name: 'Datasets',\n getKey: (instance, options?: ProjectHandle) => {\n const projectId = options?.projectId ?? instance.config.projectId\n if (!projectId) {\n throw new Error('A projectId is required to use the project API.')\n }\n return projectId\n },\n fetcher: (instance) => (options?: ProjectHandle) => {\n return getClientState(instance, {\n apiVersion: API_VERSION,\n // non-null assertion is fine because we check above\n projectId: (options?.projectId ?? instance.config.projectId)!,\n useProjectHostname: true,\n }).observable.pipe(switchMap((client) => client.observable.datasets.list()))\n },\n})\n\n/** @public */\nexport const getDatasetsState = datasets.getState\n\n/** @public */\nexport const resolveDatasets = datasets.resolveState\n","import {DocumentId, getDraftId, getPublishedId, getVersionId} from '@sanity/id-utils'\n\nimport {type DocumentHandle} from '../config/sanityConfig'\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\n\n/**\n * The id of the specific document a user is editing under a given perspective:\n * the draft, the published document, or a release version.\n *\n * Distinct from {@link getEffectiveDocumentId}, which resolves the canonical key a\n * document's state is stored under and so collapses a draft onto its published id.\n * This one keeps them apart, because some things compare the exact id. Presence is\n * the motivating case: the Studio's field indicators match the id its form is on,\n * exactly, so an app reporting the published id shows up in the Studio at document\n * level while never lighting up a single field.\n *\n * @remarks\n * Resolved from the handle alone, which is right whenever a draft or version\n * exists, so for any document actually being edited. The Studio additionally falls\n * back to whichever document exists, so for a published document nobody has edited\n * yet its form sits on the published id where this returns the draft id. Matching\n * that would mean reading document state, which presence deliberately does not\n * depend on.\n *\n * @internal\n */\nexport function getEditingDocumentId(\n doc: Pick<DocumentHandle, 'documentId' | 'liveEdit' | 'perspective'>,\n): string {\n if (doc.liveEdit) {\n return getPublishedId(DocumentId(doc.documentId))\n }\n if (isReleasePerspective(doc.perspective)) {\n return getVersionId(DocumentId(doc.documentId), doc.perspective.releaseName)\n }\n if (doc.perspective === 'published') {\n return getPublishedId(DocumentId(doc.documentId))\n }\n return getDraftId(DocumentId(doc.documentId))\n}\n\nexport function getEffectiveDocumentId(doc: DocumentHandle): string {\n if (doc.liveEdit) {\n return doc.documentId\n } else if (isReleasePerspective(doc.perspective)) {\n return getVersionId(DocumentId(doc.documentId), doc.perspective.releaseName)\n } else {\n return getPublishedId(DocumentId(doc.documentId))\n }\n}\n","import {type ReleaseDocument} from '@sanity/client'\nimport {SanityEncoder} from '@sanity/mutate'\nimport {type PatchMutation as SanityMutatePatchMutation} from '@sanity/mutate/_unstable_store'\nimport {type PatchMutation, type PatchOperations} from '@sanity/types'\nimport {type SanityDocument} from 'groq'\n\nimport {\n type DocumentHandle,\n type DocumentTypeHandle,\n type ReleaseHandle,\n} from '../config/sanityConfig'\nimport {getEffectiveDocumentId} from './util'\n\nconst isSanityMutatePatch = (value: unknown): value is SanityMutatePatchMutation => {\n if (typeof value !== 'object' || !value) return false\n if (!('type' in value) || typeof value.type !== 'string' || value.type !== 'patch') return false\n if (!('id' in value) || typeof value.id !== 'string') return false\n if (!('patches' in value) || !Array.isArray(value.patches)) return false\n return true\n}\n\n/**\n * Represents an action to create a new document.\n * Specifies the document type and optionally a document ID (which will be treated as the published ID).\n * @beta\n */\nexport interface CreateDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentTypeHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.create'\n /**\n * Optional initial field values for the document.\n * These values will be set when the document is created.\n * System fields (_id, _type, _rev, _createdAt, _updatedAt) are omitted as they are set automatically.\n */\n initialValue?: Partial<\n Omit<\n SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>,\n '_id' | '_type' | '_rev' | '_createdAt' | '_updatedAt'\n >\n >\n}\n\n/**\n * Represents an action to delete an existing document.\n * Requires the full document handle including the document ID.\n * @beta\n */\nexport interface DeleteDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.delete'\n}\n\n/**\n * Represents an action to edit an existing document using patches.\n * Requires the full document handle and an array of patch operations.\n * @beta\n */\nexport interface EditDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.edit'\n patches?: PatchOperations[]\n /**\n * When `true`, the given `patches` are forwarded verbatim to the server and\n * applied as-is locally, instead of being re-derived by diffing document\n * snapshots. This preserves the operational intent of the patches (e.g.\n * keyed array inserts/unsets), which lets concurrent edits from other\n * clients interleave coherently instead of being overwritten by\n * position-based patches computed from a stale snapshot.\n *\n * Use this when the patches were produced by an editor that tracks its own\n * operations (e.g. a collaborative text editor). During a rebase onto a\n * changed remote document, preserved patches are re-applied operationally;\n * if a patch can no longer apply, the transaction is skipped and reported\n * as a `rebase-error` document event.\n */\n preserveOperations?: boolean\n}\n\n/**\n * Represents an action to publish the draft version of a document.\n * Requires the full document handle.\n * @beta\n */\nexport interface PublishDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.publish'\n}\n\n/**\n * Represents an action to unpublish a document, moving its published content to a draft.\n * Requires the full document handle.\n * @beta\n */\nexport interface UnpublishDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.unpublish'\n}\n\n/**\n * Represents an action to discard the draft changes of a document.\n * Requires the full document handle.\n * @beta\n */\nexport interface DiscardDocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n type: 'document.discard'\n}\n\n/**\n * Union type representing all possible document actions within the SDK.\n * @beta\n */\nexport type DocumentAction<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> =\n | CreateDocumentAction<TDocumentType, TDataset, TProjectId>\n | DeleteDocumentAction<TDocumentType, TDataset, TProjectId>\n | EditDocumentAction<TDocumentType, TDataset, TProjectId>\n | PublishDocumentAction<TDocumentType, TDataset, TProjectId>\n | UnpublishDocumentAction<TDocumentType, TDataset, TProjectId>\n | DiscardDocumentAction<TDocumentType, TDataset, TProjectId>\n\n/**\n * Union of every action accepted by `applyDocumentActions` — both document-\n * level actions and release-lifecycle actions.\n * @beta\n */\nexport type Action<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> = DocumentAction<TDocumentType, TDataset, TProjectId> | ReleaseAction\n\n/**\n * Creates a `CreateDocumentAction` object.\n * @param doc - A handle identifying the document type, dataset, and project. An optional `documentId` can be provided.\n * @param initialValue - Optional initial field values for the document. (System fields are omitted as they are set automatically.)\n * @returns A `CreateDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function createDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentTypeHandle<TDocumentType, TDataset, TProjectId>,\n initialValue?: Partial<\n Omit<\n SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>,\n '_id' | '_type' | '_rev' | '_createdAt' | '_updatedAt'\n >\n >,\n): CreateDocumentAction<TDocumentType, TDataset, TProjectId> {\n // users may pass in an explicit documentId -- make sure we format it correctly for the action\n let effectiveDocumentId\n if (typeof doc.documentId === 'string') {\n effectiveDocumentId = getEffectiveDocumentId({...doc, documentId: doc.documentId})\n }\n return {\n type: 'document.create',\n ...doc,\n ...(effectiveDocumentId && {documentId: effectiveDocumentId}),\n ...(initialValue && {initialValue}),\n }\n}\n\n/**\n * Creates a `DeleteDocumentAction` object.\n * @param doc - A handle uniquely identifying the document to be deleted.\n * @returns A `DeleteDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function deleteDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): DeleteDocumentAction<TDocumentType, TDataset, TProjectId> {\n const effectiveDocumentId = getEffectiveDocumentId(doc)\n return {\n type: 'document.delete',\n ...doc,\n documentId: effectiveDocumentId,\n }\n}\n\nfunction convertSanityMutatePatch(\n sanityPatchMutation: SanityMutatePatchMutation,\n): EditDocumentAction['patches'] {\n const encoded = SanityEncoder.encode(sanityPatchMutation) as PatchMutation[]\n return encoded.map((i) => {\n const copy: PatchOperations = {...i.patch}\n if ('id' in copy) delete copy.id\n return copy\n })\n}\n\n/**\n * Options for creating an `EditDocumentAction`.\n * @beta\n */\nexport interface EditDocumentOptions {\n /**\n * Forward the given patches verbatim instead of re-deriving them by\n * diffing document snapshots. See {@link EditDocumentAction.preserveOperations}.\n */\n preserveOperations?: boolean\n}\n\n/**\n * Creates an `EditDocumentAction` object with patches for modifying a document.\n * Accepts patches in either the standard `PatchOperations` format or as a `SanityMutatePatchMutation` from `@sanity/mutate`.\n *\n * @param doc - A handle uniquely identifying the document to be edited.\n * @param sanityMutatePatch - A patch mutation object from `@sanity/mutate`.\n * @param options - Options controlling how the patches are processed.\n * @returns An `EditDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function editDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n sanityMutatePatch: SanityMutatePatchMutation,\n options?: EditDocumentOptions,\n): EditDocumentAction<TDocumentType, TDataset, TProjectId>\n/**\n * Creates an `EditDocumentAction` object with patches for modifying a document.\n *\n * @param doc - A handle uniquely identifying the document to be edited.\n * @param patches - A single patch operation or an array of patch operations.\n * @param options - Options controlling how the patches are processed.\n * @returns An `EditDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function editDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n patches?: PatchOperations | PatchOperations[],\n options?: EditDocumentOptions,\n): EditDocumentAction<TDocumentType, TDataset, TProjectId>\n/**\n * Creates an `EditDocumentAction` object with patches for modifying a document.\n * This is the implementation signature and handles the different patch input types.\n *\n * @param doc - A handle uniquely identifying the document to be edited.\n * @param patches - Patches in various formats (`PatchOperations`, `PatchOperations[]`, or `SanityMutatePatchMutation`).\n * @param options - Options controlling how the patches are processed.\n * @returns An `EditDocumentAction` object ready for dispatch.\n */\nexport function editDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n patches?: PatchOperations | PatchOperations[] | SanityMutatePatchMutation,\n options?: EditDocumentOptions,\n): EditDocumentAction<TDocumentType, TDataset, TProjectId> {\n const effectiveDocumentId = getEffectiveDocumentId(doc)\n const preserveOperations = options?.preserveOperations && {preserveOperations: true as const}\n\n if (isSanityMutatePatch(patches)) {\n const converted = convertSanityMutatePatch(patches) ?? []\n return {\n ...doc,\n type: 'document.edit',\n documentId: effectiveDocumentId,\n patches: converted,\n ...preserveOperations,\n }\n }\n\n return {\n ...doc,\n type: 'document.edit',\n documentId: effectiveDocumentId,\n ...(patches && {patches: Array.isArray(patches) ? patches : [patches]}),\n ...preserveOperations,\n }\n}\n\n/**\n * Creates a `PublishDocumentAction` object.\n * @param doc - A handle uniquely identifying the document to be published.\n * @returns A `PublishDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function publishDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): PublishDocumentAction<TDocumentType, TDataset, TProjectId> {\n const effectiveDocumentId = getEffectiveDocumentId(doc)\n return {\n type: 'document.publish',\n ...doc,\n documentId: effectiveDocumentId,\n }\n}\n\n/**\n * Creates an `UnpublishDocumentAction` object.\n * @param doc - A handle uniquely identifying the document to be unpublished.\n * @returns An `UnpublishDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function unpublishDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): UnpublishDocumentAction<TDocumentType, TDataset, TProjectId> {\n const effectiveDocumentId = getEffectiveDocumentId(doc)\n return {\n type: 'document.unpublish',\n ...doc,\n documentId: effectiveDocumentId,\n }\n}\n\n/**\n * Creates a `DiscardDocumentAction` object.\n * @param doc - A handle uniquely identifying the document whose draft changes are to be discarded.\n * @returns A `DiscardDocumentAction` object ready for dispatch.\n * @beta\n */\nexport function discardDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n doc: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): DiscardDocumentAction<TDocumentType, TDataset, TProjectId> {\n const effectiveDocumentId = getEffectiveDocumentId(doc)\n return {\n type: 'document.discard',\n ...doc,\n documentId: effectiveDocumentId,\n }\n}\n\n/**\n * Creates a new release. The `releaseId` must be unique within the current\n * retention period.\n * @beta\n */\nexport interface CreateReleaseAction extends ReleaseHandle {\n type: 'release.create'\n metadata: ReleaseDocument['metadata']\n}\n\n/**\n * Patches the metadata of an existing release.\n * @beta\n */\nexport interface EditReleaseAction extends ReleaseHandle {\n type: 'release.edit'\n patch: PatchOperations\n}\n\n/**\n * Publishes all version documents in a release.\n * @beta\n */\nexport interface PublishReleaseAction extends ReleaseHandle {\n type: 'release.publish'\n}\n\n/**\n * Schedules a release to be published at the given UTC time. Locks the\n * version documents server-side until the release is unscheduled or published.\n * @beta\n */\nexport interface ScheduleReleaseAction extends ReleaseHandle {\n type: 'release.schedule'\n publishAt: string\n}\n\n/**\n * Unschedules a release that was previously scheduled, returning it to the\n * active editable state.\n * @beta\n */\nexport interface UnscheduleReleaseAction extends ReleaseHandle {\n type: 'release.unschedule'\n}\n\n/**\n * Archives an active release. Version documents within the release are\n * removed and no longer queryable, though still recoverable through history\n * during the retention period.\n * @beta\n */\nexport interface ArchiveReleaseAction extends ReleaseHandle {\n type: 'release.archive'\n}\n\n/**\n * Restores an archived release. Only possible during the retention period.\n * @beta\n */\nexport interface UnarchiveReleaseAction extends ReleaseHandle {\n type: 'release.unarchive'\n}\n\n/**\n * Permanently deletes an archived or published release. To remove an active\n * release, use the archive action first.\n * @beta\n */\nexport interface DeleteReleaseAction extends ReleaseHandle {\n type: 'release.delete'\n}\n\n/**\n * Union of all release actions that can be dispatched alongside document\n * actions through `applyDocumentActions`.\n * @beta\n */\nexport type ReleaseAction =\n | CreateReleaseAction\n | EditReleaseAction\n | PublishReleaseAction\n | ScheduleReleaseAction\n | UnscheduleReleaseAction\n | ArchiveReleaseAction\n | UnarchiveReleaseAction\n | DeleteReleaseAction\n\n/** @beta */\nexport function createRelease(\n handle: ReleaseHandle,\n metadata: ReleaseDocument['metadata'] = {releaseType: 'undecided'},\n): CreateReleaseAction {\n return {type: 'release.create', ...handle, metadata}\n}\n\n/** @beta */\nexport function editRelease(handle: ReleaseHandle, patch: PatchOperations): EditReleaseAction {\n return {type: 'release.edit', ...handle, patch}\n}\n\n/** @beta */\nexport function publishRelease(handle: ReleaseHandle): PublishReleaseAction {\n return {type: 'release.publish', ...handle}\n}\n\n/** @beta */\nexport function scheduleRelease(handle: ReleaseHandle, publishAt: string): ScheduleReleaseAction {\n return {type: 'release.schedule', ...handle, publishAt}\n}\n\n/** @beta */\nexport function unscheduleRelease(handle: ReleaseHandle): UnscheduleReleaseAction {\n return {type: 'release.unschedule', ...handle}\n}\n\n/** @beta */\nexport function archiveRelease(handle: ReleaseHandle): ArchiveReleaseAction {\n return {type: 'release.archive', ...handle}\n}\n\n/** @beta */\nexport function unarchiveRelease(handle: ReleaseHandle): UnarchiveReleaseAction {\n return {type: 'release.unarchive', ...handle}\n}\n\n/** @beta */\nexport function deleteRelease(handle: ReleaseHandle): DeleteReleaseAction {\n return {type: 'release.delete', ...handle}\n}\n","/**\n * When a document has no more subscribers, its state is cleaned up and removed\n * from the store. A delay used to prevent re-creating resources when the last\n * subscriber is removed quickly before another one is added. This is helpful\n * when used in a frontend where components may suspend or transition to\n * different views quickly.\n */\nexport const DOCUMENT_STATE_CLEAR_DELAY = 1000\nexport const INITIAL_OUTGOING_THROTTLE_TIME = 1000\nexport const API_VERSION = 'v2025-05-06'\n\n/**\n * Base delay (ms) before retrying a document listener after an `OutOfSyncError`.\n * Backoff doubles on each successive retry, capped at {@link OUT_OF_SYNC_RETRY_MAX_DELAY}.\n */\nexport const OUT_OF_SYNC_RETRY_BASE_DELAY = 500\nexport const OUT_OF_SYNC_RETRY_MAX_DELAY = 10_000\n\n/**\n * Base delay (ms) before retrying the dataset ACL fetch after a transient\n * failure (a network error or 5xx response). Backoff doubles on each\n * successive retry, capped at {@link ACL_RETRY_MAX_DELAY}.\n */\nexport const ACL_RETRY_BASE_DELAY = 500\nexport const ACL_RETRY_MAX_DELAY = 10_000\n","import {type Action, type ReleaseAction} from '../actions'\n\n/**\n * Path prefix shared by every release document. Matches studio's\n * `RELEASE_DOCUMENTS_PATH` constant.\n */\nconst RELEASE_DOCUMENTS_PATH = '_.releases'\n\n/**\n * Returns the full release document ID for the given release name.\n * e.g. `getReleaseDocumentId('my-release') === '_.releases.my-release'`\n * @beta\n */\nexport function getReleaseDocumentId(releaseId: string): string {\n return `${RELEASE_DOCUMENTS_PATH}.${releaseId}`\n}\n\nconst RELEASE_ACTION_TYPES = new Set([\n 'release.create',\n 'release.edit',\n 'release.publish',\n 'release.schedule',\n 'release.unschedule',\n 'release.archive',\n 'release.unarchive',\n 'release.delete',\n])\n\nexport function isReleaseAction(action: Action): action is ReleaseAction {\n return RELEASE_ACTION_TYPES.has(action.type)\n}\n","import {applyPatches, parsePatch} from '@sanity/diff-match-patch'\nimport {getIndexForKey, jsonMatch, slicePath, stringifyPath} from '@sanity/json-match'\nimport {\n type IndexTuple,\n type InsertPatch,\n isKeyedObject,\n isKeySegment,\n type PathSegment,\n} from '@sanity/types'\n\ntype SingleValuePath = Exclude<PathSegment, IndexTuple>[]\n\ntype ToNumber<TInput extends string> = TInput extends `${infer TNumber extends number}`\n ? TNumber\n : TInput\n\n/**\n * Parse a single \"segment\" that may include bracket parts.\n *\n * For example, the literal\n *\n * ```\n * \"friends[0][1]\"\n * ```\n *\n * is parsed as:\n *\n * ```\n * [\"friends\", 0, 1]\n * ```\n */\ntype ParseSegment<TInput extends string> = TInput extends `${infer TProp}[${infer TRest}`\n ? TProp extends ''\n ? [...ParseBracket<`[${TRest}`>] // no property name before '['\n : [TProp, ...ParseBracket<`[${TRest}`>]\n : TInput extends ''\n ? []\n : [TInput]\n\n/**\n * Parse one or more bracketed parts from a segment.\n *\n * It recursively \"peels off\" a bracketed part and then continues.\n *\n * For example, given the string:\n *\n * ```\n * \"[0][foo]\"\n * ```\n *\n * it produces:\n *\n * ```\n * [ToNumber<\"0\">, \"foo\"]\n * ```\n */\ntype ParseBracket<TInput extends string> = TInput extends `[${infer TPart}]${infer TRest}`\n ? [ToNumber<TPart>, ...ParseSegment<TRest>]\n : [] // no leading bracket → end of this segment\n\n/**\n * Split the entire path string on dots \"outside\" of any brackets.\n *\n * For example:\n * ```\n * \"friends[0].name\"\n * ```\n *\n * becomes:\n *\n * ```\n * [...ParseSegment<\"friends[0]\">, ...ParseSegment<\"name\">]\n * ```\n *\n * (We use a simple recursion that splits on the first dot.)\n */\ntype PathParts<TPath extends string> = TPath extends `${infer Head}.${infer Tail}`\n ? [Head, ...PathParts<Tail>]\n : TPath extends ''\n ? []\n : [TPath]\n\n/**\n * Given a type T and an array of \"access keys\" Parts, recursively index into T.\n *\n * If a part is a key, it looks up that property.\n * If T is an array and the part is a number, it \"indexes\" into the element type.\n */\ntype DeepGet<TValue, TPath extends readonly (string | number)[]> = TPath extends []\n ? TValue\n : TPath extends readonly [infer THead, ...infer TTail]\n ? // Handle traversing into optional properties\n DeepGet<\n TValue extends undefined | null\n ? undefined // Stop traversal if current value is null/undefined\n : THead extends keyof TValue // Access property if key exists\n ? TValue[THead]\n : // Handle array indexing\n THead extends number\n ? TValue extends readonly (infer TElement)[]\n ? TElement | undefined // Array element or undefined if out of bounds\n : undefined // Cannot index non-array with number\n : undefined, // Key/index doesn't exist\n TTail extends readonly (string | number)[] ? TTail : [] // Continue with the rest of the path\n >\n : never // Should be unreachable\n\n/**\n * Given a document type TDocument and a JSON Match path string TPath,\n * compute the type found at that path.\n * @beta\n */\nexport type JsonMatch<TDocument, TPath extends string> = DeepGet<TDocument, PathParts<TPath>>\n\n// this is a similar array key to the studio:\n// https://github.com/sanity-io/sanity/blob/v3.74.1/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/createProtoArrayValue.ts\nfunction generateArrayKey(length: number = 12): string {\n // Each byte gives two hex characters, so generate enough bytes.\n const numBytes = Math.ceil(length / 2)\n const bytes = crypto.getRandomValues(new Uint8Array(numBytes))\n // Convert each byte to a 2-digit hex string and join them.\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0'))\n .join('')\n .slice(0, length)\n}\n\nfunction memoize<TFunction extends (input: unknown) => unknown>(fn: TFunction): TFunction {\n const cache = new WeakMap<object, unknown>()\n return ((input) => {\n if (!input || typeof input !== 'object') return fn(input)\n\n const cached = cache.get(input)\n if (cached) return cached\n\n const result = fn(input)\n cache.set(input, result)\n return result\n }) as TFunction\n}\n\n/**\n * Recursively traverse a value. When an array is encountered, ensure that\n * each object item has a _key property. Memoized such that sub-objects that\n * have not changed aren't re-computed.\n */\nexport const ensureArrayKeysDeep = memoize(<R>(input: R): R => {\n if (!input || typeof input !== 'object') return input\n\n if (Array.isArray(input)) {\n // if the array is empty then just return the input\n if (!input.length) return input\n const first = input[0]\n // if the first input in the array isn't an object (null is allowed) then\n // assume that this is an array of primitives, just return the input\n if (typeof first !== 'object') return input\n\n // if all the items already have a key, then return the input\n if (input.every(isKeyedObject)) return input\n\n // otherwise return a new object item with a new key\n return input.map((item: unknown) => {\n if (!item || typeof item !== 'object') return item\n if (isKeyedObject(item)) return ensureArrayKeysDeep(item)\n const next = ensureArrayKeysDeep(item)\n return {...next, _key: generateArrayKey()}\n }) as R\n }\n\n const entries = Object.entries(input).map(([key, value]) => [key, ensureArrayKeysDeep(value)])\n\n if (entries.every(([key, value]) => input[key as keyof typeof input] === value)) {\n return input\n }\n\n return Object.fromEntries(entries) as R\n})\n\n/**\n * Whether every array-addressing segment (keyed `[_key==\"…\"]` or numeric\n * index) in the given match path resolves to an existing array item.\n *\n * This mirrors Content Lake, which auto-creates missing *object* properties\n * when setting but never creates *array items*:\n *\n * ```js\n * // object properties are created, even nested ones:\n * set({}, {'meta.author.name': 'Ada'})\n * // -> {meta: {author: {name: 'Ada'}}} (applies)\n *\n * // array items are not:\n * set({items: [{_key: 'a'}]}, {'items[_key==\"b\"].title': 'x'})\n * // -> {items: [{_key: 'a'}]} (no-op)\n * ```\n *\n * Without this filter, the second example fabricated a degenerate item\n * (`{title: 'x'}`, no `_key`) that would never exist on the server, which\n * is how concurrent Portable Text edits grew phantom span-less children.\n */\nfunction resolvesArraySegments(input: unknown, path: SingleValuePath): boolean {\n let current: unknown = input\n for (const segment of path) {\n if (typeof segment === 'string') {\n // missing object properties (nested ones included) are created\n // server-side, so a string segment may descend into undefined\n current =\n typeof current === 'object' && current !== null && !Array.isArray(current)\n ? (current as Record<string, unknown>)[segment]\n : undefined\n continue\n }\n // keyed and numeric segments address array items, which are never created\n if (!Array.isArray(current)) return false\n if (isKeySegment(segment)) {\n const index = getIndexForKey(current, segment._key)\n if (index === undefined) return false\n current = current[index]\n } else {\n const index = segment < 0 ? current.length + segment : segment\n if (!(index in current)) return false\n current = current[index]\n }\n }\n return true\n}\n\n/**\n * Given an input object and a record of path expressions to values, this\n * function will set each match with the given value.\n *\n * ```js\n * const output = set(\n * {name: {first: 'initial', last: 'initial'}},\n * {'name.first': 'changed'}\n * );\n *\n * // { name: { first: 'changed', last: 'initial' } }\n * console.log(output);\n * ```\n */\nexport function set<R>(input: unknown, pathExpressionValues: Record<string, unknown>): R\nexport function set(input: unknown, pathExpressionValues: Record<string, unknown>): unknown {\n const result = Object.entries(pathExpressionValues)\n .flatMap(([pathExpression, replacementValue]) =>\n Array.from(jsonMatch(input, pathExpression)).map((matchEntry) => ({\n ...matchEntry,\n replacementValue,\n })),\n )\n .filter(({path}) => resolvesArraySegments(input, path))\n .reduce((acc, {path, replacementValue}) => setDeep(acc, path, replacementValue), input)\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object and a record of path expressions to values, this\n * function will set each match with the given value **if the value at the current\n * path is missing** (i.e. `null` or `undefined`).\n *\n * ```js\n * const output = setIfMissing(\n * {items: [null, 'initial']},\n * {'items[:]': 'changed'}\n * );\n *\n * // { items: ['changed', 'initial'] }\n * console.log(output);\n * ```\n */\nexport function setIfMissing<R>(input: unknown, pathExpressionValues: Record<string, unknown>): R\nexport function setIfMissing(\n input: unknown,\n pathExpressionValues: Record<string, unknown>,\n): unknown {\n const result = Object.entries(pathExpressionValues)\n .flatMap(([pathExpression, replacementValue]) => {\n return Array.from(jsonMatch(input, pathExpression)).map((matchEntry) => ({\n ...matchEntry,\n replacementValue,\n }))\n })\n .filter((matchEntry) => matchEntry.value === null || matchEntry.value === undefined)\n .filter(({path}) => resolvesArraySegments(input, path))\n .reduce((acc, {path, replacementValue}) => setDeep(acc, path, replacementValue), input)\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object and an array of path expressions, this function will\n * remove each match from the input object.\n *\n * ```js\n * const output = unset(\n * {name: {first: 'one', last: 'two'}},\n * ['name.last']\n * );\n *\n * // { name: { first: 'one' } }\n * console.log(output);\n * ```\n */\nexport function unset<R>(input: unknown, pathExpressions: string[]): R\nexport function unset(input: unknown, pathExpressions: string[]): unknown {\n const result = pathExpressions\n .flatMap((pathExpression) => Array.from(jsonMatch(input, pathExpression)))\n // ensure that we remove in the reverse order the paths were found in\n // this is necessary for array unsets so the indexes don't change as we unset\n .reverse()\n .reduce((acc, {path}) => unsetDeep(acc, path), input)\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object, a path expression (inside the insert patch object), and an array of items,\n * this function will insert or replace the matched items.\n *\n * **Insert before:**\n *\n * ```js\n * const input = {some: {array: ['a', 'b', 'c']}}\n * const output = insert(\n * input,\n * {\n * before: 'some.array[1]',\n * items: ['!']\n * }\n * );\n * // { some: { array: ['a', '!', 'b', 'c'] } }\n * console.log(output);\n * ```\n *\n * **Insert before with negative index (append):**\n *\n * ```js\n * const input = {some: {array: ['a', 'b', 'c']}}\n * const output = insert(\n * input,\n * {\n * before: 'some.array[-1]',\n * items: ['!']\n * }\n * );\n * // { some: { array: ['a', 'b', 'c', '!'] } }\n * console.log(output);\n * ```\n *\n * **Insert after:**\n *\n * ```js\n * const input = {some: {array: ['a', 'b', 'c']}}\n * const output = insert(\n * input,\n * {\n * after: 'some.array[1]',\n * items: ['!']\n * }\n * );\n * // { some: { array: ['a', 'b', '!', 'c'] } }\n * console.log(output);\n * ```\n *\n * **Replace:**\n *\n * ```js\n * const output = insert(\n * { some: { array: ['a', 'b', 'c'] } },\n * {\n * replace: 'some.array[1]',\n * items: ['!']\n * }\n * );\n * // { some: { array: ['a', '!', 'c'] } }\n * console.log(output);\n * ```\n *\n * **Replace many:**\n *\n * ```js\n * const input = {some: {array: ['a', 'b', 'c', 'd']}}\n * const output = insert(\n * input,\n * {\n * replace: 'some.array[1:3]',\n * items: ['!', '?']\n * }\n * );\n * // { some: { array: ['a', '!', '?', 'd'] } }\n * console.log(output);\n * ```\n */\nexport function insert<R>(input: unknown, insertPatch: InsertPatch): R\nexport function insert(input: unknown, {items, ...insertPatch}: InsertPatch): unknown {\n let operation\n let pathExpression\n\n // behavior observed from content-lake when inserting:\n // 1. if the operation is before, out of all the matches, it will use the\n // insert the items before the first match that appears in the array\n // 2. if the operation is after, it will insert the items after the first\n // match that appears in the array\n // 3. if the operation is replace, then insert the items before the first\n // match and then delete the rest\n if ('before' in insertPatch) {\n operation = 'before' as const\n pathExpression = insertPatch.before\n } else if ('after' in insertPatch) {\n operation = 'after' as const\n pathExpression = insertPatch.after\n } else if ('replace' in insertPatch) {\n operation = 'replace' as const\n pathExpression = insertPatch.replace\n }\n if (!operation) return input\n if (typeof pathExpression !== 'string') return input\n\n // in order to do an insert patch, you need to provide at least one path segment\n if (!pathExpression.length) return input\n\n const arrayPath = slicePath(pathExpression, 0, -1)\n const positionPath = slicePath(pathExpression, -1)\n\n let result = input\n\n for (const {path, value} of jsonMatch(input, arrayPath)) {\n if (!Array.isArray(value)) continue\n let arr = value\n\n switch (operation) {\n case 'replace': {\n const indexesToRemove = new Set<number>()\n let position = Infinity\n\n for (const itemMatch of jsonMatch(arr, positionPath)) {\n // there should only be one path segment for an insert patch, invalid otherwise\n if (itemMatch.path.length !== 1) continue\n const [segment] = itemMatch.path\n if (typeof segment === 'string') continue\n\n let index\n\n if (typeof segment === 'number') index = segment\n if (typeof index === 'number' && index < 0) index = arr.length + index\n if (isKeySegment(segment)) index = getIndexForKey(arr, segment._key)\n if (typeof index !== 'number') continue\n if (index < 0) index = arr.length + index\n\n indexesToRemove.add(index)\n if (index < position) position = index\n }\n\n if (position === Infinity) continue\n\n // remove all other indexes\n arr = arr\n .map((item, index) => ({item, index}))\n .filter(({index}) => !indexesToRemove.has(index))\n .map(({item}) => item)\n\n // insert at the min index\n arr = [...arr.slice(0, position), ...items, ...arr.slice(position, arr.length)]\n\n break\n }\n case 'before': {\n let position = Infinity\n\n for (const itemMatch of jsonMatch(arr, positionPath)) {\n if (itemMatch.path.length !== 1) continue\n const [segment] = itemMatch.path\n\n if (typeof segment === 'string') continue\n\n let index\n\n if (typeof segment === 'number') index = segment\n if (typeof index === 'number' && index < 0) index = arr.length + index\n if (isKeySegment(segment)) index = getIndexForKey(arr, segment._key)\n if (typeof index !== 'number') continue\n if (index < 0) index = arr.length - index\n if (index < position) position = index\n }\n\n if (position === Infinity) continue\n\n arr = [...arr.slice(0, position), ...items, ...arr.slice(position, arr.length)]\n\n break\n }\n case 'after': {\n let position = -Infinity\n\n for (const itemMatch of jsonMatch(arr, positionPath)) {\n if (itemMatch.path.length !== 1) continue\n const [segment] = itemMatch.path\n\n if (typeof segment === 'string') continue\n\n let index\n\n if (typeof segment === 'number') index = segment\n if (typeof index === 'number' && index < 0) index = arr.length + index\n if (isKeySegment(segment)) index = getIndexForKey(arr, segment._key)\n if (typeof index !== 'number') continue\n if (index > position) position = index\n }\n\n if (position === -Infinity) continue\n\n arr = [...arr.slice(0, position + 1), ...items, ...arr.slice(position + 1, arr.length)]\n\n break\n }\n\n default: {\n continue\n }\n }\n\n result = setDeep(result, path, arr)\n }\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object and a record of path expressions to numeric values,\n * this function will increment each match with the given value.\n *\n * ```js\n * const output = inc(\n * {foo: {first: 3, second: 4.5}},\n * {'foo.first': 3, 'foo.second': 4}\n * );\n *\n * // { foo: { first: 6, second: 8.5 } }\n * console.log(output);\n * ```\n */\nexport function inc<R>(input: unknown, pathExpressionValues: Record<string, number>): R\nexport function inc(input: unknown, pathExpressionValues: Record<string, number>): unknown {\n const result = Object.entries(pathExpressionValues)\n .flatMap(([pathExpression, valueToAdd]) =>\n Array.from(jsonMatch(input, pathExpression)).map((matchEntry) => ({\n ...matchEntry,\n valueToAdd,\n })),\n )\n .filter(\n <T extends {value: unknown}>(matchEntry: T): matchEntry is T & {value: number} =>\n typeof matchEntry.value === 'number',\n )\n .reduce((acc, {path, value, valueToAdd}) => setDeep(acc, path, value + valueToAdd), input)\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object and a record of path expressions to numeric values,\n * this function will decrement each match with the given value.\n *\n * ```js\n * const output = dec(\n * {foo: {first: 3, second: 4.5}},\n * {'foo.first': 3, 'foo.second': 4}\n * );\n *\n * // { foo: { first: 0, second: 0.5 } }\n * console.log(output);\n * ```\n */\nexport function dec<R>(input: unknown, pathExpressionValues: Record<string, number>): R\nexport function dec(input: unknown, pathExpressionValues: Record<string, number>): unknown {\n const result = inc(\n input,\n Object.fromEntries(\n Object.entries(pathExpressionValues)\n .filter(([, value]) => typeof value === 'number')\n .map(([key, value]) => [key, -value]),\n ),\n )\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Given an input object and a record of paths to [diff match patches][0], this\n * function will apply the diff match patch for the string at each match.\n *\n * [0]: https://www.sanity.io/docs/http-patches#aTbJhlAJ\n *\n * ```js\n * const output = diffMatchPatch(\n * {foo: 'the quick brown fox'},\n * {'foo': '@@ -13,7 +13,7 @@\\n own \\n-fox\\n+cat\\n'}\n * );\n *\n * // { foo: 'the quick brown cat' }\n * console.log(output);\n * ```\n */\nexport function diffMatchPatch<R>(input: unknown, pathExpressionValues: Record<string, string>): R\nexport function diffMatchPatch(\n input: unknown,\n pathExpressionValues: Record<string, string>,\n): unknown {\n const result = Object.entries(pathExpressionValues)\n .flatMap(([pathExpression, dmp]) =>\n Array.from(jsonMatch(input, pathExpression)).map((m) => ({...m, dmp})),\n )\n .filter((i) => i.value !== undefined)\n .map(({path, value, dmp}) => {\n if (typeof value !== 'string') {\n throw new Error(\n `Can't diff-match-patch \\`${JSON.stringify(value)}\\` at path \\`${stringifyPath(path)}\\`, because it is not a string`,\n )\n }\n\n // Offsets arrive as UTF-8 byte positions and can overshoot when they\n // land inside a multi-byte character, which happens once the string a\n // patch was computed against has diverged. The default is to throw, and\n // that throw escapes the rebase loop in `reducers.ts`, kills the\n // outgoing-actions pipeline, and leaves the instance silently dropping\n // every write. Clamping to the nearest index applies the patch instead,\n // which is what the Studio and the Portable Text editor already do.\n const [nextValue] = applyPatches(parsePatch(dmp), value, {\n allowExceedingIndices: true,\n })\n return {path, value: nextValue}\n })\n .reduce((acc, {path, value}) => setDeep(acc, path, value), input)\n\n return ensureArrayKeysDeep(result)\n}\n\n/**\n * Simply checks if the given document input has a `_rev` that matches the given\n * `revisionId` and throws otherwise.\n *\n * (No code example provided.)\n */\nexport function ifRevisionID<R>(input: unknown, revisionId: string): R\nexport function ifRevisionID(input: unknown, revisionId: string): unknown {\n const inputRev =\n typeof input === 'object' && !!input && '_rev' in input && typeof input._rev === 'string'\n ? input._rev\n : undefined\n\n if (typeof inputRev !== 'string') {\n throw new Error(`Patch specified \\`ifRevisionID\\` but could not find document's revision ID.`)\n }\n\n if (revisionId !== inputRev) {\n throw new Error(\n `Patch's \\`ifRevisionID\\` \\`${revisionId}\\` does not match document's revision ID \\`${inputRev}\\``,\n )\n }\n\n return input\n}\n\n/**\n * Gets a value deep inside of an object given a path. If the path does not\n * exist in the object, `undefined` will be returned.\n */\nexport function getDeep<R>(input: unknown, path: SingleValuePath): R\nexport function getDeep(input: unknown, path: SingleValuePath): unknown {\n const [currentSegment, ...restOfPath] = path\n if (currentSegment === undefined) return input\n if (typeof input !== 'object' || input === null) return undefined\n\n let key\n if (isKeySegment(currentSegment)) {\n key = getIndexForKey(input, currentSegment._key)\n } else if (typeof currentSegment === 'string') {\n key = currentSegment\n } else if (typeof currentSegment === 'number') {\n key = currentSegment\n }\n\n if (key === undefined) return undefined\n\n // Use .at() to support negative indexes on arrays.\n const nestedInput =\n typeof key === 'number' && Array.isArray(input)\n ? input.at(key)\n : (input as Record<string, unknown>)[key]\n\n return getDeep(nestedInput, restOfPath)\n}\n\n/**\n * Sets a value deep inside of an object given a path. If the path does not\n * exist in the object, it will be created.\n */\nexport function setDeep<R>(input: unknown, path: SingleValuePath, value: unknown): R\nexport function setDeep(input: unknown, path: SingleValuePath, value: unknown): unknown {\n const [currentSegment, ...restOfPath] = path\n if (currentSegment === undefined) return value\n\n // If the current input is not an object, create a new container.\n if (typeof input !== 'object' || input === null) {\n if (typeof currentSegment === 'string') {\n return {[currentSegment]: setDeep(null, restOfPath, value)}\n }\n\n let index: number | undefined\n if (isKeySegment(currentSegment)) {\n // When creating a new array via a keyed segment, use index 0.\n index = 0\n } else if (typeof currentSegment === 'number' && currentSegment >= 0) {\n index = currentSegment\n } else {\n // For negative numbers in a non‐object we simply return input.\n return input\n }\n\n return [\n // fill until index\n ...Array.from({length: index}).fill(null),\n // then set deep here\n setDeep(null, restOfPath, value),\n ]\n }\n\n // When input is an array…\n if (Array.isArray(input)) {\n let index: number | undefined\n if (isKeySegment(currentSegment)) {\n index = getIndexForKey(input, currentSegment._key) ?? input.length\n } else if (typeof currentSegment === 'number') {\n // Support negative indexes by computing the proper positive index.\n index = currentSegment < 0 ? input.length + currentSegment : currentSegment\n }\n if (index === undefined) return input\n\n if (index in input) {\n // Update the element at the resolved index.\n return input.map((nestedInput, i) =>\n i === index ? setDeep(nestedInput, restOfPath, value) : nestedInput,\n )\n }\n\n // Expand the array if needed.\n return [\n ...input,\n ...Array.from({length: index - input.length}).fill(null),\n setDeep(null, restOfPath, value),\n ]\n }\n\n // For keyed segments that aren't arrays, do nothing.\n if (typeof currentSegment === 'object') return input\n\n // For plain objects, update an existing property if it exists…\n if (currentSegment in input) {\n return Object.fromEntries(\n Object.entries(input).map(([key, nestedInput]) =>\n key === currentSegment\n ? [key, setDeep(nestedInput, restOfPath, value)]\n : [key, nestedInput],\n ),\n )\n }\n\n // ...otherwise create the new nested path.\n return {...input, [currentSegment]: setDeep(null, restOfPath, value)}\n}\n\n/**\n * Given an object and an exact path as an array, this unsets the value at the\n * given path.\n */\nexport function unsetDeep<R>(input: unknown, path: SingleValuePath): R\nexport function unsetDeep(input: unknown, path: SingleValuePath): unknown {\n const [currentSegment, ...restOfPath] = path\n if (currentSegment === undefined) return input\n if (typeof input !== 'object' || input === null) return input\n\n let _segment: string | number | undefined\n if (isKeySegment(currentSegment)) {\n _segment = getIndexForKey(input, currentSegment._key)\n } else if (typeof currentSegment === 'string' || typeof currentSegment === 'number') {\n _segment = currentSegment\n }\n if (_segment === undefined) return input\n\n // For numeric segments in arrays, compute the positive index.\n let segment: string | number = _segment\n if (typeof segment === 'number' && Array.isArray(input)) {\n segment = segment < 0 ? input.length + segment : segment\n }\n if (!(segment in input)) return input\n\n // If we're at the final segment, remove the property/element.\n if (!restOfPath.length) {\n if (Array.isArray(input)) {\n return input.filter((_nestedInput, index) => index !== segment)\n }\n return Object.fromEntries(Object.entries(input).filter(([key]) => key !== segment.toString()))\n }\n\n // Otherwise, recurse into the nested value.\n if (Array.isArray(input)) {\n return input.map((nestedInput, index) =>\n index === segment ? unsetDeep(nestedInput, restOfPath) : nestedInput,\n )\n }\n\n return Object.fromEntries(\n Object.entries(input).map(([key, value]) =>\n key === segment ? [key, unsetDeep(value, restOfPath)] : [key, value],\n ),\n )\n}\n","import {\n type Mutation,\n type MutationSelection,\n type PatchOperations,\n type SanityDocument,\n} from '@sanity/types'\n\nimport {\n dec,\n diffMatchPatch,\n ifRevisionID,\n inc,\n insert,\n set,\n setIfMissing,\n unset,\n} from './patchOperations'\n\n/**\n * Represents a set of document that will go into `applyMutations`. Before\n * applying a mutation, it's expected that all relevant documents that the\n * mutations affect are included, including those that do not exist yet.\n * Documents that don't exist have a `null` value.\n */\nexport type DocumentSet<TDocument extends SanityDocument = SanityDocument> = {\n [TDocumentId in string]?: TDocument | null\n}\n\ntype SupportedPatchOperation = Exclude<keyof PatchOperations, 'merge'>\n\n// > If multiple patches are included, then the order of execution is as follows:\n// > - set, setIfMissing, unset, inc, dec, insert.\n// > https://www.sanity.io/docs/http-mutations#5b4db1396e56\nconst patchOperations = {\n ifRevisionID,\n set,\n setIfMissing,\n unset,\n inc,\n dec,\n insert,\n diffMatchPatch,\n} satisfies {\n [K in SupportedPatchOperation]: (\n input: unknown,\n pathExpressions: NonNullable<PatchOperations[K]>,\n ) => unknown\n}\n\n/**\n * Implements ID generation:\n *\n * A create mutation creates a new document. It takes the literal document\n * content as its argument. The rules for the new document's identifier are as\n * follows:\n *\n * - If the `_id` attribute is missing, then a new, random, unique ID is\n * generated.\n * - If the `_id` attribute is present but ends with `.`, then it is used as a\n * prefix for a new, random, unique ID.\n * - If the _id attribute is present, it is used as-is.\n *\n * [- source](https://www.sanity.io/docs/http-mutations#c732f27330a4)\n */\nexport function getId(id?: string): string {\n if (!id || typeof id !== 'string') return crypto.randomUUID()\n if (id.endsWith('.')) return `${id}${crypto.randomUUID()}`\n return id\n}\n\ninterface ProcessMutationsOptions {\n /**\n * The transaction ID that will become the next `_rev` for documents mutated\n * by the given mutations.\n */\n transactionId: string\n /**\n * The input document set that the mutations will be applied to.\n */\n documents: DocumentSet\n /**\n * A list of mutations to apply to the given document set.\n */\n mutations: Mutation[]\n /**\n * An optional timestamp that will be used for `_createdAt` and `_updatedAt`\n * timestamp when applicable.\n */\n timestamp?: string\n}\n\nexport function getDocumentIds(selection: MutationSelection): string[] {\n if ('id' in selection) {\n // NOTE: the `MutationSelection` type within `@sanity/client` (instead of\n // `@sanity/types`) allows for the ID field to be an array of strings so we\n // support that as well\n const array = Array.isArray(selection.id) ? selection.id : [selection.id]\n const ids = array.filter((id): id is string => typeof id === 'string')\n return Array.from(new Set(ids))\n }\n\n if ('query' in selection) {\n throw new Error(`'query' in mutations is not supported.`)\n }\n\n return []\n}\n\n/**\n * Applies the given mutation to the given document set. Note, it is expected\n * that all relevant documents that the mutations affect should be within the\n * given `document` set. If a document does not exist, it should have the value\n * `null`. If a document is deleted as a result of the mutations, it will still\n * have its document ID present in the returns documents, but it will have a\n * value of `null`.\n *\n * The given `transactionId` will be used as the resulting `_rev` for documents\n * affected by the given set of mutations.\n *\n * If a `timestamp` is given, that will be used as for the relevant `_updatedAt`\n * and `_createdAt` timestamps.\n */\nexport function processMutations({\n documents,\n mutations,\n transactionId,\n timestamp,\n}: ProcessMutationsOptions): DocumentSet {\n // early return if there are no mutations given\n if (!mutations.length) return documents\n\n const dataset = {...documents}\n const now = timestamp || new Date().toISOString()\n\n for (const mutation of mutations) {\n if ('create' in mutation) {\n const id = getId(mutation.create._id)\n\n if (dataset[id]) {\n throw new Error(\n `Cannot create document with \\`_id\\` \\`${id}\\` because another document with the same ID already exists.`,\n )\n }\n\n const document: SanityDocument = {\n // > `_createdAt` and `_updatedAt` may be submitted and will override\n // > the default which is of course the current time. This can be used\n // > to reconstruct a data-set with its timestamp structure intact.\n // >\n // > [- source](https://www.sanity.io/docs/http-mutations#c732f27330a4)\n _createdAt: now,\n _updatedAt: now,\n ...mutation.create, // prefer the user's `_createdAt` and `_updatedAt`\n _rev: transactionId,\n _id: id,\n }\n\n dataset[id] = document\n\n continue\n }\n\n if ('createOrReplace' in mutation) {\n const id = getId(mutation.createOrReplace._id)\n const prev = dataset[id]\n\n const document: SanityDocument = {\n ...mutation.createOrReplace,\n // otherwise, if the mutation provided, a `_createdAt` time, use it,\n // otherwise default to now\n _createdAt:\n // if there was an existing document, use the previous `_createdAt`\n // since we're replacing the current document\n prev?._createdAt ||\n // if there was no previous document, then we're creating this\n // document for the first time so we should use the `_createdAt` from\n // the mutation if the user included it\n (typeof mutation.createOrReplace['_createdAt'] === 'string' &&\n mutation.createOrReplace['_createdAt']) ||\n // otherwise, default to now\n now,\n\n _updatedAt:\n // if there was an existing document, then set the `_updatedAt` to now\n // since we're replacing the current document\n prev\n ? now\n : // otherwise, we're creating this document for the first time,\n // in that case, use the user's `_updatedAt` if included in the\n // mutation\n (typeof mutation.createOrReplace['_updatedAt'] === 'string' &&\n mutation.createOrReplace['_updatedAt']) ||\n // otherwise default to now\n now,\n _rev: transactionId,\n _id: id,\n }\n\n dataset[id] = document\n\n continue\n }\n\n if ('createIfNotExists' in mutation) {\n const id = getId(mutation.createIfNotExists._id)\n const prev = dataset[id]\n if (prev) continue\n\n const document: SanityDocument = {\n // same logic as `create`:\n // prefer the user's `_createdAt` and `_updatedAt`\n _createdAt: now,\n _updatedAt: now,\n ...mutation.createIfNotExists,\n _rev: transactionId,\n _id: id,\n }\n\n dataset[id] = document\n\n continue\n }\n\n if ('delete' in mutation) {\n for (const id of getDocumentIds(mutation.delete)) {\n dataset[id] = null\n }\n\n continue\n }\n\n if ('patch' in mutation) {\n const {patch} = mutation\n const ids = getDocumentIds(patch)\n\n const patched = ids.map((id) => {\n if (!dataset[id]) {\n throw new Error(`Cannot patch document with ID \\`${id}\\` because it was not found.`)\n }\n\n type Entries<T> = {[K in keyof T]: [K, T[K]]}[keyof T][]\n const entries = Object.entries(patchOperations) as Entries<typeof patchOperations>\n\n return entries.reduce((acc, [type, operation]) => {\n if (patch[type]) {\n return operation(\n acc,\n // @ts-expect-error TS doesn't handle this union very well\n patch[type],\n )\n }\n return acc\n }, dataset[id])\n })\n\n for (const result of patched) {\n dataset[result._id] = {\n ...result,\n _rev: transactionId,\n _updatedAt: now,\n }\n }\n\n continue\n }\n }\n\n return dataset\n}\n","import {type MutationEvent} from '@sanity/client'\nimport {type Mutation, type SanityDocument} from '@sanity/types'\nimport {\n concat,\n concatMap,\n distinctUntilChanged,\n EMPTY,\n filter,\n map,\n type Observable,\n of,\n switchMap,\n throwError,\n timer,\n withLatestFrom,\n} from 'rxjs'\nimport {mergeMap, scan} from 'rxjs/operators'\n\nimport {type StoreContext} from '../store/defineStore'\nimport {type DocumentStoreState} from './documentStore'\nimport {processMutations} from './processMutations'\n\nexport const DEFAULT_MAX_BUFFER_SIZE = 20\nconst DEFAULT_DEADLINE_MS = 30000\n\nexport interface RemoteDocument {\n type: 'sync' | 'mutation'\n documentId: string\n document: SanityDocument | null\n revision?: string\n previousRev?: string\n timestamp: string\n /**\n * The raw mutations from the listener event that produced this document.\n * Only present for `'mutation'` events. These carry the operational intent\n * of the remote change (e.g. keyed patches) before it is collapsed into a\n * whole document snapshot.\n */\n mutations?: Mutation[]\n}\n\nexport interface SyncEvent {\n type: 'sync'\n document: SanityDocument | null\n}\n\nexport type ListenerEvent = SyncEvent | MutationEvent\n\ninterface ListenerSequenceState {\n /**\n * Tracks the latest revision from the server that can be applied locally\n * Once we receive a mutation event that has a `previousRev` that equals `base.revision`\n * we will move `base.revision` to the event's `resultRev`\n * `base.revision` will be undefined if document doesn't exist.\n * `base` is `undefined` until the snapshot event is received\n */\n base: {revision: string | undefined} | undefined\n /**\n * Array of events to pass on to the stream, e.g. when mutation applies to current head revision, or a chain is complete\n */\n emitEvents: ListenerEvent[]\n /**\n * Buffer to keep track of events that doesn't line up in a [previousRev, resultRev] -- [previousRev, resultRev] sequence\n * This can happen if events arrive out of order, or if an event in the middle for some reason gets lost\n */\n buffer: MutationEvent[]\n}\n\nexport class OutOfSyncError extends Error {\n /**\n * Attach state to the error for debugging/reporting\n */\n state: ListenerSequenceState\n constructor(message: string, state: ListenerSequenceState) {\n super(message)\n this.name = 'OutOfSyncError'\n this.state = state\n }\n}\n\nexport class DeadlineExceededError extends OutOfSyncError {\n constructor(message: string, state: ListenerSequenceState) {\n super(message, state)\n this.name = 'DeadlineExceededError'\n }\n}\n\nexport class MaxBufferExceededError extends OutOfSyncError {\n constructor(message: string, state: ListenerSequenceState) {\n super(message, state)\n this.name = 'MaxBufferExceededError'\n }\n}\n\ninterface SortListenerEventsOptions {\n maxBufferSize?: number\n resolveChainDeadline?: number\n}\n\n/**\n * Orders the given mutation events into chains where each event's\n * `previousRev` points at another event's `resultRev`. Events whose\n * `previousRev` matches no other event start a new chain. The buffer may have\n * multiple holes in it, so multiple chains can exist at once.\n */\nfunction toOrderedChains(events: MutationEvent[]): MutationEvent[][] {\n const chainStarts = events.filter(\n (event) => !events.some((other) => other.resultRev === event.previousRev),\n )\n\n return chainStarts.map((start) => {\n const chain: MutationEvent[] = []\n let current: MutationEvent | undefined = start\n while (current) {\n chain.push(current)\n const currentResultRev: string | undefined = current.resultRev\n current = events.find((event) => event.previousRev === currentResultRev)\n }\n return chain\n })\n}\n\n/**\n * Discards the leading events of a chain up to and including the event whose\n * `resultRev` equals the given revision. These events describe changes that\n * are already reflected in the current base (e.g. events replayed by a\n * resumed listener after the snapshot was refetched).\n */\nfunction discardChainTo(chain: MutationEvent[], revision: string | undefined): MutationEvent[] {\n const revisionIndex = chain.findIndex((event) => event.resultRev === revision)\n if (revisionIndex === -1) return chain\n return chain.slice(revisionIndex + 1)\n}\n\n/**\n * Takes an input observable of listener events that might arrive out of order, and emits them in sequence\n * If we receive mutation events that doesn't line up in [previousRev, resultRev] pairs we'll put them in a buffer and\n * check if we have an unbroken chain every time we receive a new event\n *\n * Buffered chains that lead up to the current base revision are discarded:\n * they describe changes already reflected in the base (e.g. events replayed\n * by a resumed listener after the snapshot was refetched)\n *\n * If the buffer grows beyond `maxBufferSize`, or if `resolveChainDeadline` milliseconds passes before the chain resolves\n * an OutOfSyncError will be thrown on the stream\n *\n * @internal\n */\nexport function sortListenerEvents(options?: SortListenerEventsOptions) {\n const {resolveChainDeadline = DEFAULT_DEADLINE_MS, maxBufferSize = DEFAULT_MAX_BUFFER_SIZE} =\n options || {}\n\n return (input$: Observable<ListenerEvent>): Observable<ListenerEvent> => {\n return input$.pipe(\n // Maintain state: current base revision, a buffer of pending mutation events,\n // and a list of events to emit.\n scan(\n (state: ListenerSequenceState, event: ListenerEvent): ListenerSequenceState => {\n // When a sync event is received, reset the base and clear any pending mutations.\n if (event.type === 'sync') {\n return {\n base: {revision: event.document?._rev},\n buffer: [],\n emitEvents: [event],\n }\n }\n // For mutation events we must have a base revision (from a prior sync event)\n if (event.type === 'mutation') {\n if (!state.base) {\n throw new Error(\n 'Invalid state. Cannot process mutation event without a base sync event',\n )\n }\n const baseRevision = state.base.revision\n\n // Order the buffered events (plus the new one) into chains, then\n // drop the parts of each chain the base already reflects.\n const chains = toOrderedChains(state.buffer.concat(event))\n .map((chain) => discardChainTo(chain, baseRevision))\n .filter((chain) => chain.length > 0)\n\n // A chain whose head continues the current base revision can be\n // applied. There can be at most one; anything else stays buffered.\n const applicable = chains.find((chain) => chain[0].previousRev === baseRevision)\n const buffer = chains.filter((chain) => chain !== applicable).flat()\n\n if (applicable) {\n const last = applicable[applicable.length - 1]\n return {\n // If the chain ends in a deletion, the new base revision is undefined.\n base: {revision: last.transition === 'disappear' ? undefined : last.resultRev},\n buffer,\n emitEvents: applicable,\n }\n }\n\n if (buffer.length >= maxBufferSize) {\n throw new MaxBufferExceededError(\n `Too many unchainable mutation events (${buffer.length}) waiting to resolve.`,\n {base: {revision: baseRevision}, buffer, emitEvents: []},\n )\n }\n\n return {\n base: {revision: baseRevision},\n buffer,\n emitEvents: [],\n }\n }\n // Any other event is simply forwarded.\n return {...state, emitEvents: [event]}\n },\n {\n base: undefined,\n buffer: [] as MutationEvent[],\n emitEvents: [] as ListenerEvent[],\n },\n ),\n switchMap((state) => {\n if (state.buffer.length > 0) {\n return concat(\n of(state),\n timer(resolveChainDeadline).pipe(\n mergeMap(() =>\n throwError(\n () =>\n new DeadlineExceededError(\n `Did not resolve chain within a deadline of ${resolveChainDeadline}ms`,\n state,\n ),\n ),\n ),\n ),\n )\n }\n return of(state)\n }),\n // Emit all events that are ready to be applied.\n mergeMap((state) => of(...state.emitEvents)),\n )\n }\n}\n\nexport const listen = (\n {state}: StoreContext<DocumentStoreState>,\n documentId: string,\n): Observable<RemoteDocument> => {\n const {sharedListener, fetchDocument} = state.get()\n\n return sharedListener.events.pipe(\n concatMap((e) => {\n // `welcome` means a fresh listener connection and `reset` means a\n // resumed listener could not replay what was missed; both require\n // refetching the snapshot. a `welcomeback` means the resume succeeded\n // and the missed events were replayed, so no refetch is needed\n if (e.type === 'welcome' || e.type === 'reset') {\n return fetchDocument(documentId).pipe(\n map((document): SyncEvent => ({type: 'sync', document})),\n )\n }\n if (e.type === 'mutation' && e.documentId === documentId) return of(e)\n return EMPTY\n }),\n sortListenerEvents(),\n withLatestFrom(\n state.observable.pipe(\n map((s) => s.documentStates[documentId]),\n filter(Boolean),\n distinctUntilChanged(),\n ),\n ),\n map(([next, documentState]): RemoteDocument => {\n if (next.type === 'sync') {\n return {\n type: 'sync',\n documentId,\n document: next.document,\n revision: next.document?._rev,\n timestamp: next.document?._updatedAt ?? new Date().toISOString(),\n }\n }\n\n // TODO: from manual testing, mendoza patches seem to be applying\n // let document\n // if (next.effects?.apply) {\n // document = applyPatch(omit(documentState.remote, '_rev'), next.effects?.apply)\n // }\n\n const [document] = Object.values(\n processMutations({\n documents: {[documentId]: documentState.remote},\n mutations: next.mutations as Mutation[],\n transactionId: next.transactionId,\n timestamp: next.timestamp,\n }),\n )\n\n const {previousRev, transactionId, timestamp} = next\n\n return {\n type: 'mutation',\n documentId,\n document: document ?? null,\n revision: transactionId,\n timestamp,\n mutations: next.mutations as Mutation[],\n ...(previousRev && {previousRev}),\n }\n }),\n )\n}\n","interface MultiKeyWeakMapNode {\n value: unknown\n next: WeakMap<object, MultiKeyWeakMapNode>\n}\n\nexport class MultiKeyWeakMap<T = unknown> {\n // The root of our nested WeakMap structure.\n #rootMap = new WeakMap<object, MultiKeyWeakMapNode>()\n\n // Instead of random IDs, we use a counter for deterministic IDs.\n static #globalIdCounter = 0\n // Each instance keeps a cache mapping a key to its assigned ID.\n #idCache = new WeakMap<object, number>()\n\n /**\n * Assigns a numeric ID to the key.\n */\n #assignId(key: object): number {\n const cachedId = this.#idCache.get(key)\n if (cachedId !== undefined) return cachedId\n\n const id = MultiKeyWeakMap.#globalIdCounter\n this.#idCache.set(key, id)\n MultiKeyWeakMap.#globalIdCounter++\n return id\n }\n\n /**\n * Remove duplicate keys and arrange them in a consistent order\n * by sorting according to their assigned IDs.\n */\n #arrangeKeys(keys: object[]): object[] {\n const uniqueKeys = Array.from(new Set(keys))\n const keyed = uniqueKeys.map((key) => [this.#assignId(key), key] as const)\n keyed.sort((a, b) => a[0] - b[0])\n return keyed.map(([, key]) => key)\n }\n\n /**\n * Recursively search the nested WeakMap structure for the value.\n */\n #getDeep(keys: object[], map: WeakMap<object, MultiKeyWeakMapNode>): unknown {\n if (keys.length === 0) return undefined\n\n const [firstKey, ...restKeys] = keys\n const node = map.get(firstKey)\n if (!node) return undefined\n if (restKeys.length === 0) return node.value\n return this.#getDeep(restKeys, node.next)\n }\n\n /**\n * Recursively create nodes along the key chain until the final key\n * is reached, then assign the value.\n */\n #setDeep(keys: object[], map: WeakMap<object, MultiKeyWeakMapNode>, value: unknown): void {\n if (keys.length === 0) return\n\n const [firstKey, ...restKeys] = keys\n let node = map.get(firstKey)\n if (!node) {\n node = {\n value: undefined,\n next: new WeakMap(),\n }\n map.set(firstKey, node)\n }\n\n if (restKeys.length === 0) {\n node.value = value\n } else {\n this.#setDeep(restKeys, node.next, value)\n }\n }\n\n /**\n * Retrieves the value associated with the array of keys.\n * The keys are de-duplicated and sorted so that the order does not matter.\n */\n get(keys: object[]): T | undefined {\n const arrangedKeys = this.#arrangeKeys(keys)\n return this.#getDeep(arrangedKeys, this.#rootMap) as T | undefined\n }\n\n /**\n * Associates the value with the given array of keys.\n */\n set(keys: object[], value: T): void {\n const arrangedKeys = this.#arrangeKeys(keys)\n this.#setDeep(arrangedKeys, this.#rootMap, value)\n }\n}\n","import {diffValue} from '@sanity/diff-patch'\nimport {jsonMatch, stringifyPath} from '@sanity/json-match'\nimport {type Mutation, type PatchOperations, type SanityDocument} from '@sanity/types'\nimport {evaluateSync, type ExprNode} from 'groq-js'\n\nimport {type Grant} from '../permissions'\nimport {type DocumentSet, processMutations} from '../processMutations'\nimport {type HttpAction} from '../reducers'\n\nexport interface ActionHandlerContext {\n base: DocumentSet\n working: DocumentSet\n transactionId: string\n timestamp: string\n grants: Record<Grant, ExprNode>\n /**\n * The current user's ID, used by GROQ's `identity()` when evaluating ACL\n * filters. May be `undefined` before the user has loaded; in that case\n * `identity()` evaluates to null.\n */\n identity: string | undefined\n outgoingActions: HttpAction[]\n outgoingMutations: Mutation[]\n}\n\nexport interface ActionHandlerResult {\n base: DocumentSet\n working: DocumentSet\n}\n\nexport function checkGrant(\n grantExpr: ExprNode,\n document: SanityDocument,\n identity: string | undefined,\n): boolean {\n const value = evaluateSync(grantExpr, {params: {document}, identity})\n return value.type === 'boolean' && value.data\n}\n\ninterface ActionErrorOptions {\n message: string\n documentId: string\n transactionId: string\n}\n\n/**\n * Thrown when a precondition for an action failed.\n */\nexport class ActionError extends Error implements ActionErrorOptions {\n documentId!: string\n transactionId!: string\n\n constructor(options: ActionErrorOptions) {\n super(options.message)\n Object.assign(this, options)\n }\n}\n\nexport class PermissionActionError extends ActionError {}\n\n/**\n * Creates a `processMutations` wrapper that surfaces application failures as\n * `ActionError`s when the caller asked to preserve their patch operations.\n * With preserved operations, patches can legitimately fail to apply (e.g.\n * re-applied onto a diverged document during a rebase), so wrapping lets a\n * rebase skip the transaction instead of failing the store. Without\n * `preserveOperations`, errors are rethrown untouched.\n */\nexport function createMutationApplier(options: {\n documentId: string\n transactionId: string\n timestamp: string\n preserveOperations: boolean | undefined\n}): (\n documents: DocumentSet,\n mutations: Mutation[],\n documentSetName: 'base' | 'working',\n) => DocumentSet {\n const {documentId, transactionId, timestamp, preserveOperations} = options\n return (documents, mutations, documentSetName) => {\n try {\n return processMutations({documents, transactionId, mutations, timestamp})\n } catch (error) {\n if (!preserveOperations) throw error\n throw new ActionError({\n documentId,\n transactionId,\n message: `Failed to apply patches to the ${documentSetName} document: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n })\n }\n }\n}\n\n/**\n * Re-applies the operational intent of user-supplied `inc`/`dec` patches to a\n * set of snapshot-diffed patches.\n *\n * The outgoing patches sent to Content Lake are re-derived by diffing the\n * base document before and after the user's patches were applied. That diff\n * collapses an `inc` into a `set` of the resulting number, which turns\n * concurrent increments from different clients into last-write-wins. This\n * helper finds diffed `set` operations that are exactly explained by the\n * user's `inc`/`dec` operations and swaps them back, so the server applies\n * the increment against whatever value is current at commit time.\n *\n * A `set` is only swapped when its value equals the base value plus the\n * accumulated user deltas for that exact path; anything else (e.g. an `inc`\n * combined with a `set` of the same field) keeps the diffed `set`.\n *\n * Content Lake fails the whole transaction when `inc`/`dec` targets a missing\n * path (unlike `set`, which always succeeds). To avoid turning a concurrent\n * field removal into a transaction revert, the emitted patch seeds the target\n * with a `setIfMissing` of the base value; the server executes `setIfMissing`\n * before `inc`/`dec` within a single patch, so a concurrently removed field\n * degrades to the same result the diffed `set` would have produced. A path\n * into a concurrently removed keyed array item can still fail the\n * transaction (`setIfMissing` cannot create array items); the transaction is\n * then reverted and reported, which is preferable to silently resurrecting\n * the item.\n */\nexport function preserveNumericOperations(\n baseBefore: SanityDocument | null | undefined,\n userPatches: PatchOperations[] | undefined,\n diffedPatches: PatchOperations[],\n): PatchOperations[] {\n if (!baseBefore || !userPatches?.length) return diffedPatches\n\n // accumulate the user's inc/dec deltas per concrete (stringified) path,\n // tracking the expected final value by replaying the additions in order\n const targets = new Map<string, {baseValue: number; expectedValue: number; delta: number}>()\n for (const patch of userPatches) {\n for (const [op, sign] of [\n ['inc', 1],\n ['dec', -1],\n ] as const) {\n const record = patch[op]\n if (!record) continue\n for (const [pathExpression, amount] of Object.entries(record)) {\n if (typeof amount !== 'number') continue\n for (const match of jsonMatch(baseBefore, pathExpression)) {\n const path = stringifyPath(match.path)\n const existing = targets.get(path)\n if (existing) {\n existing.expectedValue += sign * amount\n existing.delta += sign * amount\n } else if (typeof match.value === 'number') {\n targets.set(path, {\n baseValue: match.value,\n expectedValue: match.value + sign * amount,\n delta: sign * amount,\n })\n }\n }\n }\n }\n }\n if (!targets.size) return diffedPatches\n\n const preserved = new Map<string, {delta: number; baseValue: number}>()\n const next = diffedPatches.flatMap((patch) => {\n if (!patch.set) return [patch]\n\n const keptSet: Record<string, unknown> = {}\n for (const [path, value] of Object.entries(patch.set)) {\n const target = targets.get(path)\n if (target && typeof value === 'number' && value === target.expectedValue) {\n preserved.set(path, {delta: target.delta, baseValue: target.baseValue})\n } else {\n keptSet[path] = value\n }\n }\n\n if (Object.keys(keptSet).length === Object.keys(patch.set).length) return [patch]\n const {set: _set, ...rest} = patch\n const withKept = Object.keys(keptSet).length ? {...rest, set: keptSet} : rest\n return Object.keys(withKept).length ? [withKept] : []\n })\n\n if (!preserved.size) return next\n\n const setIfMissing: Record<string, unknown> = {}\n const inc: Record<string, number> = {}\n const dec: Record<string, number> = {}\n for (const [path, {delta, baseValue}] of preserved) {\n setIfMissing[path] = baseValue\n if (delta >= 0) inc[path] = delta\n else dec[path] = -delta\n }\n return [\n ...next,\n {\n setIfMissing,\n ...(Object.keys(inc).length && {inc}),\n ...(Object.keys(dec).length && {dec}),\n },\n ]\n}\n\ninterface ApplySingleDocPatchOptions {\n base: DocumentSet\n working: DocumentSet\n documentId: string\n patches: PatchOperations[] | undefined\n transactionId: string\n timestamp: string\n grants: Record<Grant, ExprNode>\n identity: string | undefined\n /**\n * Error message thrown when the target document does not exist in either\n * the base or working set.\n */\n notFoundMessage?: string\n /**\n * Error message thrown when the working document fails the `update` grant.\n */\n permissionMessage?: string\n /**\n * When `true`, the given patches are used verbatim instead of being\n * re-derived by diffing the base document before and after application.\n * Patch application failures are surfaced as `ActionError`s so a rebase\n * can skip the transaction instead of failing the store.\n */\n preserveOperations?: boolean\n}\n\ninterface ApplySingleDocPatchResult {\n base: DocumentSet\n working: DocumentSet\n /**\n * Patch operations representing the minimal diff between base before and\n * after the user's patches were applied. These are the patches that should\n * be sent to the server (or applied to the working set as mutations).\n */\n diffedPatches: PatchOperations[]\n /**\n * Mutation envelopes for `diffedPatches` already keyed to `documentId`.\n * Useful for callers that want to push them to `outgoingMutations`.\n */\n workingMutations: Mutation[]\n}\n\n/**\n * Shared logic for applying user-provided patches to a single document that\n * is identified by an exact ID (no draft/published wrapping). Used by the\n * liveEdit branch of `document.edit` and by `release.edit`.\n *\n * Returns the updated base + working sets, plus the diffed patches in both\n * raw and mutation form so the caller can decide what to send to the server.\n */\nexport function applySingleDocPatch({\n base: initialBase,\n working: initialWorking,\n documentId,\n patches,\n transactionId,\n timestamp,\n grants,\n identity,\n notFoundMessage = 'Cannot edit document because it does not exist.',\n permissionMessage = `You do not have permission to edit document \"${documentId}\".`,\n preserveOperations,\n}: ApplySingleDocPatchOptions): ApplySingleDocPatchResult {\n let base = initialBase\n let working = initialWorking\n\n const userPatches = patches?.map((patch) => ({patch: {id: documentId, ...patch}}))\n\n if (!userPatches?.length) {\n return {base, working, diffedPatches: [], workingMutations: []}\n }\n\n if (!working[documentId] || !base[documentId]) {\n throw new ActionError({documentId, transactionId, message: notFoundMessage})\n }\n\n const applyMutations = createMutationApplier({\n documentId,\n transactionId,\n timestamp,\n preserveOperations,\n })\n\n const baseBefore = base[documentId]\n base = applyMutations(base, userPatches, 'base')\n const baseAfter = base[documentId]\n const diffedPatches = preserveOperations\n ? (patches as PatchOperations[])\n : preserveNumericOperations(\n baseBefore,\n patches,\n diffValue(baseBefore, baseAfter) as PatchOperations[],\n )\n\n const workingBefore = working[documentId] as SanityDocument\n if (!checkGrant(grants.update, workingBefore, identity)) {\n throw new PermissionActionError({documentId, transactionId, message: permissionMessage})\n }\n\n const workingMutations: Mutation[] = diffedPatches.map((patch) => ({\n patch: {id: documentId, ...patch},\n }))\n\n working = applyMutations(working, workingMutations, 'working')\n\n return {base, working, diffedPatches, workingMutations}\n}\n","import {DocumentId, getDraftId, getPublishedId, getVersionId} from '@sanity/id-utils'\nimport {type SanityDocument} from '@sanity/types'\nimport {type ExprNode, parse} from 'groq-js'\nimport {createSelector} from 'reselect'\n\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\nimport {type SelectorContext} from '../store/createStateSourceAction'\nimport {MultiKeyWeakMap} from '../utils/MultiKeyWeakMap'\nimport {type DocumentAction} from './actions'\nimport {ActionError, PermissionActionError, processActions} from './processActions/processActions'\nimport {checkGrant} from './processActions/shared'\nimport {type DocumentSet} from './processMutations'\nimport {type SyncTransactionState} from './reducers'\n\nexport type Grant = 'read' | 'update' | 'create' | 'history'\n\nexport type DatasetAcl = {\n filter: string\n permissions: Grant[]\n}[]\n\nexport function createGrantsLookup(datasetAcl: DatasetAcl): Record<Grant, ExprNode> {\n const filtersByGrant: Record<Grant, Set<string>> = {\n create: new Set(),\n history: new Set(),\n read: new Set(),\n update: new Set(),\n }\n\n for (const entry of datasetAcl) {\n for (const grant of entry.permissions) {\n const set = filtersByGrant[grant]\n // Ignore permissions we don't model (e.g. \"manage\")\n if (!set) continue\n set.add(entry.filter)\n filtersByGrant[grant] = set\n }\n }\n\n return Object.fromEntries(\n Object.entries(filtersByGrant).map(([grant, filters]) => {\n const combinedFilter = Array.from(filters)\n .map((i) => `(${i})`)\n .join('||')\n\n if (!combinedFilter) return [grant, parse('false')]\n return [grant, parse(`$document {\"_\": ${combinedFilter}}._`)]\n }),\n ) as Record<Grant, ExprNode>\n}\n\n// Cache for documents based on an array of document objects.\nconst documentsCache = new MultiKeyWeakMap<DocumentSet>()\n// Use a WeakMap so that when a computed DocumentSet is no longer in use,\n// its nested cache for actions can be garbage-collected.\nconst actionsCache = new WeakMap<DocumentSet, Map<string, DocumentAction[]>>()\n\nconst nullReplacer: object = {}\n\n// Compute documents from state and actions.\n// (If the same documents are computed, the MultiKeyWeakMap will return the same instance.)\nconst documentsSelector = createSelector(\n [\n ({state: {documentStates}}: SelectorContext<SyncTransactionState>) => documentStates,\n (_context: SelectorContext<SyncTransactionState>, {actions}: {actions: DocumentAction[]}) =>\n actions,\n ],\n (documentStates, actions) => {\n // Collect all document IDs needed for permission checks.\n // Important: liveEdit documents don't have drafts, so we only fetch the single document to avoid waiting for non-existent draft documents.\n const documentIds = new Set(\n actions\n .map((action) => {\n if (typeof action.documentId !== 'string') return []\n // For liveEdit documents, only fetch the single document\n if (action.liveEdit) return [action.documentId]\n // For standard documents, fetch both draft and published\n const ids: string[] = [\n getPublishedId(DocumentId(action.documentId)),\n getDraftId(DocumentId(action.documentId)),\n ]\n if (isReleasePerspective(action.perspective)) {\n ids.push(getVersionId(DocumentId(action.documentId), action.perspective.releaseName))\n }\n return ids\n })\n .flat(),\n )\n\n const documents: DocumentSet = {}\n\n for (const documentId of documentIds) {\n const local = documentStates[documentId]?.local\n\n // early exit if we don't have all the documents yet\n if (local === undefined) return undefined\n documents[documentId] = local\n }\n\n // Create a key from the documents values (using a nullReplacer when needed).\n const keys = Object.values(\n // value in this record will be `undefined` because\n // of the early return if undefined is found above\n documents as Record<string, SanityDocument | null>,\n ).map((doc) => (doc === null ? nullReplacer : doc))\n const cached = documentsCache.get(keys)\n if (cached) return cached\n\n documentsCache.set(keys, documents)\n return documents\n },\n)\n\n// Cache the actions array based on a serialized version, but “attach” the cache\n// to the computed documents. That way if the computed documents object is no longer in use,\n// the cache is eligible for GC.\nconst memoizedActionsSelector = createSelector(\n [\n documentsSelector,\n (_state: SelectorContext<SyncTransactionState>, {actions}: {actions: DocumentAction[]}) =>\n actions,\n ],\n (documents, actions) => {\n if (!documents) return undefined\n\n // Get (or create) the nested Map for this computed documents.\n let nestedCache = actionsCache.get(documents)\n if (!nestedCache) {\n nestedCache = new Map<string, DocumentAction[]>()\n actionsCache.set(documents, nestedCache)\n }\n\n const normalizedActions = Array.isArray(actions) ? actions : [actions]\n\n // Use JSON.stringify to get a serialized key for the actions.\n // TODO: considering swapping thisfor a more efficient or stable hash\n const actionsKey = JSON.stringify(normalizedActions)\n const cached = nestedCache.get(actionsKey)\n if (cached) return cached\n\n nestedCache.set(actionsKey, normalizedActions)\n return normalizedActions\n },\n)\n\n/** @beta */\nexport interface PermissionDeniedReason {\n type: 'precondition' | 'access'\n message: string\n documentId?: string\n}\n\n/** @beta */\nexport type DocumentPermissionsResult =\n | {\n allowed: false\n message: string\n reasons: PermissionDeniedReason[]\n }\n | {allowed: true; message?: undefined; reasons?: undefined}\n\nconst enNarrowConjunction = new Intl.ListFormat('en', {style: 'narrow', type: 'conjunction'})\n\nexport function calculatePermissions(\n ...args: Parameters<typeof _calculatePermissions>\n): ReturnType<typeof _calculatePermissions> {\n return _calculatePermissions(...args)\n}\n\nconst _calculatePermissions = createSelector(\n [\n ({state: {grants}}: SelectorContext<SyncTransactionState>) => grants,\n ({state: {identity}}: SelectorContext<SyncTransactionState>) => identity,\n documentsSelector,\n memoizedActionsSelector,\n ],\n (\n grants: Record<Grant, ExprNode> | undefined,\n identity: string | undefined,\n documents: DocumentSet | undefined,\n actions: DocumentAction[] | undefined,\n ): DocumentPermissionsResult | undefined => {\n if (!documents) return undefined\n if (!grants) return undefined\n if (!actions) return undefined\n\n const timestamp = new Date().toISOString()\n const reasons: PermissionDeniedReason[] = []\n\n try {\n processActions({\n actions,\n transactionId: crypto.randomUUID(),\n working: documents,\n base: documents,\n timestamp,\n grants,\n identity,\n })\n } catch (error) {\n if (error instanceof PermissionActionError) {\n reasons.push({\n message: error.message,\n documentId: error.documentId,\n type: 'access',\n })\n } else if (error instanceof ActionError) {\n reasons.push({\n message: error.message,\n documentId: error.documentId,\n type: 'precondition',\n })\n } else {\n throw error\n }\n }\n\n for (const action of actions) {\n // Check edit actions with no patches\n if (action.type === 'document.edit' && !action.patches?.length) {\n const docId = action.documentId\n let doc: SanityDocument | null | undefined\n if (action.liveEdit) {\n doc = documents[docId]\n }\n // don't allow users to edit version documents that don't exist\n // they should be explicitly created first, as in studio\n else if (isReleasePerspective(action.perspective)) {\n doc = documents[getVersionId(DocumentId(docId), action.perspective.releaseName)]\n } else {\n doc =\n documents[getDraftId(DocumentId(docId))] ?? documents[getPublishedId(DocumentId(docId))]\n }\n if (!doc) {\n if (isReleasePerspective(action.perspective)) {\n reasons.push({\n type: 'precondition',\n message: `The version document with ID \"${docId}\" could not be found. Please create it or add it to the release first.`,\n documentId: docId,\n })\n } else {\n reasons.push({\n type: 'precondition',\n message: `The document with ID \"${docId}\" could not be found. Please check that it exists before editing.`,\n documentId: docId,\n })\n }\n } else if (!checkGrant(grants.update, doc, identity)) {\n reasons.push({\n type: 'access',\n message: `You are not allowed to edit the document with ID \"${docId}\".`,\n documentId: docId,\n })\n }\n }\n }\n\n const allowed = reasons.length === 0\n if (allowed) return {allowed}\n\n const sortedReasons = reasons\n .map((reason, index) => ({...reason, index}))\n .sort((a, b) => {\n if (a.type !== b.type) return a.type === 'access' ? -1 : 1\n return a.message.localeCompare(b.message, 'en-US')\n })\n .map(({index: _index, ...reason}) => reason)\n\n return {\n allowed,\n reasons: sortedReasons,\n message: enNarrowConjunction.format(sortedReasons.map((i) => i.message)),\n }\n },\n)\n","import {DocumentId, getDraftId, getPublishedId, getVersionId} from '@sanity/id-utils'\nimport {type Mutation, type SanityDocument} from '@sanity/types'\n\nimport {isReleasePerspective} from '../../releases/utils/isReleasePerspective'\nimport {type CreateDocumentAction} from '../actions'\nimport {getId, processMutations} from '../processMutations'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n checkGrant,\n PermissionActionError,\n} from './shared'\n\nexport function handleCreate(\n action: CreateDocumentAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {transactionId, timestamp, grants, identity, outgoingActions, outgoingMutations} = ctx\n let {base, working} = ctx\n\n const documentId = getId(action.documentId)\n\n if (action.liveEdit) {\n if (working[documentId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `This document already exists.`,\n })\n }\n\n const newDocBase = {_type: action.documentType, _id: documentId, ...action.initialValue}\n const newDocWorking = {\n _type: action.documentType,\n _id: documentId,\n ...action.initialValue,\n }\n const mutations: Mutation[] = [{create: newDocWorking}]\n\n base = processMutations({\n documents: base,\n transactionId,\n mutations: [{create: newDocBase}],\n timestamp,\n })\n working = processMutations({\n documents: working,\n transactionId,\n mutations,\n timestamp,\n })\n\n if (!checkGrant(grants.create, working[documentId] as SanityDocument, identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to create document \"${documentId}\".`,\n })\n }\n\n // liveEdit documents use the mutation endpoint directly -- we don't send actions\n outgoingMutations.push(...mutations)\n return {base, working}\n }\n\n // Standard draft/published/version logic\n const versionId = isReleasePerspective(action.perspective)\n ? getVersionId(DocumentId(documentId), action.perspective.releaseName)\n : undefined\n const draftId = getDraftId(DocumentId(documentId))\n const publishedId = getPublishedId(DocumentId(documentId))\n\n const alreadyHasVersion = versionId ? working[versionId] : working[draftId]\n\n if (alreadyHasVersion) {\n const errorDocType = versionId ? 'release version' : 'draft'\n throw new ActionError({\n documentId,\n transactionId,\n message: `A ${errorDocType} of this document already exists. Please use or discard the existing ${errorDocType} before creating a new one.`,\n })\n }\n\n // Spread the (possibly undefined) draft or published version directly.\n // (studio uses the draft version as a base if you are in a release perspective)\n const newDocBase = {\n ...(base[draftId] ?? base[publishedId]),\n _type: action.documentType,\n _id: versionId ?? draftId,\n ...action.initialValue,\n }\n const newDocWorking = {\n ...(working[draftId] ?? working[publishedId]),\n _type: action.documentType,\n _id: versionId ?? draftId,\n ...action.initialValue,\n }\n const mutations: Mutation[] = [{create: newDocWorking}]\n\n base = processMutations({\n documents: base,\n transactionId,\n mutations: [{create: newDocBase}],\n timestamp,\n })\n working = processMutations({\n documents: working,\n transactionId,\n mutations,\n timestamp,\n })\n\n if (versionId && !checkGrant(grants.create, working[versionId] as SanityDocument, identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to create a release version for document \"${documentId}\".`,\n })\n } else if (\n !versionId &&\n !checkGrant(grants.create, working[draftId] as SanityDocument, identity)\n ) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to create a draft for document \"${documentId}\".`,\n })\n }\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.version.create',\n publishedId,\n attributes: newDocWorking,\n })\n return {base, working}\n}\n","import {DocumentId, getDraftId, getPublishedId} from '@sanity/id-utils'\nimport {type Mutation} from '@sanity/types'\n\nimport {isReleasePerspective} from '../../releases/utils/isReleasePerspective'\nimport {type DeleteDocumentAction} from '../actions'\nimport {processMutations} from '../processMutations'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n checkGrant,\n PermissionActionError,\n} from './shared'\n\nexport function handleDelete(\n action: DeleteDocumentAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {transactionId, timestamp, grants, identity, outgoingActions, outgoingMutations} = ctx\n let {base, working} = ctx\n\n const documentId = action.documentId\n\n if (isReleasePerspective(action.perspective)) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot delete a version document. You may want to use the \"unpublish\" or \"discard\" actions instead.`,\n })\n }\n\n if (action.liveEdit) {\n if (!working[documentId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: 'The document you are trying to delete does not exist.',\n })\n }\n\n if (!checkGrant(grants.update, working[documentId], identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to delete this document.`,\n })\n }\n\n const mutations: Mutation[] = [{delete: {id: documentId}}]\n\n base = processMutations({documents: base, transactionId, mutations, timestamp})\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n // although liveEdit documents can use the actions API for deletion,\n // having this be an action while other operations are mutations creates an inconsistency\n // (and a possible race condition in document store where mutations might get skipped)\n outgoingMutations.push(...mutations)\n return {base, working}\n }\n\n // Standard draft/published logic\n const draftId = getDraftId(DocumentId(documentId))\n const publishedId = getPublishedId(DocumentId(documentId))\n\n if (!working[publishedId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: working[draftId]\n ? 'Cannot delete a document without a published version.'\n : 'The document you are trying to delete does not exist.',\n })\n }\n\n const cantDeleteDraft = working[draftId] && !checkGrant(grants.update, working[draftId], identity)\n const cantDeletePublished =\n working[publishedId] && !checkGrant(grants.update, working[publishedId], identity)\n\n if (cantDeleteDraft || cantDeletePublished) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to delete this document.`,\n })\n }\n\n const mutations: Mutation[] = [{delete: {id: publishedId}}, {delete: {id: draftId}}]\n const includeDrafts = working[draftId] ? [draftId] : undefined\n\n base = processMutations({documents: base, transactionId, mutations, timestamp})\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.delete',\n publishedId,\n ...(includeDrafts ? {includeDrafts} : {}),\n })\n return {base, working}\n}\n","import {DocumentId, getDraftId, getVersionId} from '@sanity/id-utils'\nimport {type Mutation} from '@sanity/types'\n\nimport {isReleasePerspective} from '../../releases/utils/isReleasePerspective'\nimport {type DiscardDocumentAction} from '../actions'\nimport {getId, processMutations} from '../processMutations'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n checkGrant,\n PermissionActionError,\n} from './shared'\n\nexport function handleDiscard(\n action: DiscardDocumentAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {transactionId, timestamp, grants, identity, outgoingActions, outgoingMutations} = ctx\n let {base, working} = ctx\n\n const documentId = getId(action.documentId)\n\n if (action.liveEdit) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot discard changes for liveEdit document \"${documentId}\". LiveEdit documents do not support drafts.`,\n })\n }\n\n // draft/published or version logic\n const versionId = isReleasePerspective(action.perspective)\n ? getVersionId(DocumentId(documentId), action.perspective.releaseName)\n : getDraftId(DocumentId(documentId))\n const mutations: Mutation[] = [{delete: {id: versionId}}]\n\n if (!working[versionId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `There is no draft or version available to discard for document \"${documentId}\".`,\n })\n }\n\n if (!checkGrant(grants.update, working[versionId], identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to discard changes for document \"${documentId}\".`,\n })\n }\n\n base = processMutations({documents: base, transactionId, mutations, timestamp})\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.version.discard',\n versionId,\n })\n return {base, working}\n}\n","import {diffValue} from '@sanity/diff-patch'\nimport {DocumentId, getDraftId, getPublishedId, getVersionId} from '@sanity/id-utils'\nimport {type Mutation, type PatchOperations, type SanityDocument} from '@sanity/types'\n\nimport {isReleasePerspective} from '../../releases/utils/isReleasePerspective'\nimport {type EditDocumentAction} from '../actions'\nimport {getId} from '../processMutations'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n applySingleDocPatch,\n checkGrant,\n createMutationApplier,\n PermissionActionError,\n preserveNumericOperations,\n} from './shared'\n\nexport function handleEdit(\n action: EditDocumentAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {transactionId, timestamp, grants, identity, outgoingActions, outgoingMutations} = ctx\n let {base, working} = ctx\n\n const documentId = getId(action.documentId)\n\n if (action.liveEdit) {\n const result = applySingleDocPatch({\n base,\n working,\n documentId,\n patches: action.patches,\n transactionId,\n timestamp,\n grants,\n identity,\n preserveOperations: action.preserveOperations,\n })\n // liveEdit documents use the mutation endpoint directly -- we don't send actions\n outgoingMutations.push(...result.workingMutations)\n return {base: result.base, working: result.working}\n }\n\n const versionId = isReleasePerspective(action.perspective)\n ? getVersionId(DocumentId(documentId), action.perspective.releaseName)\n : undefined\n const draftId = getDraftId(DocumentId(documentId))\n const publishedId = getPublishedId(DocumentId(documentId))\n const patchDocumentId = isReleasePerspective(action.perspective) ? versionId! : draftId\n const userPatches = action.patches?.map((patch) => ({\n patch: {id: patchDocumentId, ...patch},\n }))\n\n // skip this action if there are no associated patches\n if (!userPatches?.length) return {base, working}\n\n if (isReleasePerspective(action.perspective)) {\n if (!working[versionId!] && !base[versionId!]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `This document does not exist in the release. Please create it or add it to the release first.`,\n })\n }\n } else if (\n (!working[draftId] && !working[publishedId]) ||\n (!base[draftId] && !base[publishedId])\n ) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot edit document because it does not exist in draft or published form.`,\n })\n }\n\n const applyMutations = createMutationApplier({\n documentId,\n transactionId,\n timestamp,\n preserveOperations: action.preserveOperations,\n })\n\n const baseMutations: Mutation[] = []\n // don't create a draft from the published version in a release perspective\n if (!isReleasePerspective(action.perspective) && !base[draftId] && base[publishedId]) {\n // otherwise make a draft from the published version\n baseMutations.push({create: {...base[publishedId], _id: draftId}})\n }\n\n // the above statement and guards should make this never be null or undefined\n const baseBefore = base[patchDocumentId] ?? base[publishedId]\n if (userPatches) {\n baseMutations.push(...userPatches)\n }\n\n base = applyMutations(base, baseMutations, 'base')\n // this one will always be defined because a patch mutation will never\n // delete an input document\n const baseAfter = base[patchDocumentId] as SanityDocument\n // when the caller asked us to preserve their operations, forward their\n // patches verbatim instead of re-deriving them from a snapshot diff. this\n // keeps keyed array operations addressable so concurrent edits from other\n // clients interleave instead of being overwritten. otherwise, diff the\n // snapshots but swap back any `inc`/`dec` the diff collapsed into a `set`,\n // so concurrent increments accumulate instead of last-write-winning\n const patches = action.preserveOperations\n ? (action.patches ?? [])\n : preserveNumericOperations(\n baseBefore,\n action.patches,\n diffValue(baseBefore, baseAfter) as PatchOperations[],\n )\n\n const workingMutations: Mutation[] = []\n if (!isReleasePerspective(action.perspective) && !working[draftId] && working[publishedId]) {\n const newDraftFromPublished = {...working[publishedId], _id: draftId}\n\n if (!checkGrant(grants.create, newDraftFromPublished, identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to create a draft for editing this document.`,\n })\n }\n\n workingMutations.push({create: newDraftFromPublished})\n }\n\n // the first if statement should make this never be null or undefined\n const workingBefore = working[patchDocumentId] ?? working[publishedId]\n if (!checkGrant(grants.update, workingBefore!, identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to edit document \"${documentId}\".`,\n })\n }\n workingMutations.push(...patches.map((patch) => ({patch: {id: patchDocumentId, ...patch}})))\n\n working = applyMutations(working, workingMutations, 'working')\n\n outgoingMutations.push(...workingMutations)\n outgoingActions.push(\n ...patches.map((patch) => ({\n actionType: 'sanity.action.document.edit' as const,\n draftId: patchDocumentId,\n publishedId,\n patch: patch as PatchOperations,\n })),\n )\n\n return {base, working}\n}\n","import {DocumentId, getDraftId, getPublishedId} from '@sanity/id-utils'\nimport {type Mutation, type Reference, type SanityDocument} from '@sanity/types'\n\nimport {isReleasePerspective} from '../../releases/utils/isReleasePerspective'\nimport {isDeepEqual} from '../../utils/object'\nimport {type PublishDocumentAction} from '../actions'\nimport {getId, processMutations} from '../processMutations'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n checkGrant,\n PermissionActionError,\n} from './shared'\n\nexport function handlePublish(\n action: PublishDocumentAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {transactionId, timestamp, grants, identity, outgoingActions, outgoingMutations} = ctx\n let {base, working} = ctx\n\n const documentId = getId(action.documentId)\n\n if (action.liveEdit || isReleasePerspective(action.perspective)) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot publish this document. Publishing is not supported for liveEdit or version (release) documents.`,\n })\n }\n\n // Standard draft/published logic\n const draftId = getDraftId(DocumentId(documentId))\n const publishedId = getPublishedId(DocumentId(documentId))\n\n const workingDraft = working[draftId]\n const baseDraft = base[draftId]\n if (!workingDraft || !baseDraft) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot publish because no draft version was found for document \"${documentId}\".`,\n })\n }\n\n // Before proceeding, verify that the working draft is identical to the base draft.\n // TODO: is it enough just to check for the _rev or nah?\n if (!isDeepEqual(workingDraft, baseDraft)) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Publish aborted: The document has changed elsewhere. Please try again.`,\n })\n }\n\n const newPublishedFromDraft = {...strengthenOnPublish(workingDraft), _id: publishedId}\n\n const mutations: Mutation[] = [{delete: {id: draftId}}, {createOrReplace: newPublishedFromDraft}]\n\n if (working[draftId] && !checkGrant(grants.update, working[draftId], identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `Publish failed: You do not have permission to update the draft for \"${documentId}\".`,\n })\n }\n\n if (working[publishedId] && !checkGrant(grants.update, newPublishedFromDraft, identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `Publish failed: You do not have permission to update the published version of \"${documentId}\".`,\n })\n } else if (!working[publishedId] && !checkGrant(grants.create, newPublishedFromDraft, identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `Publish failed: You do not have permission to publish a new version of \"${documentId}\".`,\n })\n }\n\n base = processMutations({documents: base, transactionId, mutations, timestamp})\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.publish',\n draftId,\n publishedId,\n })\n return {base, working}\n}\n\nfunction strengthenOnPublish(draft: SanityDocument): SanityDocument {\n const isStrengthenReference = (\n value: object,\n ): value is Reference & Required<Pick<Reference, '_strengthenOnPublish'>> =>\n '_strengthenOnPublish' in value\n\n function strengthen(value: unknown): unknown {\n if (typeof value !== 'object' || !value) return value\n\n if (isStrengthenReference(value)) {\n const {_strengthenOnPublish, _weak, ...rest} = value\n return {\n ...rest,\n ...(_strengthenOnPublish.weak && {_weak: true}),\n }\n }\n\n if (Array.isArray(value)) {\n return value.map(strengthen)\n }\n\n return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, strengthen(v)]))\n }\n\n return strengthen(draft) as SanityDocument\n}\n","import {type ArchiveReleaseAction, type UnarchiveReleaseAction} from '../actions'\nimport {getReleaseDocumentId} from './releaseUtil'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n checkGrant,\n PermissionActionError,\n} from './shared'\n\nexport function handleReleaseArchive(\n action: ArchiveReleaseAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {base, working, grants, outgoingActions, transactionId, identity} = ctx\n\n const releaseDocumentId = getReleaseDocumentId(action.releaseId)\n const existing = working[releaseDocumentId] ?? base[releaseDocumentId]\n if (!existing) {\n throw new ActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `Cannot archive release \"${action.releaseId}\" because it does not exist.`,\n })\n }\n\n if (!checkGrant(grants.update, existing, identity)) {\n throw new PermissionActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `You do not have permission to archive release \"${action.releaseId}\".`,\n })\n }\n\n // Archiving deletes every version document in the release server-side.\n // Although technically we could search through the document store for all related\n // version documents, for now it's simpler to just let the server handle it.\n // (Those local documents will be eventually updated by the listener.)\n outgoingActions.push({\n actionType: 'sanity.action.release.archive',\n releaseId: action.releaseId,\n })\n\n return {base, working}\n}\n\nexport function handleReleaseUnarchive(\n action: UnarchiveReleaseAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {base, working, grants, outgoingActions, transactionId, identity} = ctx\n\n const releaseDocumentId = getReleaseDocumentId(action.releaseId)\n const existing = working[releaseDocumentId] ?? base[releaseDocumentId]\n if (!existing) {\n throw new ActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `Cannot unarchive release \"${action.releaseId}\" because it does not exist.`,\n })\n }\n\n if (!checkGrant(grants.update, existing, identity)) {\n throw new PermissionActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `You do not have permission to unarchive release \"${action.releaseId}\".`,\n })\n }\n\n outgoingActions.push({\n actionType: 'sanity.action.release.unarchive',\n releaseId: action.releaseId,\n })\n\n return {base, working}\n}\n","import {type Mutation, type SanityDocument} from '@sanity/types'\n\nimport {type CreateReleaseAction} from '../actions'\nimport {processMutations} from '../processMutations'\nimport {getReleaseDocumentId} from './releaseUtil'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n checkGrant,\n PermissionActionError,\n} from './shared'\n\nexport function handleReleaseCreate(\n action: CreateReleaseAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {transactionId, timestamp, grants, outgoingActions, outgoingMutations, identity} = ctx\n let {base, working} = ctx\n\n const releaseDocumentId = getReleaseDocumentId(action.releaseId)\n\n if (working[releaseDocumentId] || base[releaseDocumentId]) {\n throw new ActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `A release with id \"${action.releaseId}\" already exists.`,\n })\n }\n // Optimistic local release doc\n const releaseDoc = {\n _id: releaseDocumentId,\n _type: 'system.release',\n name: action.releaseId,\n state: 'active',\n metadata: action.metadata,\n }\n const mutations: Mutation[] = [{create: releaseDoc}]\n\n base = processMutations({documents: base, transactionId, mutations, timestamp})\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n if (!checkGrant(grants.create, working[releaseDocumentId] as SanityDocument, identity)) {\n throw new PermissionActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `You do not have permission to create release \"${action.releaseId}\".`,\n })\n }\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.release.create',\n releaseId: action.releaseId,\n metadata: action.metadata,\n })\n\n return {base, working}\n}\n","import {type Mutation} from '@sanity/types'\n\nimport {type DeleteReleaseAction} from '../actions'\nimport {processMutations} from '../processMutations'\nimport {getReleaseDocumentId} from './releaseUtil'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n checkGrant,\n PermissionActionError,\n} from './shared'\n\n// you can only delete archived or published releases\n// https://www.sanity.io/docs/content-lake/dispatch-actions#k22ab37420f3c\nconst DELETABLE_STATES = new Set(['archived', 'published'])\n\nexport function handleReleaseDelete(\n action: DeleteReleaseAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {transactionId, timestamp, grants, outgoingActions, outgoingMutations, identity} = ctx\n let {base, working} = ctx\n\n const releaseDocumentId = getReleaseDocumentId(action.releaseId)\n const existing = working[releaseDocumentId] ?? base[releaseDocumentId]\n\n if (!existing) {\n throw new ActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `Cannot delete release \"${action.releaseId}\" because it does not exist.`,\n })\n }\n\n const state = existing['state']\n if (state && typeof state === 'string' && !DELETABLE_STATES.has(state)) {\n throw new ActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `Cannot delete release \"${action.releaseId}\" while it is \"${state}\". Archive it first.`,\n })\n }\n\n if (!checkGrant(grants.update, existing, identity)) {\n throw new PermissionActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `You do not have permission to delete release \"${action.releaseId}\".`,\n })\n }\n\n const mutations: Mutation[] = [{delete: {id: releaseDocumentId}}]\n\n base = processMutations({documents: base, transactionId, mutations, timestamp})\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.release.delete',\n releaseId: action.releaseId,\n })\n\n return {base, working}\n}\n","import {type EditReleaseAction} from '../actions'\nimport {getReleaseDocumentId} from './releaseUtil'\nimport {type ActionHandlerContext, type ActionHandlerResult, applySingleDocPatch} from './shared'\n\nexport function handleReleaseEdit(\n action: EditReleaseAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {transactionId, timestamp, grants, outgoingActions, outgoingMutations, identity} = ctx\n const {base, working} = ctx\n\n const releaseDocumentId = getReleaseDocumentId(action.releaseId)\n\n const result = applySingleDocPatch({\n base,\n working,\n documentId: releaseDocumentId,\n patches: [action.patch],\n transactionId,\n timestamp,\n grants,\n identity,\n notFoundMessage: `Cannot edit release \"${action.releaseId}\" because it does not exist.`,\n permissionMessage: `You do not have permission to edit release \"${action.releaseId}\".`,\n })\n\n outgoingMutations.push(...result.workingMutations)\n outgoingActions.push(\n ...result.diffedPatches.map((patch) => ({\n actionType: 'sanity.action.release.edit' as const,\n releaseId: action.releaseId,\n patch,\n })),\n )\n\n return {base: result.base, working: result.working}\n}\n","import {type PublishReleaseAction} from '../actions'\nimport {getReleaseDocumentId} from './releaseUtil'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n checkGrant,\n PermissionActionError,\n} from './shared'\n\nexport function handleReleasePublish(\n action: PublishReleaseAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {base, working, grants, outgoingActions, transactionId, identity} = ctx\n\n const releaseDocumentId = getReleaseDocumentId(action.releaseId)\n const existing = working[releaseDocumentId] ?? base[releaseDocumentId]\n if (!existing) {\n throw new ActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `Cannot publish release \"${action.releaseId}\" because it does not exist.`,\n })\n }\n\n if (!checkGrant(grants.update, existing, identity)) {\n throw new PermissionActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `You do not have permission to publish release \"${action.releaseId}\".`,\n })\n }\n\n // a release publish cascades to every version document in the release\n // although technically we could search through the document store for all related\n // version documents, for now it's simpler to just let the server handle it.\n // (Those local documents will be eventually updated by the listener.)\n outgoingActions.push({\n actionType: 'sanity.action.release.publish',\n releaseId: action.releaseId,\n })\n\n return {base, working}\n}\n","import {type ScheduleReleaseAction, type UnscheduleReleaseAction} from '../actions'\nimport {getReleaseDocumentId} from './releaseUtil'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n checkGrant,\n PermissionActionError,\n} from './shared'\n\nexport function handleReleaseSchedule(\n action: ScheduleReleaseAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {base, working, grants, outgoingActions, transactionId, identity} = ctx\n\n const releaseDocumentId = getReleaseDocumentId(action.releaseId)\n\n if (Number.isNaN(Date.parse(action.publishAt))) {\n throw new ActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `Cannot schedule release \"${action.releaseId}\": \"publishAt\" must be a valid ISO 8601 timestamp (received \"${action.publishAt}\").`,\n })\n }\n\n const existing = working[releaseDocumentId] ?? base[releaseDocumentId]\n if (!existing) {\n throw new ActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `Cannot schedule release \"${action.releaseId}\" because it does not exist.`,\n })\n }\n\n if (!checkGrant(grants.update, existing, identity)) {\n throw new PermissionActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `You do not have permission to schedule release \"${action.releaseId}\".`,\n })\n }\n\n // Scheduling flips `state` to 'scheduled' and locks version documents\n // server-side. We don't model the lock locally yet — local edits to those\n // version docs will be rejected at submit time. The listener will sync the\n // updated release state.\n outgoingActions.push({\n actionType: 'sanity.action.release.schedule',\n releaseId: action.releaseId,\n publishAt: action.publishAt,\n })\n\n return {base, working}\n}\n\nexport function handleReleaseUnschedule(\n action: UnscheduleReleaseAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {base, working, grants, outgoingActions, transactionId, identity} = ctx\n\n const releaseDocumentId = getReleaseDocumentId(action.releaseId)\n const existing = working[releaseDocumentId] ?? base[releaseDocumentId]\n if (!existing) {\n throw new ActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `Cannot unschedule release \"${action.releaseId}\" because it does not exist.`,\n })\n }\n\n if (!checkGrant(grants.update, existing, identity)) {\n throw new PermissionActionError({\n documentId: releaseDocumentId,\n transactionId,\n message: `You do not have permission to unschedule release \"${action.releaseId}\".`,\n })\n }\n\n outgoingActions.push({\n actionType: 'sanity.action.release.unschedule',\n releaseId: action.releaseId,\n })\n\n return {base, working}\n}\n","import {DocumentId, getDraftId, getPublishedId} from '@sanity/id-utils'\nimport {type Mutation, type SanityDocument} from '@sanity/types'\n\nimport {isReleasePerspective} from '../../releases/utils/isReleasePerspective'\nimport {type UnpublishDocumentAction} from '../actions'\nimport {getId, processMutations} from '../processMutations'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n checkGrant,\n PermissionActionError,\n} from './shared'\n\nexport function handleUnpublish(\n action: UnpublishDocumentAction,\n ctx: ActionHandlerContext,\n): ActionHandlerResult {\n const {transactionId, timestamp, grants, identity, outgoingActions, outgoingMutations} = ctx\n let {base, working} = ctx\n\n const documentId = getId(action.documentId)\n\n if (action.liveEdit || isReleasePerspective(action.perspective)) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot unpublish this document. Unpublishing is not supported for liveEdit or version (release) documents.`,\n })\n }\n\n // Standard draft/published or version logic\n const draftId = getDraftId(DocumentId(documentId))\n const publishedId = getPublishedId(DocumentId(documentId))\n\n if (!working[publishedId] && !base[publishedId]) {\n throw new ActionError({\n documentId,\n transactionId,\n message: `Cannot unpublish because the document \"${documentId}\" is not currently published.`,\n })\n }\n\n const sourceDoc = working[publishedId] ?? (base[publishedId] as SanityDocument)\n const newDraftFromPublished = {...sourceDoc, _id: draftId}\n const mutations: Mutation[] = [\n {delete: {id: publishedId}},\n {createIfNotExists: newDraftFromPublished},\n ]\n\n if (!checkGrant(grants.update, sourceDoc, identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to unpublish the document \"${documentId}\".`,\n })\n }\n\n if (!working[draftId] && !checkGrant(grants.create, newDraftFromPublished, identity)) {\n throw new PermissionActionError({\n documentId,\n transactionId,\n message: `You do not have permission to create a draft from the published version of \"${documentId}\".`,\n })\n }\n\n base = processMutations({\n documents: base,\n transactionId,\n mutations: [\n {delete: {id: publishedId}},\n {createIfNotExists: {...(base[publishedId] ?? sourceDoc), _id: draftId}},\n ],\n timestamp,\n })\n working = processMutations({documents: working, transactionId, mutations, timestamp})\n\n outgoingMutations.push(...mutations)\n outgoingActions.push({\n actionType: 'sanity.action.document.unpublish',\n draftId,\n publishedId,\n })\n return {base, working}\n}\n","import {type Mutation} from '@sanity/types'\nimport {type ExprNode} from 'groq-js'\n\nimport {type Action, type DocumentAction} from '../actions'\nimport {type Grant} from '../permissions'\nimport {type DocumentSet} from '../processMutations'\nimport {type HttpAction} from '../reducers'\nimport {handleCreate} from './create'\nimport {handleDelete} from './delete'\nimport {handleDiscard} from './discard'\nimport {handleEdit} from './edit'\nimport {handlePublish} from './publish'\nimport {handleReleaseArchive, handleReleaseUnarchive} from './releaseArchive'\nimport {handleReleaseCreate} from './releaseCreate'\nimport {handleReleaseDelete} from './releaseDelete'\nimport {handleReleaseEdit} from './releaseEdit'\nimport {handleReleasePublish} from './releasePublish'\nimport {handleReleaseSchedule, handleReleaseUnschedule} from './releaseSchedule'\nimport {isReleaseAction} from './releaseUtil'\nimport {\n ActionError,\n type ActionHandlerContext,\n type ActionHandlerResult,\n PermissionActionError,\n} from './shared'\nimport {handleUnpublish} from './unpublish'\n\nexport {ActionError, PermissionActionError}\n\ninterface ProcessActionsOptions {\n /**\n * The ID of this transaction. This will become the resulting `_rev` for all\n * documents affected by changes derived from the current set of actions.\n */\n transactionId: string\n\n /**\n * The actions to apply to the given documents\n */\n actions: Action[]\n\n /**\n * The set of documents these actions were intended to be applied to. These\n * set of documents should be captured right before a queued action is\n * applied.\n */\n base: DocumentSet\n\n /**\n * The current \"working\" set of documents. A patch will be created by applying\n * the actions to the base. This patch will then be applied to the working\n * set for conflict resolution. Initially, this value should match the base\n * set.\n */\n working: DocumentSet\n\n /**\n * The timestamp to use for `_updateAt` and other similar timestamps for this\n * transaction\n */\n timestamp: string\n\n /**\n * the lookup with pre-parsed GROQ expressions\n */\n grants: Record<Grant, ExprNode>\n\n /**\n * The current user's ID, passed to GROQ as the value of `identity()` when\n * evaluating ACL filters. Optional because the user may not have loaded yet;\n * filters that reference `identity()` will evaluate to null in that case.\n */\n identity?: string\n\n // // TODO: implement initial values from the schema?\n // initialValues?: {[TDocumentType in string]?: {_type: string}}\n}\n\ninterface ProcessActionsResult {\n /**\n * The resulting document set after the actions have been applied. This is\n * derived from the working documents.\n */\n working: DocumentSet\n /**\n * The document set before the actions have been applied. This is simply the\n * input of the `working` document set.\n */\n previous: DocumentSet\n /**\n * The outgoing action that were collected when applying the actions. These\n * are sent to the Actions HTTP API\n */\n outgoingActions: HttpAction[]\n /**\n * The outgoing mutations that were collected when applying the actions. These\n * are here for debugging purposes.\n */\n outgoingMutations: Mutation[]\n /**\n * The previous revisions of the given documents before the actions were applied.\n */\n previousRevs: {[TDocumentId in string]?: string}\n}\n\n/**\n * Applies the given set of actions to the working set of documents and converts\n * high-level actions into lower-level outgoing mutations/actions that respect\n * the current state of the working documents.\n *\n * Supports a \"base\" and \"working\" set of documents to allow actions to be\n * applied on top of a different working set of documents in a 3-way merge\n *\n * Actions are applied to the base set of documents first. The difference\n * between the base before and after is used to create a patch. This patch is\n * then applied to the working set of documents and is set as the outgoing patch\n * sent to the server.\n */\nexport function processActions({\n actions,\n transactionId,\n working: initialWorking,\n base: initialBase,\n timestamp,\n grants,\n identity,\n}: ProcessActionsOptions): ProcessActionsResult {\n let base: DocumentSet = {...initialBase}\n let working: DocumentSet = {...initialWorking}\n\n const outgoingActions: HttpAction[] = []\n const outgoingMutations: Mutation[] = []\n\n // liveEdit document actions go to the mutations API, since the actions API\n // requires a draft+published pair. Mixing them with anything else in the same\n // transaction would silently lose atomicity for the non-liveEdit operations,\n // so require users to split the transaction.\n // (Note that the reducers already does this for us -- you'd have to try hard to mix them.)\n const liveEditAction = actions.find((action) => !isReleaseAction(action) && action.liveEdit) as\n | DocumentAction\n | undefined\n const otherAction = actions.find((action) => isReleaseAction(action) || !action.liveEdit)\n if (liveEditAction && otherAction) {\n throw new ActionError({\n documentId: liveEditAction.documentId!,\n transactionId,\n message:\n 'Cannot combine liveEdit document actions with other actions in the same transaction. Submit them as separate transactions.',\n })\n }\n\n for (const action of actions) {\n const result = dispatch(action, {\n base,\n working,\n transactionId,\n timestamp,\n grants,\n identity,\n outgoingActions,\n outgoingMutations,\n })\n base = result.base\n working = result.working\n }\n\n const previousRevs = Object.fromEntries(\n Object.entries(initialWorking).map(([id, doc]) => [id, doc?._rev]),\n )\n\n return {\n working,\n outgoingActions,\n outgoingMutations,\n previous: initialWorking,\n previousRevs,\n }\n}\n\nfunction dispatch(action: Action, ctx: ActionHandlerContext): ActionHandlerResult {\n switch (action.type) {\n case 'document.create':\n return handleCreate(action, ctx)\n case 'document.delete':\n return handleDelete(action, ctx)\n case 'document.discard':\n return handleDiscard(action, ctx)\n case 'document.edit':\n return handleEdit(action, ctx)\n case 'document.publish':\n return handlePublish(action, ctx)\n case 'document.unpublish':\n return handleUnpublish(action, ctx)\n case 'release.create':\n return handleReleaseCreate(action, ctx)\n case 'release.edit':\n return handleReleaseEdit(action, ctx)\n case 'release.publish':\n return handleReleasePublish(action, ctx)\n case 'release.schedule':\n return handleReleaseSchedule(action, ctx)\n case 'release.unschedule':\n return handleReleaseUnschedule(action, ctx)\n case 'release.archive':\n return handleReleaseArchive(action, ctx)\n case 'release.unarchive':\n return handleReleaseUnarchive(action, ctx)\n case 'release.delete':\n return handleReleaseDelete(action, ctx)\n default:\n throw new Error(\n `Unknown action type: \"${\n // @ts-expect-error invalid input\n action.type\n }\". Please contact support if this issue persists.`,\n )\n }\n}\n","import {DocumentId, getDraftId, getPublishedId, getVersionId} from '@sanity/id-utils'\nimport {type Mutation, type PatchOperations, type SanityDocumentLike} from '@sanity/types'\n\nimport {type DocumentHandle} from '../config/sanityConfig'\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\nimport {type StoreContext} from '../store/defineStore'\nimport {insecureRandomId} from '../utils/ids'\nimport {isDeepEqual, omitProperty} from '../utils/object'\nimport {setCleanupTimeout} from '../utils/setCleanupTimeout'\nimport {type Action} from './actions'\nimport {DOCUMENT_STATE_CLEAR_DELAY} from './documentConstants'\nimport {type DocumentState, type DocumentStoreState} from './documentStore'\nimport {type RemoteDocument} from './listen'\nimport {ActionError, processActions} from './processActions/processActions'\nimport {getReleaseDocumentId, isReleaseAction} from './processActions/releaseUtil'\nimport {type DocumentSet} from './processMutations'\n\nconst EMPTY_REVISIONS: NonNullable<Required<DocumentState['unverifiedRevisions']>> = {}\n\n/**\n * How many of this client's own transaction IDs to remember per document for\n * `remote-patches` origin labeling. Sized to comfortably outlast the window\n * between submitting a transaction and observing its listener echo.\n */\nconst MAX_RECENT_OWN_TRANSACTION_IDS = 50\n\nexport type SyncTransactionState = Pick<\n DocumentStoreState,\n 'queued' | 'applied' | 'documentStates' | 'outgoing' | 'grants' | 'identity'\n>\n\ntype DocumentHandleLike = Pick<DocumentHandle, 'perspective'> & {\n documentId?: string\n liveEdit?: boolean\n}\n\ntype ActionMap = {\n create: 'sanity.action.document.version.create'\n discard: 'sanity.action.document.version.discard'\n unpublish: 'sanity.action.document.unpublish'\n delete: 'sanity.action.document.delete'\n edit: 'sanity.action.document.edit'\n publish: 'sanity.action.document.publish'\n releaseCreate: 'sanity.action.release.create'\n releaseEdit: 'sanity.action.release.edit'\n releasePublish: 'sanity.action.release.publish'\n releaseSchedule: 'sanity.action.release.schedule'\n releaseUnschedule: 'sanity.action.release.unschedule'\n releaseArchive: 'sanity.action.release.archive'\n releaseUnarchive: 'sanity.action.release.unarchive'\n releaseDelete: 'sanity.action.release.delete'\n}\n\ntype OptimisticLock = {\n ifDraftRevisionId?: string\n ifPublishedRevisionId?: string\n}\n\ninterface ReleaseMetadataPayload {\n title?: string\n description?: string\n intendedPublishAt?: string\n releaseType?: 'asap' | 'scheduled' | 'undecided'\n cardinality?: 'one' | 'many'\n}\n\nexport type HttpAction =\n | {actionType: ActionMap['create']; publishedId: string; attributes: SanityDocumentLike}\n | {actionType: ActionMap['discard']; versionId: string; purge?: boolean}\n | {actionType: ActionMap['unpublish']; draftId: string; publishedId: string}\n | {actionType: ActionMap['delete']; publishedId: string; includeDrafts?: string[]}\n | {actionType: ActionMap['edit']; draftId: string; publishedId: string; patch: PatchOperations}\n | ({actionType: ActionMap['publish']; draftId: string; publishedId: string} & OptimisticLock)\n | {\n actionType: ActionMap['releaseCreate']\n releaseId: string\n metadata?: ReleaseMetadataPayload\n }\n | {actionType: ActionMap['releaseEdit']; releaseId: string; patch: PatchOperations}\n | {actionType: ActionMap['releasePublish']; releaseId: string}\n | {actionType: ActionMap['releaseSchedule']; releaseId: string; publishAt: string}\n | {actionType: ActionMap['releaseUnschedule']; releaseId: string}\n | {actionType: ActionMap['releaseArchive']; releaseId: string}\n | {actionType: ActionMap['releaseUnarchive']; releaseId: string}\n | {actionType: ActionMap['releaseDelete']; releaseId: string}\n\n/**\n * Represents a transaction that is queued to be applied but has not yet been\n * applied. A transaction will remain in a queued state until all required\n * documents for the transactions are available locally.\n */\nexport interface QueuedTransaction {\n /**\n * the ID of this transaction. this is generated client-side.\n */\n transactionId: string\n /**\n * the high-level actions associated with this transaction. note that these\n * actions don't mention draft IDs and is meant to abstract away the draft\n * model from users.\n */\n actions: Action[]\n /**\n * An optional flag set to disable this transaction from being batched with\n * other transactions.\n */\n disableBatching?: boolean\n}\n\n/**\n * Represents a transaction that has been applied locally but has not been\n * committed/transitioned-to-outgoing. These transactions are visible to the\n * user but may be rebased upon a new working document set. Applied transactions\n * also contain the resulting `outgoingActions` that will be submitted to\n * Content Lake. These `outgoingActions` depend on the state of the working\n * documents so they are recomputed on rebase and are only relevant to applied\n * actions (we cannot compute `outgoingActions` for queued transactions because\n * we haven't resolved the set of documents the actions are dependent on yet).\n *\n * In order to support better conflict resolution, the original `previous` set\n * is saved as the `base` set.\n */\nexport interface AppliedTransaction extends QueuedTransaction {\n /**\n * the resulting set of documents after the actions have been applied\n */\n working: DocumentSet\n\n /**\n * the previous set of documents before the action was applied\n */\n previous: DocumentSet\n\n /**\n * the original `previous` document set captured when this action was\n * originally applied. this is used as a reference point to do a 3-way merge\n * if this applied transaction ever needs to be reapplied on a different\n * set of documents.\n */\n base: DocumentSet\n\n /**\n * the `_rev`s from `previous` document set\n */\n previousRevs: {[TDocumentId in string]?: string}\n\n /**\n * a timestamp for when this transaction was applied locally\n */\n timestamp: string\n\n /**\n * the resulting HTTP actions derived from the state of the `working` document\n * set. these are sent to Content Lake as-is when this transaction is batched\n * and transitioned into an outgoing transaction.\n */\n outgoingActions: HttpAction[]\n\n /**\n * similar to `outgoingActions` but comprised of mutations instead of actions.\n * Useful for debugging, and is also used by liveEdit documents to send mutations,\n * since they can't use the Actions API which is pretty dependent on the draft model.\n */\n outgoingMutations: Mutation[]\n}\n\n/**\n * Represents a set of applied transactions batched into a single outgoing\n * transaction. An outgoing transaction is the result of batching many applied\n * actions. An outgoing transaction may be reverted locally if the server\n * does not accept it.\n */\nexport interface OutgoingTransaction extends AppliedTransaction {\n disableBatching: boolean\n batchedTransactionIds: string[]\n}\n\nexport interface UnverifiedDocumentRevision {\n transactionId: string\n documentId: string\n previousRev: string | undefined\n timestamp: string\n}\n\nexport function queueTransaction(\n prev: SyncTransactionState,\n transaction: QueuedTransaction,\n): SyncTransactionState {\n const {transactionId, actions} = transaction\n const prevWithSubscriptionIds = getDocumentIdsFromHandleLikes(actions).reduce(\n (acc, id) => addSubscriptionIdToDocument(acc, id, transactionId),\n prev,\n )\n\n return {\n ...prevWithSubscriptionIds,\n queued: [...prev.queued, transaction],\n }\n}\n\nexport function removeQueuedTransaction(\n prev: SyncTransactionState,\n transactionId: string,\n): SyncTransactionState {\n const transaction = prev.queued.find((t) => t.transactionId === transactionId)\n if (!transaction) return prev\n\n const prevWithSubscriptionIds = getDocumentIdsFromHandleLikes(transaction.actions).reduce(\n (acc, id) => removeSubscriptionIdFromDocument(acc, id, transactionId),\n prev,\n )\n\n return {\n ...prevWithSubscriptionIds,\n queued: prev.queued.filter((t) => transactionId !== t.transactionId),\n }\n}\n\nexport function applyFirstQueuedTransaction(prev: SyncTransactionState): SyncTransactionState {\n const queued = prev.queued.at(0)\n if (!queued) return prev\n if (!prev.grants) return prev\n\n const ids = getDocumentIdsFromHandleLikes(queued.actions)\n // the local value is only ever `undefined` if it has not been loaded yet\n // we can't get the next applied state unless all relevant documents are ready\n if (ids.some((id) => prev.documentStates[id]?.local === undefined)) return prev\n\n const working = ids.reduce<DocumentSet>((acc, id) => {\n acc[id] = prev.documentStates[id]?.local\n return acc\n }, {})\n\n const timestamp = new Date().toISOString()\n\n const result = processActions({\n ...queued,\n working,\n base: working,\n timestamp,\n grants: prev.grants,\n identity: prev.identity,\n })\n const applied: AppliedTransaction = {\n ...queued,\n ...result,\n base: result.previous,\n timestamp,\n }\n\n return {\n ...prev,\n applied: [...prev.applied, applied],\n queued: prev.queued.filter((t) => t.transactionId !== queued.transactionId),\n documentStates: Object.entries(result.working).reduce(\n (acc, [id, next]) => {\n const prevDoc = acc[id]\n if (!prevDoc) return acc\n acc[id] = {...prevDoc, local: next}\n return acc\n },\n {...prev.documentStates},\n ),\n }\n}\n\nexport function batchAppliedTransactions([curr, ...rest]: AppliedTransaction[]):\n | OutgoingTransaction\n | undefined {\n // No transactions? Nothing to batch.\n if (!curr) return undefined\n\n // Skip transactions with no actions.\n if (!curr.actions.length) return batchAppliedTransactions(rest)\n\n // If there are multiple actions, we cannot batch further.\n if (curr.actions.length > 1) {\n return {\n ...curr,\n disableBatching: true,\n batchedTransactionIds: [curr.transactionId],\n }\n }\n\n const [action] = curr.actions\n\n // If the single action isn't a document.edit or batching is disabled,\n // mark this transaction as non-batchable.\n if (action.type !== 'document.edit' || curr.disableBatching) {\n return {\n ...curr,\n disableBatching: true,\n batchedTransactionIds: [curr.transactionId],\n }\n }\n\n // Create an outgoing transaction for the single edit action.\n // At this point, batching is allowed.\n const editAction: OutgoingTransaction = {\n ...curr,\n actions: [action],\n disableBatching: false,\n batchedTransactionIds: [curr.transactionId],\n }\n if (!rest.length) return editAction\n\n const next = batchAppliedTransactions(rest)\n if (!next) return undefined\n if (next.disableBatching) return editAction\n\n // Don't batch a liveEdit edit with a non-liveEdit edit — they route to different APIs\n const nextFirst = next.actions[0]\n const nextLiveEdit = nextFirst && 'liveEdit' in nextFirst ? nextFirst.liveEdit : false\n if (!!action.liveEdit !== !!nextLiveEdit) return editAction\n\n return {\n disableBatching: false,\n // Use the transactionId from the later (next) transaction.\n transactionId: next.transactionId,\n // Accumulate actions: current action first, then later ones.\n actions: [action, ...next.actions],\n // Merge outgoingActions in order.\n outgoingActions: [...curr.outgoingActions, ...next.outgoingActions],\n // Batched transaction IDs: preserve order by placing curr first.\n batchedTransactionIds: [curr.transactionId, ...next.batchedTransactionIds],\n // Merge outgoingMutations in order.\n outgoingMutations: [...curr.outgoingMutations, ...next.outgoingMutations],\n // Working state reflects the latest optimistic changes: later transactions override earlier.\n working: {...curr.working, ...next.working},\n // Base state (base, previous, previousRevs) must reflect the original state.\n // Use curr values (the earliest transaction) to override later ones.\n previousRevs: {...next.previousRevs, ...curr.previousRevs},\n previous: {...next.previous, ...curr.previous},\n base: {...next.base, ...curr.base},\n // Use the earliest timestamp from curr.\n timestamp: curr.timestamp ?? next.timestamp,\n }\n}\n\nexport function transitionAppliedTransactionsToOutgoing(\n prev: SyncTransactionState,\n): SyncTransactionState {\n if (prev.outgoing) return prev\n\n const transaction = batchAppliedTransactions(prev.applied)\n if (!transaction) return prev\n\n const {\n transactionId,\n previousRevs,\n working,\n batchedTransactionIds: consumedTransactions,\n } = transaction\n const timestamp = new Date().toISOString()\n\n return {\n ...prev,\n outgoing: transaction,\n applied: prev.applied.filter((i) => !consumedTransactions.includes(i.transactionId)),\n documentStates: Object.entries(previousRevs).reduce(\n (acc, [documentId, previousRev]) => {\n if (working[documentId]?._rev === previousRev) return acc\n\n const documentState = prev.documentStates[documentId]\n if (!documentState) return acc\n\n acc[documentId] = {\n ...documentState,\n unverifiedRevisions: {\n ...documentState.unverifiedRevisions,\n // add unverified revision\n [transactionId]: {documentId, previousRev, transactionId, timestamp},\n },\n // also track the transaction ID durably (unverified revisions can be\n // pruned by sync events before the listener echo arrives) so\n // `remote-patches` events label our own transactions correctly\n recentOwnTransactionIds: [\n ...(documentState.recentOwnTransactionIds ?? []).slice(\n -(MAX_RECENT_OWN_TRANSACTION_IDS - 1),\n ),\n transactionId,\n ],\n }\n\n return acc\n },\n {...prev.documentStates},\n ),\n }\n}\n\nexport function cleanupOutgoingTransaction(prev: SyncTransactionState): SyncTransactionState {\n const {outgoing} = prev\n if (!outgoing) return prev\n\n let next = prev\n const ids = getDocumentIdsFromHandleLikes(outgoing.actions)\n for (const transactionId of outgoing.batchedTransactionIds) {\n for (const documentId of ids) {\n next = removeSubscriptionIdFromDocument(next, documentId, transactionId)\n }\n }\n\n return {...next, outgoing: undefined}\n}\n\nexport function revertOutgoingTransaction(prev: SyncTransactionState): SyncTransactionState {\n if (!prev.grants) return prev\n\n // unregister the reverted batch's transaction-held subscriptions, symmetric\n // with `cleanupOutgoingTransaction` on ack and `removeQueuedTransaction` on\n // apply failure. without this, a reverted document's subscription IDs are\n // never released and it can never be evicted\n let base = prev\n if (prev.outgoing) {\n const ids = getDocumentIdsFromHandleLikes(prev.outgoing.actions)\n for (const transactionId of prev.outgoing.batchedTransactionIds) {\n for (const documentId of ids) {\n base = removeSubscriptionIdFromDocument(base, documentId, transactionId)\n }\n }\n }\n\n let working = Object.fromEntries(\n Object.entries(base.documentStates).map(([documentId, documentState]) => [\n documentId,\n documentState?.remote,\n ]),\n )\n const nextApplied: AppliedTransaction[] = []\n\n for (const t of prev.applied) {\n try {\n const next = processActions({...t, working, grants: prev.grants, identity: prev.identity})\n working = next.working\n nextApplied.push({...t, ...next})\n } catch (error) {\n // if we're already reverting a transaction, skip any applied actions if\n // they throw while we rebuild the state\n if (error instanceof ActionError) continue\n throw error\n }\n }\n\n return {\n ...base,\n applied: nextApplied,\n outgoing: undefined,\n documentStates: Object.fromEntries(\n Object.entries(base.documentStates)\n .filter((e): e is [string, DocumentState] => !!e[1])\n .map(([documentId, {unverifiedRevisions = {}, local, ...documentState}]) => {\n const next: DocumentState = {\n ...documentState,\n local: documentId in working ? working[documentId] : local,\n unverifiedRevisions:\n prev.outgoing && prev.outgoing.transactionId in unverifiedRevisions\n ? omitProperty(unverifiedRevisions, prev.outgoing.transactionId)\n : unverifiedRevisions,\n }\n return [documentId, next] as const\n }),\n ),\n }\n}\n\n/**\n * Extracts the patch operations addressed to the given document from a set of\n * raw listener mutations, stripping the mutation-level `id` addressing so the\n * patches are rooted at the document. A transaction can carry mutations for\n * other documents, so anything not explicitly id-addressed to this document\n * (including query-addressed patches) is dropped.\n */\nfunction extractPatchOperations(\n mutations: Mutation[] | undefined,\n documentId: string,\n): PatchOperations[] {\n if (!mutations) return []\n return mutations.flatMap((mutation) => {\n if (!('patch' in mutation) || !mutation.patch) return []\n const {id, ...operations} = mutation.patch as PatchOperations & {id?: string}\n if (id !== documentId) return []\n return [operations]\n })\n}\n\nexport function applyRemoteDocument(\n prev: SyncTransactionState,\n {document, documentId, previousRev, revision, timestamp, type, mutations}: RemoteDocument,\n events: DocumentStoreState['events'],\n): SyncTransactionState {\n if (!prev.grants) return prev\n const prevDocState = prev.documentStates[documentId]\n\n // document state is deleted when there are no more subscribers so we can\n // simply skip if there is no state\n if (!prevDocState) return prev\n\n // we send out transactions with IDs generated client-side to identify them\n // when they are observed through the listener. here we can check if this\n // incoming remote document is the result of one of our transactions\n const prevUnverifiedRevisions = prevDocState.unverifiedRevisions\n const revisionToVerify = revision ? prevUnverifiedRevisions?.[revision] : undefined\n let unverifiedRevisions = prevUnverifiedRevisions ?? EMPTY_REVISIONS\n if (revision && revisionToVerify) {\n unverifiedRevisions = omitProperty(prevUnverifiedRevisions, revision)\n }\n\n // surface the operational patches from this transaction before they are\n // collapsed into the whole-document snapshot below. consumers that keep\n // their own state (e.g. collaborative text editors) rely on these to apply\n // remote changes without re-diffing document snapshots\n if (type === 'mutation' && revision) {\n const patches = extractPatchOperations(mutations, documentId)\n if (patches.length) {\n // `unverifiedRevisions` alone isn't a reliable origin marker: a sync\n // event can prune an in-flight transaction's entry before its listener\n // echo arrives. `recentOwnTransactionIds` survives that race\n const isOwnTransaction =\n Boolean(revisionToVerify) ||\n (prevDocState.recentOwnTransactionIds?.includes(revision) ?? false)\n events.next({\n type: 'remote-patches',\n documentId,\n transactionId: revision,\n previousRev,\n timestamp,\n patches,\n origin: isOwnTransaction ? 'local' : 'remote',\n })\n }\n }\n\n // if this remote document is from a `'sync'` event (meaning that the whole\n // thing was just fetched and not re-created from mutations)\n if (type === 'sync') {\n // then remove unverified revisions that are older than our sync time. we\n // don't need to verify them for a rebase any more because we synced and\n // grabbed the latest document\n unverifiedRevisions = Object.fromEntries(\n Object.entries(unverifiedRevisions).filter(([, unverifiedRevision]) => {\n if (!unverifiedRevision) return false\n return new Date(timestamp).getTime() <= new Date(unverifiedRevision.timestamp).getTime()\n }),\n )\n }\n\n // if there is a revision to verify and the previous revision from remote\n // matches the previous revision we expected, we can \"fast-forward\" and skip\n // rebasing local changes on top of this new base\n if (revisionToVerify && revisionToVerify.previousRev === previousRev) {\n // even on a clean fast-forward, the server's result can differ from our\n // optimistic prediction: a publish derives the published content from the\n // server's copy of the draft, which may carry concurrent edits our\n // prediction never saw. once nothing else is pending locally for this\n // document (no applied transaction and no in-flight transaction, other\n // than the one this event just confirmed, modifies it), converge `local`\n // to the server's document. while local work that modifies this document\n // is pending, keep the optimistic `local` so those changes stay visible;\n // that work's own echo (or rebase) recomputes `local` later.\n //\n // \"modifies\" matters: pending work on other documents must not block\n // convergence here (nothing would ever revisit this document's `local`),\n // and a pending draft edit carries the published document in its working\n // set without changing it, so a presence check would block published-doc\n // convergence whenever a draft edit is pending. this is the same\n // modified-test `transitionAppliedTransactionsToOutgoing` uses\n const modifiesDocument = (transaction: AppliedTransaction) =>\n transaction.working[documentId]?._rev !== transaction.previousRevs[documentId]\n const nothingElsePending =\n !prev.applied.some(modifiesDocument) &&\n (!prev.outgoing ||\n prev.outgoing.transactionId === revision ||\n !modifiesDocument(prev.outgoing))\n const local =\n nothingElsePending && !isDeepEqual(prevDocState.local, document)\n ? document\n : prevDocState.local\n\n return {\n ...prev,\n documentStates: {\n ...prev.documentStates,\n [documentId]: {\n ...prevDocState,\n remote: document,\n remoteRev: revision,\n local,\n unverifiedRevisions,\n },\n },\n }\n }\n\n // if we got this far, this means that we could not fast-forward this revision\n // for this document. now we can rebase our local changes (if any) on top of\n // this new base from remote. in order to do that we grab the set of documents\n // captured before the earliest local transaction\n const previous = prev.applied.at(0)?.previous\n // our initial working set now is the state of the documents before any of our\n // local transactions plus the newly updated document from remote\n let working = {...previous, [documentId]: document}\n const nextApplied: AppliedTransaction[] = []\n\n // now we can iterate through our applied (but not yet committed) transactions\n // starting with the updated working set and re-apply each transaction in\n // order creating a new set of applied transactions as we go.\n //\n // NOTE: we don't want to rebase over the outgoing transaction because that\n // transaction is already on its way to the server. if an outgoing transaction\n // needs to be rebased, then it eventually will be when we see that\n // transaction again through the listener and this same flow will run then\n for (const curr of prev.applied) {\n try {\n const next = processActions({...curr, working, grants: prev.grants, identity: prev.identity})\n working = next.working\n // next includes an updated `previous` set and `working` set and updates\n // the `outgoingAction` and `outgoingMutations`. the `base` set from the\n // original applied transaction gets put back into the updated transaction\n // as-is to preserve the intended base for a 3-way merge\n nextApplied.push({...curr, ...next})\n } catch (error) {\n // if processing the action ever throws a related error, we can skip this\n // local transaction and report the error to the user\n if (error instanceof ActionError) {\n events.next({\n type: 'rebase-error',\n transactionId: error.transactionId,\n documentId: error.documentId,\n message: error.message,\n error,\n })\n continue\n }\n throw error\n }\n }\n\n // when the recompute lands on a value deep-equal to the current local\n // (the common case for echoes of our own transactions), keep the previous\n // reference so subscribers don't re-render for an identical value\n const nextLocal = working[documentId]\n const local = isDeepEqual(prevDocState.local, nextLocal) ? prevDocState.local : nextLocal\n\n return {\n ...prev,\n applied: nextApplied,\n documentStates: {\n ...prev.documentStates,\n [documentId]: {\n ...prevDocState,\n remote: document,\n remoteRev: revision,\n local,\n unverifiedRevisions,\n },\n },\n }\n}\n\nexport function addSubscriptionIdToDocument(\n prev: SyncTransactionState,\n documentId: string,\n subscriptionId: string,\n): SyncTransactionState {\n const prevDocState = prev.documentStates?.[documentId]\n const prevSubscriptions = prevDocState?.subscriptions ?? []\n\n return {\n ...prev,\n documentStates: {\n ...prev.documentStates,\n [documentId]: {\n ...prevDocState,\n id: documentId,\n subscriptions: [...prevSubscriptions, subscriptionId],\n },\n },\n }\n}\n\nexport function removeSubscriptionIdFromDocument(\n prev: SyncTransactionState,\n documentId: string,\n subscriptionId: string,\n): SyncTransactionState {\n const prevDocState = prev.documentStates?.[documentId]\n const prevSubscriptions = prevDocState?.subscriptions ?? []\n const subscriptions = prevSubscriptions.filter((id) => id !== subscriptionId)\n\n if (!prevDocState) return prev\n if (!subscriptions.length) {\n return {...prev, documentStates: omitProperty(prev.documentStates, documentId)}\n }\n return {\n ...prev,\n documentStates: {\n ...prev.documentStates,\n [documentId]: {...prevDocState, subscriptions: subscriptions},\n },\n }\n}\n\nexport function manageSubscriberIds(\n {state}: StoreContext<SyncTransactionState>,\n handles: DocumentHandleLike[],\n): () => void {\n const documentIds = getDocumentIdsFromHandleLikes(handles)\n\n const subscriptionId = insecureRandomId()\n state.set('addSubscribers', (prev) =>\n documentIds.reduce(\n (acc, id) => addSubscriptionIdToDocument(acc, id, subscriptionId),\n prev as SyncTransactionState,\n ),\n )\n\n return () => {\n setCleanupTimeout(() => {\n state.set('removeSubscribers', (prev) =>\n documentIds.reduce(\n (acc, id) => removeSubscriptionIdFromDocument(acc, id, subscriptionId),\n prev as SyncTransactionState,\n ),\n )\n }, DOCUMENT_STATE_CLEAR_DELAY)\n }\n}\n\n// document handles are passed in via the public facing API, but we also need to\n// pull the correct document ids from action bodies, which have similar but not\n// identical shapes to the document handles. release actions also flow through\n// here, and resolve to the underlying release document id.\nfunction getDocumentIdsFromHandleLikes(handles: (DocumentHandleLike | Action)[]): string[] {\n return handles.flatMap((handle) => {\n if ('type' in handle && isReleaseAction(handle)) {\n return [getReleaseDocumentId(handle.releaseId)]\n }\n const idsForDocument = []\n if (!handle.documentId) return []\n if (handle.liveEdit) {\n return [handle.documentId]\n }\n if (isReleasePerspective(handle.perspective)) {\n idsForDocument.push(\n getVersionId(DocumentId(handle.documentId), handle.perspective.releaseName),\n )\n }\n idsForDocument.push(getPublishedId(DocumentId(handle.documentId)))\n idsForDocument.push(getDraftId(DocumentId(handle.documentId)))\n return idsForDocument\n })\n}\n","import {type MultipleMutationResult, type SanityClient} from '@sanity/client'\nimport {type PatchOperations} from '@sanity/types'\n\nimport {type DocumentAction, type ReleaseAction} from './actions'\nimport {getReleaseDocumentId, isReleaseAction} from './processActions/releaseUtil'\nimport {type OutgoingTransaction} from './reducers'\n\n/** @beta Response body from submitting an outgoing transaction (actions or mutations API). */\nexport type DocumentTransactionSubmissionResult =\n | Awaited<ReturnType<SanityClient['action']>>\n | MultipleMutationResult\n\n/** @beta */\nexport type DocumentEvent =\n | ActionErrorEvent\n | TransactionRevertedEvent\n | TransactionAcceptedEvent\n | DocumentRebaseErrorEvent\n | DocumentEditedEvent\n | DocumentCreatedEvent\n | DocumentDeletedEvent\n | DocumentPublishedEvent\n | DocumentUnpublishedEvent\n | DocumentDiscardedEvent\n | DocumentRemotePatchesEvent\n\n/**\n * @beta\n * Event emitted when a precondition to applying an action fails.\n * (For example: when trying to edit a document that no longer exists.)\n */\nexport interface ActionErrorEvent {\n type: 'error'\n documentId: string\n transactionId: string\n message: string\n error: unknown\n}\n/**\n * @beta\n * Event emitted when a transaction is accepted.\n */\nexport interface TransactionAcceptedEvent {\n type: 'accepted'\n outgoing: OutgoingTransaction\n result: DocumentTransactionSubmissionResult\n}\n/**\n * @beta\n * Event emitted when a transaction is reverted.\n */\nexport interface TransactionRevertedEvent {\n type: 'reverted'\n message: string\n error: unknown\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when an attempt to apply local changes to a modified remote document fails.\n */\nexport interface DocumentRebaseErrorEvent {\n type: 'rebase-error'\n documentId: string\n transactionId: string\n message: string\n error: unknown\n}\n/**\n * @beta\n * Event emitted when a document is edited.\n */\nexport interface DocumentEditedEvent {\n type: 'edited'\n documentId: string\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when a document is created.\n */\nexport interface DocumentCreatedEvent {\n type: 'created'\n documentId: string\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when a document is deleted.\n */\nexport interface DocumentDeletedEvent {\n type: 'deleted'\n documentId: string\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when a document is published.\n */\nexport interface DocumentPublishedEvent {\n type: 'published'\n documentId: string\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when a document is unpublished.\n */\nexport interface DocumentUnpublishedEvent {\n type: 'unpublished'\n documentId: string\n outgoing: OutgoingTransaction\n}\n/**\n * @beta\n * Event emitted when a document version is discarded.\n */\nexport interface DocumentDiscardedEvent {\n type: 'discarded'\n documentId: string\n outgoing: OutgoingTransaction\n}\n\n/**\n * @beta\n * Event emitted when patches for a document are observed through the listener.\n *\n * Unlike the whole-document snapshots the store keeps, these are the raw patch\n * operations from the transaction that produced the change, preserving the\n * operational intent of the edit (e.g. keyed array inserts/unsets). Consumers\n * that maintain their own local state, like collaborative text editors, can\n * apply these directly instead of diffing document snapshots.\n *\n * `origin` is `'local'` when the transaction was submitted by this document\n * store instance (an own edit observed back through the listener) and\n * `'remote'` when it came from another client.\n */\nexport interface DocumentRemotePatchesEvent {\n type: 'remote-patches'\n /** The ID of the document version the patches apply to (e.g. a draft ID). */\n documentId: string\n /** The transaction ID that carried these patches. */\n transactionId: string\n /** The revision the document was at before this transaction. */\n previousRev?: string\n /** The timestamp of the transaction. */\n timestamp: string\n /** The patch operations, rooted at the document. */\n patches: PatchOperations[]\n /** Whether the transaction originated from this client or another one. */\n origin: 'local' | 'remote'\n}\n\n// Release actions that write a mutation to the local release doc map onto\n// the regular per-document events with `documentId = '_.releases.<releaseId>'`.\n// The other release actions (publish/schedule/unschedule/archive/unarchive)\n// don't mutate local state, so they aren't in the map and get skipped — they\n// surface through the transaction-level `accepted`/`reverted` events instead.\nconst actionMap = {\n 'document.create': 'created',\n 'document.delete': 'deleted',\n 'document.discard': 'discarded',\n 'document.edit': 'edited',\n 'document.publish': 'published',\n 'document.unpublish': 'unpublished',\n 'release.create': 'created',\n 'release.edit': 'edited',\n 'release.delete': 'deleted',\n} satisfies Partial<Record<DocumentAction['type'] | ReleaseAction['type'], DocumentEvent['type']>>\n\ntype MappedActionType = keyof typeof actionMap\n\nexport function getDocumentEvents(outgoing: OutgoingTransaction): DocumentEvent[] {\n const documentIdsByAction = outgoing.actions.reduce(\n (acc, action) => {\n if (!(action.type in actionMap)) return acc\n const documentId = isReleaseAction(action)\n ? getReleaseDocumentId(action.releaseId)\n : action.documentId\n if (!documentId) return acc\n const type = action.type as MappedActionType\n const ids = acc[type] ?? new Set<string>()\n ids.add(documentId)\n acc[type] = ids\n return acc\n },\n {} as Partial<Record<MappedActionType, Set<string>>>,\n )\n\n return Object.entries(documentIdsByAction).flatMap(([actionType, documentIds]) =>\n Array.from(documentIds ?? []).map(\n (documentId): DocumentEvent => ({\n type: actionMap[actionType as MappedActionType],\n documentId,\n outgoing,\n }),\n ),\n )\n}\n","import {type ListenEvent, type MutationEvent} from '@sanity/client'\nimport {type SanityDocument} from '@sanity/types'\nimport {defer, filter, type MonoTypeOperatorFunction, Observable} from 'rxjs'\n\nimport {setCleanupTimeout} from '../utils/setCleanupTimeout'\n\nconst DEDUPE_TTL = 120_000\nconst DEDUPE_MAX_ENTRIES = 1_000\n\n/**\n * How long to hold an incomplete multi-document transaction (and the events\n * held behind it) before releasing everything anyway. Only reached when part\n * of a transaction is lost.\n */\nconst GROUP_FLUSH_DEADLINE = 30_000\n\n/**\n * How many intervening events to hold behind an incomplete multi-document\n * transaction before giving up on grouping and releasing everything in\n * arrival order.\n */\nconst GROUP_MAX_HELD_EVENTS = 100\n\ninterface DedupeOptions {\n ttl?: number\n maxEntries?: number\n}\n\n/**\n * Drops mutation events that have already been observed, keyed by\n * `transactionId#documentId`. With `enableResume`, the listener replays\n * missed events after a reconnect on an at-least-once basis, so the same\n * event can be delivered twice. A duplicate would never chain onto the\n * current base revision and would clog the sequencing buffer until it\n * overflows into an `OutOfSyncError`.\n *\n * Seen keys expire after `ttl` milliseconds and the cache is capped at\n * `maxEntries`, evicting the oldest entries first.\n *\n * @internal\n */\nexport function dedupeListenerEvents(\n options?: DedupeOptions,\n): MonoTypeOperatorFunction<ListenEvent<SanityDocument>> {\n const {ttl = DEDUPE_TTL, maxEntries = DEDUPE_MAX_ENTRIES} = options ?? {}\n\n return (source) =>\n defer(() => {\n // insertion-ordered map of dedupe key -> expiry timestamp\n const seen = new Map<string, number>()\n\n return source.pipe(\n filter((event) => {\n if (event.type !== 'mutation') return true\n\n const key = `${event.transactionId}#${event.documentId}`\n const now = Date.now()\n\n const expiry = seen.get(key)\n if (expiry !== undefined && expiry > now) return false\n\n seen.delete(key)\n seen.set(key, now + ttl)\n\n for (const [existingKey, existingExpiry] of seen) {\n if (seen.size <= maxEntries && existingExpiry > now) break\n seen.delete(existingKey)\n }\n\n return true\n }),\n )\n })\n}\n\ninterface GroupTransactionEventsOptions {\n flushDeadline?: number\n maxHeldEvents?: number\n}\n\n/**\n * Buffers the mutation events of multi-document transactions (e.g. a publish\n * touching both the draft and the published document) until every event of\n * the transaction has arrived, then emits them contiguously. Without this,\n * a rebase can run between the two halves of a transaction and observe the\n * dataset in a state that never existed on the server (draft deleted, but\n * published not yet updated).\n *\n * The backend's streaming listener pipeline delivers a transaction's events\n * contiguously and in order, but the legacy pipeline can interleave\n * concurrent transactions. So while a multi-document transaction is\n * incomplete, mutation events from other transactions are held (in arrival\n * order) rather than emitted, and released right after the transaction\n * completes; released events are re-processed so a held multi-document\n * transaction is grouped too. Per-document `previousRev` sequencing\n * downstream tolerates the reordering this introduces.\n *\n * Escape hatches so a lost event degrades to ungrouped delivery instead of\n * stalling the stream: everything is released in arrival order when a\n * non-mutation event (e.g. reconnect/welcome) arrives, when more than\n * `maxHeldEvents` are held, or after `flushDeadline` milliseconds.\n * Single-event transactions pass through untouched when nothing is buffered.\n *\n * @internal\n */\nexport function groupTransactionEvents(\n options?: GroupTransactionEventsOptions,\n): MonoTypeOperatorFunction<ListenEvent<SanityDocument>> {\n const {flushDeadline = GROUP_FLUSH_DEADLINE, maxHeldEvents = GROUP_MAX_HELD_EVENTS} =\n options ?? {}\n\n return (source) =>\n new Observable<ListenEvent<SanityDocument>>((subscriber) => {\n interface OpenTransaction {\n transactionId: string\n events: MutationEvent[]\n total: number\n timer: ReturnType<typeof setTimeout>\n }\n\n let open: OpenTransaction | null = null\n let held: MutationEvent[] = []\n\n // emits the open transaction's events (complete or not) without\n // releasing the held queue; callers decide what happens to `held`\n const closeOpen = () => {\n if (!open) return\n clearTimeout(open.timer)\n const {events} = open\n open = null\n for (const event of events) subscriber.next(event)\n }\n\n // re-processes the held queue so a held multi-document transaction\n // gets grouped in turn. processing may open a new transaction and top\n // up a new held queue; each drain only touches its own snapshot, so\n // this terminates\n const releaseHeld = () => {\n const queue = held\n held = []\n for (const event of queue) processEvent(event)\n }\n\n const releaseEverything = () => {\n closeOpen()\n const queue = held\n held = []\n for (const event of queue) subscriber.next(event)\n }\n\n const processEvent = (event: ListenEvent<SanityDocument>) => {\n if (event.type !== 'mutation') {\n // connection-level events (welcome/welcomeback/reset/reconnect)\n // reset the world downstream; release everything before them\n releaseEverything()\n subscriber.next(event)\n return\n }\n\n const isMultiDocument = (event.transactionTotalEvents ?? 0) > 1\n\n if (!open) {\n if (!isMultiDocument) {\n subscriber.next(event)\n return\n }\n // isMultiDocument guarantees total >= 2, so a freshly opened\n // transaction is always incomplete; completion is checked when\n // subsequent events of the same transaction arrive below\n open = {\n transactionId: event.transactionId,\n events: [event],\n total: event.transactionTotalEvents,\n timer: setCleanupTimeout(() => {\n closeOpen()\n releaseHeld()\n }, flushDeadline),\n }\n return\n }\n\n if (event.transactionId === open.transactionId) {\n open.events.push(event)\n if (open.events.length >= open.total) {\n closeOpen()\n releaseHeld()\n }\n return\n }\n\n // an event from another transaction while one is incomplete: hold it\n // (legacy listener pipeline interleaving) instead of giving up on the\n // open transaction\n held.push(event)\n if (held.length > maxHeldEvents) releaseEverything()\n }\n\n const subscription = source.subscribe({\n next: processEvent,\n error: (error) => {\n releaseEverything()\n subscriber.error(error)\n },\n complete: () => {\n releaseEverything()\n subscriber.complete()\n },\n })\n\n return () => {\n if (open) clearTimeout(open.timer)\n open = null\n held = []\n subscription.unsubscribe()\n }\n })\n}\n","import {type ListenEvent, type SanityDocument} from '@sanity/client'\nimport {createDocumentLoaderFromClient} from '@sanity/mutate/_unstable_store'\nimport {\n first,\n map,\n merge,\n Observable,\n partition,\n share,\n shareReplay,\n Subject,\n switchMap,\n takeUntil,\n} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {type DocumentResource} from '../config/sanityConfig'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {dedupeListenerEvents, groupTransactionEvents} from './listenerEventOperators'\n\nconst API_VERSION = 'v2025-05-06'\n\nexport interface SharedListener {\n events: Observable<ListenEvent<SanityDocument>>\n dispose: () => void\n}\n\nexport function createSharedListener(\n instance: SanityInstance,\n resource?: DocumentResource,\n): SharedListener {\n const dispose$ = new Subject<void>()\n const events$ = getClientState(instance, {\n apiVersion: API_VERSION,\n resource,\n }).observable.pipe(\n switchMap((client) =>\n // TODO: it seems like the client.listen method is not emitting disconnected\n // events. this is important to ensure we have an up to date version of the\n // doc. probably should introduce our own events for when the user goes offline\n client.listen(\n '*',\n {},\n {\n // with `enableResume`, a reconnect replays the events missed while\n // offline (emitting `welcomeback`) instead of forcing a refetch of\n // every subscribed document. when the backend cannot resume, it\n // emits `welcome` or `reset`, both of which trigger a refetch\n events: ['mutation', 'welcome', 'welcomeback', 'reconnect', 'reset'],\n enableResume: true,\n includeResult: false,\n // the document store handles version documents, so we need to include all versions\n includeAllVersions: true,\n tag: 'document-listener',\n // // from manual testing, it seems like mendoza patches may be\n // // causing some ambiguity/wonkiness\n // includeMutations: false,\n // effectFormat: 'mendoza',\n },\n ),\n ),\n // resumed events are delivered at-least-once, so drop replayed duplicates\n dedupeListenerEvents(),\n // hold multi-document transactions (e.g. publish) until complete so\n // per-document processing never observes half a transaction\n groupTransactionEvents(),\n takeUntil(dispose$),\n share(),\n )\n\n const [welcome$, mutation$] = partition(events$, (e) => e.type === 'welcome')\n\n return {\n events: merge(\n // we replay the welcome event because that event kicks off fetching the document\n welcome$.pipe(shareReplay(1)),\n mutation$,\n ),\n dispose: () => dispose$.next(),\n }\n}\n\nexport function createFetchDocument(instance: SanityInstance, resource?: DocumentResource) {\n return function (documentId: string): Observable<SanityDocument | null> {\n return getClientState(instance, {\n apiVersion: API_VERSION,\n resource,\n }).observable.pipe(\n switchMap((client) => {\n // creates a observable request to the /doc/{documentId} endpoint for a given document id\n // should work across all kinds of document IDs (drafts.**, version.**., etc.)\n const loadDocument = createDocumentLoaderFromClient(client)\n return loadDocument(documentId)\n }),\n map((result) => {\n if (!result.accessible) {\n if (result.reason === 'existence') return null\n throw new Error(`Document with ID \\`${documentId}\\` is inaccessible due to permissions.`)\n }\n return result.document as SanityDocument\n }),\n first(),\n )\n }\n}\n","import {type Action, ClientError, CorsOriginError, type Mutation} from '@sanity/client'\nimport {DocumentId, getDraftId, getPublishedId, getVersionId} from '@sanity/id-utils'\nimport {jsonMatch} from '@sanity/json-match'\nimport {type SanityDocument} from 'groq'\nimport {type ExprNode} from 'groq-js'\nimport {\n catchError,\n concatMap,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n groupBy,\n map,\n mergeMap,\n Observable,\n of,\n pairwise,\n retry,\n startWith,\n Subject,\n switchMap,\n tap,\n throttle,\n throwError,\n timer,\n withLatestFrom,\n} from 'rxjs'\n\nimport {getCurrentUserState} from '../auth/authStore'\nimport {type ClientOptions, getClientState} from '../client/clientStore'\nimport {\n type DocumentHandle,\n type DocumentResource,\n isCanvasResource,\n isDatasetResource,\n isMediaLibraryResource,\n} from '../config/sanityConfig'\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\nimport {\n bindActionByResource,\n type BoundResourceKey,\n type StoreAction,\n} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {createStateSourceAction, type StateSource} from '../store/createStateSourceAction'\nimport {defineStore, type StoreContext} from '../store/defineStore'\nimport {type DocumentAction} from './actions'\nimport {\n ACL_RETRY_BASE_DELAY,\n ACL_RETRY_MAX_DELAY,\n API_VERSION,\n INITIAL_OUTGOING_THROTTLE_TIME,\n OUT_OF_SYNC_RETRY_BASE_DELAY,\n OUT_OF_SYNC_RETRY_MAX_DELAY,\n} from './documentConstants'\nimport {\n type DocumentEvent,\n type DocumentTransactionSubmissionResult,\n getDocumentEvents,\n} from './events'\nimport {listen, OutOfSyncError} from './listen'\nimport {type JsonMatch} from './patchOperations'\nimport {\n calculatePermissions,\n createGrantsLookup,\n type DatasetAcl,\n type DocumentPermissionsResult,\n type Grant,\n} from './permissions'\nimport {ActionError} from './processActions/processActions'\nimport {isReleaseAction} from './processActions/releaseUtil'\nimport {\n type AppliedTransaction,\n applyFirstQueuedTransaction,\n applyRemoteDocument,\n cleanupOutgoingTransaction,\n manageSubscriberIds,\n type OutgoingTransaction,\n type QueuedTransaction,\n removeQueuedTransaction,\n revertOutgoingTransaction,\n transitionAppliedTransactionsToOutgoing,\n type UnverifiedDocumentRevision,\n} from './reducers'\nimport {createFetchDocument, createSharedListener, type SharedListener} from './sharedListener'\n\nexport interface DocumentStoreState {\n documentStates: {[TDocumentId in string]?: DocumentState}\n queued: QueuedTransaction[]\n applied: AppliedTransaction[]\n outgoing?: OutgoingTransaction\n grants?: Record<Grant, ExprNode>\n /**\n * The current user's identity (their user ID).\n */\n identity?: string\n error?: unknown\n sharedListener: SharedListener\n fetchDocument: (documentId: string) => Observable<SanityDocument | null>\n events: Subject<DocumentEvent>\n}\n\nexport interface DocumentState {\n id: string\n /**\n * the \"remote\" local copy that matches the server. represents the last known\n * server state. this gets updated every time we confirm remote patches\n */\n remote?: SanityDocument | null\n /**\n * the current ephemeral working copy that includes local optimistic changes\n * that have not yet been confirmed by the server\n */\n local?: SanityDocument | null\n /**\n * the revision that our remote document is at\n */\n remoteRev?: string | null\n /**\n * Array of subscription IDs. This document state will be deleted if there are\n * no subscribers.\n */\n subscriptions: string[]\n /**\n * An object keyed by transaction ID of revisions sent out but that have not\n * yet been verified yet. When an applied transaction is transitioned to an\n * outgoing transaction, it also adds unverified revisions for each document\n * that is part of that outgoing transaction. Transactions are submitted to\n * the server with a locally generated transaction ID. This way we can observe\n * when our transaction comes back through the shared listener. Each listener\n * event that comes back contains a `previousRev`. If we see our own\n * transaction with a different `previousRev` than expected, we can rebase our\n * local transactions on top of this new remote.\n */\n unverifiedRevisions?: {[TTransactionId in string]?: UnverifiedDocumentRevision}\n /**\n * transaction IDs recently submitted by this client for this document,\n * newest last. used to label `remote-patches` events with the correct\n * `origin` even after the corresponding `unverifiedRevisions` entry has\n * been pruned (e.g. by a sync event that raced the listener echo). capped\n * to the most recent entries.\n */\n recentOwnTransactionIds?: string[]\n}\n\nexport const documentStore = defineStore<DocumentStoreState, BoundResourceKey>({\n name: 'Document',\n getInitialState: (instance, {resource}) => ({\n documentStates: {},\n // these can be emptied on refetch\n queued: [],\n applied: [],\n sharedListener: createSharedListener(instance, resource),\n fetchDocument: createFetchDocument(instance, resource),\n events: new Subject(),\n }),\n initialize(context) {\n const {sharedListener} = context.state.get()\n const subscriptions = [\n subscribeToQueuedAndApplyNextTransaction(context),\n subscribeToSubscriptionsAndListenToDocuments(context),\n subscribeToAppliedAndSubmitNextTransaction(context),\n subscribeToClientAndFetchDatasetAcl(context),\n subscribeToCurrentUserAndSetIdentity(context),\n ]\n\n return () => {\n sharedListener.dispose()\n subscriptions.forEach((subscription) => subscription.unsubscribe())\n }\n },\n})\n\n/**\n * @beta\n * Options for specifying a document and optionally a path within it.\n */\nexport interface DocumentOptions<\n TPath extends string | undefined = undefined,\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n path?: TPath\n}\n\n/** @beta */\nexport function getDocumentState<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n instance: SanityInstance,\n options: DocumentOptions<undefined, TDocumentType, TDataset, TProjectId>,\n): StateSource<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`> | undefined | null>\n\n/** @beta */\nexport function getDocumentState<\n TPath extends string = string,\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n instance: SanityInstance,\n options: DocumentOptions<TPath, TDocumentType, TDataset, TProjectId>,\n): StateSource<\n JsonMatch<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>, TPath> | undefined\n>\n\n/** @beta */\nexport function getDocumentState<TData>(\n instance: SanityInstance,\n options: DocumentOptions<string | undefined>,\n): StateSource<TData | undefined | null>\n\n/** @beta */\nexport function getDocumentState(\n ...args: Parameters<typeof _getDocumentState>\n): StateSource<unknown> {\n return _getDocumentState(...args)\n}\n\nconst _getDocumentState = bindActionByResource(\n documentStore,\n createStateSourceAction({\n selector: ({state: {error, documentStates}}, options: DocumentOptions<string | undefined>) => {\n const {documentId: docId, path, liveEdit, perspective} = options\n const documentId = DocumentId(docId)\n if (error) throw error\n let document: SanityDocument | null | undefined\n\n if (liveEdit) {\n document = documentStates[documentId]?.local\n } else {\n let version: SanityDocument | null | undefined\n if (isReleasePerspective(perspective)) {\n const versionId = getVersionId(documentId, perspective.releaseName)\n version = documentStates[versionId]?.local\n // early exit if we don't have the version document and we're in a release perspective\n if (version === undefined) return undefined\n }\n const draft = documentStates[getDraftId(documentId)]?.local\n const published = documentStates[getPublishedId(documentId)]?.local\n // early exit if we don't have all the documents for draft/published logic\n if (draft === undefined || published === undefined) return undefined\n document = version ?? draft ?? published\n }\n\n if (!path) return document\n const result = jsonMatch(document, path).next()\n if (result.done) return undefined\n const {value} = result.value\n return value\n },\n onSubscribe: (context, options: DocumentOptions<string | undefined>) =>\n manageSubscriberIds(context, [options]),\n }),\n)\n\n/** @beta */\nexport function resolveDocument<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n instance: SanityInstance,\n docHandle: DocumentHandle<TDocumentType, TDataset, TProjectId>,\n): Promise<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`> | null>\n/** @beta */\nexport function resolveDocument<TData extends SanityDocument>(\n instance: SanityInstance,\n docHandle: DocumentHandle<string, string, string>,\n): Promise<TData | null>\n/** @beta */\nexport function resolveDocument(\n ...args: Parameters<typeof _resolveDocument>\n): Promise<SanityDocument | null> {\n return _resolveDocument(...args)\n}\nconst _resolveDocument = bindActionByResource(\n documentStore,\n ({instance}, docHandle: DocumentHandle<string, string, string>) => {\n return firstValueFrom(\n getDocumentState(instance, {\n ...docHandle,\n path: undefined,\n }).observable.pipe(filter((i) => i !== undefined)),\n ) as Promise<SanityDocument | null>\n },\n)\n\n/** @beta */\nexport const getDocumentSyncStatus = bindActionByResource(\n documentStore,\n createStateSourceAction({\n selector: (\n {state: {error, documentStates: documents, outgoing, applied, queued}},\n doc: DocumentHandle,\n ) => {\n const documentId = DocumentId(typeof doc === 'string' ? doc : doc.documentId)\n if (error) throw error\n\n if (doc.liveEdit) {\n // For liveEdit documents, only check the single document\n if (documents[documentId] === undefined) return undefined\n } else {\n const version = isReleasePerspective(doc.perspective)\n ? documents[getVersionId(documentId, doc.perspective.releaseName)]\n : undefined\n if (isReleasePerspective(doc.perspective) && version === undefined) return undefined\n // Standard draft/published logic\n const draft = documents[getDraftId(documentId)]\n const published = documents[getPublishedId(documentId)]\n if (draft === undefined || published === undefined) return undefined\n }\n return !queued.length && !applied.length && !outgoing\n },\n onSubscribe: (context, doc: DocumentHandle) => {\n return manageSubscriberIds(context, [doc])\n },\n }),\n)\n\ntype PermissionsStateOptions = {\n resource?: DocumentResource\n actions: DocumentAction[]\n}\n\n/** @beta */\nexport const getPermissionsState = bindActionByResource(\n documentStore,\n createStateSourceAction({\n selector: calculatePermissions,\n onSubscribe: (context, {actions}: PermissionsStateOptions) => {\n manageSubscriberIds(context, actions)\n },\n }) as StoreAction<\n DocumentStoreState,\n [PermissionsStateOptions],\n StateSource<DocumentPermissionsResult>\n >,\n)\n\n/** @beta */\nexport const resolvePermissions = bindActionByResource(\n documentStore,\n ({instance}, options: PermissionsStateOptions) => {\n return firstValueFrom(\n getPermissionsState(instance, options).observable.pipe(filter((i) => i !== undefined)),\n )\n },\n)\n\n/** @beta */\nexport const subscribeDocumentEvents = bindActionByResource(\n documentStore,\n ({state}, options: {resource?: DocumentResource; eventHandler: (e: DocumentEvent) => void}) => {\n const {events} = state.get()\n const subscription = events.subscribe(options.eventHandler)\n return () => subscription.unsubscribe()\n },\n)\n\nconst subscribeToQueuedAndApplyNextTransaction = ({\n state,\n}: StoreContext<DocumentStoreState, BoundResourceKey>) => {\n const {events} = state.get()\n return state.observable\n .pipe(\n map(applyFirstQueuedTransaction),\n distinctUntilChanged(),\n tap((next) => state.set('applyFirstQueuedTransaction', next)),\n catchError((error, caught) => {\n if (error instanceof ActionError) {\n state.set('removeQueuedTransaction', (prev) =>\n removeQueuedTransaction(prev, error.transactionId),\n )\n events.next({\n type: 'error',\n message: error.message,\n documentId: error.documentId,\n transactionId: error.transactionId,\n error,\n })\n return caught\n }\n\n throw error\n }),\n )\n .subscribe({error: (error) => state.set('setError', {error})})\n}\n\nconst subscribeToAppliedAndSubmitNextTransaction = ({\n state,\n instance,\n key: {resource},\n}: StoreContext<DocumentStoreState, BoundResourceKey>) => {\n const {events} = state.get()\n\n return state.observable\n .pipe(\n throttle(\n (s) =>\n // if there is no outgoing transaction, we can throttle by the\n // initial outgoing throttle time…\n !s.outgoing\n ? timer(INITIAL_OUTGOING_THROTTLE_TIME)\n : // …otherwise, wait until the outgoing has been cleared\n state.observable.pipe(first(({outgoing}) => !outgoing)),\n {leading: false, trailing: true},\n ),\n map(transitionAppliedTransactionsToOutgoing),\n distinctUntilChanged((a, b) => a.outgoing?.transactionId === b.outgoing?.transactionId),\n tap((next) => state.set('transitionAppliedTransactionsToOutgoing', next)),\n map((s) => s.outgoing),\n distinctUntilChanged(),\n withLatestFrom(\n getClientState(instance, {\n apiVersion: API_VERSION,\n resource,\n }).observable,\n ),\n concatMap(([outgoing, client]) => {\n if (!outgoing) return EMPTY\n\n const revertOnError = catchError((error: unknown) => {\n state.set('revertOutgoingTransaction', revertOutgoingTransaction)\n const message = error instanceof Error ? error.message : 'Request failed'\n events.next({type: 'reverted', message, outgoing, error})\n return EMPTY\n })\n\n const toResult = map((result: unknown) => ({\n result: result as DocumentTransactionSubmissionResult,\n outgoing,\n }))\n\n // liveEdit transactions route to the mutations API; everything else routes\n // to the actions API. processActions rejects transactions that mix the two,\n // and reducers won't batch across that boundary, so a batch is always\n // entirely liveEdit or entirely not.\n if (outgoing.actions.some((action) => !isReleaseAction(action) && action.liveEdit)) {\n return client.observable\n .mutate(outgoing.outgoingMutations as Mutation[], {\n transactionId: outgoing.transactionId,\n visibility: 'async',\n returnDocuments: false,\n returnFirst: false,\n tag: 'document.mutate',\n skipCrossDatasetReferenceValidation: true,\n })\n .pipe(revertOnError, toResult)\n }\n\n return client.observable\n .action(outgoing.outgoingActions as Action[], {\n transactionId: outgoing.transactionId,\n skipCrossDatasetReferenceValidation: true,\n tag: 'document.action',\n })\n .pipe(revertOnError, toResult)\n }),\n tap(({outgoing, result}) => {\n state.set('cleanupOutgoingTransaction', cleanupOutgoingTransaction)\n for (const e of getDocumentEvents(outgoing)) events.next(e)\n events.next({type: 'accepted', outgoing, result})\n }),\n )\n .subscribe({error: (error) => state.set('setError', {error})})\n}\n\nconst subscribeToSubscriptionsAndListenToDocuments = (\n context: StoreContext<DocumentStoreState, BoundResourceKey>,\n) => {\n const {state} = context\n const {events} = state.get()\n\n return state.observable\n .pipe(\n filter((s) => !!s.grants),\n map((s) => Object.keys(s.documentStates)),\n distinctUntilChanged((curr, next) => {\n if (curr.length !== next.length) return false\n const currSet = new Set(curr)\n return next.every((i) => currSet.has(i))\n }),\n startWith(new Set<string>()),\n pairwise(),\n switchMap((pair) => {\n const [curr, next] = pair.map((ids) => new Set(ids))\n const added = Array.from(next).filter((i) => !curr.has(i))\n const removed = Array.from(curr).filter((i) => !next.has(i))\n\n // NOTE: the order of which these go out is somewhat important\n // because that determines the order `applyRemoteDocument` is called\n // which in turn determines which document version get populated\n // first. because we prefer drafts, it's better to have those go out\n // first so that the published document doesn't flash for a frame\n const changes = [\n ...added.map((id) => ({id, add: true})),\n ...removed.map((id) => ({id, add: false})),\n ].sort((a, b) => {\n const aIsDraft = a.id === getDraftId(DocumentId(a.id))\n const bIsDraft = b.id === getDraftId(DocumentId(b.id))\n\n if (aIsDraft && bIsDraft) return a.id.localeCompare(b.id, 'en-US')\n if (aIsDraft) return -1\n if (bIsDraft) return 1\n return a.id.localeCompare(b.id, 'en-US')\n })\n\n return of<{id: string; add: boolean}[]>(...changes)\n }),\n groupBy((i) => i.id),\n mergeMap((group) =>\n group.pipe(\n switchMap((e) => {\n if (!e.add) return EMPTY\n return listen(context, e.id).pipe(\n retry({\n delay: (error, retryCount) => {\n if (!(error instanceof OutOfSyncError)) return throwError(() => error)\n const backoff = Math.min(\n OUT_OF_SYNC_RETRY_BASE_DELAY * 2 ** (retryCount - 1),\n OUT_OF_SYNC_RETRY_MAX_DELAY,\n )\n return timer(backoff)\n },\n }),\n tap((remote) =>\n state.set('applyRemoteDocument', (prev) =>\n applyRemoteDocument(prev, remote, events),\n ),\n ),\n )\n }),\n ),\n ),\n )\n .subscribe({error: (error) => state.set('setError', {error})})\n}\n\nconst subscribeToClientAndFetchDatasetAcl = ({\n instance,\n state,\n key: {resource},\n}: StoreContext<DocumentStoreState, BoundResourceKey>) => {\n const clientOptions: ClientOptions = {apiVersion: API_VERSION, resource}\n\n let uri: string\n if (resource && isDatasetResource(resource)) {\n uri = `/projects/${resource.projectId}/datasets/${resource.dataset}/acl`\n } else if (resource && isMediaLibraryResource(resource)) {\n uri = `/media-libraries/${resource.mediaLibraryId}/acl`\n } else if (resource && isCanvasResource(resource)) {\n uri = `/canvases/${resource.canvasId}/acl`\n } else {\n throw new Error(`Received invalid resource: ${JSON.stringify(resource)}`)\n }\n\n return getClientState(instance, clientOptions)\n .observable.pipe(\n switchMap((client) =>\n client.observable\n .request<DatasetAcl>({\n uri,\n tag: 'acl.get',\n })\n .pipe(\n retry({\n delay: (error, retryCount) => {\n // 4xx responses and CORS misconfigurations are not transient —\n // the server will keep rejecting the request, so rethrow to\n // surface them as a fatal store error. 408 (request timeout)\n // and 429 (rate limit) are the exceptions: they resolve on\n // their own, so they are retried like network errors\n const isTransientClientError =\n error instanceof ClientError &&\n (error.statusCode === 408 || error.statusCode === 429)\n if (\n (error instanceof ClientError && !isTransientClientError) ||\n error instanceof CorsOriginError\n ) {\n return throwError(() => error)\n }\n // network errors (no status code), 408/429 responses, and 5xx\n // responses are retried with exponential backoff so a transient\n // failure during startup doesn't permanently brick the store\n const backoff = Math.min(\n ACL_RETRY_BASE_DELAY * 2 ** (retryCount - 1),\n ACL_RETRY_MAX_DELAY,\n )\n return timer(backoff)\n },\n }),\n ),\n ),\n tap((datasetAcl) => state.set('setGrants', {grants: createGrantsLookup(datasetAcl)})),\n )\n .subscribe({\n error: (error) => state.set('setError', {error}),\n })\n}\n\nconst subscribeToCurrentUserAndSetIdentity = ({\n instance,\n state,\n}: StoreContext<DocumentStoreState, BoundResourceKey>) =>\n getCurrentUserState(instance).observable.subscribe({\n next: (currentUser) => state.set('setIdentity', {identity: currentUser?.id}),\n // A transient identity-fetch failure (network blip, expired token, or a\n // normal logout/re-login transition) should not brick all document\n // operations. Reset the identity to `undefined` and keep going — GROQ's\n // `identity()` then evaluates to null, matching the unauthenticated state.\n error: () => state.set('setIdentity', {identity: undefined}),\n })\n","import {DocumentId, getPublishedId} from '@sanity/id-utils'\n\nimport {\n type DocumentResource,\n isCanvasResource,\n isMediaLibraryResource,\n} from '../config/sanityConfig'\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\nimport {type Action, type DocumentAction} from './actions'\nimport {getEffectiveDocumentId} from './util'\n\nexport interface EffectiveDocModel {\n /**\n * If this is `undefined`, the resource has no opinion and the handle's `liveEdit`\n * flag should be respected.\n */\n liveEdit: boolean | undefined\n /**\n * When `false`, the resource does not support release perspectives. Callers\n * should drop any release perspective and fall back to the standard path.\n */\n supportsReleases: boolean\n}\n\nconst MEDIA_LIBRARY_DRAFTED_TYPES = new Set(['sanity.asset'])\n\n/**\n * Different resources have different \"default\" editing models.\n *\n * Canvas uses a liveEdit model.\n * Medial Library is mostly liveEdit except for `sanity.asset`, which retains the\n * draft/published model. Neither resource supports release perspectives.\n */\nexport function getEffectiveDocumentModel(\n resource: DocumentResource | undefined,\n documentType: string | undefined,\n): EffectiveDocModel {\n if (!resource) {\n return {liveEdit: undefined, supportsReleases: true}\n }\n if (isCanvasResource(resource)) {\n return {liveEdit: true, supportsReleases: false}\n }\n if (isMediaLibraryResource(resource)) {\n const isDrafted = documentType ? MEDIA_LIBRARY_DRAFTED_TYPES.has(documentType) : false\n return {liveEdit: !isDrafted, supportsReleases: false}\n }\n return {liveEdit: undefined, supportsReleases: true}\n}\n\nfunction describeResource(resource: DocumentResource | undefined): string {\n if (resource && isCanvasResource(resource)) return 'Canvas'\n if (resource && isMediaLibraryResource(resource)) return 'Media Library'\n return 'this resource'\n}\n\n/**\n * Rewrites edit actions to match the editing model of the bound resource.\n *\n * Canvas and Media Library resources do not support release perspectives, and\n * Canvas (plus most Media Library types) does not have a draft/published\n * model. When an edit action arrives with a release perspective for a resource\n * that doesn't support it, the perspective is stripped and a single warning\n * is logged. When the resource forces liveEdit, the action's `liveEdit` flag\n * is set so the dispatcher takes the liveEdit branch.\n *\n * Only `document.edit` actions are normalized today — other action types\n * (publish, unpublish, release actions, etc.) pass through unchanged.\n *\n * @internal\n */\nexport function normalizeActionsForResource(\n actions: Action[],\n resource: DocumentResource | undefined,\n): Action[] {\n // collect actions that may have changed in unexpected ways\n const stripped: Array<{documentType: string; documentId: string}> = []\n\n const normalized = actions.map((action) => {\n if (action.type !== 'document.edit') return action\n\n const {liveEdit: forcedLiveEdit, supportsReleases} = getEffectiveDocumentModel(\n resource,\n action.documentType,\n )\n const shouldRemovePerspective = isReleasePerspective(action.perspective) && !supportsReleases\n const shouldForceLiveEdit = forcedLiveEdit === true && !action.liveEdit\n\n if (!shouldRemovePerspective && !shouldForceLiveEdit) return action\n\n const corrected: DocumentAction = {...action}\n if (shouldForceLiveEdit) corrected.liveEdit = true\n if (shouldRemovePerspective) corrected.perspective = undefined\n\n // ensure we're using the right document ID for the corrected model\n corrected.documentId = getEffectiveDocumentId({\n ...corrected,\n documentId: getPublishedId(DocumentId(corrected.documentId)),\n })\n\n if (shouldRemovePerspective) {\n stripped.push({documentType: action.documentType, documentId: corrected.documentId})\n }\n\n return corrected\n })\n\n if (stripped.length > 0) {\n const docs = stripped.map((e) => `${e.documentType} (${e.documentId})`).join(', ')\n // eslint-disable-next-line no-console\n console.warn(\n `[sanity-sdk] ${describeResource(resource)} does not support release perspectives — falling back to the standard editing path for: ${docs}`,\n )\n }\n\n return normalized\n}\n","import {type SanityDocument} from 'groq'\nimport {distinctUntilChanged, filter, first, firstValueFrom, map, race} from 'rxjs'\n\nimport {type DocumentResource} from '../config/sanityConfig'\nimport {bindActionByResource} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {type StoreContext} from '../store/defineStore'\nimport {type Action} from './actions'\nimport {documentStore, type DocumentStoreState} from './documentStore'\nimport {type DocumentTransactionSubmissionResult} from './events'\nimport {type DocumentSet} from './processMutations'\nimport {type AppliedTransaction, type QueuedTransaction, queueTransaction} from './reducers'\nimport {normalizeActionsForResource} from './resourceRules'\n\n/** @beta */\nexport interface ActionsResult<TDocument extends SanityDocument = SanityDocument> {\n transactionId: string\n documents: DocumentSet<TDocument>\n previous: DocumentSet<TDocument>\n previousRevs: {[documentId: string]: string | undefined}\n appeared: string[]\n updated: string[]\n disappeared: string[]\n submitted: () => Promise<DocumentTransactionSubmissionResult>\n}\n\n/** @beta */\nexport interface ApplyDocumentActionsOptions {\n /**\n * List of actions to apply. Accepts both document actions and release\n * lifecycle actions because they share the same transaction pipeline.\n */\n actions: Action[]\n\n /**\n * The resource to which the documents being acted on belong.\n */\n resource?: DocumentResource\n\n /**\n * Optionally provide an ID to be used as this transaction ID\n */\n transactionId?: string\n /**\n * Set this to true to prevent this action from being batched with others.\n */\n disableBatching?: boolean\n}\n\n/** @beta */\nexport function applyDocumentActions<\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n instance: SanityInstance,\n options: ApplyDocumentActionsOptions,\n): Promise<ActionsResult<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>>>\n/** @beta */\nexport function applyDocumentActions(\n instance: SanityInstance,\n options: ApplyDocumentActionsOptions,\n): Promise<ActionsResult>\n\n/** @beta */\nexport function applyDocumentActions(\n ...args: Parameters<typeof boundApplyDocumentActions>\n): ReturnType<typeof boundApplyDocumentActions> {\n return boundApplyDocumentActions(...args)\n}\n\nconst boundApplyDocumentActions = bindActionByResource(documentStore, _applyDocumentActions)\n\n/** @internal */\nasync function _applyDocumentActions(\n {state}: StoreContext<DocumentStoreState>,\n {\n actions,\n resource,\n transactionId = crypto.randomUUID(),\n disableBatching,\n }: ApplyDocumentActionsOptions,\n): Promise<ActionsResult> {\n const {events} = state.get()\n\n // Rewrite edit actions to match the bound resource's editing model (e.g.\n // forcing liveEdit for Canvas, stripping unsupported release perspectives).\n // Non-edit and release actions pass through unchanged.\n const normalizedActions = normalizeActionsForResource(actions, resource)\n\n const transaction: QueuedTransaction = {\n transactionId,\n actions: normalizedActions,\n ...(disableBatching && {disableBatching}),\n }\n\n const fatalError$ = state.observable.pipe(\n map((s) => s.error),\n first(Boolean),\n map((error) => ({type: 'error', error}) as const),\n )\n\n const transactionError$ = events.pipe(\n filter((e) => e.type === 'error'),\n first((e) => e.transactionId === transactionId),\n )\n\n const appliedTransaction$ = state.observable.pipe(\n map((s) => s.applied),\n distinctUntilChanged(),\n map((applied) => applied.find((t) => t.transactionId === transactionId)),\n first(Boolean),\n )\n\n const successfulTransaction$ = events.pipe(\n filter((e) => e.type === 'accepted'),\n first((e) => e.outgoing.batchedTransactionIds.includes(transactionId)),\n )\n\n const rejectedTransaction$ = events.pipe(\n filter((e) => e.type === 'reverted'),\n first((e) => e.outgoing.batchedTransactionIds.includes(transactionId)),\n )\n\n const appliedTransactionOrError = firstValueFrom(\n race([fatalError$, transactionError$, appliedTransaction$]),\n )\n const acceptedOrRejectedTransaction = firstValueFrom(\n race([successfulTransaction$, rejectedTransaction$, transactionError$]),\n )\n\n state.set('queueTransaction', (prev) => queueTransaction(prev, transaction))\n\n const result = await appliedTransactionOrError\n if ('type' in result && result.type === 'error') throw result.error\n\n const {working: documents, previous, previousRevs} = result as AppliedTransaction\n const existingIds = new Set(\n Object.entries(previous)\n .filter(([, value]) => !!value)\n .map(([key]) => key),\n )\n const resultingIds = new Set(\n Object.entries(documents)\n .filter(([, value]) => !!value)\n .map(([key]) => key),\n )\n const allIds = new Set([...existingIds, ...resultingIds])\n\n const updated: string[] = []\n const appeared: string[] = []\n const disappeared: string[] = []\n\n for (const id of allIds) {\n if (existingIds.has(id) && resultingIds.has(id)) {\n updated.push(id)\n } else if (!existingIds.has(id) && resultingIds.has(id)) {\n appeared.push(id)\n } else if (!resultingIds.has(id) && existingIds.has(id)) {\n disappeared.push(id)\n }\n }\n\n async function submitted() {\n const raceResult = await acceptedOrRejectedTransaction\n if (raceResult.type !== 'accepted') throw raceResult.error\n return raceResult.result\n }\n\n return {\n transactionId,\n documents,\n previous,\n previousRevs,\n appeared,\n updated,\n disappeared,\n submitted,\n }\n}\n","import {\n type CanvasResource,\n type MediaResource,\n SDK_CHANNEL_NAME,\n SDK_NODE_NAME,\n type StudioResource,\n} from '@sanity/message-protocol'\nimport {catchError, filter, from, map, Observable, of, shareReplay, switchMap} from 'rxjs'\n\nimport {getNodeState} from '../comlink/node/getNodeState'\nimport {type DocumentHandle} from '../config/sanityConfig'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {createFetcherStore} from '../utils/createFetcherStore'\n\n/**\n * @public\n */\nexport interface FavoriteStatusResponse {\n isFavorited: boolean\n}\n\n/**\n * @public\n */\ninterface FavoriteDocumentContext extends DocumentHandle {\n resourceId: string\n resourceType: StudioResource['type'] | MediaResource['type'] | CanvasResource['type']\n schemaName?: string\n}\n\n// Helper to create a stable key for the store\nfunction createFavoriteKey(context: FavoriteDocumentContext): string {\n return `${context.documentId}:${context.documentType}:${context.resourceId}:${context.resourceType}${\n context.schemaName ? `:${context.schemaName}` : ''\n }`\n}\n\nconst favorites = createFetcherStore<[FavoriteDocumentContext], FavoriteStatusResponse>({\n name: 'Favorites',\n getKey: (_instance: SanityInstance, context: FavoriteDocumentContext) => {\n return createFavoriteKey(context)\n },\n fetcher: (instance: SanityInstance) => {\n return (context: FavoriteDocumentContext): Observable<FavoriteStatusResponse> => {\n const nodeStateSource = getNodeState(instance, {\n name: SDK_NODE_NAME,\n connectTo: SDK_CHANNEL_NAME,\n })\n const payload = {\n document: {\n id: context.documentId,\n type: context.documentType,\n resource: {\n id: context.resourceId,\n type: context.resourceType,\n schemaName: context.schemaName,\n },\n },\n }\n\n return nodeStateSource.observable.pipe(\n filter((nodeState) => !!nodeState), // Only proceed when connected\n shareReplay(1),\n switchMap((nodeState) => {\n const node = nodeState!.node\n return from(\n node.fetch(\n // @ts-expect-error -- getOrCreateNode should be refactored to take type arguments\n 'dashboard/v1/events/favorite/query',\n payload,\n ) as Promise<FavoriteStatusResponse>,\n ).pipe(\n map((response) => ({isFavorited: response.isFavorited})),\n catchError((err) => {\n // eslint-disable-next-line no-console\n console.error('Favorites service connection error', err)\n return of({isFavorited: false})\n }),\n )\n }),\n )\n }\n },\n})\n\n/**\n * Gets a StateSource for the favorite status of a document.\n * @param instance - The Sanity instance.\n * @param context - The document context including ID, type, and resource information.\n * @returns A StateSource emitting `{ isFavorited: boolean }`.\n * @public\n */\nexport const getFavoritesState = favorites.getState\n\n/**\n * Resolves the favorite status for a document.\n * @param instance - The Sanity instance.\n * @param context - The document context including ID, type, and resource information.\n * @returns A Promise resolving to `{ isFavorited: boolean }`.\n * @public\n */\nexport const resolveFavoritesState = favorites.resolveState\n","import {switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {defineFetcher} from '../store/fetcherStore'\nimport {buildQuery} from '../utils/buildQuery'\nimport {type Included} from '../utils/includeShape'\n\n// The Applications API is currently only available on vX.\nconst API_VERSION = 'vX'\n\n/**\n * Related data the Installations API can embed in a response. Each token adds\n * a top-level field to the {@link Installation} item.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport type InstallationInclude = 'activeConfig' | 'access' | 'interfaces'\n\n/**\n * A resource an installation accesses, embedded when `access` is included.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface InstallationAccess {\n id: string\n resourceType: 'datasets' | 'canvases' | 'dashboards' | 'media-libraries'\n resourceId: string\n}\n\n/**\n * An interface exposed by an installation, embedded when `interfaces` is\n * included.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface InstallationInterface {\n id: string\n type: 'app' | 'worker' | 'asset_source' | 'panel'\n name: string\n title: string\n version: string\n /** Module federation module ID; resolved from the host mf-manifest at runtime */\n moduleId: string\n metadata: {group?: string; priority?: number} | null\n}\n\n/**\n * The active config of an installation, embedded when `activeConfig` is\n * included. `null` when nothing is deployed.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface InstallationActiveConfig {\n id: string\n installationId: string\n deployedBy: string | null\n version: string\n isActive: boolean\n createdAt: string\n}\n\n/**\n * The always-present fields of an active singleton installation returned by the\n * Installations API (`/installations`), before any {@link InstallationInclude}.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface InstallationBase {\n id: string\n applicationId: string\n organizationId: string\n installedBy: string | null\n createdAt: string\n updatedAt: string\n application: {\n title: string\n /** Stable, immutable identity of the installed singleton, distinct from `slug`. */\n name: string\n /** Qualified, globally-unique handle of the installed singleton (e.g. `sanity/<name>`). */\n reference: string\n slug: string | null\n }\n}\n\n/**\n * An active singleton installation as returned by the Installations API\n * (`/installations`). `activeConfig`, `access` and `interfaces` are top-level\n * fields, each present only when the matching {@link InstallationInclude} token\n * was requested.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport type Installation<Include extends InstallationInclude = never> = InstallationBase &\n Included<\n InstallationInclude,\n 'activeConfig',\n Include,\n {activeConfig: InstallationActiveConfig | null}\n > &\n Included<InstallationInclude, 'access', Include, {access: InstallationAccess[]}> &\n Included<InstallationInclude, 'interfaces', Include, {interfaces: InstallationInterface[]}>\n\n/**\n * Options for listing an organization's installations.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface InstallationsOptions<Include extends InstallationInclude = InstallationInclude> {\n organizationId: string\n include?: Include[]\n /** Page size (1-100, default 50), or `'none'` to disable pagination */\n limit?: number | 'none'\n /** Cursor from a previous response's `nextCursor` */\n cursor?: string\n}\n\n/**\n * The cursor-paginated envelope returned by `GET /installations`.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @public\n */\nexport interface InstallationsResponse<Include extends InstallationInclude = never> {\n nextCursor: string | null\n data: Installation<Include>[]\n}\n\n/** The API takes `include` as a comma-separated list; sorted so key and query agree */\nfunction serializeInclude(include: InstallationInclude[] | undefined): string | undefined {\n return include?.length ? [...include].sort().join(',') : undefined\n}\n\n/**\n * Fetcher for an organization's installations (`GET /installations`), on the\n * shared fetcher cache.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @internal\n */\nexport const installations = defineFetcher<\n [options: InstallationsOptions],\n InstallationsResponse<InstallationInclude>\n>({\n name: 'installations',\n getKey: (_instance, options) =>\n [\n options.organizationId,\n serializeInclude(options.include) ?? '',\n options.limit ?? '',\n options.cursor ?? '',\n ].join(':'),\n fetch: (instance) => (options) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable.request<InstallationsResponse<InstallationInclude>>({\n uri: '/installations',\n query: buildQuery({\n organizationId: options.organizationId,\n include: serializeInclude(options.include),\n limit: options.limit,\n cursor: options.cursor,\n }),\n tag: 'installations.list',\n }),\n ),\n ),\n tags: (data) => [\n {type: 'installation', id: 'LIST'},\n ...data.data.map((installation) => ({type: 'installation', id: installation.id})),\n ],\n})\n\n/**\n * Fetcher for a single installation (`GET /installations/:id`), on the shared\n * fetcher cache. No pre-seeding from {@link installations}: its list keys\n * include the organization, which this fetcher's params can't reconstruct.\n *\n * @see https://www.sanity.io/docs/http-reference/applications-api\n * @internal\n */\nexport const installation = defineFetcher<\n [installationId: string, options?: {include?: InstallationInclude[]}],\n Installation<InstallationInclude>\n>({\n name: 'installation',\n getKey: (_instance, installationId, options) =>\n `${installationId}:${serializeInclude(options?.include) ?? ''}`,\n fetch: (instance) => (installationId, options) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable.request<Installation<InstallationInclude>>({\n uri: `/installations/${installationId}`,\n query: buildQuery({include: serializeInclude(options?.include)}),\n tag: 'installations.get',\n }),\n ),\n ),\n tags: (data) => [{type: 'installation', id: data.id}],\n})\n","import {switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {defineFetcher} from '../store/fetcherStore'\nimport {buildQuery} from '../utils/buildQuery'\n\nconst API_VERSION = 'v2025-02-19'\n\n/** @public */\nexport interface OrganizationMember {\n sanityUserId: string\n isCurrentUser: boolean\n user: {\n id: string\n displayName: string\n familyName: string\n givenName: string\n middleName: string | null\n imageUrl: string | null\n email: string\n loginProvider: string\n }\n roles: Array<{\n name: string\n title: string\n description?: string\n }>\n}\n\n/**\n * The base fields returned from `/organizations/<id>` for every organization.\n * @public\n */\nexport interface OrganizationBase {\n id: string\n name: string\n slug: string | null\n createdAt: string\n createdByUserId: string\n updatedAt: string\n deletedAt: string | null\n dashboardStatus: 'enabled' | 'disabled'\n aiFeaturesStatus: 'enabled' | 'disabled'\n mediaLibraryStatus: 'enabled' | 'disabled'\n requestAccessStatus: 'allowed' | 'disabled'\n telemetryConsentStatus: 'allowed' | 'msa_denied' | 'customer_denied'\n oauthAppsStatus: 'allowed' | 'blocked'\n defaultRoleName: string\n domains: string[] | null\n}\n\n/** @public */\nexport interface OrganizationOptions<\n IncludeMembers extends boolean = false,\n IncludeFeatures extends boolean = false,\n> {\n includeMembers?: IncludeMembers\n includeFeatures?: IncludeFeatures\n organizationId: string\n}\n\n/**\n * An `Organization` with `members` and/or `features` conditionally included\n * based on the query options used to fetch it.\n * @public\n */\nexport type Organization<\n IncludeMembers extends boolean = false,\n IncludeFeatures extends boolean = false,\n> = OrganizationBase &\n // `boolean extends T` is non-distributive — true only when T is the wide\n // `boolean`, in which case the field is optional. Literal `true`/`false`\n // fall through to the strict branch.\n (boolean extends IncludeMembers\n ? {members?: OrganizationMember[]}\n : IncludeMembers extends true\n ? {members: OrganizationMember[]}\n : unknown) &\n (boolean extends IncludeFeatures\n ? {features?: string[]}\n : IncludeFeatures extends true\n ? {features: string[]}\n : unknown)\n\nfunction resolveOrganizationId(options?: OrganizationOptions<boolean, boolean>) {\n const organizationId = options?.organizationId\n if (!organizationId) {\n throw new Error('An organizationId is required to use the organization API.')\n }\n return organizationId\n}\n\nfunction normalizeOrganizationOptions(options?: OrganizationOptions<boolean, boolean>) {\n return {\n includeMembers: options?.includeMembers ?? false,\n includeFeatures: options?.includeFeatures ?? false,\n }\n}\n\n/** @internal */\nexport function getOrganizationCacheKey(\n _instance: SanityInstance,\n options?: OrganizationOptions<boolean, boolean>,\n): string {\n const organizationId = resolveOrganizationId(options)\n const {includeMembers, includeFeatures} = normalizeOrganizationOptions(options)\n const membersKey = includeMembers ? ':members' : ''\n const featuresKey = includeFeatures ? ':features' : ''\n return `organization:${organizationId}${membersKey}${featuresKey}`\n}\n\n/**\n * Fetcher for a single organization (`GET /organizations/:id`), on the shared\n * fetcher cache. No pre-seeding from the organizations list: it returns a\n * subset of the detail fields, and a partial seed would serve as fresh for\n * the whole stale window.\n *\n * @internal\n */\nexport const organization = defineFetcher<\n [options?: OrganizationOptions<boolean, boolean>],\n Organization<boolean, boolean>\n>({\n name: 'organization',\n getKey: getOrganizationCacheKey,\n fetch: (instance) => (options) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable.request<Organization<boolean, boolean>>({\n uri: `/organizations/${resolveOrganizationId(options)}`,\n query: buildQuery(normalizeOrganizationOptions(options)),\n tag: 'organizations.get',\n }),\n ),\n ),\n tags: (data) => [{type: 'organization', id: data.id}],\n})\n","import {switchMap} from 'rxjs'\n\nimport {getClientState} from '../client/clientStore'\nimport {\n type OrganizationBase,\n type OrganizationMember,\n type OrganizationOptions,\n} from '../organization/organization'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {defineFetcher} from '../store/fetcherStore'\nimport {buildQuery} from '../utils/buildQuery'\n\nconst API_VERSION = 'v2025-02-19'\n\n/**\n * The list shape returned from `/organizations`, with `members` and/or\n * `features` conditionally included based on the query options used.\n * @public\n */\nexport type Organizations<\n IncludeMembers extends boolean = false,\n IncludeFeatures extends boolean = false,\n> = (Pick<\n OrganizationBase,\n | 'id'\n | 'name'\n | 'slug'\n | 'createdAt'\n | 'updatedAt'\n | 'defaultRoleName'\n | 'dashboardStatus'\n | 'aiFeaturesStatus'\n> &\n // `boolean extends T` is non-distributive — true only when T is the wide\n // `boolean`, in which case the field is optional. Literal `true`/`false`\n // fall through to the strict branch.\n (boolean extends IncludeMembers\n ? {members?: OrganizationMember[]}\n : IncludeMembers extends true\n ? {members: OrganizationMember[]}\n : unknown) &\n (boolean extends IncludeFeatures\n ? {features?: string[]}\n : IncludeFeatures extends true\n ? {features: string[]}\n : unknown))[]\n\n/** @public */\nexport interface OrganizationsOptions<\n IncludeMembers extends boolean = false,\n IncludeFeatures extends boolean = false,\n> extends Omit<OrganizationOptions<IncludeMembers, IncludeFeatures>, 'organizationId'> {\n /**\n * When `true`, includes organisations the user has access to via\n * project-level grants, not just direct organisation memberships.\n */\n includeImplicitMemberships?: boolean\n}\n\nfunction normalizeOrganizationsOptions(options?: OrganizationsOptions<boolean, boolean>) {\n return {\n includeImplicitMemberships: options?.includeImplicitMemberships ?? false,\n includeMembers: options?.includeMembers ?? false,\n includeFeatures: options?.includeFeatures ?? false,\n }\n}\n\n/** @internal */\nexport function getOrganizationsCacheKey(\n _instance: SanityInstance,\n options?: OrganizationsOptions<boolean, boolean>,\n): string {\n const {includeMembers, includeFeatures, includeImplicitMemberships} =\n normalizeOrganizationsOptions(options)\n const membersKey = includeMembers ? ':members' : ''\n const featuresKey = includeFeatures ? ':features' : ''\n const implicitKey = includeImplicitMemberships ? ':implicit' : ''\n return `organizations${membersKey}${featuresKey}${implicitKey}`\n}\n\n/**\n * Fetcher for the current user's organizations (`GET /organizations`), on the\n * shared fetcher cache.\n *\n * @internal\n */\nexport const organizations = defineFetcher<\n [options?: OrganizationsOptions<boolean, boolean>],\n Organizations<boolean, boolean>\n>({\n name: 'organizations',\n getKey: getOrganizationsCacheKey,\n fetch: (instance) => (options) =>\n getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(\n switchMap((client) =>\n client.observable.request<Organizations<boolean, boolean>>({\n uri: '/organizations',\n query: buildQuery(normalizeOrganizationsOptions(options)),\n tag: 'organizations.list',\n }),\n ),\n ),\n tags: (data) => [\n {type: 'organization', id: 'LIST'},\n ...data.map((org) => ({type: 'organization', id: org.id})),\n ],\n})\n","import {type SanityUser as SanityUserFromClient} from '@sanity/client'\nimport {createSelector} from 'reselect'\nimport {\n catchError,\n combineLatest,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n firstValueFrom,\n groupBy,\n map,\n mergeMap,\n NEVER,\n Observable,\n of,\n pairwise,\n race,\n skip,\n startWith,\n switchMap,\n tap,\n throwError,\n withLatestFrom,\n} from 'rxjs'\n\nimport {getDashboardOrganizationId} from '../auth/authStore'\nimport {getClient, getClientState} from '../client/clientStore'\nimport {bindActionGlobally} from '../store/createActionBinder'\nimport {createStateSourceAction, type SelectorContext} from '../store/createStateSourceAction'\nimport {type StoreState} from '../store/createStoreState'\nimport {defineStore, type StoreContext} from '../store/defineStore'\nimport {insecureRandomId} from '../utils/ids'\nimport {setCleanupTimeout} from '../utils/setCleanupTimeout'\nimport {\n addSubscription,\n cancelRequest,\n getUsersKey,\n initializeRequest,\n parseUsersKey,\n removeSubscription,\n setUsersData,\n setUsersError,\n updateLastLoadMoreRequest,\n} from './reducers'\nimport {\n type GetUserOptions,\n type GetUsersOptions,\n type ResolveUserOptions,\n type ResolveUsersOptions,\n type SanityUser,\n type SanityUserResponse,\n type UsersStoreState,\n} from './types'\nimport {API_VERSION, PROJECT_API_VERSION, USERS_STATE_CLEAR_DELAY} from './usersConstants'\n\n/** @internal */\nexport type PatchedSanityUserFromClient = Omit<SanityUserFromClient, 'id'> & {\n id: string\n sanityUserId: string\n email: string\n provider: string\n}\n\n/**\n * The users store resource that manages user data fetching and state.\n *\n * This store handles fetching, caching, and managing user data. It provides functionality for\n * retrieving users associated with specific resources and supports pagination through the\n * `loadMoreUsers` action.\n *\n * @internal\n */\nconst usersStore = defineStore<UsersStoreState>({\n name: 'UsersStore',\n getInitialState: () => ({users: {}}),\n initialize: (context) => {\n const subscription = listenForLoadMoreAndFetch(context)\n return () => subscription.unsubscribe()\n },\n})\n\nconst errorHandler =\n (state: StoreState<{error?: unknown}>) =>\n (error: unknown): void =>\n state.set('setError', {error})\n\n/**\n * Internal action that listens for new user subscriptions and load more requests.\n * Fetches user data when new subscriptions are added or when loadMoreUsers is called.\n */\nconst listenForLoadMoreAndFetch = ({state, instance}: StoreContext<UsersStoreState>) => {\n return state.observable\n .pipe(\n map((s) => new Set(Object.keys(s.users))),\n distinctUntilChanged((curr, next) => {\n if (curr.size !== next.size) return false\n return Array.from(next).every((i) => curr.has(i))\n }),\n startWith(new Set<string>()),\n pairwise(),\n mergeMap(([curr, next]) => {\n const added = Array.from(next).filter((i) => !curr.has(i))\n const removed = Array.from(curr).filter((i) => !next.has(i))\n\n return [\n ...added.map((key) => ({key, added: true})),\n ...removed.map((key) => ({key, added: false})),\n ]\n }),\n groupBy((i) => i.key),\n mergeMap((group$) =>\n group$.pipe(\n switchMap((e) => {\n if (!e.added) return EMPTY\n const {userId, batchSize, ...options} = parseUsersKey(group$.key)\n\n if (userId) {\n // In the future we will be able to fetch a user from the global API using the resourceUserId,\n // but for now we need to use the project subdomain to fetch a user if the userId is a project user (starts with \"p\")\n if (userId.startsWith('p')) {\n const client = getClient(instance, {\n apiVersion: PROJECT_API_VERSION,\n // this is a global store, so we need to use the projectId from the options when we're fetching\n // users from a project subdomain\n projectId: options.projectId,\n useProjectHostname: true,\n })\n\n return client.observable\n .request<PatchedSanityUserFromClient>({\n method: 'GET',\n uri: `/users/${userId}`,\n tag: 'users.get',\n })\n .pipe(\n map((user) => {\n // We need to convert the user to the format we expect\n const convertedUser: SanityUser = {\n sanityUserId: user.sanityUserId,\n profile: {\n id: user.id,\n displayName: user.displayName,\n familyName: user.familyName ?? undefined,\n givenName: user.givenName ?? undefined,\n middleName: user.middleName ?? undefined,\n imageUrl: user.imageUrl ?? undefined,\n createdAt: user.createdAt,\n updatedAt: user.updatedAt,\n isCurrentUser: user.isCurrentUser,\n email: user.email,\n provider: user.provider,\n },\n memberships: [],\n }\n return {\n data: [convertedUser],\n totalCount: 1,\n nextCursor: null,\n }\n }),\n catchError((error) => {\n state.set('setUsersError', setUsersError(group$.key, error))\n return EMPTY\n }),\n tap((response) =>\n state.set('setUsersData', setUsersData(group$.key, response)),\n ),\n )\n }\n\n // Fetch the user from the global API\n const scope = userId.startsWith('g') ? 'global' : undefined\n const client = getClient(instance, {\n scope,\n apiVersion: API_VERSION,\n })\n const resourceType = options.resourceType || 'project'\n const resourceId =\n resourceType === 'organization' ? options.organizationId : options.projectId\n if (!resourceId) {\n return throwError(() => new Error('An organizationId or a projectId is required'))\n }\n return client.observable\n .request<SanityUser | SanityUserResponse>({\n method: 'GET',\n uri: `access/${resourceType}/${resourceId}/users/${userId}`,\n tag: 'users.get',\n })\n .pipe(\n map((response) => {\n // If the response is a single user object (has sanityUserId), wrap it in the expected format\n if ('sanityUserId' in response) {\n return {\n data: [response],\n totalCount: 1,\n nextCursor: null,\n } as SanityUserResponse\n }\n return response as SanityUserResponse\n }),\n catchError((error) => {\n state.set('setUsersError', setUsersError(group$.key, error))\n return EMPTY\n }),\n tap((response) => state.set('setUsersData', setUsersData(group$.key, response))),\n )\n }\n const projectId = options.projectId\n\n // the resource type this request will use\n // If resourceType is explicitly provided, use it\n // Otherwise, infer from context: organization if organizationId exists,\n // project if projectId exists, or default to organization\n const resourceType =\n options.resourceType ??\n (options.organizationId ? 'organization' : projectId ? 'project' : 'organization')\n\n const organizationId$ = options.organizationId\n ? of(options.organizationId)\n : getDashboardOrganizationId(instance).observable.pipe(\n filter((i) => typeof i === 'string'),\n )\n\n const resource$: Observable<{\n type: 'project' | 'organization'\n id: string\n }> =\n resourceType === 'project'\n ? projectId\n ? of({type: 'project', id: projectId})\n : throwError(() => new Error('Project ID required for this API.'))\n : organizationId$.pipe(map((id) => ({type: 'organization', id})))\n\n const client$ = getClientState(instance, {\n scope: 'global',\n apiVersion: API_VERSION,\n }).observable\n\n const loadMore$ = state.observable.pipe(\n map((s) => s.users[group$.key]?.lastLoadMoreRequest),\n distinctUntilChanged(),\n )\n\n const cursor$ = state.observable.pipe(\n map((s) => s.users[group$.key]?.nextCursor),\n distinctUntilChanged(),\n filter((cursor) => cursor !== null),\n )\n\n return combineLatest([resource$, client$, loadMore$]).pipe(\n withLatestFrom(cursor$),\n switchMap(([[resource, client], cursor]) =>\n client.observable.request<SanityUserResponse>({\n method: 'GET',\n uri: `access/${resource.type}/${resource.id}/users`,\n tag: 'users.list',\n query: cursor\n ? {nextCursor: cursor, limit: batchSize.toString()}\n : {limit: batchSize.toString()},\n }),\n ),\n catchError((error) => {\n state.set('setUsersError', setUsersError(group$.key, error))\n return EMPTY\n }),\n tap((response) => state.set('setUsersData', setUsersData(group$.key, response))),\n )\n }),\n ),\n ),\n )\n .subscribe({error: errorHandler(state)})\n}\n\n/**\n * Returns the state source for users associated with a specific resource.\n *\n * This function returns a state source that represents the current list of users for a given\n * resource. Subscribing to the state source will instruct the SDK to fetch the users (if not\n * already fetched) and will load more from this state source as well. When the last subscriber is\n * removed, the users state is automatically cleaned up from the store after a delay.\n *\n * Note: This functionality is for advanced users who want to build their own framework\n * integrations. Our SDK also provides a React integration for convenient usage.\n *\n * @beta\n */\nexport const getUsersState = bindActionGlobally(\n usersStore,\n createStateSourceAction({\n selector: createSelector(\n [\n ({instance, state}: SelectorContext<UsersStoreState>, options?: GetUsersOptions) =>\n state.error ?? state.users[getUsersKey(instance, options)]?.error,\n ({instance, state}: SelectorContext<UsersStoreState>, options: GetUsersOptions) =>\n state.users[getUsersKey(instance, options)]?.users,\n ({instance, state}: SelectorContext<UsersStoreState>, options: GetUsersOptions) =>\n state.users[getUsersKey(instance, options)]?.totalCount,\n ({instance, state}: SelectorContext<UsersStoreState>, options: GetUsersOptions) =>\n state.users[getUsersKey(instance, options)]?.nextCursor,\n ],\n (error, data, totalCount, nextCursor) => {\n if (error) throw error\n if (data === undefined || totalCount === undefined || nextCursor === undefined) {\n return undefined\n }\n\n return {data, totalCount, hasMore: nextCursor !== null}\n },\n ),\n onSubscribe: ({instance, state}, options?: GetUsersOptions) => {\n const subscriptionId = insecureRandomId()\n const key = getUsersKey(instance, options)\n state.set('addSubscription', addSubscription(subscriptionId, key))\n return () => {\n setCleanupTimeout(\n () => state.set('removeSubscription', removeSubscription(subscriptionId, key)),\n USERS_STATE_CLEAR_DELAY,\n )\n }\n },\n }),\n)\n\n/**\n * Resolves the users for a specific resource without registering a lasting subscriber.\n *\n * This function fetches the users for a given resource and returns a promise that resolves with\n * the users result. Unlike `getUsersState`, which registers subscribers to keep the data live and\n * performs automatic cleanup, `resolveUsers` does not track subscribers. This makes it ideal for\n * use with React Suspense, where the returned promise is thrown to delay rendering until the users\n * result becomes available. Once the promise resolves, it is expected that a real subscriber will\n * be added via `getUsersState` to manage ongoing updates.\n *\n * Additionally, an optional AbortSignal can be provided to cancel the request and immediately\n * clear the associated state if there are no active subscribers.\n *\n * @beta\n */\nexport const resolveUsers = bindActionGlobally(\n usersStore,\n async ({state, instance}, {signal, ...options}: ResolveUsersOptions) => {\n const key = getUsersKey(instance, options)\n const {getCurrent} = getUsersState(instance, options)\n\n const aborted$ = signal\n ? new Observable<never>((observer) => {\n const cleanup = () => {\n signal.removeEventListener('abort', listener)\n }\n\n const listener = () => {\n observer.error(new DOMException('The operation was aborted.', 'AbortError'))\n observer.complete()\n cleanup()\n }\n signal.addEventListener('abort', listener)\n\n return cleanup\n }).pipe(\n catchError((error) => {\n if (error instanceof Error && error.name === 'AbortError') {\n state.set('cancelRequest', cancelRequest(key))\n }\n throw error\n }),\n )\n : NEVER\n\n state.set('initializeRequest', initializeRequest(key))\n\n const resolved$ = state.observable.pipe(\n map(getCurrent),\n first((i) => i !== undefined),\n )\n\n return firstValueFrom(race([resolved$, aborted$]))\n },\n)\n\n/**\n * Loads more users for a specific resource.\n *\n * This function triggers a request to fetch the next page of users for a given resource. It\n * requires that users have already been loaded for the resource (via `resolveUsers` or\n * `getUsersState`), and that there are more users available to load (as indicated by the `hasMore`\n * property).\n *\n * The function returns a promise that resolves when the next page of users has been loaded.\n *\n * @beta\n */\nexport const loadMoreUsers = bindActionGlobally(\n usersStore,\n async ({state, instance}, options?: GetUsersOptions) => {\n const key = getUsersKey(instance, options)\n const users = getUsersState(instance, options)\n const usersState = users.getCurrent()\n if (!usersState) {\n throw new Error('Users not loaded for specified resource. Please call resolveUsers first.')\n }\n\n if (!usersState.hasMore) {\n throw new Error('No more users available to load for this resource.')\n }\n\n const promise = firstValueFrom(\n users.observable.pipe(\n filter((i) => i !== undefined),\n skip(1),\n ),\n )\n\n const timestamp = new Date().toISOString()\n state.set('updateLastLoadMoreRequest', updateLastLoadMoreRequest(timestamp, key))\n\n return await promise\n },\n)\n\n/**\n * @beta\n */\nexport const getUserState = bindActionGlobally(\n usersStore,\n ({instance}, {userId, ...options}: GetUserOptions) => {\n return getUsersState(instance, {userId, ...options}).observable.pipe(\n map((res) => res?.data[0]),\n distinctUntilChanged((a, b) => a?.profile.updatedAt === b?.profile.updatedAt),\n )\n },\n)\n\n/**\n * @beta\n */\nexport const resolveUser = bindActionGlobally(\n usersStore,\n async ({instance}, {signal, ...options}: ResolveUserOptions) => {\n const result = await resolveUsers(instance, {\n signal,\n ...options,\n })\n return result?.data[0]\n },\n)\n","import {type BifurClient, fromUrl} from '@sanity/bifur-client'\nimport {type SanityClient} from '@sanity/client'\nimport {defer, EMPTY, fromEvent, merge, type Observable, timer} from 'rxjs'\nimport {catchError, distinctUntilChanged, map, retry, share, switchMap} from 'rxjs/operators'\n\nimport {\n type BifurTransportOptions,\n type PresenceLocation,\n type PresenceTransport,\n type TransportEvent,\n type TransportMessage,\n} from './types'\n\n/**\n * Longest gap between reconnection attempts, matching the Studio's presence\n * transport so both behave the same way on a flaky connection.\n */\nconst CONNECT_RETRY_MAX_DELAY = 1000 * 240\n\ntype BifurStateMessage = {\n type: 'state'\n i: string\n m: {\n sessionId: string\n locations: PresenceLocation[]\n }\n}\n\ntype BifurDisconnectMessage = {\n type: 'disconnect'\n i: string\n m: {session: string}\n}\n\ntype RollCallEvent = {\n type: 'rollCall'\n i: string\n session: string\n}\n\ntype IncomingBifurEvent = RollCallEvent | BifurStateMessage | BifurDisconnectMessage\n\nfunction getBifurClient(client: SanityClient, token$: Observable<string | null>): BifurClient {\n const bifurVersionedClient = client.withConfig({apiVersion: '2022-06-30'})\n const {\n resource,\n dataset,\n url: baseUrl,\n requestTagPrefix = 'sanity.sdk.presence',\n } = bifurVersionedClient.config()\n\n let resourcePath: string\n if (resource?.type === 'canvas') {\n resourcePath = `canvases/${resource.id}`\n } else if (dataset) {\n // Dataset clients use project hostname — dataset name alone is the socket path\n resourcePath = dataset\n } else {\n throw new Error(`Unable to determine presence URL: no canvas resource or dataset configured`)\n }\n\n const url = `${baseUrl}/socket/${resourcePath}`.replace(/^http/, 'ws')\n\n const urlWithTag = `${url}?tag=${requestTagPrefix}`\n\n return fromUrl(urlWithTag, {token$})\n}\n\nconst handleIncomingMessage = (event: IncomingBifurEvent): TransportEvent => {\n switch (event.type) {\n case 'rollCall':\n return {\n type: 'rollCall',\n userId: event.i,\n sessionId: event.session,\n }\n case 'state': {\n const {sessionId, locations} = event.m\n return {\n type: 'state',\n userId: event.i,\n sessionId,\n timestamp: new Date().toISOString(),\n locations,\n }\n }\n case 'disconnect':\n return {\n type: 'disconnect',\n userId: event.i,\n sessionId: event.m.session,\n timestamp: new Date().toISOString(),\n }\n default: {\n throw new Error(`Got unknown presence event: ${JSON.stringify(event)}`)\n }\n }\n}\n\n/**\n * Emits an incrementing generation number each time the socket becomes live.\n *\n * `@sanity/bifur-client` does not reconnect on its own — it errors the stream\n * when the socket closes. Without the `retry` below, presence stops for the\n * life of the page after the first dropped connection.\n */\nconst createConnections = (bifur: BifurClient): Observable<number> => {\n let generation = 0\n\n return defer(() => {\n const current = ++generation\n // `heartbeats` emits as soon as the socket is open and authorized, then on\n // every server heartbeat and every response. Subscribing to it is also what\n // keeps the socket alive between requests.\n return bifur.heartbeats.pipe(map(() => current))\n }).pipe(\n retry({\n delay: (_error, retryCount) =>\n timer(Math.min(CONNECT_RETRY_MAX_DELAY, 2 ** retryCount * 100)),\n resetOnSuccess: true,\n }),\n // After `retry` so that one operator instance spans reconnects, making each\n // live socket yield exactly one emission.\n distinctUntilChanged(),\n share(),\n )\n}\n\n/**\n * Presence events from everyone else in the room, re-established on every live\n * connection.\n *\n * A socket close errors this stream just as it errors the heartbeats, so without\n * re-subscribing the client would keep announcing itself after a reconnect while\n * never hearing from anyone again. Driving it from `connections$` rather than\n * giving it its own `retry` keeps a single reconnect loop, instead of two\n * independent backoffs racing over one refcounted socket.\n */\nconst createIncomingEvents = (\n bifur: BifurClient,\n connections$: Observable<number>,\n): Observable<TransportEvent> =>\n connections$.pipe(\n switchMap(() =>\n bifur.listen<IncomingBifurEvent>('presence').pipe(\n // Let a dead listener go quietly. The next connection replaces it, and\n // surfacing the error here would tear down the reconnect loop with it.\n catchError(() => EMPTY),\n ),\n ),\n map(handleIncomingMessage),\n share(),\n )\n\n/**\n * Emits when the page is going away. `pagehide` is needed alongside\n * `beforeunload` because iOS Safari and pages entering the back/forward cache\n * never fire `beforeunload`.\n */\nconst createUnload = (): Observable<void> => {\n if (typeof window === 'undefined') return EMPTY\n\n return merge(fromEvent(window, 'beforeunload'), fromEvent(window, 'pagehide')).pipe(\n map(() => undefined),\n )\n}\n\nexport const createBifurTransport = (options: BifurTransportOptions): PresenceTransport => {\n const {client, token$, sessionId} = options\n const bifur = getBifurClient(client, token$)\n\n const connections$ = createConnections(bifur)\n const incomingEvents$ = createIncomingEvents(bifur, connections$)\n\n const dispatchMessage = (message: TransportMessage): Observable<void> => {\n switch (message.type) {\n case 'rollCall':\n return bifur.request('presence_rollcall', {session: sessionId})\n case 'state':\n return bifur.request('presence_announce', {\n data: {locations: message.locations, sessionId},\n })\n case 'disconnect':\n return bifur.request('presence_disconnect', {session: sessionId})\n default: {\n return EMPTY\n }\n }\n }\n\n return [incomingEvents$, dispatchMessage, connections$, createUnload()]\n}\n","import {type IndexTuple, type KeyedSegment, type Path, type PathSegment} from '@sanity/types'\n\n/**\n * Segments are not always strings, despite what `PresenceLocation.path` declares.\n * Array items arrive as `{_key}` and Portable Text spans as a mix of keys and\n * property names, because that is what the Studio sends.\n */\nfunction isKeyedSegment(segment: PathSegment): segment is KeyedSegment {\n return (\n typeof segment === 'object' && segment !== null && !Array.isArray(segment) && '_key' in segment\n )\n}\n\n/**\n * Index tuples (`[from, to]`) only occur in slice selections, which presence never\n * reports. Compared structurally rather than assumed absent.\n */\nfunction isEqualTuple(a: IndexTuple, b: IndexTuple): boolean {\n return a.length === b.length && a.every((value, index) => value === b[index])\n}\n\n/** Compares two path segments, whatever shape they arrive in. */\nfunction isEqualSegment(a: PathSegment, b: PathSegment): boolean {\n if (a === b) return true\n if (isKeyedSegment(a) && isKeyedSegment(b)) return a._key === b._key\n if (Array.isArray(a) && Array.isArray(b)) return isEqualTuple(a, b)\n return false\n}\n\n/**\n * True when `candidate` is at or below `prefix` in the document tree.\n *\n * Equivalent to `startsWith` from the Studio's `@sanity/util/paths`, which is not\n * an SDK dependency.\n *\n * @internal\n */\nexport function startsWithPath(prefix: Path, candidate: Path): boolean {\n if (prefix.length > candidate.length) return false\n return prefix.every((segment, index) => isEqualSegment(segment, candidate[index]))\n}\n","import {DocumentId, getPublishedId} from '@sanity/id-utils'\nimport {type Path} from '@sanity/types'\nimport {createSelector} from 'reselect'\nimport {\n auditTime,\n catchError,\n combineLatest,\n distinctUntilChanged,\n EMPTY,\n filter,\n first,\n map,\n merge,\n type Observable,\n of,\n Subscription,\n switchMap,\n timer,\n withLatestFrom,\n} from 'rxjs'\n\nimport {getTokenState} from '../auth/authStore'\nimport {getClient} from '../client/clientStore'\nimport {\n type DocumentResource,\n isCanvasResource,\n isDatasetResource,\n isMediaLibraryResource,\n} from '../config/sanityConfig'\nimport {getEditingDocumentId} from '../document/util'\nimport {bindActionByResource, type BoundResourceKey} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {\n createStateSourceAction,\n type SelectorContext,\n type StateSource,\n} from '../store/createStateSourceAction'\nimport {defineStore, type StoreContext} from '../store/defineStore'\nimport {type SanityUser} from '../users/types'\nimport {getUserState} from '../users/usersStore'\nimport {createLogger} from '../utils/logger'\nimport {createBifurTransport} from './bifurTransport'\nimport {startsWithPath} from './paths'\nimport {\n type DocumentPresence,\n type DocumentPresenceOptions,\n type PresenceLocation,\n type ReportPresenceOptions,\n type TransportEvent,\n type TransportMessage,\n type UserPresence,\n type WirePresenceLocation,\n} from './types'\n\nconst logger = createLogger('presence')\n\n/**\n * Used for the canvas organization lookup only. The socket itself is pinned to\n * `2022-06-30` in `bifurTransport`, because that is the version Bifur compares\n * against when deciding whether a connection may authenticate over RPC rather\n * than requiring a JWT at upgrade. Do not align these two.\n */\nconst PRESENCE_API_VERSION = '2026-03-30'\n\n/**\n * How often the current user re-announces while idle. Matches the Studio so the\n * two agree on how long a quiet peer should be trusted.\n */\nconst REPORT_MIN_INTERVAL = 30_000\n\n/** Collapses a burst of focus changes into a single announcement. */\nconst REPORT_AUDIT_TIME = 200\n\n/**\n * How long a session may go without announcing before it is dropped. Bifur\n * publishes nothing when a peer's socket dies, so a peer that crashes, is\n * force-quit, or loses power would otherwise stay visible forever.\n *\n * Peers re-announce every 30 seconds, so this allows three missed announcements.\n */\nconst SESSION_TTL = 90_000\n\n/** How often to look for sessions that have gone quiet. */\nconst SWEEP_INTERVAL = 15_000\n\ntype PresenceSession = {\n userId: string\n locations: PresenceLocation[]\n /**\n * When we last heard from this session, on our own clock. Used for expiry in\n * preference to the sender's `lastActiveAt`, which is subject to clock skew:\n * a peer whose clock runs slow would otherwise be expired immediately, and one\n * whose clock runs fast would never be expired at all.\n */\n lastSeenAt: number\n}\n\ntype PresenceStoreState = {\n locations: Map<string, PresenceSession>\n users: Record<string, SanityUser | undefined>\n organizationId?: string\n /**\n * Set when the canvas organization lookup fails. Without it, consumers waiting\n * on `organizationId` would wait forever.\n */\n organizationIdError?: unknown\n /**\n * Where this client says it is. `undefined` means the app has never reported,\n * which keeps it silent: reading presence must not make an app start\n * broadcasting. An empty array is different, and means \"here, but not in any\n * particular document\".\n */\n localLocations?: WirePresenceLocation[]\n}\n\nconst getInitialState = (): PresenceStoreState => ({\n locations: new Map<string, PresenceSession>(),\n users: {},\n})\n\n/**\n * Sends a message without letting a failure tear down the stream it was sent on.\n *\n * This matters most for the announce pipeline, which carries the idle heartbeat,\n * roll-call responses, and the re-announce on reconnect. Those share one chain, so\n * an unhandled error from a single rejected RPC would silence this client\n * permanently while it carried on reading presence normally. A dropped socket\n * errors the in-flight request, which is exactly the case where staying alive\n * matters, since the reconnect that follows is what makes us visible again.\n *\n * No retry is needed here. The 30 second heartbeat sends again on its own, and a\n * recovered connection triggers an immediate re-announce.\n */\nconst sendSafely = (\n dispatch: (message: TransportMessage) => Observable<void>,\n message: TransportMessage,\n): Observable<void> =>\n dispatch(message).pipe(\n catchError((error: unknown) => {\n logger.warn('Failed to send presence message', {messageType: message.type, error})\n return EMPTY\n }),\n )\n\n/**\n * Reduces a stream to a bare trigger that cannot fail.\n *\n * The announce pipeline combines three inputs with `merge`, which propagates an\n * error from any one of them. Since that one pipeline carries the idle heartbeat,\n * roll-call responses, and the re-announce on reconnect, a single failing input\n * would silence this client for good. Losing one trigger is survivable; losing\n * all three is not.\n */\nconst asTrigger = (source$: Observable<unknown>, name: string): Observable<void> =>\n source$.pipe(\n map(() => undefined),\n catchError((error: unknown) => {\n logger.error('Presence announce trigger failed', {trigger: name, error})\n return EMPTY\n }),\n )\n\n/** Ignores `lastActiveAt`, which changes on every report even when nothing moved. */\nconst locationKey = ({documentId, path, selection}: WirePresenceLocation) =>\n JSON.stringify([documentId, path, selection ?? null])\n\n/**\n * Compares reported locations by value. Key order within a caller-supplied\n * `selection` could in principle differ and read as a change, which costs one\n * extra announcement and nothing else.\n */\nfunction isEqualLocations(\n a: WirePresenceLocation[] | undefined,\n b: WirePresenceLocation[] | undefined,\n): boolean {\n if (a === b) return true\n if (!a || !b || a.length !== b.length) return false\n return a.every((location, index) => locationKey(location) === locationKey(b[index]))\n}\n\n/** @public */\nexport const presenceStore = defineStore<PresenceStoreState, BoundResourceKey>({\n name: 'presence',\n getInitialState,\n initialize: (context: StoreContext<PresenceStoreState, BoundResourceKey>) => {\n const {\n instance,\n state,\n key: {resource},\n } = context\n\n if (isMediaLibraryResource(resource)) {\n throw new Error('Presence is not supported for media library resources.')\n }\n\n // A fresh id per store, deliberately not persisted. Reusing an id across\n // page loads would collide whenever a tab inherits another's session\n // storage (`window.open`, or a same-origin iframe), making two live clients\n // filter each other out as self. Stale sessions are handled by the\n // disconnect on unload, with the expiry sweep above as the backstop.\n const sessionId = crypto.randomUUID()\n\n // Dataset resources must use the project hostname so the socket URL is project-specific.\n // Canvas resources use the global API endpoint via the resource config.\n const client = isDatasetResource(resource)\n ? getClient(instance, {\n apiVersion: PRESENCE_API_VERSION,\n projectId: resource.projectId,\n dataset: resource.dataset,\n useProjectHostname: true,\n })\n : getClient(instance, {\n apiVersion: PRESENCE_API_VERSION,\n resource,\n })\n\n const token$ = getTokenState(instance).observable.pipe(distinctUntilChanged())\n\n const [incomingEvents$, dispatch, connections$, unload$] = createBifurTransport({\n client,\n token$,\n sessionId,\n })\n\n const subscription = new Subscription()\n\n // Subscribed before the roll call below, deliberately. The transport\n // establishes its listener when this stream is subscribed, and a roll call\n // sent before we are listening would have its answers arrive to no one.\n subscription.add(\n incomingEvents$.subscribe({\n next: (event: TransportEvent) => {\n if ('sessionId' in event && event.sessionId === sessionId) {\n return\n }\n\n if (event.type === 'state') {\n state.set('presence/state', (prevState: PresenceStoreState) => {\n const newLocations = new Map(prevState.locations)\n newLocations.set(event.sessionId, {\n userId: event.userId,\n locations: event.locations,\n lastSeenAt: Date.now(),\n })\n\n return {\n ...prevState,\n locations: newLocations,\n }\n })\n } else if (event.type === 'disconnect') {\n state.set('presence/disconnect', (prevState: PresenceStoreState) => {\n const newLocations = new Map(prevState.locations)\n newLocations.delete(event.sessionId)\n return {...prevState, locations: newLocations}\n })\n }\n },\n // The transport re-establishes its listener on every live connection, so\n // this should not fire. Handled rather than left to become an unhandled\n // error, which is how presence used to die silently and for good.\n error: (error: unknown) => {\n logger.error('Presence event stream failed', {error})\n },\n }),\n )\n\n // Subscribing keeps the socket alive and reconnects it with backoff. Each\n // emission is a freshly live connection: anything we accumulated is now\n // suspect, so start over and ask everyone to announce themselves again.\n subscription.add(\n connections$.subscribe(() => {\n state.set('presence/reset', (prevState) => ({\n ...prevState,\n locations: new Map<string, PresenceSession>(),\n }))\n sendSafely(dispatch, {type: 'rollCall'}).subscribe()\n }),\n )\n\n // Restarted per connection so a long reconnect backoff does not expire\n // everyone while we are offline — reconnecting clears the map anyway.\n //\n // Uses an rxjs timer rather than `setCleanupTimeout`, despite the guidance in\n // core-package-conventions, because this is a recurring sweep and not a\n // cleanup timer. Unref'ing it would not help anyway: a live presence\n // subscription holds an open WebSocket, and that is what keeps a Node process\n // alive. Anything running server-side should not subscribe to presence at all.\n subscription.add(\n connections$.pipe(switchMap(() => timer(SWEEP_INTERVAL, SWEEP_INTERVAL))).subscribe(() => {\n state.set('presence/expire', (prevState) => {\n const cutoff = Date.now() - SESSION_TTL\n const stale = [...prevState.locations].filter(([, s]) => s.lastSeenAt < cutoff)\n if (stale.length === 0) return prevState\n\n const newLocations = new Map(prevState.locations)\n for (const [staleSessionId] of stale) newLocations.delete(staleSessionId)\n return {...prevState, locations: newLocations}\n })\n }),\n )\n\n subscription.add(\n unload$.pipe(switchMap(() => sendSafely(dispatch, {type: 'disconnect'}))).subscribe(),\n )\n\n // Announce where we are. A location change, a peer asking for a roll call, or\n // a reconnect all restart `timer(0, ...)`, so we announce immediately and then\n // every 30s while idle. That idle tick is what tells peers we are still here,\n // and is what their expiry sweep measures against.\n const localLocations$ = state.observable.pipe(\n map((s) => s.localLocations),\n // Compared by value, not by reference. The Studio compares by reference and\n // so never dedupes, because its form rebuilds the array on every call.\n distinctUntilChanged(isEqualLocations),\n )\n\n const rollCallRequests$ = incomingEvents$.pipe(\n // Bifur echoes our own roll call back to us, since we are subscribed to the\n // same topic we published to. Answering it would be a pointless round trip.\n filter((event) => event.type === 'rollCall' && event.sessionId !== sessionId),\n )\n\n subscription.add(\n merge(\n asTrigger(localLocations$, 'locationChange'),\n asTrigger(rollCallRequests$, 'rollCall'),\n asTrigger(connections$, 'connection'),\n )\n .pipe(\n switchMap(() => timer(0, REPORT_MIN_INTERVAL)),\n withLatestFrom(localLocations$),\n map(([, locations]) => locations),\n // Stay silent until the app has reported at least once.\n filter((locations): locations is WirePresenceLocation[] => locations !== undefined),\n auditTime(REPORT_AUDIT_TIME),\n switchMap((locations) => sendSafely(dispatch, {type: 'state', locations})),\n )\n .subscribe(),\n )\n\n // Resolve display names for everyone we can see.\n //\n // This belongs to the store rather than to one state source: it is driven by\n // which user ids are in state, and every selector needs it. It used to hang off\n // `getPresence`'s `onSubscribe`, which meant anything reading presence another\n // way saw only \"Unknown user\".\n const userIds$ = state.observable.pipe(\n map((s) =>\n Array.from(s.locations.values())\n .map((l) => l.userId)\n .filter((id): id is string => !!id),\n ),\n distinctUntilChanged((a, b) => a.length === b.length && a.every((v, i) => v === b[i])),\n )\n\n // For canvas resources, wait for the organizationId to arrive. A failed lookup\n // resolves to `undefined` rather than never emitting, so one failed request\n // does not leave every user permanently unresolved. Dataset resources emit\n // immediately so the stream is never blocked.\n const organizationId$: Observable<string | undefined> = isCanvasResource(resource)\n ? state.observable.pipe(\n filter((s) => s.organizationId !== undefined || s.organizationIdError !== undefined),\n first(),\n map((s) => s.organizationId),\n )\n : of(undefined)\n\n subscription.add(\n combineLatest([userIds$, organizationId$])\n .pipe(\n switchMap(([userIds, organizationId]) => {\n if (userIds.length === 0) {\n return of([])\n }\n // Without an organization there is nothing to scope the lookup to, so\n // skip the request rather than making one that cannot succeed.\n if (!isDatasetResource(resource) && !organizationId) {\n return of([])\n }\n const userObservables = userIds.map((userId) =>\n getUserState(instance, {\n userId,\n ...(isDatasetResource(resource)\n ? {resourceType: 'project', projectId: resource.projectId}\n : {resourceType: 'organization', organizationId}),\n }).pipe(filter((v): v is NonNullable<typeof v> => !!v)),\n )\n return combineLatest(userObservables)\n }),\n )\n .subscribe((users) => {\n state.set('presence/users', (prevState) => ({\n ...prevState,\n users: {\n ...prevState.users,\n ...users.reduce<Record<string, SanityUser>>((acc, user) => {\n if (user) {\n acc[user.profile.id] = user\n }\n return acc\n }, {}),\n },\n }))\n }),\n )\n\n // Canvas resources need the organizationId to resolve users — fetch it once from the canvas endpoint\n if (isCanvasResource(resource)) {\n const globalClient = getClient(instance, {apiVersion: PRESENCE_API_VERSION})\n subscription.add(\n globalClient.observable\n .request<{organizationId: string}>({\n uri: `/canvases/${resource.canvasId}`,\n tag: 'canvases.get',\n })\n .subscribe({\n next: ({organizationId}) => {\n state.set('presence/organizationId', (prev) => ({...prev, organizationId}))\n },\n error: (organizationIdError: unknown) => {\n state.set('presence/organizationIdError', (prev) => ({...prev, organizationIdError}))\n },\n }),\n )\n }\n\n return () => {\n sendSafely(dispatch, {type: 'disconnect'}).subscribe()\n subscription.unsubscribe()\n }\n },\n})\n\nconst selectLocations = (state: PresenceStoreState) => state.locations\nconst selectUsers = (state: PresenceStoreState) => state.users\n\n/**\n * Stands in for a participant whose profile has not resolved yet, or cannot be\n * resolved. This must be a structurally valid `SanityUser`: consumers read\n * `user.profile`, and a partial object would throw there on first render.\n */\nconst createUnresolvedUser = (userId: string): SanityUser => ({\n sanityUserId: userId,\n profile: {\n id: userId,\n displayName: 'Unknown user',\n email: '',\n provider: '',\n createdAt: '',\n },\n memberships: [],\n})\n\nconst selectPresence = createSelector(\n selectLocations,\n selectUsers,\n (locations, users): UserPresence[] => {\n return Array.from(locations.entries()).map(([sessionId, {userId, locations: locs}]) => ({\n user: users[userId] || createUnresolvedUser(userId),\n sessionId,\n locations: locs,\n }))\n },\n)\n\n/**\n * Results per state object, then per query.\n *\n * `createStateSourceAction` runs its selector afresh on every `getCurrent()`, and\n * `getCurrent` is what React's `useSyncExternalStore` calls as its snapshot. A\n * selector that builds a new array each call therefore sends React into an\n * infinite render loop, which is why the store docs point at memoized selectors.\n *\n * A single `reselect` memo slot is not enough here, because the selector is\n * parameterised per document and callers watching different documents would\n * evict each other. Keyed on the state object, which is replaced on every change,\n * so entries are collected once that state is unreachable.\n */\nconst documentPresenceCache = new WeakMap<PresenceStoreState, Map<string, DocumentPresence[]>>()\n\n/** Flattens the session map down to one document. */\nfunction selectDocumentPresence(\n state: PresenceStoreState,\n options: DocumentPresenceOptions,\n): DocumentPresence[] {\n const cacheKey = JSON.stringify([\n getEditingDocumentId(options),\n options.path ?? null,\n options.excludeVersions ?? false,\n ])\n\n let perState = documentPresenceCache.get(state)\n if (!perState) {\n perState = new Map<string, DocumentPresence[]>()\n documentPresenceCache.set(state, perState)\n }\n\n const cached = perState.get(cacheKey)\n if (cached) return cached\n\n const computed = computeDocumentPresence(state, options)\n perState.set(cacheKey, computed)\n return computed\n}\n\n/**\n * The id a query and a location are compared on. Exact when `excludeVersions` is\n * set, otherwise normalized so a draft, its published version, and any release\n * version count as one document.\n */\nconst scopeId = (documentId: string, excludeVersions: boolean | undefined): string =>\n excludeVersions ? documentId : getPublishedId(DocumentId(documentId))\n\n/**\n * Declared `string[]`, actually a `Path`. See the note on\n * {@link PresenceLocation.path}; `DocumentPresence.path` reports it honestly.\n */\nconst pathOf = (location: PresenceLocation): Path => location.path as unknown as Path\n\nfunction matchesQuery(\n location: PresenceLocation,\n target: string,\n {path, excludeVersions}: DocumentPresenceOptions,\n): boolean {\n if (scopeId(location.documentId, excludeVersions) !== target) return false\n return !path || startsWithPath(path, pathOf(location))\n}\n\nfunction toDocumentPresence(\n users: PresenceStoreState['users'],\n sessionId: string,\n userId: string,\n location: PresenceLocation,\n): DocumentPresence {\n return {\n user: users[userId] || createUnresolvedUser(userId),\n sessionId,\n documentId: location.documentId,\n path: pathOf(location),\n lastActiveAt: location.lastActiveAt,\n ...(location.selection === undefined ? {} : {selection: location.selection}),\n }\n}\n\nfunction computeDocumentPresence(\n state: PresenceStoreState,\n options: DocumentPresenceOptions,\n): DocumentPresence[] {\n // Resolved before scoping, and identically to the write side, or a query for a\n // document would not match the client reporting it.\n const target = scopeId(getEditingDocumentId(options), options.excludeVersions)\n\n return Array.from(state.locations).flatMap(([sessionId, session]) =>\n session.locations\n .filter((location) => matchesQuery(location, target, options))\n .map((location) => toDocumentPresence(state.users, sessionId, session.userId, location)),\n )\n}\n\nconst _getPresence = bindActionByResource(\n presenceStore,\n createStateSourceAction({\n selector: (context: SelectorContext<PresenceStoreState>): UserPresence[] =>\n selectPresence(context.state),\n }),\n)\n\n/** @beta */\nexport function getPresence(\n instance: SanityInstance,\n params?: {resource?: DocumentResource},\n): StateSource<UserPresence[]> {\n // bit of a hack to support the old bound action by dataset\n // in reality, this will always be passed a resource\n return _getPresence(instance, params ?? {})\n}\n\nconst _getDocumentPresence = bindActionByResource(\n presenceStore,\n createStateSourceAction({\n selector: (\n {state}: SelectorContext<PresenceStoreState>,\n options: {resource?: DocumentResource} & DocumentPresenceOptions,\n ): DocumentPresence[] => selectDocumentPresence(state, options),\n }),\n)\n\n/**\n * Presence within a single document, flattened to one entry per participant per\n * location so it can be rendered directly against a field.\n *\n * Reading presence never announces anything. Use `reportPresence` to make the\n * current user visible to others.\n *\n * @param instance - the Sanity instance\n * @param params - the document to look at, its perspective, an optional `path` to\n * narrow to a field subtree, and `excludeVersions` to compare document ids exactly\n *\n * @beta\n */\nexport function getDocumentPresence(\n instance: SanityInstance,\n params: {resource?: DocumentResource} & DocumentPresenceOptions,\n): StateSource<DocumentPresence[]> {\n return _getDocumentPresence(instance, params)\n}\n\nconst _reportPresence = bindActionByResource(\n presenceStore,\n (\n {state}: StoreContext<PresenceStoreState, BoundResourceKey>,\n {locations}: {resource?: DocumentResource; locations: ReportPresenceOptions[]},\n ) => {\n const lastActiveAt = new Date().toISOString()\n const wireLocations: WirePresenceLocation[] = locations.map((location) => ({\n type: 'document',\n // The specific document being edited, not the canonical id. Other clients,\n // the Studio included, compare exact ids for field-level presence.\n documentId: getEditingDocumentId(location),\n path: location.path ?? [],\n lastActiveAt,\n ...(location.selection === undefined ? {} : {selection: location.selection}),\n }))\n\n state.set('presence/report', (prevState) => ({...prevState, localLocations: wireLocations}))\n },\n)\n\n/**\n * Announces where the current user is, so other clients in the same project and\n * dataset can show them. Reading presence never announces anything, so this is\n * the only way an app becomes visible to others.\n *\n * Call it again whenever the user moves. Announcements are collapsed over a short\n * window and then repeated every 30 seconds while idle, which is what tells peers\n * the session is still alive.\n *\n * Which specific document each location resolves to depends on its perspective, and\n * that matters for interoperability: other clients, the Studio included, compare\n * exact document ids for field-level presence. Pass the perspective you are editing\n * under rather than building a draft or version id yourself.\n *\n * @param instance - the Sanity instance\n * @param params - the resource to announce on, plus the locations to report.\n * Pass one location with a `documentId` for document-level presence, add a\n * `path` for field-level presence, and pass an empty array to appear present\n * without being in any document.\n *\n * @beta\n */\nexport function reportPresence(\n instance: SanityInstance,\n params: {resource?: DocumentResource; locations: ReportPresenceOptions[]},\n): void {\n return _reportPresence(instance, params)\n}\n","export function hashString(str: string): string {\n // Using a large prime number for the hash\n const PRIME = 31\n // Using a max 32-bit integer to prevent overflow\n const MOD = 2147483647\n\n let hash = 0\n\n // Process chunks of the string to reduce complexity\n for (let i = 0; i < str.length; i++) {\n // Rolling hash computation\n hash = (hash * PRIME + str.charCodeAt(i)) % MOD\n }\n\n // Ensure we return a positive hash\n return Math.abs(hash).toString(16).padStart(8, '0')\n}\n","export const PROJECTION_TAG = 'projection'\nexport const PROJECTION_STATE_CLEAR_DELAY = 1000\n\nexport const STABLE_EMPTY_PROJECTION = {\n data: null,\n isPending: false,\n}\n\nexport function validateProjection(projection: string): string {\n if (!projection.startsWith('{') || !projection.endsWith('}')) {\n throw new Error(\n `Invalid projection format: \"${projection}\". Projections must be enclosed in curly braces, e.g. \"{title, 'author': author.name}\"`,\n )\n }\n return projection\n}\n","import {type ClientPerspective} from '@sanity/client'\nimport {DocumentId, getPublishedId} from '@sanity/id-utils'\n\nimport {type ReleasePerspective} from '../config/sanityConfig'\nimport {\n type DocumentProjections,\n type DocumentProjectionValues,\n type ProjectionStoreState,\n} from './types'\nimport {validateProjection} from './util'\n\nexport type ProjectionQueryResult = {\n _id: string\n _type: string\n _updatedAt: string\n result: Record<string, unknown>\n __projectionHash: string\n}\n\ninterface CreateProjectionQueryResult {\n query: string\n params: Record<string, unknown>\n}\n\ntype ProjectionMap = Record<string, {projection: string; documentIds: Set<string>}>\n\nexport function createProjectionQuery(\n documentIds: Set<DocumentId>,\n documentProjections: {[TDocumentId in DocumentId]?: DocumentProjections},\n): CreateProjectionQueryResult {\n const projections = Array.from(documentIds)\n .flatMap((id) => {\n const projectionsForDoc = documentProjections[id]\n if (!projectionsForDoc) return []\n\n return Object.entries(projectionsForDoc).map(([projectionHash, projection]) => ({\n documentId: id,\n projection: validateProjection(projection),\n projectionHash,\n }))\n })\n .reduce<ProjectionMap>((acc, {documentId, projection, projectionHash}) => {\n const obj = acc[projectionHash] ?? {documentIds: new Set(), projection}\n obj.documentIds.add(documentId)\n\n acc[projectionHash] = obj\n return acc\n }, {})\n\n const query = `[${Object.entries(projections)\n .map(([projectionHash, {projection}]) => {\n return `...*[_id in $__ids_${projectionHash}]{_id,_type,_updatedAt,\"__projectionHash\":\"${projectionHash}\",\"result\":{...${projection}}}`\n })\n .join(',')}]`\n\n const params = Object.fromEntries(\n Object.entries(projections).map(([projectionHash, value]) => {\n const idsInProjection = Array.from(value.documentIds).flatMap((id) => DocumentId(id))\n return [`__ids_${projectionHash}`, Array.from(idsInProjection)]\n }),\n )\n\n return {query, params}\n}\n\ninterface ProcessProjectionQueryOptions {\n ids: Set<string>\n results: ProjectionQueryResult[]\n documentStatuses?: ProjectionStoreState['documentStatuses']\n perspective: ClientPerspective | ReleasePerspective\n}\n\nexport function processProjectionQuery({\n ids,\n results,\n documentStatuses,\n}: ProcessProjectionQueryOptions): {\n [TDocumentId in string]?: DocumentProjectionValues<Record<string, unknown>>\n} {\n const groupedResults: {\n [docId: string]: {\n [hash: string]: ProjectionQueryResult | undefined\n }\n } = {}\n\n for (const result of results) {\n const originalId = getPublishedId(DocumentId(result._id))\n const hash = result.__projectionHash\n\n if (!ids.has(originalId)) continue\n\n if (!groupedResults[originalId]) {\n groupedResults[originalId] = {}\n }\n if (!groupedResults[originalId][hash]) {\n groupedResults[originalId][hash] = undefined\n }\n\n groupedResults[originalId][hash] = result\n }\n\n const finalValues: {\n [docId: string]: DocumentProjectionValues<Record<string, unknown>>\n } = {}\n\n for (const originalId of ids) {\n finalValues[originalId] = {}\n\n const projectionsForDoc = groupedResults[originalId]\n if (!projectionsForDoc) continue\n\n for (const hash in projectionsForDoc) {\n const projectionResult = projectionsForDoc[hash]\n const projectionResultData = projectionResult?.result\n\n if (!projectionResultData) {\n finalValues[originalId][hash] = {data: null, isPending: false}\n continue\n }\n\n const statusFromStore = documentStatuses?.[originalId]\n\n finalValues[originalId][hash] = {\n data: {...projectionResultData, _status: statusFromStore},\n isPending: false,\n }\n }\n }\n\n return finalValues\n}\n","import {\n DocumentId,\n getDraftId,\n getPublishedId,\n getVersionId,\n isDraftId,\n isPublishedId,\n isVersionId,\n} from '@sanity/id-utils'\n\nimport {isReleasePerspective} from '../releases/utils/isReleasePerspective'\nimport {type BoundPerspectiveKey} from '../store/createActionBinder'\nimport {type ProjectionStoreState} from './types'\n\ninterface StatusQueryResult {\n _id: string\n _updatedAt: string\n}\n\n/**\n * Builds an array of document IDs to query for status information using the \"raw\" perspective.\n * Includes draft, published, and version IDs as needed.\n */\nexport function buildStatusQueryIds(\n documentIds: Set<string>,\n perspective: BoundPerspectiveKey['perspective'],\n): string[] {\n const ids: string[] = []\n const releaseName = isReleasePerspective(perspective) ? perspective.releaseName : null\n\n for (const id of documentIds) {\n const publishedId = getPublishedId(DocumentId(id))\n const draftId = getDraftId(publishedId)\n\n // Always query for draft and published versions\n ids.push(draftId, publishedId)\n\n // If it's a release perspective, also query for the version\n if (releaseName) {\n ids.push(getVersionId(publishedId, releaseName))\n }\n }\n\n return ids\n}\n\n/**\n * Processes status query results into documentStatuses (same shape as _status returned to users).\n */\nexport function processStatusQueryResults(\n results: StatusQueryResult[],\n): ProjectionStoreState['documentStatuses'] {\n const documentStatuses: ProjectionStoreState['documentStatuses'] = {}\n\n for (const result of results) {\n const id = DocumentId(result._id)\n const updatedAt = result._updatedAt\n const publishedId = getPublishedId(id)\n const statusData = documentStatuses[publishedId] ?? {}\n if (isDraftId(id)) {\n statusData.lastEditedDraftAt = updatedAt\n } else if (isVersionId(id)) {\n statusData.lastEditedVersionAt = updatedAt\n } else if (isPublishedId(id)) {\n statusData.lastEditedPublishedAt = updatedAt\n }\n documentStatuses[publishedId] = statusData\n }\n\n return documentStatuses\n}\n","import {DocumentId} from '@sanity/id-utils'\nimport {\n combineLatest,\n debounceTime,\n defer,\n distinctUntilChanged,\n EMPTY,\n filter,\n from,\n map,\n Observable,\n pairwise,\n startWith,\n Subscription,\n switchMap,\n tap,\n} from 'rxjs'\n\nimport {getQueryState, resolveQuery} from '../query/queryStore'\nimport {type BoundPerspectiveKey} from '../store/createActionBinder'\nimport {type StoreContext} from '../store/defineStore'\nimport {isDeepEqual} from '../utils/object'\nimport {\n createProjectionQuery,\n processProjectionQuery,\n type ProjectionQueryResult,\n} from './projectionQuery'\nimport {buildStatusQueryIds, processStatusQueryResults} from './statusQuery'\nimport {type ProjectionStoreState} from './types'\nimport {PROJECTION_TAG} from './util'\n\nconst BATCH_DEBOUNCE_TIME = 50\n\nconst isSetEqual = <T>(a: Set<T>, b: Set<T>) =>\n a.size === b.size && Array.from(a).every((i) => b.has(i))\n\ninterface StatusQueryResult {\n _id: string\n _updatedAt: string\n}\n\nexport const subscribeToStateAndFetchBatches = ({\n state,\n instance,\n key: {resource, perspective},\n}: StoreContext<ProjectionStoreState, BoundPerspectiveKey>): Subscription => {\n const documentProjections$ = state.observable.pipe(\n map((s) => s.documentProjections),\n distinctUntilChanged(isDeepEqual),\n )\n\n const activeDocumentIds$ = state.observable.pipe(\n map(({subscriptions}) => new Set(Object.keys(subscriptions).map((id) => DocumentId(id)))),\n distinctUntilChanged(isSetEqual),\n )\n\n const pendingUpdateSubscription = activeDocumentIds$\n .pipe(\n debounceTime(BATCH_DEBOUNCE_TIME),\n startWith(new Set<DocumentId>()),\n pairwise(),\n tap(([prevIds, currIds]) => {\n const newIds = [...currIds].filter((id) => !prevIds.has(id))\n if (newIds.length === 0) return\n\n state.set('updatingPending', (prev) => {\n const nextValues = {...prev.values}\n for (const id of newIds) {\n const projectionsForDoc = prev.documentProjections[id]\n if (!projectionsForDoc) continue\n\n const currentValuesForDoc = prev.values[id] ?? {}\n const updatedValuesForDoc = {...currentValuesForDoc}\n\n for (const hash in projectionsForDoc) {\n const currentValue = updatedValuesForDoc[hash]\n updatedValuesForDoc[hash] = {\n data: currentValue?.data ?? null,\n isPending: true,\n }\n }\n nextValues[id] = updatedValuesForDoc\n }\n return {values: nextValues}\n })\n }),\n )\n .subscribe()\n\n const queryTrigger$ = combineLatest([activeDocumentIds$, documentProjections$]).pipe(\n debounceTime(BATCH_DEBOUNCE_TIME),\n distinctUntilChanged(isDeepEqual),\n )\n\n const queryExecutionSubscription = queryTrigger$\n .pipe(\n switchMap(([ids, documentProjections]) => {\n if (!ids.size) return EMPTY\n const {query, params} = createProjectionQuery(ids, documentProjections)\n const controller = new AbortController()\n\n // Build status query IDs and query\n const statusQueryIds = buildStatusQueryIds(ids, perspective)\n const statusQuery = `*[_id in $statusIds]{_id, _updatedAt}`\n const statusParams = {statusIds: statusQueryIds}\n\n const projectionQuery$ = new Observable<ProjectionQueryResult[]>((observer) => {\n const {getCurrent, observable} = getQueryState<ProjectionQueryResult[]>(instance, {\n ...{\n query,\n params,\n tag: PROJECTION_TAG,\n perspective,\n },\n resource,\n })\n\n const querySource$ = defer(() => {\n if (getCurrent() === undefined) {\n return from(\n resolveQuery<ProjectionQueryResult[]>(instance, {\n ...{\n query,\n params,\n tag: PROJECTION_TAG,\n signal: controller.signal,\n perspective,\n },\n resource,\n }),\n ).pipe(switchMap(() => observable))\n }\n return observable\n }).pipe(filter((result): result is ProjectionQueryResult[] => result !== undefined))\n\n const subscription = querySource$.subscribe(observer)\n\n return () => {\n if (!controller.signal.aborted) {\n controller.abort()\n }\n subscription.unsubscribe()\n }\n })\n\n const statusQuery$ = new Observable<StatusQueryResult[]>((observer) => {\n const {getCurrent, observable} = getQueryState<StatusQueryResult[]>(instance, {\n ...{\n query: statusQuery,\n params: statusParams,\n tag: PROJECTION_TAG,\n perspective: 'raw',\n },\n resource,\n })\n\n const statusQuerySource$ = defer(() => {\n if (getCurrent() === undefined) {\n return from(\n resolveQuery<StatusQueryResult[]>(instance, {\n ...{\n query: statusQuery,\n params: statusParams,\n tag: PROJECTION_TAG,\n signal: controller.signal,\n perspective: 'raw',\n },\n resource,\n }),\n ).pipe(switchMap(() => observable))\n }\n return observable\n }).pipe(filter((result): result is StatusQueryResult[] => result !== undefined))\n\n const subscription = statusQuerySource$.subscribe(observer)\n\n return () => {\n subscription.unsubscribe()\n }\n })\n\n // Combine both streams: emit whenever either has a new value (after both have\n // emitted at least one defined value). This keeps reacting to query store updates.\n return combineLatest([projectionQuery$, statusQuery$]).pipe(\n filter(\n (pair): pair is [ProjectionQueryResult[], StatusQueryResult[]] =>\n pair[0] !== undefined && pair[1] !== undefined,\n ),\n map(([projection, status]) => ({\n data: projection,\n ids,\n statusResults: status,\n })),\n )\n }),\n map(({ids, data, statusResults}) => {\n // Process status results into documentStatuses (same shape as _status returned to users)\n const documentStatuses = processStatusQueryResults(statusResults)\n state.set('updateStatuses', (prev) => ({\n documentStatuses: {\n ...prev.documentStatuses,\n ...documentStatuses,\n },\n }))\n\n // Assemble projection values with _status (buildStatusForDocument in statusQuery)\n const currentState = state.get()\n return processProjectionQuery({\n ids,\n results: data,\n documentStatuses: currentState.documentStatuses,\n perspective: perspective,\n })\n }),\n )\n .subscribe({\n next: (processedValues) => {\n state.set('updateResult', (prev) => {\n const nextValues = {...prev.values}\n for (const docId in processedValues) {\n if (processedValues[docId]) {\n nextValues[docId] = {\n ...(prev.values[docId] ?? {}),\n ...processedValues[docId],\n }\n }\n }\n return {values: nextValues}\n })\n },\n error: (err) => {\n // eslint-disable-next-line no-console\n console.error('Error fetching projection batches:', err)\n // TODO: Potentially update state to reflect error state for affected projections?\n },\n })\n\n return new Subscription(() => {\n pendingUpdateSubscription.unsubscribe()\n queryExecutionSubscription.unsubscribe()\n })\n}\n","import {type BoundPerspectiveKey} from '../store/createActionBinder'\nimport {defineStore} from '../store/defineStore'\nimport {subscribeToStateAndFetchBatches} from './subscribeToStateAndFetchBatches'\nimport {type ProjectionStoreState} from './types'\n\nexport const projectionStore = defineStore<ProjectionStoreState, BoundPerspectiveKey>({\n name: 'Projection',\n getInitialState() {\n return {\n values: {},\n documentProjections: {},\n subscriptions: {},\n documentStatuses: {},\n }\n },\n initialize(context) {\n const batchSubscription = subscribeToStateAndFetchBatches(context)\n return () => batchSubscription.unsubscribe()\n },\n})\n","import {DocumentId, getPublishedId} from '@sanity/id-utils'\nimport {type SanityProjectionResult} from 'groq'\n\nimport {type DocumentHandle} from '../config/sanityConfig'\nimport {bindActionByResourceAndPerspective} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {\n createStateSourceAction,\n type SelectorContext,\n type StateSource,\n} from '../store/createStateSourceAction'\nimport {hashString} from '../utils/hashString'\nimport {insecureRandomId} from '../utils/ids'\nimport {omitProperty} from '../utils/object'\nimport {setCleanupTimeout} from '../utils/setCleanupTimeout'\nimport {projectionStore} from './projectionStore'\nimport {type ProjectionStoreState, type ProjectionValuePending} from './types'\nimport {PROJECTION_STATE_CLEAR_DELAY, STABLE_EMPTY_PROJECTION, validateProjection} from './util'\n\nexport interface ProjectionOptions<\n TProjection extends string = string,\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n> extends DocumentHandle<TDocumentType, TDataset, TProjectId> {\n projection: TProjection\n}\n\n/**\n * @beta\n */\nexport function getProjectionState<\n TProjection extends string = string,\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n instance: SanityInstance,\n options: ProjectionOptions<TProjection, TDocumentType, TDataset, TProjectId>,\n): StateSource<\n | ProjectionValuePending<\n SanityProjectionResult<TProjection, TDocumentType, `${TProjectId}.${TDataset}`>\n >\n | undefined\n>\n\n/**\n * @beta\n */\nexport function getProjectionState<TData extends object>(\n instance: SanityInstance,\n options: ProjectionOptions,\n): StateSource<ProjectionValuePending<TData> | undefined>\n\n/**\n * @beta\n */\nexport function getProjectionState(\n instance: SanityInstance,\n options: ProjectionOptions,\n): StateSource<ProjectionValuePending<Record<string, unknown>> | undefined>\n\n/**\n * @beta\n */\nexport function getProjectionState(\n ...args: Parameters<typeof _getProjectionState>\n): ReturnType<typeof _getProjectionState> {\n return _getProjectionState(...args)\n}\n\n/**\n * @beta\n */\nexport const _getProjectionState = bindActionByResourceAndPerspective(\n projectionStore,\n createStateSourceAction({\n selector: (\n {state}: SelectorContext<ProjectionStoreState>,\n options: ProjectionOptions<string, string, string, string>,\n ): ProjectionValuePending<object> | undefined => {\n const documentId = getPublishedId(DocumentId(options.documentId))\n const projectionHash = hashString(options.projection)\n return state.values[documentId]?.[projectionHash] ?? STABLE_EMPTY_PROJECTION\n },\n onSubscribe: ({state}, options: ProjectionOptions<string, string, string, string>) => {\n const {projection, ...docHandle} = options\n const subscriptionId = insecureRandomId()\n const documentId = getPublishedId(DocumentId(docHandle.documentId))\n const validProjection = validateProjection(projection)\n const projectionHash = hashString(validProjection)\n\n state.set('addSubscription', (prev) => ({\n documentProjections: {\n ...prev.documentProjections,\n [documentId]: {\n ...prev.documentProjections[documentId],\n [projectionHash]: validProjection,\n },\n },\n subscriptions: {\n ...prev.subscriptions,\n [documentId]: {\n ...prev.subscriptions[documentId],\n [projectionHash]: {\n ...prev.subscriptions[documentId]?.[projectionHash],\n [subscriptionId]: true,\n },\n },\n },\n }))\n\n return () => {\n setCleanupTimeout(() => {\n state.set('removeSubscription', (prev): Partial<ProjectionStoreState> => {\n const documentSubscriptionsForHash = omitProperty(\n prev.subscriptions[documentId]?.[projectionHash],\n subscriptionId,\n )\n const hasSubscribersForProjection = !!Object.keys(documentSubscriptionsForHash).length\n\n const nextSubscriptions = {...prev.subscriptions}\n const nextDocumentProjections = {...prev.documentProjections}\n const nextValues = {...prev.values}\n\n // clean up the subscription and documentProjection if there are no subscribers\n if (!hasSubscribersForProjection) {\n delete nextSubscriptions[documentId]![projectionHash]\n delete nextDocumentProjections[documentId]![projectionHash]\n\n const currentProjectionValue = prev.values[documentId]?.[projectionHash]\n if (currentProjectionValue && nextValues[documentId]) {\n nextValues[documentId]![projectionHash] = {\n data: currentProjectionValue.data,\n isPending: false,\n }\n }\n } else {\n if (nextSubscriptions[documentId]) {\n nextSubscriptions[documentId]![projectionHash] = documentSubscriptionsForHash\n }\n }\n\n const hasAnySubscribersForDocument = Object.values(\n nextSubscriptions[documentId] ?? {},\n ).some((subs) => Object.keys(subs).length > 0)\n\n if (!hasAnySubscribersForDocument) {\n delete nextSubscriptions[documentId]\n delete nextDocumentProjections[documentId]\n // Keep nextValues[documentId] as cache\n }\n\n return {\n subscriptions: nextSubscriptions,\n documentProjections: nextDocumentProjections,\n values: nextValues,\n }\n })\n }, PROJECTION_STATE_CLEAR_DELAY)\n }\n },\n }),\n)\n","import {type SanityProjectionResult} from 'groq'\nimport {filter, firstValueFrom} from 'rxjs'\n\nimport {bindActionByResourceAndPerspective} from '../store/createActionBinder'\nimport {type SanityInstance} from '../store/createSanityInstance'\nimport {getProjectionState, type ProjectionOptions} from './getProjectionState'\nimport {projectionStore} from './projectionStore'\nimport {type ProjectionValuePending} from './types'\n\n/** @beta */\nexport function resolveProjection<\n TProjection extends string = string,\n TDocumentType extends string = string,\n TDataset extends string = string,\n TProjectId extends string = string,\n>(\n instance: SanityInstance,\n options: ProjectionOptions<TProjection, TDocumentType, TDataset, TProjectId>,\n): Promise<\n ProjectionValuePending<\n SanityProjectionResult<TProjection, TDocumentType, `${TProjectId}.${TDataset}`>\n >\n>\n\n/** @beta */\nexport function resolveProjection<TData extends object>(\n instance: SanityInstance,\n options: ProjectionOptions,\n): Promise<ProjectionValuePending<TData>>\n\n/** @beta */\nexport function resolveProjection(\n ...args: Parameters<typeof _resolveProjection>\n): ReturnType<typeof _resolveProjection> {\n return _resolveProjection(...args)\n}\n\n/**\n * @beta\n */\nconst _resolveProjection = bindActionByResourceAndPerspective(\n projectionStore,\n (\n {instance}: {instance: SanityInstance},\n options: ProjectionOptions,\n ): Promise<ProjectionValuePending<Record<string, unknown>>> =>\n firstValueFrom(\n getProjectionState<Record<string, unknown>>(instance, options).observable.pipe(\n filter((state): state is ProjectionValuePending<Record<string, unknown>> => !!state?.data),\n ),\n ),\n)\n","import {CorsOriginError} from '@sanity/client'\n\n/**\n * @public\n * Extracts the project ID from a CorsOriginError message.\n * @param error - The error to extract the project ID from.\n * @returns The project ID or null if the error is not a CorsOriginError.\n */\nexport function getCorsErrorProjectId(error: Error): string | null {\n if (!(error instanceof CorsOriginError)) return null\n\n const message = (error as unknown as {message?: string}).message || ''\n const projMatch = message.match(/manage\\/project\\/([^/?#]+)/)\n return projMatch ? projMatch[1] : null\n}\n","/**\n * Returns true when the given error looks like a dynamic-import or\n * code-split chunk-loading failure.\n *\n * These errors typically surface when a user has a tab open against a\n * previously-deployed version of an app and the JavaScript or CSS chunk\n * filenames have since changed: a fresh deployment removes the hashed assets\n * the open tab still references. Detecting them lets the SDK trigger an\n * automatic reload so the user gets the new build without manual intervention.\n *\n * Recognized shapes (webpack ChunkLoadError, Vite \"Failed to fetch\n * dynamically imported module\", Firefox \"error loading dynamically imported\n * module\", Safari \"Importing a module script failed\", and Vite \"Unable to\n * preload CSS\").\n *\n * @param error - The value to inspect. Anything that is not an Error\n * instance returns false.\n * @returns True if the error matches a known import/chunk-load failure.\n *\n * @public\n */\nexport function isImportError(error: unknown): boolean {\n if (!(error instanceof Error)) return false\n if (error.name === 'ChunkLoadError') return true\n\n const message = error.message || ''\n return (\n /Loading chunk [\\w-]+ failed/i.test(message) ||\n /Failed to fetch dynamically imported module/i.test(message) ||\n /error loading dynamically imported module/i.test(message) ||\n /Import(?:ing)? a module script failed/i.test(message) ||\n /Unable to preload CSS/i.test(message)\n )\n}\n"],"mappings":"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"}