@sanity/sdk 0.0.0-chore-react-18-compat.1 → 0.0.0-chore-react-18-compat.3

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 (134) hide show
  1. package/dist/index.d.ts +441 -322
  2. package/dist/index.js +1685 -1481
  3. package/dist/index.js.map +1 -1
  4. package/package.json +13 -15
  5. package/src/_exports/index.ts +32 -30
  6. package/src/auth/authStore.test.ts +149 -104
  7. package/src/auth/authStore.ts +51 -100
  8. package/src/auth/handleAuthCallback.test.ts +67 -34
  9. package/src/auth/handleAuthCallback.ts +8 -7
  10. package/src/auth/logout.test.ts +61 -29
  11. package/src/auth/logout.ts +26 -28
  12. package/src/auth/refreshStampedToken.test.ts +197 -91
  13. package/src/auth/refreshStampedToken.ts +170 -59
  14. package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +5 -5
  15. package/src/auth/subscribeToStateAndFetchCurrentUser.ts +45 -47
  16. package/src/auth/subscribeToStorageEventsAndSetToken.test.ts +4 -5
  17. package/src/auth/subscribeToStorageEventsAndSetToken.ts +22 -24
  18. package/src/client/clientStore.test.ts +131 -67
  19. package/src/client/clientStore.ts +117 -116
  20. package/src/comlink/controller/actions/destroyController.test.ts +38 -13
  21. package/src/comlink/controller/actions/destroyController.ts +11 -15
  22. package/src/comlink/controller/actions/getOrCreateChannel.test.ts +56 -27
  23. package/src/comlink/controller/actions/getOrCreateChannel.ts +37 -35
  24. package/src/comlink/controller/actions/getOrCreateController.test.ts +27 -16
  25. package/src/comlink/controller/actions/getOrCreateController.ts +23 -22
  26. package/src/comlink/controller/actions/releaseChannel.test.ts +37 -13
  27. package/src/comlink/controller/actions/releaseChannel.ts +22 -21
  28. package/src/comlink/controller/comlinkControllerStore.test.ts +65 -36
  29. package/src/comlink/controller/comlinkControllerStore.ts +44 -5
  30. package/src/comlink/node/actions/getOrCreateNode.test.ts +31 -15
  31. package/src/comlink/node/actions/getOrCreateNode.ts +30 -29
  32. package/src/comlink/node/actions/releaseNode.test.ts +75 -55
  33. package/src/comlink/node/actions/releaseNode.ts +19 -21
  34. package/src/comlink/node/comlinkNodeStore.test.ts +6 -11
  35. package/src/comlink/node/comlinkNodeStore.ts +22 -5
  36. package/src/config/authConfig.ts +79 -0
  37. package/src/config/sanityConfig.ts +48 -0
  38. package/src/datasets/datasets.test.ts +2 -2
  39. package/src/datasets/datasets.ts +18 -5
  40. package/src/document/actions.test.ts +22 -10
  41. package/src/document/actions.ts +44 -56
  42. package/src/document/applyDocumentActions.test.ts +96 -36
  43. package/src/document/applyDocumentActions.ts +140 -99
  44. package/src/document/documentStore.test.ts +103 -155
  45. package/src/document/documentStore.ts +247 -238
  46. package/src/document/listen.ts +56 -55
  47. package/src/document/patchOperations.ts +0 -43
  48. package/src/document/permissions.test.ts +25 -12
  49. package/src/document/permissions.ts +11 -4
  50. package/src/document/processActions.test.ts +41 -8
  51. package/src/document/reducers.test.ts +87 -16
  52. package/src/document/reducers.ts +2 -2
  53. package/src/document/sharedListener.test.ts +34 -16
  54. package/src/document/sharedListener.ts +33 -11
  55. package/src/preview/getPreviewState.test.ts +40 -39
  56. package/src/preview/getPreviewState.ts +68 -56
  57. package/src/preview/previewConstants.ts +43 -0
  58. package/src/preview/previewQuery.test.ts +1 -1
  59. package/src/preview/previewQuery.ts +4 -5
  60. package/src/preview/previewStore.test.ts +13 -58
  61. package/src/preview/previewStore.ts +7 -21
  62. package/src/preview/resolvePreview.test.ts +33 -104
  63. package/src/preview/resolvePreview.ts +11 -21
  64. package/src/preview/subscribeToStateAndFetchBatches.test.ts +96 -97
  65. package/src/preview/subscribeToStateAndFetchBatches.ts +85 -81
  66. package/src/preview/util.ts +1 -0
  67. package/src/project/project.test.ts +3 -3
  68. package/src/project/project.ts +28 -5
  69. package/src/projection/getProjectionState.test.ts +188 -72
  70. package/src/projection/getProjectionState.ts +92 -62
  71. package/src/projection/projectionQuery.test.ts +114 -12
  72. package/src/projection/projectionQuery.ts +75 -32
  73. package/src/projection/projectionStore.test.ts +13 -51
  74. package/src/projection/projectionStore.ts +6 -43
  75. package/src/projection/resolveProjection.test.ts +32 -127
  76. package/src/projection/resolveProjection.ts +16 -28
  77. package/src/projection/subscribeToStateAndFetchBatches.test.ts +203 -116
  78. package/src/projection/subscribeToStateAndFetchBatches.ts +140 -85
  79. package/src/projection/types.ts +50 -0
  80. package/src/projection/util.ts +3 -1
  81. package/src/projects/projects.test.ts +13 -4
  82. package/src/projects/projects.ts +6 -1
  83. package/src/query/queryStore.test.ts +10 -47
  84. package/src/query/queryStore.ts +151 -133
  85. package/src/query/queryStoreConstants.ts +2 -0
  86. package/src/store/createActionBinder.test.ts +153 -0
  87. package/src/store/createActionBinder.ts +176 -0
  88. package/src/store/createSanityInstance.test.ts +84 -0
  89. package/src/store/createSanityInstance.ts +124 -0
  90. package/src/store/createStateSourceAction.test.ts +196 -0
  91. package/src/store/createStateSourceAction.ts +260 -0
  92. package/src/store/createStoreInstance.test.ts +81 -0
  93. package/src/store/createStoreInstance.ts +80 -0
  94. package/src/store/createStoreState.test.ts +85 -0
  95. package/src/store/createStoreState.ts +92 -0
  96. package/src/store/defineStore.test.ts +18 -0
  97. package/src/store/defineStore.ts +81 -0
  98. package/src/users/reducers.test.ts +318 -0
  99. package/src/users/reducers.ts +88 -0
  100. package/src/users/types.ts +46 -4
  101. package/src/users/usersConstants.ts +4 -0
  102. package/src/users/usersStore.test.ts +350 -223
  103. package/src/users/usersStore.ts +285 -149
  104. package/src/utils/createFetcherStore.test.ts +6 -7
  105. package/src/utils/createFetcherStore.ts +150 -153
  106. package/src/utils/createGroqSearchFilter.test.ts +75 -0
  107. package/src/utils/createGroqSearchFilter.ts +85 -0
  108. package/src/{common/util.test.ts → utils/hashString.test.ts} +1 -1
  109. package/dist/index.cjs +0 -4888
  110. package/dist/index.cjs.map +0 -1
  111. package/dist/index.d.cts +0 -2121
  112. package/src/auth/fetchLoginUrls.test.ts +0 -163
  113. package/src/auth/fetchLoginUrls.ts +0 -74
  114. package/src/common/createLiveEventSubscriber.test.ts +0 -121
  115. package/src/common/createLiveEventSubscriber.ts +0 -55
  116. package/src/common/types.ts +0 -4
  117. package/src/instance/identity.test.ts +0 -46
  118. package/src/instance/identity.ts +0 -29
  119. package/src/instance/sanityInstance.test.ts +0 -77
  120. package/src/instance/sanityInstance.ts +0 -57
  121. package/src/instance/types.ts +0 -37
  122. package/src/preview/getPreviewProjection.ts +0 -45
  123. package/src/resources/README.md +0 -370
  124. package/src/resources/createAction.test.ts +0 -101
  125. package/src/resources/createAction.ts +0 -44
  126. package/src/resources/createResource.test.ts +0 -112
  127. package/src/resources/createResource.ts +0 -102
  128. package/src/resources/createStateSourceAction.test.ts +0 -114
  129. package/src/resources/createStateSourceAction.ts +0 -83
  130. package/src/resources/createStore.test.ts +0 -67
  131. package/src/resources/createStore.ts +0 -46
  132. package/src/store/createStore.test.ts +0 -108
  133. package/src/store/createStore.ts +0 -106
  134. /package/src/{common/util.ts → utils/hashString.ts} +0 -0
@@ -1,163 +0,0 @@
1
- import {createSanityInstance} from '../instance/sanityInstance'
2
- import {createResourceState} from '../resources/createResource'
3
- import {authStore} from './authStore'
4
- import {fetchLoginUrls} from './fetchLoginUrls'
5
-
6
- describe('fetchLoginUrls', () => {
7
- it('returns providers with updated URLs', async () => {
8
- const mockRequest = vi.fn().mockResolvedValue({
9
- providers: [
10
- {title: 'Provider A', url: 'https://auth.example.com/a'},
11
- {title: 'Provider B', url: 'https://auth.example.com/b'},
12
- ],
13
- })
14
- const clientFactory = vi.fn().mockReturnValue({request: mockRequest})
15
- const instance = createSanityInstance({
16
- projectId: 'p',
17
- dataset: 'd',
18
- auth: {clientFactory},
19
- })
20
- const state = createResourceState(authStore.getInitialState(instance))
21
- const providers = await fetchLoginUrls({instance, state})
22
-
23
- expect(providers.length).toBe(2)
24
- expect(providers[0].url).toContain('withSid=true')
25
- expect(providers[1].url).toContain('withSid=true')
26
- })
27
-
28
- it('caches the providers and early returns', async () => {
29
- const clientFactory = vi.fn()
30
- const instance = createSanityInstance({
31
- projectId: 'p',
32
- dataset: 'd',
33
- auth: {clientFactory},
34
- })
35
- const state = createResourceState(authStore.getInitialState(instance))
36
-
37
- const provider = {
38
- name: 'cached-provided',
39
- title: 'cached provider',
40
- url: 'https://auth.example.com#withSid=true',
41
- }
42
- state.set('setInitialProviders', {providers: [provider]})
43
-
44
- const providers = await fetchLoginUrls({instance, state})
45
-
46
- expect(providers.length).toBe(1)
47
- expect(providers[0].url).toContain('https://auth.example.com#withSid=true')
48
- })
49
-
50
- it('handles providers as a static array and merges/replaces accordingly', async () => {
51
- const mockRequest = vi.fn().mockResolvedValue({
52
- providers: [
53
- {title: 'Provider A', name: 'provider-a', url: 'https://auth.example.com/a'},
54
- {title: 'Provider B', name: 'provider-b', url: 'https://auth.example.com/b'},
55
- ],
56
- })
57
- const clientFactory = vi.fn().mockReturnValue({request: mockRequest})
58
- const instance = createSanityInstance({
59
- projectId: 'p',
60
- dataset: 'd',
61
- auth: {
62
- clientFactory,
63
- providers: [
64
- {
65
- title: 'Custom Provider B',
66
- name: 'custom-provider-b',
67
- url: 'https://auth.example.com/b',
68
- },
69
- {title: 'Provider C', name: 'provider-c', url: 'https://auth.example.com/c'},
70
- ],
71
- },
72
- })
73
- const state = createResourceState(authStore.getInitialState(instance))
74
- const providers = await fetchLoginUrls({instance, state})
75
-
76
- expect(providers.find((p) => p.title === 'Provider A')).toBeTruthy()
77
- expect(providers.find((p) => p.title === 'Custom Provider B')).toBeTruthy()
78
- expect(providers.find((p) => p.title === 'Provider C')).toBeTruthy()
79
- expect(providers.find((p) => p.title === 'Provider B')).toBeFalsy()
80
- })
81
-
82
- it('allows custom provider function modification', async () => {
83
- const mockRequest = vi.fn().mockResolvedValue({
84
- providers: [{title: 'Provider A', url: 'https://auth.example.com/a'}],
85
- })
86
- const clientFactory = vi.fn().mockReturnValue({request: mockRequest})
87
- const instance = createSanityInstance({
88
- projectId: 'p',
89
- dataset: 'd',
90
- auth: {
91
- clientFactory,
92
- providers: (defaults) => defaults.map((p) => ({...p, title: 'Modified ' + p.title})),
93
- },
94
- })
95
- const state = createResourceState(authStore.getInitialState(instance))
96
- const providers = await fetchLoginUrls({instance, state})
97
-
98
- expect(providers[0].title).toBe('Modified Provider A')
99
- })
100
-
101
- it('uses default providers if none are specified', async () => {
102
- const mockRequest = vi.fn().mockResolvedValue({
103
- providers: [{title: 'Provider A', url: 'https://auth.example.com/a'}],
104
- })
105
- const clientFactory = vi.fn().mockReturnValue({request: mockRequest})
106
- const instance = createSanityInstance({
107
- projectId: 'p',
108
- dataset: 'd',
109
- auth: {
110
- clientFactory,
111
- },
112
- })
113
- const state = createResourceState(authStore.getInitialState(instance))
114
- const providers = await fetchLoginUrls({instance, state})
115
-
116
- expect(providers.length).toBe(1)
117
- expect(providers[0].title).toBe('Provider A')
118
- })
119
-
120
- it('includes callbackUrl in provider URLs if set', async () => {
121
- const mockRequest = vi.fn().mockResolvedValue({
122
- providers: [{title: 'Provider A', url: 'https://auth.example.com/a'}],
123
- })
124
- const clientFactory = vi.fn().mockReturnValue({request: mockRequest})
125
- const instance = createSanityInstance({
126
- projectId: 'p',
127
- dataset: 'd',
128
- auth: {
129
- clientFactory,
130
- callbackUrl: 'http://localhost/callback',
131
- },
132
- })
133
- const state = createResourceState(authStore.getInitialState(instance))
134
- const providers = await fetchLoginUrls({instance, state})
135
- expect(providers[0].url).toContain('origin=http%3A%2F%2Flocalhost%2Fcallback')
136
- })
137
-
138
- it('should allow async custom provider function', async () => {
139
- const mockRequest = vi.fn().mockResolvedValue({
140
- providers: [{title: 'Provider A', url: 'https://auth.example.com/a'}],
141
- })
142
- const clientFactory = vi.fn().mockReturnValue({request: mockRequest})
143
- const instance = createSanityInstance({
144
- projectId: 'p',
145
- dataset: 'd',
146
- auth: {
147
- clientFactory,
148
- providers: async (defaults) => {
149
- await new Promise((r) => setTimeout(r, 10))
150
- return defaults.concat([
151
- {title: 'Provider C', name: 'provider-c', url: 'https://auth.example.com/c'},
152
- ])
153
- },
154
- },
155
- })
156
- const state = createResourceState(authStore.getInitialState(instance))
157
-
158
- const providers = await fetchLoginUrls({instance, state})
159
-
160
- expect(providers.length).toBe(2)
161
- expect(providers.some((p) => p.title === 'Provider C')).toBe(true)
162
- })
163
- })
@@ -1,74 +0,0 @@
1
- import {type AuthProvider} from '@sanity/client'
2
-
3
- import {createAction} from '../resources/createAction'
4
- import {DEFAULT_API_VERSION, REQUEST_TAG_PREFIX} from './authConstants'
5
- import {authStore} from './authStore'
6
- import {getDefaultLocation} from './utils'
7
-
8
- /**
9
- * @public
10
- */
11
- export const fetchLoginUrls = createAction(authStore, ({state}) => {
12
- const {callbackUrl, clientFactory, apiHost, customProviders} = state.get().options
13
- const client = clientFactory({
14
- apiVersion: DEFAULT_API_VERSION,
15
- requestTagPrefix: REQUEST_TAG_PREFIX,
16
- useProjectHostname: false,
17
- ...(apiHost && {apiHost}),
18
- })
19
-
20
- return async function () {
21
- const cachedProviders = state.get().providers
22
- if (cachedProviders) return cachedProviders
23
-
24
- const {providers: defaultProviders} = await client.request<{providers: AuthProvider[]}>({
25
- uri: '/auth/providers',
26
- tag: 'fetch-providers',
27
- })
28
-
29
- let providers: AuthProvider[]
30
-
31
- if (typeof customProviders === 'function') {
32
- providers = await customProviders(defaultProviders)
33
- } else if (!customProviders?.length) {
34
- providers = defaultProviders
35
- } else {
36
- const customProviderUrls = new Set(customProviders.map((p) => p.url))
37
- providers = defaultProviders
38
- .filter((official) => !customProviderUrls.has(official.url))
39
- .concat(customProviders)
40
- }
41
-
42
- const configuredProviders = providers.map((provider) => {
43
- const url = new URL(provider.url)
44
- const origin = new URL(
45
- callbackUrl
46
- ? new URL(callbackUrl, new URL(getDefaultLocation()).origin).toString()
47
- : getDefaultLocation(),
48
- )
49
-
50
- // `getDefaultLocation()` may be populated with an `sid` from a previous
51
- // failed login attempt and should be omitted from the next login URL
52
- const hashParams = new URLSearchParams(origin.hash.slice(1))
53
- hashParams.delete('sid')
54
- origin.hash = hashParams.toString()
55
- origin.searchParams.delete('sid')
56
- origin.searchParams.delete('url')
57
-
58
- // similarly, the origin may be populated with an `error` query param if
59
- // the auth provider redirects back to the application. this should also
60
- // be omitted from the origin sent
61
- origin.searchParams.delete('error')
62
-
63
- url.searchParams.set('origin', origin.toString())
64
- url.searchParams.set('withSid', 'true')
65
- url.searchParams.set('type', 'stampedToken')
66
-
67
- return {...provider, url: url.toString()}
68
- })
69
-
70
- state.set('fetchedLoginUrls', {providers: configuredProviders})
71
-
72
- return configuredProviders
73
- }
74
- })
@@ -1,121 +0,0 @@
1
- import {type LiveEventMessage, SanityClient} from '@sanity/client'
2
- import {Observable, of, Subject} from 'rxjs'
3
- import {describe, it, vi} from 'vitest'
4
-
5
- import {getClientState} from '../client/clientStore'
6
- import {createSanityInstance} from '../instance/sanityInstance'
7
- import {createResourceState, type ResourceState} from '../resources/createResource'
8
- import {type StateSource} from '../resources/createStateSourceAction'
9
- import {createLiveEventSubscriber} from './createLiveEventSubscriber'
10
- import {type LiveEventAwareState} from './types'
11
-
12
- vi.mock('../client/clientStore.ts', () => ({getClientState: vi.fn()}))
13
-
14
- vi.mock('../resources/createResource', async (importOriginal) => {
15
- const original = await importOriginal<typeof import('../resources/createResource')>()
16
- return {...original, getOrCreateResource: vi.fn()}
17
- })
18
-
19
- describe('createLiveEventSubscriber', () => {
20
- const TEST_TAG = 'test-tag'
21
- const instance = createSanityInstance({projectId: 'exampleProject', dataset: 'exampleDataset'})
22
- const initialState: LiveEventAwareState = {
23
- lastLiveEventId: null,
24
- syncTags: {},
25
- }
26
- let state: ResourceState<LiveEventAwareState>
27
-
28
- beforeEach(() => {
29
- state = createResourceState(initialState)
30
- vi.clearAllMocks()
31
- })
32
-
33
- it('listens for matching sync tags and updates the `lastLiveEventId`', async () => {
34
- const mockLiveEvents = new Observable<LiveEventMessage>((observer) => {
35
- observer.next({
36
- type: 'message',
37
- id: 'event123',
38
- tags: ['s1:tag1', 's1:tag2'],
39
- })
40
- })
41
-
42
- const mockClient = {
43
- live: {
44
- events: vi.fn().mockReturnValue(mockLiveEvents),
45
- },
46
- config: vi.fn().mockReturnValue({}),
47
- }
48
-
49
- // Mock the getSubscribableClient to emit our mock client
50
- vi.mocked(getClientState).mockReturnValue({
51
- observable: of(mockClient as unknown as SanityClient),
52
- } as StateSource<SanityClient>)
53
-
54
- // Set up initial state with a matching sync tag
55
- state.set('setSyncTags', {
56
- syncTags: {
57
- 's1:tag1': true,
58
- },
59
- })
60
-
61
- // Create and subscribe to live events
62
- const subscribeToLiveAndSetLastLiveEventId =
63
- createLiveEventSubscriber<LiveEventAwareState>(TEST_TAG)
64
- const subscription = subscribeToLiveAndSetLastLiveEventId({instance, state})
65
-
66
- // Verify the client was configured correctly
67
- expect(mockClient.live.events).toHaveBeenCalledWith({
68
- includeDrafts: false,
69
- tag: TEST_TAG,
70
- })
71
-
72
- // Verify the state was updated with the new event ID
73
- expect(state.get().lastLiveEventId).toBe('event123')
74
-
75
- // Clean up subscription
76
- subscription.unsubscribe()
77
- })
78
-
79
- it('unsubscribes from the previous live content connection if any', () => {
80
- const unsubscribe = vi.fn()
81
-
82
- const mockLiveEvents = new Observable<LiveEventMessage>((observer) => {
83
- observer.next({
84
- type: 'message',
85
- id: 'event123',
86
- tags: ['s1:tag1'],
87
- })
88
-
89
- return unsubscribe
90
- })
91
-
92
- const mockClient = {
93
- live: {
94
- events: vi.fn().mockReturnValue(mockLiveEvents),
95
- },
96
- config: vi.fn().mockReturnValue({}),
97
- }
98
-
99
- const clientSubject = new Subject()
100
-
101
- vi.mocked(getClientState).mockReturnValue({
102
- observable: clientSubject as Observable<SanityClient>,
103
- } as StateSource<SanityClient>)
104
-
105
- // Create and subscribe to live events
106
- const subscribeToLiveAndSetLastLiveEventId =
107
- createLiveEventSubscriber<LiveEventAwareState>(TEST_TAG)
108
- const liveSubscription = subscribeToLiveAndSetLastLiveEventId({instance, state})
109
- clientSubject.next(mockClient)
110
-
111
- expect(mockClient.live.events).toHaveBeenCalledTimes(1)
112
-
113
- const newClient = {...mockClient}
114
- clientSubject.next(newClient)
115
- expect(unsubscribe).toHaveBeenCalledTimes(1)
116
-
117
- // Clean up subscriptions
118
- liveSubscription.unsubscribe()
119
- expect(unsubscribe).toHaveBeenCalledTimes(2)
120
- })
121
- })
@@ -1,55 +0,0 @@
1
- import {combineLatest, distinctUntilChanged, filter, map, type Subscription, switchMap} from 'rxjs'
2
-
3
- import {getClientState} from '../client/clientStore'
4
- import {type ActionContext, createInternalAction} from '../resources/createAction'
5
- import {type LiveEventAwareState} from './types'
6
-
7
- /*
8
- * Factory function for creating a subscribeToLiveAndSetLastLiveEventId action.
9
- * Typically invoked in the initialization of stores that depend on the live events API.
10
- * It listens to events associated with sync tags (also kept internally in the store)
11
-
12
- * Usage like:
13
- *
14
- * const subscribeToLiveAndSetLastLiveEventId = createLiveEventSubscriber<ProjectionStoreState<TValue>>(TAG)
15
- * const liveSubscription = subscribeToLiveAndSetLastLiveEventId(this)
16
- *
17
- * return () => {
18
- * stateSubscriptionForBatches.unsubscribe()
19
- * liveSubscription.unsubscribe()
20
- */
21
- export function createLiveEventSubscriber<TState extends LiveEventAwareState>(
22
- tag: string,
23
- ): (actionContext: ActionContext<TState>) => Subscription {
24
- return createInternalAction(({instance, state}: ActionContext<TState>) => {
25
- const client$ = getClientState(instance, {apiVersion: 'vX'}).observable
26
- const syncTags$ = state.observable.pipe(
27
- map((i) => i.syncTags),
28
- distinctUntilChanged(),
29
- )
30
-
31
- return function () {
32
- const messageEvents$ = client$.pipe(
33
- switchMap((client) =>
34
- client.live
35
- .events({includeDrafts: !!client.config().token, tag})
36
- .pipe(filter((e): e is Extract<typeof e, {type: 'message'}> => e.type === 'message')),
37
- ),
38
- )
39
-
40
- return combineLatest([messageEvents$, syncTags$]).subscribe({
41
- next: ([event, currentSyncTags]) => {
42
- for (const eventTag of event.tags) {
43
- if (currentSyncTags[eventTag]) {
44
- state.set('setLastLiveEventId', (prevState: TState) => ({
45
- ...prevState,
46
- lastLiveEventId: event.id,
47
- }))
48
- return
49
- }
50
- }
51
- },
52
- })
53
- }
54
- })
55
- }
@@ -1,4 +0,0 @@
1
- export interface LiveEventAwareState {
2
- lastLiveEventId: string | null
3
- syncTags: Record<string, true>
4
- }
@@ -1,46 +0,0 @@
1
- import {describe, expect, it} from 'vitest'
2
-
3
- import {getSdkIdentity} from './identity'
4
-
5
- describe('identity', () => {
6
- describe('getSdkIdentity', () => {
7
- it('creates a frozen object with expected properties', () => {
8
- const identity = getSdkIdentity({
9
- projectId: 'test-project',
10
- dataset: 'test-dataset',
11
- })
12
-
13
- // Check if object is frozen
14
- expect(Object.isFrozen(identity)).toBe(true)
15
-
16
- // Check if all expected properties exist
17
- expect(identity).toHaveProperty('id')
18
- expect(identity).toHaveProperty('projectId', 'test-project')
19
- expect(identity).toHaveProperty('dataset', 'test-dataset')
20
- })
21
-
22
- it('generates unique ids for different instances', () => {
23
- const identity1 = getSdkIdentity({
24
- projectId: 'test-project',
25
- dataset: 'test-dataset',
26
- })
27
-
28
- const identity2 = getSdkIdentity({
29
- projectId: 'test-project',
30
- dataset: 'test-dataset',
31
- })
32
-
33
- expect(identity1.id).not.toBe(identity2.id)
34
- })
35
-
36
- it('generates id with correct format', () => {
37
- const identity = getSdkIdentity({
38
- projectId: 'test-project',
39
- dataset: 'test-dataset',
40
- })
41
-
42
- // ID should be 16 characters long (8 pairs of hex digits)
43
- expect(identity.id).toMatch(/^[0-9a-f]{16}$/)
44
- })
45
- })
46
- })
@@ -1,29 +0,0 @@
1
- import {type SdkIdentity} from './types'
2
-
3
- /**
4
- * thoughtLevel 2 - Primarily what we want is to have an object that we can bind stores/memoizations to, but let the things that depend on it (eg projectId, dataset) be internals that can't be overwritten by accident/intentionally
5
- * @public
6
- */
7
- export function getSdkIdentity({
8
- projectId,
9
- dataset,
10
- }: {
11
- projectId: string
12
- dataset: string
13
- }): SdkIdentity {
14
- const id = generateId()
15
- return Object.freeze({
16
- id,
17
- projectId,
18
- dataset,
19
- resourceId: `${projectId}.${dataset}`,
20
- })
21
- }
22
-
23
- function generateId() {
24
- return Array.from({length: 8}, () =>
25
- Math.floor(Math.random() * 16)
26
- .toString(16)
27
- .padStart(2, '0'),
28
- ).join('')
29
- }
@@ -1,77 +0,0 @@
1
- import {beforeEach, describe, expect, test} from 'vitest'
2
-
3
- import {disposeResources} from '../resources/createResource'
4
- import {createSanityInstance, getOrCreateResource} from './sanityInstance'
5
- import {type SanityConfig} from './types'
6
-
7
- vi.mock('../resources/createResource')
8
-
9
- describe('sanityInstance', () => {
10
- let config: SanityConfig
11
-
12
- beforeEach(() => {
13
- config = {
14
- projectId: 'test-project',
15
- dataset: 'test-dataset',
16
- }
17
- })
18
-
19
- describe('createSanityInstance', () => {
20
- test('creates instance with correct configuration', () => {
21
- const instance = createSanityInstance(config)
22
-
23
- expect(instance.identity).toEqual(
24
- expect.objectContaining({
25
- projectId: 'test-project',
26
- dataset: 'test-dataset',
27
- }),
28
- )
29
- })
30
-
31
- test('instance.dispose', () => {
32
- const instance = createSanityInstance(config)
33
- instance.dispose()
34
-
35
- expect(disposeResources).toHaveBeenCalled()
36
- })
37
- })
38
-
39
- describe('getOrCreateResource', () => {
40
- test('creates and caches resource', () => {
41
- const instance = createSanityInstance(config)
42
- let createCount = 0
43
-
44
- const creator = () => {
45
- createCount++
46
- return {value: 'test-resource'}
47
- }
48
-
49
- // First call should create new resource
50
- const resource1 = getOrCreateResource(instance, 'test-key', creator)
51
- expect(resource1).toEqual({value: 'test-resource'})
52
- expect(createCount).toBe(1)
53
-
54
- // Second call should return cached resource
55
- const resource2 = getOrCreateResource(instance, 'test-key', creator)
56
- expect(resource2).toBe(resource1)
57
- expect(createCount).toBe(1)
58
- })
59
-
60
- test('different instances have separate resource caches', () => {
61
- const instance1 = createSanityInstance({...config, projectId: 'project1'})
62
- const instance2 = createSanityInstance({...config, projectId: 'project2'})
63
- let createCount = 0
64
-
65
- const creator = () => {
66
- createCount++
67
- return {value: 'test-resource'}
68
- }
69
-
70
- const resource1 = getOrCreateResource(instance1, 'test-key', creator)
71
- const resource2 = getOrCreateResource(instance2, 'test-key', creator)
72
-
73
- expect(resource1).not.toBe(resource2)
74
- expect(createCount).toBe(2)
75
- })
76
- })
77
- })
@@ -1,57 +0,0 @@
1
- import {disposeResources} from '../resources/createResource'
2
- import {getSdkIdentity} from './identity'
3
- import {type SanityConfig, type SanityInstance, type SdkIdentity} from './types'
4
-
5
- /**
6
- * Returns a new instance of dependencies required for SanitySDK.
7
- *
8
- * @public
9
- *
10
- * @param config - The configuration for this instance
11
- *
12
- * @returns A new "instance" of a Sanity SDK, used to bind resources/configuration to it
13
- */
14
- export function createSanityInstance({
15
- projectId = '',
16
- dataset = '',
17
- ...config
18
- }: SanityConfig): SanityInstance {
19
- const identity = getSdkIdentity({projectId, dataset})
20
- return {
21
- identity,
22
- config,
23
- dispose: () => disposeResources(identity),
24
- }
25
- }
26
-
27
- const resourceStorage = new WeakMap<SdkIdentity, Map<string, unknown>>()
28
-
29
- function getResource(instance: SanityInstance, key: string) {
30
- const instanceMap = resourceStorage.get(instance.identity)
31
- return instanceMap?.get(key)
32
- }
33
-
34
- function setResource(instance: SanityInstance, key: string, value: unknown) {
35
- let instanceMap = resourceStorage.get(instance.identity)
36
- if (!instanceMap) {
37
- instanceMap = new Map()
38
- resourceStorage.set(instance.identity, instanceMap)
39
- }
40
- instanceMap.set(key, value)
41
- }
42
-
43
- /**
44
- * This is an internal function that retrieves or creates a Zustand store resource.
45
- * @internal
46
- */
47
- export function getOrCreateResource<T>(instance: SanityInstance, key: string, creator: () => T): T {
48
- const cached = getResource(instance, key)
49
-
50
- if (cached) {
51
- return cached as T
52
- }
53
-
54
- const resource = creator()
55
- setResource(instance, key, resource)
56
- return resource
57
- }
@@ -1,37 +0,0 @@
1
- /* eslint-disable import/consistent-type-specifier-style */
2
- // NOTE: These have to be type import because we do not want the side-effect
3
- // of importing these modules, we just want the types for their configs
4
- import type {AuthConfig} from '../auth/authStore'
5
- import type {ResourceId} from '../document/patchOperations'
6
-
7
- /**
8
- * @public
9
- */
10
- export interface SanityConfig {
11
- projectId: string
12
- dataset: string
13
- auth?: AuthConfig
14
- }
15
-
16
- /** @public */
17
- export interface SanityInstance {
18
- /**
19
- * The following is used to look up resources associated with this instance,
20
- * and can be used to retrieve an "id" for the instance - useful in debugging.
21
- *
22
- * @public
23
- */
24
- readonly identity: SdkIdentity
25
-
26
- config: Omit<SanityConfig, 'projectId' | 'dataset'>
27
-
28
- dispose: () => void
29
- }
30
-
31
- /** @public */
32
- export interface SdkIdentity {
33
- readonly id: string
34
- readonly projectId: string
35
- readonly dataset: string
36
- readonly resourceId: ResourceId
37
- }