@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
@@ -1,707 +0,0 @@
1
- import {diffValue} from '@sanity/diff-patch'
2
- import {
3
- type Mutation,
4
- type PatchOperations,
5
- type Reference,
6
- type SanityDocument,
7
- } from '@sanity/types'
8
- import {evaluateSync, type ExprNode} from 'groq-js'
9
- import {isEqual} from 'lodash-es'
10
-
11
- import {getDraftId, getPublishedId} from '../utils/ids'
12
- import {type DocumentAction} from './actions'
13
- import {type Grant} from './permissions'
14
- import {type DocumentSet, getId, processMutations} from './processMutations'
15
- import {type HttpAction} from './reducers'
16
-
17
- function checkGrant(grantExpr: ExprNode, document: SanityDocument): boolean {
18
- const value = evaluateSync(grantExpr, {params: {document}})
19
- return value.type === 'boolean' && value.data
20
- }
21
-
22
- interface ProcessActionsOptions {
23
- /**
24
- * The ID of this transaction. This will become the resulting `_rev` for all
25
- * documents affected by changes derived from the current set of actions.
26
- */
27
- transactionId: string
28
-
29
- /**
30
- * The actions to apply to the given documents
31
- */
32
- actions: DocumentAction[]
33
-
34
- /**
35
- * The set of documents these actions were intended to be applied to. These
36
- * set of documents should be captured right before a queued action is
37
- * applied.
38
- */
39
- base: DocumentSet
40
-
41
- /**
42
- * The current "working" set of documents. A patch will be created by applying
43
- * the actions to the base. This patch will then be applied to the working
44
- * set for conflict resolution. Initially, this value should match the base
45
- * set.
46
- */
47
- working: DocumentSet
48
-
49
- /**
50
- * The timestamp to use for `_updateAt` and other similar timestamps for this
51
- * transaction
52
- */
53
- timestamp: string
54
-
55
- /**
56
- * the lookup with pre-parsed GROQ expressions
57
- */
58
- grants: Record<Grant, ExprNode>
59
-
60
- // // TODO: implement initial values from the schema?
61
- // initialValues?: {[TDocumentType in string]?: {_type: string}}
62
- }
63
-
64
- interface ProcessActionsResult {
65
- /**
66
- * The resulting document set after the actions have been applied. This is
67
- * derived from the working documents.
68
- */
69
- working: DocumentSet
70
- /**
71
- * The document set before the actions have been applied. This is simply the
72
- * input of the `working` document set.
73
- */
74
- previous: DocumentSet
75
- /**
76
- * The outgoing action that were collected when applying the actions. These
77
- * are sent to the Actions HTTP API
78
- */
79
- outgoingActions: HttpAction[]
80
- /**
81
- * The outgoing mutations that were collected when applying the actions. These
82
- * are here for debugging purposes.
83
- */
84
- outgoingMutations: Mutation[]
85
- /**
86
- * The previous revisions of the given documents before the actions were applied.
87
- */
88
- previousRevs: {[TDocumentId in string]?: string}
89
- }
90
-
91
- interface ActionErrorOptions {
92
- message: string
93
- documentId: string
94
- transactionId: string
95
- }
96
-
97
- /**
98
- * Thrown when a precondition for an action failed.
99
- */
100
- export class ActionError extends Error implements ActionErrorOptions {
101
- documentId!: string
102
- transactionId!: string
103
-
104
- constructor(options: ActionErrorOptions) {
105
- super(options.message)
106
- Object.assign(this, options)
107
- }
108
- }
109
-
110
- export class PermissionActionError extends ActionError {}
111
-
112
- /**
113
- * Applies the given set of actions to the working set of documents and converts
114
- * high-level actions into lower-level outgoing mutations/actions that respect
115
- * the current state of the working documents.
116
- *
117
- * Supports a "base" and "working" set of documents to allow actions to be
118
- * applied on top of a different working set of documents in a 3-way merge
119
- *
120
- * Actions are applied to the base set of documents first. The difference
121
- * between the base before and after is used to create a patch. This patch is
122
- * then applied to the working set of documents and is set as the outgoing patch
123
- * sent to the server.
124
- */
125
- export function processActions({
126
- actions,
127
- transactionId,
128
- working: initialWorking,
129
- base: initialBase,
130
- timestamp,
131
- grants,
132
- }: ProcessActionsOptions): ProcessActionsResult {
133
- let working: DocumentSet = {...initialWorking}
134
- let base: DocumentSet = {...initialBase}
135
-
136
- const outgoingActions: HttpAction[] = []
137
- const outgoingMutations: Mutation[] = []
138
-
139
- for (const action of actions) {
140
- switch (action.type) {
141
- case 'document.create': {
142
- const documentId = getId(action.documentId)
143
-
144
- if (action.liveEdit) {
145
- // For liveEdit documents, create directly without draft/published logic
146
- if (working[documentId]) {
147
- throw new ActionError({
148
- documentId,
149
- transactionId,
150
- message: `This document already exists.`,
151
- })
152
- }
153
-
154
- const newDocBase = {_type: action.documentType, _id: documentId}
155
- const newDocWorking = {_type: action.documentType, _id: documentId}
156
- const mutations: Mutation[] = [{create: newDocWorking}]
157
-
158
- base = processMutations({
159
- documents: base,
160
- transactionId,
161
- mutations: [{create: newDocBase}],
162
- timestamp,
163
- })
164
- working = processMutations({
165
- documents: working,
166
- transactionId,
167
- mutations,
168
- timestamp,
169
- })
170
-
171
- if (!checkGrant(grants.create, working[documentId] as SanityDocument)) {
172
- throw new PermissionActionError({
173
- documentId,
174
- transactionId,
175
- message: `You do not have permission to create document "${documentId}".`,
176
- })
177
- }
178
-
179
- outgoingMutations.push(...mutations)
180
- outgoingActions.push({
181
- actionType: 'sanity.action.document.create',
182
- publishedId: documentId,
183
- attributes: newDocWorking,
184
- })
185
- continue
186
- }
187
-
188
- // Standard draft/published logic
189
- const draftId = getDraftId(documentId)
190
- const publishedId = getPublishedId(documentId)
191
-
192
- if (working[draftId]) {
193
- throw new ActionError({
194
- documentId,
195
- transactionId,
196
- message: `A draft version of this document already exists. Please use or discard the existing draft before creating a new one.`,
197
- })
198
- }
199
-
200
- // Spread the (possibly undefined) published version directly.
201
- const newDocBase = {
202
- ...base[publishedId],
203
- _type: action.documentType,
204
- _id: draftId,
205
- ...action.initialValue,
206
- }
207
- const newDocWorking = {
208
- ...working[publishedId],
209
- _type: action.documentType,
210
- _id: draftId,
211
- ...action.initialValue,
212
- }
213
- const mutations: Mutation[] = [{create: newDocWorking}]
214
-
215
- base = processMutations({
216
- documents: base,
217
- transactionId,
218
- mutations: [{create: newDocBase}],
219
- timestamp,
220
- })
221
- working = processMutations({
222
- documents: working,
223
- transactionId,
224
- mutations,
225
- timestamp,
226
- })
227
-
228
- if (!checkGrant(grants.create, working[draftId] as SanityDocument)) {
229
- throw new PermissionActionError({
230
- documentId,
231
- transactionId,
232
- message: `You do not have permission to create a draft for document "${documentId}".`,
233
- })
234
- }
235
-
236
- outgoingMutations.push(...mutations)
237
- outgoingActions.push({
238
- actionType: 'sanity.action.document.version.create',
239
- publishedId,
240
- attributes: newDocWorking,
241
- })
242
- continue
243
- }
244
-
245
- case 'document.delete': {
246
- const documentId = action.documentId
247
-
248
- if (action.liveEdit) {
249
- // For liveEdit documents, delete directly
250
- if (!working[documentId]) {
251
- throw new ActionError({
252
- documentId,
253
- transactionId,
254
- message: 'The document you are trying to delete does not exist.',
255
- })
256
- }
257
-
258
- if (!checkGrant(grants.update, working[documentId])) {
259
- throw new PermissionActionError({
260
- documentId,
261
- transactionId,
262
- message: `You do not have permission to delete this document.`,
263
- })
264
- }
265
-
266
- const mutations: Mutation[] = [{delete: {id: documentId}}]
267
-
268
- base = processMutations({documents: base, transactionId, mutations, timestamp})
269
- working = processMutations({documents: working, transactionId, mutations, timestamp})
270
-
271
- outgoingMutations.push(...mutations)
272
- outgoingActions.push({
273
- actionType: 'sanity.action.document.delete',
274
- publishedId: documentId,
275
- })
276
- continue
277
- }
278
-
279
- // Standard draft/published logic
280
- const draftId = getDraftId(documentId)
281
- const publishedId = getPublishedId(documentId)
282
-
283
- if (!working[publishedId]) {
284
- throw new ActionError({
285
- documentId,
286
- transactionId,
287
- message: working[draftId]
288
- ? 'Cannot delete a document without a published version.'
289
- : 'The document you are trying to delete does not exist.',
290
- })
291
- }
292
-
293
- const cantDeleteDraft = working[draftId] && !checkGrant(grants.update, working[draftId])
294
- const cantDeletePublished =
295
- working[publishedId] && !checkGrant(grants.update, working[publishedId])
296
-
297
- if (cantDeleteDraft || cantDeletePublished) {
298
- throw new PermissionActionError({
299
- documentId,
300
- transactionId,
301
- message: `You do not have permission to delete this document.`,
302
- })
303
- }
304
-
305
- const mutations: Mutation[] = [{delete: {id: publishedId}}, {delete: {id: draftId}}]
306
- const includeDrafts = working[draftId] ? [draftId] : undefined
307
-
308
- base = processMutations({documents: base, transactionId, mutations, timestamp})
309
- working = processMutations({documents: working, transactionId, mutations, timestamp})
310
-
311
- outgoingMutations.push(...mutations)
312
- outgoingActions.push({
313
- actionType: 'sanity.action.document.delete',
314
- publishedId,
315
- ...(includeDrafts ? {includeDrafts} : {}),
316
- })
317
- continue
318
- }
319
-
320
- case 'document.discard': {
321
- const documentId = getId(action.documentId)
322
-
323
- if (action.liveEdit) {
324
- throw new ActionError({
325
- documentId,
326
- transactionId,
327
- message: `Cannot discard changes for liveEdit document "${documentId}". LiveEdit documents do not support drafts.`,
328
- })
329
- }
330
-
331
- // Standard draft/published logic
332
- const draftId = getDraftId(documentId)
333
- const mutations: Mutation[] = [{delete: {id: draftId}}]
334
-
335
- if (!working[draftId]) {
336
- throw new ActionError({
337
- documentId,
338
- transactionId,
339
- message: `There is no draft available to discard for document "${documentId}".`,
340
- })
341
- }
342
-
343
- if (!checkGrant(grants.update, working[draftId])) {
344
- throw new PermissionActionError({
345
- documentId,
346
- transactionId,
347
- message: `You do not have permission to discard changes for document "${documentId}".`,
348
- })
349
- }
350
-
351
- base = processMutations({documents: base, transactionId, mutations, timestamp})
352
- working = processMutations({documents: working, transactionId, mutations, timestamp})
353
-
354
- outgoingMutations.push(...mutations)
355
- outgoingActions.push({
356
- actionType: 'sanity.action.document.version.discard',
357
- versionId: draftId,
358
- })
359
- continue
360
- }
361
-
362
- case 'document.edit': {
363
- const documentId = getId(action.documentId)
364
-
365
- if (action.liveEdit) {
366
- // For liveEdit documents, edit directly without draft logic
367
- const userPatches = action.patches?.map((patch) => ({patch: {id: documentId, ...patch}}))
368
-
369
- // skip this action if there are no associated patches
370
- if (!userPatches?.length) continue
371
-
372
- if (!working[documentId] || !base[documentId]) {
373
- throw new ActionError({
374
- documentId,
375
- transactionId,
376
- message: `Cannot edit document because it does not exist.`,
377
- })
378
- }
379
-
380
- const baseBefore = base[documentId] as SanityDocument
381
- if (userPatches) {
382
- base = processMutations({
383
- documents: base,
384
- transactionId,
385
- mutations: userPatches,
386
- timestamp,
387
- })
388
- }
389
-
390
- const baseAfter = base[documentId] as SanityDocument
391
- const patches = diffValue(baseBefore, baseAfter)
392
-
393
- const workingBefore = working[documentId] as SanityDocument
394
- if (!checkGrant(grants.update, workingBefore)) {
395
- throw new PermissionActionError({
396
- documentId,
397
- transactionId,
398
- message: `You do not have permission to edit document "${documentId}".`,
399
- })
400
- }
401
-
402
- const workingMutations = patches.map((patch) => ({patch: {id: documentId, ...patch}}))
403
-
404
- working = processMutations({
405
- documents: working,
406
- transactionId,
407
- mutations: workingMutations,
408
- timestamp,
409
- })
410
-
411
- outgoingMutations.push(...workingMutations)
412
- outgoingActions.push(
413
- ...patches.map(
414
- (patch): HttpAction => ({
415
- actionType: 'sanity.action.document.edit',
416
- // Server requires draftId to have drafts. prefix for validation, even for liveEdit
417
- draftId: getDraftId(documentId),
418
- publishedId: documentId,
419
- patch: patch as PatchOperations,
420
- }),
421
- ),
422
- )
423
-
424
- continue
425
- }
426
-
427
- // Standard draft/published logic
428
- const draftId = getDraftId(documentId)
429
- const publishedId = getPublishedId(documentId)
430
- const userPatches = action.patches?.map((patch) => ({patch: {id: draftId, ...patch}}))
431
-
432
- // skip this action if there are no associated patches
433
- if (!userPatches?.length) continue
434
-
435
- if (
436
- (!working[draftId] && !working[publishedId]) ||
437
- (!base[draftId] && !base[publishedId])
438
- ) {
439
- throw new ActionError({
440
- documentId,
441
- transactionId,
442
- message: `Cannot edit document because it does not exist in draft or published form.`,
443
- })
444
- }
445
-
446
- const baseMutations: Mutation[] = []
447
- if (!base[draftId] && base[publishedId]) {
448
- baseMutations.push({create: {...base[publishedId], _id: draftId}})
449
- }
450
-
451
- // the first if statement should make this never be null or undefined
452
- const baseBefore = (base[draftId] ?? base[publishedId]) as SanityDocument
453
- if (userPatches) {
454
- baseMutations.push(...userPatches)
455
- }
456
-
457
- base = processMutations({
458
- documents: base,
459
- transactionId,
460
- mutations: baseMutations,
461
- timestamp,
462
- })
463
- // this one will always be defined because a patch mutation will never
464
- // delete an input document
465
- const baseAfter = base[draftId] as SanityDocument
466
- const patches = diffValue(baseBefore, baseAfter)
467
-
468
- const workingMutations: Mutation[] = []
469
- if (!working[draftId] && working[publishedId]) {
470
- const newDraftFromPublished = {...working[publishedId], _id: draftId}
471
-
472
- if (!checkGrant(grants.create, newDraftFromPublished)) {
473
- throw new PermissionActionError({
474
- documentId,
475
- transactionId,
476
- message: `You do not have permission to create a draft for editing this document.`,
477
- })
478
- }
479
-
480
- workingMutations.push({create: newDraftFromPublished})
481
- }
482
-
483
- // the first if statement should make this never be null or undefined
484
- const workingBefore = (working[draftId] ?? working[publishedId]) as SanityDocument
485
- if (!checkGrant(grants.update, workingBefore)) {
486
- throw new PermissionActionError({
487
- documentId,
488
- transactionId,
489
- message: `You do not have permission to edit document "${documentId}".`,
490
- })
491
- }
492
- workingMutations.push(...patches.map((patch) => ({patch: {id: draftId, ...patch}})))
493
-
494
- working = processMutations({
495
- documents: working,
496
- transactionId,
497
- mutations: workingMutations,
498
- timestamp,
499
- })
500
-
501
- outgoingMutations.push(...workingMutations)
502
- outgoingActions.push(
503
- ...patches.map(
504
- (patch): HttpAction => ({
505
- actionType: 'sanity.action.document.edit',
506
- draftId,
507
- publishedId,
508
- patch: patch as PatchOperations,
509
- }),
510
- ),
511
- )
512
-
513
- continue
514
- }
515
-
516
- case 'document.publish': {
517
- const documentId = getId(action.documentId)
518
-
519
- if (action.liveEdit) {
520
- throw new ActionError({
521
- documentId,
522
- transactionId,
523
- message: `Cannot publish liveEdit document "${documentId}". LiveEdit documents do not support drafts or publishing.`,
524
- })
525
- }
526
-
527
- // Standard draft/published logic
528
- const draftId = getDraftId(documentId)
529
- const publishedId = getPublishedId(documentId)
530
-
531
- const workingDraft = working[draftId]
532
- const baseDraft = base[draftId]
533
- if (!workingDraft || !baseDraft) {
534
- throw new ActionError({
535
- documentId,
536
- transactionId,
537
- message: `Cannot publish because no draft version was found for document "${documentId}".`,
538
- })
539
- }
540
-
541
- // Before proceeding, verify that the working draft is identical to the base draft.
542
- // TODO: is it enough just to check for the _rev or nah?
543
- if (!isEqual(workingDraft, baseDraft)) {
544
- throw new ActionError({
545
- documentId,
546
- transactionId,
547
- message: `Publish aborted: The document has changed elsewhere. Please try again.`,
548
- })
549
- }
550
-
551
- const newPublishedFromDraft = {...strengthenOnPublish(workingDraft), _id: publishedId}
552
-
553
- const mutations: Mutation[] = [
554
- {delete: {id: draftId}},
555
- {createOrReplace: newPublishedFromDraft},
556
- ]
557
-
558
- if (working[draftId] && !checkGrant(grants.update, working[draftId])) {
559
- throw new PermissionActionError({
560
- documentId,
561
- transactionId,
562
- message: `Publish failed: You do not have permission to update the draft for "${documentId}".`,
563
- })
564
- }
565
-
566
- if (working[publishedId] && !checkGrant(grants.update, newPublishedFromDraft)) {
567
- throw new PermissionActionError({
568
- documentId,
569
- transactionId,
570
- message: `Publish failed: You do not have permission to update the published version of "${documentId}".`,
571
- })
572
- } else if (!working[publishedId] && !checkGrant(grants.create, newPublishedFromDraft)) {
573
- throw new PermissionActionError({
574
- documentId,
575
- transactionId,
576
- message: `Publish failed: You do not have permission to publish a new version of "${documentId}".`,
577
- })
578
- }
579
-
580
- base = processMutations({documents: base, transactionId, mutations, timestamp})
581
- working = processMutations({documents: working, transactionId, mutations, timestamp})
582
-
583
- outgoingMutations.push(...mutations)
584
- outgoingActions.push({
585
- actionType: 'sanity.action.document.publish',
586
- draftId,
587
- publishedId,
588
- })
589
- continue
590
- }
591
-
592
- case 'document.unpublish': {
593
- const documentId = getId(action.documentId)
594
-
595
- if (action.liveEdit) {
596
- throw new ActionError({
597
- documentId,
598
- transactionId,
599
- message: `Cannot unpublish liveEdit document "${documentId}". LiveEdit documents do not support drafts or publishing.`,
600
- })
601
- }
602
-
603
- // Standard draft/published logic
604
- const draftId = getDraftId(documentId)
605
- const publishedId = getPublishedId(documentId)
606
-
607
- if (!working[publishedId] && !base[publishedId]) {
608
- throw new ActionError({
609
- documentId,
610
- transactionId,
611
- message: `Cannot unpublish because the document "${documentId}" is not currently published.`,
612
- })
613
- }
614
-
615
- const sourceDoc = working[publishedId] ?? (base[publishedId] as SanityDocument)
616
- const newDraftFromPublished = {...sourceDoc, _id: draftId}
617
- const mutations: Mutation[] = [
618
- {delete: {id: publishedId}},
619
- {createIfNotExists: newDraftFromPublished},
620
- ]
621
-
622
- if (!checkGrant(grants.update, sourceDoc)) {
623
- throw new PermissionActionError({
624
- documentId,
625
- transactionId,
626
- message: `You do not have permission to unpublish the document "${documentId}".`,
627
- })
628
- }
629
-
630
- if (!working[draftId] && !checkGrant(grants.create, newDraftFromPublished)) {
631
- throw new PermissionActionError({
632
- documentId,
633
- transactionId,
634
- message: `You do not have permission to create a draft from the published version of "${documentId}".`,
635
- })
636
- }
637
-
638
- base = processMutations({
639
- documents: base,
640
- transactionId,
641
- mutations: [
642
- {delete: {id: publishedId}},
643
- {createIfNotExists: {...(base[publishedId] ?? sourceDoc), _id: draftId}},
644
- ],
645
- timestamp,
646
- })
647
- working = processMutations({documents: working, transactionId, mutations, timestamp})
648
-
649
- outgoingMutations.push(...mutations)
650
- outgoingActions.push({
651
- actionType: 'sanity.action.document.unpublish',
652
- draftId,
653
- publishedId,
654
- })
655
- continue
656
- }
657
-
658
- default: {
659
- throw new Error(
660
- `Unknown action type: "${
661
- // @ts-expect-error invalid input
662
- action.type
663
- }". Please contact support if this issue persists.`,
664
- )
665
- }
666
- }
667
- }
668
-
669
- const previousRevs = Object.fromEntries(
670
- Object.entries(initialWorking).map(([id, doc]) => [id, doc?._rev]),
671
- )
672
-
673
- return {
674
- working,
675
- outgoingActions,
676
- outgoingMutations,
677
- previous: initialWorking,
678
- previousRevs,
679
- }
680
- }
681
-
682
- function strengthenOnPublish(draft: SanityDocument): SanityDocument {
683
- const isStrengthenReference = (
684
- value: object,
685
- ): value is Reference & Required<Pick<Reference, '_strengthenOnPublish'>> =>
686
- '_strengthenOnPublish' in value
687
-
688
- function strengthen(value: unknown): unknown {
689
- if (typeof value !== 'object' || !value) return value
690
-
691
- if (isStrengthenReference(value)) {
692
- const {_strengthenOnPublish, _weak, ...rest} = value
693
- return {
694
- ...rest,
695
- ...(_strengthenOnPublish.weak && {_weak: true}),
696
- }
697
- }
698
-
699
- if (Array.isArray(value)) {
700
- return value.map(strengthen)
701
- }
702
-
703
- return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, strengthen(v)]))
704
- }
705
-
706
- return strengthen(draft) as SanityDocument
707
- }