import joi from 'joi' import { adminViewSchema } from './shared/adminViewSchema.js' import { componentSchema, livePreviewSchema } from './shared/componentSchema.js' const component = joi.alternatives().try(joi.object().unknown(), joi.func()) export const endpointsSchema = joi.alternatives().try( joi.array().items( joi.object({ custom: joi.object().pattern(joi.string(), joi.any()), handler: joi.alternatives().try(joi.array().items(joi.func()), joi.func()), method: joi .string() .valid('get', 'head', 'post', 'put', 'patch', 'delete', 'connect', 'options'), path: joi.string(), root: joi.bool(), }), ), joi.boolean(), ) export default joi.object({ admin: joi.object({ autoLogin: joi.alternatives().try( joi.object().keys({ email: joi.string(), password: joi.string(), prefillOnly: joi.boolean(), }), joi.boolean(), ), avatar: joi.alternatives().try(joi.string(), component), buildPath: joi.string(), components: joi.object().keys({ Nav: component, actions: joi.array().items(component), afterDashboard: joi.array().items(component), afterLogin: joi.array().items(component), afterNavLinks: joi.array().items(component), beforeDashboard: joi.array().items(component), beforeLogin: joi.array().items(component), beforeNavLinks: joi.array().items(component), graphics: joi.object({ Icon: component, Logo: component, }), logout: joi.object({ Button: component, }), providers: joi.array().items(component), views: joi.alternatives().try( joi.object({ Account: joi.alternatives().try(component, adminViewSchema), Dashboard: joi.alternatives().try(component, adminViewSchema), }), joi.object().pattern(joi.string(), component), ), }), custom: joi.object().pattern(joi.string(), joi.any()), dateFormat: joi.string(), disable: joi.bool(), inactivityRoute: joi.string(), livePreview: joi.object({ ...livePreviewSchema, collections: joi.array().items(joi.string()), globals: joi.array().items(joi.string()), }), logoutRoute: joi.string(), meta: joi.object().keys({ favicon: joi.string(), ogImage: joi.string(), titleSuffix: joi.string(), }), user: joi.string(), }), bin: joi.array().items( joi.object().keys({ key: joi.string(), scriptPath: joi.string(), }), ), collections: joi.array(), cookiePrefix: joi.string(), cors: [joi.string().valid('*'), joi.array().items(joi.string())], csrf: joi.array().items(joi.string().allow('')).sparse(), custom: joi.object().pattern(joi.string(), joi.any()), db: joi.any(), debug: joi.boolean(), defaultDepth: joi.number().min(0).max(30), defaultMaxTextLength: joi.number(), editor: joi .object() .required() .keys({ CellComponent: componentSchema.optional(), FieldComponent: componentSchema.optional(), afterReadPromise: joi.func().optional(), outputSchema: joi.func().optional(), populationPromise: joi.func().optional(), validate: joi.func().required(), }) .unknown(), email: joi.alternatives().try(joi.object(), joi.func()), endpoints: endpointsSchema, globals: joi.array(), graphQL: joi.object().keys({ disable: joi.boolean(), disablePlaygroundInProduction: joi.boolean(), maxComplexity: joi.number(), mutations: joi.function(), queries: joi.function(), }), hooks: joi.object().keys({ afterError: joi.func(), }), i18n: joi.object(), indexSortableFields: joi.boolean(), local: joi.boolean(), localization: joi.alternatives().try( joi.object().keys({ defaultLocale: joi.string(), fallback: joi.boolean(), localeCodes: joi.array().items(joi.string()), locales: joi.alternatives().try( joi.array().items( joi.object().keys({ code: joi.string(), fallbackLocale: joi.string(), label: joi .alternatives() .try( joi.object().pattern(joi.string(), [joi.string()]), joi.string(), joi.valid(false), ), rtl: joi.boolean(), toString: joi.func(), }), ), joi.array().items(joi.string()), ), }), joi.boolean(), ), maxDepth: joi.number().min(0).max(100), onInit: joi.func(), plugins: joi.array().items(joi.func()), routes: joi.object({ admin: joi.string(), api: joi.string(), graphQL: joi.string(), graphQLPlayground: joi.string(), }), secret: joi.string(), serverURL: joi .string() .uri() .allow('') .custom((value, helper) => { const urlWithoutProtocol = value.split('//')[1] if (!urlWithoutProtocol) { return helper.message({ custom: 'You need to include either "https://" or "http://" in your serverURL.', }) } if (urlWithoutProtocol.indexOf('/') > -1) { return helper.message({ custom: 'Your serverURL cannot have a path. It can only contain a protocol, a domain, and an optional port.', }) } return value }), sharp: joi.any(), telemetry: joi.boolean(), typescript: joi.object({ declare: joi.alternatives().try(joi.boolean(), joi.object({ ignoreTSError: joi.boolean() })), outputFile: joi.string(), }), upload: joi.object(), })