Files
twenty/packages/twenty-cli/src/utils/schema-validator.ts
T
martmull 7723fa70a4 Move schemas to constant folder (#15207)
- move schemas to constants
- increase npm package version
2025-10-20 15:41:53 +02:00

84 lines
2.1 KiB
TypeScript

import Ajv from 'ajv';
import * as fs from 'fs-extra';
import * as path from 'path';
import {
AGENT_SCHEMA_URL,
APP_MANIFEST_SCHEMA_URL,
OBJECT_SCHEMA_URL,
SERVERLESS_FUNCTION_SCHEMA_URL,
TRIGGER_SCHEMA_URL,
} from '../constants/schemas';
import { BASE_SCHEMAS_PATH } from '../constants/constants-path';
export class SchemaValidationError extends Error {
constructor(
message: string,
public readonly errors: any[],
public readonly filePath?: string,
) {
super(message);
this.name = 'SchemaValidationError';
}
}
const formatErrors = (errors: any[]): string => {
return errors
.map((error) => {
const path = error.instancePath || 'root';
const message = error.message;
const value =
error.data !== undefined ? ` (got: ${JSON.stringify(error.data)})` : '';
return `${path}: ${message}${value}`;
})
.join('\n');
};
export const validateSchema = async (
schemaName: 'appManifest' | 'agent' | 'object' | 'serverlessFunction',
manifest: any,
filePath?: string,
): Promise<void> => {
const ajv = new Ajv({
allErrors: true,
verbose: true,
strict: false,
$data: true,
});
const schemaUrls = getSchemaUrls();
let schema;
for (const name of Object.keys(schemaUrls) as (keyof typeof schemaUrls)[]) {
const schemaPath = path.join(BASE_SCHEMAS_PATH, `${name}.schema.json`);
ajv.addSchema(await fs.readJson(schemaPath));
if (name === schemaName) {
schema = ajv.getSchema(schemaUrls[name])?.schema;
}
}
if (!schema) throw new Error(`Schema ${schemaName} not found.`);
const valid = ajv.validate(schema, manifest);
if (!valid) {
const errorMessages = formatErrors(ajv.errors || []);
throw new SchemaValidationError(
`${schemaName} validation failed:\n${errorMessages}`,
ajv.errors || [],
filePath,
);
}
};
export const getSchemaUrls = () => {
return {
trigger: TRIGGER_SCHEMA_URL,
agent: AGENT_SCHEMA_URL,
object: OBJECT_SCHEMA_URL,
serverlessFunction: SERVERLESS_FUNCTION_SCHEMA_URL,
appManifest: APP_MANIFEST_SCHEMA_URL,
};
};