@sanity/client
Version:
Client for retrieving, creating and patching data from Sanity.io
182 lines (181 loc) • 14.8 kB
JavaScript
function generateHelpUrl(slug) {
return "https://www.sanity.io/help/" + slug;
}
const VALID_ASSET_TYPES = ["image", "file"], VALID_INSERT_LOCATIONS = [
"before",
"after",
"replace"
], dataset = (name) => {
if (!/^(~[a-z0-9]{1}[-\w]{0,63}|[a-z0-9]{1}[-\w]{0,63})$/.test(name)) throw Error("Datasets can only contain lowercase characters, numbers, underscores and dashes, and start with tilde, and be maximum 64 characters");
}, projectId = (id) => {
if (!/^[-a-z0-9]+$/i.test(id)) throw Error("`projectId` can only contain only a-z, 0-9 and dashes");
}, validateAssetType = (type) => {
if (VALID_ASSET_TYPES.indexOf(type) === -1) throw Error(`Invalid asset type: ${type}. Must be one of ${VALID_ASSET_TYPES.join(", ")}`);
}, validateObject = (op, val) => {
if (typeof val != "object" || !val || Array.isArray(val)) throw Error(`${op}() takes an object of properties`);
}, validateDocumentId = (op, id) => {
if (typeof id != "string" || !/^[a-z0-9_][a-z0-9_.-]{0,127}$/i.test(id) || id.includes("..")) throw Error(`${op}(): "${id}" is not a valid document ID`);
}, requireDocumentId = (op, doc) => {
if (!doc._id) throw Error(`${op}() requires that the document contains an ID ("_id" property)`);
validateDocumentId(op, doc._id);
}, validateDocumentType = (op, type) => {
if (typeof type != "string") throw Error(`\`${op}()\`: \`${type}\` is not a valid document type`);
}, requireDocumentType = (op, doc) => {
if (!doc._type) throw Error(`\`${op}()\` requires that the document contains a type (\`_type\` property)`);
validateDocumentType(op, doc._type);
}, validateVersionIdMatch = (builtVersionId, document) => {
if (document._id && document._id !== builtVersionId) throw Error(`The provided document ID (\`${document._id}\`) does not match the generated version ID (\`${builtVersionId}\`)`);
}, validateInsert = (at, selector, items) => {
let signature = "insert(at, selector, items)";
if (VALID_INSERT_LOCATIONS.indexOf(at) === -1) {
let valid = VALID_INSERT_LOCATIONS.map((loc) => `"${loc}"`).join(", ");
throw Error(`${signature} takes an "at"-argument which is one of: ${valid}`);
}
if (typeof selector != "string") throw Error(`${signature} takes a "selector"-argument which must be a string`);
if (!Array.isArray(items)) throw Error(`${signature} takes an "items"-argument which must be an array`);
}, hasDataset = (config) => {
if (config.dataset) return config.dataset;
let resource = config.resource;
if (resource && resource.type === "dataset") {
let segments = resource.id.split(".");
if (segments.length !== 2) throw Error("Dataset resource ID must be in the format \"project.dataset\"");
return segments[1];
}
throw Error("`dataset` must be provided to perform queries");
}, requestTag = (tag) => {
if (typeof tag != "string" || !/^[a-z0-9._-]{1,75}$/i.test(tag)) throw Error("Tag can only contain alphanumeric characters, underscores, dashes and dots, and be between one and 75 characters long.");
return tag;
}, resourceConfig = (config) => {
let resource = config.resource;
if (!resource) throw Error("`resource` must be provided to perform resource queries");
let { type, id } = resource;
switch (type) {
case "dataset":
if (id.split(".").length !== 2) throw Error("Dataset resource ID must be in the format \"project.dataset\"");
return;
case "dashboard":
case "knowledge-base":
case "media-library":
case "canvas": return;
default: throw Error(`Unsupported resource type: ${type.toString()}`);
}
}, resourceGuard = (service, config) => {
if (config.resource) throw Error(`\`${service}\` does not support resource-based operations`);
};
function once(fn) {
let didCall = !1, returnValue;
return (...args) => (didCall ||= (returnValue = fn(...args), !0), returnValue);
}
const createWarningPrinter = (message) => once((...args) => console.warn(message.join(" "), ...args)), printCdnAndWithCredentialsWarning = createWarningPrinter(["Because you set `withCredentials` to true, we will override your `useCdn`", "setting to be false since (cookie-based) credentials are never set on the CDN"]), printCdnWarning = createWarningPrinter([
"Since you haven't set a value for `useCdn`, we will deliver content using our",
"global, edge-cached API-CDN. If you wish to have content delivered faster, set",
"`useCdn: false` to use the Live API. Note: You may incur higher costs using the live API."
]), printCdnPreviewDraftsWarning = createWarningPrinter(["The Sanity client is configured with the `perspective` set to `drafts` or `previewDrafts`, which doesn't support the API-CDN.", "The Live API will be used instead. Set `useCdn: false` in your configuration to hide this warning."]), printPreviewDraftsDeprecationWarning = createWarningPrinter(["The `previewDrafts` perspective has been renamed to `drafts` and will be removed in a future API version"]), printBrowserTokenWarning = createWarningPrinter(["You have configured Sanity client to use a token in the browser. This may cause unintentional security issues.", `See ${generateHelpUrl("js-client-browser-token")} for more information and how to hide this warning.`]), printCredentialedTokenWarning = createWarningPrinter(["You have configured Sanity client to use a token, but also provided `withCredentials: true`.", "This is no longer supported - only token will be used - remove `withCredentials: true`."]), printNoApiVersionSpecifiedWarning = createWarningPrinter(["Using the Sanity client without specifying an API version is deprecated.", `See ${generateHelpUrl("js-client-api-version")}`]), printNoDefaultExport = createWarningPrinter(["The default export of @sanity/client has been deprecated. Use the named export `createClient` instead."]), printCreateVersionWithBaseIdWarning = createWarningPrinter(["You have called `createVersion()` with a defined `document`.", "If you are creating a version of a document that already exists, prefer providing `baseId` and `releaseId` instead."]), printDeprecatedUriOptionWarning = createWarningPrinter(["The `uri` request option has been renamed to `url`.", "Please update your code to use `url` instead. Support for `uri` will be removed in a future version."]), printConfigTokenUnderReactiveAuthWarning = createWarningPrinter(["This client is configured with a reactive `auth`, so `client.config().token` and `client.config().withCredentials` are `undefined`.", "Use `await client.getAuth()` to read the credential the client sends, or subscribe to `client.observeAuth()` to follow changes."]), printDeprecatedResourceConfigWarning = createWarningPrinter(["The `~experimental_resource` configuration property has been renamed to `resource`.", "Please update your client configuration to use `resource` instead. Support for `~experimental_resource` will be removed in a future version."]), defaultConfig = {
apiHost: "https://api.sanity.io",
apiVersion: "1",
useProjectHostname: !0,
stega: { enabled: !1 }
}, LOCALHOSTS = [
"localhost",
"127.0.0.1",
"0.0.0.0"
], isLocal = (host) => LOCALHOSTS.indexOf(host) !== -1;
function validateApiVersion(apiVersion) {
if (apiVersion === "1" || apiVersion === "X") return;
let apiDate = new Date(apiVersion);
if (!(/^\d{4}-\d{2}-\d{2}$/.test(apiVersion) && apiDate instanceof Date && apiDate.getTime() > 0)) throw Error("Invalid API version string, expected `1` or date in format `YYYY-MM-DD`");
}
/**
* @internal - it may have breaking changes in any release
*/
function validateApiPerspective(perspective) {
if (Array.isArray(perspective) && perspective.length > 1 && perspective.includes("raw")) throw TypeError("Invalid API perspective value: \"raw\". The raw-perspective can not be combined with other perspectives");
}
/**
* Whether `key` is an own, enumerable property of `obj`. Enumerable only, so the
* non-enumerable `token` / `withCredentials` getters `exposeConfig` adds under a
* reactive `auth` do not count as a static credential when a `client.config()`
* result is passed back in without being spread.
*/
const hasOwn = (obj, key) => Object.prototype.propertyIsEnumerable.call(obj, key), hasOwnReactiveAuth = (config) => hasOwn(config, "auth") && config.auth !== void 0, hasOwnStaticAuth = (config) => hasOwn(config, "token") || hasOwn(config, "withCredentials");
/**
* Merge a partial configuration onto an existing one for `withConfig()`.
*
* Plain spread semantics for everything, with one rule for the credential: a
* credential the new configuration sets itself replaces the inherited one. An
* `auth` of its own drops the inherited `token` / `withCredentials`, and a
* `token` / `withCredentials` of its own (an own property, even with the value
* `undefined`) drops an inherited `auth`. Setting both forms at once is left
* for `initConfig` to reject.
*
* @internal
*/
function mergeConfig(prev, next = {}) {
let merged = {
...prev,
...next,
stega: {
...prev.stega,
...typeof next.stega == "boolean" ? { enabled: next.stega } : next.stega || {}
}
}, nextHasReactiveAuth = hasOwnReactiveAuth(next), nextHasStaticAuth = hasOwnStaticAuth(next);
return nextHasReactiveAuth && !nextHasStaticAuth ? (delete merged.token, delete merged.withCredentials) : nextHasStaticAuth && !nextHasReactiveAuth && delete merged.auth, merged;
}
/**
* The configuration as `client.config()` returns it: a copy, so callers cannot
* mutate the client's own config. It describes what was configured. Under a
* reactive `auth` observable that is `auth`, so `token` and `withCredentials`
* are `undefined`; they are non-enumerable getters that say so once, to help
* code that still reads them move to `client.getAuth()`.
*
* @internal
*/
function exposeConfig(config) {
let copy = { ...config };
if (!config.auth) return copy;
for (let key of ["token", "withCredentials"]) Object.defineProperty(copy, key, {
enumerable: !1,
configurable: !0,
get: () => {
printConfigTokenUnderReactiveAuthWarning();
}
});
return copy;
}
const initConfig = (config, prevConfig) => {
let specifiedConfig = {
...prevConfig,
...config,
stega: {
...typeof prevConfig.stega == "boolean" ? { enabled: prevConfig.stega } : prevConfig.stega || defaultConfig.stega,
...typeof config.stega == "boolean" ? { enabled: config.stega } : config.stega || {}
}
};
specifiedConfig.apiVersion || printNoApiVersionSpecifiedWarning();
let newConfig = {
...defaultConfig,
...specifiedConfig,
apiHost: specifiedConfig.apiHost ?? defaultConfig.apiHost
};
newConfig["~experimental_resource"] && !newConfig.resource && (printDeprecatedResourceConfigWarning(), newConfig.resource = newConfig["~experimental_resource"]);
let resourceConfig$1 = newConfig.resource, projectBased = newConfig.useProjectHostname && !resourceConfig$1;
if (typeof Promise > "u") {
let helpUrl = generateHelpUrl("js-client-promise-polyfill");
throw Error(`No native Promise-implementation found, polyfill needed - see ${helpUrl}`);
}
if (projectBased && !newConfig.projectId) throw Error("Configuration must contain `projectId`");
if (resourceConfig$1 && resourceConfig(newConfig), newConfig.perspective !== void 0 && validateApiPerspective(newConfig.perspective), "encodeSourceMap" in newConfig) throw Error("It looks like you're using options meant for '@sanity/preview-kit/client'. 'encodeSourceMap' is not supported in '@sanity/client'. Did you mean 'stega.enabled'?");
if ("encodeSourceMapAtPath" in newConfig) throw Error("It looks like you're using options meant for '@sanity/preview-kit/client'. 'encodeSourceMapAtPath' is not supported in '@sanity/client'. Did you mean 'stega.filter'?");
if (typeof newConfig.stega.enabled != "boolean") throw Error(`stega.enabled must be a boolean, received ${newConfig.stega.enabled}`);
if (newConfig.stega.enabled && newConfig.stega.studioUrl === void 0) throw Error("stega.studioUrl must be defined when stega.enabled is true");
if (newConfig.stega.enabled && typeof newConfig.stega.studioUrl != "string" && typeof newConfig.stega.studioUrl != "function") throw Error(`stega.studioUrl must be a string or a function, received ${newConfig.stega.studioUrl}`);
let isBrowser = typeof window < "u" && window.location && window.location.hostname, isLocalhost = isBrowser && isLocal(window.location.hostname), ownReactiveAuth = hasOwnReactiveAuth(config), ownStaticAuth = hasOwnStaticAuth(config);
if (ownReactiveAuth && ownStaticAuth && (config.token || config.withCredentials)) throw Error("`auth` cannot be combined with `token` or `withCredentials`. Pass the credential through `auth` alone, or use the static options without `auth`. A client configured with `auth` includes it in `client.config()`, so to replace its credential, use `client.withConfig({token})` rather than spreading its config into `createClient()`.");
ownReactiveAuth ? (delete newConfig.token, delete newConfig.withCredentials) : (ownStaticAuth || !newConfig.auth) && delete newConfig.auth;
let hasToken = !!newConfig.token;
newConfig.withCredentials && hasToken && (printCredentialedTokenWarning(), newConfig.withCredentials = !1), isBrowser && isLocalhost && hasToken && newConfig.ignoreBrowserTokenWarning !== !0 ? printBrowserTokenWarning() : newConfig.useCdn === void 0 && printCdnWarning(), projectBased && projectId(newConfig.projectId), newConfig.dataset && dataset(newConfig.dataset), "requestTagPrefix" in newConfig && (newConfig.requestTagPrefix = newConfig.requestTagPrefix ? requestTag(newConfig.requestTagPrefix).replace(/\.+$/, "") : void 0), newConfig.apiVersion = `${newConfig.apiVersion}`.replace(/^v/, ""), newConfig.isDefaultApi = newConfig.apiHost === defaultConfig.apiHost, newConfig.useCdn === !0 && newConfig.withCredentials && printCdnAndWithCredentialsWarning(), newConfig.useCdn = newConfig.useCdn !== !1 && !newConfig.withCredentials, validateApiVersion(newConfig.apiVersion);
let hostParts = newConfig.apiHost.split("://", 2), protocol = hostParts[0], host = hostParts[1], cdnHost = newConfig.isDefaultApi ? "apicdn.sanity.io" : host;
return projectBased ? (newConfig.url = `${protocol}://${newConfig.projectId}.${host}/v${newConfig.apiVersion}`, newConfig.cdnUrl = `${protocol}://${newConfig.projectId}.${cdnHost}/v${newConfig.apiVersion}`) : (newConfig.url = `${newConfig.apiHost}/v${newConfig.apiVersion}`, newConfig.cdnUrl = newConfig.url), newConfig;
};
export { validateVersionIdMatch as S, resourceGuard as _, validateApiPerspective as a, validateInsert as b, printDeprecatedUriOptionWarning as c, dataset as d, hasDataset as f, resourceConfig as g, requireDocumentType as h, mergeConfig as i, printNoDefaultExport as l, requireDocumentId as m, exposeConfig as n, printCdnPreviewDraftsWarning as o, requestTag as p, initConfig as r, printCreateVersionWithBaseIdWarning as s, defaultConfig as t, printPreviewDraftsDeprecationWarning as u, validateAssetType as v, validateObject as x, validateDocumentId as y };
//# sourceMappingURL=config-DqaFfT9q.js.map