@sanity/sdk 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +124 -13
- package/dist/index.js +468 -243
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/_exports/index.ts +3 -0
- package/src/auth/authMode.test.ts +56 -0
- package/src/auth/authMode.ts +71 -0
- package/src/auth/authStore.test.ts +85 -4
- package/src/auth/authStore.ts +63 -125
- package/src/auth/authStrategy.ts +39 -0
- package/src/auth/dashboardAuth.ts +132 -0
- package/src/auth/standaloneAuth.ts +109 -0
- package/src/auth/studioAuth.ts +217 -0
- package/src/auth/studioModeAuth.test.ts +43 -1
- package/src/auth/studioModeAuth.ts +10 -1
- package/src/auth/subscribeToStateAndFetchCurrentUser.ts +21 -6
- package/src/config/sanityConfig.ts +48 -7
- package/src/projection/getProjectionState.ts +6 -5
- package/src/projection/projectionQuery.test.ts +38 -55
- package/src/projection/projectionQuery.ts +27 -31
- package/src/projection/projectionStore.test.ts +4 -4
- package/src/projection/projectionStore.ts +3 -2
- package/src/projection/resolveProjection.ts +2 -2
- package/src/projection/statusQuery.test.ts +35 -0
- package/src/projection/statusQuery.ts +71 -0
- package/src/projection/subscribeToStateAndFetchBatches.test.ts +63 -50
- package/src/projection/subscribeToStateAndFetchBatches.ts +106 -27
- package/src/projection/types.ts +12 -0
- package/src/projection/util.ts +0 -1
- package/src/query/queryStore.test.ts +64 -0
- package/src/query/queryStore.ts +30 -10
- package/src/releases/getPerspectiveState.test.ts +17 -14
- package/src/releases/getPerspectiveState.ts +58 -38
- package/src/releases/releasesStore.test.ts +59 -61
- package/src/releases/releasesStore.ts +21 -35
- package/src/releases/utils/isReleasePerspective.ts +7 -0
- package/src/store/createActionBinder.test.ts +211 -1
- package/src/store/createActionBinder.ts +95 -17
- package/src/store/createSanityInstance.ts +3 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import {DocumentId, getPublishedId} from '@sanity/id-utils'
|
|
1
2
|
import {type SanityProjectionResult} from 'groq'
|
|
2
3
|
import {omit} from 'lodash-es'
|
|
3
4
|
|
|
4
5
|
import {type DocumentHandle} from '../config/sanityConfig'
|
|
5
|
-
import {
|
|
6
|
+
import {bindActionBySourceAndPerspective} from '../store/createActionBinder'
|
|
6
7
|
import {type SanityInstance} from '../store/createSanityInstance'
|
|
7
8
|
import {
|
|
8
9
|
createStateSourceAction,
|
|
@@ -10,7 +11,7 @@ import {
|
|
|
10
11
|
type StateSource,
|
|
11
12
|
} from '../store/createStateSourceAction'
|
|
12
13
|
import {hashString} from '../utils/hashString'
|
|
13
|
-
import {
|
|
14
|
+
import {insecureRandomId} from '../utils/ids'
|
|
14
15
|
import {projectionStore} from './projectionStore'
|
|
15
16
|
import {type ProjectionStoreState, type ProjectionValuePending} from './types'
|
|
16
17
|
import {PROJECTION_STATE_CLEAR_DELAY, STABLE_EMPTY_PROJECTION, validateProjection} from './util'
|
|
@@ -70,21 +71,21 @@ export function getProjectionState(
|
|
|
70
71
|
/**
|
|
71
72
|
* @beta
|
|
72
73
|
*/
|
|
73
|
-
export const _getProjectionState =
|
|
74
|
+
export const _getProjectionState = bindActionBySourceAndPerspective(
|
|
74
75
|
projectionStore,
|
|
75
76
|
createStateSourceAction({
|
|
76
77
|
selector: (
|
|
77
78
|
{state}: SelectorContext<ProjectionStoreState>,
|
|
78
79
|
options: ProjectionOptions<string, string, string, string>,
|
|
79
80
|
): ProjectionValuePending<object> | undefined => {
|
|
80
|
-
const documentId = getPublishedId(options.documentId)
|
|
81
|
+
const documentId = getPublishedId(DocumentId(options.documentId))
|
|
81
82
|
const projectionHash = hashString(options.projection)
|
|
82
83
|
return state.values[documentId]?.[projectionHash] ?? STABLE_EMPTY_PROJECTION
|
|
83
84
|
},
|
|
84
85
|
onSubscribe: ({state}, options: ProjectionOptions<string, string, string, string>) => {
|
|
85
86
|
const {projection, ...docHandle} = options
|
|
86
87
|
const subscriptionId = insecureRandomId()
|
|
87
|
-
const documentId = getPublishedId(docHandle.documentId)
|
|
88
|
+
const documentId = getPublishedId(DocumentId(docHandle.documentId))
|
|
88
89
|
const validProjection = validateProjection(projection)
|
|
89
90
|
const projectionHash = hashString(validProjection)
|
|
90
91
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import {DocumentId} from '@sanity/id-utils'
|
|
1
2
|
import {describe, expect, it} from 'vitest'
|
|
2
3
|
|
|
3
4
|
import {createProjectionQuery, processProjectionQuery} from './projectionQuery'
|
|
4
5
|
|
|
5
6
|
describe('createProjectionQuery', () => {
|
|
6
7
|
it('creates a query and params for given ids and projections', () => {
|
|
7
|
-
const ids = new Set(['doc1', 'doc2'])
|
|
8
|
+
const ids = new Set(['doc1', 'doc2'].map(DocumentId))
|
|
8
9
|
const projectionHash = '{title, description}'
|
|
9
10
|
const documentProjections = {
|
|
10
11
|
doc1: {[projectionHash]: projectionHash},
|
|
@@ -15,11 +16,11 @@ describe('createProjectionQuery', () => {
|
|
|
15
16
|
expect(query).toMatch(/.*_id in \$__ids_.*/)
|
|
16
17
|
expect(Object.keys(params)).toHaveLength(1)
|
|
17
18
|
expect(params[`__ids_${projectionHash}`]).toBeDefined()
|
|
18
|
-
expect(params[`__ids_${projectionHash}`]).toHaveLength(
|
|
19
|
+
expect(params[`__ids_${projectionHash}`]).toHaveLength(2)
|
|
19
20
|
})
|
|
20
21
|
|
|
21
22
|
it('handles multiple different projections', () => {
|
|
22
|
-
const ids = new Set(['doc1', 'doc2'])
|
|
23
|
+
const ids = new Set(['doc1', 'doc2'].map(DocumentId))
|
|
23
24
|
const projectionHash1 = '{title, description}'
|
|
24
25
|
const projectionHash2 = '{name, age}'
|
|
25
26
|
const documentProjections = {
|
|
@@ -31,13 +32,13 @@ describe('createProjectionQuery', () => {
|
|
|
31
32
|
expect(query).toMatch(/.*_id in \$__ids_.*/)
|
|
32
33
|
expect(Object.keys(params)).toHaveLength(2)
|
|
33
34
|
expect(params[`__ids_${projectionHash1}`]).toBeDefined()
|
|
34
|
-
expect(params[`__ids_${projectionHash1}`]).toHaveLength(
|
|
35
|
+
expect(params[`__ids_${projectionHash1}`]).toHaveLength(1)
|
|
35
36
|
expect(params[`__ids_${projectionHash2}`]).toBeDefined()
|
|
36
|
-
expect(params[`__ids_${projectionHash2}`]).toHaveLength(
|
|
37
|
+
expect(params[`__ids_${projectionHash2}`]).toHaveLength(1)
|
|
37
38
|
})
|
|
38
39
|
|
|
39
40
|
it('filters out ids without projections', () => {
|
|
40
|
-
const ids = new Set(['doc1', 'doc2', 'doc3'])
|
|
41
|
+
const ids = new Set(['doc1', 'doc2', 'doc3'].map(DocumentId))
|
|
41
42
|
const projectionHash1 = '{title}'
|
|
42
43
|
// projectionHash2 missing intentionally
|
|
43
44
|
const projectionHash3 = '{name}'
|
|
@@ -51,9 +52,9 @@ describe('createProjectionQuery', () => {
|
|
|
51
52
|
expect(query).toMatch(/.*_id in \$__ids_.*/)
|
|
52
53
|
expect(Object.keys(params)).toHaveLength(2)
|
|
53
54
|
expect(params[`__ids_${projectionHash1}`]).toBeDefined()
|
|
54
|
-
expect(params[`__ids_${projectionHash1}`]).toHaveLength(
|
|
55
|
+
expect(params[`__ids_${projectionHash1}`]).toHaveLength(1)
|
|
55
56
|
expect(params[`__ids_${projectionHash3}`]).toBeDefined()
|
|
56
|
-
expect(params[`__ids_${projectionHash3}`]).toHaveLength(
|
|
57
|
+
expect(params[`__ids_${projectionHash3}`]).toHaveLength(1)
|
|
57
58
|
})
|
|
58
59
|
})
|
|
59
60
|
|
|
@@ -63,10 +64,9 @@ describe('processProjectionQuery', () => {
|
|
|
63
64
|
it('returns structure with empty object if no results found', () => {
|
|
64
65
|
const ids = new Set(['doc1'])
|
|
65
66
|
const result = processProjectionQuery({
|
|
66
|
-
projectId: 'p',
|
|
67
|
-
dataset: 'd',
|
|
68
67
|
ids,
|
|
69
68
|
results: [], // no results
|
|
69
|
+
perspective: 'published',
|
|
70
70
|
})
|
|
71
71
|
|
|
72
72
|
expect(result['doc1']).toEqual({})
|
|
@@ -85,10 +85,14 @@ describe('processProjectionQuery', () => {
|
|
|
85
85
|
]
|
|
86
86
|
|
|
87
87
|
const processed = processProjectionQuery({
|
|
88
|
-
projectId: 'p',
|
|
89
|
-
dataset: 'd',
|
|
90
88
|
ids,
|
|
91
89
|
results,
|
|
90
|
+
perspective: 'published',
|
|
91
|
+
documentStatuses: {
|
|
92
|
+
doc1: {
|
|
93
|
+
lastEditedPublishedAt: '2021-01-01',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
92
96
|
})
|
|
93
97
|
|
|
94
98
|
expect(processed['doc1']?.[testProjectionHash]).toEqual({
|
|
@@ -116,10 +120,14 @@ describe('processProjectionQuery', () => {
|
|
|
116
120
|
]
|
|
117
121
|
|
|
118
122
|
const processed = processProjectionQuery({
|
|
119
|
-
projectId: 'p',
|
|
120
|
-
dataset: 'd',
|
|
121
123
|
ids: new Set(['doc1']),
|
|
122
124
|
results,
|
|
125
|
+
perspective: 'published',
|
|
126
|
+
documentStatuses: {
|
|
127
|
+
doc1: {
|
|
128
|
+
lastEditedPublishedAt: '2021-01-01',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
123
131
|
})
|
|
124
132
|
|
|
125
133
|
expect(processed['doc1']?.[testProjectionHash]).toEqual({
|
|
@@ -134,66 +142,37 @@ describe('processProjectionQuery', () => {
|
|
|
134
142
|
})
|
|
135
143
|
})
|
|
136
144
|
|
|
137
|
-
it('handles
|
|
145
|
+
it('handles release perspective with all three status fields', () => {
|
|
138
146
|
const results = [
|
|
139
|
-
{
|
|
140
|
-
_id: 'drafts.doc1',
|
|
141
|
-
_type: 'document',
|
|
142
|
-
_updatedAt: '2021-01-02',
|
|
143
|
-
result: {title: 'Draft'},
|
|
144
|
-
__projectionHash: testProjectionHash,
|
|
145
|
-
},
|
|
146
147
|
{
|
|
147
148
|
_id: 'doc1',
|
|
148
149
|
_type: 'document',
|
|
149
|
-
_updatedAt: '2021-01-
|
|
150
|
-
result: {title: '
|
|
150
|
+
_updatedAt: '2021-01-03',
|
|
151
|
+
result: {title: 'Version'},
|
|
151
152
|
__projectionHash: testProjectionHash,
|
|
152
153
|
},
|
|
153
154
|
]
|
|
154
155
|
|
|
155
156
|
const processed = processProjectionQuery({
|
|
156
|
-
projectId: 'p',
|
|
157
|
-
dataset: 'd',
|
|
158
157
|
ids: new Set(['doc1']),
|
|
159
158
|
results,
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
data: {
|
|
164
|
-
title: 'Draft',
|
|
165
|
-
_status: {
|
|
159
|
+
perspective: {releaseName: 'release1'},
|
|
160
|
+
documentStatuses: {
|
|
161
|
+
doc1: {
|
|
166
162
|
lastEditedDraftAt: '2021-01-02',
|
|
167
163
|
lastEditedPublishedAt: '2021-01-01',
|
|
164
|
+
lastEditedVersionAt: '2021-01-03',
|
|
168
165
|
},
|
|
169
166
|
},
|
|
170
|
-
isPending: false,
|
|
171
|
-
})
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
it('uses published result when no draft exists', () => {
|
|
175
|
-
const results = [
|
|
176
|
-
{
|
|
177
|
-
_id: 'doc1',
|
|
178
|
-
_type: 'document',
|
|
179
|
-
_updatedAt: '2021-01-01',
|
|
180
|
-
result: {title: 'Published'},
|
|
181
|
-
__projectionHash: testProjectionHash,
|
|
182
|
-
},
|
|
183
|
-
]
|
|
184
|
-
|
|
185
|
-
const processed = processProjectionQuery({
|
|
186
|
-
projectId: 'p',
|
|
187
|
-
dataset: 'd',
|
|
188
|
-
ids: new Set(['doc1']),
|
|
189
|
-
results,
|
|
190
167
|
})
|
|
191
168
|
|
|
192
169
|
expect(processed['doc1']?.[testProjectionHash]).toEqual({
|
|
193
170
|
data: {
|
|
194
|
-
title: '
|
|
171
|
+
title: 'Version',
|
|
195
172
|
_status: {
|
|
173
|
+
lastEditedDraftAt: '2021-01-02',
|
|
196
174
|
lastEditedPublishedAt: '2021-01-01',
|
|
175
|
+
lastEditedVersionAt: '2021-01-03',
|
|
197
176
|
},
|
|
198
177
|
},
|
|
199
178
|
isPending: false,
|
|
@@ -221,10 +200,14 @@ describe('processProjectionQuery', () => {
|
|
|
221
200
|
]
|
|
222
201
|
|
|
223
202
|
const processed = processProjectionQuery({
|
|
224
|
-
projectId: 'p',
|
|
225
|
-
dataset: 'd',
|
|
226
203
|
ids: new Set(['doc1']),
|
|
227
204
|
results,
|
|
205
|
+
perspective: 'published',
|
|
206
|
+
documentStatuses: {
|
|
207
|
+
doc1: {
|
|
208
|
+
lastEditedPublishedAt: '2021-01-01',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
228
211
|
})
|
|
229
212
|
|
|
230
213
|
expect(processed['doc1']?.[hash1]).toEqual({
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {type ClientPerspective} from '@sanity/client'
|
|
2
|
+
import {DocumentId} from '@sanity/id-utils'
|
|
3
|
+
|
|
4
|
+
import {type ReleasePerspective} from '../config/sanityConfig'
|
|
5
|
+
import {getPublishedId} from '../utils/ids'
|
|
6
|
+
import {
|
|
7
|
+
type DocumentProjections,
|
|
8
|
+
type DocumentProjectionValues,
|
|
9
|
+
type ProjectionStoreState,
|
|
10
|
+
} from './types'
|
|
3
11
|
import {validateProjection} from './util'
|
|
4
12
|
|
|
5
13
|
export type ProjectionQueryResult = {
|
|
@@ -18,8 +26,8 @@ interface CreateProjectionQueryResult {
|
|
|
18
26
|
type ProjectionMap = Record<string, {projection: string; documentIds: Set<string>}>
|
|
19
27
|
|
|
20
28
|
export function createProjectionQuery(
|
|
21
|
-
documentIds: Set<
|
|
22
|
-
documentProjections: {[TDocumentId in
|
|
29
|
+
documentIds: Set<DocumentId>,
|
|
30
|
+
documentProjections: {[TDocumentId in DocumentId]?: DocumentProjections},
|
|
23
31
|
): CreateProjectionQueryResult {
|
|
24
32
|
const projections = Array.from(documentIds)
|
|
25
33
|
.flatMap((id) => {
|
|
@@ -48,11 +56,7 @@ export function createProjectionQuery(
|
|
|
48
56
|
|
|
49
57
|
const params = Object.fromEntries(
|
|
50
58
|
Object.entries(projections).map(([projectionHash, value]) => {
|
|
51
|
-
const idsInProjection = Array.from(value.documentIds).flatMap((id) =>
|
|
52
|
-
getPublishedId(id),
|
|
53
|
-
getDraftId(id),
|
|
54
|
-
])
|
|
55
|
-
|
|
59
|
+
const idsInProjection = Array.from(value.documentIds).flatMap((id) => DocumentId(id))
|
|
56
60
|
return [`__ids_${projectionHash}`, Array.from(idsInProjection)]
|
|
57
61
|
}),
|
|
58
62
|
)
|
|
@@ -61,28 +65,28 @@ export function createProjectionQuery(
|
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
interface ProcessProjectionQueryOptions {
|
|
64
|
-
projectId: string
|
|
65
|
-
dataset: string
|
|
66
68
|
ids: Set<string>
|
|
67
69
|
results: ProjectionQueryResult[]
|
|
70
|
+
documentStatuses?: ProjectionStoreState['documentStatuses']
|
|
71
|
+
perspective: ClientPerspective | ReleasePerspective
|
|
68
72
|
}
|
|
69
73
|
|
|
70
|
-
export function processProjectionQuery({
|
|
74
|
+
export function processProjectionQuery({
|
|
75
|
+
ids,
|
|
76
|
+
results,
|
|
77
|
+
documentStatuses,
|
|
78
|
+
}: ProcessProjectionQueryOptions): {
|
|
71
79
|
[TDocumentId in string]?: DocumentProjectionValues<Record<string, unknown>>
|
|
72
80
|
} {
|
|
73
81
|
const groupedResults: {
|
|
74
82
|
[docId: string]: {
|
|
75
|
-
[hash: string]:
|
|
76
|
-
draft?: ProjectionQueryResult
|
|
77
|
-
published?: ProjectionQueryResult
|
|
78
|
-
}
|
|
83
|
+
[hash: string]: ProjectionQueryResult | undefined
|
|
79
84
|
}
|
|
80
85
|
} = {}
|
|
81
86
|
|
|
82
87
|
for (const result of results) {
|
|
83
88
|
const originalId = getPublishedId(result._id)
|
|
84
89
|
const hash = result.__projectionHash
|
|
85
|
-
const isDraft = result._id.startsWith('drafts.')
|
|
86
90
|
|
|
87
91
|
if (!ids.has(originalId)) continue
|
|
88
92
|
|
|
@@ -90,14 +94,10 @@ export function processProjectionQuery({ids, results}: ProcessProjectionQueryOpt
|
|
|
90
94
|
groupedResults[originalId] = {}
|
|
91
95
|
}
|
|
92
96
|
if (!groupedResults[originalId][hash]) {
|
|
93
|
-
groupedResults[originalId][hash] =
|
|
97
|
+
groupedResults[originalId][hash] = undefined
|
|
94
98
|
}
|
|
95
99
|
|
|
96
|
-
|
|
97
|
-
groupedResults[originalId][hash].draft = result
|
|
98
|
-
} else {
|
|
99
|
-
groupedResults[originalId][hash].published = result
|
|
100
|
-
}
|
|
100
|
+
groupedResults[originalId][hash] = result
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
const finalValues: {
|
|
@@ -111,22 +111,18 @@ export function processProjectionQuery({ids, results}: ProcessProjectionQueryOpt
|
|
|
111
111
|
if (!projectionsForDoc) continue
|
|
112
112
|
|
|
113
113
|
for (const hash in projectionsForDoc) {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
const projectionResultData = draft?.result ?? published?.result
|
|
114
|
+
const projectionResult = projectionsForDoc[hash]
|
|
115
|
+
const projectionResultData = projectionResult?.result
|
|
117
116
|
|
|
118
117
|
if (!projectionResultData) {
|
|
119
118
|
finalValues[originalId][hash] = {data: null, isPending: false}
|
|
120
119
|
continue
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
const
|
|
124
|
-
...(draft?._updatedAt && {lastEditedDraftAt: draft._updatedAt}),
|
|
125
|
-
...(published?._updatedAt && {lastEditedPublishedAt: published._updatedAt}),
|
|
126
|
-
}
|
|
122
|
+
const statusFromStore = documentStatuses?.[originalId]
|
|
127
123
|
|
|
128
124
|
finalValues[originalId][hash] = {
|
|
129
|
-
data: {...projectionResultData, _status},
|
|
125
|
+
data: {...projectionResultData, _status: statusFromStore},
|
|
130
126
|
isPending: false,
|
|
131
127
|
}
|
|
132
128
|
}
|
|
@@ -30,8 +30,8 @@ describe('projectionStore', () => {
|
|
|
30
30
|
instance,
|
|
31
31
|
{
|
|
32
32
|
name: 'p.d',
|
|
33
|
-
projectId: 'p',
|
|
34
|
-
|
|
33
|
+
source: {projectId: 'p', dataset: 'd'},
|
|
34
|
+
perspective: 'drafts',
|
|
35
35
|
},
|
|
36
36
|
projectionStore,
|
|
37
37
|
)
|
|
@@ -42,8 +42,8 @@ describe('projectionStore', () => {
|
|
|
42
42
|
state,
|
|
43
43
|
key: {
|
|
44
44
|
name: 'p.d',
|
|
45
|
-
projectId: 'p',
|
|
46
|
-
|
|
45
|
+
source: {projectId: 'p', dataset: 'd'},
|
|
46
|
+
perspective: 'drafts',
|
|
47
47
|
},
|
|
48
48
|
})
|
|
49
49
|
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {type
|
|
1
|
+
import {type BoundPerspectiveKey} from '../store/createActionBinder'
|
|
2
2
|
import {defineStore} from '../store/defineStore'
|
|
3
3
|
import {subscribeToStateAndFetchBatches} from './subscribeToStateAndFetchBatches'
|
|
4
4
|
import {type ProjectionStoreState} from './types'
|
|
5
5
|
|
|
6
|
-
export const projectionStore = defineStore<ProjectionStoreState,
|
|
6
|
+
export const projectionStore = defineStore<ProjectionStoreState, BoundPerspectiveKey>({
|
|
7
7
|
name: 'Projection',
|
|
8
8
|
getInitialState() {
|
|
9
9
|
return {
|
|
10
10
|
values: {},
|
|
11
11
|
documentProjections: {},
|
|
12
12
|
subscriptions: {},
|
|
13
|
+
documentStatuses: {},
|
|
13
14
|
}
|
|
14
15
|
},
|
|
15
16
|
initialize(context) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {type SanityProjectionResult} from 'groq'
|
|
2
2
|
import {filter, firstValueFrom} from 'rxjs'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {bindActionBySourceAndPerspective} from '../store/createActionBinder'
|
|
5
5
|
import {type SanityInstance} from '../store/createSanityInstance'
|
|
6
6
|
import {getProjectionState, type ProjectionOptions} from './getProjectionState'
|
|
7
7
|
import {projectionStore} from './projectionStore'
|
|
@@ -38,7 +38,7 @@ export function resolveProjection(
|
|
|
38
38
|
/**
|
|
39
39
|
* @beta
|
|
40
40
|
*/
|
|
41
|
-
const _resolveProjection =
|
|
41
|
+
const _resolveProjection = bindActionBySourceAndPerspective(
|
|
42
42
|
projectionStore,
|
|
43
43
|
(
|
|
44
44
|
{instance}: {instance: SanityInstance},
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {DocumentId, getVersionId} from '@sanity/id-utils'
|
|
2
|
+
import {describe, expect, it} from 'vitest'
|
|
3
|
+
|
|
4
|
+
import {buildStatusQueryIds, processStatusQueryResults} from './statusQuery'
|
|
5
|
+
|
|
6
|
+
describe('buildStatusQueryIds', () => {
|
|
7
|
+
it('includes draft and published ids only when perspective is not a release', () => {
|
|
8
|
+
const ids = new Set(['doc1'].map(DocumentId))
|
|
9
|
+
const result = buildStatusQueryIds(ids, 'published')
|
|
10
|
+
expect(result).toContain('drafts.doc1')
|
|
11
|
+
expect(result).toContain('doc1')
|
|
12
|
+
expect(result).toHaveLength(2)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('includes version ids when perspective is a release', () => {
|
|
16
|
+
const ids = new Set(['doc1'].map(DocumentId))
|
|
17
|
+
const perspective = {releaseName: 'myRelease'}
|
|
18
|
+
const result = buildStatusQueryIds(ids, perspective)
|
|
19
|
+
expect(result).toContain('drafts.doc1')
|
|
20
|
+
expect(result).toContain('doc1')
|
|
21
|
+
expect(result).toContain(getVersionId(DocumentId('doc1'), 'myRelease'))
|
|
22
|
+
expect(result).toHaveLength(3)
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('processStatusQueryResults', () => {
|
|
27
|
+
it('sets lastEditedVersionAt when result _id is a version id', () => {
|
|
28
|
+
const versionId = getVersionId(DocumentId('doc1'), 'myRelease')
|
|
29
|
+
const results = [{_id: versionId, _updatedAt: '2025-01-01T12:00:00Z'}]
|
|
30
|
+
const documentStatuses = processStatusQueryResults(results)
|
|
31
|
+
expect(documentStatuses['doc1']).toEqual({
|
|
32
|
+
lastEditedVersionAt: '2025-01-01T12:00:00Z',
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
})
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DocumentId,
|
|
3
|
+
getDraftId,
|
|
4
|
+
getPublishedId,
|
|
5
|
+
getVersionId,
|
|
6
|
+
isDraftId,
|
|
7
|
+
isPublishedId,
|
|
8
|
+
isVersionId,
|
|
9
|
+
} from '@sanity/id-utils'
|
|
10
|
+
|
|
11
|
+
import {isReleasePerspective} from '../releases/utils/isReleasePerspective'
|
|
12
|
+
import {type BoundPerspectiveKey} from '../store/createActionBinder'
|
|
13
|
+
import {type ProjectionStoreState} from './types'
|
|
14
|
+
|
|
15
|
+
interface StatusQueryResult {
|
|
16
|
+
_id: string
|
|
17
|
+
_updatedAt: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Builds an array of document IDs to query for status information using the "raw" perspective.
|
|
22
|
+
* Includes draft, published, and version IDs as needed.
|
|
23
|
+
*/
|
|
24
|
+
export function buildStatusQueryIds(
|
|
25
|
+
documentIds: Set<string>,
|
|
26
|
+
perspective: BoundPerspectiveKey['perspective'],
|
|
27
|
+
): string[] {
|
|
28
|
+
const ids: string[] = []
|
|
29
|
+
const releaseName = isReleasePerspective(perspective) ? perspective.releaseName : null
|
|
30
|
+
|
|
31
|
+
for (const id of documentIds) {
|
|
32
|
+
const publishedId = getPublishedId(DocumentId(id))
|
|
33
|
+
const draftId = getDraftId(publishedId)
|
|
34
|
+
|
|
35
|
+
// Always query for draft and published versions
|
|
36
|
+
ids.push(draftId, publishedId)
|
|
37
|
+
|
|
38
|
+
// If it's a release perspective, also query for the version
|
|
39
|
+
if (releaseName) {
|
|
40
|
+
ids.push(getVersionId(publishedId, releaseName))
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return ids
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Processes status query results into documentStatuses (same shape as _status returned to users).
|
|
49
|
+
*/
|
|
50
|
+
export function processStatusQueryResults(
|
|
51
|
+
results: StatusQueryResult[],
|
|
52
|
+
): ProjectionStoreState['documentStatuses'] {
|
|
53
|
+
const documentStatuses: ProjectionStoreState['documentStatuses'] = {}
|
|
54
|
+
|
|
55
|
+
for (const result of results) {
|
|
56
|
+
const id = DocumentId(result._id)
|
|
57
|
+
const updatedAt = result._updatedAt
|
|
58
|
+
const publishedId = getPublishedId(id)
|
|
59
|
+
const statusData = documentStatuses[publishedId] ?? {}
|
|
60
|
+
if (isDraftId(id)) {
|
|
61
|
+
statusData.lastEditedDraftAt = updatedAt
|
|
62
|
+
} else if (isVersionId(id)) {
|
|
63
|
+
statusData.lastEditedVersionAt = updatedAt
|
|
64
|
+
} else if (isPublishedId(id)) {
|
|
65
|
+
statusData.lastEditedPublishedAt = updatedAt
|
|
66
|
+
}
|
|
67
|
+
documentStatuses[publishedId] = statusData
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return documentStatuses
|
|
71
|
+
}
|