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
260 lines (259 loc) • 10.5 kB
JavaScript
;
var chalk = require("chalk"), extractManifestAction = require("./extractManifestAction.js"), 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_TYPE = "sanity.workspace.schema";
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"), requiredInId = SANITY_WORKSPACE_SCHEMA_TYPE.replace(/[.]/g, "\\."), idPattern = new RegExp(`^(?:[${validForIdChars}]+?\\.)?${requiredInId}\\.([${validForIdChars}]+)$`);
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), idPrefix = parseIdPrefix(flags, errors), schemaRequired = !!flags["schema-required"];
return assertNoErrors(errors), {
...commonFlags,
workspaceName,
idPrefix,
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 workspace = trimmedId.match(idPattern)?.[1] ?? "";
if (!workspace) {
errors.push(`id must end with ${SANITY_WORKSPACE_SCHEMA_TYPE}.<workspaceName> but found: "${trimmedId}"`);
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 parseIdPrefix(flags, errors) {
if (flags["id-prefix"] === void 0)
return;
const idPrefix = parseNonEmptyString(flags, "id-prefix", errors);
if (!errors.length) {
if (idPrefix.endsWith(".")) {
errors.push(`id-prefix argument cannot end with . (period), but was: "${idPrefix}"`);
return;
}
if (!idPrefix.match(validForIdPattern)) {
errors.push(`id-prefix can only contain _id compatible characters [${validForIdChars}], but was: "${idPrefix}"`);
return;
}
if (idPrefix.startsWith("-")) {
errors.push(`id-prefix cannot start with - (dash) but was: "${idPrefix}"`);
return;
}
if (idPrefix.match(/\.\./g)) {
errors.push(`id-prefix cannot have consecutive . (period) characters, but was: "${idPrefix}"`);
return;
}
return idPrefix;
}
}
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";
}
function getProjectIdMismatchMessage(workspace, operation) {
return `No permissions to ${operation} schema for workspace "${workspace.name}" with projectId "${workspace.projectId}"`;
}
function throwWriteProjectIdMismatch(workspace, projectId) {
if (workspace.projectId !== projectId)
throw new Error(getProjectIdMismatchMessage(workspace, "write"));
}
function filterLogReadProjectIdMismatch(workspace, projectId, output) {
const canRead = workspace.projectId === projectId;
return canRead || output.warn(`${getProjectIdMismatchMessage(workspace, "read")} \u2013 ignoring it.`), canRead;
}
async function ensureManifestExtractSatisfied(args) {
const {
schemaRequired,
extractManifest,
manifestDir,
manifestExtractor,
output
} = args;
if (!extractManifest)
return !0;
try {
return await manifestExtractor(manifestDir), !0;
} catch (err) {
if (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
};
}
exports.FlagValidationError = FlagValidationError;
exports.SANITY_WORKSPACE_SCHEMA_TYPE = SANITY_WORKSPACE_SCHEMA_TYPE;
exports.createManifestExtractor = createManifestExtractor;
exports.createManifestReader = createManifestReader;
exports.createSchemaApiClient = createSchemaApiClient;
exports.ensureManifestExtractSatisfied = ensureManifestExtractSatisfied;
exports.filterLogReadProjectIdMismatch = filterLogReadProjectIdMismatch;
exports.isDefined = isDefined;
exports.parseDeleteSchemasConfig = parseDeleteSchemasConfig;
exports.parseDeploySchemasConfig = parseDeploySchemasConfig;
exports.parseListSchemasConfig = parseListSchemasConfig;
exports.throwWriteProjectIdMismatch = throwWriteProjectIdMismatch;
exports.validForIdChars = validForIdChars;
exports.validForIdPattern = validForIdPattern;
//# sourceMappingURL=schemaApiClient.js.map