@sanity/sdk 2.8.0 → 2.9.0
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/_chunks-dts/utils.d.ts +2396 -0
- package/dist/_chunks-es/_internal.js +129 -0
- package/dist/_chunks-es/_internal.js.map +1 -0
- package/dist/_chunks-es/createGroqSearchFilter.js +1460 -0
- package/dist/_chunks-es/createGroqSearchFilter.js.map +1 -0
- package/dist/_chunks-es/telemetryManager.js +87 -0
- package/dist/_chunks-es/telemetryManager.js.map +1 -0
- package/dist/_chunks-es/version.js +7 -0
- package/dist/_chunks-es/version.js.map +1 -0
- package/dist/_exports/_internal.d.ts +64 -0
- package/dist/_exports/_internal.js +20 -0
- package/dist/_exports/_internal.js.map +1 -0
- package/dist/index.d.ts +2 -2343
- package/dist/index.js +383 -1777
- package/dist/index.js.map +1 -1
- package/package.json +11 -4
- package/src/_exports/_internal.ts +14 -0
- package/src/_exports/index.ts +10 -1
- package/src/auth/authStore.test.ts +150 -1
- package/src/auth/authStore.ts +11 -11
- package/src/auth/dashboardAuth.ts +2 -2
- package/src/auth/handleAuthCallback.ts +9 -3
- package/src/auth/logout.test.ts +1 -1
- package/src/auth/logout.ts +1 -1
- package/src/auth/refreshStampedToken.test.ts +118 -1
- package/src/auth/refreshStampedToken.ts +3 -2
- package/src/auth/standaloneAuth.ts +9 -3
- package/src/auth/studioAuth.ts +34 -7
- package/src/auth/studioModeAuth.ts +2 -1
- package/src/auth/subscribeToStateAndFetchCurrentUser.test.ts +10 -2
- package/src/auth/subscribeToStateAndFetchCurrentUser.ts +5 -1
- package/src/auth/subscribeToStorageEventsAndSetToken.ts +2 -2
- package/src/auth/utils.ts +33 -0
- package/src/client/clientStore.test.ts +14 -0
- package/src/client/clientStore.ts +2 -1
- package/src/comlink/node/getNodeState.ts +2 -1
- package/src/config/sanityConfig.ts +6 -0
- package/src/document/actions.ts +18 -11
- package/src/document/applyDocumentActions.test.ts +7 -6
- package/src/document/applyDocumentActions.ts +10 -4
- package/src/document/documentStore.test.ts +536 -188
- package/src/document/documentStore.ts +142 -76
- package/src/document/events.ts +7 -2
- package/src/document/permissions.test.ts +18 -16
- package/src/document/permissions.ts +35 -11
- package/src/document/processActions.test.ts +359 -32
- package/src/document/processActions.ts +104 -76
- package/src/document/reducers.test.ts +117 -29
- package/src/document/reducers.ts +43 -36
- package/src/document/sharedListener.ts +16 -6
- package/src/document/util.ts +14 -0
- package/src/favorites/favorites.test.ts +9 -2
- package/src/presence/bifurTransport.ts +6 -1
- package/src/preview/getPreviewState.test.ts +115 -98
- package/src/preview/getPreviewState.ts +38 -60
- package/src/preview/previewProjectionUtils.test.ts +179 -0
- package/src/preview/previewProjectionUtils.ts +93 -0
- package/src/preview/resolvePreview.test.ts +42 -25
- package/src/preview/resolvePreview.ts +29 -10
- package/src/preview/{previewStore.ts → types.ts} +8 -17
- package/src/projection/getProjectionState.test.ts +16 -16
- package/src/projection/getProjectionState.ts +2 -1
- package/src/projection/projectionQuery.ts +2 -3
- package/src/projection/types.ts +1 -1
- package/src/query/queryStore.ts +2 -1
- package/src/releases/getPerspectiveState.ts +7 -6
- package/src/releases/releasesStore.test.ts +20 -5
- package/src/releases/releasesStore.ts +20 -8
- package/src/store/createStateSourceAction.test.ts +62 -0
- package/src/store/createStateSourceAction.ts +34 -39
- package/src/telemetry/__telemetry__/sdk.telemetry.ts +42 -0
- package/src/telemetry/devMode.test.ts +52 -0
- package/src/telemetry/devMode.ts +40 -0
- package/src/telemetry/initTelemetry.test.ts +225 -0
- package/src/telemetry/initTelemetry.ts +205 -0
- package/src/telemetry/telemetryManager.test.ts +263 -0
- package/src/telemetry/telemetryManager.ts +187 -0
- package/src/users/usersStore.test.ts +1 -0
- package/src/users/usersStore.ts +5 -1
- package/src/utils/createFetcherStore.test.ts +6 -4
- package/src/utils/createFetcherStore.ts +2 -1
- package/src/utils/getStagingApiHost.test.ts +21 -0
- package/src/utils/getStagingApiHost.ts +14 -0
- package/src/utils/ids.test.ts +1 -29
- package/src/utils/ids.ts +0 -10
- package/src/utils/setCleanupTimeout.ts +24 -0
- package/src/preview/previewQuery.test.ts +0 -236
- package/src/preview/previewQuery.ts +0 -153
- package/src/preview/previewStore.test.ts +0 -36
- package/src/preview/subscribeToStateAndFetchBatches.test.ts +0 -221
- package/src/preview/subscribeToStateAndFetchBatches.ts +0 -112
- package/src/preview/util.ts +0 -13
|
@@ -0,0 +1,1460 @@
|
|
|
1
|
+
import { pick, omit, isObject } from "lodash-es";
|
|
2
|
+
import { createClient, CorsOriginError } from "@sanity/client";
|
|
3
|
+
import { Observable, map, distinctUntilChanged, shareReplay, skip, defer, finalize, filter, exhaustMap, from, timer, switchMap, takeWhile, firstValueFrom, fromEvent, EMPTY, catchError, NEVER, first, race, startWith, pairwise, mergeMap, groupBy, of, combineLatest, tap, share } from "rxjs";
|
|
4
|
+
import { createSelector } from "reselect";
|
|
5
|
+
import { createImageUrlBuilder } from "@sanity/image-url";
|
|
6
|
+
import { devtools } from "zustand/middleware";
|
|
7
|
+
import { createStore } from "zustand/vanilla";
|
|
8
|
+
function isDatasetSource(source) {
|
|
9
|
+
return "projectId" in source && "dataset" in source;
|
|
10
|
+
}
|
|
11
|
+
function isMediaLibrarySource(source) {
|
|
12
|
+
return "mediaLibraryId" in source;
|
|
13
|
+
}
|
|
14
|
+
function isCanvasSource(source) {
|
|
15
|
+
return "canvasId" in source;
|
|
16
|
+
}
|
|
17
|
+
const isReleasePerspective = (perspective) => typeof perspective == "object" && perspective !== null && "releaseName" in perspective;
|
|
18
|
+
function insecureRandomId() {
|
|
19
|
+
return Array.from({ length: 16 }, () => Math.floor(Math.random() * 16).toString(16)).join("");
|
|
20
|
+
}
|
|
21
|
+
const LOG_LEVEL_PRIORITY = {
|
|
22
|
+
error: 0,
|
|
23
|
+
warn: 1,
|
|
24
|
+
info: 2,
|
|
25
|
+
debug: 3,
|
|
26
|
+
trace: 4
|
|
27
|
+
}, DEFAULT_CONFIG = {
|
|
28
|
+
level: "warn",
|
|
29
|
+
namespaces: [],
|
|
30
|
+
internal: !1,
|
|
31
|
+
timestamps: !0,
|
|
32
|
+
enableInProduction: !1,
|
|
33
|
+
handler: {
|
|
34
|
+
// eslint-disable-next-line no-console
|
|
35
|
+
error: console.error.bind(console),
|
|
36
|
+
// eslint-disable-next-line no-console
|
|
37
|
+
warn: console.warn.bind(console),
|
|
38
|
+
// eslint-disable-next-line no-console
|
|
39
|
+
info: console.info.bind(console),
|
|
40
|
+
// eslint-disable-next-line no-console
|
|
41
|
+
debug: console.debug.bind(console),
|
|
42
|
+
// eslint-disable-next-line no-console
|
|
43
|
+
trace: console.debug.bind(console)
|
|
44
|
+
// trace uses console.debug
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
function parseDebugEnvVar() {
|
|
48
|
+
if (typeof process > "u" || !process.env?.DEBUG)
|
|
49
|
+
return null;
|
|
50
|
+
const debug = process.env.DEBUG;
|
|
51
|
+
if (!debug.includes("sanity"))
|
|
52
|
+
return null;
|
|
53
|
+
const config = {}, levelMatch = debug.match(/sanity:(trace|debug|info|warn|error):/), hasLevelSpecifier = !!levelMatch;
|
|
54
|
+
if (levelMatch ? config.level = levelMatch[1] : config.level = "debug", debug === "sanity")
|
|
55
|
+
config.namespaces = ["*"];
|
|
56
|
+
else if (hasLevelSpecifier && debug.match(/sanity:(trace|debug|info|warn|error):\*/))
|
|
57
|
+
config.namespaces = ["*"];
|
|
58
|
+
else if (!hasLevelSpecifier && debug.includes("sanity:*"))
|
|
59
|
+
config.namespaces = ["*"];
|
|
60
|
+
else {
|
|
61
|
+
const namespaces = debug.split(",").filter((s) => s.includes("sanity:")).map((s) => {
|
|
62
|
+
const cleaned = s.replace(/^sanity:/, "");
|
|
63
|
+
return hasLevelSpecifier && cleaned.match(/^(trace|debug|info|warn|error):/) ? cleaned.split(":").slice(1).join(":") : cleaned.split(":")[0];
|
|
64
|
+
}).filter(Boolean).filter((ns) => ns !== "*");
|
|
65
|
+
namespaces.length > 0 && (config.namespaces = namespaces);
|
|
66
|
+
}
|
|
67
|
+
return debug.includes(":internal") && (config.internal = !0), config;
|
|
68
|
+
}
|
|
69
|
+
const envConfig = parseDebugEnvVar();
|
|
70
|
+
let globalConfig = {
|
|
71
|
+
...DEFAULT_CONFIG,
|
|
72
|
+
...envConfig ?? {}
|
|
73
|
+
};
|
|
74
|
+
envConfig && (["info", "debug", "trace"].includes(globalConfig.level) || globalConfig.level === "warn") && console.info(
|
|
75
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] [INFO] [sdk] Logging auto-configured from DEBUG environment variable`,
|
|
76
|
+
{
|
|
77
|
+
level: globalConfig.level,
|
|
78
|
+
namespaces: globalConfig.namespaces,
|
|
79
|
+
internal: globalConfig.internal,
|
|
80
|
+
source: "env:DEBUG",
|
|
81
|
+
value: typeof process < "u" ? process.env?.DEBUG : void 0
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
function configureLogging(config) {
|
|
85
|
+
globalConfig = {
|
|
86
|
+
...globalConfig,
|
|
87
|
+
...config,
|
|
88
|
+
handler: config.handler ?? globalConfig.handler
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function isLoggingEnabled() {
|
|
92
|
+
return typeof process < "u" && process.env?.NODE_ENV === "production" ? globalConfig.enableInProduction : !0;
|
|
93
|
+
}
|
|
94
|
+
function isNamespaceEnabled(namespace) {
|
|
95
|
+
return isLoggingEnabled() ? globalConfig.namespaces.includes("*") ? !0 : globalConfig.namespaces.includes(namespace) : !1;
|
|
96
|
+
}
|
|
97
|
+
function isLevelEnabled(level) {
|
|
98
|
+
return isLoggingEnabled() ? LOG_LEVEL_PRIORITY[level] <= LOG_LEVEL_PRIORITY[globalConfig.level] : !1;
|
|
99
|
+
}
|
|
100
|
+
function formatMessage(namespace, level, message, context) {
|
|
101
|
+
const parts = [];
|
|
102
|
+
if (globalConfig.timestamps) {
|
|
103
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
104
|
+
parts.push(`[${timestamp}]`);
|
|
105
|
+
}
|
|
106
|
+
parts.push(`[${level.toUpperCase()}]`), parts.push(`[${namespace}]`);
|
|
107
|
+
const instanceContext = context?.instanceContext;
|
|
108
|
+
return instanceContext && (instanceContext.projectId && parts.push(`[project:${instanceContext.projectId}]`), instanceContext.dataset && parts.push(`[dataset:${instanceContext.dataset}]`), instanceContext.instanceId && parts.push(`[instance:${instanceContext.instanceId.slice(0, 8)}]`)), parts.push(message), [parts.join(" "), context];
|
|
109
|
+
}
|
|
110
|
+
function sanitizeContext(context) {
|
|
111
|
+
if (!context || Object.keys(context).length === 0) return;
|
|
112
|
+
const sanitized = { ...context }, sensitiveKeys = ["token", "password", "secret", "apiKey", "authorization"];
|
|
113
|
+
for (const key of Object.keys(sanitized))
|
|
114
|
+
sensitiveKeys.some((sensitive) => key.toLowerCase().includes(sensitive)) && (sanitized[key] = "[REDACTED]");
|
|
115
|
+
return sanitized;
|
|
116
|
+
}
|
|
117
|
+
function createLogger(namespace, baseContext) {
|
|
118
|
+
const logAtLevel = (level, message, context) => {
|
|
119
|
+
if (!isNamespaceEnabled(namespace) || !isLevelEnabled(level) || context?.internal && !globalConfig.internal) return;
|
|
120
|
+
const mergedContext = { ...baseContext, ...context }, sanitized = sanitizeContext(mergedContext), [formatted, finalContext] = formatMessage(namespace, level, message, sanitized);
|
|
121
|
+
globalConfig.handler[level](formatted, finalContext);
|
|
122
|
+
};
|
|
123
|
+
return {
|
|
124
|
+
namespace,
|
|
125
|
+
error: (message, context) => logAtLevel("error", message, context),
|
|
126
|
+
warn: (message, context) => logAtLevel("warn", message, context),
|
|
127
|
+
info: (message, context) => logAtLevel("info", message, context),
|
|
128
|
+
debug: (message, context) => logAtLevel("debug", message, context),
|
|
129
|
+
trace: (message, context) => logAtLevel("trace", message, { ...context, internal: !0 }),
|
|
130
|
+
isLevelEnabled: (level) => isNamespaceEnabled(namespace) && isLevelEnabled(level),
|
|
131
|
+
child: (childContext) => createLogger(namespace, { ...baseContext, ...childContext }),
|
|
132
|
+
getInstanceContext: () => baseContext?.instanceContext
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function getEnv(key) {
|
|
136
|
+
if (typeof import.meta < "u" && import.meta.env)
|
|
137
|
+
return import.meta.env[key];
|
|
138
|
+
if (typeof process < "u" && process.env)
|
|
139
|
+
return process.env[key];
|
|
140
|
+
if (typeof window < "u" && window.ENV)
|
|
141
|
+
return window.ENV?.[key];
|
|
142
|
+
}
|
|
143
|
+
function createStoreState(initialState, devToolsOptions) {
|
|
144
|
+
const store = createStore()(devtools(() => initialState, devToolsOptions));
|
|
145
|
+
return {
|
|
146
|
+
get: store.getState,
|
|
147
|
+
set: (actionKey, updatedState) => {
|
|
148
|
+
const currentState = store.getState(), nextState = typeof updatedState == "function" ? updatedState(currentState) : updatedState;
|
|
149
|
+
currentState !== nextState && store.setState(nextState, !1, actionKey);
|
|
150
|
+
},
|
|
151
|
+
observable: new Observable((observer) => {
|
|
152
|
+
const emit = () => observer.next(store.getState());
|
|
153
|
+
emit();
|
|
154
|
+
const unsubscribe = store.subscribe(emit);
|
|
155
|
+
return () => unsubscribe();
|
|
156
|
+
})
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function defineStore(storeDefinition) {
|
|
160
|
+
return storeDefinition;
|
|
161
|
+
}
|
|
162
|
+
function createStoreInstance(instance, key, { name, getInitialState, initialize }) {
|
|
163
|
+
const state = createStoreState(getInitialState(instance, key), {
|
|
164
|
+
enabled: !!getEnv("DEV"),
|
|
165
|
+
name: `${name}-${key.name}`
|
|
166
|
+
}), dispose = initialize?.({ state, instance, key }), disposed = { current: !1 };
|
|
167
|
+
return {
|
|
168
|
+
state,
|
|
169
|
+
dispose: () => {
|
|
170
|
+
disposed.current || (disposed.current = !0, dispose?.());
|
|
171
|
+
},
|
|
172
|
+
isDisposed: () => disposed.current
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function createActionBinder(keyFn) {
|
|
176
|
+
const instanceRegistry = /* @__PURE__ */ new Map(), storeRegistry = /* @__PURE__ */ new Map();
|
|
177
|
+
return function(storeDefinition, action) {
|
|
178
|
+
return function(instance, ...params) {
|
|
179
|
+
const key = keyFn(instance, ...params), compositeKey = storeDefinition.name + (key.name ? `:${key.name}` : "");
|
|
180
|
+
let instances = instanceRegistry.get(compositeKey);
|
|
181
|
+
instances || (instances = /* @__PURE__ */ new Set(), instanceRegistry.set(compositeKey, instances)), instances.has(instance.instanceId) || (instances.add(instance.instanceId), instance.onDispose(() => {
|
|
182
|
+
instances.delete(instance.instanceId), instances.size === 0 && (storeRegistry.get(compositeKey)?.dispose(), storeRegistry.delete(compositeKey), instanceRegistry.delete(compositeKey));
|
|
183
|
+
}));
|
|
184
|
+
let storeInstance = storeRegistry.get(compositeKey);
|
|
185
|
+
return storeInstance || (storeInstance = createStoreInstance(instance, key, storeDefinition), storeRegistry.set(compositeKey, storeInstance)), action({ instance, state: storeInstance.state, key }, ...params);
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
const bindActionByDataset = createActionBinder((instance, options) => {
|
|
190
|
+
const projectId = options?.projectId ?? instance.config.projectId, dataset = options?.dataset ?? instance.config.dataset;
|
|
191
|
+
if (!projectId || !dataset)
|
|
192
|
+
throw new Error("This API requires a project ID and dataset configured.");
|
|
193
|
+
return { name: `${projectId}.${dataset}`, projectId, dataset };
|
|
194
|
+
}), createSourceKey = (instance, source) => {
|
|
195
|
+
let name, sourceForKey;
|
|
196
|
+
if (source) {
|
|
197
|
+
if (sourceForKey = source, isDatasetSource(source))
|
|
198
|
+
name = `${source.projectId}.${source.dataset}`;
|
|
199
|
+
else if (isMediaLibrarySource(source))
|
|
200
|
+
name = `media-library:${source.mediaLibraryId}`;
|
|
201
|
+
else if (isCanvasSource(source))
|
|
202
|
+
name = `canvas:${source.canvasId}`;
|
|
203
|
+
else
|
|
204
|
+
throw new Error(`Received invalid source: ${JSON.stringify(source)}`);
|
|
205
|
+
return { name, source: sourceForKey };
|
|
206
|
+
}
|
|
207
|
+
const { projectId, dataset } = instance.config;
|
|
208
|
+
if (!projectId || !dataset)
|
|
209
|
+
throw new Error("This API requires a project ID and dataset configured.");
|
|
210
|
+
return { name: `${projectId}.${dataset}`, source: { projectId, dataset } };
|
|
211
|
+
}, bindActionBySource = createActionBinder((instance, { source }) => createSourceKey(instance, source)), bindActionBySourceAndPerspective = createActionBinder((instance, options) => {
|
|
212
|
+
const { source, perspective } = options, utilizedPerspective = perspective ?? instance.config.perspective ?? "drafts";
|
|
213
|
+
let perspectiveKey;
|
|
214
|
+
isReleasePerspective(utilizedPerspective) ? perspectiveKey = utilizedPerspective.releaseName : typeof utilizedPerspective == "string" ? perspectiveKey = utilizedPerspective : perspectiveKey = JSON.stringify(utilizedPerspective);
|
|
215
|
+
const sourceKey = createSourceKey(instance, source);
|
|
216
|
+
return {
|
|
217
|
+
name: `${sourceKey.name}:${perspectiveKey}`,
|
|
218
|
+
source: sourceKey.source,
|
|
219
|
+
perspective: utilizedPerspective
|
|
220
|
+
};
|
|
221
|
+
}), bindActionGlobally = createActionBinder((..._rest) => ({ name: "global" }));
|
|
222
|
+
function createStateSourceAction(options) {
|
|
223
|
+
const selector = typeof options == "function" ? options : options.selector, subscribeHandler = options && "onSubscribe" in options ? options.onSubscribe : void 0, isEqual = options && "isEqual" in options ? options.isEqual ?? Object.is : Object.is, selectorContextCache = /* @__PURE__ */ new WeakMap();
|
|
224
|
+
function stateSourceAction(context, ...params) {
|
|
225
|
+
const { state, instance } = context, getCurrent = (currentState) => {
|
|
226
|
+
if (typeof currentState != "object" || currentState === null)
|
|
227
|
+
throw new Error(
|
|
228
|
+
`Expected store state to be an object but got "${typeof currentState}" instead`
|
|
229
|
+
);
|
|
230
|
+
let instanceCache = selectorContextCache.get(currentState);
|
|
231
|
+
instanceCache || (instanceCache = /* @__PURE__ */ new WeakMap(), selectorContextCache.set(currentState, instanceCache));
|
|
232
|
+
let selectorContext = instanceCache.get(instance);
|
|
233
|
+
return selectorContext || (selectorContext = { state: currentState, instance }, instanceCache.set(instance, selectorContext)), selector(selectorContext, ...params);
|
|
234
|
+
};
|
|
235
|
+
let values = state.observable.pipe(map(getCurrent), distinctUntilChanged(isEqual));
|
|
236
|
+
subscribeHandler && (values = withSubscribeHook(values, () => subscribeHandler(context, ...params)));
|
|
237
|
+
const sharedValues = values.pipe(shareReplay({ bufferSize: 1, refCount: !0 }));
|
|
238
|
+
return {
|
|
239
|
+
getCurrent: () => getCurrent(state.get()),
|
|
240
|
+
subscribe: (onStoreChanged) => {
|
|
241
|
+
const subscription = sharedValues.pipe(skip(1)).subscribe({
|
|
242
|
+
next: () => onStoreChanged?.(),
|
|
243
|
+
// Propagate selector errors to both subscription types
|
|
244
|
+
error: () => onStoreChanged?.()
|
|
245
|
+
});
|
|
246
|
+
return () => {
|
|
247
|
+
subscription.unsubscribe();
|
|
248
|
+
};
|
|
249
|
+
},
|
|
250
|
+
observable: sharedValues
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
return stateSourceAction;
|
|
254
|
+
}
|
|
255
|
+
function withSubscribeHook(obs, fn) {
|
|
256
|
+
return defer(() => {
|
|
257
|
+
const cleanup = fn();
|
|
258
|
+
return cleanup ? obs.pipe(finalize(() => cleanup())) : obs;
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function getStagingApiHost() {
|
|
262
|
+
if (typeof __SANITY_STAGING__ < "u" && __SANITY_STAGING__ === !0)
|
|
263
|
+
return "https://api.sanity.work";
|
|
264
|
+
}
|
|
265
|
+
const DEFAULT_BASE = "http://localhost", AUTH_CODE_PARAM = "sid", DEFAULT_API_VERSION$1 = "2021-06-07", REQUEST_TAG_PREFIX = "sanity.sdk.auth";
|
|
266
|
+
function resolveAuthMode(config, locationHref) {
|
|
267
|
+
return isStudioConfig(config) ? "studio" : detectDashboardContext(locationHref) ? "dashboard" : "standalone";
|
|
268
|
+
}
|
|
269
|
+
function isStudioConfig(config) {
|
|
270
|
+
return !!config.studio || !!config.studioMode?.enabled;
|
|
271
|
+
}
|
|
272
|
+
function detectDashboardContext(locationHref) {
|
|
273
|
+
try {
|
|
274
|
+
const contextParam = new URL(locationHref, DEFAULT_BASE).searchParams.get("_context");
|
|
275
|
+
if (!contextParam) return !1;
|
|
276
|
+
const parsed = JSON.parse(contextParam);
|
|
277
|
+
return typeof parsed == "object" && parsed !== null && !Array.isArray(parsed) && Object.keys(parsed).length > 0;
|
|
278
|
+
} catch (err) {
|
|
279
|
+
return console.error("Failed to parse dashboard context from initial location:", err), !1;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
var AuthStateType = /* @__PURE__ */ ((AuthStateType2) => (AuthStateType2.LOGGED_IN = "logged-in", AuthStateType2.LOGGING_IN = "logging-in", AuthStateType2.ERROR = "error", AuthStateType2.LOGGED_OUT = "logged-out", AuthStateType2))(AuthStateType || {});
|
|
283
|
+
const REFRESH_INTERVAL = 720 * 60 * 1e3, LOCK_NAME = "sanity-token-refresh-lock";
|
|
284
|
+
function getLastRefreshTime(storageArea, storageKey) {
|
|
285
|
+
try {
|
|
286
|
+
const data = storageArea?.getItem(`${storageKey}_last_refresh`), parsed = data ? parseInt(data, 10) : 0;
|
|
287
|
+
return isNaN(parsed) ? 0 : parsed;
|
|
288
|
+
} catch {
|
|
289
|
+
return 0;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function setLastRefreshTime(storageArea, storageKey) {
|
|
293
|
+
try {
|
|
294
|
+
storageArea?.setItem(`${storageKey}_last_refresh`, Date.now().toString());
|
|
295
|
+
} catch {
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function getNextRefreshDelay(storageArea, storageKey) {
|
|
299
|
+
const lastRefresh = getLastRefreshTime(storageArea, storageKey);
|
|
300
|
+
if (!lastRefresh) return 0;
|
|
301
|
+
const now = Date.now(), nextRefreshTime = lastRefresh + REFRESH_INTERVAL;
|
|
302
|
+
return Math.max(0, nextRefreshTime - now);
|
|
303
|
+
}
|
|
304
|
+
function createTokenRefreshStream(token, clientFactory, apiHost) {
|
|
305
|
+
return new Observable((subscriber) => {
|
|
306
|
+
const subscription = clientFactory({
|
|
307
|
+
apiVersion: DEFAULT_API_VERSION$1,
|
|
308
|
+
requestTagPrefix: REQUEST_TAG_PREFIX,
|
|
309
|
+
useProjectHostname: !1,
|
|
310
|
+
useCdn: !1,
|
|
311
|
+
token,
|
|
312
|
+
ignoreBrowserTokenWarning: !0,
|
|
313
|
+
...apiHost && { apiHost }
|
|
314
|
+
}).observable.request({
|
|
315
|
+
uri: "auth/refresh-token",
|
|
316
|
+
method: "POST",
|
|
317
|
+
tag: "refresh-token",
|
|
318
|
+
body: {
|
|
319
|
+
token
|
|
320
|
+
}
|
|
321
|
+
}).subscribe(subscriber);
|
|
322
|
+
return () => subscription.unsubscribe();
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
async function acquireTokenRefreshLock(refreshFn, storageArea, storageKey) {
|
|
326
|
+
if (!navigator.locks)
|
|
327
|
+
return console.warn("Web Locks API not supported. Proceeding with uncoordinated refresh."), await refreshFn(), setLastRefreshTime(storageArea, storageKey), !0;
|
|
328
|
+
try {
|
|
329
|
+
return await navigator.locks.request(LOCK_NAME, { mode: "exclusive" }, async (lock) => {
|
|
330
|
+
if (!lock) return !1;
|
|
331
|
+
for (; ; ) {
|
|
332
|
+
const delay = getNextRefreshDelay(storageArea, storageKey);
|
|
333
|
+
delay > 0 && await new Promise((resolve) => setTimeout(resolve, delay));
|
|
334
|
+
try {
|
|
335
|
+
await refreshFn(), setLastRefreshTime(storageArea, storageKey);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
console.error("Token refresh failed within lock:", error);
|
|
338
|
+
}
|
|
339
|
+
await new Promise((resolve) => setTimeout(resolve, REFRESH_INTERVAL));
|
|
340
|
+
}
|
|
341
|
+
}) === !0;
|
|
342
|
+
} catch (error) {
|
|
343
|
+
return console.error("Failed to request token refresh lock:", error), !1;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function shouldRefreshToken(lastRefresh) {
|
|
347
|
+
return lastRefresh ? Date.now() - lastRefresh >= REFRESH_INTERVAL : !0;
|
|
348
|
+
}
|
|
349
|
+
const refreshStampedToken = ({ state }) => {
|
|
350
|
+
const { clientFactory, apiHost, storageArea, storageKey } = state.get().options;
|
|
351
|
+
return state.observable.pipe(
|
|
352
|
+
map((storeState) => ({
|
|
353
|
+
authState: storeState.authState,
|
|
354
|
+
dashboardContext: storeState.dashboardContext
|
|
355
|
+
})),
|
|
356
|
+
filter(
|
|
357
|
+
(storeState) => storeState.authState.type === AuthStateType.LOGGED_IN
|
|
358
|
+
),
|
|
359
|
+
distinctUntilChanged(
|
|
360
|
+
(prev, curr) => prev.authState.type === curr.authState.type && prev.authState.token === curr.authState.token && // Only care about token for distinctness here
|
|
361
|
+
prev.dashboardContext === curr.dashboardContext
|
|
362
|
+
),
|
|
363
|
+
// Make distinctness check explicit
|
|
364
|
+
filter((storeState) => storeState.authState.token.includes("-st")),
|
|
365
|
+
// Ensure we only try to refresh stamped tokens
|
|
366
|
+
exhaustMap((storeState) => {
|
|
367
|
+
const performRefresh = async () => {
|
|
368
|
+
const currentState = state.get();
|
|
369
|
+
if (currentState.authState.type !== AuthStateType.LOGGED_IN)
|
|
370
|
+
throw new Error("User logged out before refresh could complete");
|
|
371
|
+
const currentToken = currentState.authState.token, response = await firstValueFrom(
|
|
372
|
+
createTokenRefreshStream(currentToken, clientFactory, apiHost)
|
|
373
|
+
);
|
|
374
|
+
state.set("setRefreshStampedToken", (prev) => ({
|
|
375
|
+
authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, token: response.token } : prev.authState
|
|
376
|
+
})), storageArea?.setItem(storageKey, JSON.stringify({ token: response.token }));
|
|
377
|
+
};
|
|
378
|
+
return storeState.dashboardContext ? new Observable((subscriber) => {
|
|
379
|
+
const visibilityHandler = () => {
|
|
380
|
+
const currentState = state.get();
|
|
381
|
+
document.visibilityState === "visible" && currentState.authState.type === AuthStateType.LOGGED_IN && shouldRefreshToken(currentState.authState.lastTokenRefresh) && createTokenRefreshStream(
|
|
382
|
+
currentState.authState.token,
|
|
383
|
+
clientFactory,
|
|
384
|
+
apiHost
|
|
385
|
+
).subscribe({
|
|
386
|
+
next: (response) => {
|
|
387
|
+
state.set("setRefreshStampedToken", (prev) => ({
|
|
388
|
+
authState: prev.authState.type === AuthStateType.LOGGED_IN ? {
|
|
389
|
+
...prev.authState,
|
|
390
|
+
token: response.token,
|
|
391
|
+
lastTokenRefresh: Date.now()
|
|
392
|
+
} : prev.authState
|
|
393
|
+
})), subscriber.next(response);
|
|
394
|
+
},
|
|
395
|
+
error: (error) => subscriber.error(error)
|
|
396
|
+
});
|
|
397
|
+
}, timerSubscription = timer(REFRESH_INTERVAL, REFRESH_INTERVAL).pipe(
|
|
398
|
+
filter(() => document.visibilityState === "visible"),
|
|
399
|
+
switchMap(() => {
|
|
400
|
+
const currentState = state.get().authState;
|
|
401
|
+
if (currentState.type !== AuthStateType.LOGGED_IN)
|
|
402
|
+
throw new Error("User logged out before refresh could complete");
|
|
403
|
+
return createTokenRefreshStream(currentState.token, clientFactory, apiHost);
|
|
404
|
+
})
|
|
405
|
+
).subscribe({
|
|
406
|
+
next: (response) => {
|
|
407
|
+
state.set("setRefreshStampedToken", (prev) => ({
|
|
408
|
+
authState: prev.authState.type === AuthStateType.LOGGED_IN ? {
|
|
409
|
+
...prev.authState,
|
|
410
|
+
token: response.token,
|
|
411
|
+
lastTokenRefresh: Date.now()
|
|
412
|
+
} : prev.authState
|
|
413
|
+
})), subscriber.next(response);
|
|
414
|
+
},
|
|
415
|
+
error: (error) => subscriber.error(error)
|
|
416
|
+
});
|
|
417
|
+
return document.addEventListener("visibilitychange", visibilityHandler), () => {
|
|
418
|
+
document.removeEventListener("visibilitychange", visibilityHandler), timerSubscription.unsubscribe();
|
|
419
|
+
};
|
|
420
|
+
}).pipe(
|
|
421
|
+
takeWhile(() => state.get().authState.type === AuthStateType.LOGGED_IN),
|
|
422
|
+
map((response) => ({ token: response.token }))
|
|
423
|
+
) : from(acquireTokenRefreshLock(performRefresh, storageArea, storageKey)).pipe(
|
|
424
|
+
filter((hasLock) => hasLock),
|
|
425
|
+
map(() => {
|
|
426
|
+
const currentState = state.get().authState;
|
|
427
|
+
if (currentState.type !== AuthStateType.LOGGED_IN)
|
|
428
|
+
throw new Error("User logged out before refresh could complete");
|
|
429
|
+
return { token: currentState.token };
|
|
430
|
+
})
|
|
431
|
+
);
|
|
432
|
+
})
|
|
433
|
+
).subscribe({
|
|
434
|
+
next: (response) => {
|
|
435
|
+
state.set("setRefreshStampedToken", (prev) => ({
|
|
436
|
+
authState: prev.authState.type === AuthStateType.LOGGED_IN ? {
|
|
437
|
+
...prev.authState,
|
|
438
|
+
token: response.token,
|
|
439
|
+
lastTokenRefresh: Date.now()
|
|
440
|
+
} : prev.authState
|
|
441
|
+
})), storageArea?.setItem(storageKey, JSON.stringify({ token: response.token }));
|
|
442
|
+
},
|
|
443
|
+
error: (error) => {
|
|
444
|
+
state.set("setRefreshStampedTokenError", { authState: { type: AuthStateType.ERROR, error } });
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
}, subscribeToStateAndFetchCurrentUser = ({ state, instance }, fetchOptions) => {
|
|
448
|
+
const { clientFactory, apiHost } = state.get().options, useProjectHostname = fetchOptions?.useProjectHostname ?? isStudioConfig(instance.config), projectId = instance.config.projectId;
|
|
449
|
+
return state.observable.pipe(
|
|
450
|
+
map(({ authState, options: storeOptions }) => ({
|
|
451
|
+
authState,
|
|
452
|
+
authMethod: storeOptions.authMethod
|
|
453
|
+
})),
|
|
454
|
+
filter(
|
|
455
|
+
(value) => value.authState.type === AuthStateType.LOGGED_IN && !value.authState.currentUser
|
|
456
|
+
),
|
|
457
|
+
map((value) => ({ token: value.authState.token, authMethod: value.authMethod })),
|
|
458
|
+
distinctUntilChanged(
|
|
459
|
+
(prev, curr) => prev.token === curr.token && prev.authMethod === curr.authMethod
|
|
460
|
+
)
|
|
461
|
+
).pipe(
|
|
462
|
+
map(
|
|
463
|
+
({ token, authMethod }) => clientFactory({
|
|
464
|
+
apiVersion: DEFAULT_API_VERSION$1,
|
|
465
|
+
requestTagPrefix: REQUEST_TAG_PREFIX,
|
|
466
|
+
token: authMethod === "cookie" ? void 0 : token,
|
|
467
|
+
ignoreBrowserTokenWarning: !0,
|
|
468
|
+
useProjectHostname,
|
|
469
|
+
useCdn: !1,
|
|
470
|
+
...authMethod === "cookie" ? { withCredentials: !0 } : {},
|
|
471
|
+
...useProjectHostname && projectId ? { projectId } : {},
|
|
472
|
+
...apiHost && { apiHost }
|
|
473
|
+
})
|
|
474
|
+
),
|
|
475
|
+
switchMap(
|
|
476
|
+
(client) => client.observable.request({
|
|
477
|
+
uri: "/users/me",
|
|
478
|
+
method: "GET",
|
|
479
|
+
tag: "users.get-current"
|
|
480
|
+
})
|
|
481
|
+
)
|
|
482
|
+
).subscribe({
|
|
483
|
+
next: (currentUser) => {
|
|
484
|
+
state.set("setCurrentUser", (prev) => ({
|
|
485
|
+
authState: prev.authState.type === AuthStateType.LOGGED_IN ? { ...prev.authState, currentUser } : prev.authState
|
|
486
|
+
}));
|
|
487
|
+
},
|
|
488
|
+
error: (error) => {
|
|
489
|
+
state.set("setError", { authState: { type: AuthStateType.ERROR, error } });
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
};
|
|
493
|
+
function createLoggedInAuthState(token, currentUser, existingLastTokenRefresh) {
|
|
494
|
+
const isStampedToken = token.includes("-st"), lastTokenRefresh = existingLastTokenRefresh ?? (isStampedToken ? Date.now() : void 0);
|
|
495
|
+
return {
|
|
496
|
+
type: AuthStateType.LOGGED_IN,
|
|
497
|
+
token,
|
|
498
|
+
currentUser,
|
|
499
|
+
...lastTokenRefresh !== void 0 && { lastTokenRefresh }
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
function getAuthCode(callbackUrl, locationHref) {
|
|
503
|
+
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;
|
|
504
|
+
let authCode = new URLSearchParams(loc.hash.slice(1)).get(AUTH_CODE_PARAM) || new URLSearchParams(loc.search).get(AUTH_CODE_PARAM);
|
|
505
|
+
if (!authCode) {
|
|
506
|
+
const contextParam = new URLSearchParams(loc.search).get("_context");
|
|
507
|
+
if (contextParam)
|
|
508
|
+
try {
|
|
509
|
+
const parsedContext = JSON.parse(contextParam);
|
|
510
|
+
parsedContext && typeof parsedContext == "object" && typeof parsedContext.sid == "string" && parsedContext.sid && (authCode = parsedContext.sid);
|
|
511
|
+
} catch {
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return authCode && callbackLocationMatches ? authCode : null;
|
|
515
|
+
}
|
|
516
|
+
function getTokenFromLocation(locationHref) {
|
|
517
|
+
const loc = new URL(locationHref);
|
|
518
|
+
return new URLSearchParams(loc.hash.slice(1)).get("token") || null;
|
|
519
|
+
}
|
|
520
|
+
function getTokenFromStorage(storageArea, storageKey) {
|
|
521
|
+
if (!storageArea) return null;
|
|
522
|
+
const item = storageArea.getItem(storageKey);
|
|
523
|
+
if (item === null) return null;
|
|
524
|
+
try {
|
|
525
|
+
const parsed = JSON.parse(item);
|
|
526
|
+
if (typeof parsed != "object" || parsed === null || !("token" in parsed) || typeof parsed.token != "string")
|
|
527
|
+
throw new Error("Invalid stored auth data structure");
|
|
528
|
+
return parsed.token;
|
|
529
|
+
} catch {
|
|
530
|
+
return storageArea.removeItem(storageKey), null;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
function getStorageEvents() {
|
|
534
|
+
return typeof window < "u" && typeof window.addEventListener == "function" ? fromEvent(window, "storage") : EMPTY;
|
|
535
|
+
}
|
|
536
|
+
function getDefaultStorage() {
|
|
537
|
+
try {
|
|
538
|
+
return typeof localStorage < "u" && typeof localStorage.getItem == "function" ? localStorage : void 0;
|
|
539
|
+
} catch {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
function getDefaultLocation() {
|
|
544
|
+
try {
|
|
545
|
+
return typeof location > "u" ? DEFAULT_BASE : typeof location.href == "string" ? location.href : DEFAULT_BASE;
|
|
546
|
+
} catch {
|
|
547
|
+
return DEFAULT_BASE;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
function getCleanedUrl(locationUrl) {
|
|
551
|
+
const loc = new URL(locationUrl), rawHash = loc.hash.startsWith("#") ? loc.hash.slice(1) : loc.hash;
|
|
552
|
+
if (rawHash && rawHash.includes("=")) {
|
|
553
|
+
const hashParams = new URLSearchParams(rawHash);
|
|
554
|
+
hashParams.delete("token"), hashParams.delete("withSid");
|
|
555
|
+
const nextHash = hashParams.toString();
|
|
556
|
+
loc.hash = nextHash ? `#${nextHash}` : "";
|
|
557
|
+
}
|
|
558
|
+
return loc.searchParams.delete("sid"), loc.searchParams.delete("url"), loc.toString();
|
|
559
|
+
}
|
|
560
|
+
function getClientErrorApiBody(error) {
|
|
561
|
+
const body = error.response?.body;
|
|
562
|
+
return body && typeof body == "object" ? body : void 0;
|
|
563
|
+
}
|
|
564
|
+
function getClientErrorApiType(error) {
|
|
565
|
+
const body = getClientErrorApiBody(error);
|
|
566
|
+
return body?.error?.type ?? body?.type;
|
|
567
|
+
}
|
|
568
|
+
function getClientErrorApiDescription(error) {
|
|
569
|
+
const body = getClientErrorApiBody(error);
|
|
570
|
+
return body?.error?.description ?? body?.description;
|
|
571
|
+
}
|
|
572
|
+
function isProjectUserNotFoundClientError(error) {
|
|
573
|
+
return getClientErrorApiType(error) === "projectUserNotFoundError";
|
|
574
|
+
}
|
|
575
|
+
function parseDashboardContext(locationHref) {
|
|
576
|
+
try {
|
|
577
|
+
const contextParam = new URL(locationHref, DEFAULT_BASE).searchParams.get("_context");
|
|
578
|
+
if (contextParam) {
|
|
579
|
+
const parsedContext = JSON.parse(contextParam);
|
|
580
|
+
if (parsedContext && typeof parsedContext == "object" && !Array.isArray(parsedContext) && Object.keys(parsedContext).length > 0)
|
|
581
|
+
return delete parsedContext.sid, parsedContext;
|
|
582
|
+
}
|
|
583
|
+
} catch (err) {
|
|
584
|
+
console.error("Failed to parse dashboard context from initial location:", err);
|
|
585
|
+
}
|
|
586
|
+
return {};
|
|
587
|
+
}
|
|
588
|
+
function getDashboardInitialState(options) {
|
|
589
|
+
const { authConfig, initialLocationHref } = options, providedToken = authConfig.token, callbackUrl = authConfig.callbackUrl, storageKey = "__sanity_auth_token", dashboardContext = parseDashboardContext(initialLocationHref), storageArea = void 0;
|
|
590
|
+
return providedToken ? {
|
|
591
|
+
authState: createLoggedInAuthState(providedToken, null),
|
|
592
|
+
storageKey,
|
|
593
|
+
storageArea,
|
|
594
|
+
authMethod: void 0,
|
|
595
|
+
dashboardContext
|
|
596
|
+
} : getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref) ? {
|
|
597
|
+
authState: { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 },
|
|
598
|
+
storageKey,
|
|
599
|
+
storageArea,
|
|
600
|
+
authMethod: void 0,
|
|
601
|
+
dashboardContext
|
|
602
|
+
} : {
|
|
603
|
+
authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 },
|
|
604
|
+
storageKey,
|
|
605
|
+
storageArea,
|
|
606
|
+
authMethod: void 0,
|
|
607
|
+
dashboardContext
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
function initializeDashboardAuth(context, tokenRefresherRunning2) {
|
|
611
|
+
const subscriptions = [];
|
|
612
|
+
let startedRefresher = !1;
|
|
613
|
+
return subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !1 })), tokenRefresherRunning2 || (startedRefresher = !0, subscriptions.push(refreshStampedToken(context))), {
|
|
614
|
+
dispose: () => {
|
|
615
|
+
for (const subscription of subscriptions)
|
|
616
|
+
subscription.unsubscribe();
|
|
617
|
+
},
|
|
618
|
+
tokenRefresherStarted: startedRefresher
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
const subscribeToStorageEventsAndSetToken = ({
|
|
622
|
+
state
|
|
623
|
+
}) => {
|
|
624
|
+
const { storageArea, storageKey } = state.get().options;
|
|
625
|
+
return defer(getStorageEvents).pipe(
|
|
626
|
+
filter(
|
|
627
|
+
(e) => e.storageArea === storageArea && e.key === storageKey
|
|
628
|
+
),
|
|
629
|
+
map(() => getTokenFromStorage(storageArea, storageKey)),
|
|
630
|
+
distinctUntilChanged()
|
|
631
|
+
).subscribe((token) => {
|
|
632
|
+
state.set("updateTokenFromStorageEvent", {
|
|
633
|
+
authState: token ? createLoggedInAuthState(token, null) : { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
|
|
634
|
+
});
|
|
635
|
+
});
|
|
636
|
+
};
|
|
637
|
+
function getStandaloneInitialState(options) {
|
|
638
|
+
const { authConfig, initialLocationHref } = options, providedToken = authConfig.token, callbackUrl = authConfig.callbackUrl, storageKey = "__sanity_auth_token", storageArea = authConfig.storageArea ?? getDefaultStorage();
|
|
639
|
+
if (providedToken)
|
|
640
|
+
return {
|
|
641
|
+
authState: createLoggedInAuthState(providedToken, null),
|
|
642
|
+
storageKey,
|
|
643
|
+
storageArea,
|
|
644
|
+
authMethod: void 0,
|
|
645
|
+
dashboardContext: {}
|
|
646
|
+
};
|
|
647
|
+
if (getAuthCode(callbackUrl, initialLocationHref) || getTokenFromLocation(initialLocationHref))
|
|
648
|
+
return {
|
|
649
|
+
authState: { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 },
|
|
650
|
+
storageKey,
|
|
651
|
+
storageArea,
|
|
652
|
+
authMethod: void 0,
|
|
653
|
+
dashboardContext: {}
|
|
654
|
+
};
|
|
655
|
+
const token = getTokenFromStorage(storageArea, storageKey);
|
|
656
|
+
return token ? {
|
|
657
|
+
authState: createLoggedInAuthState(token, null),
|
|
658
|
+
storageKey,
|
|
659
|
+
storageArea,
|
|
660
|
+
authMethod: "localstorage",
|
|
661
|
+
dashboardContext: {}
|
|
662
|
+
} : {
|
|
663
|
+
authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 },
|
|
664
|
+
storageKey,
|
|
665
|
+
storageArea,
|
|
666
|
+
authMethod: void 0,
|
|
667
|
+
dashboardContext: {}
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
function initializeStandaloneAuth(context, tokenRefresherRunning2) {
|
|
671
|
+
const subscriptions = [];
|
|
672
|
+
let startedRefresher = !1;
|
|
673
|
+
return subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !1 })), context.state.get().options?.storageArea && subscriptions.push(subscribeToStorageEventsAndSetToken(context)), tokenRefresherRunning2 || (startedRefresher = !0, subscriptions.push(refreshStampedToken(context))), {
|
|
674
|
+
dispose: () => {
|
|
675
|
+
for (const subscription of subscriptions)
|
|
676
|
+
subscription.unsubscribe();
|
|
677
|
+
},
|
|
678
|
+
tokenRefresherStarted: startedRefresher
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
const COOKIE_AUTH_TIMEOUT_MS = 1e4;
|
|
682
|
+
async function checkForCookieAuth(projectId, clientFactory) {
|
|
683
|
+
if (!projectId) return !1;
|
|
684
|
+
try {
|
|
685
|
+
const user = await clientFactory({
|
|
686
|
+
projectId,
|
|
687
|
+
useCdn: !1,
|
|
688
|
+
requestTagPrefix: REQUEST_TAG_PREFIX,
|
|
689
|
+
timeout: COOKIE_AUTH_TIMEOUT_MS
|
|
690
|
+
}).request({
|
|
691
|
+
uri: "/users/me",
|
|
692
|
+
withCredentials: !0,
|
|
693
|
+
tag: "users.get-current"
|
|
694
|
+
});
|
|
695
|
+
return user != null && typeof user == "object" && typeof user.id == "string";
|
|
696
|
+
} catch {
|
|
697
|
+
return !1;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
function getStudioTokenFromLocalStorage(storageArea, storageKey) {
|
|
701
|
+
return !storageArea || !storageKey ? null : getTokenFromStorage(storageArea, storageKey) || null;
|
|
702
|
+
}
|
|
703
|
+
function getStudioInitialState(options) {
|
|
704
|
+
const { authConfig, projectId, tokenSource } = options, storageArea = authConfig.storageArea ?? getDefaultStorage(), studioStorageKey = `__studio_auth_token_${projectId ?? ""}`;
|
|
705
|
+
if (tokenSource)
|
|
706
|
+
return {
|
|
707
|
+
authState: { type: AuthStateType.LOGGING_IN, isExchangingToken: !1 },
|
|
708
|
+
storageKey: studioStorageKey,
|
|
709
|
+
storageArea,
|
|
710
|
+
authMethod: void 0,
|
|
711
|
+
dashboardContext: {}
|
|
712
|
+
};
|
|
713
|
+
const providedToken = authConfig.token;
|
|
714
|
+
let authMethod;
|
|
715
|
+
const token = getStudioTokenFromLocalStorage(storageArea, studioStorageKey);
|
|
716
|
+
return token && (authMethod = "localstorage"), providedToken ? {
|
|
717
|
+
authState: createLoggedInAuthState(providedToken, null),
|
|
718
|
+
storageKey: studioStorageKey,
|
|
719
|
+
storageArea,
|
|
720
|
+
authMethod,
|
|
721
|
+
dashboardContext: {}
|
|
722
|
+
} : token ? {
|
|
723
|
+
authState: createLoggedInAuthState(token, null),
|
|
724
|
+
storageKey: studioStorageKey,
|
|
725
|
+
storageArea,
|
|
726
|
+
authMethod: "localstorage",
|
|
727
|
+
dashboardContext: {}
|
|
728
|
+
} : {
|
|
729
|
+
authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 },
|
|
730
|
+
storageKey: studioStorageKey,
|
|
731
|
+
storageArea,
|
|
732
|
+
authMethod: void 0,
|
|
733
|
+
dashboardContext: {}
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
function initializeStudioAuth(context, tokenRefresherRunning2) {
|
|
737
|
+
const tokenSource = context.instance.config.studio?.auth?.token;
|
|
738
|
+
return tokenSource ? initializeWithTokenSource(context, tokenSource) : initializeWithFallback(context, tokenRefresherRunning2);
|
|
739
|
+
}
|
|
740
|
+
function initializeWithTokenSource(context, tokenSource) {
|
|
741
|
+
const subscriptions = [], studioAuthenticated = context.instance.config.studio?.authenticated === !0;
|
|
742
|
+
subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !0 }));
|
|
743
|
+
const tokenSub = tokenSource.subscribe({
|
|
744
|
+
next: (token) => {
|
|
745
|
+
const { state } = context;
|
|
746
|
+
token ? state.set("studioTokenSource", (prev) => ({
|
|
747
|
+
options: { ...prev.options, authMethod: void 0 },
|
|
748
|
+
authState: createLoggedInAuthState(token, null)
|
|
749
|
+
})) : studioAuthenticated ? state.set("studioTokenSourceCookieAuth", (prev) => ({
|
|
750
|
+
options: { ...prev.options, authMethod: "cookie" },
|
|
751
|
+
authState: prev.authState.type === AuthStateType.LOGGED_IN ? prev.authState : createLoggedInAuthState("", null)
|
|
752
|
+
})) : state.set("studioTokenSourceLoggedOut", (prev) => ({
|
|
753
|
+
options: { ...prev.options, authMethod: void 0 },
|
|
754
|
+
authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
|
|
755
|
+
}));
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
return {
|
|
759
|
+
dispose: () => {
|
|
760
|
+
tokenSub.unsubscribe();
|
|
761
|
+
for (const subscription of subscriptions)
|
|
762
|
+
subscription.unsubscribe();
|
|
763
|
+
},
|
|
764
|
+
// Studio handles token refresh — do not start the SDK's refresher
|
|
765
|
+
tokenRefresherStarted: !1
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
function initializeWithFallback(context, tokenRefresherRunning2) {
|
|
769
|
+
const subscriptions = [];
|
|
770
|
+
let startedRefresher = !1;
|
|
771
|
+
subscriptions.push(subscribeToStateAndFetchCurrentUser(context, { useProjectHostname: !0 })), context.state.get().options?.storageArea && subscriptions.push(subscribeToStorageEventsAndSetToken(context));
|
|
772
|
+
try {
|
|
773
|
+
const { instance, state } = context;
|
|
774
|
+
if (!(state.get().authState?.type === AuthStateType.LOGGED_IN && state.get().authState.token)) {
|
|
775
|
+
const projectIdValue = instance.config.projectId, clientFactory = state.get().options.clientFactory;
|
|
776
|
+
checkForCookieAuth(projectIdValue, clientFactory).then((isCookieAuthEnabled) => {
|
|
777
|
+
isCookieAuthEnabled && state.set("enableCookieAuth", (prev) => ({
|
|
778
|
+
options: { ...prev.options, authMethod: "cookie" },
|
|
779
|
+
authState: prev.authState.type === AuthStateType.LOGGED_IN ? prev.authState : createLoggedInAuthState("", null)
|
|
780
|
+
}));
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
} catch {
|
|
784
|
+
}
|
|
785
|
+
return tokenRefresherRunning2 || (startedRefresher = !0, subscriptions.push(refreshStampedToken(context))), {
|
|
786
|
+
dispose: () => {
|
|
787
|
+
for (const subscription of subscriptions)
|
|
788
|
+
subscription.unsubscribe();
|
|
789
|
+
},
|
|
790
|
+
tokenRefresherStarted: startedRefresher
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
let tokenRefresherRunning = !1;
|
|
794
|
+
const authStore = {
|
|
795
|
+
name: "Auth",
|
|
796
|
+
getInitialState(instance) {
|
|
797
|
+
const {
|
|
798
|
+
apiHost: configApiHost,
|
|
799
|
+
callbackUrl,
|
|
800
|
+
providers: customProviders,
|
|
801
|
+
token: providedToken,
|
|
802
|
+
clientFactory = createClient,
|
|
803
|
+
initialLocationHref = getDefaultLocation()
|
|
804
|
+
} = instance.config.auth ?? {}, apiHost = configApiHost ?? getStagingApiHost(), authConfig = instance.config.auth ?? {};
|
|
805
|
+
let loginDomain = "https://www.sanity.io";
|
|
806
|
+
try {
|
|
807
|
+
apiHost && new URL(apiHost).hostname.endsWith(".sanity.work") && (loginDomain = "https://www.sanity.work");
|
|
808
|
+
} catch {
|
|
809
|
+
}
|
|
810
|
+
const loginUrl = new URL("/login", loginDomain);
|
|
811
|
+
loginUrl.searchParams.set("origin", getCleanedUrl(initialLocationHref)), loginUrl.searchParams.set("type", "stampedToken"), loginUrl.searchParams.set("withSid", "true");
|
|
812
|
+
const mode = resolveAuthMode(instance.config, initialLocationHref), strategyOptions = {
|
|
813
|
+
authConfig,
|
|
814
|
+
projectId: instance.config.projectId,
|
|
815
|
+
initialLocationHref,
|
|
816
|
+
tokenSource: instance.config.studio?.auth?.token
|
|
817
|
+
};
|
|
818
|
+
let result;
|
|
819
|
+
switch (mode) {
|
|
820
|
+
case "studio":
|
|
821
|
+
result = getStudioInitialState(strategyOptions);
|
|
822
|
+
break;
|
|
823
|
+
case "dashboard":
|
|
824
|
+
result = getDashboardInitialState(strategyOptions);
|
|
825
|
+
break;
|
|
826
|
+
case "standalone":
|
|
827
|
+
result = getStandaloneInitialState(strategyOptions);
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
return {
|
|
831
|
+
authState: result.authState,
|
|
832
|
+
dashboardContext: result.dashboardContext,
|
|
833
|
+
options: {
|
|
834
|
+
apiHost,
|
|
835
|
+
loginUrl: loginUrl.toString(),
|
|
836
|
+
callbackUrl,
|
|
837
|
+
customProviders,
|
|
838
|
+
providedToken,
|
|
839
|
+
clientFactory,
|
|
840
|
+
initialLocationHref,
|
|
841
|
+
storageKey: result.storageKey,
|
|
842
|
+
storageArea: result.storageArea,
|
|
843
|
+
authMethod: result.authMethod
|
|
844
|
+
}
|
|
845
|
+
};
|
|
846
|
+
},
|
|
847
|
+
initialize(context) {
|
|
848
|
+
const initialLocationHref = context.state.get().options?.initialLocationHref ?? getDefaultLocation(), mode = resolveAuthMode(context.instance.config, initialLocationHref);
|
|
849
|
+
let initResult;
|
|
850
|
+
switch (mode) {
|
|
851
|
+
case "studio":
|
|
852
|
+
initResult = initializeStudioAuth(context, tokenRefresherRunning);
|
|
853
|
+
break;
|
|
854
|
+
case "dashboard":
|
|
855
|
+
initResult = initializeDashboardAuth(context, tokenRefresherRunning);
|
|
856
|
+
break;
|
|
857
|
+
case "standalone":
|
|
858
|
+
initResult = initializeStandaloneAuth(context, tokenRefresherRunning);
|
|
859
|
+
break;
|
|
860
|
+
}
|
|
861
|
+
return initResult.tokenRefresherStarted && (tokenRefresherRunning = !0), initResult.dispose;
|
|
862
|
+
}
|
|
863
|
+
}, getCurrentUserState = bindActionGlobally(
|
|
864
|
+
authStore,
|
|
865
|
+
createStateSourceAction(
|
|
866
|
+
({ state: { authState } }) => authState.type === AuthStateType.LOGGED_IN ? authState.currentUser : null
|
|
867
|
+
)
|
|
868
|
+
), getTokenState = bindActionGlobally(
|
|
869
|
+
authStore,
|
|
870
|
+
createStateSourceAction(
|
|
871
|
+
({ state: { authState } }) => authState.type === AuthStateType.LOGGED_IN ? authState.token : null
|
|
872
|
+
)
|
|
873
|
+
), getAuthMethodState = bindActionGlobally(
|
|
874
|
+
authStore,
|
|
875
|
+
createStateSourceAction(({ state: { options } }) => options.authMethod)
|
|
876
|
+
), getLoginUrlState = bindActionGlobally(
|
|
877
|
+
authStore,
|
|
878
|
+
createStateSourceAction(({ state: { options } }) => options.loginUrl)
|
|
879
|
+
), getAuthState = bindActionGlobally(
|
|
880
|
+
authStore,
|
|
881
|
+
createStateSourceAction(({ state: { authState } }) => authState)
|
|
882
|
+
), getDashboardOrganizationId = bindActionGlobally(
|
|
883
|
+
authStore,
|
|
884
|
+
createStateSourceAction(({ state: { dashboardContext } }) => dashboardContext?.orgId)
|
|
885
|
+
), getIsInDashboardState = bindActionGlobally(
|
|
886
|
+
authStore,
|
|
887
|
+
createStateSourceAction(
|
|
888
|
+
({ state: { dashboardContext } }) => (
|
|
889
|
+
// Check if dashboardContext exists and is not empty
|
|
890
|
+
!!dashboardContext && Object.keys(dashboardContext).length > 0
|
|
891
|
+
)
|
|
892
|
+
)
|
|
893
|
+
), setAuthToken = bindActionGlobally(authStore, ({ state }, token) => {
|
|
894
|
+
const currentAuthState = state.get().authState;
|
|
895
|
+
if (token) {
|
|
896
|
+
if (currentAuthState.type !== AuthStateType.LOGGED_IN || currentAuthState.token !== token) {
|
|
897
|
+
const currentUser = currentAuthState.type === AuthStateType.LOGGED_IN ? currentAuthState.currentUser : null, preservedLastTokenRefresh = currentAuthState.type === AuthStateType.LOGGED_IN ? currentAuthState.lastTokenRefresh : void 0;
|
|
898
|
+
state.set("setToken", {
|
|
899
|
+
authState: createLoggedInAuthState(token, currentUser, preservedLastTokenRefresh)
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
} else
|
|
903
|
+
currentAuthState.type !== AuthStateType.LOGGED_OUT && state.set("setToken", {
|
|
904
|
+
authState: { type: AuthStateType.LOGGED_OUT, isDestroyingSession: !1 }
|
|
905
|
+
});
|
|
906
|
+
});
|
|
907
|
+
var authStore$1 = /* @__PURE__ */ Object.freeze({
|
|
908
|
+
__proto__: null,
|
|
909
|
+
authStore,
|
|
910
|
+
getAuthMethodState,
|
|
911
|
+
getAuthState,
|
|
912
|
+
getCurrentUserState,
|
|
913
|
+
getDashboardOrganizationId,
|
|
914
|
+
getIsInDashboardState,
|
|
915
|
+
getLoginUrlState,
|
|
916
|
+
getTokenState,
|
|
917
|
+
setAuthToken
|
|
918
|
+
});
|
|
919
|
+
const DEFAULT_API_VERSION = "2024-11-12", DEFAULT_REQUEST_TAG_PREFIX = "sanity.sdk", allowedKeys = Object.keys({
|
|
920
|
+
apiHost: null,
|
|
921
|
+
useCdn: null,
|
|
922
|
+
token: null,
|
|
923
|
+
perspective: null,
|
|
924
|
+
proxy: null,
|
|
925
|
+
withCredentials: null,
|
|
926
|
+
timeout: null,
|
|
927
|
+
maxRetries: null,
|
|
928
|
+
dataset: null,
|
|
929
|
+
projectId: null,
|
|
930
|
+
scope: null,
|
|
931
|
+
apiVersion: null,
|
|
932
|
+
requestTagPrefix: null,
|
|
933
|
+
useProjectHostname: null,
|
|
934
|
+
"~experimental_resource": null,
|
|
935
|
+
source: null
|
|
936
|
+
}), DEFAULT_CLIENT_CONFIG = {
|
|
937
|
+
apiVersion: DEFAULT_API_VERSION,
|
|
938
|
+
useCdn: !1,
|
|
939
|
+
ignoreBrowserTokenWarning: !0,
|
|
940
|
+
allowReconfigure: !1,
|
|
941
|
+
requestTagPrefix: DEFAULT_REQUEST_TAG_PREFIX
|
|
942
|
+
}, clientStore = {
|
|
943
|
+
name: "clientStore",
|
|
944
|
+
getInitialState: (instance) => ({
|
|
945
|
+
clients: {},
|
|
946
|
+
token: getTokenState(instance).getCurrent()
|
|
947
|
+
}),
|
|
948
|
+
initialize(context) {
|
|
949
|
+
const subscription = listenToToken(context), authMethodSubscription = listenToAuthMethod(context);
|
|
950
|
+
return () => {
|
|
951
|
+
subscription.unsubscribe(), authMethodSubscription.unsubscribe();
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
}, listenToToken = ({ instance, state }) => getTokenState(instance).observable.subscribe((token) => {
|
|
955
|
+
state.set("setTokenAndResetClients", { token, clients: {} });
|
|
956
|
+
}), listenToAuthMethod = ({ instance, state }) => getAuthMethodState(instance).observable.subscribe((authMethod) => {
|
|
957
|
+
state.set("setAuthMethod", { authMethod });
|
|
958
|
+
}), getClientConfigKey = (options) => JSON.stringify(pick(options, ...allowedKeys)), getClient = bindActionGlobally(
|
|
959
|
+
clientStore,
|
|
960
|
+
({ state, instance }, options) => {
|
|
961
|
+
if (!options || typeof options != "object")
|
|
962
|
+
throw new Error(
|
|
963
|
+
'getClient() requires a configuration object with at least an "apiVersion" property. Example: getClient(instance, { apiVersion: "2024-11-12" })'
|
|
964
|
+
);
|
|
965
|
+
const disallowedKeys = Object.keys(options).filter((key2) => !allowedKeys.includes(key2));
|
|
966
|
+
if (disallowedKeys.length > 0) {
|
|
967
|
+
const listFormatter = new Intl.ListFormat("en", { style: "long", type: "conjunction" });
|
|
968
|
+
throw new Error(
|
|
969
|
+
`The client options provided contains unsupported properties: ${listFormatter.format(disallowedKeys)}. Allowed keys are: ${listFormatter.format(allowedKeys)}.`
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
const tokenFromState = state.get().token, { clients, authMethod } = state.get();
|
|
973
|
+
let resource;
|
|
974
|
+
options.source && (isDatasetSource(options.source) ? resource = { type: "dataset", id: `${options.source.projectId}.${options.source.dataset}` } : isMediaLibrarySource(options.source) ? resource = { type: "media-library", id: options.source.mediaLibraryId } : isCanvasSource(options.source) && (resource = { type: "canvas", id: options.source.canvasId }));
|
|
975
|
+
const projectId = options.projectId ?? instance.config.projectId, dataset = options.dataset ?? instance.config.dataset, apiHost = options.apiHost ?? instance.config.auth?.apiHost ?? getStagingApiHost(), effectiveOptions = {
|
|
976
|
+
...DEFAULT_CLIENT_CONFIG,
|
|
977
|
+
...(options.scope === "global" || !projectId || resource) && { useProjectHostname: !1 },
|
|
978
|
+
token: authMethod === "cookie" ? void 0 : tokenFromState ?? void 0,
|
|
979
|
+
...options,
|
|
980
|
+
...projectId && { projectId },
|
|
981
|
+
...dataset && { dataset },
|
|
982
|
+
...apiHost && { apiHost },
|
|
983
|
+
...resource && { "~experimental_resource": resource }
|
|
984
|
+
};
|
|
985
|
+
resource && ((options.projectId || options.dataset) && console.warn(
|
|
986
|
+
"Both source and explicit projectId/dataset are provided. The source will be used and projectId/dataset will be ignored."
|
|
987
|
+
), delete effectiveOptions.projectId, delete effectiveOptions.dataset), effectiveOptions.token === null || typeof effectiveOptions.token > "u" ? (delete effectiveOptions.token, authMethod === "cookie" && (effectiveOptions.withCredentials = !0)) : delete effectiveOptions.withCredentials;
|
|
988
|
+
const key = getClientConfigKey(effectiveOptions);
|
|
989
|
+
if (clients[key]) return clients[key];
|
|
990
|
+
const client = createClient(effectiveOptions);
|
|
991
|
+
return state.set("addClient", (prev) => ({ clients: { ...prev.clients, [key]: client } })), client;
|
|
992
|
+
}
|
|
993
|
+
), getClientState = bindActionGlobally(
|
|
994
|
+
clientStore,
|
|
995
|
+
createStateSourceAction(({ instance }, options) => getClient(instance, options))
|
|
996
|
+
);
|
|
997
|
+
var clientStore$1 = /* @__PURE__ */ Object.freeze({
|
|
998
|
+
__proto__: null,
|
|
999
|
+
getClient,
|
|
1000
|
+
getClientState
|
|
1001
|
+
});
|
|
1002
|
+
function setCleanupTimeout(fn, delay) {
|
|
1003
|
+
const timer2 = setTimeout(fn, delay), t = timer2;
|
|
1004
|
+
return typeof t == "object" && t !== null && "unref" in t && typeof t.unref == "function" && t.unref(), timer2;
|
|
1005
|
+
}
|
|
1006
|
+
const API_VERSION$1 = "vX", PROJECT_API_VERSION = "2025-07-18", USERS_STATE_CLEAR_DELAY = 5e3, DEFAULT_USERS_BATCH_SIZE = 100, getUsersKey = (instance, {
|
|
1007
|
+
resourceType,
|
|
1008
|
+
organizationId,
|
|
1009
|
+
batchSize = DEFAULT_USERS_BATCH_SIZE,
|
|
1010
|
+
projectId = instance.config.projectId,
|
|
1011
|
+
userId
|
|
1012
|
+
} = {}) => JSON.stringify({
|
|
1013
|
+
resourceType,
|
|
1014
|
+
organizationId,
|
|
1015
|
+
batchSize,
|
|
1016
|
+
projectId,
|
|
1017
|
+
userId
|
|
1018
|
+
}), parseUsersKey = (key) => JSON.parse(key), addSubscription = (subscriptionId, key) => (prev) => {
|
|
1019
|
+
const group = prev.users[key], subscriptions = [...group?.subscriptions ?? [], subscriptionId];
|
|
1020
|
+
return { ...prev, users: { ...prev.users, [key]: { ...group, subscriptions } } };
|
|
1021
|
+
}, removeSubscription = (subscriptionId, key) => (prev) => {
|
|
1022
|
+
const group = prev.users[key];
|
|
1023
|
+
if (!group) return prev;
|
|
1024
|
+
const subscriptions = group.subscriptions.filter((id) => id !== subscriptionId);
|
|
1025
|
+
return subscriptions.length ? { ...prev, users: { ...prev.users, [key]: { ...group, subscriptions } } } : { ...prev, users: omit(prev.users, key) };
|
|
1026
|
+
}, setUsersData = (key, { data, nextCursor, totalCount }) => (prev) => {
|
|
1027
|
+
const group = prev.users[key];
|
|
1028
|
+
if (!group) return prev;
|
|
1029
|
+
const users = [...group.users ?? [], ...data];
|
|
1030
|
+
return { ...prev, users: { ...prev.users, [key]: { ...group, users, totalCount, nextCursor } } };
|
|
1031
|
+
}, updateLastLoadMoreRequest = (timestamp, key) => (prev) => {
|
|
1032
|
+
const group = prev.users[key];
|
|
1033
|
+
return group ? { ...prev, users: { ...prev.users, [key]: { ...group, lastLoadMoreRequest: timestamp } } } : prev;
|
|
1034
|
+
}, setUsersError = (key, error) => (prev) => {
|
|
1035
|
+
const group = prev.users[key];
|
|
1036
|
+
return group ? { ...prev, users: { ...prev.users, [key]: { ...group, error } } } : prev;
|
|
1037
|
+
}, cancelRequest = (key) => (prev) => {
|
|
1038
|
+
const group = prev.users[key];
|
|
1039
|
+
return !group || group.subscriptions.length ? prev : { ...prev, users: omit(prev.users, key) };
|
|
1040
|
+
}, initializeRequest = (key) => (prev) => prev.users[key] ? prev : { ...prev, users: { ...prev.users, [key]: { subscriptions: [] } } };
|
|
1041
|
+
function sortReleases(releases = []) {
|
|
1042
|
+
return [...releases].sort((a, b) => {
|
|
1043
|
+
if (a.metadata.releaseType === "undecided" && b.metadata.releaseType !== "undecided")
|
|
1044
|
+
return -1;
|
|
1045
|
+
if (a.metadata.releaseType !== "undecided" && b.metadata.releaseType === "undecided")
|
|
1046
|
+
return 1;
|
|
1047
|
+
if (a.metadata.releaseType === "undecided" && b.metadata.releaseType === "undecided")
|
|
1048
|
+
return new Date(b._createdAt).getTime() - new Date(a._createdAt).getTime();
|
|
1049
|
+
if (a.metadata.releaseType === "scheduled" && b.metadata.releaseType === "scheduled") {
|
|
1050
|
+
const aPublishAt = a.publishAt || a.metadata.intendedPublishAt;
|
|
1051
|
+
if (!aPublishAt)
|
|
1052
|
+
return 1;
|
|
1053
|
+
const bPublishAt = b.publishAt || b.metadata.intendedPublishAt;
|
|
1054
|
+
return bPublishAt ? new Date(bPublishAt).getTime() - new Date(aPublishAt).getTime() : -1;
|
|
1055
|
+
}
|
|
1056
|
+
return a.metadata.releaseType === "asap" && b.metadata.releaseType !== "asap" ? 1 : a.metadata.releaseType !== "asap" && b.metadata.releaseType === "asap" ? -1 : a.metadata.releaseType === "asap" && b.metadata.releaseType === "asap" ? new Date(b._createdAt).getTime() - new Date(a._createdAt).getTime() : 0;
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
const ARCHIVED_RELEASE_STATES = ["archived", "published"], STABLE_EMPTY_RELEASES = [], releasesStore = {
|
|
1060
|
+
name: "Releases",
|
|
1061
|
+
getInitialState: () => ({
|
|
1062
|
+
activeReleases: void 0
|
|
1063
|
+
}),
|
|
1064
|
+
initialize: (context) => {
|
|
1065
|
+
const subscription = subscribeToReleases(context);
|
|
1066
|
+
return () => subscription.unsubscribe();
|
|
1067
|
+
}
|
|
1068
|
+
}, _getActiveReleasesState = bindActionBySource(
|
|
1069
|
+
releasesStore,
|
|
1070
|
+
createStateSourceAction({
|
|
1071
|
+
selector: ({ state }, _) => state.activeReleases
|
|
1072
|
+
})
|
|
1073
|
+
), getActiveReleasesState = (instance, options) => (
|
|
1074
|
+
// bindActionBySource keyFn destructures { source } from the first param, so pass {} when no options
|
|
1075
|
+
_getActiveReleasesState(instance, options ?? {})
|
|
1076
|
+
), RELEASES_QUERY = "releases::all()", subscribeToReleases = ({
|
|
1077
|
+
instance,
|
|
1078
|
+
state,
|
|
1079
|
+
key: { source }
|
|
1080
|
+
}) => {
|
|
1081
|
+
const { observable: releases$ } = getQueryState(instance, {
|
|
1082
|
+
query: RELEASES_QUERY,
|
|
1083
|
+
perspective: "raw",
|
|
1084
|
+
source: source && !isDatasetSource(source) ? source : void 0,
|
|
1085
|
+
tag: "releases"
|
|
1086
|
+
});
|
|
1087
|
+
return releases$.pipe(
|
|
1088
|
+
map((releases) => {
|
|
1089
|
+
state.set("setActiveReleases", {
|
|
1090
|
+
activeReleases: sortReleases(releases ?? STABLE_EMPTY_RELEASES).filter((release) => !ARCHIVED_RELEASE_STATES.includes(release.state)).reverse()
|
|
1091
|
+
});
|
|
1092
|
+
})
|
|
1093
|
+
).subscribe({ error: (error) => state.set("setError", { error }) });
|
|
1094
|
+
}, DEFAULT_PERSPECTIVE = "drafts", optionsCache = /* @__PURE__ */ new Map(), selectInstancePerspective = (context, _) => context.instance.config.perspective, selectActiveReleases = (context) => context.state.activeReleases, selectOptions = (_context, options) => options, memoizedOptionsSelector = createSelector(
|
|
1095
|
+
[selectActiveReleases, selectOptions],
|
|
1096
|
+
(activeReleases, options) => {
|
|
1097
|
+
if (!options || !activeReleases) return options;
|
|
1098
|
+
const releaseIds = activeReleases.map((release) => release._id).join(",");
|
|
1099
|
+
let nestedCache = optionsCache.get(releaseIds);
|
|
1100
|
+
nestedCache || (nestedCache = /* @__PURE__ */ new Map(), optionsCache.set(releaseIds, nestedCache));
|
|
1101
|
+
const optionsKey = JSON.stringify(options);
|
|
1102
|
+
let cachedOptions = nestedCache.get(optionsKey);
|
|
1103
|
+
return cachedOptions || (cachedOptions = options, nestedCache.set(optionsKey, cachedOptions)), cachedOptions;
|
|
1104
|
+
}
|
|
1105
|
+
), _getPerspectiveStateSelector = createStateSourceAction({
|
|
1106
|
+
selector: createSelector(
|
|
1107
|
+
[selectInstancePerspective, selectActiveReleases, memoizedOptionsSelector],
|
|
1108
|
+
(instancePerspective, activeReleases, memoizedOptions) => {
|
|
1109
|
+
const perspective = memoizedOptions?.perspective ?? instancePerspective ?? DEFAULT_PERSPECTIVE;
|
|
1110
|
+
if (!isReleasePerspective(perspective)) return perspective;
|
|
1111
|
+
if (!activeReleases || activeReleases.length === 0) return;
|
|
1112
|
+
const releaseNames = sortReleases(activeReleases).map((release) => release.name), index = releaseNames.findIndex((name) => name === perspective.releaseName);
|
|
1113
|
+
if (index < 0)
|
|
1114
|
+
throw new Error(`Release "${perspective.releaseName}" not found in active releases`);
|
|
1115
|
+
return ["drafts", ...releaseNames.slice(0, index + 1)].filter((name) => !perspective.excludedPerspectives?.includes(name)).reverse();
|
|
1116
|
+
}
|
|
1117
|
+
)
|
|
1118
|
+
});
|
|
1119
|
+
let _boundGetPerspectiveState;
|
|
1120
|
+
const getPerspectiveState = (instance, ...rest) => (_boundGetPerspectiveState || (_boundGetPerspectiveState = bindActionBySource(
|
|
1121
|
+
releasesStore,
|
|
1122
|
+
_getPerspectiveStateSelector
|
|
1123
|
+
)), _boundGetPerspectiveState(instance, ...rest.length ? rest : [{}])), QUERY_STATE_CLEAR_DELAY = 1e3, QUERY_STORE_API_VERSION = "v2025-05-06", QUERY_STORE_DEFAULT_PERSPECTIVE = "drafts", setQueryError = (key, error) => (prev) => {
|
|
1124
|
+
const prevQuery = prev.queries[key];
|
|
1125
|
+
return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, error } } } : prev;
|
|
1126
|
+
}, setQueryData = (key, result, syncTags) => (prev) => {
|
|
1127
|
+
const prevQuery = prev.queries[key];
|
|
1128
|
+
return prevQuery ? {
|
|
1129
|
+
...prev,
|
|
1130
|
+
queries: { ...prev.queries, [key]: { ...prevQuery, result: result ?? null, syncTags } }
|
|
1131
|
+
} : prev;
|
|
1132
|
+
}, setLastLiveEventId = (key, lastLiveEventId) => (prev) => {
|
|
1133
|
+
const prevQuery = prev.queries[key];
|
|
1134
|
+
return prevQuery ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, lastLiveEventId } } } : prev;
|
|
1135
|
+
}, addSubscriber = (key, subscriptionId) => (prev) => {
|
|
1136
|
+
const prevQuery = prev.queries[key], subscribers = [...prevQuery?.subscribers ?? [], subscriptionId];
|
|
1137
|
+
return { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, subscribers } } };
|
|
1138
|
+
}, removeSubscriber = (key, subscriptionId) => (prev) => {
|
|
1139
|
+
const prevQuery = prev.queries[key];
|
|
1140
|
+
if (!prevQuery) return prev;
|
|
1141
|
+
const subscribers = prevQuery.subscribers.filter((id) => id !== subscriptionId);
|
|
1142
|
+
return subscribers.length ? { ...prev, queries: { ...prev.queries, [key]: { ...prevQuery, subscribers } } } : { ...prev, queries: omit(prev.queries, key) };
|
|
1143
|
+
}, cancelQuery = (key) => (prev) => {
|
|
1144
|
+
const prevQuery = prev.queries[key];
|
|
1145
|
+
return !prevQuery || prevQuery.subscribers.length ? prev : { ...prev, queries: omit(prev.queries, key) };
|
|
1146
|
+
}, initializeQuery = (key) => (prev) => prev.queries[key] ? prev : { ...prev, queries: { ...prev.queries, [key]: { subscribers: [] } } }, EMPTY_ARRAY = [], getQueryKey = (options) => JSON.stringify(options), parseQueryKey = (key) => JSON.parse(key);
|
|
1147
|
+
function normalizeOptionsWithPerspective(instance, options) {
|
|
1148
|
+
if (options.perspective !== void 0) return options;
|
|
1149
|
+
const instancePerspective = instance.config.perspective;
|
|
1150
|
+
return {
|
|
1151
|
+
...options,
|
|
1152
|
+
perspective: instancePerspective !== void 0 ? instancePerspective : QUERY_STORE_DEFAULT_PERSPECTIVE
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
const queryStore = {
|
|
1156
|
+
name: "QueryStore",
|
|
1157
|
+
getInitialState: () => ({ queries: {} }),
|
|
1158
|
+
initialize(context) {
|
|
1159
|
+
const subscriptions = [
|
|
1160
|
+
listenForNewSubscribersAndFetch(context),
|
|
1161
|
+
listenToLiveClientAndSetLastLiveEventIds(context)
|
|
1162
|
+
];
|
|
1163
|
+
return () => {
|
|
1164
|
+
for (const subscription of subscriptions)
|
|
1165
|
+
subscription.unsubscribe();
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
}, errorHandler = (state) => (error) => state.set("setError", { error }), listenForNewSubscribersAndFetch = ({ state, instance }) => state.observable.pipe(
|
|
1169
|
+
map((s) => new Set(Object.keys(s.queries))),
|
|
1170
|
+
distinctUntilChanged((curr, next) => curr.size !== next.size ? !1 : Array.from(next).every((i) => curr.has(i))),
|
|
1171
|
+
startWith(/* @__PURE__ */ new Set()),
|
|
1172
|
+
pairwise(),
|
|
1173
|
+
mergeMap(([curr, next]) => {
|
|
1174
|
+
const added = Array.from(next).filter((i) => !curr.has(i)), removed = Array.from(curr).filter((i) => !next.has(i));
|
|
1175
|
+
return [
|
|
1176
|
+
...added.map((key) => ({ key, added: !0 })),
|
|
1177
|
+
...removed.map((key) => ({ key, added: !1 }))
|
|
1178
|
+
];
|
|
1179
|
+
}),
|
|
1180
|
+
groupBy((i) => i.key),
|
|
1181
|
+
mergeMap(
|
|
1182
|
+
(group$) => group$.pipe(
|
|
1183
|
+
switchMap((e) => {
|
|
1184
|
+
if (!e.added) return EMPTY;
|
|
1185
|
+
const lastLiveEventId$ = state.observable.pipe(
|
|
1186
|
+
map((s) => s.queries[group$.key]?.lastLiveEventId),
|
|
1187
|
+
distinctUntilChanged()
|
|
1188
|
+
), {
|
|
1189
|
+
query,
|
|
1190
|
+
params,
|
|
1191
|
+
projectId,
|
|
1192
|
+
dataset,
|
|
1193
|
+
tag,
|
|
1194
|
+
source,
|
|
1195
|
+
perspective: perspectiveFromOptions,
|
|
1196
|
+
...restOptions
|
|
1197
|
+
} = parseQueryKey(group$.key), perspective$ = isReleasePerspective(perspectiveFromOptions) ? getPerspectiveState(instance, {
|
|
1198
|
+
perspective: perspectiveFromOptions
|
|
1199
|
+
}).observable.pipe(filter(Boolean)) : of(perspectiveFromOptions ?? QUERY_STORE_DEFAULT_PERSPECTIVE), client$ = getClientState(instance, {
|
|
1200
|
+
apiVersion: QUERY_STORE_API_VERSION,
|
|
1201
|
+
projectId,
|
|
1202
|
+
dataset,
|
|
1203
|
+
source
|
|
1204
|
+
}).observable;
|
|
1205
|
+
return combineLatest({
|
|
1206
|
+
lastLiveEventId: lastLiveEventId$,
|
|
1207
|
+
client: client$,
|
|
1208
|
+
perspective: perspective$
|
|
1209
|
+
}).pipe(
|
|
1210
|
+
switchMap(
|
|
1211
|
+
({ lastLiveEventId, client, perspective }) => client.observable.fetch(query, params, {
|
|
1212
|
+
...restOptions,
|
|
1213
|
+
perspective,
|
|
1214
|
+
filterResponse: !1,
|
|
1215
|
+
returnQuery: !1,
|
|
1216
|
+
lastLiveEventId,
|
|
1217
|
+
tag
|
|
1218
|
+
})
|
|
1219
|
+
)
|
|
1220
|
+
);
|
|
1221
|
+
}),
|
|
1222
|
+
catchError((error) => (state.set("setQueryError", setQueryError(group$.key, error)), EMPTY)),
|
|
1223
|
+
tap(({ result, syncTags }) => {
|
|
1224
|
+
state.set("setQueryData", setQueryData(group$.key, result, syncTags));
|
|
1225
|
+
})
|
|
1226
|
+
)
|
|
1227
|
+
)
|
|
1228
|
+
).subscribe({ error: errorHandler(state) }), listenToLiveClientAndSetLastLiveEventIds = ({
|
|
1229
|
+
state,
|
|
1230
|
+
instance,
|
|
1231
|
+
key: { source }
|
|
1232
|
+
}) => {
|
|
1233
|
+
const liveMessages$ = getClientState(instance, {
|
|
1234
|
+
apiVersion: QUERY_STORE_API_VERSION,
|
|
1235
|
+
// temporary guard here until we're ready for everything to be queried via global api
|
|
1236
|
+
...source && !isDatasetSource(source) ? { source } : {}
|
|
1237
|
+
}).observable.pipe(
|
|
1238
|
+
switchMap(
|
|
1239
|
+
(client) => defer(
|
|
1240
|
+
() => client.live.events({ includeDrafts: !!client.config().token, tag: "query-store" })
|
|
1241
|
+
).pipe(
|
|
1242
|
+
catchError((error) => {
|
|
1243
|
+
if (error instanceof CorsOriginError)
|
|
1244
|
+
return state.set("setError", { error }), EMPTY;
|
|
1245
|
+
throw error;
|
|
1246
|
+
})
|
|
1247
|
+
)
|
|
1248
|
+
),
|
|
1249
|
+
share(),
|
|
1250
|
+
filter((e) => e.type === "message")
|
|
1251
|
+
);
|
|
1252
|
+
return state.observable.pipe(
|
|
1253
|
+
mergeMap((s) => Object.entries(s.queries)),
|
|
1254
|
+
groupBy(([key]) => key),
|
|
1255
|
+
mergeMap((group$) => {
|
|
1256
|
+
const syncTags$ = group$.pipe(
|
|
1257
|
+
map(([, queryState]) => queryState),
|
|
1258
|
+
map((i) => i?.syncTags ?? EMPTY_ARRAY),
|
|
1259
|
+
distinctUntilChanged()
|
|
1260
|
+
);
|
|
1261
|
+
return combineLatest([liveMessages$, syncTags$]).pipe(
|
|
1262
|
+
filter(([message, syncTags]) => message.tags.some((tag) => syncTags.includes(tag))),
|
|
1263
|
+
tap(([message]) => {
|
|
1264
|
+
state.set("setLastLiveEventId", setLastLiveEventId(group$.key, message.id));
|
|
1265
|
+
})
|
|
1266
|
+
);
|
|
1267
|
+
})
|
|
1268
|
+
).subscribe({ error: errorHandler(state) });
|
|
1269
|
+
};
|
|
1270
|
+
function getQueryState(...args) {
|
|
1271
|
+
return _getQueryState(...args);
|
|
1272
|
+
}
|
|
1273
|
+
const _getQueryState = bindActionBySource(
|
|
1274
|
+
queryStore,
|
|
1275
|
+
createStateSourceAction({
|
|
1276
|
+
selector: ({ state, instance }, options) => {
|
|
1277
|
+
if (state.error) throw state.error;
|
|
1278
|
+
const key = getQueryKey(normalizeOptionsWithPerspective(instance, options)), queryState = state.queries[key];
|
|
1279
|
+
if (queryState?.error) throw queryState.error;
|
|
1280
|
+
return queryState?.result;
|
|
1281
|
+
},
|
|
1282
|
+
onSubscribe: ({ state, instance }, options) => {
|
|
1283
|
+
const subscriptionId = insecureRandomId(), key = getQueryKey(normalizeOptionsWithPerspective(instance, options));
|
|
1284
|
+
return state.set("addSubscriber", addSubscriber(key, subscriptionId)), () => {
|
|
1285
|
+
setCleanupTimeout(
|
|
1286
|
+
() => state.set("removeSubscriber", removeSubscriber(key, subscriptionId)),
|
|
1287
|
+
QUERY_STATE_CLEAR_DELAY
|
|
1288
|
+
);
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
})
|
|
1292
|
+
);
|
|
1293
|
+
function resolveQuery(...args) {
|
|
1294
|
+
return _resolveQuery(...args);
|
|
1295
|
+
}
|
|
1296
|
+
const _resolveQuery = bindActionBySource(
|
|
1297
|
+
queryStore,
|
|
1298
|
+
({ state, instance }, { signal, ...options }) => {
|
|
1299
|
+
const normalized = normalizeOptionsWithPerspective(instance, options), { getCurrent } = getQueryState(instance, normalized), key = getQueryKey(normalized), aborted$ = signal ? new Observable((observer) => {
|
|
1300
|
+
const cleanup = () => {
|
|
1301
|
+
signal.removeEventListener("abort", listener);
|
|
1302
|
+
}, listener = () => {
|
|
1303
|
+
observer.error(new DOMException("The operation was aborted.", "AbortError")), observer.complete(), cleanup();
|
|
1304
|
+
};
|
|
1305
|
+
return signal.addEventListener("abort", listener), cleanup;
|
|
1306
|
+
}).pipe(
|
|
1307
|
+
catchError((error) => {
|
|
1308
|
+
throw error instanceof Error && error.name === "AbortError" && state.set("cancelQuery", cancelQuery(key)), error;
|
|
1309
|
+
})
|
|
1310
|
+
) : NEVER;
|
|
1311
|
+
state.set("initializeQuery", initializeQuery(key));
|
|
1312
|
+
const resolved$ = state.observable.pipe(
|
|
1313
|
+
map(getCurrent),
|
|
1314
|
+
first((i) => i !== void 0)
|
|
1315
|
+
);
|
|
1316
|
+
return firstValueFrom(race([resolved$, aborted$]));
|
|
1317
|
+
}
|
|
1318
|
+
), TITLE_CANDIDATES = ["title", "name", "label", "heading", "header", "caption"], SUBTITLE_CANDIDATES = ["description", "subtitle", ...TITLE_CANDIDATES], PREVIEW_PROJECTION = `{
|
|
1319
|
+
// Get all potential title fields
|
|
1320
|
+
"titleCandidates": {
|
|
1321
|
+
${TITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(`,
|
|
1322
|
+
`)}
|
|
1323
|
+
},
|
|
1324
|
+
// Get all potential subtitle fields
|
|
1325
|
+
"subtitleCandidates": {
|
|
1326
|
+
${SUBTITLE_CANDIDATES.map((field) => `"${field}": ${field}`).join(`,
|
|
1327
|
+
`)}
|
|
1328
|
+
},
|
|
1329
|
+
"media": coalesce(
|
|
1330
|
+
select(
|
|
1331
|
+
defined(asset) => {"type": "image-asset", "_ref": asset._ref},
|
|
1332
|
+
defined(image.asset) => {"type": "image-asset", "_ref": image.asset._ref},
|
|
1333
|
+
defined(mainImage.asset) => {"type": "image-asset", "_ref": mainImage.asset._ref},
|
|
1334
|
+
null
|
|
1335
|
+
)
|
|
1336
|
+
),
|
|
1337
|
+
_type,
|
|
1338
|
+
_id,
|
|
1339
|
+
_updatedAt
|
|
1340
|
+
}`, API_VERSION = "v2025-05-06";
|
|
1341
|
+
function hasImageRef(value) {
|
|
1342
|
+
return isObject(value) && "_ref" in value && typeof value._ref == "string";
|
|
1343
|
+
}
|
|
1344
|
+
function normalizeMedia(media, client) {
|
|
1345
|
+
if (!media || !hasImageRef(media)) return null;
|
|
1346
|
+
const url = createImageUrlBuilder(client).image({ _ref: media._ref }).url();
|
|
1347
|
+
return {
|
|
1348
|
+
type: "image-asset",
|
|
1349
|
+
_ref: media._ref,
|
|
1350
|
+
url
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
function findFirstDefined(fieldsToSearch, candidates, exclude) {
|
|
1354
|
+
if (candidates)
|
|
1355
|
+
for (const field of fieldsToSearch) {
|
|
1356
|
+
const value = candidates[field];
|
|
1357
|
+
if (typeof value == "string" && value.trim() !== "" && value !== exclude)
|
|
1358
|
+
return value;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
function transformProjectionToPreview(instance, projectionResult, source) {
|
|
1362
|
+
const title = findFirstDefined(TITLE_CANDIDATES, projectionResult.titleCandidates), subtitle = findFirstDefined(SUBTITLE_CANDIDATES, projectionResult.subtitleCandidates, title), client = getClient(instance, {
|
|
1363
|
+
apiVersion: API_VERSION,
|
|
1364
|
+
// TODO: remove in v3 when we're ready for everything to be queried via source
|
|
1365
|
+
source: source && !isDatasetSource(source) ? source : void 0
|
|
1366
|
+
});
|
|
1367
|
+
return {
|
|
1368
|
+
title: String(title || `${projectionResult._type}: ${projectionResult._id}`),
|
|
1369
|
+
subtitle: subtitle || void 0,
|
|
1370
|
+
media: normalizeMedia(projectionResult.media, client),
|
|
1371
|
+
...projectionResult._status && { _status: projectionResult._status }
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
const TOKEN_REGEX = /(?:[^\s"]+|"[^"]*")+/g;
|
|
1375
|
+
function isNegationToken(token) {
|
|
1376
|
+
return typeof token < "u" && token.trim().startsWith("-");
|
|
1377
|
+
}
|
|
1378
|
+
function isPrefixToken(token) {
|
|
1379
|
+
return typeof token < "u" && token.trim().endsWith("*");
|
|
1380
|
+
}
|
|
1381
|
+
function isExactMatchToken(token) {
|
|
1382
|
+
return !!token && token.length >= 2 && token.startsWith('"') && token.endsWith('"');
|
|
1383
|
+
}
|
|
1384
|
+
function createGroqSearchFilter(query) {
|
|
1385
|
+
const trimmedQuery = query.trim();
|
|
1386
|
+
if (!trimmedQuery)
|
|
1387
|
+
return "";
|
|
1388
|
+
const tokens = trimmedQuery.match(TOKEN_REGEX) ?? [], reversedIndex = [...tokens].reverse().findIndex(
|
|
1389
|
+
(token) => !isNegationToken(token) && !isExactMatchToken(token)
|
|
1390
|
+
), finalIncrementalTokenIndex = reversedIndex === -1 ? -1 : tokens.length - 1 - reversedIndex, finalIncrementalToken = tokens[finalIncrementalTokenIndex], processedTokens = [...tokens];
|
|
1391
|
+
return finalIncrementalToken !== void 0 && !isPrefixToken(finalIncrementalToken) && processedTokens.splice(
|
|
1392
|
+
finalIncrementalTokenIndex,
|
|
1393
|
+
1,
|
|
1394
|
+
`${finalIncrementalToken}*`
|
|
1395
|
+
), `[@] match text::query("${processedTokens.join(" ").replace(/"/g, '\\"')}")`;
|
|
1396
|
+
}
|
|
1397
|
+
export {
|
|
1398
|
+
API_VERSION$1 as API_VERSION,
|
|
1399
|
+
AuthStateType,
|
|
1400
|
+
DEFAULT_API_VERSION$1 as DEFAULT_API_VERSION,
|
|
1401
|
+
PREVIEW_PROJECTION,
|
|
1402
|
+
PROJECT_API_VERSION,
|
|
1403
|
+
REQUEST_TAG_PREFIX,
|
|
1404
|
+
USERS_STATE_CLEAR_DELAY,
|
|
1405
|
+
addSubscription,
|
|
1406
|
+
authStore,
|
|
1407
|
+
authStore$1,
|
|
1408
|
+
bindActionByDataset,
|
|
1409
|
+
bindActionBySource,
|
|
1410
|
+
bindActionBySourceAndPerspective,
|
|
1411
|
+
bindActionGlobally,
|
|
1412
|
+
cancelRequest,
|
|
1413
|
+
clientStore$1 as clientStore,
|
|
1414
|
+
configureLogging,
|
|
1415
|
+
createGroqSearchFilter,
|
|
1416
|
+
createLoggedInAuthState,
|
|
1417
|
+
createLogger,
|
|
1418
|
+
createStateSourceAction,
|
|
1419
|
+
defineStore,
|
|
1420
|
+
getActiveReleasesState,
|
|
1421
|
+
getAuthCode,
|
|
1422
|
+
getAuthState,
|
|
1423
|
+
getCleanedUrl,
|
|
1424
|
+
getClient,
|
|
1425
|
+
getClientErrorApiBody,
|
|
1426
|
+
getClientErrorApiDescription,
|
|
1427
|
+
getClientErrorApiType,
|
|
1428
|
+
getClientState,
|
|
1429
|
+
getCurrentUserState,
|
|
1430
|
+
getDashboardOrganizationId,
|
|
1431
|
+
getDefaultLocation,
|
|
1432
|
+
getEnv,
|
|
1433
|
+
getIsInDashboardState,
|
|
1434
|
+
getLoginUrlState,
|
|
1435
|
+
getPerspectiveState,
|
|
1436
|
+
getQueryKey,
|
|
1437
|
+
getQueryState,
|
|
1438
|
+
getTokenFromLocation,
|
|
1439
|
+
getTokenState,
|
|
1440
|
+
getUsersKey,
|
|
1441
|
+
initializeRequest,
|
|
1442
|
+
insecureRandomId,
|
|
1443
|
+
isCanvasSource,
|
|
1444
|
+
isDatasetSource,
|
|
1445
|
+
isMediaLibrarySource,
|
|
1446
|
+
isProjectUserNotFoundClientError,
|
|
1447
|
+
isReleasePerspective,
|
|
1448
|
+
isStudioConfig,
|
|
1449
|
+
parseQueryKey,
|
|
1450
|
+
parseUsersKey,
|
|
1451
|
+
removeSubscription,
|
|
1452
|
+
resolveQuery,
|
|
1453
|
+
setAuthToken,
|
|
1454
|
+
setCleanupTimeout,
|
|
1455
|
+
setUsersData,
|
|
1456
|
+
setUsersError,
|
|
1457
|
+
transformProjectionToPreview,
|
|
1458
|
+
updateLastLoadMoreRequest
|
|
1459
|
+
};
|
|
1460
|
+
//# sourceMappingURL=createGroqSearchFilter.js.map
|