@sanity/sdk 2.5.0 → 2.6.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/index.d.ts +311 -20
- package/dist/index.js +195 -29
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/_exports/index.ts +15 -3
- package/src/client/clientStore.test.ts +45 -43
- package/src/client/clientStore.ts +23 -9
- package/src/config/loggingConfig.ts +149 -0
- package/src/config/sanityConfig.ts +39 -20
- package/src/query/queryStore.ts +3 -1
- package/src/store/createActionBinder.ts +17 -6
- package/src/store/createSanityInstance.test.ts +85 -1
- package/src/store/createSanityInstance.ts +53 -4
- package/src/utils/logger-usage-example.md +141 -0
- package/src/utils/logger.test.ts +757 -0
- package/src/utils/logger.ts +537 -0
package/dist/index.js
CHANGED
|
@@ -17,15 +17,14 @@ import { isKeySegment, isKeyedObject } from "@sanity/types";
|
|
|
17
17
|
import { createDocumentLoaderFromClient } from "@sanity/mutate/_unstable_store";
|
|
18
18
|
import { SDK_CHANNEL_NAME, SDK_NODE_NAME } from "@sanity/message-protocol";
|
|
19
19
|
import { fromUrl } from "@sanity/bifur-client";
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return { [SOURCE_ID]: { projectId, dataset } };
|
|
20
|
+
function isDatasetSource(source) {
|
|
21
|
+
return "projectId" in source && "dataset" in source;
|
|
23
22
|
}
|
|
24
|
-
function
|
|
25
|
-
return
|
|
23
|
+
function isMediaLibrarySource(source) {
|
|
24
|
+
return "mediaLibraryId" in source;
|
|
26
25
|
}
|
|
27
|
-
function
|
|
28
|
-
return
|
|
26
|
+
function isCanvasSource(source) {
|
|
27
|
+
return "canvasId" in source;
|
|
29
28
|
}
|
|
30
29
|
function getPublishedId(id) {
|
|
31
30
|
const draftsPrefix = "drafts.";
|
|
@@ -38,13 +37,152 @@ function getDraftId(id) {
|
|
|
38
37
|
function insecureRandomId() {
|
|
39
38
|
return Array.from({ length: 16 }, () => Math.floor(Math.random() * 16).toString(16)).join("");
|
|
40
39
|
}
|
|
40
|
+
const LOG_LEVEL_PRIORITY = {
|
|
41
|
+
error: 0,
|
|
42
|
+
warn: 1,
|
|
43
|
+
info: 2,
|
|
44
|
+
debug: 3,
|
|
45
|
+
trace: 4
|
|
46
|
+
}, DEFAULT_CONFIG = {
|
|
47
|
+
level: "warn",
|
|
48
|
+
namespaces: [],
|
|
49
|
+
internal: !1,
|
|
50
|
+
timestamps: !0,
|
|
51
|
+
enableInProduction: !1,
|
|
52
|
+
handler: {
|
|
53
|
+
// eslint-disable-next-line no-console
|
|
54
|
+
error: console.error.bind(console),
|
|
55
|
+
// eslint-disable-next-line no-console
|
|
56
|
+
warn: console.warn.bind(console),
|
|
57
|
+
// eslint-disable-next-line no-console
|
|
58
|
+
info: console.info.bind(console),
|
|
59
|
+
// eslint-disable-next-line no-console
|
|
60
|
+
debug: console.debug.bind(console),
|
|
61
|
+
// eslint-disable-next-line no-console
|
|
62
|
+
trace: console.debug.bind(console)
|
|
63
|
+
// trace uses console.debug
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
function parseDebugEnvVar() {
|
|
67
|
+
if (typeof process > "u" || !process.env?.DEBUG)
|
|
68
|
+
return null;
|
|
69
|
+
const debug = process.env.DEBUG;
|
|
70
|
+
if (!debug.includes("sanity"))
|
|
71
|
+
return null;
|
|
72
|
+
const config = {}, levelMatch = debug.match(/sanity:(trace|debug|info|warn|error):/), hasLevelSpecifier = !!levelMatch;
|
|
73
|
+
if (levelMatch ? config.level = levelMatch[1] : config.level = "debug", debug === "sanity")
|
|
74
|
+
config.namespaces = ["*"];
|
|
75
|
+
else if (hasLevelSpecifier && debug.match(/sanity:(trace|debug|info|warn|error):\*/))
|
|
76
|
+
config.namespaces = ["*"];
|
|
77
|
+
else if (!hasLevelSpecifier && debug.includes("sanity:*"))
|
|
78
|
+
config.namespaces = ["*"];
|
|
79
|
+
else {
|
|
80
|
+
const namespaces = debug.split(",").filter((s) => s.includes("sanity:")).map((s) => {
|
|
81
|
+
const cleaned = s.replace(/^sanity:/, "");
|
|
82
|
+
return hasLevelSpecifier && cleaned.match(/^(trace|debug|info|warn|error):/) ? cleaned.split(":").slice(1).join(":") : cleaned.split(":")[0];
|
|
83
|
+
}).filter(Boolean).filter((ns) => ns !== "*");
|
|
84
|
+
namespaces.length > 0 && (config.namespaces = namespaces);
|
|
85
|
+
}
|
|
86
|
+
return debug.includes(":internal") && (config.internal = !0), config;
|
|
87
|
+
}
|
|
88
|
+
const envConfig = parseDebugEnvVar();
|
|
89
|
+
let globalConfig = {
|
|
90
|
+
...DEFAULT_CONFIG,
|
|
91
|
+
...envConfig ?? {}
|
|
92
|
+
};
|
|
93
|
+
envConfig && (["info", "debug", "trace"].includes(globalConfig.level) || globalConfig.level === "warn") && console.info(
|
|
94
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] [INFO] [sdk] Logging auto-configured from DEBUG environment variable`,
|
|
95
|
+
{
|
|
96
|
+
level: globalConfig.level,
|
|
97
|
+
namespaces: globalConfig.namespaces,
|
|
98
|
+
internal: globalConfig.internal,
|
|
99
|
+
source: "env:DEBUG",
|
|
100
|
+
value: typeof process < "u" ? process.env?.DEBUG : void 0
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
function configureLogging$1(config) {
|
|
104
|
+
globalConfig = {
|
|
105
|
+
...globalConfig,
|
|
106
|
+
...config,
|
|
107
|
+
handler: config.handler ?? globalConfig.handler
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function isLoggingEnabled() {
|
|
111
|
+
return typeof process < "u" && process.env?.NODE_ENV === "production" ? globalConfig.enableInProduction : !0;
|
|
112
|
+
}
|
|
113
|
+
function isNamespaceEnabled(namespace) {
|
|
114
|
+
return isLoggingEnabled() ? globalConfig.namespaces.includes("*") ? !0 : globalConfig.namespaces.includes(namespace) : !1;
|
|
115
|
+
}
|
|
116
|
+
function isLevelEnabled(level) {
|
|
117
|
+
return isLoggingEnabled() ? LOG_LEVEL_PRIORITY[level] <= LOG_LEVEL_PRIORITY[globalConfig.level] : !1;
|
|
118
|
+
}
|
|
119
|
+
function formatMessage(namespace, level, message, context) {
|
|
120
|
+
const parts = [];
|
|
121
|
+
if (globalConfig.timestamps) {
|
|
122
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
123
|
+
parts.push(`[${timestamp}]`);
|
|
124
|
+
}
|
|
125
|
+
parts.push(`[${level.toUpperCase()}]`), parts.push(`[${namespace}]`);
|
|
126
|
+
const instanceContext = context?.instanceContext;
|
|
127
|
+
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];
|
|
128
|
+
}
|
|
129
|
+
function sanitizeContext(context) {
|
|
130
|
+
if (!context || Object.keys(context).length === 0) return;
|
|
131
|
+
const sanitized = { ...context }, sensitiveKeys = ["token", "password", "secret", "apiKey", "authorization"];
|
|
132
|
+
for (const key of Object.keys(sanitized))
|
|
133
|
+
sensitiveKeys.some((sensitive) => key.toLowerCase().includes(sensitive)) && (sanitized[key] = "[REDACTED]");
|
|
134
|
+
return sanitized;
|
|
135
|
+
}
|
|
136
|
+
function createLogger(namespace, baseContext) {
|
|
137
|
+
const logAtLevel = (level, message, context) => {
|
|
138
|
+
if (!isNamespaceEnabled(namespace) || !isLevelEnabled(level) || context?.internal && !globalConfig.internal) return;
|
|
139
|
+
const mergedContext = { ...baseContext, ...context }, sanitized = sanitizeContext(mergedContext), [formatted, finalContext] = formatMessage(namespace, level, message, sanitized);
|
|
140
|
+
globalConfig.handler[level](formatted, finalContext);
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
namespace,
|
|
144
|
+
error: (message, context) => logAtLevel("error", message, context),
|
|
145
|
+
warn: (message, context) => logAtLevel("warn", message, context),
|
|
146
|
+
info: (message, context) => logAtLevel("info", message, context),
|
|
147
|
+
debug: (message, context) => logAtLevel("debug", message, context),
|
|
148
|
+
trace: (message, context) => logAtLevel("trace", message, { ...context, internal: !0 }),
|
|
149
|
+
isLevelEnabled: (level) => isNamespaceEnabled(namespace) && isLevelEnabled(level),
|
|
150
|
+
child: (childContext) => createLogger(namespace, { ...baseContext, ...childContext }),
|
|
151
|
+
getInstanceContext: () => baseContext?.instanceContext
|
|
152
|
+
};
|
|
153
|
+
}
|
|
41
154
|
function createSanityInstance(config = {}) {
|
|
42
|
-
const instanceId = crypto.randomUUID(), disposeListeners = /* @__PURE__ */ new Map(), disposed = { current: !1 },
|
|
155
|
+
const instanceId = crypto.randomUUID(), disposeListeners = /* @__PURE__ */ new Map(), disposed = { current: !1 }, instanceContext = {
|
|
156
|
+
instanceId,
|
|
157
|
+
projectId: config.projectId,
|
|
158
|
+
dataset: config.dataset
|
|
159
|
+
}, logger = createLogger("sdk", { instanceContext });
|
|
160
|
+
logger.info("Sanity instance created", {
|
|
161
|
+
hasProjectId: !!config.projectId,
|
|
162
|
+
hasDataset: !!config.dataset,
|
|
163
|
+
hasAuth: !!config.auth,
|
|
164
|
+
hasPerspective: !!config.perspective
|
|
165
|
+
}), logger.debug("Instance configuration", {
|
|
166
|
+
projectId: config.projectId,
|
|
167
|
+
dataset: config.dataset,
|
|
168
|
+
perspective: config.perspective,
|
|
169
|
+
studioMode: config.studioMode?.enabled,
|
|
170
|
+
hasAuthProviders: !!config.auth?.providers,
|
|
171
|
+
hasAuthToken: !!config.auth?.token
|
|
172
|
+
});
|
|
173
|
+
const instance = {
|
|
43
174
|
instanceId,
|
|
44
175
|
config,
|
|
45
176
|
isDisposed: () => disposed.current,
|
|
46
177
|
dispose: () => {
|
|
47
|
-
|
|
178
|
+
if (disposed.current) {
|
|
179
|
+
logger.trace("Dispose called on already disposed instance", { internal: !0 });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
logger.trace("Disposing instance", {
|
|
183
|
+
internal: !0,
|
|
184
|
+
listenerCount: disposeListeners.size
|
|
185
|
+
}), disposed.current = !0, disposeListeners.forEach((listener) => listener()), disposeListeners.clear(), logger.info("Instance disposed");
|
|
48
186
|
},
|
|
49
187
|
onDispose: (cb) => {
|
|
50
188
|
const listenerId = insecureRandomId();
|
|
@@ -54,14 +192,26 @@ function createSanityInstance(config = {}) {
|
|
|
54
192
|
},
|
|
55
193
|
getParent: () => {
|
|
56
194
|
},
|
|
57
|
-
createChild: (next) =>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
195
|
+
createChild: (next) => {
|
|
196
|
+
logger.debug("Creating child instance", {
|
|
197
|
+
parentInstanceId: instanceId.slice(0, 8),
|
|
198
|
+
overridingProjectId: !!next.projectId,
|
|
199
|
+
overridingDataset: !!next.dataset,
|
|
200
|
+
overridingAuth: !!next.auth
|
|
201
|
+
});
|
|
202
|
+
const child = Object.assign(
|
|
203
|
+
createSanityInstance({
|
|
204
|
+
...config,
|
|
205
|
+
...next,
|
|
206
|
+
...config.auth === next.auth ? config.auth : config.auth && next.auth && { auth: { ...config.auth, ...next.auth } }
|
|
207
|
+
}),
|
|
208
|
+
{ getParent: () => instance }
|
|
209
|
+
);
|
|
210
|
+
return logger.trace("Child instance created", {
|
|
211
|
+
internal: !0,
|
|
212
|
+
childInstanceId: child.instanceId.slice(0, 8)
|
|
213
|
+
}), child;
|
|
214
|
+
},
|
|
65
215
|
match: (targetConfig) => {
|
|
66
216
|
if (Object.entries(pick(targetConfig, "auth", "projectId", "dataset")).every(
|
|
67
217
|
([key, value]) => config[key] === value
|
|
@@ -131,9 +281,9 @@ const bindActionByDataset = createActionBinder((instance, options) => {
|
|
|
131
281
|
return { name: `${projectId}.${dataset}`, projectId, dataset };
|
|
132
282
|
}), bindActionBySource = createActionBinder((instance, { source }) => {
|
|
133
283
|
if (source) {
|
|
134
|
-
|
|
135
|
-
if (!id) throw new Error(
|
|
136
|
-
return
|
|
284
|
+
let id;
|
|
285
|
+
if (isDatasetSource(source) ? id = `${source.projectId}.${source.dataset}` : isMediaLibrarySource(source) ? id = `media-library:${source.mediaLibraryId}` : isCanvasSource(source) && (id = `canvas:${source.canvasId}`), !id) throw new Error(`Received invalid source: ${JSON.stringify(source)}`);
|
|
286
|
+
return { name: id };
|
|
137
287
|
}
|
|
138
288
|
const { projectId, dataset } = instance.config;
|
|
139
289
|
if (!projectId || !dataset)
|
|
@@ -673,12 +823,12 @@ const authStore = {
|
|
|
673
823
|
`The client options provided contains unsupported properties: ${listFormatter.format(disallowedKeys)}. Allowed keys are: ${listFormatter.format(allowedKeys)}.`
|
|
674
824
|
);
|
|
675
825
|
}
|
|
676
|
-
const tokenFromState = state.get().token, { clients, authMethod } = state.get()
|
|
677
|
-
let
|
|
678
|
-
|
|
826
|
+
const tokenFromState = state.get().token, { clients, authMethod } = state.get();
|
|
827
|
+
let resource;
|
|
828
|
+
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 }));
|
|
679
829
|
const projectId = options.projectId ?? instance.config.projectId, dataset = options.dataset ?? instance.config.dataset, apiHost = options.apiHost ?? instance.config.auth?.apiHost, effectiveOptions = {
|
|
680
830
|
...DEFAULT_CLIENT_CONFIG,
|
|
681
|
-
...(options.scope === "global" || !projectId ||
|
|
831
|
+
...(options.scope === "global" || !projectId || resource) && { useProjectHostname: !1 },
|
|
682
832
|
token: authMethod === "cookie" ? void 0 : tokenFromState ?? void 0,
|
|
683
833
|
...options,
|
|
684
834
|
...projectId && { projectId },
|
|
@@ -686,7 +836,7 @@ const authStore = {
|
|
|
686
836
|
...apiHost && { apiHost },
|
|
687
837
|
...resource && { "~experimental_resource": resource }
|
|
688
838
|
};
|
|
689
|
-
|
|
839
|
+
resource && ((options.projectId || options.dataset) && console.warn(
|
|
690
840
|
"Both source and explicit projectId/dataset are provided. The source will be used and projectId/dataset will be ignored."
|
|
691
841
|
), delete effectiveOptions.projectId, delete effectiveOptions.dataset), effectiveOptions.token === null || typeof effectiveOptions.token > "u" ? (delete effectiveOptions.token, authMethod === "cookie" && (effectiveOptions.withCredentials = !0)) : delete effectiveOptions.withCredentials;
|
|
692
842
|
const key = getClientConfigKey(effectiveOptions);
|
|
@@ -1144,6 +1294,21 @@ function createProjectHandle(handle) {
|
|
|
1144
1294
|
function createDatasetHandle(handle) {
|
|
1145
1295
|
return handle;
|
|
1146
1296
|
}
|
|
1297
|
+
function configureLogging(config) {
|
|
1298
|
+
configureLogging$1(config);
|
|
1299
|
+
const configLevel = config.level || "warn", shouldLog = ["info", "debug", "trace"].includes(configLevel) || configLevel === "warn";
|
|
1300
|
+
shouldLog && config.handler?.info ? config.handler.info(`[${(/* @__PURE__ */ new Date()).toISOString()}] [INFO] [sdk] Logging configured`, {
|
|
1301
|
+
level: configLevel,
|
|
1302
|
+
namespaces: config.namespaces || [],
|
|
1303
|
+
internal: config.internal || !1,
|
|
1304
|
+
source: "programmatic"
|
|
1305
|
+
}) : shouldLog && console.info(`[${(/* @__PURE__ */ new Date()).toISOString()}] [INFO] [sdk] Logging configured`, {
|
|
1306
|
+
level: configLevel,
|
|
1307
|
+
namespaces: config.namespaces || [],
|
|
1308
|
+
internal: config.internal || !1,
|
|
1309
|
+
source: "programmatic"
|
|
1310
|
+
});
|
|
1311
|
+
}
|
|
1147
1312
|
const API_VERSION$4 = "v2025-02-19", datasets = createFetcherStore({
|
|
1148
1313
|
name: "Datasets",
|
|
1149
1314
|
getKey: (instance, options) => {
|
|
@@ -4122,7 +4287,7 @@ function getCorsErrorProjectId(error) {
|
|
|
4122
4287
|
const projMatch = (error.message || "").match(/manage\/project\/([^/?#]+)/);
|
|
4123
4288
|
return projMatch ? projMatch[1] : null;
|
|
4124
4289
|
}
|
|
4125
|
-
var version = "2.
|
|
4290
|
+
var version = "2.6.0";
|
|
4126
4291
|
const CORE_SDK_VERSION = getEnv("PKG_VERSION") || `${version}-development`;
|
|
4127
4292
|
export {
|
|
4128
4293
|
AuthStateType,
|
|
@@ -4133,7 +4298,7 @@ export {
|
|
|
4133
4298
|
agentTransform,
|
|
4134
4299
|
agentTranslate,
|
|
4135
4300
|
applyDocumentActions,
|
|
4136
|
-
|
|
4301
|
+
configureLogging,
|
|
4137
4302
|
createDatasetHandle,
|
|
4138
4303
|
createDocument,
|
|
4139
4304
|
createDocumentHandle,
|
|
@@ -4141,7 +4306,6 @@ export {
|
|
|
4141
4306
|
createGroqSearchFilter,
|
|
4142
4307
|
createProjectHandle,
|
|
4143
4308
|
createSanityInstance,
|
|
4144
|
-
datasetSource,
|
|
4145
4309
|
defineIntent,
|
|
4146
4310
|
deleteDocument,
|
|
4147
4311
|
destroyController,
|
|
@@ -4183,12 +4347,14 @@ export {
|
|
|
4183
4347
|
getUsersKey,
|
|
4184
4348
|
getUsersState,
|
|
4185
4349
|
handleAuthCallback,
|
|
4350
|
+
isCanvasSource,
|
|
4351
|
+
isDatasetSource,
|
|
4352
|
+
isMediaLibrarySource,
|
|
4186
4353
|
isProjectUserNotFoundClientError,
|
|
4187
4354
|
joinPaths,
|
|
4188
4355
|
jsonMatch2 as jsonMatch,
|
|
4189
4356
|
loadMoreUsers,
|
|
4190
4357
|
logout,
|
|
4191
|
-
mediaLibrarySource,
|
|
4192
4358
|
observeOrganizationVerificationState,
|
|
4193
4359
|
parseQueryKey,
|
|
4194
4360
|
parseUsersKey,
|