@sanity/cli
Version:
Sanity CLI tool for managing Sanity installations, managing plugins, schemas and datasets
390 lines (389 loc) • 16.8 kB
JavaScript
import { createClient } from "@sanity/client";
import fs from "node:fs";
import path from "node:path";
import debugIt from "debug";
import require$$0 from "fs";
import require$$1 from "path";
import require$$2 from "os";
import require$$3 from "crypto";
const debug = debugIt("sanity:cli"), requireFunc = typeof __webpack_require__ == "function" ? __non_webpack_require__ : require;
function dynamicRequire(request) {
const mod = requireFunc(request);
return mod.__esModule && mod.default ? mod.default : mod;
}
dynamicRequire.resolve = requireFunc.resolve;
dynamicRequire.cache = requireFunc.cache;
function getSanityCliConfig(cwd, clearCache = !1) {
const jsConfigPath = path.join(cwd, "sanity.cli.js"), tsConfigPath = path.join(cwd, "sanity.cli.ts"), [js, ts] = [fs.existsSync(jsConfigPath), fs.existsSync(tsConfigPath)];
return !js && !ts ? null : !js && ts ? {
config: importConfig(tsConfigPath, clearCache),
path: tsConfigPath
} : (js && ts && warn("Found both `sanity.cli.js` and `sanity.cli.ts` - using sanity.cli.js"), {
config: importConfig(jsConfigPath, clearCache),
path: jsConfigPath
});
}
function importConfig(filePath, clearCache) {
try {
if (clearCache) {
const resolvedPath = dynamicRequire.resolve(filePath);
delete dynamicRequire.cache[resolvedPath];
}
const config = dynamicRequire(filePath);
if (config === null || typeof config != "object")
throw new Error("Module export is not a configuration object");
return "default" in config ? config.default : config;
} catch (err) {
return err.code === "MODULE_NOT_FOUND" && err.message.includes("sanity/cli") || console.error(`Error reading "${filePath}": ${err.message}`), null;
}
}
function warn(warning) {
typeof process.send == "function" ? process.send({ type: "warning", warning }) : console.warn(warning);
}
function resolveRootDir(cwd) {
try {
return resolveProjectRoot(cwd) || cwd;
} catch (err) {
throw new Error(`Error occurred trying to resolve project root:
${err.message}`);
}
}
function hasSanityConfig(basePath, configName) {
return [
fileExists(path.join(basePath, `${configName}.js`)),
fileExists(path.join(basePath, `${configName}.ts`)),
isSanityV2StudioRoot(basePath)
].some(Boolean);
}
function resolveProjectRoot(basePath, iterations = 0) {
if (hasSanityConfig(basePath, "sanity.config"))
return basePath;
const parentDir = path.resolve(basePath, "..");
return parentDir === basePath || iterations > 30 ? !1 : resolveProjectRoot(parentDir, iterations + 1);
}
function isSanityV2StudioRoot(basePath) {
try {
const content = fs.readFileSync(path.join(basePath, "sanity.json"), "utf8"), isRoot = !!JSON.parse(content)?.root;
return isRoot && debug("Found Sanity v2 studio root at %s", basePath), isRoot;
} catch {
return !1;
}
}
function fileExists(filePath) {
return fs.existsSync(filePath);
}
function getCliClientImpl(options = {}) {
if (typeof process != "object")
throw new Error("getCliClient() should only be called from node.js scripts");
const {
cwd = process.env.SANITY_BASE_PATH || process.cwd(),
useCdn = !1,
apiVersion = "2022-06-06",
projectId,
dataset,
token = getCliClient.__internal__getToken()
} = options;
if (projectId && dataset)
return createClient({ projectId, dataset, apiVersion, useCdn, token });
const rootDir = resolveRootDir(cwd), { config } = getSanityCliConfig(rootDir) || {};
if (!config)
throw new Error("Unable to resolve CLI configuration");
const apiConfig = config?.api || {};
if (!apiConfig.projectId || !apiConfig.dataset)
throw new Error("Unable to resolve project ID/dataset from CLI configuration");
return createClient({
projectId: apiConfig.projectId,
dataset: apiConfig.dataset,
apiVersion,
useCdn,
token
});
}
getCliClientImpl.__internal__getToken = () => {
};
const getCliClient = getCliClientImpl;
function defineCliConfig(config) {
return config;
}
function createCliConfig(config) {
return config;
}
var main$1 = { exports: {} }, version = "16.6.1", require$$4 = {
version
}, hasRequiredMain$1;
function requireMain$1() {
if (hasRequiredMain$1) return main$1.exports;
hasRequiredMain$1 = 1;
const fs2 = require$$0, path2 = require$$1, os = require$$2, crypto = require$$3, version2 = require$$4.version, LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
function parse(src) {
const obj = {};
let lines = src.toString();
lines = lines.replace(/\r\n?/mg, `
`);
let match;
for (; (match = LINE.exec(lines)) != null; ) {
const key = match[1];
let value = match[2] || "";
value = value.trim();
const maybeQuote = value[0];
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2"), maybeQuote === '"' && (value = value.replace(/\\n/g, `
`), value = value.replace(/\\r/g, "\r")), obj[key] = value;
}
return obj;
}
function _parseVault(options) {
options = options || {};
const vaultPath = _vaultPath(options);
options.path = vaultPath;
const result = DotenvModule.configDotenv(options);
if (!result.parsed) {
const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
throw err.code = "MISSING_DATA", err;
}
const keys = _dotenvKey(options).split(","), length = keys.length;
let decrypted;
for (let i = 0; i < length; i++)
try {
const key = keys[i].trim(), attrs = _instructions(result, key);
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
break;
} catch (error) {
if (i + 1 >= length)
throw error;
}
return DotenvModule.parse(decrypted);
}
function _warn(message) {
console.log(`[dotenv@${version2}][WARN] ${message}`);
}
function _debug(message) {
console.log(`[dotenv@${version2}][DEBUG] ${message}`);
}
function _log(message) {
console.log(`[dotenv@${version2}] ${message}`);
}
function _dotenvKey(options) {
return options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0 ? options.DOTENV_KEY : process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0 ? process.env.DOTENV_KEY : "";
}
function _instructions(result, dotenvKey) {
let uri;
try {
uri = new URL(dotenvKey);
} catch (error) {
if (error.code === "ERR_INVALID_URL") {
const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
throw err.code = "INVALID_DOTENV_KEY", err;
}
throw error;
}
const key = uri.password;
if (!key) {
const err = new Error("INVALID_DOTENV_KEY: Missing key part");
throw err.code = "INVALID_DOTENV_KEY", err;
}
const environment = uri.searchParams.get("environment");
if (!environment) {
const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
throw err.code = "INVALID_DOTENV_KEY", err;
}
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`, ciphertext = result.parsed[environmentKey];
if (!ciphertext) {
const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
throw err.code = "NOT_FOUND_DOTENV_ENVIRONMENT", err;
}
return { ciphertext, key };
}
function _vaultPath(options) {
let possibleVaultPath = null;
if (options && options.path && options.path.length > 0)
if (Array.isArray(options.path))
for (const filepath of options.path)
fs2.existsSync(filepath) && (possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`);
else
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
else
possibleVaultPath = path2.resolve(process.cwd(), ".env.vault");
return fs2.existsSync(possibleVaultPath) ? possibleVaultPath : null;
}
function _resolveHome(envPath) {
return envPath[0] === "~" ? path2.join(os.homedir(), envPath.slice(1)) : envPath;
}
function _configVault(options) {
const debug2 = !!(options && options.debug), quiet = options && "quiet" in options ? options.quiet : !0;
(debug2 || !quiet) && _log("Loading env from encrypted .env.vault");
const parsed = DotenvModule._parseVault(options);
let processEnv = process.env;
return options && options.processEnv != null && (processEnv = options.processEnv), DotenvModule.populate(processEnv, parsed, options), { parsed };
}
function configDotenv(options) {
const dotenvPath = path2.resolve(process.cwd(), ".env");
let encoding = "utf8";
const debug2 = !!(options && options.debug), quiet = options && "quiet" in options ? options.quiet : !0;
options && options.encoding ? encoding = options.encoding : debug2 && _debug("No encoding is specified. UTF-8 is used by default");
let optionPaths = [dotenvPath];
if (options && options.path)
if (!Array.isArray(options.path))
optionPaths = [_resolveHome(options.path)];
else {
optionPaths = [];
for (const filepath of options.path)
optionPaths.push(_resolveHome(filepath));
}
let lastError;
const parsedAll = {};
for (const path3 of optionPaths)
try {
const parsed = DotenvModule.parse(fs2.readFileSync(path3, { encoding }));
DotenvModule.populate(parsedAll, parsed, options);
} catch (e) {
debug2 && _debug(`Failed to load ${path3} ${e.message}`), lastError = e;
}
let processEnv = process.env;
if (options && options.processEnv != null && (processEnv = options.processEnv), DotenvModule.populate(processEnv, parsedAll, options), debug2 || !quiet) {
const keysCount = Object.keys(parsedAll).length, shortPaths = [];
for (const filePath of optionPaths)
try {
const relative = path2.relative(process.cwd(), filePath);
shortPaths.push(relative);
} catch (e) {
debug2 && _debug(`Failed to load ${filePath} ${e.message}`), lastError = e;
}
_log(`injecting env (${keysCount}) from ${shortPaths.join(",")}`);
}
return lastError ? { parsed: parsedAll, error: lastError } : { parsed: parsedAll };
}
function config(options) {
if (_dotenvKey(options).length === 0)
return DotenvModule.configDotenv(options);
const vaultPath = _vaultPath(options);
return vaultPath ? DotenvModule._configVault(options) : (_warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`), DotenvModule.configDotenv(options));
}
function decrypt(encrypted, keyStr) {
const key = Buffer.from(keyStr.slice(-64), "hex");
let ciphertext = Buffer.from(encrypted, "base64");
const nonce = ciphertext.subarray(0, 12), authTag = ciphertext.subarray(-16);
ciphertext = ciphertext.subarray(12, -16);
try {
const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
return aesgcm.setAuthTag(authTag), `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
} catch (error) {
const isRange = error instanceof RangeError, invalidKeyLength = error.message === "Invalid key length", decryptionFailed = error.message === "Unsupported state or unable to authenticate data";
if (isRange || invalidKeyLength) {
const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
throw err.code = "INVALID_DOTENV_KEY", err;
} else if (decryptionFailed) {
const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
throw err.code = "DECRYPTION_FAILED", err;
} else
throw error;
}
}
function populate(processEnv, parsed, options = {}) {
const debug2 = !!(options && options.debug), override = !!(options && options.override);
if (typeof parsed != "object") {
const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
throw err.code = "OBJECT_REQUIRED", err;
}
for (const key of Object.keys(parsed))
Object.prototype.hasOwnProperty.call(processEnv, key) ? (override === !0 && (processEnv[key] = parsed[key]), debug2 && _debug(override === !0 ? `"${key}" is already defined and WAS overwritten` : `"${key}" is already defined and was NOT overwritten`)) : processEnv[key] = parsed[key];
}
const DotenvModule = {
configDotenv,
_configVault,
_parseVault,
config,
decrypt,
parse,
populate
};
return main$1.exports.configDotenv = DotenvModule.configDotenv, main$1.exports._configVault = DotenvModule._configVault, main$1.exports._parseVault = DotenvModule._parseVault, main$1.exports.config = DotenvModule.config, main$1.exports.decrypt = DotenvModule.decrypt, main$1.exports.parse = DotenvModule.parse, main$1.exports.populate = DotenvModule.populate, main$1.exports = DotenvModule, main$1.exports;
}
var mainExports$1 = requireMain$1(), main = {}, hasRequiredMain;
function requireMain() {
if (hasRequiredMain) return main;
hasRequiredMain = 1;
function _interpolate(envValue, environment, config) {
const matches = envValue.match(/(.?\${*[\w]*(?::-[\w/]*)?}*)/g) || [];
return matches.reduce(function(newEnv, match, index) {
const parts = /(.?)\${*([\w]*(?::-[\w/]*)?)?}*/g.exec(match);
if (!parts || parts.length === 0)
return newEnv;
const prefix = parts[1];
let value, replacePart;
if (prefix === "\\")
replacePart = parts[0], value = replacePart.replace("\\$", "$");
else {
const keyParts = parts[2].split(":-"), key = keyParts[0];
if (replacePart = parts[0].substring(prefix.length), value = Object.prototype.hasOwnProperty.call(environment, key) ? environment[key] : config.parsed[key] || keyParts[1] || "", keyParts.length > 1 && value) {
const replaceNested = matches[index + 1];
matches[index + 1] = "", newEnv = newEnv.replace(replaceNested, "");
}
value = _interpolate(value, environment, config);
}
return newEnv.replace(replacePart, value);
}, envValue);
}
function expand(config) {
const environment = config.ignoreProcessEnv ? {} : process.env;
for (const configKey in config.parsed) {
const value = Object.prototype.hasOwnProperty.call(environment, configKey) ? environment[configKey] : config.parsed[configKey];
config.parsed[configKey] = _interpolate(value, environment, config);
}
for (const processKey in config.parsed)
environment[processKey] = config.parsed[processKey];
return config;
}
return main.expand = expand, main;
}
var mainExports = requireMain();
function loadEnv(mode, envDir, prefixes = ["VITE_"]) {
if (mode === "local")
throw new Error(
'"local" cannot be used as a mode name because it conflicts with the .local postfix for .env files.'
);
const env = {}, envFiles = [
/** default file */
".env",
/** local file */
".env.local",
/** mode file */
`.env.${mode}`,
/** mode local file */
`.env.${mode}.local`
], parsed = Object.fromEntries(
envFiles.flatMap((file) => {
const envPath = lookupFile(envDir, [file], {
rootDir: envDir
});
return envPath ? Object.entries(mainExports$1.parse(fs.readFileSync(envPath))) : [];
})
);
parsed.NODE_ENV && process.env.VITE_USER_NODE_ENV === void 0 && (process.env.VITE_USER_NODE_ENV = parsed.NODE_ENV), parsed.BROWSER && process.env.BROWSER === void 0 && (process.env.BROWSER = parsed.BROWSER), parsed.BROWSER_ARGS && process.env.BROWSER_ARGS === void 0 && (process.env.BROWSER_ARGS = parsed.BROWSER_ARGS);
try {
mainExports.expand({ parsed });
} catch (e) {
throw e.message.includes("split") ? new Error("dotenv-expand failed to expand env vars. Maybe you need to escape `$`?") : e;
}
for (const [key, value] of Object.entries(parsed))
prefixes.some((prefix) => key.startsWith(prefix)) && (env[key] = value);
for (const key in process.env)
prefixes.some((prefix) => key.startsWith(prefix)) && (env[key] = process.env[key]);
return env;
}
function lookupFile(dir, formats, options) {
for (const format of formats) {
const fullPath = path.join(dir, format);
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile())
return fullPath;
}
const parentDir = path.dirname(dir);
if (parentDir !== dir && (!options?.rootDir || parentDir.startsWith(options?.rootDir)))
return lookupFile(parentDir, formats, options);
}
export {
createCliConfig,
defineCliConfig,
getCliClient,
loadEnv
};
//# sourceMappingURL=index.mjs.map