@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.
Files changed (90) hide show
  1. package/dist/_exports/_internal.d.ts +25 -3
  2. package/dist/_exports/_internal.d.ts.map +1 -1
  3. package/dist/_exports/_internal.js +127 -9
  4. package/dist/_exports/_internal.js.map +1 -1
  5. package/dist/_exports/agent.d.ts +1 -1
  6. package/dist/_exports/agent.js +1 -1
  7. package/dist/_exports/comlink.d.ts +1 -1
  8. package/dist/_exports/comlink.js +2 -3
  9. package/dist/_exports/comlink.js.map +1 -1
  10. package/dist/{authStore-C0o1NOxW.d.ts → authStore-C-OEkGaM.d.ts} +2 -2
  11. package/dist/{authStore-C0o1NOxW.d.ts.map → authStore-C-OEkGaM.d.ts.map} +1 -1
  12. package/dist/{authStore-CtE9bLHW.js → clientStore-gUALQ0qW.js} +269 -11
  13. package/dist/{authStore-CtE9bLHW.js.map → clientStore-gUALQ0qW.js.map} +1 -1
  14. package/dist/{createSanityInstance-DUI1bGIg.d.ts → createSanityInstance-DCePpBYW.d.ts} +2 -2
  15. package/dist/{createSanityInstance-DUI1bGIg.d.ts.map → createSanityInstance-DCePpBYW.d.ts.map} +1 -1
  16. package/dist/{getNodeState-CR3__B2D.js → getNodeState-E0hjqFOo.js} +2 -3
  17. package/dist/{getNodeState-CR3__B2D.js.map → getNodeState-E0hjqFOo.js.map} +1 -1
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.js +40 -44
  20. package/dist/index.js.map +1 -1
  21. package/dist/{createStateSourceAction-BOKtqFNm.js → object-BwynGPRZ.js} +87 -3
  22. package/dist/object-BwynGPRZ.js.map +1 -0
  23. package/dist/{queryStore-C7yMHPUI.js → version-C90rNWaX.js} +47 -15
  24. package/dist/version-C90rNWaX.js.map +1 -0
  25. package/package.json +5 -5
  26. package/src/_exports/_internal.ts +1 -0
  27. package/src/access/checkPermissions.test.ts +1 -1
  28. package/src/access/checkPermissions.ts +1 -1
  29. package/src/applications/applications.test.ts +4 -4
  30. package/src/applications/applications.ts +4 -4
  31. package/src/auth/handleAuthCallback.test.ts +2 -2
  32. package/src/auth/handleAuthCallback.ts +1 -1
  33. package/src/auth/logout.test.ts +1 -1
  34. package/src/auth/logout.ts +1 -1
  35. package/src/auth/refreshStampedToken.ts +1 -1
  36. package/src/auth/studioModeAuth.test.ts +1 -1
  37. package/src/auth/studioModeAuth.ts +1 -1
  38. package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +2 -2
  39. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +1 -1
  40. package/src/comments/addonDatasetStore.test.ts +2 -2
  41. package/src/comments/addonDatasetStore.ts +2 -2
  42. package/src/comments/commentActions.ts +6 -5
  43. package/src/comments/commentsStore.ts +4 -4
  44. package/src/document/applyDocumentActions.ts +2 -6
  45. package/src/document/documentStore.concurrency.test.ts +2 -1
  46. package/src/document/documentStore.test.ts +19 -18
  47. package/src/document/documentStore.ts +5 -5
  48. package/src/document/permissions.ts +2 -1
  49. package/src/document/processActions.test.ts +2 -1
  50. package/src/document/processMutations.ts +3 -2
  51. package/src/document/reducers.ts +2 -2
  52. package/src/installations/installations.test.ts +2 -2
  53. package/src/installations/installations.ts +2 -2
  54. package/src/organization/organization.test.ts +2 -2
  55. package/src/organization/organization.ts +1 -1
  56. package/src/organizations/organizations.test.ts +2 -2
  57. package/src/organizations/organizations.ts +1 -1
  58. package/src/presence/presenceStore.test.ts +15 -22
  59. package/src/presence/presenceStore.ts +3 -2
  60. package/src/project/project.test.ts +3 -3
  61. package/src/project/project.ts +1 -1
  62. package/src/projection/getProjectionState.test.ts +6 -4
  63. package/src/projection/getProjectionState.ts +2 -2
  64. package/src/projects/projects.test.ts +2 -2
  65. package/src/projects/projects.ts +1 -1
  66. package/src/query/queryStore.ts +3 -3
  67. package/src/store/createSanityInstance.test.ts +1 -1
  68. package/src/store/createSanityInstance.ts +4 -4
  69. package/src/store/createStoreInstance.test.ts +0 -5
  70. package/src/telemetry/telemetryManager.test.ts +1 -1
  71. package/src/telemetry/telemetryManager.ts +2 -2
  72. package/src/users/usersStore.test.ts +1 -1
  73. package/src/users/usersStore.ts +5 -5
  74. package/src/utils/ids.test.ts +40 -15
  75. package/src/utils/ids.ts +47 -2
  76. package/dist/clientStore-BtE2-q2i.js +0 -90
  77. package/dist/clientStore-BtE2-q2i.js.map +0 -1
  78. package/dist/createStateSourceAction-BOKtqFNm.js.map +0 -1
  79. package/dist/getEnv-D5RGkQLu.js +0 -8
  80. package/dist/getEnv-D5RGkQLu.js.map +0 -1
  81. package/dist/logger-DAtJb5RQ.js +0 -173
  82. package/dist/logger-DAtJb5RQ.js.map +0 -1
  83. package/dist/object-CxXlSVg7.js +0 -83
  84. package/dist/object-CxXlSVg7.js.map +0 -1
  85. package/dist/queryStore-C7yMHPUI.js.map +0 -1
  86. package/dist/rolldown-runtime-vyAXikos.js +0 -9
  87. package/dist/telemetryManager-UIEiMtC0.js +0 -127
  88. package/dist/telemetryManager-UIEiMtC0.js.map +0 -1
  89. package/dist/version-D8RP_Q59.js +0 -9
  90. 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
- uri: '/users/me',
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
- uri: '/users/me',
100
+ url: '/users/me',
101
101
  tag: 'users.get-current',
102
102
  })
103
103
 
@@ -73,7 +73,7 @@ export const subscribeToStateAndFetchCurrentUser = (
73
73
  switchMap((client) =>
74
74
  client.observable
75
75
  .request<CurrentUser>({
76
- uri: '/users/me',
76
+ url: '/users/me',
77
77
  method: 'GET',
78
78
  tag: 'users.get-current',
79
79
  })
@@ -59,7 +59,7 @@ describe('getAddonDatasetState', () => {
59
59
  )
60
60
 
61
61
  expect(observableRequest).toHaveBeenCalledWith({
62
- uri: '/projects/p/datasets?datasetProfile=comments&addonFor=d',
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
- uri: '/comments/d/setup',
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
- uri: `/projects/${projectId}/datasets?datasetProfile=${ADDON_DATASET_PROFILE}&addonFor=${dataset}`,
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
- uri: `/comments/${resource.dataset}/setup`,
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 ?? crypto.randomUUID(),
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 ?? crypto.randomUUID(),
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 ?? crypto.randomUUID(),
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 = crypto.randomUUID()
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 = crypto.randomUUID()
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 {insecureRandomId} from '../utils/ids'
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 = insecureRandomId()
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 = insecureRandomId()
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 = insecureRandomId()
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 ?? crypto.randomUUID())
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 = crypto.randomUUID()} = {}) => ({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: crypto.randomUUID(), documentType: 'article'})
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: crypto.randomUUID(), documentType: 'article'})
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(crypto.randomUUID())
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: crypto.randomUUID(), documentType: 'article'})
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: crypto.randomUUID(), documentType: 'book'})
979
- const author = createDocumentHandle({documentId: crypto.randomUUID(), documentType: 'author'})
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: crypto.randomUUID(), documentType: 'article'})
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.uri?.endsWith('/acl'))
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: crypto.randomUUID(), documentType: 'article'})
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: crypto.randomUUID(), documentType: 'article'})
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: crypto.randomUUID(), documentType: 'article'})
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: crypto.randomUUID(), documentType: 'article'})
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: crypto.randomUUID(), documentType: 'article'})
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(crypto.randomUUID())
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(crypto.randomUUID())
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 ?? crypto.randomUUID()
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 = crypto.randomUUID(), dryRun}: BaseActionOptions,
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 uri: string
553
+ let url: string
554
554
  if (resource && isDatasetResource(resource)) {
555
- uri = `/projects/${resource.projectId}/datasets/${resource.dataset}/acl`
555
+ url = `/projects/${resource.projectId}/datasets/${resource.dataset}/acl`
556
556
  } else if (resource && isMediaLibraryResource(resource)) {
557
- uri = `/media-libraries/${resource.mediaLibraryId}/acl`
557
+ url = `/media-libraries/${resource.mediaLibraryId}/acl`
558
558
  } else if (resource && isCanvasResource(resource)) {
559
- uri = `/canvases/${resource.canvasId}/acl`
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
- uri,
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: crypto.randomUUID(),
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 = crypto.randomUUID()
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 crypto.randomUUID()
67
- if (id.endsWith('.')) return `${id}${crypto.randomUUID()}`
67
+ if (!id || typeof id !== 'string') return randomUuid()
68
+ if (id.endsWith('.')) return `${id}${randomUuid()}`
68
69
  return id
69
70
  }
70
71
 
@@ -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 {insecureRandomId} from '../utils/ids'
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 = insecureRandomId()
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
- uri: '/installations',
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
- uri: '/installations/inst1',
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
- uri: '/installations',
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
- uri: `/installations/${installationId}`,
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
- uri: '/organizations/org_1',
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
- uri: '/organizations/org_1',
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
- uri: `/organizations/${resolveOrganizationId(options)}`,
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
- uri: '/organizations',
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
- uri: '/organizations',
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
- uri: '/organizations',
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: 'test-session-id',
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: 'test-session-id', // Same as our session
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
- uri: '/canvases/canvas123',
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: 'test-session-id',
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 = vi.mocked(createBifurTransport).mock.calls.at(-1)?.[0].sessionId
1146
+ const first = lastTransportSessionId()
1155
1147
 
1156
1148
  getPresence(instance, {resource: {projectId: 'p2', dataset: 'd2'}}).subscribe(() => {})
1157
- const second = vi.mocked(createBifurTransport).mock.calls.at(-1)?.[0].sessionId
1149
+ const second = lastTransportSessionId()
1158
1150
 
1159
- expect(first).toBe('session-1')
1160
- expect(second).toBe('session-2')
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
  })