@sanity/sdk 3.0.0 → 3.1.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/_exports/_internal.d.ts +25 -3
- package/dist/_exports/_internal.d.ts.map +1 -1
- package/dist/_exports/_internal.js +127 -9
- package/dist/_exports/_internal.js.map +1 -1
- package/dist/_exports/agent.d.ts +1 -1
- package/dist/_exports/agent.js +1 -1
- package/dist/_exports/comlink.d.ts +1 -1
- package/dist/_exports/comlink.js +2 -3
- package/dist/_exports/comlink.js.map +1 -1
- package/dist/{authStore-C0o1NOxW.d.ts → authStore-C-OEkGaM.d.ts} +2 -2
- package/dist/{authStore-C0o1NOxW.d.ts.map → authStore-C-OEkGaM.d.ts.map} +1 -1
- package/dist/{authStore-CtE9bLHW.js → clientStore-gUALQ0qW.js} +269 -11
- package/dist/{authStore-CtE9bLHW.js.map → clientStore-gUALQ0qW.js.map} +1 -1
- package/dist/{createSanityInstance-DUI1bGIg.d.ts → createSanityInstance-DCePpBYW.d.ts} +2 -2
- package/dist/{createSanityInstance-DUI1bGIg.d.ts.map → createSanityInstance-DCePpBYW.d.ts.map} +1 -1
- package/dist/{getNodeState-CR3__B2D.js → getNodeState-E0hjqFOo.js} +2 -3
- package/dist/{getNodeState-CR3__B2D.js.map → getNodeState-E0hjqFOo.js.map} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +40 -44
- package/dist/index.js.map +1 -1
- package/dist/{createStateSourceAction-BOKtqFNm.js → object-BwynGPRZ.js} +87 -3
- package/dist/object-BwynGPRZ.js.map +1 -0
- package/dist/{queryStore-C7yMHPUI.js → version-C90rNWaX.js} +47 -15
- package/dist/version-C90rNWaX.js.map +1 -0
- package/package.json +5 -5
- package/src/_exports/_internal.ts +1 -0
- package/src/access/checkPermissions.test.ts +1 -1
- package/src/access/checkPermissions.ts +1 -1
- package/src/applications/applications.test.ts +4 -4
- package/src/applications/applications.ts +4 -4
- package/src/auth/handleAuthCallback.test.ts +2 -2
- package/src/auth/handleAuthCallback.ts +1 -1
- package/src/auth/logout.test.ts +1 -1
- package/src/auth/logout.ts +1 -1
- package/src/auth/refreshStampedToken.ts +1 -1
- package/src/auth/studioModeAuth.test.ts +1 -1
- package/src/auth/studioModeAuth.ts +1 -1
- package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +2 -2
- package/src/auth/subscribeToStateAndFetchCurrentUser.ts +1 -1
- package/src/comments/addonDatasetStore.test.ts +2 -2
- package/src/comments/addonDatasetStore.ts +2 -2
- package/src/comments/commentActions.ts +6 -5
- package/src/comments/commentsStore.ts +4 -4
- package/src/document/applyDocumentActions.ts +2 -6
- package/src/document/documentStore.concurrency.test.ts +2 -1
- package/src/document/documentStore.test.ts +19 -18
- package/src/document/documentStore.ts +5 -5
- package/src/document/permissions.ts +2 -1
- package/src/document/processActions.test.ts +2 -1
- package/src/document/processMutations.ts +3 -2
- package/src/document/reducers.ts +2 -2
- package/src/installations/installations.test.ts +2 -2
- package/src/installations/installations.ts +2 -2
- package/src/organization/organization.test.ts +2 -2
- package/src/organization/organization.ts +1 -1
- package/src/organizations/organizations.test.ts +2 -2
- package/src/organizations/organizations.ts +1 -1
- package/src/presence/presenceStore.test.ts +15 -22
- package/src/presence/presenceStore.ts +3 -2
- package/src/project/project.test.ts +3 -3
- package/src/project/project.ts +1 -1
- package/src/projection/getProjectionState.test.ts +6 -4
- package/src/projection/getProjectionState.ts +2 -2
- package/src/projects/projects.test.ts +2 -2
- package/src/projects/projects.ts +1 -1
- package/src/query/queryStore.ts +3 -3
- package/src/store/createSanityInstance.test.ts +1 -1
- package/src/store/createSanityInstance.ts +4 -4
- package/src/store/createStoreInstance.test.ts +0 -5
- package/src/telemetry/telemetryManager.test.ts +1 -1
- package/src/telemetry/telemetryManager.ts +2 -2
- package/src/users/usersStore.test.ts +1 -1
- package/src/users/usersStore.ts +5 -5
- package/src/utils/ids.test.ts +40 -15
- package/src/utils/ids.ts +47 -2
- package/dist/clientStore-BtE2-q2i.js +0 -90
- package/dist/clientStore-BtE2-q2i.js.map +0 -1
- package/dist/createStateSourceAction-BOKtqFNm.js.map +0 -1
- package/dist/getEnv-D5RGkQLu.js +0 -8
- package/dist/getEnv-D5RGkQLu.js.map +0 -1
- package/dist/logger-DAtJb5RQ.js +0 -173
- package/dist/logger-DAtJb5RQ.js.map +0 -1
- package/dist/object-CxXlSVg7.js +0 -83
- package/dist/object-CxXlSVg7.js.map +0 -1
- package/dist/queryStore-C7yMHPUI.js.map +0 -1
- package/dist/rolldown-runtime-vyAXikos.js +0 -9
- package/dist/telemetryManager-UIEiMtC0.js +0 -127
- package/dist/telemetryManager-UIEiMtC0.js.map +0 -1
- package/dist/version-D8RP_Q59.js +0 -9
- package/dist/version-D8RP_Q59.js.map +0 -1
|
@@ -57,7 +57,7 @@ describe('subscribeToStateAndFetchCurrentUser', () => {
|
|
|
57
57
|
})
|
|
58
58
|
expect(mockRequest).toHaveBeenCalledWith({
|
|
59
59
|
method: 'GET',
|
|
60
|
-
|
|
60
|
+
url: '/users/me',
|
|
61
61
|
tag: 'users.get-current',
|
|
62
62
|
})
|
|
63
63
|
|
|
@@ -97,7 +97,7 @@ describe('subscribeToStateAndFetchCurrentUser', () => {
|
|
|
97
97
|
})
|
|
98
98
|
expect(mockRequest).toHaveBeenCalledWith({
|
|
99
99
|
method: 'GET',
|
|
100
|
-
|
|
100
|
+
url: '/users/me',
|
|
101
101
|
tag: 'users.get-current',
|
|
102
102
|
})
|
|
103
103
|
|
|
@@ -59,7 +59,7 @@ describe('getAddonDatasetState', () => {
|
|
|
59
59
|
)
|
|
60
60
|
|
|
61
61
|
expect(observableRequest).toHaveBeenCalledWith({
|
|
62
|
-
|
|
62
|
+
url: '/projects/p/datasets?datasetProfile=comments&addonFor=d',
|
|
63
63
|
tag: 'comments.addon-dataset.list',
|
|
64
64
|
})
|
|
65
65
|
})
|
|
@@ -139,7 +139,7 @@ describe('provisionAddonDataset', () => {
|
|
|
139
139
|
|
|
140
140
|
await expect(provisionAddonDataset(instance, {})).resolves.toBe('d-comments')
|
|
141
141
|
expect(request).toHaveBeenCalledWith({
|
|
142
|
-
|
|
142
|
+
url: '/comments/d/setup',
|
|
143
143
|
method: 'POST',
|
|
144
144
|
tag: 'comments.addon-dataset.setup',
|
|
145
145
|
})
|
|
@@ -67,7 +67,7 @@ function requestAddonDataset(
|
|
|
67
67
|
): Observable<string | undefined> {
|
|
68
68
|
return client.observable
|
|
69
69
|
.request<{name: string}[] | undefined>({
|
|
70
|
-
|
|
70
|
+
url: `/projects/${projectId}/datasets?datasetProfile=${ADDON_DATASET_PROFILE}&addonFor=${dataset}`,
|
|
71
71
|
tag: 'comments.addon-dataset.list',
|
|
72
72
|
})
|
|
73
73
|
.pipe(map((datasets) => datasets?.[0]?.name))
|
|
@@ -182,7 +182,7 @@ export const provisionAddonDataset: (
|
|
|
182
182
|
})
|
|
183
183
|
|
|
184
184
|
const response = await client.request<{datasetName?: string} | undefined>({
|
|
185
|
-
|
|
185
|
+
url: `/comments/${resource.dataset}/setup`,
|
|
186
186
|
method: 'POST',
|
|
187
187
|
tag: 'comments.addon-dataset.setup',
|
|
188
188
|
})
|
|
@@ -16,6 +16,7 @@ import {bindActionByResource, type BoundResourceKey} from '../store/createAction
|
|
|
16
16
|
import {type SanityInstance} from '../store/createSanityInstance'
|
|
17
17
|
import {type StoreState} from '../store/createStoreState'
|
|
18
18
|
import {type StoreContext} from '../store/defineStore'
|
|
19
|
+
import {randomUuid} from '../utils/ids'
|
|
19
20
|
import {
|
|
20
21
|
assertDatasetResource,
|
|
21
22
|
getAddonDatasetState,
|
|
@@ -326,7 +327,7 @@ export const createComment: (
|
|
|
326
327
|
options,
|
|
327
328
|
buildCommentPayload({
|
|
328
329
|
authorId: requireCurrentUserId(instance),
|
|
329
|
-
commentId: options.commentId ??
|
|
330
|
+
commentId: options.commentId ?? randomUuid(),
|
|
330
331
|
contentSnapshot: options.contentSnapshot,
|
|
331
332
|
context: options.context,
|
|
332
333
|
documentRevisionId: options.documentRevisionId,
|
|
@@ -336,7 +337,7 @@ export const createComment: (
|
|
|
336
337
|
fieldPath,
|
|
337
338
|
selection: options.selection,
|
|
338
339
|
status: options.status ?? 'open',
|
|
339
|
-
threadId: options.threadId ??
|
|
340
|
+
threadId: options.threadId ?? randomUuid(),
|
|
340
341
|
...(isReleasePerspective(perspective) ? {documentVersionId: perspective.releaseName} : {}),
|
|
341
342
|
}),
|
|
342
343
|
)
|
|
@@ -386,7 +387,7 @@ export const replyToComment: (
|
|
|
386
387
|
options,
|
|
387
388
|
buildCommentPayload({
|
|
388
389
|
authorId: requireCurrentUserId(instance),
|
|
389
|
-
commentId: options.commentId ??
|
|
390
|
+
commentId: options.commentId ?? randomUuid(),
|
|
390
391
|
handle: options,
|
|
391
392
|
message: options.message,
|
|
392
393
|
// Replies to a reply belong to the thread's first comment, matching how
|
|
@@ -420,7 +421,7 @@ export const updateComment: (
|
|
|
420
421
|
{commentId, message}: UpdateCommentOptions,
|
|
421
422
|
) => {
|
|
422
423
|
const lastEditedAt = new Date().toISOString()
|
|
423
|
-
const transactionId =
|
|
424
|
+
const transactionId = randomUuid()
|
|
424
425
|
const previous = findCommentById(state, commentId)
|
|
425
426
|
|
|
426
427
|
if (previous) {
|
|
@@ -468,7 +469,7 @@ export const setCommentStatus: (
|
|
|
468
469
|
{state, instance, key}: StoreContext<CommentsStoreState, BoundResourceKey>,
|
|
469
470
|
{commentId, status}: SetCommentStatusOptions,
|
|
470
471
|
) => {
|
|
471
|
-
const transactionId =
|
|
472
|
+
const transactionId = randomUuid()
|
|
472
473
|
const previousComments: StoredComment[] = []
|
|
473
474
|
|
|
474
475
|
for (const entry of Object.values(state.get().entries)) {
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
} from '../store/createStateSourceAction'
|
|
30
30
|
import {type StoreState} from '../store/createStoreState'
|
|
31
31
|
import {defineStore, type StoreContext} from '../store/defineStore'
|
|
32
|
-
import {
|
|
32
|
+
import {randomId} from '../utils/ids'
|
|
33
33
|
import {setCleanupTimeout} from '../utils/setCleanupTimeout'
|
|
34
34
|
import {observeAddonDatasetClient} from './addonDatasetStore'
|
|
35
35
|
import {buildCommentThreads} from './buildCommentThreads'
|
|
@@ -360,7 +360,7 @@ export const getCommentsState: (
|
|
|
360
360
|
selector: selectComments,
|
|
361
361
|
onSubscribe: ({state, instance}, options: CommentsOptions) => {
|
|
362
362
|
const key = getCommentsKey(toCommentsKeyParts(instance, options))
|
|
363
|
-
const subscriptionId =
|
|
363
|
+
const subscriptionId = randomId(16)
|
|
364
364
|
state.set('addSubscriber', addSubscriber(key, subscriptionId))
|
|
365
365
|
|
|
366
366
|
return () => {
|
|
@@ -390,7 +390,7 @@ export const getCommentThreadsState: (
|
|
|
390
390
|
selector: selectCommentThreads,
|
|
391
391
|
onSubscribe: ({state, instance}, options: CommentsOptions) => {
|
|
392
392
|
const key = getCommentsKey(toCommentsKeyParts(instance, options))
|
|
393
|
-
const subscriptionId =
|
|
393
|
+
const subscriptionId = randomId(16)
|
|
394
394
|
state.set('addSubscriber', addSubscriber(key, subscriptionId))
|
|
395
395
|
|
|
396
396
|
return () => {
|
|
@@ -452,7 +452,7 @@ function resolveList<T>(
|
|
|
452
452
|
// fetch and this promise would never settle. Holding it only for the duration
|
|
453
453
|
// of the resolve also means a component that suspends and then errors before
|
|
454
454
|
// mounting does not leave a subscriber-less entry behind holding its error.
|
|
455
|
-
const subscriptionId =
|
|
455
|
+
const subscriptionId = randomId(16)
|
|
456
456
|
state.set('addSubscriber', addSubscriber(key, subscriptionId))
|
|
457
457
|
|
|
458
458
|
const release = () => state.set('removeSubscriber', removeSubscriber(key, subscriptionId))
|
|
@@ -5,6 +5,7 @@ import {type DocumentResource} from '../config/sanityConfig'
|
|
|
5
5
|
import {bindActionByResource} from '../store/createActionBinder'
|
|
6
6
|
import {type SanityInstance} from '../store/createSanityInstance'
|
|
7
7
|
import {type StoreContext} from '../store/defineStore'
|
|
8
|
+
import {randomUuid} from '../utils/ids'
|
|
8
9
|
import {type Action} from './actions'
|
|
9
10
|
import {documentStore, type DocumentStoreState} from './documentStore'
|
|
10
11
|
import {type DocumentTransactionSubmissionResult} from './events'
|
|
@@ -74,12 +75,7 @@ const boundApplyDocumentActions = bindActionByResource(documentStore, _applyDocu
|
|
|
74
75
|
/** @internal */
|
|
75
76
|
async function _applyDocumentActions(
|
|
76
77
|
{state}: StoreContext<DocumentStoreState>,
|
|
77
|
-
{
|
|
78
|
-
actions,
|
|
79
|
-
resource,
|
|
80
|
-
transactionId = crypto.randomUUID(),
|
|
81
|
-
disableBatching,
|
|
82
|
-
}: ApplyDocumentActionsOptions,
|
|
78
|
+
{actions, resource, transactionId = randomUuid(), disableBatching}: ApplyDocumentActionsOptions,
|
|
83
79
|
): Promise<ActionsResult> {
|
|
84
80
|
const {events} = state.get()
|
|
85
81
|
|
|
@@ -44,6 +44,7 @@ import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest'
|
|
|
44
44
|
import {getClientState} from '../client/clientStore'
|
|
45
45
|
import {createSanityInstance, type SanityInstance} from '../store/createSanityInstance'
|
|
46
46
|
import {type StateSource} from '../store/createStateSourceAction'
|
|
47
|
+
import {randomUuid} from '../utils/ids'
|
|
47
48
|
import {editDocument, publishDocument} from './actions'
|
|
48
49
|
import {applyDocumentActions} from './applyDocumentActions'
|
|
49
50
|
import {getDocumentState, getDocumentSyncStatus} from './documentStore'
|
|
@@ -273,7 +274,7 @@ function createMockClient(server: MockContentLake): SanityClient {
|
|
|
273
274
|
|
|
274
275
|
const action = vi.fn(async (input: HttpAction | HttpAction[], options?: BaseActionOptions) => {
|
|
275
276
|
const actions = Array.isArray(input) ? input : [input]
|
|
276
|
-
return server.submitActions(actions, options?.transactionId ??
|
|
277
|
+
return server.submitActions(actions, options?.transactionId ?? randomUuid())
|
|
277
278
|
})
|
|
278
279
|
|
|
279
280
|
const request = vi.fn(async () => {
|
|
@@ -36,6 +36,7 @@ import {getClientState} from '../client/clientStore'
|
|
|
36
36
|
import {createDocumentHandle} from '../config/handles'
|
|
37
37
|
import {createSanityInstance, type SanityInstance} from '../store/createSanityInstance'
|
|
38
38
|
import {type StateSource} from '../store/createStateSourceAction'
|
|
39
|
+
import {randomUuid} from '../utils/ids'
|
|
39
40
|
import {
|
|
40
41
|
createDocument,
|
|
41
42
|
deleteDocument,
|
|
@@ -369,7 +370,7 @@ it('labels an echo that arrives after the last subscriber left as its own', asyn
|
|
|
369
370
|
// and out of band, which is the ordering the real API produces
|
|
370
371
|
const clientActionMockImplementation = vi.mocked(client.action).getMockImplementation()!
|
|
371
372
|
vi.mocked(client.action).mockImplementation(
|
|
372
|
-
async (_input, {transactionId =
|
|
373
|
+
async (_input, {transactionId = randomUuid()} = {}) => ({transactionId}),
|
|
373
374
|
)
|
|
374
375
|
|
|
375
376
|
const patchEvents: DocumentRemotePatchesEvent[] = []
|
|
@@ -671,7 +672,7 @@ it('fetches documents if there are no active subscriptions for the actions appli
|
|
|
671
672
|
})
|
|
672
673
|
|
|
673
674
|
it('batches edit transaction into one outgoing transaction', async () => {
|
|
674
|
-
const doc = createDocumentHandle({documentId:
|
|
675
|
+
const doc = createDocumentHandle({documentId: randomUuid(), documentType: 'article'})
|
|
675
676
|
|
|
676
677
|
const unsubscribe = getDocumentState(instance, doc).subscribe()
|
|
677
678
|
|
|
@@ -747,7 +748,7 @@ it('submits liveEdit document edits through observable.mutate', async () => {
|
|
|
747
748
|
})
|
|
748
749
|
|
|
749
750
|
it('provides the consistency status via `getDocumentSyncStatus`', async () => {
|
|
750
|
-
const doc = createDocumentHandle({documentId:
|
|
751
|
+
const doc = createDocumentHandle({documentId: randomUuid(), documentType: 'article'})
|
|
751
752
|
|
|
752
753
|
const syncStatus = getDocumentSyncStatus(instance, doc)
|
|
753
754
|
expect(syncStatus.getCurrent()).toBeUndefined()
|
|
@@ -802,7 +803,7 @@ it('reverts failed outgoing transaction locally', async () => {
|
|
|
802
803
|
})
|
|
803
804
|
})
|
|
804
805
|
|
|
805
|
-
const documentId = DocumentId(
|
|
806
|
+
const documentId = DocumentId(randomUuid())
|
|
806
807
|
const doc = createDocumentHandle({documentId, documentType: 'article'})
|
|
807
808
|
|
|
808
809
|
const {getCurrent, subscribe} = getDocumentState(instance, doc)
|
|
@@ -870,7 +871,7 @@ it('removes a queued transaction if it fails to apply', async () => {
|
|
|
870
871
|
})
|
|
871
872
|
})
|
|
872
873
|
|
|
873
|
-
const doc = createDocumentHandle({documentId:
|
|
874
|
+
const doc = createDocumentHandle({documentId: randomUuid(), documentType: 'article'})
|
|
874
875
|
const state = getDocumentState(instance, doc)
|
|
875
876
|
const unsubscribe = state.subscribe()
|
|
876
877
|
|
|
@@ -975,8 +976,8 @@ it('fetches dataset ACL and updates grants in the document store state', async (
|
|
|
975
976
|
]
|
|
976
977
|
vi.mocked(client.request).mockResolvedValue(datasetAcl)
|
|
977
978
|
|
|
978
|
-
const book = createDocumentHandle({documentId:
|
|
979
|
-
const author = createDocumentHandle({documentId:
|
|
979
|
+
const book = createDocumentHandle({documentId: randomUuid(), documentType: 'book'})
|
|
980
|
+
const author = createDocumentHandle({documentId: randomUuid(), documentType: 'author'})
|
|
980
981
|
|
|
981
982
|
expect(await resolvePermissions(instance, {actions: [createDocument(book)]})).toEqual({
|
|
982
983
|
allowed: true,
|
|
@@ -988,12 +989,12 @@ it('fetches dataset ACL and updates grants in the document store state', async (
|
|
|
988
989
|
})
|
|
989
990
|
|
|
990
991
|
it('does not send credentials with the dataset ACL request', async () => {
|
|
991
|
-
const doc = createDocumentHandle({documentId:
|
|
992
|
+
const doc = createDocumentHandle({documentId: randomUuid(), documentType: 'article'})
|
|
992
993
|
await resolvePermissions(instance, {actions: [createDocument(doc)]})
|
|
993
994
|
|
|
994
995
|
const aclCall = vi
|
|
995
996
|
.mocked(client.request)
|
|
996
|
-
.mock.calls.find(([options]) => options.
|
|
997
|
+
.mock.calls.find(([options]) => options.url?.endsWith('/acl'))
|
|
997
998
|
expect(aclCall).toBeDefined()
|
|
998
999
|
expect(aclCall![0]).not.toHaveProperty('withCredentials')
|
|
999
1000
|
})
|
|
@@ -1011,7 +1012,7 @@ it('retries transient dataset ACL fetch failures instead of failing fatally', as
|
|
|
1011
1012
|
}),
|
|
1012
1013
|
)
|
|
1013
1014
|
|
|
1014
|
-
const doc = createDocumentHandle({documentId:
|
|
1015
|
+
const doc = createDocumentHandle({documentId: randomUuid(), documentType: 'article'})
|
|
1015
1016
|
const result = await resolvePermissions(instance, {actions: [createDocument(doc)]})
|
|
1016
1017
|
|
|
1017
1018
|
expect(result).toEqual({allowed: true})
|
|
@@ -1037,7 +1038,7 @@ it('does not retry dataset ACL fetch failures caused by 4xx client errors', asyn
|
|
|
1037
1038
|
}),
|
|
1038
1039
|
)
|
|
1039
1040
|
|
|
1040
|
-
const doc = createDocumentHandle({documentId:
|
|
1041
|
+
const doc = createDocumentHandle({documentId: randomUuid(), documentType: 'article'})
|
|
1041
1042
|
const documentState = getDocumentState(instance, doc)
|
|
1042
1043
|
const unsubscribe = documentState.subscribe()
|
|
1043
1044
|
|
|
@@ -1070,7 +1071,7 @@ it('retries dataset ACL fetch failures caused by 429 rate-limit errors', async (
|
|
|
1070
1071
|
}),
|
|
1071
1072
|
)
|
|
1072
1073
|
|
|
1073
|
-
const doc = createDocumentHandle({documentId:
|
|
1074
|
+
const doc = createDocumentHandle({documentId: randomUuid(), documentType: 'article'})
|
|
1074
1075
|
const result = await resolvePermissions(instance, {actions: [createDocument(doc)]})
|
|
1075
1076
|
|
|
1076
1077
|
expect(result).toEqual({allowed: true})
|
|
@@ -1087,7 +1088,7 @@ it('fetches ACL for MediaLibraryResource', async () => {
|
|
|
1087
1088
|
const datasetAcl = [{filter: 'true', permissions: ['read', 'update', 'create', 'history']}]
|
|
1088
1089
|
vi.mocked(client.request).mockResolvedValue(datasetAcl)
|
|
1089
1090
|
|
|
1090
|
-
const doc = createDocumentHandle({documentId:
|
|
1091
|
+
const doc = createDocumentHandle({documentId: randomUuid(), documentType: 'article'})
|
|
1091
1092
|
const mediaLibraryResource = {mediaLibraryId: 'test-media-library'}
|
|
1092
1093
|
|
|
1093
1094
|
const result = await resolvePermissions(mediaLibraryInstance, {
|
|
@@ -1105,7 +1106,7 @@ it('fetches ACL for CanvasResource', async () => {
|
|
|
1105
1106
|
const datasetAcl = [{filter: 'true', permissions: ['read', 'update', 'create', 'history']}]
|
|
1106
1107
|
vi.mocked(client.request).mockResolvedValue(datasetAcl)
|
|
1107
1108
|
|
|
1108
|
-
const doc = createDocumentHandle({documentId:
|
|
1109
|
+
const doc = createDocumentHandle({documentId: randomUuid(), documentType: 'article'})
|
|
1109
1110
|
const canvasResource = {canvasId: 'test-canvas'}
|
|
1110
1111
|
|
|
1111
1112
|
const result = await resolvePermissions(canvasInstance, {
|
|
@@ -1118,7 +1119,7 @@ it('fetches ACL for CanvasResource', async () => {
|
|
|
1118
1119
|
})
|
|
1119
1120
|
|
|
1120
1121
|
it('returns a promise that resolves when a document has been loaded in the store (useful for suspense)', async () => {
|
|
1121
|
-
const documentId = DocumentId(
|
|
1122
|
+
const documentId = DocumentId(randomUuid())
|
|
1122
1123
|
const doc = createDocumentHandle({documentId, documentType: 'article'})
|
|
1123
1124
|
|
|
1124
1125
|
expect(await resolveDocument(instance, doc)).toBe(null)
|
|
@@ -1143,7 +1144,7 @@ it('emits an event for each action after an outgoing transaction has been accept
|
|
|
1143
1144
|
const handler = vi.fn()
|
|
1144
1145
|
const unsubscribe = subscribeDocumentEvents(instance, {resource, eventHandler: handler})
|
|
1145
1146
|
|
|
1146
|
-
const documentId = DocumentId(
|
|
1147
|
+
const documentId = DocumentId(randomUuid())
|
|
1147
1148
|
const doc = createDocumentHandle({documentId, documentType: 'article'})
|
|
1148
1149
|
expect(handler).toHaveBeenCalledTimes(0)
|
|
1149
1150
|
|
|
@@ -1574,7 +1575,7 @@ beforeEach(() => {
|
|
|
1574
1575
|
mutations: Mutation[],
|
|
1575
1576
|
options: BaseMutationOptions = {},
|
|
1576
1577
|
): Promise<MultipleMutationResult> => {
|
|
1577
|
-
const transactionId = options.transactionId ??
|
|
1578
|
+
const transactionId = options.transactionId ?? randomUuid()
|
|
1578
1579
|
const timestamp = new Date().toISOString()
|
|
1579
1580
|
const prior = {...documents}
|
|
1580
1581
|
let next = {...documents}
|
|
@@ -1647,7 +1648,7 @@ beforeEach(() => {
|
|
|
1647
1648
|
const action = vi.fn(
|
|
1648
1649
|
async (
|
|
1649
1650
|
input: HttpAction | HttpAction[],
|
|
1650
|
-
{transactionId =
|
|
1651
|
+
{transactionId = randomUuid(), dryRun}: BaseActionOptions,
|
|
1651
1652
|
): Promise<SingleActionResult | MultipleActionResult> => {
|
|
1652
1653
|
const actions = Array.isArray(input) ? input : [input]
|
|
1653
1654
|
let next: DocumentSet = {...documents}
|
|
@@ -550,13 +550,13 @@ const subscribeToClientAndFetchDatasetAcl = ({
|
|
|
550
550
|
}: StoreContext<DocumentStoreState, BoundResourceKey>) => {
|
|
551
551
|
const clientOptions: ClientOptions = {apiVersion: API_VERSION, resource}
|
|
552
552
|
|
|
553
|
-
let
|
|
553
|
+
let url: string
|
|
554
554
|
if (resource && isDatasetResource(resource)) {
|
|
555
|
-
|
|
555
|
+
url = `/projects/${resource.projectId}/datasets/${resource.dataset}/acl`
|
|
556
556
|
} else if (resource && isMediaLibraryResource(resource)) {
|
|
557
|
-
|
|
557
|
+
url = `/media-libraries/${resource.mediaLibraryId}/acl`
|
|
558
558
|
} else if (resource && isCanvasResource(resource)) {
|
|
559
|
-
|
|
559
|
+
url = `/canvases/${resource.canvasId}/acl`
|
|
560
560
|
} else {
|
|
561
561
|
throw new Error(`Received invalid resource: ${JSON.stringify(resource)}`)
|
|
562
562
|
}
|
|
@@ -566,7 +566,7 @@ const subscribeToClientAndFetchDatasetAcl = ({
|
|
|
566
566
|
switchMap((client) =>
|
|
567
567
|
client.observable
|
|
568
568
|
.request<DatasetAcl>({
|
|
569
|
-
|
|
569
|
+
url,
|
|
570
570
|
tag: 'acl.get',
|
|
571
571
|
})
|
|
572
572
|
.pipe(
|
|
@@ -5,6 +5,7 @@ import {createSelector} from 'reselect'
|
|
|
5
5
|
|
|
6
6
|
import {isReleasePerspective} from '../releases/utils/isReleasePerspective'
|
|
7
7
|
import {type SelectorContext} from '../store/createStateSourceAction'
|
|
8
|
+
import {randomId} from '../utils/ids'
|
|
8
9
|
import {MultiKeyWeakMap} from '../utils/MultiKeyWeakMap'
|
|
9
10
|
import {type DocumentAction} from './actions'
|
|
10
11
|
import {ActionError, PermissionActionError, processActions} from './processActions/processActions'
|
|
@@ -190,7 +191,7 @@ const _calculatePermissions = createSelector(
|
|
|
190
191
|
try {
|
|
191
192
|
processActions({
|
|
192
193
|
actions,
|
|
193
|
-
transactionId:
|
|
194
|
+
transactionId: randomId(16),
|
|
194
195
|
working: documents,
|
|
195
196
|
base: documents,
|
|
196
197
|
timestamp,
|
|
@@ -2,6 +2,7 @@ import {type CreateMutation, type Reference, type SanityDocument} from '@sanity/
|
|
|
2
2
|
import {parse} from 'groq-js'
|
|
3
3
|
import {describe, expect, it} from 'vitest'
|
|
4
4
|
|
|
5
|
+
import {randomUuid} from '../utils/ids'
|
|
5
6
|
import {type Action, type DocumentAction} from './actions'
|
|
6
7
|
import {ActionError, processActions} from './processActions/processActions'
|
|
7
8
|
import {type DocumentSet, processMutations} from './processMutations'
|
|
@@ -973,7 +974,7 @@ describe('processActions', () => {
|
|
|
973
974
|
})
|
|
974
975
|
|
|
975
976
|
it('should strengthen `_strengthenOnPublish` references', () => {
|
|
976
|
-
const _ref =
|
|
977
|
+
const _ref = randomUuid()
|
|
977
978
|
const referenceToStrength: Reference = {
|
|
978
979
|
_ref,
|
|
979
980
|
_type: 'reference',
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type SanityDocument,
|
|
6
6
|
} from '@sanity/types'
|
|
7
7
|
|
|
8
|
+
import {randomUuid} from '../utils/ids'
|
|
8
9
|
import {
|
|
9
10
|
dec,
|
|
10
11
|
diffMatchPatch,
|
|
@@ -63,8 +64,8 @@ const patchOperations = {
|
|
|
63
64
|
* [- source](https://www.sanity.io/docs/http-mutations#c732f27330a4)
|
|
64
65
|
*/
|
|
65
66
|
export function getId(id?: string): string {
|
|
66
|
-
if (!id || typeof id !== 'string') return
|
|
67
|
-
if (id.endsWith('.')) return `${id}${
|
|
67
|
+
if (!id || typeof id !== 'string') return randomUuid()
|
|
68
|
+
if (id.endsWith('.')) return `${id}${randomUuid()}`
|
|
68
69
|
return id
|
|
69
70
|
}
|
|
70
71
|
|
package/src/document/reducers.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {type Mutation, type PatchOperations, type SanityDocumentLike} from '@san
|
|
|
4
4
|
import {type DocumentHandle} from '../config/sanityConfig'
|
|
5
5
|
import {isReleasePerspective} from '../releases/utils/isReleasePerspective'
|
|
6
6
|
import {type StoreContext} from '../store/defineStore'
|
|
7
|
-
import {
|
|
7
|
+
import {randomId} from '../utils/ids'
|
|
8
8
|
import {isDeepEqual, omitProperty} from '../utils/object'
|
|
9
9
|
import {setCleanupTimeout} from '../utils/setCleanupTimeout'
|
|
10
10
|
import {type Action} from './actions'
|
|
@@ -790,7 +790,7 @@ export function manageSubscriberIds(
|
|
|
790
790
|
): () => void {
|
|
791
791
|
const documentIds = getDocumentIdsFromHandleLikes(handles)
|
|
792
792
|
|
|
793
|
-
const subscriptionId =
|
|
793
|
+
const subscriptionId = randomId(16)
|
|
794
794
|
state.set('addSubscribers', (prev) =>
|
|
795
795
|
documentIds.reduce(
|
|
796
796
|
(acc, id) => addSubscriptionIdToDocument(acc, id, subscriptionId),
|
|
@@ -40,7 +40,7 @@ describe('installations', () => {
|
|
|
40
40
|
scope: 'global',
|
|
41
41
|
})
|
|
42
42
|
expect(request).toHaveBeenCalledWith({
|
|
43
|
-
|
|
43
|
+
url: '/installations',
|
|
44
44
|
query: {organizationId: 'org1', include: 'interfaces'},
|
|
45
45
|
tag: 'installations.list',
|
|
46
46
|
})
|
|
@@ -54,7 +54,7 @@ describe('installations', () => {
|
|
|
54
54
|
|
|
55
55
|
expect(result).toEqual(inst)
|
|
56
56
|
expect(request).toHaveBeenCalledWith({
|
|
57
|
-
|
|
57
|
+
url: '/installations/inst1',
|
|
58
58
|
query: {},
|
|
59
59
|
tag: 'installations.get',
|
|
60
60
|
})
|
|
@@ -160,7 +160,7 @@ export const installations = defineFetcher<
|
|
|
160
160
|
getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(
|
|
161
161
|
switchMap((client) =>
|
|
162
162
|
client.observable.request<InstallationsResponse<InstallationInclude>>({
|
|
163
|
-
|
|
163
|
+
url: '/installations',
|
|
164
164
|
query: buildQuery({
|
|
165
165
|
organizationId: options.organizationId,
|
|
166
166
|
include: serializeInclude(options.include),
|
|
@@ -196,7 +196,7 @@ export const installation = defineFetcher<
|
|
|
196
196
|
getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(
|
|
197
197
|
switchMap((client) =>
|
|
198
198
|
client.observable.request<Installation<InstallationInclude>>({
|
|
199
|
-
|
|
199
|
+
url: `/installations/${installationId}`,
|
|
200
200
|
query: buildQuery({include: serializeInclude(options?.include)}),
|
|
201
201
|
tag: 'installations.get',
|
|
202
202
|
}),
|
|
@@ -35,7 +35,7 @@ describe('organization', () => {
|
|
|
35
35
|
const result = await organization.resolveState(instance, {organizationId: 'org_1'})
|
|
36
36
|
expect(result).toEqual(detail)
|
|
37
37
|
expect(request).toHaveBeenCalledWith({
|
|
38
|
-
|
|
38
|
+
url: '/organizations/org_1',
|
|
39
39
|
query: {includeMembers: 'false', includeFeatures: 'false'},
|
|
40
40
|
tag: 'organizations.get',
|
|
41
41
|
})
|
|
@@ -58,7 +58,7 @@ describe('organization', () => {
|
|
|
58
58
|
})
|
|
59
59
|
|
|
60
60
|
expect(request).toHaveBeenCalledWith({
|
|
61
|
-
|
|
61
|
+
url: '/organizations/org_1',
|
|
62
62
|
query: {
|
|
63
63
|
includeMembers: 'true',
|
|
64
64
|
includeFeatures: 'true',
|
|
@@ -128,7 +128,7 @@ export const organization = defineFetcher<
|
|
|
128
128
|
getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(
|
|
129
129
|
switchMap((client) =>
|
|
130
130
|
client.observable.request<Organization<boolean, boolean>>({
|
|
131
|
-
|
|
131
|
+
url: `/organizations/${resolveOrganizationId(options)}`,
|
|
132
132
|
query: buildQuery(normalizeOrganizationOptions(options)),
|
|
133
133
|
tag: 'organizations.get',
|
|
134
134
|
}),
|
|
@@ -35,7 +35,7 @@ describe('organizations', () => {
|
|
|
35
35
|
const result = await organizations.resolveState(instance)
|
|
36
36
|
expect(result).toEqual(list)
|
|
37
37
|
expect(request).toHaveBeenCalledWith({
|
|
38
|
-
|
|
38
|
+
url: '/organizations',
|
|
39
39
|
query: {
|
|
40
40
|
includeImplicitMemberships: 'false',
|
|
41
41
|
includeMembers: 'false',
|
|
@@ -62,7 +62,7 @@ describe('organizations', () => {
|
|
|
62
62
|
})
|
|
63
63
|
|
|
64
64
|
expect(request).toHaveBeenCalledWith({
|
|
65
|
-
|
|
65
|
+
url: '/organizations',
|
|
66
66
|
query: {
|
|
67
67
|
includeImplicitMemberships: 'true',
|
|
68
68
|
includeMembers: 'true',
|
|
@@ -94,7 +94,7 @@ export const organizations = defineFetcher<
|
|
|
94
94
|
getClientState(instance, {apiVersion: API_VERSION, scope: 'global'}).observable.pipe(
|
|
95
95
|
switchMap((client) =>
|
|
96
96
|
client.observable.request<Organizations<boolean, boolean>>({
|
|
97
|
-
|
|
97
|
+
url: '/organizations',
|
|
98
98
|
query: buildQuery(normalizeOrganizationsOptions(options)),
|
|
99
99
|
tag: 'organizations.list',
|
|
100
100
|
}),
|
|
@@ -24,6 +24,12 @@ vi.mock('../client/clientStore')
|
|
|
24
24
|
vi.mock('../users/usersStore')
|
|
25
25
|
vi.mock('./bifurTransport')
|
|
26
26
|
|
|
27
|
+
function lastTransportSessionId(): string {
|
|
28
|
+
const call = vi.mocked(createBifurTransport).mock.calls.at(-1)
|
|
29
|
+
if (!call) throw new Error('createBifurTransport was not called')
|
|
30
|
+
return call[0].sessionId
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
describe('presenceStore', () => {
|
|
28
34
|
let instance: SanityInstance
|
|
29
35
|
let mockClient: SanityClient
|
|
@@ -49,13 +55,6 @@ describe('presenceStore', () => {
|
|
|
49
55
|
beforeEach(() => {
|
|
50
56
|
vi.clearAllMocks()
|
|
51
57
|
|
|
52
|
-
// Mock crypto.randomUUID
|
|
53
|
-
Object.defineProperty(global, 'crypto', {
|
|
54
|
-
value: {
|
|
55
|
-
randomUUID: vi.fn(() => 'test-session-id'),
|
|
56
|
-
},
|
|
57
|
-
})
|
|
58
|
-
|
|
59
58
|
mockClient = {
|
|
60
59
|
withConfig: vi.fn().mockReturnThis(),
|
|
61
60
|
observable: {
|
|
@@ -103,7 +102,7 @@ describe('presenceStore', () => {
|
|
|
103
102
|
expect(createBifurTransport).toHaveBeenCalledWith({
|
|
104
103
|
client: mockClient,
|
|
105
104
|
token$: expect.any(Object),
|
|
106
|
-
sessionId:
|
|
105
|
+
sessionId: expect.stringMatching(/^[a-zA-Z0-9]{16}$/),
|
|
107
106
|
})
|
|
108
107
|
})
|
|
109
108
|
|
|
@@ -164,7 +163,7 @@ describe('presenceStore', () => {
|
|
|
164
163
|
mockIncomingEvents.next({
|
|
165
164
|
type: 'state',
|
|
166
165
|
userId: 'user-1',
|
|
167
|
-
sessionId:
|
|
166
|
+
sessionId: lastTransportSessionId(), // Same as our session
|
|
168
167
|
timestamp: '2023-01-01T12:00:00Z',
|
|
169
168
|
locations: [],
|
|
170
169
|
})
|
|
@@ -314,7 +313,7 @@ describe('presenceStore', () => {
|
|
|
314
313
|
getPresence(instance, {resource: canvasResource})
|
|
315
314
|
|
|
316
315
|
expect(mockClient.observable.request).toHaveBeenCalledWith({
|
|
317
|
-
|
|
316
|
+
url: '/canvases/canvas123',
|
|
318
317
|
tag: 'canvases.get',
|
|
319
318
|
})
|
|
320
319
|
})
|
|
@@ -1050,7 +1049,7 @@ describe('presenceStore', () => {
|
|
|
1050
1049
|
mockIncomingEvents.next({
|
|
1051
1050
|
type: 'rollCall',
|
|
1052
1051
|
userId: 'user-1',
|
|
1053
|
-
sessionId:
|
|
1052
|
+
sessionId: lastTransportSessionId(),
|
|
1054
1053
|
})
|
|
1055
1054
|
await flush()
|
|
1056
1055
|
|
|
@@ -1139,25 +1138,19 @@ describe('presenceStore', () => {
|
|
|
1139
1138
|
})
|
|
1140
1139
|
|
|
1141
1140
|
describe('session id', () => {
|
|
1142
|
-
afterEach(() => {
|
|
1143
|
-
vi.unstubAllGlobals()
|
|
1144
|
-
})
|
|
1145
|
-
|
|
1146
1141
|
it('gives each store its own id, so nothing can collide across tabs', () => {
|
|
1147
1142
|
// Ids are deliberately not persisted: a tab that inherits another's
|
|
1148
1143
|
// session storage would otherwise reuse the id and the two live clients
|
|
1149
1144
|
// would filter each other out as their own session.
|
|
1150
|
-
let counter = 0
|
|
1151
|
-
vi.stubGlobal('crypto', {randomUUID: vi.fn(() => `session-${++counter}`)})
|
|
1152
|
-
|
|
1153
1145
|
getPresence(instance, {resource: {projectId: 'p1', dataset: 'd1'}}).subscribe(() => {})
|
|
1154
|
-
const first =
|
|
1146
|
+
const first = lastTransportSessionId()
|
|
1155
1147
|
|
|
1156
1148
|
getPresence(instance, {resource: {projectId: 'p2', dataset: 'd2'}}).subscribe(() => {})
|
|
1157
|
-
const second =
|
|
1149
|
+
const second = lastTransportSessionId()
|
|
1158
1150
|
|
|
1159
|
-
expect(first).
|
|
1160
|
-
expect(second).
|
|
1151
|
+
expect(first).toMatch(/^[a-zA-Z0-9]{16}$/)
|
|
1152
|
+
expect(second).toMatch(/^[a-zA-Z0-9]{16}$/)
|
|
1153
|
+
expect(first).not.toBe(second)
|
|
1161
1154
|
})
|
|
1162
1155
|
})
|
|
1163
1156
|
})
|