UNPKG

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

1,403 lines • 61.5 kB
"use strict"; var get = require("lodash/get.js"), oneline = require("oneline"), helpers = require("yargs/helpers"), yargs = require("yargs/yargs"), _internal = require("./_internal.js"), getIt = require("get-it"), middleware = require("get-it/middleware"), generateHelpUrl_esm = require("./generate-help-url.esm.js"), schema = require("@sanity/schema"), types = require("@sanity/types"), startCase = require("lodash/startCase.js"), uniqBy = require("lodash/uniqBy.js"), upperFirst = require("lodash/upperFirst.js"), logSymbols = require("log-symbols"), flatten = require("lodash/flatten.js"), pluralize = require("pluralize-esm"), getGraphQLAPIs = require("./getGraphQLAPIs.js"); function _interopDefaultCompat(e) { return e && typeof e == "object" && "default" in e ? e : { default: e }; } var get__default = /* @__PURE__ */ _interopDefaultCompat(get), oneline__default = /* @__PURE__ */ _interopDefaultCompat(oneline), yargs__default = /* @__PURE__ */ _interopDefaultCompat(yargs), startCase__default = /* @__PURE__ */ _interopDefaultCompat(startCase), uniqBy__default = /* @__PURE__ */ _interopDefaultCompat(uniqBy), upperFirst__default = /* @__PURE__ */ _interopDefaultCompat(upperFirst), logSymbols__default = /* @__PURE__ */ _interopDefaultCompat(logSymbols), flatten__default = /* @__PURE__ */ _interopDefaultCompat(flatten), pluralize__default = /* @__PURE__ */ _interopDefaultCompat(pluralize); const request = getIt.getIt([middleware.promise()]); class HttpError extends Error { constructor(message) { super(message), this.name = "HttpError"; } } async function getUrlHeaders(url, headers = {}) { const response = await request({ url, stream: !0, maxRedirects: 0, method: "HEAD", headers }); if (response.statusCode >= 400) { const error = new HttpError(`Request returned HTTP ${response.statusCode}`); throw error.statusCode = response.statusCode, error; } return response.body.resume(), response.headers; } const SCHEMA_LIFT_ANONYMOUS_OBJECT_TYPE = "schema-lift-anonymous-object-type", consoleOutputter = { error: (...args) => console.error(...args) }; class SchemaError extends Error { constructor(problemGroups) { super("Schema errors encountered"), this.name = "SchemaError", this.problemGroups = problemGroups; } print(output) { (output || consoleOutputter).error(`Uh oh\u2026 found errors in schema: `), this.problemGroups.forEach((group) => { group.problems.forEach((problem) => { const icon = logSymbols__default.default[problem.severity] || logSymbols__default.default.info; output.error(` ${icon} ${upperFirst__default.default(problem.severity)}: ${getPath(group.path)}`), output.error(` ${problem.message}`), problem.helpId && output.error(` See ${generateHelpUrl_esm.generateHelpUrl(problem.helpId)}`), output.error(""); }); }); } } function getPath(path) { return path.map((segment) => segment.kind === "type" && segment.name && segment.type ? `${segment.name} - (${segment.type})` : segment.kind === "property" && segment.name ? segment.name : null).filter(Boolean).join(" / "); } const skipTypes = ["document", "reference"], allowedJsonTypes = ["object", "array"], disallowedCustomizedMembers = ["object", "array", "image", "file", "block"], disabledBlockFields = ["markDefs"], scalars = ["string", "number", "boolean"], internal = Symbol("internal"); function getBaseType(baseSchema, typeName) { return typeName === "crossDatasetReference" ? schema.Schema.compile({ types: [{ name: "__placeholder__", type: "crossDatasetReference", // Just needs _something_ to refer to, doesn't matter what to: [{ type: "sanity.imageAsset" }] }], parent: baseSchema }).get("__placeholder__") : typeName === "globalDocumentReference" ? schema.Schema.compile({ types: [{ name: "__placeholder__", type: "globalDocumentReference", // Just needs _something_ to refer to, doesn't matter what to: [{ type: "sanity.imageAsset" }] }], parent: baseSchema }).get("__placeholder__") : schema.Schema.compile({ types: [{ name: "__placeholder__", type: typeName, options: { hotspot: !0 } }], parent: baseSchema }).get("__placeholder__"); } function getTypeName(str) { const name = startCase__default.default(str).replace(/\s+/g, ""); return name === "Number" ? "Float" : name; } function isBaseType(type) { return type.name !== type.jsonType && allowedJsonTypes.includes(type.jsonType) && !skipTypes.includes(type.name) && !isReference(type); } function isBlockType(typeDef) { return typeDef.name === "block" ? !0 : typeDef.type ? isBlockType(typeDef.type) : !1; } function hasBlockParent(typeDef) { return typeDef.type && typeDef.type.name === "block" && !typeDef.type.type ? !0 : !!(typeDef.type && hasBlockParent(typeDef.type)); } function isArrayOfBlocks(typeDef) { const type = typeDef.type || typeDef; return !("jsonType" in type) || type.jsonType !== "array" ? !1 : (type.of || []).some(hasBlockParent); } function isType(typeDef, typeName) { let type = typeDef; for (; type; ) { if (type.name === typeName || type.type && type.type.name === typeName) return !0; type = type.type; } return !1; } function isReference(typeDef) { return isType(typeDef, "reference"); } function isCrossDatasetReference(typeDef) { return isType(typeDef, "crossDatasetReference"); } function getCrossDatasetReferenceMetadata(typeDef) { if (!isCrossDatasetReference(typeDef)) return; function getTypeNames(type) { if (type) return "to" in type ? type.to.map((t) => t.type).filter((t) => typeof t == "string") : getTypeNames(type.type); } function getDataset(type) { if (type) { if ("dataset" in type && typeof type.dataset == "string") return type.dataset; if (type.type) return getDataset(type.type); } } const typeNames = getTypeNames(typeDef); if (!typeNames) return; const dataset = getDataset(typeDef); if (typeof dataset == "string") return { typeNames, dataset }; } function extractFromSanitySchema(sanitySchema, extractOptions = {}) { const { nonNullDocumentFields, withUnionCache } = extractOptions, unionRecursionGuards = /* @__PURE__ */ new Set(), unionDefinitionCache = /* @__PURE__ */ new Map(); if (sanitySchema._validation && sanitySchema._validation.some((group) => group.problems.some((problem) => problem.severity === "error")) && Array.isArray(sanitySchema._validation)) throw new SchemaError(sanitySchema._validation); const sanityTypes = sanitySchema._original?.types || [], typeNames = sanitySchema.getTypeNames(), unionTypes = [], types2 = []; for (const typeName of typeNames) { const schemaType = sanitySchema.get(typeName); if (schemaType === void 0 || !isBaseType(schemaType)) continue; const convertedType = convertType(schemaType); types2.push(convertedType); } return { types: [...types2, ...unionTypes], interfaces: [getDocumentInterfaceDefinition()] }; function isTopLevelType(typeName) { return typeNames.includes(typeName); } function mapFieldType(field) { if (!field.type) throw new Error("Field has no type!"); const jsonType = "jsonType" in field ? field.jsonType : "", isScalar = scalars.includes(jsonType); if (isScalar && jsonType === "number") return hasValidationFlag(field, "integer") ? "Int" : "Float"; if (isScalar) return getTypeName(jsonType); const type = field.type.type || field.type; if (type.type) return mapFieldType(type); switch (type.name) { case "number": return hasValidationFlag(field, "integer") ? "Int" : "Float"; default: return getTypeName(type.name); } } function isArrayType(type) { return !!("jsonType" in type && type.jsonType === "array" || type.type && type.type.jsonType === "array"); } function _convertType(type, parent, options) { let name; return type.type ? name = type.type.name : "jsonType" in type && (name = type.jsonType), isReference(type) ? getReferenceDefinition(type) : isArrayType(type) ? getArrayDefinition(type, parent, options) : name === "document" ? getDocumentDefinition(type) : name === "block" || name === "object" || hasFields(type) ? getObjectDefinition(type, parent) : { type: mapFieldType(type), description: getDescription(type) }; } function convertType(type, parent, props = {}) { const mapped = _convertType(type, parent || "", { isField: !!props.fieldName }), gqlName = props.fieldName || mapped.name, originalName = type.name, original = gqlName === originalName ? {} : { originalName }, crossDatasetReferenceMetadata = getCrossDatasetReferenceMetadata(type); return { ...getDeprecation$1(type.type), ...props, ...mapped, ...original, ...crossDatasetReferenceMetadata && { crossDatasetReferenceMetadata } }; } function isField(def) { return !("jsonType" in def) || !def.jsonType; } function getObjectDefinition(def, parent) { const isInline = isField(def), isDocument = def.type ? def.type.name === "document" : !1, actualType = isInline ? def.type : def; if (typeNeedsHoisting(actualType)) throw createLiftTypeError(def.name, parent || "", actualType.name); if (isInline && parent && def.type.name === "object") throw createLiftTypeError(def.name, parent); if (parent && def.type && isTopLevelType(def.type.name)) return { type: getTypeName(def.type.name) }; const name = `${parent || ""}${getTypeName(def.name)}`, fields = collectFields(def), firstUnprefixed = Math.max(0, fields.findIndex((field) => field.name[0] !== "_")), keyField = createStringField("_key"); fields.splice(firstUnprefixed, 0, keyField), isDocument || fields.splice(firstUnprefixed + 1, 0, createStringField("_type")); const objectFields = isBlockType(def) ? fields.filter((field) => !disabledBlockFields.includes(field.name)) : fields; return { kind: "Type", name, type: "Object", description: getDescription(def), fields: objectFields.map((field) => isArrayOfBlocks(field) ? buildRawField(field, name) : convertType(field, name, { fieldName: field.name, ...getDeprecation$1(def) })), [internal]: { ...getDeprecation$1(def) } }; } function buildRawField(field, parentName) { return { ...convertType(field, parentName, { fieldName: `${field.name}Raw` }), type: "JSON", isRawAlias: !0 }; } function createStringField(name) { return { name, type: { jsonType: "string", name: "string", type: { name: "string", type: void 0, jsonType: "string" } } }; } function collectFields(def) { const fields = gatherAllFields(def); if (fields.length > 0) return fields; const extended = getBaseType(sanitySchema, def.name); return gatherAllFields(extended); } function getReferenceDefinition(def, parent) { const base = { description: getDescription(def), isReference: !0 }, candidates = arrayify(gatherAllReferenceCandidates(def)); if (candidates.length === 0) throw new Error("No candidates for reference"); if (candidates.length === 1) return { type: getTypeName(candidates[0].type.name), ...base }; const allTypeNames = candidates.map((c) => getTypeName(c.type.name)), targetTypes = [...new Set(allTypeNames)].sort(), name = targetTypes.join("Or"); return unionTypes.some((item) => item.name === name) || unionTypes.push({ kind: "Union", name, types: targetTypes }), { type: name, ...base }; } function getArrayDefinition(def, parent, options = {}) { const base = { description: getDescription(def), kind: "List" }, name = !options.isField && def.name ? { name: getTypeName(def.name) } : {}, candidates = def.type?.type && "of" in def.type ? arrayify(def.type.of) : def.of; return candidates.length === 1 ? { children: getArrayChildDefinition(candidates[0], def), ...base, ...name } : { children: getUnionDefinition(candidates, def, { grandParent: parent }), ...base, ...name }; } function getArrayChildDefinition(child, arrayDef) { if (typeNeedsHoisting(child)) throw createLiftTypeError(child.name, arrayDef.name); return isReference(child) ? getReferenceDefinition(child) : scalars.includes(child.jsonType) && !scalars.includes(child.name) ? { type: mapFieldType(child) } : { type: getTypeName(child.name) }; } function typeNeedsHoisting(type) { return !!(type.name === "object" || type.jsonType === "object" && !isTopLevelType(type.name) || type.isCustomized && !isTopLevelType(type.name) || type.isCustomized && disallowedCustomizedMembers.includes(type.name)); } function getUnionDefinition(candidates, parent, options = {}) { if (candidates.length < 2) throw new Error("Not enough candidates for a union type"); const guardPathName = `${typeof parent == "object" ? parent.name : parent}`; if (unionRecursionGuards.has(guardPathName)) return {}; const unionCacheKey = `${options.grandParent}-${guardPathName}-${candidates.map((c) => c.type?.name).join("-")}`; if (withUnionCache && unionDefinitionCache.has(unionCacheKey)) return unionDefinitionCache.get(unionCacheKey); try { unionRecursionGuards.add(guardPathName), candidates.forEach((def, i) => { if (typeNeedsHoisting(def)) throw createLiftTypeArrayError(i, parent.name, def.type ? def.type.name : def.name, options.grandParent); }); const converted = candidates.map((def) => convertType(def)), getName = (def) => typeof def.type == "string" ? def.type : def.type.name, flattened = converted.reduce((acc, candidate) => { const union = unionTypes.find((item) => item.name === candidate.type); return union ? acc.concat(union.types.map((type) => ({ type, isReference: candidate.isReference }))) : acc.concat(candidate); }, []); let allCandidatesAreDocuments = !0; const refs = [], inlineObjs = [], allTypeNames = []; for (const def of flattened) { def.isReference && refs.push(def.type), isReference || inlineObjs.push(def.name || ""); const typeName = typeof def.type == "string" ? def.type : def.type.name; (def.name || def.type) && allTypeNames.push(def.isReference ? typeName : def.name || ""); const typeDef = sanityTypes.find((type) => type.name === getName(def)); (!typeDef || typeDef.type !== "document") && (allCandidatesAreDocuments = !1); } const interfaces = allCandidatesAreDocuments ? ["Document"] : void 0, possibleTypes = [...new Set(allTypeNames)].sort(); if (possibleTypes.length < 2) throw new Error(`Not enough types for a union type. Parent: ${parent.name}`); const name = possibleTypes.join("Or"); unionTypes.some((item) => item.name === name) || unionTypes.push({ kind: "Union", name, types: possibleTypes, interfaces }); const references = refs.length > 0 ? refs : void 0, inlineObjects = inlineObjs.length > 0 ? inlineObjs : void 0, unionDefinition = isReference(parent) ? { type: name, references } : { type: name, references, inlineObjects }; return unionDefinitionCache.set(unionCacheKey, unionDefinition), unionDefinition; } finally { unionRecursionGuards.delete(guardPathName); } } function getDocumentDefinition(def) { const objectDef = getObjectDefinition(def), fields = getDocumentInterfaceFields(def).concat(objectDef.fields); return { ...objectDef, fields, interfaces: ["Document"] }; } function getDocumentInterfaceDefinition() { return { kind: "Interface", name: "Document", description: "A Sanity document", fields: getDocumentInterfaceFields() }; } function getDocumentInterfaceFields(type) { const isNullable = typeof nonNullDocumentFields == "boolean" ? !nonNullDocumentFields : !0; return [{ fieldName: "_id", type: "ID", isNullable, description: "Document ID", ...getDeprecation$1(type) }, { fieldName: "_type", type: "String", isNullable, description: "Document type", ...getDeprecation$1(type) }, { fieldName: "_createdAt", type: "Datetime", isNullable, description: "Date the document was created", ...getDeprecation$1(type) }, { fieldName: "_updatedAt", type: "Datetime", isNullable, description: "Date the document was last modified", ...getDeprecation$1(type) }, { fieldName: "_rev", type: "String", isNullable, description: "Current document revision", ...getDeprecation$1(type) }]; } function arrayify(thing) { return Array.isArray(thing) ? thing : thing === null || typeof thing > "u" ? [] : [thing]; } function hasValidationFlag(field, flag) { return "validation" in field && Array.isArray(field.validation) && field.validation.some((rule) => rule && "_rules" in rule && rule._rules.some((item) => item.flag === flag)); } function getDescription(type) { const description = type.type && type.type.description; return typeof description == "string" ? description : void 0; } function gatherAllReferenceCandidates(type) { const allFields = gatherReferenceCandidates(type); return uniqBy__default.default(allFields, "name"); } function gatherReferenceCandidates(type) { const refTo = "to" in type ? type.to : []; return "type" in type && type.type ? [...gatherReferenceCandidates(type.type), ...refTo] : refTo; } function gatherAllFields(type) { const allFields = gatherFields(type); return uniqBy__default.default(allFields, "name"); } function gatherFields(type) { return "fields" in type ? type.type ? gatherFields(type.type).concat(type.fields) : type.fields : []; } function hasFieldsLikeShape(type) { return typeof type == "object" && type !== null && "fields" in type; } function hasArrayOfFields(type) { return hasFieldsLikeShape(type) && Array.isArray(type.fields); } function hasFields(type) { return hasArrayOfFields(type) ? gatherAllFields(type).length > 0 : "type" in type && type.type ? hasFields(type.type) : !1; } } function createLiftTypeArrayError(index, parent, inlineType = "object", grandParent = "") { const helpUrl = generateHelpUrl_esm.generateHelpUrl(SCHEMA_LIFT_ANONYMOUS_OBJECT_TYPE), context = [grandParent, parent].filter(Boolean).join("/"); return new HelpfulError(oneline__default.default` Encountered anonymous inline ${inlineType} at index ${index} for type/field ${context}. To use this type with GraphQL you will need to create a top-level schema type for it. See ${helpUrl}`, helpUrl); } function createLiftTypeError(typeName, parent, inlineType = "object") { const helpUrl = generateHelpUrl_esm.generateHelpUrl(SCHEMA_LIFT_ANONYMOUS_OBJECT_TYPE); return new HelpfulError(oneline__default.default` Encountered anonymous inline ${inlineType} "${typeName}" for field/type "${parent}". To use this field with GraphQL you will need to create a top-level schema type for it. See ${helpUrl}`, helpUrl); } class HelpfulError extends Error { constructor(message, helpUrl) { super(message), this.name = "HelpfulError", this.helpUrl = helpUrl; } } function getDeprecation$1(type) { return types.isDeprecationConfiguration(type) ? { deprecationReason: type.deprecated.reason } : {}; } function isUnion(type) { return type.kind === "Union"; } function isNonUnion(type) { return !isUnion(type) && "type" in type; } function isDocumentType(type) { return isNonUnion(type) && type.type === "Object" && Array.isArray(type.interfaces) && type.interfaces.includes("Document"); } const filterCreators$2 = { ID: createIdFilters$1, String: createStringFilters$1, Url: createStringFilters$1, Float: createNumberFilters, Integer: createNumberFilters, Boolean: createBooleanFilters$1, Datetime: createDateFilters$1, Date: createDateFilters$1, Object: createObjectFilters }; function generateTypeFilters$2(types2) { return types2.filter(isNonUnion).filter((type) => type.type === "Object" && type.interfaces && type.interfaces.includes("Document")).map((type) => { const name = `${type.name}Filter`, fields = flatten__default.default(type.fields.map(createFieldFilters$2)).filter(Boolean); return { name, kind: "InputObject", fields: [...fields, ...getDocumentFilters$2()] }; }); } function createFieldFilters$2(field) { return filterCreators$2[field.type] ? filterCreators$2[field.type](field) : field.kind === "List" ? createListFilters() : field.isReference ? createReferenceFilters(field) : createInlineTypeFilters(); } function getFieldName(field, modifier = "") { const suffix = modifier ? `_${modifier}` : ""; return `${field.fieldName}${suffix}`; } function getDocumentFilters$2() { return [{ fieldName: "references", type: "ID", description: "All documents references the given document ID", constraint: { comparator: "REFERENCES" } }, { fieldName: "is_draft", type: "Boolean", description: "All documents that are drafts", constraint: { field: "_id", comparator: "IS_DRAFT" } }]; } function createIsDefinedFilter(field) { return { fieldName: getFieldName(field, "is_defined"), type: "Boolean", description: "All documents that have a value for this field", constraint: { field: field.fieldName, comparator: "IS_DEFINED" } }; } function createEqualityFilter(field) { return { fieldName: getFieldName(field), type: field.type, description: "All documents that are equal to given value", constraint: { field: field.fieldName, comparator: "EQUALS" } }; } function createInequalityFilter(field) { return { fieldName: getFieldName(field, "not"), type: field.type, description: "All documents that are not equal to given value", constraint: { field: field.fieldName, comparator: "NOT_EQUALS" } }; } function createDefaultFilters(field) { return [createEqualityFilter(field), createInequalityFilter(field), createIsDefinedFilter(field)]; } function createGtLtFilters(field) { return [{ fieldName: getFieldName(field, "lt"), type: field.type, description: "All documents are less than given value", constraint: { field: field.fieldName, comparator: "LT" } }, { fieldName: getFieldName(field, "lte"), type: field.type, description: "All documents are less than or equal to given value", constraint: { field: field.fieldName, comparator: "LTE" } }, { fieldName: getFieldName(field, "gt"), type: field.type, description: "All documents are greater than given value", constraint: { field: field.fieldName, comparator: "GT" } }, { fieldName: getFieldName(field, "gte"), type: field.type, description: "All documents are greater than or equal to given value", constraint: { field: field.fieldName, comparator: "GTE" } }]; } function createBooleanFilters$1(field) { return createDefaultFilters(field); } function createIdFilters$1(field) { return createStringFilters$1(field); } function createDateFilters$1(field) { return createDefaultFilters(field).concat(createGtLtFilters(field)); } function createStringFilters$1(field) { return [...createDefaultFilters(field), { fieldName: getFieldName(field, "matches"), type: "String", description: "All documents contain (match) the given word/words", constraint: { field: field.fieldName, comparator: "MATCHES" } }, { fieldName: getFieldName(field, "in"), kind: "List", children: { type: "String", isNullable: !1 }, description: "All documents match one of the given values", constraint: { field: field.fieldName, comparator: "IN" } }, { fieldName: getFieldName(field, "not_in"), kind: "List", children: { type: "String", isNullable: !1 }, description: "None of the values match any of the given values", constraint: { field: field.fieldName, comparator: "NOT_IN" } }]; } function createNumberFilters(field) { return createDefaultFilters(field).concat(createGtLtFilters(field)); } function createObjectFilters(field) { return []; } function createListFilters() { return []; } function createInlineTypeFilters() { return []; } function createReferenceFilters(field) { return [{ fieldName: getFieldName(field), type: "ID", constraint: { field: `${field.fieldName}._ref`, comparator: "EQUALS" } }]; } function pluralizeTypeName(name) { const words = startCase__default.default(name).split(" "), last = words[words.length - 1], plural = pluralize__default.default(last.toLowerCase()).replace(/(\d)s$/g, "$1S"); return words[words.length - 1] = upperFirst__default.default(plural), words.join(""); } function generateTypeQueries$2(types2, filters) { const queries = [], queryable = types2.filter(isNonUnion).filter((type) => type.type === "Object" && type.interfaces && type.interfaces.includes("Document")); return queryable.forEach((type) => { queries.push({ fieldName: type.name, type: type.name, constraints: [{ field: "_id", comparator: "EQUALS", value: { kind: "argumentValue", argName: "id" } }], args: [{ name: "id", description: `${type.name} document ID`, type: "ID", isNullable: !1 }] }); }), queryable.forEach((type) => { const filterName = `${type.name}Filter`, hasFilter = filters.find((filter) => filter.name === filterName); queries.push({ fieldName: `all${pluralizeTypeName(type.name)}`, filter: `_type == "${type.originalName || type.name}"`, type: { kind: "List", isNullable: !1, children: { type: type.name, isNullable: !1 } }, args: hasFilter ? [{ name: "where", type: filterName, isFieldFilter: !0 }, ...getLimitOffsetArgs()] : getLimitOffsetArgs() }); }), queries; } function getLimitOffsetArgs() { return [{ name: "limit", type: "Int", description: "Max documents to return", isFieldFilter: !1 }, { name: "offset", type: "Int", description: "Offset at which to start returning documents from", isFieldFilter: !1 }]; } var gen1 = (extracted) => { const filters = generateTypeFilters$2(extracted.types), queries = generateTypeQueries$2(extracted.types, filters); return { types: [...extracted.types, ...filters], queries, interfaces: extracted.interfaces, generation: "gen1" }; }; function createBooleanFilters() { return { name: "BooleanFilter", kind: "InputObject", isConstraintFilter: !0, fields: [{ fieldName: "eq", type: "Boolean", description: "Checks if the value is equal to the given input." }, { fieldName: "neq", type: "Boolean", description: "Checks if the value is not equal to the given input." }, { fieldName: "is_defined", type: "Boolean", description: "Checks if the value is defined." }] }; } function createDateFilters() { return { name: "DateFilter", kind: "InputObject", isConstraintFilter: !0, fields: [{ fieldName: "eq", type: "Date", description: "Checks if the value is equal to the given input." }, { fieldName: "neq", type: "Date", description: "Checks if the value is not equal to the given input." }, { fieldName: "gt", type: "Date", description: "Checks if the value is greater than the given input." }, { fieldName: "gte", type: "Date", description: "Checks if the value is greater than or equal to the given input." }, { fieldName: "lt", type: "Date", description: "Checks if the value is lesser than the given input." }, { fieldName: "lte", type: "Date", description: "Checks if the value is lesser than or equal to the given input." }, { fieldName: "is_defined", type: "Boolean", description: "Checks if the value is defined." }] }; } function createDateTimeFilters() { return { name: "DatetimeFilter", kind: "InputObject", isConstraintFilter: !0, fields: [{ fieldName: "eq", type: "Datetime", description: "Checks if the value is equal to the given input." }, { fieldName: "neq", type: "Datetime", description: "Checks if the value is not equal to the given input." }, { fieldName: "gt", type: "Datetime", description: "Checks if the value is greater than the given input." }, { fieldName: "gte", type: "Datetime", description: "Checks if the value is greater than or equal to the given input." }, { fieldName: "lt", type: "Datetime", description: "Checks if the value is lesser than the given input." }, { fieldName: "lte", type: "Datetime", description: "Checks if the value is lesser than or equal to the given input." }, { fieldName: "is_defined", type: "Boolean", description: "Checks if the value is defined." }] }; } function createDocumentFilters$1() { return { name: "DocumentFilter", kind: "InputObject", isConstraintFilter: !0, fields: [{ fieldName: "references", type: "ID", description: "All documents referencing the given document ID." }, { fieldName: "is_draft", type: "Boolean", description: "All documents that are drafts." }] }; } function createFloatFilters() { return { name: "FloatFilter", kind: "InputObject", isConstraintFilter: !0, fields: [{ fieldName: "eq", type: "Float", description: "Checks if the value is equal to the given input." }, { fieldName: "neq", type: "Float", description: "Checks if the value is not equal to the given input." }, { fieldName: "gt", type: "Float", description: "Checks if the value is greater than the given input." }, { fieldName: "gte", type: "Float", description: "Checks if the value is greater than or equal to the given input." }, { fieldName: "lt", type: "Float", description: "Checks if the value is lesser than the given input." }, { fieldName: "lte", type: "Float", description: "Checks if the value is lesser than or equal to the given input." }, { fieldName: "is_defined", type: "Boolean", description: "Checks if the value is defined." }] }; } function createIdFilters() { return { name: "IDFilter", kind: "InputObject", isConstraintFilter: !0, fields: [{ fieldName: "eq", type: "ID", description: "Checks if the value is equal to the given input." }, { fieldName: "neq", type: "ID", description: "Checks if the value is not equal to the given input." }, { fieldName: "matches", type: "ID", description: "Checks if the value matches the given word/words." }, { fieldName: "in", kind: "List", children: { type: "ID", isNullable: !1 }, description: "Checks if the value is equal to one of the given values." }, { fieldName: "nin", kind: "List", children: { type: "ID", isNullable: !1 }, description: "Checks if the value is not equal to one of the given values." }] }; } function createIntegerFilters() { return { name: "IntFilter", kind: "InputObject", isConstraintFilter: !0, fields: [{ fieldName: "eq", type: "Int", description: "Checks if the value is equal to the given input." }, { fieldName: "neq", type: "Int", description: "Checks if the value is not equal to the given input." }, { fieldName: "gt", type: "Int", description: "Checks if the value is greater than the given input." }, { fieldName: "gte", type: "Int", description: "Checks if the value is greater than or equal to the given input." }, { fieldName: "lt", type: "Int", description: "Checks if the value is lesser than the given input." }, { fieldName: "lte", type: "Int", description: "Checks if the value is lesser than or equal to the given input." }, { fieldName: "is_defined", type: "Boolean", description: "Checks if the value is defined." }] }; } function createStringFilters() { return { name: "StringFilter", kind: "InputObject", isConstraintFilter: !0, fields: [{ fieldName: "eq", type: "String", description: "Checks if the value is equal to the given input." }, { fieldName: "neq", type: "String", description: "Checks if the value is not equal to the given input." }, { fieldName: "matches", type: "String", description: "Checks if the value matches the given word/words." }, { fieldName: "in", kind: "List", children: { type: "String", isNullable: !1 }, description: "Checks if the value is equal to one of the given values." }, { fieldName: "nin", kind: "List", children: { type: "String", isNullable: !1 }, description: "Checks if the value is not equal to one of the given values." }, { fieldName: "is_defined", type: "Boolean", description: "Checks if the value is defined." }] }; } const typeAliases$1 = { Url: "String", Text: "String", Email: "String" }, filterCreators$1 = { ID: createIdFilters, String: createStringFilters, Float: createFloatFilters, Integer: createIntegerFilters, Boolean: createBooleanFilters, Datetime: createDateTimeFilters, Date: createDateFilters, Document: createDocumentFilters$1 }; function generateTypeFilters$1(types2) { const builtInTypeKeys = Object.keys(filterCreators$1), builtinTypeValues = Object.values(filterCreators$1), objectTypes = types2.filter(isNonUnion).filter((type) => type.type === "Object" && !["Block", "Span"].includes(type.name) && !type.interfaces && !builtInTypeKeys.includes(type.type)), unionTypes = types2.filter(isUnion).map((type) => type.name), documentTypes = types2.filter(isNonUnion).filter((type) => type.type === "Object" && type.interfaces && type.interfaces.includes("Document")), builtinTypeFilters = createBuiltinTypeFilters$1(builtinTypeValues), objectTypeFilters = createObjectTypeFilters$1(objectTypes, { unionTypes }), documentTypeFilters = createDocumentTypeFilters$1(documentTypes, { unionTypes }); return [...builtinTypeFilters, ...objectTypeFilters, ...documentTypeFilters]; } function createBuiltinTypeFilters$1(builtinTypeValues) { return builtinTypeValues.map((filterCreator) => filterCreator()); } function createObjectTypeFilters$1(objectTypes, options) { return objectTypes.map((objectType) => ({ name: `${objectType.name}Filter`, kind: "InputObject", fields: createFieldFilters$1(objectType, options) })); } function createDocumentTypeFilters$1(documentTypes, options) { return documentTypes.map((documentType) => ({ name: `${documentType.name}Filter`, kind: "InputObject", fields: [...getDocumentFilters$1(), ...createFieldFilters$1(documentType, options)] })); } function createFieldFilters$1(objectType, options) { const { unionTypes } = options; return objectType.fields.filter((field) => field.type !== "JSON" && field.kind !== "List" && !unionTypes.includes(field.type)).map((field) => ({ fieldName: field.fieldName, type: `${typeAliases$1[field.type] || field.type}Filter`, isReference: field.isReference })); } function getDocumentFilters$1() { return [{ fieldName: "_", type: "DocumentFilter", description: "Apply filters on document level" }]; } function generateTypeQueries$1(types2, sortings) { const queries = [], queryable = types2.filter(isDocumentType), isSortable = (type) => sortings.some((sorting) => sorting.name === `${type.name}Sorting`); return queries.push({ fieldName: "Document", type: "Document", constraints: [{ field: "_id", comparator: "eq", value: { kind: "argumentValue", argName: "id" } }], args: [{ name: "id", description: "Document ID", type: "ID", isNullable: !1 }] }), queryable.forEach((type) => { queries.push({ fieldName: type.name, type: type.name, constraints: [{ field: "_id", comparator: "eq", value: { kind: "argumentValue", argName: "id" } }], args: [{ name: "id", description: `${type.name} document ID`, type: "ID", isNullable: !1 }] }); }), queryable.forEach((type) => { const sorting = []; isSortable(type) && sorting.push({ name: "sort", type: { kind: "List", isNullable: !0, children: { type: `${type.name}Sorting`, isNullable: !1 } } }), queries.push({ fieldName: `all${upperFirst__default.default(type.name)}`, filter: `_type == "${type.originalName || type.name}"`, type: { kind: "List", isNullable: !1, children: { type: type.name, isNullable: !1 } }, args: [{ name: "where", type: `${type.name}Filter`, isFieldFilter: !0 }, ...sorting, { name: "limit", type: "Int", description: "Max documents to return", isFieldFilter: !1 }, { name: "offset", type: "Int", description: "Offset at which to start returning documents from", isFieldFilter: !1 }] }); }), queries; } const builtInTypes$1 = ["Boolean", "Date", "Datetime", "Email", "Float", "ID", "Integer", "String", "Text", "Url"], builtInSortingEnum$1 = { name: "SortOrder", kind: "Enum", values: [{ name: "ASC", description: "Sorts on the value in ascending order.", value: 1 }, { name: "DESC", description: "Sorts on the value in descending order.", value: 2 }] }; function generateTypeSortings$1(types2) { const objectTypes = types2.filter(isNonUnion).filter((type) => type.type === "Object" && !["Block", "Span"].includes(type.name) && // TODO: What do we do with blocks? !type.interfaces && !builtInTypes$1.includes(type.name)), documentTypes = types2.filter(isDocumentType), hasFields = (type) => type.fields.length > 0, objectTypeSortings = createObjectTypeSortings$1(objectTypes), documentTypeSortings = createDocumentTypeSortings$1(documentTypes); return [...[...objectTypeSortings, ...documentTypeSortings].filter(hasFields), builtInSortingEnum$1]; } function createObjectTypeSortings$1(objectTypes) { return objectTypes.map((objectType) => ({ name: `${objectType.name}Sorting`, kind: "InputObject", fields: objectType.fields.filter((field) => field.type !== "JSON" && field.kind !== "List").filter((field) => !field.isReference).map((field) => ({ fieldName: field.fieldName, type: builtInTypes$1.includes(field.type) ? builtInSortingEnum$1.name : `${field.type}Sorting` })) })); } function createDocumentTypeSortings$1(documentTypes) { return documentTypes.map((documentType) => ({ name: `${documentType.name}Sorting`, kind: "InputObject", fields: documentType.fields.filter((field) => field.type !== "JSON" && field.kind !== "List").filter((field) => !field.isReference).map((field) => ({ fieldName: field.fieldName, type: builtInTypes$1.includes(field.type) ? builtInSortingEnum$1.name : `${field.type}Sorting` })) })); } var gen2 = (extracted) => { const filters = generateTypeFilters$1(extracted.types), sortings = generateTypeSortings$1(extracted.types), queries = generateTypeQueries$1(extracted.types, sortings.filter((node) => node.kind === "InputObject")); return { types: [...extracted.types, ...filters, ...sortings], queries, interfaces: extracted.interfaces, generation: "gen2" }; }; function createDocumentFilters() { return { name: "Sanity_DocumentFilter", kind: "InputObject", isConstraintFilter: !0, fields: [{ fieldName: "references", type: "ID", description: "All documents referencing the given document ID." }, { fieldName: "is_draft", type: "Boolean", description: "All documents that are drafts." }] }; } function getFilterFieldName(fieldName, suffix = "Filter") { return `${fieldName}${suffix}`; } const typeAliases = { Url: "String", Text: "String", Email: "String" }, filterCreators = { ID: createIdFilters, String: createStringFilters, Float: createFloatFilters, Integer: createIntegerFilters, Boolean: createBooleanFilters, Datetime: createDateTimeFilters, Date: createDateFilters, Document: createDocumentFilters }; function generateTypeFilters(types2, options) { const { filterSuffix } = options || {}, builtInTypeKeys = Object.keys(filterCreators), builtinTypeValues = Object.values(filterCreators), objectTypes = types2.filter(isNonUnion).filter((type) => type.type === "Object" && !["Block", "Span"].includes(type.name) && // TODO: What do we do with blocks? !type.interfaces && !builtInTypeKeys.includes(type.type)), unionTypes = types2.filter(isUnion).map((type) => type.name), documentTypes = types2.filter((type) => type.name === "Document" || isDocumentType(type)), builtinTypeFilters = createBuiltinTypeFilters(builtinTypeValues), objectTypeFilters = createObjectTypeFilters(objectTypes, { unionTypes, filterSuffix }), documentTypeFilters = createDocumentTypeFilters(documentTypes, { unionTypes, filterSuffix }); return builtinTypeFilters.concat(objectTypeFilters).concat(documentTypeFilters); } function createBuiltinTypeFilters(builtinTypeValues) { return builtinTypeValues.map((filterCreator) => filterCreator()); } function createObjectTypeFilters(objectTypes, options) { return objectTypes.map((objectType) => ({ name: getFilterFieldName(objectType.name, options.filterSuffix), kind: "InputObject", fields: createFieldFilters(objectType, options) })); } function createDocumentTypeFilters(documentTypes, options) { return documentTypes.map((documentType) => ({ name: getFilterFieldName(documentType.name, options.filterSuffix), kind: "InputObject", fields: [...getDocumentFilters(), ...createFieldFilters(documentType, options)] })); } function createFieldFilters(objectType, options) { const { unionTypes } = options; return objectType.fields ? objectType.fields.filter((field) => field.type !== "JSON" && field.kind !== "List" && !unionTypes.includes(field.type)).map((field) => { const typeName = typeAliases[field.type] || field.type, filterSuffix = Object.keys({ ...typeAliases, ...filterCreators }).includes(typeName) ? void 0 : options.filterSuffix; return { fieldName: field.fieldName, type: getFilterFieldName(typeAliases[field.type] || field.type, filterSuffix), isReference: field.isReference }; }) : []; } function getDocumentFilters() { return [{ fieldName: "_", type: "Sanity_DocumentFilter", description: "Apply filters on document level" }]; } function generateTypeQueries(types2, sortings, options) { const { filterSuffix } = options || {}, queries = [], documentTypes = types2.filter(isDocumentType), documentsFilter = `_type in [${documentTypes.map((docType) => JSON.stringify(docType.originalName || docType.name)).join(", ")}]`, documentInterface = types2.find((type) => type.name === "Document"); if (!documentInterface || isUnion(documentInterface)) throw new Error("Failed to find document interface"); const queryable = [...documentTypes, documentInterface], isSortable = (type) => sortings.some((sorting) => sorting.name === `${type.name}Sorting`); return queryable.forEach((type) => { queries.push({ fieldName: type.name, type: type.name, constraints: [{ field: "_id", comparator: "eq", value: { kind: "argumentValue", argName: "id" } }], args: [{ name: "id", description: `${type.name} document ID`, type: "ID", isNullable: !1 }], ...getDeprecation(type) }); }), queryable.forEach((type) => { const sorting = []; isSortable(type) && sorting.push({ name: "sort", type: { kind: "List", isNullable: !0, children: { type: `${type.name}Sorting`, isNullable: !1 } } }), queries.push({ fieldName: `all${upperFirst__default.default(type.name)}`, filter: type.name === "Document" && type.kind === "Interface" ? documentsFilter : `_type == ${JSON.stringify(type.originalName || type.name)}`, type: { kind: "List", isNullable: !1, children: { type: type.name, isNullable: !1 } }, args: [{ name: "where", type: getFilterFieldName(type.name, filterSuffix), isFieldFilter: !0 }, ...sorting, { name: "limit", type: "Int", description: "Max documents to return", isFieldFilter: !1 }, { name: "offset", type: "Int", description: "Offset at which to start returning documents from", isFieldFilter: !1 }], ...getDeprecation(type) }); }), queries; } function getDeprecation(type) { return type[internal]?.deprecationReason ? { deprecationReason: type[internal].deprecationReason } : {}; } const builtInTypes = ["Boolean", "Date", "Datetime", "Email", "Float", "ID", "Integer", "String", "Text", "Url"], builtInSortingEnum = { name: "SortOrder", kind: "Enum", values: [{ name: "ASC", description: "Sorts on the value in ascending order.", value: 1 }, { name: "DESC", description: "Sorts on the value in descending order.", value: 2 }] }; function generateTypeSortings(types2) { const objectTypes = types2.filter(isNonUnion).filter((type) => type.type === "Object" && !["Block", "Span"].includes(type.name) && // TODO: What do we do with blocks? !type.interfaces && !builtInTypes.includes(type.name)), documentTypes = types2.filter((type) => type.name === "Document" || isDocumentType(type)), hasFields = (type) => type.fields.length > 0, objectTypeSortings = createObjectTypeSortings(objectTypes), documentTypeSortings = createDocumentTypeSortings(documentTypes); return [...[...objectTypeSortings, ...documentTypeSortings].filter(hasFields), builtInSortingEnum]; } function createObjectTypeSortings(objectTypes) { return objectTypes.map((objectType) => ({ name: `${objectType.name}Sorting`, kind: "InputObject", fields: objectType.fields.filter((field) => field.type !== "JSON" && field.kind !== "List").filter((field) => !field.isReference).map((field) => ({ fieldName: field.fieldName, type: builtInTypes.includes(field.type) ? builtInSortingEnum.name : `${field.type}Sorting` })) })); } function createDocumentTypeSortings(documentTypes) { return documentTypes.map((documentType) => ({ name: `${documentType.name}Sorting`, kind: "InputObject", fields: documentType.fields.filter((field) => field.type !== "JSON" && field.kind !== "List").filter((field) => !field.isReference).map((field) => ({ fieldName: field.fieldName, type: builtInTypes.includes(field.type) ? builtInSortingEnum.name : `${field.type}Sorting` })) })); } var gen3 = (extracted, options) => { const documentInterface = extracted.interfaces.find((iface) => iface.name === "Document"); if (!documentInterface || isUnion(documentInterface)) throw new Error("Failed to find document interface"); const types2 = [...extracted.types, documentInterface], filters = generateTypeFilters(types2, options), sortings = generateTypeSortings(types2), queries = generateTypeQueries(types2, sortings.filter((node) => node.kind === "InputObject"), options); return { types: [...extracted.types, ...filters, ...sortings], queries, interfaces: extracted.interfaces, generation: "gen3" }; }; const latestGeneration = "gen3", generations = { gen1, gen2, gen3 }, apiIdRegex = /^[a-z0-9_-]+$/, isInteractive = process.stdout.isTTY && process.env.TERM !== "dumb" && !("CI" in process.env), ignoredWarnings = ["OPTIONAL_INPUT_FIELD_ADDED"], ignoredBreaking = []; async function deployGraphQLApiAction(args, context) { const flags = await parseCliFlags(args), { force, dryRun, api: onlyApis, dataset: datasetFlag, tag: tagFlag, playground: playgroundFlag, generation: generationFlag, "non-null-document-fields": nonNullDocumentFieldsFlag, withUnionCache } = flags, { apiClient, output, prompt } = context; l