@sanity/sdk 0.0.0-alpha.1
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 +339 -0
- package/dist/index.js +492 -0
- package/dist/index.js.map +1 -0
- package/package.json +77 -0
- package/src/_exports/index.ts +39 -0
- package/src/auth/authStore.test.ts +296 -0
- package/src/auth/authStore.ts +125 -0
- package/src/auth/getAuthStore.test.ts +14 -0
- package/src/auth/getInternalAuthStore.ts +20 -0
- package/src/auth/internalAuthStore.test.ts +334 -0
- package/src/auth/internalAuthStore.ts +519 -0
- package/src/client/getClient.test.ts +41 -0
- package/src/client/getClient.ts +13 -0
- package/src/client/getSubscribableClient.test.ts +71 -0
- package/src/client/getSubscribableClient.ts +17 -0
- package/src/client/store/actions/getClientEvents.test.ts +95 -0
- package/src/client/store/actions/getClientEvents.ts +33 -0
- package/src/client/store/actions/getOrCreateClient.test.ts +56 -0
- package/src/client/store/actions/getOrCreateClient.ts +40 -0
- package/src/client/store/actions/receiveToken.test.ts +18 -0
- package/src/client/store/actions/receiveToken.ts +31 -0
- package/src/client/store/clientStore.test.ts +152 -0
- package/src/client/store/clientStore.ts +98 -0
- package/src/documentList/documentListStore.test.ts +575 -0
- package/src/documentList/documentListStore.ts +269 -0
- package/src/documents/.keep +0 -0
- package/src/instance/identity.test.ts +46 -0
- package/src/instance/identity.ts +28 -0
- package/src/instance/sanityInstance.test.ts +66 -0
- package/src/instance/sanityInstance.ts +64 -0
- package/src/instance/types.d.ts +29 -0
- package/src/schema/schemaStore.test.ts +30 -0
- package/src/schema/schemaStore.ts +32 -0
- package/src/store/createStore.test.ts +108 -0
- package/src/store/createStore.ts +106 -0
- package/src/tsdoc.json +39 -0
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sanity/sdk",
|
|
3
|
+
"version": "0.0.0-alpha.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Sanity SDK for Content OS",
|
|
6
|
+
"keywords": [],
|
|
7
|
+
"homepage": "https://github.com/sanity-io/sdk#readme",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/sanity-io/sdk/issues"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+ssh://git@github.com/sanity-io/sdk.git"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "Sanity <developers@sanity.io>",
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"type": "module",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"source": "./src/_exports/index.ts",
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./package.json": "./package.json"
|
|
26
|
+
},
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"src"
|
|
33
|
+
],
|
|
34
|
+
"lint-staged": {
|
|
35
|
+
"*": [
|
|
36
|
+
"prettier --write --cache --ignore-unknown"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"browserslist": "extends @sanity/browserslist-config",
|
|
40
|
+
"prettier": "@sanity/prettier-config",
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@sanity/client": "^6.22.3",
|
|
43
|
+
"@types/lodash-es": "^4.17.12",
|
|
44
|
+
"lodash-es": "^4.17.21",
|
|
45
|
+
"rxjs": "^7.8.1",
|
|
46
|
+
"zustand": "^5.0.1"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@sanity/pkg-utils": "^6.11.14",
|
|
50
|
+
"@sanity/prettier-config": "^1.0.3",
|
|
51
|
+
"@sanity/types": "^3.65.1",
|
|
52
|
+
"@vitest/coverage-v8": "2.1.8",
|
|
53
|
+
"eslint": "^9.16.0",
|
|
54
|
+
"lint-staged": "^15.2.10",
|
|
55
|
+
"prettier": "^3.4.2",
|
|
56
|
+
"typescript": "^5.7.2",
|
|
57
|
+
"vitest": "^2.1.8",
|
|
58
|
+
"@repo/package.config": "0.0.1"
|
|
59
|
+
},
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": ">=20.0.0"
|
|
62
|
+
},
|
|
63
|
+
"publishConfig": {
|
|
64
|
+
"access": "restricted"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "pkg build --strict --clean --check",
|
|
68
|
+
"clean": "rimraf dist",
|
|
69
|
+
"dev": "pkg watch",
|
|
70
|
+
"format": "prettier --write --cache --ignore-unknown .",
|
|
71
|
+
"lint": "eslint .",
|
|
72
|
+
"test": "vitest run",
|
|
73
|
+
"test:coverage": "vitest run --coverage",
|
|
74
|
+
"test:watch": "vitest",
|
|
75
|
+
"ts:check": "tsc --noEmit"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** MAIN INSTANCE */
|
|
2
|
+
// Utils
|
|
3
|
+
export {createSanityInstance} from '../instance/sanityInstance'
|
|
4
|
+
// Types
|
|
5
|
+
export type {SanityConfig} from '../instance/sanityInstance'
|
|
6
|
+
export type {InternalStores, SanityInstance, SdkIdentity} from '../instance/types'
|
|
7
|
+
|
|
8
|
+
/** CLIENT */
|
|
9
|
+
// Utils
|
|
10
|
+
export {getClient} from '../client/getClient'
|
|
11
|
+
export {getSubscribableClient} from '../client/getSubscribableClient'
|
|
12
|
+
// Types
|
|
13
|
+
export type {ClientOptions, ClientState, ClientStore} from '../client/store/clientStore'
|
|
14
|
+
|
|
15
|
+
/** SCHEMA */
|
|
16
|
+
export type {SchemaState, SchemaStore} from '../schema/schemaStore'
|
|
17
|
+
|
|
18
|
+
/** DOCUMENT LIST */
|
|
19
|
+
export type {
|
|
20
|
+
DocumentHandle,
|
|
21
|
+
DocumentListOptions,
|
|
22
|
+
DocumentListState,
|
|
23
|
+
DocumentListStore,
|
|
24
|
+
SortOrderingItem,
|
|
25
|
+
} from '../documentList/documentListStore'
|
|
26
|
+
export {createDocumentListStore} from '../documentList/documentListStore'
|
|
27
|
+
|
|
28
|
+
/** AUTH */
|
|
29
|
+
export type {CurrentUserSlice} from '../auth/authStore'
|
|
30
|
+
export {
|
|
31
|
+
type AuthConfig,
|
|
32
|
+
type AuthProvider,
|
|
33
|
+
type AuthState,
|
|
34
|
+
type AuthStateSlice,
|
|
35
|
+
type AuthStore,
|
|
36
|
+
getAuthStore,
|
|
37
|
+
type AuthTokenSlice as PublicTokenSlice,
|
|
38
|
+
} from '../auth/authStore'
|
|
39
|
+
export type {CurrentUser, Role} from '@sanity/types'
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import type {CurrentUser} from '@sanity/types'
|
|
2
|
+
import {beforeEach, describe, expect, type Mock, test, vi} from 'vitest'
|
|
3
|
+
|
|
4
|
+
import type {SanityInstance} from '../instance/types'
|
|
5
|
+
import {getAuthStore} from './authStore'
|
|
6
|
+
import {getInternalAuthStore} from './getInternalAuthStore'
|
|
7
|
+
|
|
8
|
+
// Mock the getInternalAuthStore module
|
|
9
|
+
vi.mock('./getInternalAuthStore')
|
|
10
|
+
|
|
11
|
+
describe('authStore', () => {
|
|
12
|
+
const mockCurrentUser: CurrentUser = {
|
|
13
|
+
id: 'user-123',
|
|
14
|
+
name: 'Test User',
|
|
15
|
+
email: 'test@example.com',
|
|
16
|
+
profileImage: 'https://example.com/image.jpg',
|
|
17
|
+
role: 'admin',
|
|
18
|
+
roles: [],
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const mockLoggedInState = {
|
|
22
|
+
authState: {
|
|
23
|
+
type: 'logged-in' as const,
|
|
24
|
+
token: 'mock-token',
|
|
25
|
+
currentUser: mockCurrentUser,
|
|
26
|
+
},
|
|
27
|
+
handleCallback: vi.fn(),
|
|
28
|
+
logout: vi.fn(),
|
|
29
|
+
dispose: vi.fn(),
|
|
30
|
+
getLoginUrls: vi.fn(),
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const mockLoggedOutState = {
|
|
34
|
+
authState: {
|
|
35
|
+
type: 'logged-out' as const,
|
|
36
|
+
isDestroyingSession: false,
|
|
37
|
+
},
|
|
38
|
+
handleCallback: vi.fn(),
|
|
39
|
+
logout: vi.fn(),
|
|
40
|
+
dispose: vi.fn(),
|
|
41
|
+
getLoginUrls: vi.fn(),
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const mockInternalStore = {
|
|
45
|
+
getState: vi.fn(() => mockLoggedInState),
|
|
46
|
+
getInitialState: vi.fn(() => mockLoggedInState),
|
|
47
|
+
subscribe: vi.fn((_selector, _listener) => vi.fn()),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
vi.clearAllMocks()
|
|
52
|
+
;(getInternalAuthStore as Mock).mockReturnValue(mockInternalStore)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('creates auth store with all required methods', () => {
|
|
56
|
+
const mockInstance = {} as SanityInstance
|
|
57
|
+
const store = getAuthStore(mockInstance)
|
|
58
|
+
|
|
59
|
+
expect(store).toHaveProperty('authState')
|
|
60
|
+
expect(store).toHaveProperty('tokenState')
|
|
61
|
+
expect(store).toHaveProperty('currentUserState')
|
|
62
|
+
expect(store).toHaveProperty('handleCallback')
|
|
63
|
+
expect(store).toHaveProperty('logout')
|
|
64
|
+
expect(store).toHaveProperty('dispose')
|
|
65
|
+
expect(store).toHaveProperty('getLoginUrls')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('authState returns correct state when logged in', () => {
|
|
69
|
+
const mockInstance = {} as SanityInstance
|
|
70
|
+
const store = getAuthStore(mockInstance)
|
|
71
|
+
|
|
72
|
+
expect(store.authState.getState()).toBe(mockLoggedInState.authState)
|
|
73
|
+
expect(store.authState.getInitialState()).toBe(mockLoggedInState.authState)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test('tokenState returns correct token when logged in', () => {
|
|
77
|
+
const mockInstance = {} as SanityInstance
|
|
78
|
+
const store = getAuthStore(mockInstance)
|
|
79
|
+
|
|
80
|
+
expect(store.tokenState.getState()).toBe('mock-token')
|
|
81
|
+
expect(store.tokenState.getInitialState()).toBe('mock-token')
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test('tokenState returns null when logged out', () => {
|
|
85
|
+
const mockInstance = {} as SanityInstance
|
|
86
|
+
mockInternalStore.getState.mockReturnValue({
|
|
87
|
+
...mockLoggedOutState,
|
|
88
|
+
authState: mockLoggedOutState.authState,
|
|
89
|
+
} as unknown as typeof mockLoggedInState)
|
|
90
|
+
|
|
91
|
+
mockInternalStore.getInitialState.mockReturnValue({
|
|
92
|
+
...mockLoggedOutState,
|
|
93
|
+
authState: mockLoggedOutState.authState,
|
|
94
|
+
} as unknown as typeof mockLoggedInState)
|
|
95
|
+
|
|
96
|
+
const store = getAuthStore(mockInstance)
|
|
97
|
+
|
|
98
|
+
expect(store.tokenState.getState()).toBeNull()
|
|
99
|
+
expect(store.tokenState.getInitialState()).toBeNull()
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('currentUserState returns correct user when logged in', () => {
|
|
103
|
+
const mockInstance = {} as SanityInstance
|
|
104
|
+
mockInternalStore.getState.mockReturnValue(mockLoggedInState)
|
|
105
|
+
mockInternalStore.getInitialState.mockReturnValue(mockLoggedInState)
|
|
106
|
+
|
|
107
|
+
const store = getAuthStore(mockInstance)
|
|
108
|
+
|
|
109
|
+
expect(store.currentUserState.getState()).toBe(mockCurrentUser)
|
|
110
|
+
expect(store.currentUserState.getInitialState()).toBe(mockCurrentUser)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test('currentUserState returns null when logged out', () => {
|
|
114
|
+
const mockInstance = {} as SanityInstance
|
|
115
|
+
mockInternalStore.getState.mockReturnValue({
|
|
116
|
+
...mockLoggedOutState,
|
|
117
|
+
authState: mockLoggedOutState.authState,
|
|
118
|
+
} as unknown as typeof mockLoggedInState)
|
|
119
|
+
|
|
120
|
+
mockInternalStore.getInitialState.mockReturnValue({
|
|
121
|
+
...mockLoggedOutState,
|
|
122
|
+
authState: mockLoggedOutState.authState,
|
|
123
|
+
} as unknown as typeof mockLoggedInState)
|
|
124
|
+
|
|
125
|
+
const store = getAuthStore(mockInstance)
|
|
126
|
+
|
|
127
|
+
expect(store.currentUserState.getState()).toBeNull()
|
|
128
|
+
expect(store.currentUserState.getInitialState()).toBeNull()
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
test('subscribe callbacks are properly set up', () => {
|
|
132
|
+
const mockInstance = {} as SanityInstance
|
|
133
|
+
const store = getAuthStore(mockInstance)
|
|
134
|
+
const mockListener = vi.fn()
|
|
135
|
+
|
|
136
|
+
store.authState.subscribe(mockListener)
|
|
137
|
+
store.tokenState.subscribe(mockListener)
|
|
138
|
+
store.currentUserState.subscribe(mockListener)
|
|
139
|
+
|
|
140
|
+
expect(mockInternalStore.subscribe).toHaveBeenCalledTimes(3)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
test('tokenState.getInitialState returns null when initial state is logged out', () => {
|
|
144
|
+
const mockInstance = {} as SanityInstance
|
|
145
|
+
mockInternalStore.getInitialState.mockReturnValue({
|
|
146
|
+
...mockLoggedOutState,
|
|
147
|
+
authState: mockLoggedOutState.authState,
|
|
148
|
+
} as unknown as typeof mockLoggedInState)
|
|
149
|
+
|
|
150
|
+
const store = getAuthStore(mockInstance)
|
|
151
|
+
expect(store.tokenState.getInitialState()).toBeNull()
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
test('currentUserState.getInitialState returns null when initial state is logged out', () => {
|
|
155
|
+
const mockInstance = {} as SanityInstance
|
|
156
|
+
mockInternalStore.getInitialState.mockReturnValue({
|
|
157
|
+
...mockLoggedOutState,
|
|
158
|
+
authState: mockLoggedOutState.authState,
|
|
159
|
+
} as unknown as typeof mockLoggedInState)
|
|
160
|
+
|
|
161
|
+
const store = getAuthStore(mockInstance)
|
|
162
|
+
|
|
163
|
+
expect(store.currentUserState.getInitialState()).toBeNull()
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
test('tokenState.subscribe works correctly', () => {
|
|
167
|
+
const mockInstance = {} as SanityInstance
|
|
168
|
+
const store = getAuthStore(mockInstance)
|
|
169
|
+
const mockListener = vi.fn()
|
|
170
|
+
|
|
171
|
+
store.tokenState.subscribe(mockListener)
|
|
172
|
+
|
|
173
|
+
// Simulate a state change to 'logged-in' with a new token
|
|
174
|
+
mockInternalStore.subscribe.mock.calls[0][0](
|
|
175
|
+
{
|
|
176
|
+
authState: {type: 'logged-in', token: 'new-token', currentUser: mockCurrentUser},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
authState: {type: 'logged-in', token: 'mock-token', currentUser: mockCurrentUser},
|
|
180
|
+
},
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
expect(mockListener).toHaveBeenCalledWith('new-token', 'mock-token')
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
test('currentUserState.subscribe works correctly', () => {
|
|
187
|
+
const mockInstance = {} as SanityInstance
|
|
188
|
+
const store = getAuthStore(mockInstance)
|
|
189
|
+
const mockListener = vi.fn()
|
|
190
|
+
|
|
191
|
+
store.currentUserState.subscribe(mockListener)
|
|
192
|
+
|
|
193
|
+
// Simulate a state change to 'logged-in' with a new user
|
|
194
|
+
mockInternalStore.subscribe.mock.calls[0][0](
|
|
195
|
+
{
|
|
196
|
+
authState: {
|
|
197
|
+
type: 'logged-in',
|
|
198
|
+
token: 'mock-token',
|
|
199
|
+
currentUser: {...mockCurrentUser, name: 'New Name'},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
authState: {type: 'logged-in', token: 'mock-token', currentUser: mockCurrentUser},
|
|
204
|
+
},
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
expect(mockListener).toHaveBeenCalledWith(
|
|
208
|
+
{...mockCurrentUser, name: 'New Name'},
|
|
209
|
+
mockCurrentUser,
|
|
210
|
+
)
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
test('tokenState.subscribe handles logged-out state correctly', () => {
|
|
214
|
+
const mockInstance = {} as SanityInstance
|
|
215
|
+
const store = getAuthStore(mockInstance)
|
|
216
|
+
const mockListener = vi.fn()
|
|
217
|
+
|
|
218
|
+
store.tokenState.subscribe(mockListener)
|
|
219
|
+
|
|
220
|
+
// Simulate a state change to 'logged-out'
|
|
221
|
+
mockInternalStore.subscribe.mock.calls[0][0](
|
|
222
|
+
{
|
|
223
|
+
authState: {type: 'logged-out', isDestroyingSession: false},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
authState: {type: 'logged-in', token: 'mock-token', currentUser: mockCurrentUser},
|
|
227
|
+
},
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
expect(mockListener).toHaveBeenCalledWith(null, 'mock-token')
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
test('currentUserState.subscribe handles logged-out state correctly', () => {
|
|
234
|
+
const mockInstance = {} as SanityInstance
|
|
235
|
+
const store = getAuthStore(mockInstance)
|
|
236
|
+
const mockListener = vi.fn()
|
|
237
|
+
|
|
238
|
+
store.currentUserState.subscribe(mockListener)
|
|
239
|
+
|
|
240
|
+
// Simulate a state change to 'logged-out'
|
|
241
|
+
mockInternalStore.subscribe.mock.calls[0][0](
|
|
242
|
+
{
|
|
243
|
+
authState: {type: 'logged-out', isDestroyingSession: false},
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
authState: {type: 'logged-in', token: 'mock-token', currentUser: mockCurrentUser},
|
|
247
|
+
},
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
expect(mockListener).toHaveBeenCalledWith(null, mockCurrentUser)
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
test('tokenState.subscribe handles transition from logged-out to logged-in correctly', () => {
|
|
254
|
+
const mockInstance = {} as SanityInstance
|
|
255
|
+
const store = getAuthStore(mockInstance)
|
|
256
|
+
const mockListener = vi.fn()
|
|
257
|
+
|
|
258
|
+
store.tokenState.subscribe(mockListener)
|
|
259
|
+
|
|
260
|
+
// Simulate a state change from 'logged-out' to 'logged-in'
|
|
261
|
+
mockInternalStore.subscribe.mock.calls[0][0](
|
|
262
|
+
{
|
|
263
|
+
authState: {type: 'logged-in', token: 'new-token', currentUser: mockCurrentUser},
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
authState: {type: 'logged-out', isDestroyingSession: false},
|
|
267
|
+
},
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
expect(mockListener).toHaveBeenCalledWith('new-token', null)
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
test('currentUserState.subscribe handles transition from logged-out to logged-in correctly', () => {
|
|
274
|
+
const mockInstance = {} as SanityInstance
|
|
275
|
+
const store = getAuthStore(mockInstance)
|
|
276
|
+
const mockListener = vi.fn()
|
|
277
|
+
|
|
278
|
+
store.currentUserState.subscribe(mockListener)
|
|
279
|
+
|
|
280
|
+
// Simulate a state change from 'logged-out' to 'logged-in'
|
|
281
|
+
mockInternalStore.subscribe.mock.calls[0][0](
|
|
282
|
+
{
|
|
283
|
+
authState: {
|
|
284
|
+
type: 'logged-in',
|
|
285
|
+
token: 'new-token',
|
|
286
|
+
currentUser: {...mockCurrentUser, name: 'Updated User'},
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
authState: {type: 'logged-out', isDestroyingSession: false},
|
|
291
|
+
},
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
expect(mockListener).toHaveBeenCalledWith({...mockCurrentUser, name: 'Updated User'}, null)
|
|
295
|
+
})
|
|
296
|
+
})
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type {CurrentUser} from '@sanity/types'
|
|
2
|
+
|
|
3
|
+
import type {SanityInstance} from '../instance/types'
|
|
4
|
+
import {getInternalAuthStore} from './getInternalAuthStore'
|
|
5
|
+
import type {AuthProvider, AuthState} from './internalAuthStore'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export interface AuthStore {
|
|
11
|
+
authState: AuthStateSlice
|
|
12
|
+
tokenState: AuthTokenSlice
|
|
13
|
+
currentUserState: CurrentUserSlice
|
|
14
|
+
handleCallback: (locationHref?: string) => Promise<string | false>
|
|
15
|
+
logout: () => Promise<void>
|
|
16
|
+
dispose: () => void
|
|
17
|
+
getLoginUrls: () => AuthProvider[] | Promise<AuthProvider[]>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Public interface for the auth store.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export interface AuthStateSlice {
|
|
25
|
+
getState: () => AuthState
|
|
26
|
+
getInitialState: () => AuthState
|
|
27
|
+
subscribe: (listener: (state: AuthState, prevState: AuthState) => void) => () => void
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Public interface for the token store.
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export interface AuthTokenSlice {
|
|
36
|
+
getState: () => string | null
|
|
37
|
+
getInitialState: () => string | null
|
|
38
|
+
subscribe: (listener: (token: string | null, prevToken: string | null) => void) => () => void
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Public interface for the auth store slice that contains the current user.
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
export interface CurrentUserSlice {
|
|
47
|
+
getState: () => CurrentUser | null
|
|
48
|
+
getInitialState: () => CurrentUser | null
|
|
49
|
+
subscribe: (
|
|
50
|
+
listener: (user: CurrentUser | null, prevUser: CurrentUser | null) => void,
|
|
51
|
+
) => () => void
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type {AuthConfig, AuthProvider, AuthState} from './internalAuthStore'
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Retrieves or creates an `AuthStore` for the given `SanityInstance`.
|
|
58
|
+
*
|
|
59
|
+
* @param instance - The `SanityInstance` to get or create the `AuthStore` for.
|
|
60
|
+
* @returns The `AuthStore` associated with the given `SanityInstance`.
|
|
61
|
+
*
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
64
|
+
export const getAuthStore = (instance: SanityInstance): AuthStore => {
|
|
65
|
+
const internalAuthStore = getInternalAuthStore(instance)
|
|
66
|
+
|
|
67
|
+
const authState: AuthStateSlice = {
|
|
68
|
+
getState: () => internalAuthStore.getState().authState,
|
|
69
|
+
getInitialState: () => internalAuthStore.getInitialState().authState,
|
|
70
|
+
subscribe: (listener) =>
|
|
71
|
+
internalAuthStore.subscribe((current, prev) => {
|
|
72
|
+
listener(current.authState, prev.authState)
|
|
73
|
+
}),
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const tokenState: AuthTokenSlice = {
|
|
77
|
+
getState: () => {
|
|
78
|
+
const state = internalAuthStore.getState()
|
|
79
|
+
if (state.authState.type !== 'logged-in') return null
|
|
80
|
+
return state.authState.token
|
|
81
|
+
},
|
|
82
|
+
getInitialState: () => {
|
|
83
|
+
const state = internalAuthStore.getInitialState()
|
|
84
|
+
if (state.authState.type !== 'logged-in') return null
|
|
85
|
+
return state.authState.token
|
|
86
|
+
},
|
|
87
|
+
subscribe: (listener) =>
|
|
88
|
+
internalAuthStore.subscribe((state, prevState) => {
|
|
89
|
+
const token = state.authState.type === 'logged-in' ? state.authState.token : null
|
|
90
|
+
const prevToken =
|
|
91
|
+
prevState.authState.type === 'logged-in' ? prevState.authState.token : null
|
|
92
|
+
listener(token, prevToken)
|
|
93
|
+
}),
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const currentUserState: CurrentUserSlice = {
|
|
97
|
+
getState: () => {
|
|
98
|
+
const state = internalAuthStore.getState()
|
|
99
|
+
if (state.authState.type !== 'logged-in') return null
|
|
100
|
+
return state.authState.currentUser
|
|
101
|
+
},
|
|
102
|
+
getInitialState: () => {
|
|
103
|
+
const state = internalAuthStore.getInitialState()
|
|
104
|
+
if (state.authState.type !== 'logged-in') return null
|
|
105
|
+
return state.authState.currentUser
|
|
106
|
+
},
|
|
107
|
+
subscribe: (listener) =>
|
|
108
|
+
internalAuthStore.subscribe((state, prevState) => {
|
|
109
|
+
const user = state.authState.type === 'logged-in' ? state.authState.currentUser : null
|
|
110
|
+
const prevUser =
|
|
111
|
+
prevState.authState.type === 'logged-in' ? prevState.authState.currentUser : null
|
|
112
|
+
listener(user, prevUser)
|
|
113
|
+
}),
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
authState,
|
|
118
|
+
tokenState,
|
|
119
|
+
currentUserState,
|
|
120
|
+
handleCallback: internalAuthStore.getState().handleCallback,
|
|
121
|
+
logout: internalAuthStore.getState().logout,
|
|
122
|
+
dispose: internalAuthStore.getState().dispose,
|
|
123
|
+
getLoginUrls: internalAuthStore.getState().getLoginUrls,
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {describe, expect, it} from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {createSanityInstance} from '../instance/sanityInstance'
|
|
4
|
+
import {getInternalAuthStore} from './getInternalAuthStore'
|
|
5
|
+
|
|
6
|
+
describe('getAuthStore', () => {
|
|
7
|
+
it('returns the same AuthStore instance on subsequent calls for the same instance', () => {
|
|
8
|
+
const instance = createSanityInstance({projectId: 'testProject', dataset: 'testDataset'})
|
|
9
|
+
const storeA = getInternalAuthStore(instance)
|
|
10
|
+
const storeB = getInternalAuthStore(instance)
|
|
11
|
+
|
|
12
|
+
expect(storeA).toBe(storeB)
|
|
13
|
+
})
|
|
14
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {getOrCreateResource} from '../instance/sanityInstance'
|
|
2
|
+
import type {SanityInstance} from '../instance/types'
|
|
3
|
+
import {createInternalAuthStore, type InternalAuthStore} from './internalAuthStore'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Retrieves or creates an `AuthStore` for the given `SanityInstance`.
|
|
7
|
+
*
|
|
8
|
+
* Ensures a single `AuthStore` instance is associated with the provided instance.
|
|
9
|
+
* Creates a new store using the instance's configuration if none exists.
|
|
10
|
+
*
|
|
11
|
+
* @param instance - The `SanityInstance` to get or create the `AuthStore` for.
|
|
12
|
+
* @returns The `AuthStore` associated with the given `SanityInstance`.
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export const getInternalAuthStore = (instance: SanityInstance): InternalAuthStore => {
|
|
17
|
+
return getOrCreateResource(instance, 'authStore', () => {
|
|
18
|
+
return createInternalAuthStore(instance, instance.config?.auth)
|
|
19
|
+
})
|
|
20
|
+
}
|