sanity
Version:
Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches
279 lines (278 loc) • 11.7 kB
JavaScript
;
var chalk = require("chalk"), extractManifestAction = require("./extractManifestAction.js"), telemetry = require("@sanity/telemetry"), uniqBy = require("lodash/uniqBy"), fs = require("node:fs/promises"), path = require("node:path");
function _interopDefaultCompat(e) {
return e && typeof e == "object" && "default" in e ? e : { default: e };
}
var chalk__default = /* @__PURE__ */ _interopDefaultCompat(chalk), uniqBy__default = /* @__PURE__ */ _interopDefaultCompat(uniqBy), path__default = /* @__PURE__ */ _interopDefaultCompat(path);
const SANITY_WORKSPACE_SCHEMA_ID_PREFIX = "_.schemas", CURRENT_WORKSPACE_SCHEMA_VERSION = "2025-05-01", GenerateManifest = telemetry.defineTrace({
name: "Manifest generation executed",
version: 1,
description: "Manifest generation was executed"
}), SchemaDeploy = telemetry.defineTrace({
name: "Schema deploy action executed",
version: 1,
description: "Schema deploy action was executed, either via sanity schema deploy or as sanity deploy"
});
function isDefined(value) {
return value != null;
}
const createManifestReader = ({
manifestDir,
output,
jsonReader = parseJsonFile
}) => {
let parsedManifest;
const parsedWorkspaces = {}, getManifest = async () => {
if (parsedManifest)
return parsedManifest?.parsedJson;
const manifestFile = path__default.default.join(manifestDir, extractManifestAction.MANIFEST_FILENAME), result = await jsonReader(manifestFile);
if (!result)
throw new Error(`Manifest does not exist at ${manifestFile}. To create the manifest file, omit --no-extract-manifest or run "sanity manifest extract" first.`);
return output.print(chalk__default.default.gray(`\u21B3 Read manifest from ${manifestFile} (last modified: ${result.lastModified})`)), parsedManifest = result, result.parsedJson;
};
return {
getManifest,
getWorkspaceSchema: async (workspaceName) => {
if (parsedWorkspaces[workspaceName])
return parsedWorkspaces[workspaceName]?.parsedJson;
const manifest = await getManifest();
if (!manifest)
throw Error("Manifest is required to read workspace schema.");
const workspaceManifest = manifest.workspaces.find((workspace) => workspace.name === workspaceName);
if (!workspaceManifest)
throw Error(`No workspace named "${workspaceName}" found in manifest.`);
const workspaceSchemaFile = path__default.default.join(manifestDir, workspaceManifest.schema ?? ""), result = await jsonReader(workspaceSchemaFile);
if (!result)
throw Error(`Workspace schema file at "${workspaceSchemaFile}" does not exist.`);
return parsedWorkspaces[workspaceName] = result, result.parsedJson;
}
};
};
function resolveManifestDirectory(workDir, customPath) {
const defaultOutputDir = path.resolve(path.join(workDir, "dist")), outputDir = path.resolve(defaultOutputDir), defaultStaticPath = path.join(outputDir, "static"), staticPath = customPath ?? defaultStaticPath;
return path__default.default.resolve(process.cwd(), staticPath);
}
async function parseJsonFile(filePath) {
let stats;
try {
stats = await fs.stat(filePath);
} catch {
return;
}
const content = await fs.readFile(filePath, "utf-8"), lastModified = stats.mtime.toISOString(), json = JSON.parse(content);
if (!json)
throw new Error(`JSON file "${filePath}" was empty.`);
return {
parsedJson: json,
path: filePath,
lastModified
};
}
const validForIdChars = "a-zA-Z0-9._-", validForIdPattern = new RegExp(`^[${validForIdChars}]+$`, "g"), validForNamesChars = "a-zA-Z0-9_-", validForNamesPattern = new RegExp(`^[${validForNamesChars}]+$`, "g"), requiredInId = SANITY_WORKSPACE_SCHEMA_ID_PREFIX.replace(/[.]/g, "\\."), idIdPatternString = `^${requiredInId}\\.([${validForNamesChars}]+)`, baseIdPattern = new RegExp(`${idIdPatternString}$`), taggedIdIdPattern = new RegExp(`${idIdPatternString}\\.tag\\.([${validForNamesChars}]+)$`);
class FlagValidationError extends Error {
constructor(message) {
super(message), this.name = "FlagValidationError";
}
}
function parseCommonFlags(flags, context, errors) {
const manifestDir = parseManifestDir(flags, errors), verbose = !!flags.verbose, extractManifest = flags["extract-manifest"] ?? !0;
return {
manifestDir: resolveManifestDirectory(context.workDir, manifestDir),
verbose,
extractManifest
};
}
function parseDeploySchemasConfig(flags, context) {
const errors = [], commonFlags = parseCommonFlags(flags, context, errors), workspaceName = parseWorkspace(flags, errors), tag = parseTag(flags, errors), schemaRequired = !!flags["schema-required"];
return assertNoErrors(errors), {
...commonFlags,
workspaceName,
tag,
schemaRequired
};
}
function parseListSchemasConfig(flags, context) {
const errors = [], commonFlags = parseCommonFlags(flags, context, errors), id = parseId(flags, errors), json = !!flags.json;
return assertNoErrors(errors), {
...commonFlags,
json,
id
};
}
function parseDeleteSchemasConfig(flags, context) {
const errors = [], commonFlags = parseCommonFlags(flags, context, errors), ids = parseIds(flags, errors), dataset = parseDataset(flags, errors);
return assertNoErrors(errors), {
...commonFlags,
dataset,
ids
};
}
function assertNoErrors(errors) {
if (errors.length)
throw new FlagValidationError(`Invalid arguments:
${errors.map((error) => ` - ${error}`).join(`
`)}`);
}
function parseIds(flags, errors) {
const parsedIds = parseNonEmptyString(flags, "ids", errors);
if (errors.length)
return [];
const ids = parsedIds.split(",").map((id) => id.trim()).filter((id) => !!id).map((id) => parseWorkspaceSchemaId(id, errors)).filter(isDefined), uniqueIds = uniqBy__default.default(ids, "schemaId");
return uniqueIds.length < ids.length && errors.push("ids contains duplicates"), !errors.length && !uniqueIds.length && errors.push("ids contains no valid id strings"), uniqueIds;
}
function parseId(flags, errors) {
const id = flags.id === void 0 ? void 0 : parseNonEmptyString(flags, "id", errors);
if (id)
return parseWorkspaceSchemaId(id, errors)?.schemaId;
}
function parseWorkspaceSchemaId(id, errors) {
const trimmedId = id.trim();
if (!trimmedId.match(validForIdPattern)) {
errors.push(`id can only contain characters in [${validForIdChars}] but found: "${trimmedId}"`);
return;
}
if (trimmedId.startsWith("-")) {
errors.push(`id cannot start with - (dash) but found: "${trimmedId}"`);
return;
}
if (trimmedId.match(/\.\./g)) {
errors.push(`id cannot have consecutive . (period) characters, but found: "${trimmedId}"`);
return;
}
const [fullMatch, workspace, tag] = trimmedId.match(taggedIdIdPattern) ?? trimmedId.match(baseIdPattern) ?? [];
if (!workspace) {
errors.push([`id must either match ${SANITY_WORKSPACE_SCHEMA_ID_PREFIX}.<workspaceName> `, `or ${SANITY_WORKSPACE_SCHEMA_ID_PREFIX}.<workspaceName>.tag.<tag> but found: "${trimmedId}". `, `Note that workspace name characters not in [${validForNamesChars}] has to be replaced with _ for schema id.`].join(""));
return;
}
return {
schemaId: trimmedId,
workspace
};
}
function parseDataset(flags, errors) {
return flags.dataset === void 0 ? void 0 : parseNonEmptyString(flags, "dataset", errors);
}
function parseWorkspace(flags, errors) {
return flags.workspace === void 0 ? void 0 : parseNonEmptyString(flags, "workspace", errors);
}
function parseManifestDir(flags, errors) {
return flags["manifest-dir"] === void 0 ? void 0 : parseNonEmptyString(flags, "manifest-dir", errors);
}
function parseTag(flags, errors) {
if (flags.tag === void 0)
return;
const tag = parseNonEmptyString(flags, "tag", errors);
if (!errors.length) {
if (tag.includes(".")) {
errors.push(`tag cannot contain . (period), but was: "${tag}"`);
return;
}
if (!tag.match(validForNamesPattern)) {
errors.push(`tag can only contain characters in [${validForNamesChars}], but was: "${tag}"`);
return;
}
if (tag.startsWith("-")) {
errors.push(`tag cannot start with - (dash) but was: "${tag}"`);
return;
}
return tag;
}
}
function parseNonEmptyString(flags, flagName, errors) {
const flag = flags[flagName];
return !isString(flag) || !flag ? (errors.push(`${flagName} argument is empty`), "") : flag;
}
function isString(flag) {
return typeof flag == "string";
}
const SCHEMA_PERMISSION_HELP_TEXT = "For multi-project workspaces, set SANITY_AUTH_TOKEN environment variable to a token with access to the workspace projects.";
async function ensureManifestExtractSatisfied(args) {
const {
schemaRequired,
extractManifest,
manifestDir,
manifestExtractor,
output,
telemetry: telemetry2
} = args;
if (!extractManifest)
return !0;
const trace = telemetry2.trace(GenerateManifest, {
manifestDir,
schemaRequired
});
try {
return trace.start(), await manifestExtractor(manifestDir), trace.complete(), !0;
} catch (err) {
if (trace.error(err), schemaRequired || err instanceof FlagValidationError)
throw err;
return output.print(chalk__default.default.gray(`\u21B3 Failed to extract manifest:
${err.message}`)), !1;
}
}
function createManifestExtractor(context) {
return async (manifestDir) => {
const error = await extractManifestAction.extractManifestSafe({
extOptions: {
path: manifestDir
},
groupOrCommand: "extract",
argv: [],
argsWithoutOptions: [],
extraArguments: []
}, context);
if (!context.safe && error)
throw error;
};
}
function createSchemaApiClient(apiClient) {
const client = apiClient({
requireUser: !0,
requireProject: !0
}).withConfig({
apiVersion: "v2025-03-01",
useCdn: !1
}), projectId = client.config().projectId, dataset = client.config().dataset;
if (!projectId) throw new Error("Project ID is not defined");
if (!dataset) throw new Error("Dataset is not defined");
return {
client,
projectId,
dataset
};
}
function getProjectIdDatasetsOutString(projectIdDatasets) {
return projectIdDatasets.length === 1 ? `${projectIdDatasetPair(projectIdDatasets[0])}` : `${getStringArrayOutString(projectIdDatasets.map(projectIdDatasetPair))}`;
}
function projectIdDatasetPair(pair) {
return JSON.stringify({
projectId: pair.projectId,
dataset: pair.dataset
});
}
function getStringArrayOutString(array) {
return `[${array.map((d) => `"${d}"`).join(",")}]`;
}
function getStringList(array) {
return array.map((s) => `- ${s}`).join(`
`);
}
exports.CURRENT_WORKSPACE_SCHEMA_VERSION = CURRENT_WORKSPACE_SCHEMA_VERSION;
exports.FlagValidationError = FlagValidationError;
exports.SANITY_WORKSPACE_SCHEMA_ID_PREFIX = SANITY_WORKSPACE_SCHEMA_ID_PREFIX;
exports.SCHEMA_PERMISSION_HELP_TEXT = SCHEMA_PERMISSION_HELP_TEXT;
exports.SchemaDeploy = SchemaDeploy;
exports.createManifestExtractor = createManifestExtractor;
exports.createManifestReader = createManifestReader;
exports.createSchemaApiClient = createSchemaApiClient;
exports.ensureManifestExtractSatisfied = ensureManifestExtractSatisfied;
exports.getProjectIdDatasetsOutString = getProjectIdDatasetsOutString;
exports.getStringList = getStringList;
exports.isDefined = isDefined;
exports.parseDeleteSchemasConfig = parseDeleteSchemasConfig;
exports.parseDeploySchemasConfig = parseDeploySchemasConfig;
exports.parseListSchemasConfig = parseListSchemasConfig;
exports.projectIdDatasetPair = projectIdDatasetPair;
exports.validForNamesChars = validForNamesChars;
exports.validForNamesPattern = validForNamesPattern;
//# sourceMappingURL=schemaStoreOutStrings.js.map