@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/dist/index.js
ADDED
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
import { createClient } from "@sanity/client";
|
|
2
|
+
import { filter, map, distinctUntilChanged, fromEvent, EMPTY, Observable, startWith, switchMap, tap, pairwise } from "rxjs";
|
|
3
|
+
import { devtools } from "zustand/middleware";
|
|
4
|
+
import { createStore as createStore$1 } from "zustand/vanilla";
|
|
5
|
+
import { isEqual } from "lodash-es";
|
|
6
|
+
function getSdkIdentity({
|
|
7
|
+
projectId,
|
|
8
|
+
dataset
|
|
9
|
+
}) {
|
|
10
|
+
const id = generateId();
|
|
11
|
+
return Object.freeze({
|
|
12
|
+
id,
|
|
13
|
+
projectId,
|
|
14
|
+
dataset
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function generateId() {
|
|
18
|
+
return Array.from(
|
|
19
|
+
{ length: 8 },
|
|
20
|
+
() => Math.floor(Math.random() * 16).toString(16).padStart(2, "0")
|
|
21
|
+
).join("");
|
|
22
|
+
}
|
|
23
|
+
function createSanityInstance({
|
|
24
|
+
projectId = "",
|
|
25
|
+
dataset = "",
|
|
26
|
+
...config
|
|
27
|
+
}) {
|
|
28
|
+
return {
|
|
29
|
+
identity: getSdkIdentity({ projectId, dataset }),
|
|
30
|
+
config
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const resourceStorage = /* @__PURE__ */ new WeakMap();
|
|
34
|
+
function getResource(instance, key) {
|
|
35
|
+
return resourceStorage.get(instance.identity)?.get(key);
|
|
36
|
+
}
|
|
37
|
+
function setResource(instance, key, value) {
|
|
38
|
+
let instanceMap = resourceStorage.get(instance.identity);
|
|
39
|
+
instanceMap || (instanceMap = /* @__PURE__ */ new Map(), resourceStorage.set(instance.identity, instanceMap)), instanceMap.set(key, value);
|
|
40
|
+
}
|
|
41
|
+
function getOrCreateResource(instance, key, creator) {
|
|
42
|
+
const cached = getResource(instance, key);
|
|
43
|
+
if (cached)
|
|
44
|
+
return cached;
|
|
45
|
+
const resource = creator();
|
|
46
|
+
return setResource(instance, key, resource), resource;
|
|
47
|
+
}
|
|
48
|
+
const AUTH_CODE_PARAM = "sid", DEFAULT_BASE = "http://localhost", DEFAULT_API_VERSION$1 = "2021-06-07", REQUEST_TAG_PREFIX = "sdk.auth";
|
|
49
|
+
function getDefaultLocation() {
|
|
50
|
+
try {
|
|
51
|
+
return typeof location > "u" ? DEFAULT_BASE : typeof location.href == "string" ? location.href : DEFAULT_BASE;
|
|
52
|
+
} catch {
|
|
53
|
+
return DEFAULT_BASE;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function getDefaultStorage() {
|
|
57
|
+
try {
|
|
58
|
+
return typeof localStorage < "u" && typeof localStorage.getItem == "function" ? localStorage : void 0;
|
|
59
|
+
} catch {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function getStorageEvents() {
|
|
64
|
+
return typeof window < "u" && typeof window.addEventListener == "function" ? fromEvent(window, "storage") : EMPTY;
|
|
65
|
+
}
|
|
66
|
+
function createInternalAuthStore(instance, config = {}) {
|
|
67
|
+
const {
|
|
68
|
+
clientFactory = createClient,
|
|
69
|
+
initialLocationHref = getDefaultLocation(),
|
|
70
|
+
storageArea = getDefaultStorage(),
|
|
71
|
+
authScope = "project",
|
|
72
|
+
apiHost,
|
|
73
|
+
callbackUrl,
|
|
74
|
+
providers: customProviders,
|
|
75
|
+
token: providedToken
|
|
76
|
+
} = config, { projectId, dataset } = instance.identity, storageKey = `__sanity_auth_token_${projectId}_${dataset}`;
|
|
77
|
+
function getTokenFromStorage() {
|
|
78
|
+
if (!storageArea) return null;
|
|
79
|
+
const item = storageArea.getItem(storageKey);
|
|
80
|
+
if (item === null) return null;
|
|
81
|
+
try {
|
|
82
|
+
const parsed = JSON.parse(item);
|
|
83
|
+
if (typeof parsed != "object" || parsed === null || !("token" in parsed) || typeof parsed.token != "string")
|
|
84
|
+
throw new Error("Invalid stored auth data structure");
|
|
85
|
+
return parsed.token;
|
|
86
|
+
} catch {
|
|
87
|
+
return storageArea.removeItem(storageKey), null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function getAuthCode(locationHref) {
|
|
91
|
+
const loc = new URL(locationHref, DEFAULT_BASE), callbackLocation = callbackUrl ? new URL(callbackUrl, DEFAULT_BASE) : void 0, callbackLocationMatches = callbackLocation ? loc.pathname.toLowerCase().startsWith(callbackLocation.pathname.toLowerCase()) : !0, authCode = new URLSearchParams(loc.hash.slice(1)).get(AUTH_CODE_PARAM);
|
|
92
|
+
return authCode && callbackLocationMatches ? authCode : null;
|
|
93
|
+
}
|
|
94
|
+
function getInitialState() {
|
|
95
|
+
if (providedToken) return { type: "logged-in", token: providedToken, currentUser: null };
|
|
96
|
+
if (getAuthCode(initialLocationHref)) return { type: "logging-in", isExchangingToken: !1 };
|
|
97
|
+
const token = getTokenFromStorage();
|
|
98
|
+
return token ? { type: "logged-in", token, currentUser: null } : { type: "logged-out", isDestroyingSession: !1 };
|
|
99
|
+
}
|
|
100
|
+
async function handleCallback(locationHref = getDefaultLocation()) {
|
|
101
|
+
if (providedToken) return !1;
|
|
102
|
+
const { authState } = store.getState();
|
|
103
|
+
if (authState.type === "logging-in" && authState.isExchangingToken) return !1;
|
|
104
|
+
const authCode = getAuthCode(locationHref);
|
|
105
|
+
if (!authCode) return !1;
|
|
106
|
+
store.setState(
|
|
107
|
+
{ authState: { type: "logging-in", isExchangingToken: !0 } },
|
|
108
|
+
void 0,
|
|
109
|
+
"exchangeSessionForToken"
|
|
110
|
+
);
|
|
111
|
+
try {
|
|
112
|
+
const client = clientFactory({
|
|
113
|
+
projectId,
|
|
114
|
+
dataset,
|
|
115
|
+
apiVersion: DEFAULT_API_VERSION$1,
|
|
116
|
+
requestTagPrefix: REQUEST_TAG_PREFIX,
|
|
117
|
+
useProjectHostname: authScope === "project",
|
|
118
|
+
...apiHost && { apiHost }
|
|
119
|
+
}), { token } = await client.request({
|
|
120
|
+
method: "GET",
|
|
121
|
+
uri: "/auth/fetch",
|
|
122
|
+
query: { sid: authCode },
|
|
123
|
+
tag: "fetch-token"
|
|
124
|
+
});
|
|
125
|
+
storageArea?.setItem(storageKey, JSON.stringify({ token })), store.setState({ authState: { type: "logged-in", token, currentUser: null } });
|
|
126
|
+
const loc = new URL(locationHref);
|
|
127
|
+
return loc.hash = "", loc.toString();
|
|
128
|
+
} catch (error) {
|
|
129
|
+
return store.setState({ authState: { type: "error", error } }, void 0, "exchangeSessionForTokenError"), !1;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function fetchLoginUrls() {
|
|
133
|
+
const client = clientFactory({
|
|
134
|
+
projectId,
|
|
135
|
+
dataset,
|
|
136
|
+
apiVersion: DEFAULT_API_VERSION$1,
|
|
137
|
+
requestTagPrefix: REQUEST_TAG_PREFIX,
|
|
138
|
+
useProjectHostname: authScope === "project",
|
|
139
|
+
...apiHost && { apiHost }
|
|
140
|
+
}), { providers: defaultProviders } = await client.request({
|
|
141
|
+
uri: "/auth/providers",
|
|
142
|
+
tag: "fetch-providers"
|
|
143
|
+
});
|
|
144
|
+
let providers;
|
|
145
|
+
if (typeof customProviders == "function")
|
|
146
|
+
providers = await customProviders(defaultProviders);
|
|
147
|
+
else if (!customProviders?.length)
|
|
148
|
+
providers = defaultProviders;
|
|
149
|
+
else {
|
|
150
|
+
const customProviderUrls = new Set(customProviders.map((p) => p.url));
|
|
151
|
+
providers = defaultProviders.filter((official) => !customProviderUrls.has(official.url)).concat(customProviders);
|
|
152
|
+
}
|
|
153
|
+
const configuredProviders = providers.map((provider) => {
|
|
154
|
+
const url = new URL(provider.url), origin = new URL(
|
|
155
|
+
callbackUrl ? new URL(callbackUrl, new URL(getDefaultLocation()).origin).toString() : getDefaultLocation()
|
|
156
|
+
), hashParams = new URLSearchParams(origin.hash.slice(1));
|
|
157
|
+
return hashParams.delete("sid"), origin.hash = hashParams.toString(), origin.searchParams.delete("error"), url.searchParams.set("origin", origin.toString()), url.searchParams.set("withSid", "true"), authScope === "project" && url.searchParams.set("projectId", projectId), { ...provider, url: url.toString() };
|
|
158
|
+
});
|
|
159
|
+
return store.setState({ providers: configuredProviders }, void 0, "fetchedLoginUrls"), configuredProviders;
|
|
160
|
+
}
|
|
161
|
+
const store = createStore$1()(
|
|
162
|
+
devtools(
|
|
163
|
+
(set, get) => ({
|
|
164
|
+
authState: getInitialState(),
|
|
165
|
+
setAuthState: (authState) => {
|
|
166
|
+
set({ authState }, void 0, "setAuthState");
|
|
167
|
+
},
|
|
168
|
+
providers: void 0,
|
|
169
|
+
setProviders: (providers) => {
|
|
170
|
+
set({ providers }, void 0, "setProviders");
|
|
171
|
+
},
|
|
172
|
+
logout: async () => {
|
|
173
|
+
if (providedToken) return;
|
|
174
|
+
const { authState } = store.getState();
|
|
175
|
+
if (authState.type === "logged-out" && authState.isDestroyingSession) return;
|
|
176
|
+
const token = authState.type === "logged-in" && authState.token;
|
|
177
|
+
try {
|
|
178
|
+
token && (set(
|
|
179
|
+
{ authState: { type: "logged-out", isDestroyingSession: !0 } },
|
|
180
|
+
void 0,
|
|
181
|
+
"loggingOut"
|
|
182
|
+
), await clientFactory({
|
|
183
|
+
token,
|
|
184
|
+
projectId,
|
|
185
|
+
dataset,
|
|
186
|
+
requestTagPrefix: REQUEST_TAG_PREFIX,
|
|
187
|
+
apiVersion: DEFAULT_API_VERSION$1,
|
|
188
|
+
useProjectHostname: authScope === "project",
|
|
189
|
+
...apiHost && { apiHost }
|
|
190
|
+
}).request({ uri: "/auth/logout", method: "POST" }));
|
|
191
|
+
} finally {
|
|
192
|
+
set(
|
|
193
|
+
{ authState: { type: "logged-out", isDestroyingSession: !1 } },
|
|
194
|
+
void 0,
|
|
195
|
+
"logoutSuccess"
|
|
196
|
+
), storageArea?.removeItem(storageKey);
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
getCurrent: () => get().authState,
|
|
200
|
+
handleCallback: (locationHref = getDefaultLocation()) => handleCallback(locationHref),
|
|
201
|
+
getLoginUrls: () => get().providers ?? fetchLoginUrls(),
|
|
202
|
+
dispose: () => {
|
|
203
|
+
storageSubscription.unsubscribe();
|
|
204
|
+
}
|
|
205
|
+
}),
|
|
206
|
+
{
|
|
207
|
+
name: "SanityInternalAuthStore",
|
|
208
|
+
enabled: !0
|
|
209
|
+
// Should be process.env.NODE_ENV === 'development',
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
), storageSubscription = getStorageEvents().pipe(
|
|
213
|
+
filter(
|
|
214
|
+
(e) => e.storageArea === storageArea && e.key === storageKey
|
|
215
|
+
),
|
|
216
|
+
map(() => getTokenFromStorage()),
|
|
217
|
+
distinctUntilChanged()
|
|
218
|
+
).subscribe(
|
|
219
|
+
(token) => store.getState().setAuthState(
|
|
220
|
+
token ? { type: "logged-in", token, currentUser: null } : { type: "logged-out", isDestroyingSession: !1 }
|
|
221
|
+
)
|
|
222
|
+
), fetchCurrentUser = (authState) => {
|
|
223
|
+
clientFactory({
|
|
224
|
+
token: authState.token,
|
|
225
|
+
projectId,
|
|
226
|
+
dataset,
|
|
227
|
+
requestTagPrefix: REQUEST_TAG_PREFIX,
|
|
228
|
+
apiVersion: DEFAULT_API_VERSION$1,
|
|
229
|
+
useProjectHostname: authScope === "project",
|
|
230
|
+
...apiHost && { apiHost }
|
|
231
|
+
}).request({ uri: "/users/me", method: "GET" }).then(
|
|
232
|
+
(currentUser) => store.getState().setAuthState({
|
|
233
|
+
...authState,
|
|
234
|
+
currentUser
|
|
235
|
+
})
|
|
236
|
+
).catch((error) => store.getState().setAuthState({
|
|
237
|
+
...authState,
|
|
238
|
+
type: "error",
|
|
239
|
+
error
|
|
240
|
+
}));
|
|
241
|
+
};
|
|
242
|
+
return store.getState().authState.type === "logged-in" && !store.getState().authState.currentUser?.id && fetchCurrentUser(store.getState().authState), store.subscribe((state) => {
|
|
243
|
+
state.authState.type === "logged-in" && !state.authState.currentUser && fetchCurrentUser(state.authState);
|
|
244
|
+
}), store;
|
|
245
|
+
}
|
|
246
|
+
const getInternalAuthStore = (instance) => getOrCreateResource(instance, "authStore", () => createInternalAuthStore(instance, instance.config?.auth));
|
|
247
|
+
function createStore(initialState, actions, { name, instance }) {
|
|
248
|
+
const uniqueName = `${name}-${instance.identity.id}`, context = { store: createStore$1()(devtools(() => ({ ...initialState }), { name: uniqueName })), instance };
|
|
249
|
+
return createCurriedActions(actions, context);
|
|
250
|
+
}
|
|
251
|
+
function createCurriedActions(actions, store) {
|
|
252
|
+
const curried = {};
|
|
253
|
+
return Object.entries(actions).reduce((acc, [key, action]) => {
|
|
254
|
+
const curriedAction = (...args) => action(store, ...args);
|
|
255
|
+
return { ...acc, [key]: curriedAction };
|
|
256
|
+
}, curried);
|
|
257
|
+
}
|
|
258
|
+
const getOrCreateClient = ({ store }, options = {}) => {
|
|
259
|
+
const state = store.getState(), { apiVersion } = options;
|
|
260
|
+
if (!apiVersion)
|
|
261
|
+
throw new Error("Missing required `apiVersion` option");
|
|
262
|
+
const cached = state.clients.get(apiVersion);
|
|
263
|
+
if (cached)
|
|
264
|
+
return cached;
|
|
265
|
+
const client = state.defaultClient.withConfig(options);
|
|
266
|
+
return store.setState((prevState) => {
|
|
267
|
+
const newMap = new Map(prevState.clients);
|
|
268
|
+
return newMap.set(apiVersion, client), {
|
|
269
|
+
clients: newMap
|
|
270
|
+
};
|
|
271
|
+
}), client;
|
|
272
|
+
}, getClientEvents = (context, options = {}) => {
|
|
273
|
+
const { store } = context, initialClient = getOrCreateClient(context, options), client$ = new Observable(
|
|
274
|
+
(subscriber) => store.subscribe(() => subscriber.next())
|
|
275
|
+
).pipe(
|
|
276
|
+
map(() => getOrCreateClient(context, options)),
|
|
277
|
+
startWith(initialClient),
|
|
278
|
+
distinctUntilChanged((prev, curr) => prev.config().token === curr.config().token)
|
|
279
|
+
);
|
|
280
|
+
return {
|
|
281
|
+
subscribe: client$.subscribe.bind(client$)
|
|
282
|
+
};
|
|
283
|
+
}, receiveToken = ({ store }, token) => {
|
|
284
|
+
const newDefaultClient = store.getState().defaultClient.withConfig({
|
|
285
|
+
token
|
|
286
|
+
});
|
|
287
|
+
store.setState((prevState) => {
|
|
288
|
+
const updatedClients = new Map(
|
|
289
|
+
Array.from(prevState.clients.entries()).map(([version, client]) => [
|
|
290
|
+
version,
|
|
291
|
+
client.withConfig({ token })
|
|
292
|
+
])
|
|
293
|
+
);
|
|
294
|
+
return {
|
|
295
|
+
defaultClient: newDefaultClient,
|
|
296
|
+
clients: updatedClients
|
|
297
|
+
};
|
|
298
|
+
});
|
|
299
|
+
}, DEFAULT_API_VERSION = "v2024-11-12", createInitialState = (defaultClient) => {
|
|
300
|
+
const clients = /* @__PURE__ */ new Map();
|
|
301
|
+
return clients.set(defaultClient.config().apiVersion, defaultClient), { defaultClient, clients };
|
|
302
|
+
}, clientStoreActions = {
|
|
303
|
+
getOrCreateClient,
|
|
304
|
+
receiveToken,
|
|
305
|
+
getClientEvents
|
|
306
|
+
}, createClientStore = (instance, defaultClient) => {
|
|
307
|
+
const internalAuthStore = getInternalAuthStore(instance), store = createStore(createInitialState(defaultClient), clientStoreActions, {
|
|
308
|
+
name: "clientStore",
|
|
309
|
+
instance
|
|
310
|
+
});
|
|
311
|
+
return internalAuthStore.subscribe((state, prevState) => {
|
|
312
|
+
state.authState.type === "logged-in" && prevState.authState.type !== "logged-in" && store.receiveToken(state.authState.token), prevState.authState.type === "logged-in" && state.authState.type !== "logged-in" && store.receiveToken(void 0);
|
|
313
|
+
}), store;
|
|
314
|
+
}, getClientStore = (instance) => getOrCreateResource(instance, "clientStore", () => {
|
|
315
|
+
const { config, identity } = instance, client = createClient({
|
|
316
|
+
projectId: identity.projectId,
|
|
317
|
+
dataset: identity.dataset,
|
|
318
|
+
token: config?.auth?.token,
|
|
319
|
+
useCdn: !1,
|
|
320
|
+
apiVersion: DEFAULT_API_VERSION
|
|
321
|
+
});
|
|
322
|
+
return createClientStore(instance, client);
|
|
323
|
+
}), getClient = (options, instance) => getClientStore(instance).getOrCreateClient(options), getSubscribableClient = (options, instance) => getClientStore(instance).getClientEvents(options), PAGE_SIZE = 50, API_VERSION = "vX";
|
|
324
|
+
function createDocumentListStore(instance) {
|
|
325
|
+
const clientStore = getClientStore(instance), clientStream$ = new Observable(
|
|
326
|
+
clientStore.getClientEvents({ apiVersion: API_VERSION }).subscribe
|
|
327
|
+
), initialState = {
|
|
328
|
+
syncTags: /* @__PURE__ */ new Set(),
|
|
329
|
+
isPending: !1,
|
|
330
|
+
result: null,
|
|
331
|
+
limit: PAGE_SIZE
|
|
332
|
+
}, store = createStore$1()(
|
|
333
|
+
devtools((..._unusedArgs) => initialState, {
|
|
334
|
+
name: "SanityDocumentListStore",
|
|
335
|
+
enabled: !0
|
|
336
|
+
// Should be process.env.NODE_ENV === 'development'
|
|
337
|
+
})
|
|
338
|
+
), liveSubscription = clientStream$.pipe(
|
|
339
|
+
switchMap((client) => client.live.events({ includeDrafts: !0, tag: "sdk.live-listener" }))
|
|
340
|
+
).subscribe({
|
|
341
|
+
next: (event) => {
|
|
342
|
+
const { syncTags } = store.getState();
|
|
343
|
+
event.type === "message" && event.tags.some((tag) => syncTags.has(tag)) && store.setState(
|
|
344
|
+
{ lastLiveEventId: event.id },
|
|
345
|
+
!1,
|
|
346
|
+
"UPDATE_EVENT_ID_FROM_LIVE_CONTENT_API"
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}), resultSubscription = new Observable(
|
|
350
|
+
(observer) => store.subscribe((state) => observer.next(state))
|
|
351
|
+
).pipe(
|
|
352
|
+
distinctUntilChanged((prev, current) => !(prev.filter !== current.filter || prev.lastLiveEventId !== current.lastLiveEventId || !isEqual(prev.sort, current.sort) || prev.limit !== current.limit)),
|
|
353
|
+
tap(() => store.setState({ isPending: !0 }, !1, { type: "START_FETCH" })),
|
|
354
|
+
switchMap((state) => {
|
|
355
|
+
const filter2 = state.filter ? `[${state.filter}]` : "", order = state.sort ? `| order(${state.sort.map(
|
|
356
|
+
(ordering) => [ordering.field, ordering.direction.toLowerCase()].map((str) => str.trim()).filter(Boolean).join(" ")
|
|
357
|
+
).join(",")})` : "";
|
|
358
|
+
return clientStream$.pipe(
|
|
359
|
+
switchMap(
|
|
360
|
+
(client) => client.observable.fetch(
|
|
361
|
+
`*${filter2}${order}[0..$__limit]{_id, _type}`,
|
|
362
|
+
{ __limit: state.limit },
|
|
363
|
+
{
|
|
364
|
+
filterResponse: !1,
|
|
365
|
+
returnQuery: !1,
|
|
366
|
+
lastLiveEventId: state.lastLiveEventId,
|
|
367
|
+
tag: "sdk.document-list"
|
|
368
|
+
// // TODO: this should use the `previewDrafts` perspective for
|
|
369
|
+
// // removing duplicates in the result set but the live content API
|
|
370
|
+
// // does not currently return the correct sync tags. CLDX has
|
|
371
|
+
// // planned to add perspective support to the live content API
|
|
372
|
+
// // in december of 2024
|
|
373
|
+
// perspective: 'previewDrafts'
|
|
374
|
+
}
|
|
375
|
+
)
|
|
376
|
+
)
|
|
377
|
+
);
|
|
378
|
+
})
|
|
379
|
+
).subscribe({
|
|
380
|
+
next: ({ syncTags, result }) => {
|
|
381
|
+
store.setState(
|
|
382
|
+
{
|
|
383
|
+
syncTags: new Set(syncTags),
|
|
384
|
+
result,
|
|
385
|
+
isPending: !1
|
|
386
|
+
},
|
|
387
|
+
!1,
|
|
388
|
+
{ type: "UPDATE_FROM_FETCH" }
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
function setOptions({ filter: filter2, sort }) {
|
|
393
|
+
store.setState(
|
|
394
|
+
{
|
|
395
|
+
// spreads properties only if they exist, preserving other state
|
|
396
|
+
// properties set in the zustand store already
|
|
397
|
+
...filter2 && { filter: filter2 },
|
|
398
|
+
...sort && { sort }
|
|
399
|
+
},
|
|
400
|
+
!1,
|
|
401
|
+
{ type: "SET_OPTIONS" }
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
function loadMore() {
|
|
405
|
+
store.setState((prev) => ({ limit: prev.limit + PAGE_SIZE }), void 0, { type: "LOAD_MORE" });
|
|
406
|
+
}
|
|
407
|
+
function getCurrent() {
|
|
408
|
+
const { isPending, result, filter: filter2, sort } = store.getState();
|
|
409
|
+
return { isPending, result, filter: filter2, sort };
|
|
410
|
+
}
|
|
411
|
+
const state$ = new Observable((observer) => {
|
|
412
|
+
function emitCurrent() {
|
|
413
|
+
const { isPending, result, filter: filter2, sort } = store.getState();
|
|
414
|
+
observer.next({
|
|
415
|
+
isPending,
|
|
416
|
+
result,
|
|
417
|
+
filter: filter2,
|
|
418
|
+
sort
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
return emitCurrent(), store.subscribe(emitCurrent);
|
|
422
|
+
}).pipe(
|
|
423
|
+
distinctUntilChanged((prev, curr) => !(!isEqual(prev.sort, curr.sort) || prev.result !== curr.result || prev.filter !== curr.filter || prev.isPending !== curr.isPending)),
|
|
424
|
+
startWith(null),
|
|
425
|
+
pairwise(),
|
|
426
|
+
map((arg) => {
|
|
427
|
+
const [prev, curr] = arg;
|
|
428
|
+
if (!prev?.result || !curr?.result) return curr;
|
|
429
|
+
const prevMap = prev.result.reduce((acc, handle) => (acc.set(handle._id, handle), acc), /* @__PURE__ */ new Map());
|
|
430
|
+
return {
|
|
431
|
+
...curr,
|
|
432
|
+
result: curr.result.map((i) => prevMap.get(i._id) ?? i)
|
|
433
|
+
};
|
|
434
|
+
})
|
|
435
|
+
), subscribe = state$.subscribe.bind(state$);
|
|
436
|
+
function dispose() {
|
|
437
|
+
liveSubscription.unsubscribe(), resultSubscription.unsubscribe();
|
|
438
|
+
}
|
|
439
|
+
return { setOptions, getCurrent, loadMore, subscribe, dispose };
|
|
440
|
+
}
|
|
441
|
+
const getAuthStore = (instance) => {
|
|
442
|
+
const internalAuthStore = getInternalAuthStore(instance);
|
|
443
|
+
return {
|
|
444
|
+
authState: {
|
|
445
|
+
getState: () => internalAuthStore.getState().authState,
|
|
446
|
+
getInitialState: () => internalAuthStore.getInitialState().authState,
|
|
447
|
+
subscribe: (listener) => internalAuthStore.subscribe((current, prev) => {
|
|
448
|
+
listener(current.authState, prev.authState);
|
|
449
|
+
})
|
|
450
|
+
},
|
|
451
|
+
tokenState: {
|
|
452
|
+
getState: () => {
|
|
453
|
+
const state = internalAuthStore.getState();
|
|
454
|
+
return state.authState.type !== "logged-in" ? null : state.authState.token;
|
|
455
|
+
},
|
|
456
|
+
getInitialState: () => {
|
|
457
|
+
const state = internalAuthStore.getInitialState();
|
|
458
|
+
return state.authState.type !== "logged-in" ? null : state.authState.token;
|
|
459
|
+
},
|
|
460
|
+
subscribe: (listener) => internalAuthStore.subscribe((state, prevState) => {
|
|
461
|
+
const token = state.authState.type === "logged-in" ? state.authState.token : null, prevToken = prevState.authState.type === "logged-in" ? prevState.authState.token : null;
|
|
462
|
+
listener(token, prevToken);
|
|
463
|
+
})
|
|
464
|
+
},
|
|
465
|
+
currentUserState: {
|
|
466
|
+
getState: () => {
|
|
467
|
+
const state = internalAuthStore.getState();
|
|
468
|
+
return state.authState.type !== "logged-in" ? null : state.authState.currentUser;
|
|
469
|
+
},
|
|
470
|
+
getInitialState: () => {
|
|
471
|
+
const state = internalAuthStore.getInitialState();
|
|
472
|
+
return state.authState.type !== "logged-in" ? null : state.authState.currentUser;
|
|
473
|
+
},
|
|
474
|
+
subscribe: (listener) => internalAuthStore.subscribe((state, prevState) => {
|
|
475
|
+
const user = state.authState.type === "logged-in" ? state.authState.currentUser : null, prevUser = prevState.authState.type === "logged-in" ? prevState.authState.currentUser : null;
|
|
476
|
+
listener(user, prevUser);
|
|
477
|
+
})
|
|
478
|
+
},
|
|
479
|
+
handleCallback: internalAuthStore.getState().handleCallback,
|
|
480
|
+
logout: internalAuthStore.getState().logout,
|
|
481
|
+
dispose: internalAuthStore.getState().dispose,
|
|
482
|
+
getLoginUrls: internalAuthStore.getState().getLoginUrls
|
|
483
|
+
};
|
|
484
|
+
};
|
|
485
|
+
export {
|
|
486
|
+
createDocumentListStore,
|
|
487
|
+
createSanityInstance,
|
|
488
|
+
getAuthStore,
|
|
489
|
+
getClient,
|
|
490
|
+
getSubscribableClient
|
|
491
|
+
};
|
|
492
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/instance/identity.ts","../src/instance/sanityInstance.ts","../src/auth/internalAuthStore.ts","../src/auth/getInternalAuthStore.ts","../src/store/createStore.ts","../src/client/store/actions/getOrCreateClient.ts","../src/client/store/actions/getClientEvents.ts","../src/client/store/actions/receiveToken.ts","../src/client/store/clientStore.ts","../src/client/getClient.ts","../src/client/getSubscribableClient.ts","../src/documentList/documentListStore.ts","../src/auth/authStore.ts"],"sourcesContent":["import type {SdkIdentity} from './types'\n\n/**\n * 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\n * @public\n */\nexport function getSdkIdentity({\n projectId,\n dataset,\n}: {\n projectId: string\n dataset: string\n}): SdkIdentity {\n const id = generateId()\n return Object.freeze({\n id,\n projectId,\n dataset,\n })\n}\n\nfunction generateId() {\n return Array.from({length: 8}, () =>\n Math.floor(Math.random() * 16)\n .toString(16)\n .padStart(2, '0'),\n ).join('')\n}\n","import type {AuthConfig} from '../auth/internalAuthStore'\nimport {getSdkIdentity} from './identity'\nimport type {SanityInstance, SdkIdentity} from './types'\n\n/**\n * @public\n */\nexport interface SanityConfig {\n projectId: string\n dataset: string\n auth?: AuthConfig\n}\n\n/**\n * Returns a new instance of dependencies required for SanitySDK.\n *\n * @public\n *\n * @param config - The configuration for this instance\n *\n * @returns A new \"instance\" of a Sanity SDK, used to bind resources/configuration to it\n */\nexport function createSanityInstance({\n projectId = '',\n dataset = '',\n ...config\n}: SanityConfig): SanityInstance {\n return {\n identity: getSdkIdentity({projectId, dataset}),\n config,\n }\n}\n\nconst resourceStorage = new WeakMap<SdkIdentity, Map<string, unknown>>()\n\nfunction getResource(instance: SanityInstance, key: string) {\n const instanceMap = resourceStorage.get(instance.identity)\n return instanceMap?.get(key)\n}\n\nfunction setResource(instance: SanityInstance, key: string, value: unknown) {\n let instanceMap = resourceStorage.get(instance.identity)\n if (!instanceMap) {\n instanceMap = new Map()\n resourceStorage.set(instance.identity, instanceMap)\n }\n instanceMap.set(key, value)\n}\n\n/**\n * This is an internal function that retrieves or creates a Zustand store resource.\n * @internal\n */\nexport function getOrCreateResource<T>(instance: SanityInstance, key: string, creator: () => T): T {\n const cached = getResource(instance, key)\n\n if (cached) {\n return cached as T\n }\n\n const resource = creator()\n setResource(instance, key, resource)\n return resource\n}\n","import {type ClientConfig, createClient, type SanityClient} from '@sanity/client'\nimport type {CurrentUser} from '@sanity/types'\nimport {distinctUntilChanged, EMPTY, filter, fromEvent, map, Observable} from 'rxjs'\nimport {devtools} from 'zustand/middleware'\nimport {createStore, type StoreApi} from 'zustand/vanilla'\n\nimport type {SanityInstance} from '../instance/types'\n\nconst AUTH_CODE_PARAM = 'sid'\nconst DEFAULT_BASE = 'http://localhost'\nconst DEFAULT_API_VERSION = '2021-06-07'\nconst REQUEST_TAG_PREFIX = 'sdk.auth'\n\n/**\n * Represents the various states the authentication store can be in.\n *\n * @public\n */\nexport type AuthState =\n | {type: 'logged-in'; token: string; currentUser: CurrentUser | null}\n | {type: 'logging-in'; isExchangingToken: boolean}\n | {type: 'error'; error: unknown}\n | {type: 'logged-out'; isDestroyingSession: boolean}\n\n/**\n * Configuration for an authentication provider\n * @public\n */\nexport interface AuthProvider {\n /**\n * Unique identifier for the auth provider (e.g., 'google', 'github')\n */\n name: string\n\n /**\n * Display name for the auth provider in the UI\n */\n title: string\n\n /**\n * Complete authentication URL including callback and token parameters\n */\n url: string\n\n /**\n * Optional URL for direct sign-up flow\n */\n signUpUrl?: string\n}\n\n/**\n * Configuration options for creating an auth store.\n *\n * @public\n */\nexport interface AuthConfig {\n /**\n * The initial location href to use when handling auth callbacks.\n * Defaults to the current window location if available.\n */\n initialLocationHref?: string\n\n /**\n * Factory function to create a SanityClient instance.\n * Defaults to the standard Sanity client factory if not provided.\n */\n clientFactory?: (config: ClientConfig) => SanityClient\n\n /**\n * Custom authentication providers to use instead of or in addition to the default ones.\n * Can be an array of providers or a function that takes the default providers and returns\n * a modified array or a Promise resolving to one.\n */\n providers?: AuthProvider[] | ((prev: AuthProvider[]) => AuthProvider[] | Promise<AuthProvider[]>)\n\n /**\n * The API hostname for requests. Usually leave this undefined, but it can be set\n * if using a custom domain or CNAME for the API endpoint.\n */\n apiHost?: string\n\n /**\n * Storage implementation to persist authentication state.\n * Defaults to `localStorage` if available.\n */\n storageArea?: Storage\n\n /**\n * A callback URL for your application.\n * If none is provided, the auth API will redirect back to the current location (`location.href`).\n * When handling callbacks, this URL's pathname is checked to ensure it matches the callback.\n */\n callbackUrl?: string\n\n /**\n * A static authentication token to use instead of handling the OAuth flow.\n * When provided, the auth store will remain in a logged-in state with this token,\n * ignoring any storage or callback handling.\n */\n token?: string\n\n /**\n * The authentication scope.\n * If set to 'project', requests are scoped to the project-level.\n * If set to 'org', requests are scoped to the organization-level.\n * Defaults to 'project'.\n */\n authScope?: 'project' | 'org'\n}\n\n/**\n * Represents an authentication store that can handle login/logout flows, fetch providers,\n * handle auth callbacks, subscribe to state changes, and more.\n *\n * @internal\n */\nexport interface InternalAuthState {\n authState: AuthState\n setAuthState: (authState: AuthState) => void\n providers: AuthProvider[] | undefined\n setProviders: (providers: AuthProvider[] | undefined) => void\n /**\n * Handles an OAuth callback by reading the `sid` parameter from the given `locationHref`.\n * If a token is successfully fetched, the state transitions to `logged-in`.\n *\n * @param locationHref - The location to parse for callback parameters. Defaults to current location.\n * @returns A promise resolving to the updated URL (with callback params removed) or `false` if no callback was handled.\n */\n handleCallback(locationHref?: string): Promise<string | false>\n\n /**\n * Fetches authentication providers (OAuth endpoints) for logging in.\n * Can optionally be customized with `providers` in {@link AuthConfig}.\n * Results are cached after the first call. Subsequent calls return synchronously from cache.\n *\n * @returns Authentication providers as {@link AuthProvider} objects with pre-configured login URLs.\n */\n getLoginUrls(): AuthProvider[] | Promise<AuthProvider[]>\n\n /**\n * Logs out the current user. If a static token was provided, logout is a no-op.\n * Otherwise, sends a request to invalidate the current token and updates state to `logged-out`.\n */\n logout(): Promise<void>\n\n /**\n * Disposes of any internal resources and subscriptions used by the store.\n * After calling dispose, the store should no longer be used.\n */\n dispose(): void\n}\n\n/**\n * Internal auth store type.\n * @internal\n */\nexport type InternalAuthStore = StoreApi<InternalAuthState>\n\n/**\n * Returns the default location to use.\n * Tries accessing `location.href`, falls back to a default base if not available or on error.\n */\nfunction getDefaultLocation() {\n try {\n if (typeof location === 'undefined') return DEFAULT_BASE\n if (typeof location.href === 'string') return location.href\n return DEFAULT_BASE\n } catch {\n return DEFAULT_BASE\n }\n}\n\n/**\n * Returns a default storage instance (localStorage) if available.\n * If not available or an error occurs, returns undefined.\n */\nfunction getDefaultStorage() {\n try {\n if (typeof localStorage !== 'undefined' && typeof localStorage.getItem === 'function') {\n return localStorage\n }\n return undefined\n } catch {\n return undefined\n }\n}\n\n/**\n * Creates an observable stream of storage events. If not in a browser environment,\n * returns an EMPTY observable.\n */\nfunction getStorageEvents(): Observable<StorageEvent> {\n const isBrowser = typeof window !== 'undefined' && typeof window.addEventListener === 'function'\n\n if (!isBrowser) {\n return EMPTY\n }\n\n return fromEvent<StorageEvent>(window, 'storage')\n}\n\n/**\n * Creates a new authentication store for managing OAuth flows, tokens, and related state.\n *\n * @param instance - The Sanity instance configuration.\n * @param config - The auth configuration options.\n * @returns An {@link InternalAuthStore} instance.\n *\n * @internal\n */\nexport function createInternalAuthStore(\n instance: SanityInstance,\n config: AuthConfig = {},\n): InternalAuthStore {\n const {\n clientFactory = createClient,\n initialLocationHref = getDefaultLocation(),\n storageArea = getDefaultStorage(),\n authScope = 'project',\n apiHost,\n callbackUrl,\n providers: customProviders,\n token: providedToken,\n } = config\n\n const {projectId, dataset} = instance.identity\n const storageKey = `__sanity_auth_token_${projectId}_${dataset}`\n\n /**\n * Attempts to retrieve a token from the configured storage.\n * If invalid or not present, returns null.\n */\n function getTokenFromStorage() {\n if (!storageArea) return null\n const item = storageArea.getItem(storageKey)\n if (item === null) return null\n\n try {\n const parsed: unknown = JSON.parse(item)\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n !('token' in parsed) ||\n typeof parsed.token !== 'string'\n ) {\n throw new Error('Invalid stored auth data structure')\n }\n return parsed.token\n } catch {\n storageArea.removeItem(storageKey)\n return null\n }\n }\n\n /**\n * Extracts the auth code (`sid`) from a location, if it matches the callback URL conditions.\n * Returns null if no valid code is found.\n */\n function getAuthCode(locationHref: string) {\n const loc = new URL(locationHref, DEFAULT_BASE)\n const callbackLocation = callbackUrl ? new URL(callbackUrl, DEFAULT_BASE) : undefined\n const callbackLocationMatches = callbackLocation\n ? loc.pathname.toLowerCase().startsWith(callbackLocation.pathname.toLowerCase())\n : true\n\n const authCode = new URLSearchParams(loc.hash.slice(1)).get(AUTH_CODE_PARAM)\n return authCode && callbackLocationMatches ? authCode : null\n }\n\n /**\n * Determines the initial auth state based on provided token, callback params, or stored token.\n */\n function getInitialState(): AuthState {\n if (providedToken) return {type: 'logged-in', token: providedToken, currentUser: null}\n if (getAuthCode(initialLocationHref)) return {type: 'logging-in', isExchangingToken: false}\n const token = getTokenFromStorage()\n if (token) return {type: 'logged-in', token, currentUser: null}\n return {type: 'logged-out', isDestroyingSession: false}\n }\n\n async function handleCallback(locationHref = getDefaultLocation()) {\n // If a token is provided, no need to handle callback\n if (providedToken) return false\n\n // Don't handle the callback if already in flight.\n const {authState} = store.getState()\n if (authState.type === 'logging-in' && authState.isExchangingToken) return false\n\n // If there is no matching `authCode` then we can't handle the callback\n const authCode = getAuthCode(locationHref)\n if (!authCode) return false\n\n // Otherwise, start the exchange\n store.setState(\n {authState: {type: 'logging-in', isExchangingToken: true}},\n undefined,\n 'exchangeSessionForToken',\n )\n\n try {\n const client = clientFactory({\n projectId,\n dataset,\n apiVersion: DEFAULT_API_VERSION,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n useProjectHostname: authScope === 'project',\n ...(apiHost && {apiHost}),\n })\n\n const {token} = await client.request<{token: string; label: string}>({\n method: 'GET',\n uri: '/auth/fetch',\n query: {sid: authCode},\n tag: 'fetch-token',\n })\n\n storageArea?.setItem(storageKey, JSON.stringify({token}))\n store.setState({authState: {type: 'logged-in', token, currentUser: null}})\n\n const loc = new URL(locationHref)\n loc.hash = ''\n return loc.toString()\n } catch (error) {\n store.setState({authState: {type: 'error', error}}, undefined, 'exchangeSessionForTokenError')\n return false\n }\n }\n\n /**\n * Fetches the providers from `/auth/providers`, adds params to each url, and\n * caches the result for synchronous usage.\n */\n async function fetchLoginUrls() {\n const client = clientFactory({\n projectId,\n dataset,\n apiVersion: DEFAULT_API_VERSION,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n useProjectHostname: authScope === 'project',\n ...(apiHost && {apiHost}),\n })\n\n const {providers: defaultProviders} = await client.request<{providers: AuthProvider[]}>({\n uri: '/auth/providers',\n tag: 'fetch-providers',\n })\n\n let providers: AuthProvider[]\n\n if (typeof customProviders === 'function') {\n providers = await customProviders(defaultProviders)\n } else if (!customProviders?.length) {\n providers = defaultProviders\n } else {\n const customProviderUrls = new Set(customProviders.map((p) => p.url))\n providers = defaultProviders\n .filter((official) => !customProviderUrls.has(official.url))\n .concat(customProviders)\n }\n\n const configuredProviders = providers.map((provider) => {\n const url = new URL(provider.url)\n const origin = new URL(\n callbackUrl\n ? new URL(callbackUrl, new URL(getDefaultLocation()).origin).toString()\n : getDefaultLocation(),\n )\n\n // `getDefaultLocation()` may be populated with an `sid` from a previous\n // failed login attempt and should be omitted from the next login URL\n const hashParams = new URLSearchParams(origin.hash.slice(1))\n hashParams.delete('sid')\n origin.hash = hashParams.toString()\n\n // similarly, the origin may be populated with an `error` query param if\n // the auth provider redirects back to the application. this should also\n // be omitted from the origin sent\n origin.searchParams.delete('error')\n\n url.searchParams.set('origin', origin.toString())\n url.searchParams.set('withSid', 'true')\n if (authScope === 'project') {\n url.searchParams.set('projectId', projectId)\n }\n\n return {...provider, url: url.toString()}\n })\n\n store.setState({providers: configuredProviders}, undefined, 'fetchedLoginUrls')\n\n return configuredProviders\n }\n\n const store = createStore<InternalAuthState>()(\n devtools(\n (set, get) => ({\n authState: getInitialState(),\n setAuthState: (authState: AuthState) => {\n set({authState}, undefined, 'setAuthState')\n },\n providers: undefined,\n setProviders: (providers: AuthProvider[] | undefined) => {\n set({providers}, undefined, 'setProviders')\n },\n logout: async () => {\n // If a token is statically provided, logout does nothing\n if (providedToken) return\n\n const {authState} = store.getState()\n\n // If we already have an inflight request, no-op\n if (authState.type === 'logged-out' && authState.isDestroyingSession) return\n const token = authState.type === 'logged-in' && authState.token\n\n try {\n if (token) {\n set(\n {authState: {type: 'logged-out', isDestroyingSession: true}},\n undefined,\n 'loggingOut',\n )\n\n const client = clientFactory({\n token,\n projectId,\n dataset,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n apiVersion: DEFAULT_API_VERSION,\n useProjectHostname: authScope === 'project',\n ...(apiHost && {apiHost}),\n })\n\n await client.request<void>({uri: '/auth/logout', method: 'POST'})\n }\n } finally {\n set(\n {authState: {type: 'logged-out', isDestroyingSession: false}},\n undefined,\n 'logoutSuccess',\n )\n storageArea?.removeItem(storageKey)\n }\n },\n getCurrent: () => get().authState,\n handleCallback: (locationHref = getDefaultLocation()) => handleCallback(locationHref),\n getLoginUrls: () => get().providers ?? fetchLoginUrls(),\n dispose: () => {\n storageSubscription.unsubscribe()\n },\n }),\n {\n name: 'SanityInternalAuthStore',\n enabled: true, // Should be process.env.NODE_ENV === 'development',\n },\n ),\n )\n\n const storageSubscription = getStorageEvents()\n .pipe(\n filter(\n (e): e is StorageEvent & {newValue: string} =>\n e.storageArea === storageArea && e.key === storageKey,\n ),\n map(() => getTokenFromStorage()),\n distinctUntilChanged(),\n )\n .subscribe((token) =>\n store\n .getState()\n .setAuthState(\n token\n ? {type: 'logged-in', token, currentUser: null}\n : {type: 'logged-out', isDestroyingSession: false},\n ),\n )\n\n const fetchCurrentUser = (authState: Extract<AuthState, {type: 'logged-in'}>) => {\n const client = clientFactory({\n token: authState.token,\n projectId,\n dataset,\n requestTagPrefix: REQUEST_TAG_PREFIX,\n apiVersion: DEFAULT_API_VERSION,\n useProjectHostname: authScope === 'project',\n ...(apiHost && {apiHost}),\n })\n\n client\n .request<CurrentUser>({uri: '/users/me', method: 'GET'})\n .then((currentUser) =>\n store.getState().setAuthState({\n ...authState,\n currentUser,\n } as Extract<AuthState, {type: 'logged-in'}>),\n )\n .catch((error) => {\n return store.getState().setAuthState({\n ...authState,\n type: 'error',\n error,\n } as Extract<AuthState, {type: 'error'}>)\n })\n }\n\n if (\n store.getState().authState.type === 'logged-in' &&\n !(store.getState().authState as Extract<AuthState, {type: 'logged-in'}>).currentUser?.id\n ) {\n fetchCurrentUser(store.getState().authState as Extract<AuthState, {type: 'logged-in'}>)\n }\n\n store.subscribe((state) => {\n if (state.authState.type === 'logged-in' && !state.authState.currentUser) {\n fetchCurrentUser(state.authState)\n }\n })\n\n return store\n}\n","import {getOrCreateResource} from '../instance/sanityInstance'\nimport type {SanityInstance} from '../instance/types'\nimport {createInternalAuthStore, type InternalAuthStore} from './internalAuthStore'\n\n/**\n * Retrieves or creates an `AuthStore` for the given `SanityInstance`.\n *\n * Ensures a single `AuthStore` instance is associated with the provided instance.\n * Creates a new store using the instance's configuration if none exists.\n *\n * @param instance - The `SanityInstance` to get or create the `AuthStore` for.\n * @returns The `AuthStore` associated with the given `SanityInstance`.\n *\n * @public\n */\nexport const getInternalAuthStore = (instance: SanityInstance): InternalAuthStore => {\n return getOrCreateResource(instance, 'authStore', () => {\n return createInternalAuthStore(instance, instance.config?.auth)\n })\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {devtools} from 'zustand/middleware'\nimport {createStore as createZustandStore, type StoreApi} from 'zustand/vanilla'\n\nimport type {SanityInstance} from '../instance/types'\n\n/**\n * Creates a (vanilla) zustand store with the given initial state and actions.\n * Only the actions will be returned - actions should be created to interact with it.\n *\n * The rationale for this is to encapsulate the internal state so only the store knows about it,\n * making refactoring easier and more predictable. While this seems like good practice, I am unsure\n * if it might get in our way once we start wanting to subscribe to finer piece of state or similar.\n * I will leave it for now, and we can see if it becomes a problem.\n *\n * @param initialState - Initial state of the store\n * @param actions - The actions available on the store\n * @param options - Options for the store\n * @returns The actions available on the store\n * @internal\n */\nexport function createStore<S, A extends StoreActionMap<S>>(\n initialState: S,\n actions: A,\n {name, instance}: StoreOptions,\n): CurriedActions<S, A> {\n const uniqueName = `${name}-${instance.identity.id}`\n const store = createZustandStore<S>()(devtools(() => ({...initialState}), {name: uniqueName}))\n const context = {store, instance}\n return createCurriedActions(actions, context)\n}\n\n/**\n * Context passed to store actions as first argument.\n *\n * @internal\n */\nexport interface StoreActionContext<S> {\n /**\n * The store API, from zustand. Contains `getState()`, `setState()`, and `subscribe()`.\n */\n store: StoreApi<S>\n\n /**\n * The Sanity SDK instance associated with the store. Often used\n */\n instance: SanityInstance\n}\n\n/**\n * An action that can be performed on a store.\n *\n * @param context - Store context. Contains the store API (`getState()`, `setState()`, `subscribe()`), as well as the SDK instance associated with it.\n * @internal\n */\nexport type StoreAction<S> = (context: StoreActionContext<S>, ...args: any[]) => any\n\n/**\n * A map of actions that can be performed on a store.\n *\n * @internal\n */\nexport type StoreActionMap<S> = Record<string, StoreAction<S>>\n\n/**\n * Options for creating a store.\n *\n * @internal\n */\nexport interface StoreOptions {\n /**\n * Name used for debugging\n */\n name: string\n\n /**\n * The Sanity SDK instance associated with the store\n */\n instance: SanityInstance\n}\n\nfunction createCurriedActions<S, A extends StoreActionMap<S>>(\n actions: A,\n store: StoreActionContext<S>,\n): CurriedActions<S, A> {\n const curried: CurriedActions<S, A> = {} as CurriedActions<S, A>\n return Object.entries(actions).reduce((acc, [key, action]) => {\n const curriedAction = (...args: RestParameters<typeof action>) => action(store, ...args)\n return {...acc, [key]: curriedAction}\n }, curried)\n}\n\ntype RestParameters<T extends (...args: any[]) => any> = T extends (\n first: any,\n ...rest: infer R\n) => any\n ? R\n : never\n\ntype ActionReturn<T extends (...args: any[]) => any> = ReturnType<T>\n\ntype CurriedActions<S, A extends StoreActionMap<S>> = {\n [K in keyof A]: A[K] extends StoreAction<S>\n ? (...args: RestParameters<A[K]>) => ActionReturn<A[K]>\n : never\n}\n","import {type SanityClient} from '@sanity/client'\n\nimport type {StoreActionContext} from '../../../store/createStore'\nimport type {ClientOptions, ClientState} from '../clientStore'\n\n/**\n * Retrieves a memoized client based on the API version,\n * or creates a new one if it doesn't exist.\n * @internal\n */\nexport const getOrCreateClient = (\n {store}: StoreActionContext<ClientState>,\n options: ClientOptions = {},\n): SanityClient => {\n const state = store.getState()\n const {apiVersion} = options\n\n if (!apiVersion) {\n throw new Error('Missing required `apiVersion` option')\n }\n\n const cached = state.clients.get(apiVersion)\n if (cached) {\n return cached\n }\n\n // Create new client with specified API version\n const client = state.defaultClient.withConfig(options)\n\n // Update state with new client\n store.setState((prevState) => {\n const newMap = new Map(prevState.clients)\n newMap.set(apiVersion, client)\n return {\n clients: newMap,\n }\n })\n\n return client\n}\n","import type {SanityClient} from '@sanity/client'\nimport {distinctUntilChanged, map, Observable, startWith, type Subscribable} from 'rxjs'\n\nimport type {StoreActionContext} from '../../../store/createStore'\nimport type {ClientOptions, ClientState} from '../clientStore'\nimport {getOrCreateClient} from './getOrCreateClient'\n\n/**\n * Provides a stream of clients, based on the current state of the store.\n * (For example, when a user logs in, this will emit an authorized client.)\n * @internal\n */\nexport const getClientEvents = (\n context: StoreActionContext<ClientState>,\n options: ClientOptions = {},\n): Subscribable<SanityClient> => {\n const {store} = context\n\n const initialClient = getOrCreateClient(context, options)\n const clientStore$ = new Observable<void>((subscriber) =>\n store.subscribe(() => subscriber.next()),\n )\n\n const client$ = clientStore$.pipe(\n map(() => getOrCreateClient(context, options)),\n startWith(initialClient),\n distinctUntilChanged((prev, curr) => prev.config().token === curr.config().token),\n )\n\n return {\n subscribe: client$.subscribe.bind(client$),\n }\n}\n","import type {StoreActionContext} from '../../../store/createStore'\nimport type {ClientState} from '../clientStore'\n\n/**\n * Updates the client store state when a token is received.\n * @internal\n */\nexport const receiveToken = (\n {store}: StoreActionContext<ClientState>,\n token: string | undefined,\n): void => {\n // Update the default client\n const newDefaultClient = store.getState().defaultClient.withConfig({\n token,\n })\n\n // Update existing clients while preserving the map structure\n store.setState((prevState) => {\n const updatedClients = new Map(\n Array.from(prevState.clients.entries()).map(([version, client]) => [\n version,\n client.withConfig({token}),\n ]),\n )\n\n return {\n defaultClient: newDefaultClient,\n clients: updatedClients,\n }\n })\n}\n","import {createClient, type SanityClient} from '@sanity/client'\nimport type {Subscribable} from 'rxjs'\n\nimport {getInternalAuthStore} from '../../auth/getInternalAuthStore'\nimport {getOrCreateResource} from '../../instance/sanityInstance'\nimport type {SanityInstance} from '../../instance/types'\nimport {createStore} from '../../store/createStore'\nimport {getClientEvents} from './actions/getClientEvents'\nimport {getOrCreateClient} from './actions/getOrCreateClient'\nimport {receiveToken} from './actions/receiveToken'\n\nexport const DEFAULT_API_VERSION = 'v2024-11-12'\n\n/**\n * Options used when retrieving a client via getOrCreateClient.\n * @public\n */\nexport interface ClientOptions {\n apiVersion?: string\n}\n\n/**\n * Internal state of the client store.\n * @internal\n */\nexport interface ClientState {\n // default client shouldn't be exposed, but is used in creation of new clients\n defaultClient: SanityClient\n clients: Map<string, SanityClient>\n}\n\n/**\n * Collection of actions to retrieve or create clients.\n * @internal\n */\nexport interface ClientStore {\n getOrCreateClient: (options: ClientOptions) => SanityClient\n receiveToken: (token: string | undefined) => void\n getClientEvents: (options: ClientOptions) => Subscribable<SanityClient>\n}\n\nconst createInitialState = (defaultClient: SanityClient): ClientState => {\n const clients = new Map<string, SanityClient>()\n clients.set(defaultClient.config().apiVersion, defaultClient)\n return {defaultClient, clients}\n}\n\nconst clientStoreActions = {\n getOrCreateClient,\n receiveToken,\n getClientEvents,\n}\n\n/**\n * Construction method for creating a client store, including subscribing to auth store.\n * @internal\n */\nexport const createClientStore = (\n instance: SanityInstance,\n defaultClient: SanityClient,\n): ClientStore => {\n const internalAuthStore = getInternalAuthStore(instance)\n\n const store = createStore(createInitialState(defaultClient), clientStoreActions, {\n name: 'clientStore',\n instance,\n })\n\n internalAuthStore.subscribe((state, prevState) => {\n if (state.authState.type === 'logged-in' && prevState.authState.type !== 'logged-in') {\n store.receiveToken(state.authState.token)\n }\n if (prevState.authState.type === 'logged-in' && state.authState.type !== 'logged-in') {\n store.receiveToken(undefined)\n }\n })\n\n return store\n}\n\n/**\n * This is an internal function that retrieves or creates a client store.\n * @internal\n */\nexport const getClientStore = (instance: SanityInstance): ClientStore => {\n return getOrCreateResource(instance, 'clientStore', () => {\n const {config, identity} = instance\n\n const client = createClient({\n projectId: identity.projectId,\n dataset: identity.dataset,\n token: config?.auth?.token,\n useCdn: false,\n apiVersion: DEFAULT_API_VERSION,\n })\n return createClientStore(instance, client)\n })\n}\n","import type {SanityClient} from '@sanity/client'\n\nimport type {SanityInstance} from '../instance/types'\nimport {type ClientOptions, getClientStore} from './store/clientStore'\n\n/**\n * Retrieve a memoized client based on the apiVersion.\n * @public\n */\nexport const getClient = (options: ClientOptions, instance: SanityInstance): SanityClient => {\n const clientStore = getClientStore(instance)\n return clientStore.getOrCreateClient(options)\n}\n","import type {SanityClient} from '@sanity/client'\nimport type {Subscribable} from 'rxjs'\n\nimport type {SanityInstance} from '../instance/types'\nimport {type ClientOptions, getClientStore} from './store/clientStore'\n\n/**\n * Creates a subscribable client based on the apiVersion.\n * The client will update when the underlying store changes (e.g., on user authentication changes).\n * @public\n */\nexport const getSubscribableClient = (\n options: ClientOptions,\n instance: SanityInstance,\n): Subscribable<SanityClient> => {\n return getClientStore(instance).getClientEvents(options)\n}\n","import type {SyncTag} from '@sanity/client'\nimport {isEqual} from 'lodash-es'\nimport {\n distinctUntilChanged,\n map,\n Observable,\n pairwise,\n startWith,\n type Subscribable,\n switchMap,\n tap,\n} from 'rxjs'\nimport {devtools} from 'zustand/middleware'\nimport {createStore} from 'zustand/vanilla'\n\nimport {getClientStore} from '../client/store/clientStore'\nimport type {SanityInstance} from '../instance/types'\n\nconst PAGE_SIZE = 50\n\nconst API_VERSION = 'vX'\n\n/**\n * Represents an identifier to a Sanity document, containing its `_id` to pull\n * the document from content lake and its `_type` to look up its schema type.\n * @public\n */\nexport interface DocumentHandle {\n _id: string\n _type: string\n}\n\n/**\n * Represents the current state of a document list, including the query options\n * and loading status.\n * @public\n */\nexport interface DocumentListState extends DocumentListOptions {\n /** Array of document handles in the current result set, or null if not yet loaded */\n result: DocumentHandle[] | null\n /** Indicates whether the document list is currently loading */\n isPending: boolean\n}\n\n/**\n * Represents a sort ordering configuration.\n * @public\n */\nexport interface SortOrderingItem {\n field: string\n direction: 'asc' | 'desc'\n}\n\n/**\n * Configuration options for filtering and sorting documents in a document list.\n * @public\n */\nexport interface DocumentListOptions {\n /** GROQ filter expression to query specific documents */\n filter?: string\n /** Array of sort ordering specifications to determine the order of results */\n sort?: SortOrderingItem[]\n}\n\n/**\n * Manages the state and operations for a list of Sanity documents.\n * Provides methods to update options, load more documents, and subscribe to\n * state changes.\n *\n * Implements a subscription model where you can register callback functions\n * to be notified when the document list state changes.\n * @public\n */\nexport interface DocumentListStore extends Subscribable<DocumentListState> {\n /** Updates the filtering and sorting options for the document list */\n setOptions: (options: DocumentListOptions) => void\n /** Retrieves the current state of the document list synchronously */\n getCurrent: () => DocumentListState\n /** Loads the next page of documents */\n loadMore: () => void\n /** Cleans up resources and subscriptions when the store is no longer needed */\n dispose: () => void\n}\n\ninterface DocumentListInternalState extends DocumentListOptions {\n isPending: boolean\n lastLiveEventId?: string\n syncTags: Set<SyncTag>\n limit: number\n result: DocumentHandle[] | null\n}\n\n/**\n * Creates a `DocumentListStore` from a `SanityInstance`.\n *\n * @public\n *\n * See {@link SanityInstance} and {@link DocumentListStore}\n */\nexport function createDocumentListStore(instance: SanityInstance): DocumentListStore {\n const clientStore = getClientStore(instance)\n const clientStream$ = new Observable(\n clientStore.getClientEvents({apiVersion: API_VERSION}).subscribe,\n )\n\n const initialState: DocumentListInternalState = {\n syncTags: new Set<SyncTag>(),\n isPending: false,\n result: null,\n limit: PAGE_SIZE,\n }\n\n const store = createStore<DocumentListInternalState>()(\n devtools((..._unusedArgs) => initialState, {\n name: 'SanityDocumentListStore',\n enabled: true, // Should be process.env.NODE_ENV === 'development'\n }),\n )\n\n const liveSubscription = clientStream$\n .pipe(\n switchMap((client) => client.live.events({includeDrafts: true, tag: 'sdk.live-listener'})),\n )\n .subscribe({\n next: (event) => {\n const {syncTags} = store.getState()\n if (event.type === 'message' && event.tags.some((tag) => syncTags.has(tag))) {\n store.setState(\n {lastLiveEventId: event.id},\n false,\n 'UPDATE_EVENT_ID_FROM_LIVE_CONTENT_API',\n )\n }\n },\n })\n\n const resultSubscription = new Observable<DocumentListInternalState>((observer) =>\n store.subscribe((state) => observer.next(state)),\n )\n .pipe(\n distinctUntilChanged((prev, current) => {\n if (prev.filter !== current.filter) return false\n if (prev.lastLiveEventId !== current.lastLiveEventId) return false\n if (!isEqual(prev.sort, current.sort)) return false\n if (prev.limit !== current.limit) return false\n return true\n }),\n tap(() => store.setState({isPending: true}, false, {type: 'START_FETCH'})),\n switchMap((state) => {\n const filter = state.filter ? `[${state.filter}]` : ''\n const order = state.sort\n ? `| order(${state.sort\n .map((ordering) =>\n [ordering.field, ordering.direction.toLowerCase()]\n .map((str) => str.trim())\n .filter(Boolean)\n .join(' '),\n )\n .join(',')})`\n : ''\n\n return clientStream$.pipe(\n switchMap((client) =>\n client.observable.fetch(\n `*${filter}${order}[0..$__limit]{_id, _type}`,\n {__limit: state.limit},\n {\n filterResponse: false,\n returnQuery: false,\n lastLiveEventId: state.lastLiveEventId,\n tag: 'sdk.document-list',\n // // TODO: this should use the `previewDrafts` perspective for\n // // removing duplicates in the result set but the live content API\n // // does not currently return the correct sync tags. CLDX has\n // // planned to add perspective support to the live content API\n // // in december of 2024\n // perspective: 'previewDrafts'\n },\n ),\n ),\n )\n }),\n )\n .subscribe({\n next: ({syncTags, result}) => {\n store.setState(\n {\n syncTags: new Set(syncTags),\n result,\n isPending: false,\n },\n false,\n {type: 'UPDATE_FROM_FETCH'},\n )\n },\n })\n\n function setOptions({filter, sort}: DocumentListOptions) {\n store.setState(\n {\n // spreads properties only if they exist, preserving other state\n // properties set in the zustand store already\n ...(filter && {filter}),\n ...(sort && {sort}),\n },\n false,\n {type: 'SET_OPTIONS'},\n )\n }\n\n function loadMore() {\n store.setState((prev) => ({limit: prev.limit + PAGE_SIZE}), undefined, {type: 'LOAD_MORE'})\n }\n\n function getCurrent() {\n const {isPending, result, filter, sort} = store.getState()\n return {isPending, result, filter, sort}\n }\n\n const state$ = new Observable<DocumentListState>((observer) => {\n function emitCurrent() {\n const {isPending, result, filter, sort} = store.getState()\n observer.next({\n isPending,\n result,\n filter,\n sort,\n })\n }\n\n emitCurrent()\n return store.subscribe(emitCurrent)\n }).pipe(\n distinctUntilChanged((prev, curr) => {\n if (!isEqual(prev.sort, curr.sort)) return false\n if (prev.result !== curr.result) return false\n if (prev.filter !== curr.filter) return false\n if (prev.isPending !== curr.isPending) return false\n return true\n }),\n startWith(null),\n pairwise(),\n map((arg): DocumentListState => {\n // casting this since `curr` will never be null\n const [prev, curr] = arg as [DocumentListState | null, DocumentListState]\n if (!prev?.result) return curr\n if (!curr?.result) return curr\n\n const prevMap = prev.result.reduce<Map<string, DocumentHandle>>((acc, handle) => {\n acc.set(handle._id, handle)\n return acc\n }, new Map())\n\n return {\n ...curr,\n result: curr.result.map((i) => prevMap.get(i._id) ?? i),\n }\n }),\n )\n\n const subscribe = state$.subscribe.bind(state$)\n\n function dispose() {\n liveSubscription.unsubscribe()\n resultSubscription.unsubscribe()\n }\n\n return {setOptions, getCurrent, loadMore, subscribe, dispose}\n}\n","import type {CurrentUser} from '@sanity/types'\n\nimport type {SanityInstance} from '../instance/types'\nimport {getInternalAuthStore} from './getInternalAuthStore'\nimport type {AuthProvider, AuthState} from './internalAuthStore'\n\n/**\n * @public\n */\nexport interface AuthStore {\n authState: AuthStateSlice\n tokenState: AuthTokenSlice\n currentUserState: CurrentUserSlice\n handleCallback: (locationHref?: string) => Promise<string | false>\n logout: () => Promise<void>\n dispose: () => void\n getLoginUrls: () => AuthProvider[] | Promise<AuthProvider[]>\n}\n\n/**\n * Public interface for the auth store.\n * @public\n */\nexport interface AuthStateSlice {\n getState: () => AuthState\n getInitialState: () => AuthState\n subscribe: (listener: (state: AuthState, prevState: AuthState) => void) => () => void\n}\n\n/**\n * Public interface for the token store.\n *\n * @public\n */\nexport interface AuthTokenSlice {\n getState: () => string | null\n getInitialState: () => string | null\n subscribe: (listener: (token: string | null, prevToken: string | null) => void) => () => void\n}\n\n/**\n * Public interface for the auth store slice that contains the current user.\n *\n * @public\n */\nexport interface CurrentUserSlice {\n getState: () => CurrentUser | null\n getInitialState: () => CurrentUser | null\n subscribe: (\n listener: (user: CurrentUser | null, prevUser: CurrentUser | null) => void,\n ) => () => void\n}\n\nexport type {AuthConfig, AuthProvider, AuthState} from './internalAuthStore'\n\n/**\n * Retrieves or creates an `AuthStore` for the given `SanityInstance`.\n *\n * @param instance - The `SanityInstance` to get or create the `AuthStore` for.\n * @returns The `AuthStore` associated with the given `SanityInstance`.\n *\n * @public\n */\nexport const getAuthStore = (instance: SanityInstance): AuthStore => {\n const internalAuthStore = getInternalAuthStore(instance)\n\n const authState: AuthStateSlice = {\n getState: () => internalAuthStore.getState().authState,\n getInitialState: () => internalAuthStore.getInitialState().authState,\n subscribe: (listener) =>\n internalAuthStore.subscribe((current, prev) => {\n listener(current.authState, prev.authState)\n }),\n }\n\n const tokenState: AuthTokenSlice = {\n getState: () => {\n const state = internalAuthStore.getState()\n if (state.authState.type !== 'logged-in') return null\n return state.authState.token\n },\n getInitialState: () => {\n const state = internalAuthStore.getInitialState()\n if (state.authState.type !== 'logged-in') return null\n return state.authState.token\n },\n subscribe: (listener) =>\n internalAuthStore.subscribe((state, prevState) => {\n const token = state.authState.type === 'logged-in' ? state.authState.token : null\n const prevToken =\n prevState.authState.type === 'logged-in' ? prevState.authState.token : null\n listener(token, prevToken)\n }),\n }\n\n const currentUserState: CurrentUserSlice = {\n getState: () => {\n const state = internalAuthStore.getState()\n if (state.authState.type !== 'logged-in') return null\n return state.authState.currentUser\n },\n getInitialState: () => {\n const state = internalAuthStore.getInitialState()\n if (state.authState.type !== 'logged-in') return null\n return state.authState.currentUser\n },\n subscribe: (listener) =>\n internalAuthStore.subscribe((state, prevState) => {\n const user = state.authState.type === 'logged-in' ? state.authState.currentUser : null\n const prevUser =\n prevState.authState.type === 'logged-in' ? prevState.authState.currentUser : null\n listener(user, prevUser)\n }),\n }\n\n return {\n authState,\n tokenState,\n currentUserState,\n handleCallback: internalAuthStore.getState().handleCallback,\n logout: internalAuthStore.getState().logout,\n dispose: internalAuthStore.getState().dispose,\n getLoginUrls: internalAuthStore.getState().getLoginUrls,\n }\n}\n"],"names":["DEFAULT_API_VERSION","createStore","createZustandStore","filter"],"mappings":"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"}
|