@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.
- package/README.md +12 -0
- package/dist/_exports/_internal.d.ts +163 -0
- package/dist/_exports/_internal.d.ts.map +1 -0
- package/dist/_exports/_internal.js +332 -0
- package/dist/_exports/_internal.js.map +1 -0
- package/dist/_exports/agent.d.ts +65 -0
- package/dist/_exports/agent.d.ts.map +1 -0
- package/dist/_exports/agent.js +71 -0
- package/dist/_exports/agent.js.map +1 -0
- package/dist/_exports/comlink.d.ts +118 -0
- package/dist/_exports/comlink.d.ts.map +1 -0
- package/dist/_exports/comlink.js +69 -0
- package/dist/_exports/comlink.js.map +1 -0
- package/dist/authStore-CtE9bLHW.js +754 -0
- package/dist/authStore-CtE9bLHW.js.map +1 -0
- package/dist/authStore-DKFX8fn7.d.ts +3179 -0
- package/dist/authStore-DKFX8fn7.d.ts.map +1 -0
- package/dist/clientStore-BtE2-q2i.js +90 -0
- package/dist/clientStore-BtE2-q2i.js.map +1 -0
- package/dist/createSanityInstance-DUI1bGIg.d.ts +278 -0
- package/dist/createSanityInstance-DUI1bGIg.d.ts.map +1 -0
- package/dist/createStateSourceAction-BOKtqFNm.js +300 -0
- package/dist/createStateSourceAction-BOKtqFNm.js.map +1 -0
- package/dist/getEnv-D5RGkQLu.js +8 -0
- package/dist/getEnv-D5RGkQLu.js.map +1 -0
- package/dist/getNodeState-CR3__B2D.js +67 -0
- package/dist/getNodeState-CR3__B2D.js.map +1 -0
- package/dist/index.d.ts +3 -2332
- package/dist/index.js +4171 -4332
- package/dist/index.js.map +1 -1
- package/dist/logger-DAtJb5RQ.js +173 -0
- package/dist/logger-DAtJb5RQ.js.map +1 -0
- package/dist/object-CxXlSVg7.js +83 -0
- package/dist/object-CxXlSVg7.js.map +1 -0
- package/dist/queryStore-DPf9sN3V.js +1346 -0
- package/dist/queryStore-DPf9sN3V.js.map +1 -0
- package/dist/rolldown-runtime-vyAXikos.js +9 -0
- package/dist/setCleanupTimeout-BiM6q1KF.js +31 -0
- package/dist/setCleanupTimeout-BiM6q1KF.js.map +1 -0
- package/dist/telemetryManager-Dq_qCkeI.js +127 -0
- package/dist/telemetryManager-Dq_qCkeI.js.map +1 -0
- package/dist/version-BChjsi4u.js +9 -0
- package/dist/version-BChjsi4u.js.map +1 -0
- package/package.json +47 -52
- package/src/_exports/_internal.ts +27 -0
- package/src/_exports/agent.ts +19 -0
- package/src/_exports/comlink.ts +16 -0
- package/src/_exports/index.ts +125 -64
- package/src/access/checkPermissions.test.ts +55 -0
- package/src/access/checkPermissions.ts +54 -0
- package/src/agent/agentActions.test.ts +16 -60
- package/src/agent/agentActions.ts +25 -38
- package/src/applications/applications.test-d.ts +88 -0
- package/src/applications/applications.test.ts +130 -0
- package/src/applications/applications.ts +367 -0
- package/src/auth/authLogger.ts +30 -0
- package/src/auth/authStore.test.ts +194 -13
- package/src/auth/authStore.ts +58 -26
- package/src/auth/getOrganizationVerificationState.test.ts +18 -17
- package/src/auth/getOrganizationVerificationState.ts +4 -4
- package/src/auth/handleAuthCallback.test.ts +35 -1
- package/src/auth/handleAuthCallback.ts +25 -6
- package/src/auth/logout.test.ts +75 -2
- package/src/auth/logout.ts +23 -4
- package/src/auth/refreshStampedToken.test.ts +219 -469
- package/src/auth/refreshStampedToken.ts +79 -195
- package/src/auth/studioAuth.ts +1 -1
- package/src/auth/studioModeAuth.ts +2 -1
- package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +146 -13
- package/src/auth/subscribeToStateAndFetchCurrentUser.ts +37 -6
- package/src/auth/subscribeToStorageEventsAndSetToken.test.ts +2 -0
- package/src/client/clientStore.test.ts +62 -37
- package/src/client/clientStore.ts +45 -75
- package/src/client/liveEvents.test.ts +151 -0
- package/src/client/liveEvents.ts +107 -0
- package/src/comlink/controller/actions/destroyController.test.ts +4 -1
- package/src/comlink/controller/actions/getOrCreateChannel.test.ts +4 -1
- package/src/comlink/controller/actions/getOrCreateChannel.ts +2 -2
- package/src/comlink/controller/actions/getOrCreateController.test.ts +4 -1
- package/src/comlink/controller/actions/releaseChannel.test.ts +1 -1
- package/src/comlink/controller/comlinkControllerStore.test.ts +4 -1
- package/src/comlink/node/actions/getOrCreateNode.test.ts +9 -3
- package/src/comlink/node/actions/getOrCreateNode.ts +2 -2
- package/src/comlink/node/actions/releaseNode.test.ts +7 -4
- package/src/comlink/node/comlinkNodeStore.test.ts +2 -2
- package/src/comlink/node/getNodeState.test.ts +1 -1
- package/src/comlink/node/getNodeState.ts +2 -1
- package/src/comments/addonDatasetStore.test.ts +215 -0
- package/src/comments/addonDatasetStore.ts +249 -0
- package/src/comments/buildCommentThreads.test.ts +83 -0
- package/src/comments/buildCommentThreads.ts +54 -0
- package/src/comments/commentActions.test.ts +540 -0
- package/src/comments/commentActions.ts +555 -0
- package/src/comments/commentFieldPath.test.ts +40 -0
- package/src/comments/commentFieldPath.ts +44 -0
- package/src/comments/commentsConstants.ts +80 -0
- package/src/comments/commentsStore.test.ts +419 -0
- package/src/comments/commentsStore.ts +483 -0
- package/src/comments/normalizeComment.test.ts +116 -0
- package/src/comments/normalizeComment.ts +45 -0
- package/src/comments/observeComments.test.ts +193 -0
- package/src/comments/observeComments.ts +113 -0
- package/src/comments/reducers.test.ts +277 -0
- package/src/comments/reducers.ts +316 -0
- package/src/comments/types.ts +249 -0
- package/src/comments/weakenReferences.test.ts +47 -0
- package/src/comments/weakenReferences.ts +29 -0
- package/src/config/__tests__/handles.test.ts +18 -12
- package/src/config/handles.ts +25 -7
- package/src/config/sanityConfig.ts +40 -82
- package/src/datasets/datasets.test.ts +2 -2
- package/src/datasets/datasets.ts +10 -4
- package/src/document/actions.test.ts +115 -33
- package/src/document/actions.ts +212 -15
- package/src/document/applyDocumentActions.test.ts +35 -13
- package/src/document/applyDocumentActions.ts +30 -9
- package/src/document/documentConstants.ts +15 -0
- package/src/document/documentStore.concurrency.test.ts +1306 -0
- package/src/document/documentStore.test.ts +753 -273
- package/src/document/documentStore.ts +197 -75
- package/src/document/events.test.ts +57 -2
- package/src/document/events.ts +82 -26
- package/src/document/listen.test.ts +56 -0
- package/src/document/listen.ts +74 -21
- package/src/document/listenerEventOperators.test.ts +311 -0
- package/src/document/listenerEventOperators.ts +217 -0
- package/src/document/patchOperations.test.ts +76 -2
- package/src/document/patchOperations.ts +60 -1
- package/src/document/permissions.test.ts +107 -60
- package/src/document/permissions.ts +44 -19
- package/src/document/processActions/create.ts +138 -0
- package/src/document/processActions/delete.ts +100 -0
- package/src/document/processActions/discard.ts +63 -0
- package/src/document/processActions/edit.ts +154 -0
- package/src/document/processActions/processActions.ts +218 -0
- package/src/document/processActions/publish.ts +120 -0
- package/src/document/processActions/releaseArchive.ts +77 -0
- package/src/document/processActions/releaseCreate.ts +59 -0
- package/src/document/processActions/releaseDelete.ts +65 -0
- package/src/document/processActions/releaseEdit.ts +37 -0
- package/src/document/processActions/releasePublish.ts +45 -0
- package/src/document/processActions/releaseSchedule.ts +87 -0
- package/src/document/processActions/releaseUtil.ts +31 -0
- package/src/document/processActions/shared.ts +308 -0
- package/src/document/processActions/unpublish.ts +85 -0
- package/src/document/processActions.test.ts +1129 -121
- package/src/document/reducers.test.ts +772 -64
- package/src/document/reducers.ts +205 -51
- package/src/document/resourceRules.test.ts +178 -0
- package/src/document/resourceRules.ts +117 -0
- package/src/document/sharedListener.test.ts +16 -14
- package/src/document/sharedListener.ts +24 -8
- package/src/document/util.test.ts +46 -0
- package/src/document/util.ts +50 -0
- package/src/favorites/favorites.test.ts +5 -6
- package/src/installations/installations.test-d.ts +73 -0
- package/src/installations/installations.test.ts +62 -0
- package/src/installations/installations.ts +206 -0
- package/src/organization/organization.test-d.ts +36 -0
- package/src/organization/organization.test.ts +138 -0
- package/src/organization/organization.ts +138 -0
- package/src/organizations/organizations.test-d.ts +56 -0
- package/src/organizations/organizations.test.ts +150 -0
- package/src/organizations/organizations.ts +107 -0
- package/src/presence/bifurTransport.test.ts +201 -9
- package/src/presence/bifurTransport.ts +98 -14
- package/src/presence/paths.test.ts +70 -0
- package/src/presence/paths.ts +41 -0
- package/src/presence/presenceStore.test.ts +915 -24
- package/src/presence/presenceStore.ts +576 -104
- package/src/presence/types.ts +175 -3
- package/src/preview/previewProjectionUtils.test.ts +9 -22
- package/src/preview/previewProjectionUtils.ts +7 -3
- package/src/preview/types.ts +0 -15
- package/src/project/project.test-d.ts +37 -0
- package/src/project/project.test.ts +157 -12
- package/src/project/project.ts +138 -25
- package/src/projection/getProjectionState.test.ts +18 -20
- package/src/projection/getProjectionState.ts +23 -3
- package/src/projection/projectionQuery.ts +5 -5
- package/src/projection/projectionStore.test.ts +1 -9
- package/src/projection/resolveProjection.test.ts +1 -2
- package/src/projection/resolveProjection.ts +16 -0
- package/src/projection/subscribeToStateAndFetchBatches.test.ts +1 -1
- package/src/projection/subscribeToStateAndFetchBatches.ts +32 -23
- package/src/projects/projects.test-d.ts +32 -0
- package/src/projects/projects.test.ts +108 -42
- package/src/projects/projects.ts +63 -27
- package/src/query/queryStore.test.ts +259 -123
- package/src/query/queryStore.ts +85 -69
- package/src/query/reducers.test.ts +0 -42
- package/src/query/reducers.ts +2 -18
- package/src/releases/getPerspectiveState.test.ts +17 -23
- package/src/releases/getPerspectiveState.ts +8 -20
- package/src/releases/observeReleases.test.ts +127 -0
- package/src/releases/observeReleases.ts +102 -0
- package/src/releases/releasesStore.test.ts +100 -53
- package/src/releases/releasesStore.ts +69 -44
- package/src/releases/utils/sortReleases.test.ts +38 -2
- package/src/releases/utils/sortReleases.ts +15 -10
- package/src/store/createActionBinder.test.ts +109 -90
- package/src/store/createActionBinder.ts +36 -28
- package/src/store/createSanityInstance.test.ts +15 -13
- package/src/store/createSanityInstance.ts +14 -2
- package/src/store/createStateSourceAction.test.ts +64 -2
- package/src/store/createStateSourceAction.ts +38 -43
- package/src/store/createStoreInstance.test.ts +4 -2
- package/src/store/fetcherStore.test-d.ts +121 -0
- package/src/store/fetcherStore.test.ts +299 -0
- package/src/store/fetcherStore.ts +801 -0
- package/src/telemetry/environment.test.ts +119 -0
- package/src/telemetry/environment.ts +92 -0
- package/src/telemetry/events.ts +42 -0
- package/src/telemetry/initTelemetry.test.ts +432 -0
- package/src/telemetry/initTelemetry.ts +218 -0
- package/src/telemetry/telemetryManager.test.ts +327 -0
- package/src/telemetry/telemetryManager.ts +199 -0
- package/src/users/reducers.test.ts +3 -1
- package/src/users/reducers.ts +5 -6
- package/src/users/types.ts +4 -4
- package/src/users/usersStore.test.ts +16 -12
- package/src/users/usersStore.ts +5 -1
- package/src/utils/buildQuery.test.ts +14 -0
- package/src/utils/buildQuery.ts +17 -0
- package/src/utils/createFetcherStore.test.ts +7 -5
- package/src/utils/createFetcherStore.ts +8 -5
- package/src/utils/getStagingApiHost.test.ts +21 -0
- package/src/utils/getStagingApiHost.ts +14 -0
- package/src/utils/ids.test.ts +1 -29
- package/src/utils/ids.ts +0 -10
- package/src/utils/includeShape.ts +36 -0
- package/src/utils/isImportError.test.ts +72 -0
- package/src/utils/isImportError.ts +34 -0
- package/src/utils/logger.test.ts +12 -0
- package/src/utils/logger.ts +8 -3
- package/src/utils/object.test.ts +95 -0
- package/src/utils/object.ts +142 -0
- package/src/utils/setCleanupTimeout.ts +37 -0
- package/src/document/processActions.ts +0 -707
- package/src/utils/defineIntent.test.ts +0 -477
- package/src/utils/defineIntent.ts +0 -244
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {type Action} from '@sanity/client'
|
|
2
|
-
import {getPublishedId} from '@sanity/
|
|
1
|
+
import {type Action, ClientError, CorsOriginError, type Mutation} from '@sanity/client'
|
|
2
|
+
import {DocumentId, getDraftId, getPublishedId, getVersionId} from '@sanity/id-utils'
|
|
3
3
|
import {jsonMatch} from '@sanity/json-match'
|
|
4
|
-
import {type SanityDocument} from '
|
|
4
|
+
import {type SanityDocument} from 'groq'
|
|
5
5
|
import {type ExprNode} from 'groq-js'
|
|
6
6
|
import {
|
|
7
7
|
catchError,
|
|
@@ -17,15 +17,18 @@ import {
|
|
|
17
17
|
Observable,
|
|
18
18
|
of,
|
|
19
19
|
pairwise,
|
|
20
|
+
retry,
|
|
20
21
|
startWith,
|
|
21
22
|
Subject,
|
|
22
23
|
switchMap,
|
|
23
24
|
tap,
|
|
24
25
|
throttle,
|
|
26
|
+
throwError,
|
|
25
27
|
timer,
|
|
26
28
|
withLatestFrom,
|
|
27
29
|
} from 'rxjs'
|
|
28
30
|
|
|
31
|
+
import {getCurrentUserState} from '../auth/authStore'
|
|
29
32
|
import {type ClientOptions, getClientState} from '../client/clientStore'
|
|
30
33
|
import {
|
|
31
34
|
type DocumentHandle,
|
|
@@ -34,6 +37,7 @@ import {
|
|
|
34
37
|
isDatasetResource,
|
|
35
38
|
isMediaLibraryResource,
|
|
36
39
|
} from '../config/sanityConfig'
|
|
40
|
+
import {isReleasePerspective} from '../releases/utils/isReleasePerspective'
|
|
37
41
|
import {
|
|
38
42
|
bindActionByResource,
|
|
39
43
|
type BoundResourceKey,
|
|
@@ -42,11 +46,22 @@ import {
|
|
|
42
46
|
import {type SanityInstance} from '../store/createSanityInstance'
|
|
43
47
|
import {createStateSourceAction, type StateSource} from '../store/createStateSourceAction'
|
|
44
48
|
import {defineStore, type StoreContext} from '../store/defineStore'
|
|
45
|
-
import {getDraftId} from '../utils/ids'
|
|
46
49
|
import {type DocumentAction} from './actions'
|
|
47
|
-
import {
|
|
48
|
-
|
|
50
|
+
import {
|
|
51
|
+
ACL_RETRY_BASE_DELAY,
|
|
52
|
+
ACL_RETRY_MAX_DELAY,
|
|
53
|
+
API_VERSION,
|
|
54
|
+
INITIAL_OUTGOING_THROTTLE_TIME,
|
|
55
|
+
OUT_OF_SYNC_RETRY_BASE_DELAY,
|
|
56
|
+
OUT_OF_SYNC_RETRY_MAX_DELAY,
|
|
57
|
+
} from './documentConstants'
|
|
58
|
+
import {
|
|
59
|
+
type DocumentEvent,
|
|
60
|
+
type DocumentTransactionSubmissionResult,
|
|
61
|
+
getDocumentEvents,
|
|
62
|
+
} from './events'
|
|
49
63
|
import {listen, OutOfSyncError} from './listen'
|
|
64
|
+
import {type JsonMatch} from './patchOperations'
|
|
50
65
|
import {
|
|
51
66
|
calculatePermissions,
|
|
52
67
|
createGrantsLookup,
|
|
@@ -54,13 +69,13 @@ import {
|
|
|
54
69
|
type DocumentPermissionsResult,
|
|
55
70
|
type Grant,
|
|
56
71
|
} from './permissions'
|
|
57
|
-
import {ActionError} from './processActions'
|
|
72
|
+
import {ActionError} from './processActions/processActions'
|
|
73
|
+
import {isReleaseAction} from './processActions/releaseUtil'
|
|
58
74
|
import {
|
|
59
75
|
type AppliedTransaction,
|
|
60
76
|
applyFirstQueuedTransaction,
|
|
61
77
|
applyRemoteDocument,
|
|
62
78
|
cleanupOutgoingTransaction,
|
|
63
|
-
getDocumentIdsFromActions,
|
|
64
79
|
manageSubscriberIds,
|
|
65
80
|
type OutgoingTransaction,
|
|
66
81
|
type QueuedTransaction,
|
|
@@ -77,6 +92,10 @@ export interface DocumentStoreState {
|
|
|
77
92
|
applied: AppliedTransaction[]
|
|
78
93
|
outgoing?: OutgoingTransaction
|
|
79
94
|
grants?: Record<Grant, ExprNode>
|
|
95
|
+
/**
|
|
96
|
+
* The current user's identity (their user ID).
|
|
97
|
+
*/
|
|
98
|
+
identity?: string
|
|
80
99
|
error?: unknown
|
|
81
100
|
sharedListener: SharedListener
|
|
82
101
|
fetchDocument: (documentId: string) => Observable<SanityDocument | null>
|
|
@@ -116,6 +135,14 @@ export interface DocumentState {
|
|
|
116
135
|
* local transactions on top of this new remote.
|
|
117
136
|
*/
|
|
118
137
|
unverifiedRevisions?: {[TTransactionId in string]?: UnverifiedDocumentRevision}
|
|
138
|
+
/**
|
|
139
|
+
* transaction IDs recently submitted by this client for this document,
|
|
140
|
+
* newest last. used to label `remote-patches` events with the correct
|
|
141
|
+
* `origin` even after the corresponding `unverifiedRevisions` entry has
|
|
142
|
+
* been pruned (e.g. by a sync event that raced the listener echo). capped
|
|
143
|
+
* to the most recent entries.
|
|
144
|
+
*/
|
|
145
|
+
recentOwnTransactionIds?: string[]
|
|
119
146
|
}
|
|
120
147
|
|
|
121
148
|
export const documentStore = defineStore<DocumentStoreState, BoundResourceKey>({
|
|
@@ -136,6 +163,7 @@ export const documentStore = defineStore<DocumentStoreState, BoundResourceKey>({
|
|
|
136
163
|
subscribeToSubscriptionsAndListenToDocuments(context),
|
|
137
164
|
subscribeToAppliedAndSubmitNextTransaction(context),
|
|
138
165
|
subscribeToClientAndFetchDatasetAcl(context),
|
|
166
|
+
subscribeToCurrentUserAndSetIdentity(context),
|
|
139
167
|
]
|
|
140
168
|
|
|
141
169
|
return () => {
|
|
@@ -158,6 +186,29 @@ export interface DocumentOptions<
|
|
|
158
186
|
path?: TPath
|
|
159
187
|
}
|
|
160
188
|
|
|
189
|
+
/** @beta */
|
|
190
|
+
export function getDocumentState<
|
|
191
|
+
TDocumentType extends string = string,
|
|
192
|
+
TDataset extends string = string,
|
|
193
|
+
TProjectId extends string = string,
|
|
194
|
+
>(
|
|
195
|
+
instance: SanityInstance,
|
|
196
|
+
options: DocumentOptions<undefined, TDocumentType, TDataset, TProjectId>,
|
|
197
|
+
): StateSource<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`> | undefined | null>
|
|
198
|
+
|
|
199
|
+
/** @beta */
|
|
200
|
+
export function getDocumentState<
|
|
201
|
+
TPath extends string = string,
|
|
202
|
+
TDocumentType extends string = string,
|
|
203
|
+
TDataset extends string = string,
|
|
204
|
+
TProjectId extends string = string,
|
|
205
|
+
>(
|
|
206
|
+
instance: SanityInstance,
|
|
207
|
+
options: DocumentOptions<TPath, TDocumentType, TDataset, TProjectId>,
|
|
208
|
+
): StateSource<
|
|
209
|
+
JsonMatch<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>, TPath> | undefined
|
|
210
|
+
>
|
|
211
|
+
|
|
161
212
|
/** @beta */
|
|
162
213
|
export function getDocumentState<TData>(
|
|
163
214
|
instance: SanityInstance,
|
|
@@ -175,29 +226,28 @@ const _getDocumentState = bindActionByResource(
|
|
|
175
226
|
documentStore,
|
|
176
227
|
createStateSourceAction({
|
|
177
228
|
selector: ({state: {error, documentStates}}, options: DocumentOptions<string | undefined>) => {
|
|
178
|
-
const {documentId, path, liveEdit} = options
|
|
229
|
+
const {documentId: docId, path, liveEdit, perspective} = options
|
|
230
|
+
const documentId = DocumentId(docId)
|
|
179
231
|
if (error) throw error
|
|
232
|
+
let document: SanityDocument | null | undefined
|
|
180
233
|
|
|
181
234
|
if (liveEdit) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
235
|
+
document = documentStates[documentId]?.local
|
|
236
|
+
} else {
|
|
237
|
+
let version: SanityDocument | null | undefined
|
|
238
|
+
if (isReleasePerspective(perspective)) {
|
|
239
|
+
const versionId = getVersionId(documentId, perspective.releaseName)
|
|
240
|
+
version = documentStates[versionId]?.local
|
|
241
|
+
// early exit if we don't have the version document and we're in a release perspective
|
|
242
|
+
if (version === undefined) return undefined
|
|
243
|
+
}
|
|
244
|
+
const draft = documentStates[getDraftId(documentId)]?.local
|
|
245
|
+
const published = documentStates[getPublishedId(documentId)]?.local
|
|
246
|
+
// early exit if we don't have all the documents for draft/published logic
|
|
247
|
+
if (draft === undefined || published === undefined) return undefined
|
|
248
|
+
document = version ?? draft ?? published
|
|
190
249
|
}
|
|
191
250
|
|
|
192
|
-
// Standard draft/published logic
|
|
193
|
-
const draftId = getDraftId(documentId)
|
|
194
|
-
const publishedId = getPublishedId(documentId)
|
|
195
|
-
const draft = documentStates[draftId]?.local
|
|
196
|
-
const published = documentStates[publishedId]?.local
|
|
197
|
-
|
|
198
|
-
// wait for draft and published to be loaded before returning a value
|
|
199
|
-
if (draft === undefined || published === undefined) return undefined
|
|
200
|
-
const document = draft ?? published
|
|
201
251
|
if (!path) return document
|
|
202
252
|
const result = jsonMatch(document, path).next()
|
|
203
253
|
if (result.done) return undefined
|
|
@@ -205,20 +255,24 @@ const _getDocumentState = bindActionByResource(
|
|
|
205
255
|
return value
|
|
206
256
|
},
|
|
207
257
|
onSubscribe: (context, options: DocumentOptions<string | undefined>) =>
|
|
208
|
-
manageSubscriberIds(context, options
|
|
258
|
+
manageSubscriberIds(context, [options]),
|
|
209
259
|
}),
|
|
210
260
|
)
|
|
211
261
|
|
|
212
262
|
/** @beta */
|
|
213
|
-
export function resolveDocument<
|
|
263
|
+
export function resolveDocument<
|
|
264
|
+
TDocumentType extends string = string,
|
|
265
|
+
TDataset extends string = string,
|
|
266
|
+
TProjectId extends string = string,
|
|
267
|
+
>(
|
|
214
268
|
instance: SanityInstance,
|
|
215
|
-
docHandle: DocumentHandle,
|
|
216
|
-
): Promise<
|
|
269
|
+
docHandle: DocumentHandle<TDocumentType, TDataset, TProjectId>,
|
|
270
|
+
): Promise<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`> | null>
|
|
217
271
|
/** @beta */
|
|
218
|
-
export function resolveDocument(
|
|
272
|
+
export function resolveDocument<TData extends SanityDocument>(
|
|
219
273
|
instance: SanityInstance,
|
|
220
|
-
docHandle: DocumentHandle,
|
|
221
|
-
): Promise<
|
|
274
|
+
docHandle: DocumentHandle<string, string, string>,
|
|
275
|
+
): Promise<TData | null>
|
|
222
276
|
/** @beta */
|
|
223
277
|
export function resolveDocument(
|
|
224
278
|
...args: Parameters<typeof _resolveDocument>
|
|
@@ -245,32 +299,32 @@ export const getDocumentSyncStatus = bindActionByResource(
|
|
|
245
299
|
{state: {error, documentStates: documents, outgoing, applied, queued}},
|
|
246
300
|
doc: DocumentHandle,
|
|
247
301
|
) => {
|
|
248
|
-
const documentId = typeof doc === 'string' ? doc : doc.documentId
|
|
302
|
+
const documentId = DocumentId(typeof doc === 'string' ? doc : doc.documentId)
|
|
249
303
|
if (error) throw error
|
|
250
304
|
|
|
251
305
|
if (doc.liveEdit) {
|
|
252
306
|
// For liveEdit documents, only check the single document
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
307
|
+
if (documents[documentId] === undefined) return undefined
|
|
308
|
+
} else {
|
|
309
|
+
const version = isReleasePerspective(doc.perspective)
|
|
310
|
+
? documents[getVersionId(documentId, doc.perspective.releaseName)]
|
|
311
|
+
: undefined
|
|
312
|
+
if (isReleasePerspective(doc.perspective) && version === undefined) return undefined
|
|
313
|
+
// Standard draft/published logic
|
|
314
|
+
const draft = documents[getDraftId(documentId)]
|
|
315
|
+
const published = documents[getPublishedId(documentId)]
|
|
316
|
+
if (draft === undefined || published === undefined) return undefined
|
|
256
317
|
}
|
|
257
|
-
|
|
258
|
-
// Standard draft/published logic
|
|
259
|
-
const draftId = getDraftId(documentId)
|
|
260
|
-
const publishedId = getPublishedId(documentId)
|
|
261
|
-
|
|
262
|
-
const draft = documents[draftId]
|
|
263
|
-
const published = documents[publishedId]
|
|
264
|
-
|
|
265
|
-
if (draft === undefined || published === undefined) return undefined
|
|
266
318
|
return !queued.length && !applied.length && !outgoing
|
|
267
319
|
},
|
|
268
|
-
onSubscribe: (context, doc: DocumentHandle) =>
|
|
320
|
+
onSubscribe: (context, doc: DocumentHandle) => {
|
|
321
|
+
return manageSubscriberIds(context, [doc])
|
|
322
|
+
},
|
|
269
323
|
}),
|
|
270
324
|
)
|
|
271
325
|
|
|
272
326
|
type PermissionsStateOptions = {
|
|
273
|
-
resource
|
|
327
|
+
resource?: DocumentResource
|
|
274
328
|
actions: DocumentAction[]
|
|
275
329
|
}
|
|
276
330
|
|
|
@@ -279,8 +333,9 @@ export const getPermissionsState = bindActionByResource(
|
|
|
279
333
|
documentStore,
|
|
280
334
|
createStateSourceAction({
|
|
281
335
|
selector: calculatePermissions,
|
|
282
|
-
onSubscribe: (context, {actions}: PermissionsStateOptions) =>
|
|
283
|
-
manageSubscriberIds(context,
|
|
336
|
+
onSubscribe: (context, {actions}: PermissionsStateOptions) => {
|
|
337
|
+
manageSubscriberIds(context, actions)
|
|
338
|
+
},
|
|
284
339
|
}) as StoreAction<
|
|
285
340
|
DocumentStoreState,
|
|
286
341
|
[PermissionsStateOptions],
|
|
@@ -301,7 +356,7 @@ export const resolvePermissions = bindActionByResource(
|
|
|
301
356
|
/** @beta */
|
|
302
357
|
export const subscribeDocumentEvents = bindActionByResource(
|
|
303
358
|
documentStore,
|
|
304
|
-
({state}, options: {resource
|
|
359
|
+
({state}, options: {resource?: DocumentResource; eventHandler: (e: DocumentEvent) => void}) => {
|
|
305
360
|
const {events} = state.get()
|
|
306
361
|
const subscription = events.subscribe(options.eventHandler)
|
|
307
362
|
return () => subscription.unsubscribe()
|
|
@@ -365,24 +420,48 @@ const subscribeToAppliedAndSubmitNextTransaction = ({
|
|
|
365
420
|
withLatestFrom(
|
|
366
421
|
getClientState(instance, {
|
|
367
422
|
apiVersion: API_VERSION,
|
|
368
|
-
|
|
423
|
+
resource,
|
|
369
424
|
}).observable,
|
|
370
425
|
),
|
|
371
426
|
concatMap(([outgoing, client]) => {
|
|
372
427
|
if (!outgoing) return EMPTY
|
|
428
|
+
|
|
429
|
+
const revertOnError = catchError((error: unknown) => {
|
|
430
|
+
state.set('revertOutgoingTransaction', revertOutgoingTransaction)
|
|
431
|
+
const message = error instanceof Error ? error.message : 'Request failed'
|
|
432
|
+
events.next({type: 'reverted', message, outgoing, error})
|
|
433
|
+
return EMPTY
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
const toResult = map((result: unknown) => ({
|
|
437
|
+
result: result as DocumentTransactionSubmissionResult,
|
|
438
|
+
outgoing,
|
|
439
|
+
}))
|
|
440
|
+
|
|
441
|
+
// liveEdit transactions route to the mutations API; everything else routes
|
|
442
|
+
// to the actions API. processActions rejects transactions that mix the two,
|
|
443
|
+
// and reducers won't batch across that boundary, so a batch is always
|
|
444
|
+
// entirely liveEdit or entirely not.
|
|
445
|
+
if (outgoing.actions.some((action) => !isReleaseAction(action) && action.liveEdit)) {
|
|
446
|
+
return client.observable
|
|
447
|
+
.mutate(outgoing.outgoingMutations as Mutation[], {
|
|
448
|
+
transactionId: outgoing.transactionId,
|
|
449
|
+
visibility: 'async',
|
|
450
|
+
returnDocuments: false,
|
|
451
|
+
returnFirst: false,
|
|
452
|
+
tag: 'document.mutate',
|
|
453
|
+
skipCrossDatasetReferenceValidation: true,
|
|
454
|
+
})
|
|
455
|
+
.pipe(revertOnError, toResult)
|
|
456
|
+
}
|
|
457
|
+
|
|
373
458
|
return client.observable
|
|
374
459
|
.action(outgoing.outgoingActions as Action[], {
|
|
375
460
|
transactionId: outgoing.transactionId,
|
|
376
461
|
skipCrossDatasetReferenceValidation: true,
|
|
462
|
+
tag: 'document.action',
|
|
377
463
|
})
|
|
378
|
-
.pipe(
|
|
379
|
-
catchError((error) => {
|
|
380
|
-
state.set('revertOutgoingTransaction', revertOutgoingTransaction)
|
|
381
|
-
events.next({type: 'reverted', message: error.message, outgoing, error})
|
|
382
|
-
return EMPTY
|
|
383
|
-
}),
|
|
384
|
-
map((result) => ({result, outgoing})),
|
|
385
|
-
)
|
|
464
|
+
.pipe(revertOnError, toResult)
|
|
386
465
|
}),
|
|
387
466
|
tap(({outgoing, result}) => {
|
|
388
467
|
state.set('cleanupOutgoingTransaction', cleanupOutgoingTransaction)
|
|
@@ -424,8 +503,8 @@ const subscribeToSubscriptionsAndListenToDocuments = (
|
|
|
424
503
|
...added.map((id) => ({id, add: true})),
|
|
425
504
|
...removed.map((id) => ({id, add: false})),
|
|
426
505
|
].sort((a, b) => {
|
|
427
|
-
const aIsDraft = a.id === getDraftId(a.id)
|
|
428
|
-
const bIsDraft = b.id === getDraftId(b.id)
|
|
506
|
+
const aIsDraft = a.id === getDraftId(DocumentId(a.id))
|
|
507
|
+
const bIsDraft = b.id === getDraftId(DocumentId(b.id))
|
|
429
508
|
|
|
430
509
|
if (aIsDraft && bIsDraft) return a.id.localeCompare(b.id, 'en-US')
|
|
431
510
|
if (aIsDraft) return -1
|
|
@@ -441,10 +520,15 @@ const subscribeToSubscriptionsAndListenToDocuments = (
|
|
|
441
520
|
switchMap((e) => {
|
|
442
521
|
if (!e.add) return EMPTY
|
|
443
522
|
return listen(context, e.id).pipe(
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
523
|
+
retry({
|
|
524
|
+
delay: (error, retryCount) => {
|
|
525
|
+
if (!(error instanceof OutOfSyncError)) return throwError(() => error)
|
|
526
|
+
const backoff = Math.min(
|
|
527
|
+
OUT_OF_SYNC_RETRY_BASE_DELAY * 2 ** (retryCount - 1),
|
|
528
|
+
OUT_OF_SYNC_RETRY_MAX_DELAY,
|
|
529
|
+
)
|
|
530
|
+
return timer(backoff)
|
|
531
|
+
},
|
|
448
532
|
}),
|
|
449
533
|
tap((remote) =>
|
|
450
534
|
state.set('applyRemoteDocument', (prev) =>
|
|
@@ -464,10 +548,7 @@ const subscribeToClientAndFetchDatasetAcl = ({
|
|
|
464
548
|
state,
|
|
465
549
|
key: {resource},
|
|
466
550
|
}: StoreContext<DocumentStoreState, BoundResourceKey>) => {
|
|
467
|
-
const clientOptions: ClientOptions = {apiVersion: API_VERSION}
|
|
468
|
-
if (resource) {
|
|
469
|
-
clientOptions.resource = resource
|
|
470
|
-
}
|
|
551
|
+
const clientOptions: ClientOptions = {apiVersion: API_VERSION, resource}
|
|
471
552
|
|
|
472
553
|
let uri: string
|
|
473
554
|
if (resource && isDatasetResource(resource)) {
|
|
@@ -483,11 +564,39 @@ const subscribeToClientAndFetchDatasetAcl = ({
|
|
|
483
564
|
return getClientState(instance, clientOptions)
|
|
484
565
|
.observable.pipe(
|
|
485
566
|
switchMap((client) =>
|
|
486
|
-
client.observable
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
567
|
+
client.observable
|
|
568
|
+
.request<DatasetAcl>({
|
|
569
|
+
uri,
|
|
570
|
+
tag: 'acl.get',
|
|
571
|
+
})
|
|
572
|
+
.pipe(
|
|
573
|
+
retry({
|
|
574
|
+
delay: (error, retryCount) => {
|
|
575
|
+
// 4xx responses and CORS misconfigurations are not transient —
|
|
576
|
+
// the server will keep rejecting the request, so rethrow to
|
|
577
|
+
// surface them as a fatal store error. 408 (request timeout)
|
|
578
|
+
// and 429 (rate limit) are the exceptions: they resolve on
|
|
579
|
+
// their own, so they are retried like network errors
|
|
580
|
+
const isTransientClientError =
|
|
581
|
+
error instanceof ClientError &&
|
|
582
|
+
(error.statusCode === 408 || error.statusCode === 429)
|
|
583
|
+
if (
|
|
584
|
+
(error instanceof ClientError && !isTransientClientError) ||
|
|
585
|
+
error instanceof CorsOriginError
|
|
586
|
+
) {
|
|
587
|
+
return throwError(() => error)
|
|
588
|
+
}
|
|
589
|
+
// network errors (no status code), 408/429 responses, and 5xx
|
|
590
|
+
// responses are retried with exponential backoff so a transient
|
|
591
|
+
// failure during startup doesn't permanently brick the store
|
|
592
|
+
const backoff = Math.min(
|
|
593
|
+
ACL_RETRY_BASE_DELAY * 2 ** (retryCount - 1),
|
|
594
|
+
ACL_RETRY_MAX_DELAY,
|
|
595
|
+
)
|
|
596
|
+
return timer(backoff)
|
|
597
|
+
},
|
|
598
|
+
}),
|
|
599
|
+
),
|
|
491
600
|
),
|
|
492
601
|
tap((datasetAcl) => state.set('setGrants', {grants: createGrantsLookup(datasetAcl)})),
|
|
493
602
|
)
|
|
@@ -495,3 +604,16 @@ const subscribeToClientAndFetchDatasetAcl = ({
|
|
|
495
604
|
error: (error) => state.set('setError', {error}),
|
|
496
605
|
})
|
|
497
606
|
}
|
|
607
|
+
|
|
608
|
+
const subscribeToCurrentUserAndSetIdentity = ({
|
|
609
|
+
instance,
|
|
610
|
+
state,
|
|
611
|
+
}: StoreContext<DocumentStoreState, BoundResourceKey>) =>
|
|
612
|
+
getCurrentUserState(instance).observable.subscribe({
|
|
613
|
+
next: (currentUser) => state.set('setIdentity', {identity: currentUser?.id}),
|
|
614
|
+
// A transient identity-fetch failure (network blip, expired token, or a
|
|
615
|
+
// normal logout/re-login transition) should not brick all document
|
|
616
|
+
// operations. Reset the identity to `undefined` and keep going — GROQ's
|
|
617
|
+
// `identity()` then evaluates to null, matching the unauthenticated state.
|
|
618
|
+
error: () => state.set('setIdentity', {identity: undefined}),
|
|
619
|
+
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {describe, expect, it} from 'vitest'
|
|
2
2
|
|
|
3
|
-
import {type DocumentAction} from '../document/actions'
|
|
3
|
+
import {type Action, type DocumentAction} from '../document/actions'
|
|
4
4
|
import {type DocumentEvent, getDocumentEvents} from '../document/events'
|
|
5
5
|
import {type OutgoingTransaction} from '../document/reducers'
|
|
6
6
|
|
|
@@ -41,11 +41,66 @@ describe('getDocumentEvents', () => {
|
|
|
41
41
|
expect(events).toHaveLength(outgoing.actions.length)
|
|
42
42
|
events.forEach((event) => {
|
|
43
43
|
const action = outgoing.actions.find(
|
|
44
|
-
(a) => 'documentId' in event && event.documentId === a.documentId,
|
|
44
|
+
(a) => 'documentId' in a && 'documentId' in event && event.documentId === a.documentId,
|
|
45
45
|
)
|
|
46
46
|
expect(action).toBeDefined()
|
|
47
47
|
expect(event.type).toEqual(expectedMap[action!.type])
|
|
48
48
|
expect((event as Extract<DocumentEvent, {outgoing: unknown}>).outgoing).toBe(outgoing)
|
|
49
49
|
})
|
|
50
50
|
})
|
|
51
|
+
|
|
52
|
+
it('emits created/edited/deleted events for release.create/edit/delete with release doc IDs', () => {
|
|
53
|
+
const outgoing: OutgoingTransaction = {
|
|
54
|
+
transactionId: 'txn-release',
|
|
55
|
+
actions: [
|
|
56
|
+
{type: 'release.create', releaseId: 'r1'} as Action,
|
|
57
|
+
{type: 'release.edit', releaseId: 'r2', patch: {set: {}}} as Action,
|
|
58
|
+
{type: 'release.delete', releaseId: 'r3'} as Action,
|
|
59
|
+
],
|
|
60
|
+
disableBatching: false,
|
|
61
|
+
batchedTransactionIds: [],
|
|
62
|
+
outgoingActions: [],
|
|
63
|
+
outgoingMutations: [],
|
|
64
|
+
base: {},
|
|
65
|
+
working: {},
|
|
66
|
+
previous: {},
|
|
67
|
+
previousRevs: {},
|
|
68
|
+
timestamp: '2025-02-06T00:00:00.000Z',
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const events = getDocumentEvents(outgoing)
|
|
72
|
+
expect(events).toEqual([
|
|
73
|
+
{type: 'created', documentId: '_.releases.r1', outgoing},
|
|
74
|
+
{type: 'edited', documentId: '_.releases.r2', outgoing},
|
|
75
|
+
{type: 'deleted', documentId: '_.releases.r3', outgoing},
|
|
76
|
+
])
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('skips release actions that have no local mutation (publish/schedule/archive/etc.)', () => {
|
|
80
|
+
const outgoing: OutgoingTransaction = {
|
|
81
|
+
transactionId: 'txn-release-noop',
|
|
82
|
+
actions: [
|
|
83
|
+
{type: 'release.publish', releaseId: 'r1'} as Action,
|
|
84
|
+
{
|
|
85
|
+
type: 'release.schedule',
|
|
86
|
+
releaseId: 'r2',
|
|
87
|
+
publishAt: '2026-01-01T00:00:00.000Z',
|
|
88
|
+
} as Action,
|
|
89
|
+
{type: 'release.unschedule', releaseId: 'r3'} as Action,
|
|
90
|
+
{type: 'release.archive', releaseId: 'r4'} as Action,
|
|
91
|
+
{type: 'release.unarchive', releaseId: 'r5'} as Action,
|
|
92
|
+
],
|
|
93
|
+
disableBatching: false,
|
|
94
|
+
batchedTransactionIds: [],
|
|
95
|
+
outgoingActions: [],
|
|
96
|
+
outgoingMutations: [],
|
|
97
|
+
base: {},
|
|
98
|
+
working: {},
|
|
99
|
+
previous: {},
|
|
100
|
+
previousRevs: {},
|
|
101
|
+
timestamp: '2025-02-06T00:00:00.000Z',
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
expect(getDocumentEvents(outgoing)).toEqual([])
|
|
105
|
+
})
|
|
51
106
|
})
|
package/src/document/events.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import {type SanityClient} from '@sanity/client'
|
|
1
|
+
import {type MultipleMutationResult, type SanityClient} from '@sanity/client'
|
|
2
|
+
import {type PatchOperations} from '@sanity/types'
|
|
2
3
|
|
|
3
|
-
import {type DocumentAction} from './actions'
|
|
4
|
+
import {type DocumentAction, type ReleaseAction} from './actions'
|
|
5
|
+
import {getReleaseDocumentId, isReleaseAction} from './processActions/releaseUtil'
|
|
4
6
|
import {type OutgoingTransaction} from './reducers'
|
|
5
7
|
|
|
8
|
+
/** @beta Response body from submitting an outgoing transaction (actions or mutations API). */
|
|
9
|
+
export type DocumentTransactionSubmissionResult =
|
|
10
|
+
| Awaited<ReturnType<SanityClient['action']>>
|
|
11
|
+
| MultipleMutationResult
|
|
12
|
+
|
|
6
13
|
/** @beta */
|
|
7
14
|
export type DocumentEvent =
|
|
8
15
|
| ActionErrorEvent
|
|
@@ -15,6 +22,7 @@ export type DocumentEvent =
|
|
|
15
22
|
| DocumentPublishedEvent
|
|
16
23
|
| DocumentUnpublishedEvent
|
|
17
24
|
| DocumentDiscardedEvent
|
|
25
|
+
| DocumentRemotePatchesEvent
|
|
18
26
|
|
|
19
27
|
/**
|
|
20
28
|
* @beta
|
|
@@ -35,7 +43,7 @@ export interface ActionErrorEvent {
|
|
|
35
43
|
export interface TransactionAcceptedEvent {
|
|
36
44
|
type: 'accepted'
|
|
37
45
|
outgoing: OutgoingTransaction
|
|
38
|
-
result:
|
|
46
|
+
result: DocumentTransactionSubmissionResult
|
|
39
47
|
}
|
|
40
48
|
/**
|
|
41
49
|
* @beta
|
|
@@ -113,31 +121,79 @@ export interface DocumentDiscardedEvent {
|
|
|
113
121
|
outgoing: OutgoingTransaction
|
|
114
122
|
}
|
|
115
123
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
/**
|
|
125
|
+
* @beta
|
|
126
|
+
* Event emitted when patches for a document are observed through the listener.
|
|
127
|
+
*
|
|
128
|
+
* Unlike the whole-document snapshots the store keeps, these are the raw patch
|
|
129
|
+
* operations from the transaction that produced the change, preserving the
|
|
130
|
+
* operational intent of the edit (e.g. keyed array inserts/unsets). Consumers
|
|
131
|
+
* that maintain their own local state, like collaborative text editors, can
|
|
132
|
+
* apply these directly instead of diffing document snapshots.
|
|
133
|
+
*
|
|
134
|
+
* `origin` is `'local'` when the transaction was submitted by this document
|
|
135
|
+
* store instance (an own edit observed back through the listener) and
|
|
136
|
+
* `'remote'` when it came from another client.
|
|
137
|
+
*/
|
|
138
|
+
export interface DocumentRemotePatchesEvent {
|
|
139
|
+
type: 'remote-patches'
|
|
140
|
+
/** The ID of the document version the patches apply to (e.g. a draft ID). */
|
|
141
|
+
documentId: string
|
|
142
|
+
/** The transaction ID that carried these patches. */
|
|
143
|
+
transactionId: string
|
|
144
|
+
/** The revision the document was at before this transaction. */
|
|
145
|
+
previousRev?: string
|
|
146
|
+
/** The timestamp of the transaction. */
|
|
147
|
+
timestamp: string
|
|
148
|
+
/** The patch operations, rooted at the document. */
|
|
149
|
+
patches: PatchOperations[]
|
|
150
|
+
/** Whether the transaction originated from this client or another one. */
|
|
151
|
+
origin: 'local' | 'remote'
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Release actions that write a mutation to the local release doc map onto
|
|
155
|
+
// the regular per-document events with `documentId = '_.releases.<releaseId>'`.
|
|
156
|
+
// The other release actions (publish/schedule/unschedule/archive/unarchive)
|
|
157
|
+
// don't mutate local state, so they aren't in the map and get skipped — they
|
|
158
|
+
// surface through the transaction-level `accepted`/`reverted` events instead.
|
|
159
|
+
const actionMap = {
|
|
160
|
+
'document.create': 'created',
|
|
161
|
+
'document.delete': 'deleted',
|
|
162
|
+
'document.discard': 'discarded',
|
|
163
|
+
'document.edit': 'edited',
|
|
164
|
+
'document.publish': 'published',
|
|
165
|
+
'document.unpublish': 'unpublished',
|
|
166
|
+
'release.create': 'created',
|
|
167
|
+
'release.edit': 'edited',
|
|
168
|
+
'release.delete': 'deleted',
|
|
169
|
+
} satisfies Partial<Record<DocumentAction['type'] | ReleaseAction['type'], DocumentEvent['type']>>
|
|
128
170
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
171
|
+
type MappedActionType = keyof typeof actionMap
|
|
172
|
+
|
|
173
|
+
export function getDocumentEvents(outgoing: OutgoingTransaction): DocumentEvent[] {
|
|
174
|
+
const documentIdsByAction = outgoing.actions.reduce(
|
|
175
|
+
(acc, action) => {
|
|
176
|
+
if (!(action.type in actionMap)) return acc
|
|
177
|
+
const documentId = isReleaseAction(action)
|
|
178
|
+
? getReleaseDocumentId(action.releaseId)
|
|
179
|
+
: action.documentId
|
|
180
|
+
if (!documentId) return acc
|
|
181
|
+
const type = action.type as MappedActionType
|
|
182
|
+
const ids = acc[type] ?? new Set<string>()
|
|
183
|
+
ids.add(documentId)
|
|
184
|
+
acc[type] = ids
|
|
185
|
+
return acc
|
|
186
|
+
},
|
|
187
|
+
{} as Partial<Record<MappedActionType, Set<string>>>,
|
|
188
|
+
)
|
|
137
189
|
|
|
138
|
-
return documentIdsByAction.flatMap(([actionType, documentIds]) =>
|
|
139
|
-
Array.from(documentIds).map(
|
|
140
|
-
(documentId): DocumentEvent => ({
|
|
190
|
+
return Object.entries(documentIdsByAction).flatMap(([actionType, documentIds]) =>
|
|
191
|
+
Array.from(documentIds ?? []).map(
|
|
192
|
+
(documentId): DocumentEvent => ({
|
|
193
|
+
type: actionMap[actionType as MappedActionType],
|
|
194
|
+
documentId,
|
|
195
|
+
outgoing,
|
|
196
|
+
}),
|
|
141
197
|
),
|
|
142
198
|
)
|
|
143
199
|
}
|