@sanity/sdk 0.0.0-alpha.21 → 0.0.0-alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +428 -325
- package/dist/index.js +1618 -1553
- package/dist/index.js.map +1 -1
- package/package.json +6 -7
- package/src/_exports/index.ts +31 -30
- package/src/auth/authStore.test.ts +149 -104
- package/src/auth/authStore.ts +51 -100
- package/src/auth/handleAuthCallback.test.ts +67 -34
- package/src/auth/handleAuthCallback.ts +8 -7
- package/src/auth/logout.test.ts +61 -29
- package/src/auth/logout.ts +26 -28
- package/src/auth/refreshStampedToken.test.ts +9 -9
- package/src/auth/refreshStampedToken.ts +62 -56
- package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +5 -5
- package/src/auth/subscribeToStateAndFetchCurrentUser.ts +45 -47
- package/src/auth/subscribeToStorageEventsAndSetToken.test.ts +4 -5
- package/src/auth/subscribeToStorageEventsAndSetToken.ts +22 -24
- package/src/client/clientStore.test.ts +131 -67
- package/src/client/clientStore.ts +117 -116
- package/src/comlink/controller/actions/destroyController.test.ts +38 -13
- package/src/comlink/controller/actions/destroyController.ts +11 -15
- package/src/comlink/controller/actions/getOrCreateChannel.test.ts +56 -27
- package/src/comlink/controller/actions/getOrCreateChannel.ts +37 -35
- package/src/comlink/controller/actions/getOrCreateController.test.ts +27 -16
- package/src/comlink/controller/actions/getOrCreateController.ts +23 -22
- package/src/comlink/controller/actions/releaseChannel.test.ts +37 -13
- package/src/comlink/controller/actions/releaseChannel.ts +22 -21
- package/src/comlink/controller/comlinkControllerStore.test.ts +65 -36
- package/src/comlink/controller/comlinkControllerStore.ts +44 -5
- package/src/comlink/node/actions/getOrCreateNode.test.ts +31 -15
- package/src/comlink/node/actions/getOrCreateNode.ts +30 -29
- package/src/comlink/node/actions/releaseNode.test.ts +75 -55
- package/src/comlink/node/actions/releaseNode.ts +19 -21
- package/src/comlink/node/comlinkNodeStore.test.ts +6 -11
- package/src/comlink/node/comlinkNodeStore.ts +22 -5
- package/src/config/authConfig.ts +79 -0
- package/src/config/sanityConfig.ts +48 -0
- package/src/datasets/datasets.test.ts +2 -2
- package/src/datasets/datasets.ts +18 -5
- package/src/document/actions.test.ts +22 -10
- package/src/document/actions.ts +44 -56
- package/src/document/applyDocumentActions.test.ts +96 -36
- package/src/document/applyDocumentActions.ts +140 -99
- package/src/document/documentStore.test.ts +103 -155
- package/src/document/documentStore.ts +247 -237
- package/src/document/listen.ts +56 -55
- package/src/document/patchOperations.ts +0 -43
- package/src/document/permissions.test.ts +25 -12
- package/src/document/permissions.ts +11 -4
- package/src/document/processActions.test.ts +41 -8
- package/src/document/reducers.test.ts +87 -16
- package/src/document/reducers.ts +2 -2
- package/src/document/sharedListener.test.ts +34 -16
- package/src/document/sharedListener.ts +33 -11
- package/src/preview/getPreviewState.test.ts +40 -39
- package/src/preview/getPreviewState.ts +68 -56
- package/src/preview/previewConstants.ts +43 -0
- package/src/preview/previewQuery.test.ts +1 -1
- package/src/preview/previewQuery.ts +4 -5
- package/src/preview/previewStore.test.ts +13 -58
- package/src/preview/previewStore.ts +7 -21
- package/src/preview/resolvePreview.test.ts +33 -104
- package/src/preview/resolvePreview.ts +11 -21
- package/src/preview/subscribeToStateAndFetchBatches.test.ts +96 -97
- package/src/preview/subscribeToStateAndFetchBatches.ts +85 -81
- package/src/preview/util.ts +1 -0
- package/src/project/project.test.ts +3 -3
- package/src/project/project.ts +28 -5
- package/src/projection/getProjectionState.test.ts +69 -49
- package/src/projection/getProjectionState.ts +42 -50
- package/src/projection/projectionQuery.ts +1 -1
- package/src/projection/projectionStore.test.ts +13 -51
- package/src/projection/projectionStore.ts +6 -18
- package/src/projection/resolveProjection.test.ts +32 -127
- package/src/projection/resolveProjection.ts +15 -28
- package/src/projection/subscribeToStateAndFetchBatches.test.ts +105 -90
- package/src/projection/subscribeToStateAndFetchBatches.ts +94 -81
- package/src/projection/util.ts +2 -0
- package/src/projects/projects.test.ts +13 -4
- package/src/projects/projects.ts +6 -1
- package/src/query/queryStore.test.ts +10 -47
- package/src/query/queryStore.ts +151 -133
- package/src/query/queryStoreConstants.ts +2 -0
- package/src/store/createActionBinder.test.ts +153 -0
- package/src/store/createActionBinder.ts +176 -0
- package/src/store/createSanityInstance.test.ts +84 -0
- package/src/store/createSanityInstance.ts +124 -0
- package/src/store/createStateSourceAction.test.ts +196 -0
- package/src/store/createStateSourceAction.ts +260 -0
- package/src/store/createStoreInstance.test.ts +81 -0
- package/src/store/createStoreInstance.ts +80 -0
- package/src/store/createStoreState.test.ts +85 -0
- package/src/store/createStoreState.ts +92 -0
- package/src/store/defineStore.test.ts +18 -0
- package/src/store/defineStore.ts +81 -0
- package/src/users/reducers.test.ts +318 -0
- package/src/users/reducers.ts +88 -0
- package/src/users/types.ts +46 -4
- package/src/users/usersConstants.ts +4 -0
- package/src/users/usersStore.test.ts +350 -223
- package/src/users/usersStore.ts +285 -149
- package/src/utils/createFetcherStore.test.ts +6 -7
- package/src/utils/createFetcherStore.ts +150 -153
- package/src/{common/util.test.ts → utils/hashString.test.ts} +1 -1
- package/src/auth/fetchLoginUrls.test.ts +0 -163
- package/src/auth/fetchLoginUrls.ts +0 -74
- package/src/common/createLiveEventSubscriber.test.ts +0 -121
- package/src/common/createLiveEventSubscriber.ts +0 -55
- package/src/common/types.ts +0 -4
- package/src/instance/identity.test.ts +0 -46
- package/src/instance/identity.ts +0 -29
- package/src/instance/sanityInstance.test.ts +0 -77
- package/src/instance/sanityInstance.ts +0 -57
- package/src/instance/types.ts +0 -37
- package/src/preview/getPreviewProjection.ts +0 -45
- package/src/resources/README.md +0 -370
- package/src/resources/createAction.test.ts +0 -101
- package/src/resources/createAction.ts +0 -44
- package/src/resources/createResource.test.ts +0 -112
- package/src/resources/createResource.ts +0 -102
- package/src/resources/createStateSourceAction.test.ts +0 -114
- package/src/resources/createStateSourceAction.ts +0 -83
- package/src/resources/createStore.test.ts +0 -67
- package/src/resources/createStore.ts +0 -46
- package/src/store/createStore.test.ts +0 -108
- package/src/store/createStore.ts +0 -106
- /package/src/{common/util.ts → utils/hashString.ts} +0 -0
|
@@ -1,39 +1,60 @@
|
|
|
1
|
-
import {type Controller} from '@sanity/comlink'
|
|
1
|
+
import {type ChannelInstance, type Controller} from '@sanity/comlink'
|
|
2
2
|
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {type
|
|
7
|
-
import {
|
|
8
|
-
import {comlinkControllerStore} from '../comlinkControllerStore'
|
|
4
|
+
import {createSanityInstance} from '../../../store/createSanityInstance'
|
|
5
|
+
import {createStoreState} from '../../../store/createStoreState'
|
|
6
|
+
import {type FrameMessage, type WindowMessage} from '../../types'
|
|
7
|
+
import {type ChannelEntry, type ComlinkControllerState} from '../comlinkControllerStore'
|
|
9
8
|
import {getOrCreateChannel} from './getOrCreateChannel'
|
|
10
|
-
import {getOrCreateController} from './getOrCreateController'
|
|
11
9
|
|
|
12
10
|
const channelConfig = {
|
|
13
11
|
name: 'test',
|
|
14
12
|
connectTo: 'iframe',
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
describe('
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
describe('getOrCreateChannel', () => {
|
|
16
|
+
const instance = createSanityInstance({
|
|
17
|
+
projectId: 'test-project-id',
|
|
18
|
+
dataset: 'test-dataset',
|
|
19
|
+
})
|
|
20
|
+
let state: ReturnType<typeof createStoreState<ComlinkControllerState>>
|
|
21
|
+
let mockController: Partial<Controller>
|
|
22
|
+
let mockChannel: Partial<ChannelInstance<FrameMessage, WindowMessage>>
|
|
20
23
|
|
|
21
24
|
beforeEach(() => {
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
// Set up mock channel that we can spy on
|
|
26
|
+
mockChannel = {
|
|
27
|
+
start: vi.fn(),
|
|
28
|
+
stop: vi.fn(),
|
|
29
|
+
on: vi.fn(),
|
|
30
|
+
post: vi.fn(),
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Set up mock controller that returns our mock channel
|
|
34
|
+
mockController = {
|
|
35
|
+
createChannel: vi.fn(() => mockChannel as ChannelInstance<FrameMessage, WindowMessage>),
|
|
36
|
+
destroy: vi.fn(),
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Initialize fresh test store state with a mock controller
|
|
40
|
+
state = createStoreState<ComlinkControllerState>({
|
|
41
|
+
controller: mockController as Controller,
|
|
42
|
+
controllerOrigin: 'https://test.sanity.dev',
|
|
43
|
+
channels: new Map(),
|
|
44
|
+
})
|
|
45
|
+
|
|
24
46
|
vi.clearAllMocks()
|
|
25
47
|
})
|
|
26
48
|
|
|
27
49
|
it('should create a new channel using the controller', () => {
|
|
28
|
-
const createChannelSpy = vi.spyOn(
|
|
50
|
+
const createChannelSpy = vi.spyOn(mockController, 'createChannel')
|
|
29
51
|
|
|
30
|
-
const channel = getOrCreateChannel(instance, channelConfig)
|
|
52
|
+
const channel = getOrCreateChannel({state, instance}, channelConfig)
|
|
31
53
|
|
|
32
54
|
expect(createChannelSpy).toHaveBeenCalledWith(channelConfig)
|
|
33
55
|
expect(channel.on).toBeDefined()
|
|
34
56
|
expect(channel.post).toBeDefined()
|
|
35
|
-
|
|
36
|
-
expect(store.state.get().channels.get('test')).toStrictEqual(
|
|
57
|
+
expect(state.get().channels.get('test')).toStrictEqual(
|
|
37
58
|
expect.objectContaining({
|
|
38
59
|
channel,
|
|
39
60
|
options: channelConfig,
|
|
@@ -42,34 +63,42 @@ describe('createChannel', () => {
|
|
|
42
63
|
})
|
|
43
64
|
|
|
44
65
|
it('should throw error when controller is not initialized', () => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
store.state.set('test reset', {
|
|
66
|
+
// Reset state to have no controller
|
|
67
|
+
state.set('reset', {
|
|
48
68
|
controller: null,
|
|
69
|
+
controllerOrigin: null,
|
|
49
70
|
channels: new Map(),
|
|
50
71
|
})
|
|
51
72
|
|
|
52
|
-
expect(() => getOrCreateChannel(instance, channelConfig)).toThrow(
|
|
73
|
+
expect(() => getOrCreateChannel({state, instance}, channelConfig)).toThrow(
|
|
53
74
|
'Controller must be initialized before using or creating channels',
|
|
54
75
|
)
|
|
55
76
|
})
|
|
56
77
|
|
|
57
78
|
it('should retrieve channel directly from store once created', () => {
|
|
58
|
-
const createdChannel = getOrCreateChannel(instance, channelConfig)
|
|
79
|
+
const createdChannel = getOrCreateChannel({state, instance}, channelConfig)
|
|
80
|
+
vi.clearAllMocks() // Clear call counts
|
|
59
81
|
|
|
60
|
-
|
|
82
|
+
// Retrieve channel again
|
|
83
|
+
const retrievedChannel = getOrCreateChannel({state, instance}, channelConfig)
|
|
61
84
|
expect(retrievedChannel).toBeDefined()
|
|
62
85
|
expect(retrievedChannel).toBe(createdChannel)
|
|
86
|
+
|
|
87
|
+
// Should increment refCount
|
|
88
|
+
const channelEntry = state.get().channels.get('test') as ChannelEntry
|
|
89
|
+
expect(channelEntry.refCount).toBe(2)
|
|
90
|
+
|
|
91
|
+
// Start should be called again
|
|
92
|
+
expect(mockChannel.start).toHaveBeenCalled()
|
|
93
|
+
// But createChannel should not be called again
|
|
94
|
+
expect(mockController.createChannel).not.toHaveBeenCalled()
|
|
63
95
|
})
|
|
64
96
|
|
|
65
97
|
it('should throw error when trying to create channel with different options', () => {
|
|
66
|
-
getOrCreateChannel(instance, channelConfig)
|
|
98
|
+
getOrCreateChannel({state, instance}, channelConfig)
|
|
67
99
|
|
|
68
100
|
expect(() =>
|
|
69
|
-
getOrCreateChannel(instance, {
|
|
70
|
-
...channelConfig,
|
|
71
|
-
connectTo: 'window',
|
|
72
|
-
}),
|
|
101
|
+
getOrCreateChannel({state, instance}, {...channelConfig, connectTo: 'window'}),
|
|
73
102
|
).toThrow('Channel "test" already exists with different options')
|
|
74
103
|
})
|
|
75
104
|
})
|
|
@@ -1,51 +1,53 @@
|
|
|
1
|
-
import {type ChannelInput} from '@sanity/comlink'
|
|
1
|
+
import {type ChannelInput, type ChannelInstance} from '@sanity/comlink'
|
|
2
2
|
import {isEqual} from 'lodash-es'
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import {type StoreContext} from '../../../store/defineStore'
|
|
5
|
+
import {type FrameMessage, type WindowMessage} from '../../types'
|
|
6
|
+
import {type ComlinkControllerState} from '../comlinkControllerStore'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Retrieve or create a channel to be used for communication between
|
|
9
10
|
* an application and the controller.
|
|
10
11
|
* @public
|
|
11
12
|
*/
|
|
12
|
-
export const getOrCreateChannel =
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
export const getOrCreateChannel = (
|
|
14
|
+
{state}: StoreContext<ComlinkControllerState>,
|
|
15
|
+
options: ChannelInput,
|
|
16
|
+
): ChannelInstance<FrameMessage, WindowMessage> => {
|
|
17
|
+
const controller = state.get().controller
|
|
18
|
+
|
|
19
|
+
if (!controller) {
|
|
20
|
+
throw new Error('Controller must be initialized before using or creating channels')
|
|
21
|
+
}
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
23
|
+
const channels = state.get().channels
|
|
24
|
+
const existing = channels.get(options.name)
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (existing) {
|
|
25
|
-
if (!isEqual(existing.options, options)) {
|
|
26
|
-
throw new Error(`Channel "${options.name}" already exists with different options`)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
state.set('incrementChannelRefCount', {
|
|
30
|
-
channels: new Map(channels).set(options.name, {
|
|
31
|
-
...existing,
|
|
32
|
-
refCount: existing.refCount + 1,
|
|
33
|
-
}),
|
|
34
|
-
})
|
|
35
|
-
existing.channel.start()
|
|
36
|
-
return existing.channel
|
|
26
|
+
// limit channels to one per name
|
|
27
|
+
if (existing) {
|
|
28
|
+
if (!isEqual(existing.options, options)) {
|
|
29
|
+
throw new Error(`Channel "${options.name}" already exists with different options`)
|
|
37
30
|
}
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
channel.start()
|
|
41
|
-
state.set('createChannel', {
|
|
32
|
+
state.set('incrementChannelRefCount', {
|
|
42
33
|
channels: new Map(channels).set(options.name, {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
refCount: 1,
|
|
34
|
+
...existing,
|
|
35
|
+
refCount: existing.refCount + 1,
|
|
46
36
|
}),
|
|
47
37
|
})
|
|
48
|
-
|
|
49
|
-
return channel
|
|
38
|
+
existing.channel.start()
|
|
39
|
+
return existing.channel
|
|
50
40
|
}
|
|
51
|
-
|
|
41
|
+
|
|
42
|
+
const channel = controller.createChannel(options)
|
|
43
|
+
channel.start()
|
|
44
|
+
state.set('createChannel', {
|
|
45
|
+
channels: new Map(channels).set(options.name, {
|
|
46
|
+
channel,
|
|
47
|
+
options,
|
|
48
|
+
refCount: 1,
|
|
49
|
+
}),
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
return channel
|
|
53
|
+
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import * as comlink from '@sanity/comlink'
|
|
2
|
-
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
|
2
|
+
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest'
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {type
|
|
7
|
-
import {getOrCreateResource} from '../../../resources/createResource'
|
|
8
|
-
import {comlinkControllerStore} from '../comlinkControllerStore'
|
|
4
|
+
import {createSanityInstance, type SanityInstance} from '../../../store/createSanityInstance'
|
|
5
|
+
import {createStoreState} from '../../../store/createStoreState'
|
|
6
|
+
import {type ComlinkControllerState} from '../comlinkControllerStore'
|
|
9
7
|
import {getOrCreateController} from './getOrCreateController'
|
|
10
8
|
|
|
11
9
|
vi.mock('@sanity/comlink', () => {
|
|
@@ -20,36 +18,46 @@ vi.mock('@sanity/comlink', () => {
|
|
|
20
18
|
|
|
21
19
|
describe('getOrCreateController', () => {
|
|
22
20
|
let instance: SanityInstance
|
|
21
|
+
let state: ReturnType<typeof createStoreState<ComlinkControllerState>>
|
|
23
22
|
|
|
24
23
|
beforeEach(() => {
|
|
25
|
-
instance = createSanityInstance(
|
|
26
|
-
|
|
24
|
+
instance = createSanityInstance({
|
|
25
|
+
projectId: 'test-project-id',
|
|
26
|
+
dataset: 'test-dataset',
|
|
27
|
+
})
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
store.state.set('test reset', {
|
|
29
|
+
state = createStoreState<ComlinkControllerState>({
|
|
30
30
|
controller: null,
|
|
31
|
+
controllerOrigin: null,
|
|
31
32
|
channels: new Map(),
|
|
32
33
|
})
|
|
34
|
+
|
|
33
35
|
vi.clearAllMocks()
|
|
34
36
|
})
|
|
35
37
|
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
instance.dispose()
|
|
40
|
+
})
|
|
41
|
+
|
|
36
42
|
it('should create a new controller if none exists', () => {
|
|
37
43
|
const controllerSpy = vi.spyOn(comlink, 'createController')
|
|
38
44
|
const targetOrigin = 'https://test.sanity.dev'
|
|
39
45
|
|
|
40
|
-
const controller = getOrCreateController(instance, targetOrigin)
|
|
46
|
+
const controller = getOrCreateController({state, instance}, targetOrigin)
|
|
41
47
|
|
|
42
48
|
expect(controllerSpy).toHaveBeenCalledWith({targetOrigin})
|
|
43
49
|
expect(controller).toBeDefined()
|
|
44
|
-
expect(controller
|
|
50
|
+
expect(controller.destroy).toBeDefined() // Verify it's a real controller
|
|
51
|
+
expect(state.get().controller).toBe(controller)
|
|
52
|
+
expect(state.get().controllerOrigin).toBe(targetOrigin)
|
|
45
53
|
})
|
|
46
54
|
|
|
47
55
|
it('should return existing controller if one exists', () => {
|
|
48
56
|
const controllerSpy = vi.spyOn(comlink, 'createController')
|
|
49
57
|
const targetOrigin = 'https://test.sanity.dev'
|
|
50
58
|
|
|
51
|
-
const firstController = getOrCreateController(instance, targetOrigin)
|
|
52
|
-
const secondController = getOrCreateController(instance, targetOrigin)
|
|
59
|
+
const firstController = getOrCreateController({state, instance}, targetOrigin)
|
|
60
|
+
const secondController = getOrCreateController({state, instance}, targetOrigin)
|
|
53
61
|
|
|
54
62
|
expect(controllerSpy).toHaveBeenCalledTimes(1)
|
|
55
63
|
expect(firstController).toBe(secondController)
|
|
@@ -60,10 +68,13 @@ describe('getOrCreateController', () => {
|
|
|
60
68
|
const targetOrigin = 'https://test.sanity.dev'
|
|
61
69
|
const targetOrigin2 = 'https://test2.sanity.dev'
|
|
62
70
|
|
|
63
|
-
const firstController = getOrCreateController(instance, targetOrigin)
|
|
64
|
-
const
|
|
71
|
+
const firstController = getOrCreateController({state, instance}, targetOrigin)
|
|
72
|
+
const destroySpy = vi.spyOn(firstController, 'destroy')
|
|
73
|
+
const secondController = getOrCreateController({state, instance}, targetOrigin2)
|
|
65
74
|
|
|
66
75
|
expect(controllerSpy).toHaveBeenCalledTimes(2)
|
|
76
|
+
expect(destroySpy).toHaveBeenCalled()
|
|
67
77
|
expect(firstController).not.toBe(secondController)
|
|
78
|
+
expect(state.get().controllerOrigin).toBe(targetOrigin2)
|
|
68
79
|
})
|
|
69
80
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {createController} from '@sanity/comlink'
|
|
1
|
+
import {type Controller, createController} from '@sanity/comlink'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import {type StoreContext} from '../../../store/defineStore'
|
|
4
|
+
import {type ComlinkControllerState} from '../comlinkControllerStore'
|
|
5
5
|
import {destroyController} from './destroyController'
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -9,25 +9,26 @@ import {destroyController} from './destroyController'
|
|
|
9
9
|
* between an application and iframes.
|
|
10
10
|
* @public
|
|
11
11
|
*/
|
|
12
|
-
export const getOrCreateController =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
export const getOrCreateController = (
|
|
13
|
+
{state, instance}: StoreContext<ComlinkControllerState>,
|
|
14
|
+
targetOrigin: string,
|
|
15
|
+
): Controller => {
|
|
16
|
+
const {controller, controllerOrigin} = state.get()
|
|
17
|
+
if (controller && controllerOrigin === targetOrigin) {
|
|
18
|
+
return controller
|
|
19
|
+
}
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
// if the target origin has changed, we'll create a new controller,
|
|
22
|
+
// but need to clean up first
|
|
23
|
+
if (controller) {
|
|
24
|
+
destroyController({state, instance})
|
|
25
|
+
}
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const newController = createController({targetOrigin})
|
|
28
|
+
state.set('initializeController', {
|
|
29
|
+
controllerOrigin: targetOrigin,
|
|
30
|
+
controller: newController,
|
|
31
|
+
})
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
})
|
|
33
|
+
return newController
|
|
34
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
import {type ChannelInput, type ChannelInstance, type Controller} from '@sanity/comlink'
|
|
1
2
|
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
-
import {createSanityInstance} from '../../../
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
4
|
+
import {type StoreAction} from '../../../store/createActionBinder'
|
|
5
|
+
import {createSanityInstance, type SanityInstance} from '../../../store/createSanityInstance'
|
|
6
|
+
import {} from '../../../store/createStateSourceAction'
|
|
7
|
+
import {createStoreInstance, type StoreInstance} from '../../../store/createStoreInstance'
|
|
8
|
+
import {type FrameMessage, type WindowMessage} from '../../types'
|
|
9
|
+
import {type ComlinkControllerState, comlinkControllerStore} from '../comlinkControllerStore'
|
|
10
|
+
import {getOrCreateChannel as unboundGetOrCreateChannel} from './getOrCreateChannel'
|
|
11
|
+
import {getOrCreateController as unboundGetOrCreateController} from './getOrCreateController'
|
|
12
|
+
import {releaseChannel as unboundReleaseChannel} from './releaseChannel'
|
|
11
13
|
|
|
12
14
|
const channelConfig = {
|
|
13
15
|
name: 'test',
|
|
@@ -16,19 +18,44 @@ const channelConfig = {
|
|
|
16
18
|
|
|
17
19
|
describe('releaseChannel', () => {
|
|
18
20
|
let instance: SanityInstance
|
|
21
|
+
let store: StoreInstance<ComlinkControllerState>
|
|
22
|
+
|
|
23
|
+
let getOrCreateChannel: (
|
|
24
|
+
inst: SanityInstance,
|
|
25
|
+
options: ChannelInput,
|
|
26
|
+
) => ChannelInstance<FrameMessage, WindowMessage>
|
|
27
|
+
let getOrCreateController: (inst: SanityInstance, targetOrigin: string) => Controller
|
|
28
|
+
let releaseChannel: (inst: SanityInstance, channelName: string) => void
|
|
19
29
|
|
|
20
30
|
beforeEach(() => {
|
|
21
|
-
instance = createSanityInstance(
|
|
31
|
+
instance = createSanityInstance({projectId: 'test-project-id', dataset: 'test-dataset'})
|
|
32
|
+
store = createStoreInstance(instance, comlinkControllerStore)
|
|
33
|
+
|
|
34
|
+
const bind =
|
|
35
|
+
<TParams extends unknown[], TReturn>(
|
|
36
|
+
action: StoreAction<ComlinkControllerState, TParams, TReturn>,
|
|
37
|
+
) =>
|
|
38
|
+
(inst: SanityInstance, ...params: TParams) =>
|
|
39
|
+
action({instance: inst, state: store.state}, ...params)
|
|
40
|
+
|
|
41
|
+
getOrCreateChannel = bind(unboundGetOrCreateChannel)
|
|
42
|
+
getOrCreateController = bind(unboundGetOrCreateController)
|
|
43
|
+
releaseChannel = bind(unboundReleaseChannel)
|
|
44
|
+
|
|
22
45
|
getOrCreateController(instance, 'https://test.sanity.dev')!
|
|
23
46
|
vi.clearAllMocks()
|
|
24
47
|
})
|
|
25
48
|
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
instance.dispose()
|
|
51
|
+
store.dispose()
|
|
52
|
+
})
|
|
53
|
+
|
|
26
54
|
it('should remove channel when released', () => {
|
|
27
55
|
// Create a channel
|
|
28
56
|
getOrCreateChannel(instance, channelConfig)
|
|
29
57
|
|
|
30
58
|
// Get store state
|
|
31
|
-
const store = getOrCreateResource(instance, comlinkControllerStore)
|
|
32
59
|
expect(store.state.get().channels.has('test')).toBe(true)
|
|
33
60
|
|
|
34
61
|
// Release the channel
|
|
@@ -75,7 +102,6 @@ describe('releaseChannel', () => {
|
|
|
75
102
|
expect(stopSpy).not.toHaveBeenCalled()
|
|
76
103
|
|
|
77
104
|
// Verify refCount is 1
|
|
78
|
-
const store = getOrCreateResource(instance, comlinkControllerStore)
|
|
79
105
|
const channelEntry = store.state.get().channels.get('test')
|
|
80
106
|
expect(channelEntry?.refCount).toBe(1)
|
|
81
107
|
})
|
|
@@ -89,7 +115,6 @@ describe('releaseChannel', () => {
|
|
|
89
115
|
releaseChannel(instance, 'test')
|
|
90
116
|
releaseChannel(instance, 'test')
|
|
91
117
|
|
|
92
|
-
const store = getOrCreateResource(instance, comlinkControllerStore)
|
|
93
118
|
expect(store.state.get().channels.has('test')).toBe(false)
|
|
94
119
|
})
|
|
95
120
|
|
|
@@ -104,7 +129,6 @@ describe('releaseChannel', () => {
|
|
|
104
129
|
getOrCreateChannel(instance, channelConfig)
|
|
105
130
|
getOrCreateChannel(instance, channelConfig)
|
|
106
131
|
|
|
107
|
-
const store = getOrCreateResource(instance, comlinkControllerStore)
|
|
108
132
|
let channelEntry = store.state.get().channels.get('test')
|
|
109
133
|
|
|
110
134
|
// Initial refCount should be 3
|
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {type StoreContext} from '../../../store/defineStore'
|
|
2
|
+
import {type ComlinkControllerState} from '../comlinkControllerStore'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Signals to the store that the consumer has stopped using the channel
|
|
6
6
|
* @public
|
|
7
7
|
*/
|
|
8
|
-
export const releaseChannel =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
export const releaseChannel = (
|
|
9
|
+
{state}: StoreContext<ComlinkControllerState>,
|
|
10
|
+
name: string,
|
|
11
|
+
): void => {
|
|
12
|
+
const channels = state.get().channels
|
|
13
|
+
const channelEntry = channels.get(name)
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
if (channelEntry) {
|
|
16
|
+
const newRefCount = channelEntry.refCount === 0 ? 0 : channelEntry.refCount - 1
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
18
|
+
if (newRefCount === 0) {
|
|
19
|
+
channelEntry.channel.stop()
|
|
20
|
+
channels.delete(name)
|
|
21
|
+
state.set('releaseChannel', {channels: new Map(channels)})
|
|
22
|
+
} else {
|
|
23
|
+
state.set('releaseChannel', {
|
|
24
|
+
channels: new Map(channels).set(name, {
|
|
25
|
+
...channelEntry,
|
|
26
|
+
refCount: newRefCount,
|
|
27
|
+
}),
|
|
28
|
+
})
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
|
-
}
|
|
31
|
+
}
|
|
@@ -1,59 +1,88 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {type Controller} from '@sanity/comlink'
|
|
2
|
+
import {describe, expect, it, vi} from 'vitest'
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
-
import {createSanityInstance} from '../../
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {comlinkControllerStore} from './comlinkControllerStore'
|
|
4
|
+
import {bindActionGlobally} from '../../store/createActionBinder'
|
|
5
|
+
import {createSanityInstance, type SanityInstance} from '../../store/createSanityInstance'
|
|
6
|
+
import {} from '../../store/createStateSourceAction'
|
|
7
|
+
import {createStoreState} from '../../store/createStoreState'
|
|
8
|
+
import {type ComlinkControllerState} from './comlinkControllerStore'
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
vi.mock('../../store/createActionBinder', async (importOriginal) => ({
|
|
11
|
+
...(await importOriginal<typeof import('../../store/createActionBinder')>()),
|
|
12
|
+
bindActionGlobally: vi.fn(),
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
describe('comlinkControllerStore', () => {
|
|
11
16
|
let instance: SanityInstance
|
|
12
17
|
beforeEach(() => {
|
|
13
|
-
|
|
18
|
+
vi.resetModules()
|
|
19
|
+
instance = createSanityInstance({
|
|
20
|
+
projectId: 'test-project-id',
|
|
21
|
+
dataset: 'test-dataset',
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
instance.dispose()
|
|
14
27
|
})
|
|
15
28
|
|
|
16
|
-
it('should have correct initial state', () => {
|
|
17
|
-
const
|
|
18
|
-
|
|
29
|
+
it('should have correct initial state', async () => {
|
|
30
|
+
const {comlinkControllerStore} = await import('./comlinkControllerStore')
|
|
31
|
+
|
|
32
|
+
// Create store state directly
|
|
33
|
+
const state = createStoreState<ComlinkControllerState>(
|
|
34
|
+
comlinkControllerStore.getInitialState(instance),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
const initialState = state.get()
|
|
19
38
|
|
|
20
39
|
expect(initialState.controller).toBeNull()
|
|
21
40
|
expect(initialState.channels).toBeInstanceOf(Map)
|
|
22
41
|
expect(initialState.channels.size).toBe(0)
|
|
23
42
|
})
|
|
24
43
|
|
|
25
|
-
it('should cleanup controller on dispose', () => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
it('should cleanup controller on dispose', async () => {
|
|
45
|
+
const controller = {
|
|
46
|
+
destroy: vi.fn() as Controller['destroy'],
|
|
47
|
+
} as Controller
|
|
48
|
+
|
|
49
|
+
// Set up state with controller
|
|
50
|
+
const state = createStoreState<ComlinkControllerState>({
|
|
51
|
+
controller,
|
|
52
|
+
controllerOrigin: 'https://test.sanity.dev',
|
|
53
|
+
channels: new Map(),
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
vi.mocked(bindActionGlobally).mockImplementation(
|
|
57
|
+
(_storeDef, action) =>
|
|
58
|
+
(inst: SanityInstance, ...params: unknown[]) =>
|
|
59
|
+
action({instance: inst, state}, ...params),
|
|
40
60
|
)
|
|
41
61
|
|
|
62
|
+
const {comlinkControllerStore} = await import('./comlinkControllerStore')
|
|
63
|
+
|
|
64
|
+
// Get the cleanup function from the store
|
|
65
|
+
const dispose = comlinkControllerStore.initialize?.({state, instance})
|
|
66
|
+
|
|
42
67
|
// Run cleanup
|
|
43
68
|
dispose?.()
|
|
44
69
|
|
|
45
70
|
// Verify controller.destroy was called
|
|
46
|
-
expect(
|
|
71
|
+
expect(controller.destroy).toHaveBeenCalled()
|
|
47
72
|
})
|
|
48
73
|
|
|
49
|
-
it('should handle cleanup when no controller exists', () => {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
74
|
+
it('should handle cleanup when no controller exists', async () => {
|
|
75
|
+
const {comlinkControllerStore} = await import('./comlinkControllerStore')
|
|
76
|
+
|
|
77
|
+
// Set up state with no controller
|
|
78
|
+
const state = createStoreState<ComlinkControllerState>({
|
|
79
|
+
controller: null,
|
|
80
|
+
controllerOrigin: null,
|
|
81
|
+
channels: new Map(),
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// Get the cleanup function
|
|
85
|
+
const cleanup = comlinkControllerStore.initialize?.({state, instance})
|
|
57
86
|
|
|
58
87
|
// Should not throw when no controller exists
|
|
59
88
|
expect(() => cleanup?.()).not.toThrow()
|