@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.
Files changed (127) hide show
  1. package/dist/index.d.ts +428 -325
  2. package/dist/index.js +1618 -1553
  3. package/dist/index.js.map +1 -1
  4. package/package.json +6 -7
  5. package/src/_exports/index.ts +31 -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 +9 -9
  13. package/src/auth/refreshStampedToken.ts +62 -56
  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 -237
  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 +69 -49
  70. package/src/projection/getProjectionState.ts +42 -50
  71. package/src/projection/projectionQuery.ts +1 -1
  72. package/src/projection/projectionStore.test.ts +13 -51
  73. package/src/projection/projectionStore.ts +6 -18
  74. package/src/projection/resolveProjection.test.ts +32 -127
  75. package/src/projection/resolveProjection.ts +15 -28
  76. package/src/projection/subscribeToStateAndFetchBatches.test.ts +105 -90
  77. package/src/projection/subscribeToStateAndFetchBatches.ts +94 -81
  78. package/src/projection/util.ts +2 -0
  79. package/src/projects/projects.test.ts +13 -4
  80. package/src/projects/projects.ts +6 -1
  81. package/src/query/queryStore.test.ts +10 -47
  82. package/src/query/queryStore.ts +151 -133
  83. package/src/query/queryStoreConstants.ts +2 -0
  84. package/src/store/createActionBinder.test.ts +153 -0
  85. package/src/store/createActionBinder.ts +176 -0
  86. package/src/store/createSanityInstance.test.ts +84 -0
  87. package/src/store/createSanityInstance.ts +124 -0
  88. package/src/store/createStateSourceAction.test.ts +196 -0
  89. package/src/store/createStateSourceAction.ts +260 -0
  90. package/src/store/createStoreInstance.test.ts +81 -0
  91. package/src/store/createStoreInstance.ts +80 -0
  92. package/src/store/createStoreState.test.ts +85 -0
  93. package/src/store/createStoreState.ts +92 -0
  94. package/src/store/defineStore.test.ts +18 -0
  95. package/src/store/defineStore.ts +81 -0
  96. package/src/users/reducers.test.ts +318 -0
  97. package/src/users/reducers.ts +88 -0
  98. package/src/users/types.ts +46 -4
  99. package/src/users/usersConstants.ts +4 -0
  100. package/src/users/usersStore.test.ts +350 -223
  101. package/src/users/usersStore.ts +285 -149
  102. package/src/utils/createFetcherStore.test.ts +6 -7
  103. package/src/utils/createFetcherStore.ts +150 -153
  104. package/src/{common/util.test.ts → utils/hashString.test.ts} +1 -1
  105. package/src/auth/fetchLoginUrls.test.ts +0 -163
  106. package/src/auth/fetchLoginUrls.ts +0 -74
  107. package/src/common/createLiveEventSubscriber.test.ts +0 -121
  108. package/src/common/createLiveEventSubscriber.ts +0 -55
  109. package/src/common/types.ts +0 -4
  110. package/src/instance/identity.test.ts +0 -46
  111. package/src/instance/identity.ts +0 -29
  112. package/src/instance/sanityInstance.test.ts +0 -77
  113. package/src/instance/sanityInstance.ts +0 -57
  114. package/src/instance/types.ts +0 -37
  115. package/src/preview/getPreviewProjection.ts +0 -45
  116. package/src/resources/README.md +0 -370
  117. package/src/resources/createAction.test.ts +0 -101
  118. package/src/resources/createAction.ts +0 -44
  119. package/src/resources/createResource.test.ts +0 -112
  120. package/src/resources/createResource.ts +0 -102
  121. package/src/resources/createStateSourceAction.test.ts +0 -114
  122. package/src/resources/createStateSourceAction.ts +0 -83
  123. package/src/resources/createStore.test.ts +0 -67
  124. package/src/resources/createStore.ts +0 -46
  125. package/src/store/createStore.test.ts +0 -108
  126. package/src/store/createStore.ts +0 -106
  127. /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 {config} from '../../../../test/fixtures'
5
- import {createSanityInstance} from '../../../instance/sanityInstance'
6
- import {type SanityInstance} from '../../../instance/types'
7
- import {getOrCreateResource} from '../../../resources/createResource'
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('createChannel', () => {
18
- let instance: SanityInstance
19
- let controller: Controller
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
- instance = createSanityInstance(config)
23
- controller = getOrCreateController(instance, 'https://test.sanity.dev')!
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(controller, 'createChannel')
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
- const store = getOrCreateResource(instance, comlinkControllerStore)
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
- const store = getOrCreateResource(instance, comlinkControllerStore)
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
- const retrievedChannel = getOrCreateChannel(instance, channelConfig)
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 {createAction} from '../../../resources/createAction'
5
- import {comlinkControllerStore} from '../comlinkControllerStore'
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 = createAction(comlinkControllerStore, ({state}) => {
13
- return (options: ChannelInput) => {
14
- const controller = state.get().controller
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
- if (!controller) {
17
- throw new Error('Controller must be initialized before using or creating channels')
18
- }
23
+ const channels = state.get().channels
24
+ const existing = channels.get(options.name)
19
25
 
20
- const channels = state.get().channels
21
- const existing = channels.get(options.name)
22
-
23
- // limit channels to one per name
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
- const channel = controller.createChannel(options)
40
- channel.start()
41
- state.set('createChannel', {
32
+ state.set('incrementChannelRefCount', {
42
33
  channels: new Map(channels).set(options.name, {
43
- channel,
44
- options,
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 {config} from '../../../../test/fixtures'
5
- import {createSanityInstance} from '../../../instance/sanityInstance'
6
- import {type SanityInstance} from '../../../instance/types'
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(config)
26
- const store = getOrCreateResource(instance, comlinkControllerStore)
24
+ instance = createSanityInstance({
25
+ projectId: 'test-project-id',
26
+ dataset: 'test-dataset',
27
+ })
27
28
 
28
- // Reset store state
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!.destroy).toBeDefined() // Verify it's a real 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 secondController = getOrCreateController(instance, targetOrigin2)
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 {createAction} from '../../../resources/createAction'
4
- import {comlinkControllerStore} from '../comlinkControllerStore'
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 = createAction(comlinkControllerStore, ({state, instance}) => {
13
- return (targetOrigin: string) => {
14
- const {controller, controllerOrigin} = state.get()
15
- if (controller && controllerOrigin === targetOrigin) {
16
- return controller
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
- // if the target origin has changed, we'll create a new controller,
20
- // but need to clean up first
21
- if (controller) {
22
- destroyController({state, instance})
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
- const newController = createController({targetOrigin})
26
- state.set('initializeController', {
27
- controllerOrigin: targetOrigin,
28
- controller: newController,
29
- })
27
+ const newController = createController({targetOrigin})
28
+ state.set('initializeController', {
29
+ controllerOrigin: targetOrigin,
30
+ controller: newController,
31
+ })
30
32
 
31
- return newController
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 {config} from '../../../../test/fixtures'
4
- import {createSanityInstance} from '../../../instance/sanityInstance'
5
- import {type SanityInstance} from '../../../instance/types'
6
- import {getOrCreateResource} from '../../../resources/createResource'
7
- import {comlinkControllerStore} from '../comlinkControllerStore'
8
- import {getOrCreateChannel} from './getOrCreateChannel'
9
- import {getOrCreateController} from './getOrCreateController'
10
- import {releaseChannel} from './releaseChannel'
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(config)
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 {createAction} from '../../../resources/createAction'
2
- import {comlinkControllerStore} from '../comlinkControllerStore'
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 = createAction(comlinkControllerStore, ({state}) => {
9
- return (name: string) => {
10
- const channels = state.get().channels
11
- const channelEntry = channels.get(name)
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
- if (channelEntry) {
14
- const newRefCount = channelEntry.refCount === 0 ? 0 : channelEntry.refCount - 1
15
+ if (channelEntry) {
16
+ const newRefCount = channelEntry.refCount === 0 ? 0 : channelEntry.refCount - 1
15
17
 
16
- if (newRefCount === 0) {
17
- channelEntry.channel.stop()
18
- channels.delete(name)
19
- state.set('releaseChannel', {channels: new Map(channels)})
20
- } else {
21
- state.set('releaseChannel', {
22
- channels: new Map(channels).set(name, {
23
- ...channelEntry,
24
- refCount: newRefCount,
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 {describe, expect, it} from 'vitest'
1
+ import {type Controller} from '@sanity/comlink'
2
+ import {describe, expect, it, vi} from 'vitest'
2
3
 
3
- import {config} from '../../../test/fixtures'
4
- import {createSanityInstance} from '../../instance/sanityInstance'
5
- import {type SanityInstance} from '../../instance/types'
6
- import {createResourceState, getOrCreateResource} from '../../resources/createResource'
7
- import {getOrCreateController} from './actions/getOrCreateController'
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
- describe('comlinkStore', () => {
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
- instance = createSanityInstance(config)
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 store = getOrCreateResource(instance, comlinkControllerStore)
18
- const initialState = store.state.get()
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
- // Create instance and initialize controller
27
- const controller = getOrCreateController(instance, 'https://test.sanity.dev')
28
- const destroySpy = vi.spyOn(controller!, 'destroy')
29
-
30
- // Get initial state and create resource state
31
- const initialState = comlinkControllerStore.getInitialState(instance)
32
- initialState.controller = controller // Set the controller in our initial state
33
-
34
- const dispose = comlinkControllerStore.initialize!.call(
35
- {
36
- instance,
37
- state: createResourceState(initialState),
38
- },
39
- instance,
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(destroySpy).toHaveBeenCalled()
71
+ expect(controller.destroy).toHaveBeenCalled()
47
72
  })
48
73
 
49
- it('should handle cleanup when no controller exists', () => {
50
- const cleanup = comlinkControllerStore.initialize!.call(
51
- {
52
- instance,
53
- state: createResourceState(comlinkControllerStore.getInitialState(instance)),
54
- },
55
- instance,
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()