Skip to main content
Glama
validators.js12 kB
/** * Domain-Specific Validators * Validators for different domains using the composable validation system */ import { validate, ValidationSchema } from './validation-chain.js'; import { VALIDATION_CONFIG, getEnumValues, getPaginationLimits } from './validation-config.js'; /** * Forms Validator */ export class FormsValidator { /** * Get validation schema for list forms parameters */ static getListFormsSchema() { const schema = new ValidationSchema(); schema .field('include', validate('include') .array() .custom((value) => { if (Array.isArray(value)) { value.forEach((id, index) => { validate(`include[${index}]`) .required() .positiveInteger() .validate(id); }); } return true; }) ) .field('status', validate('status') .enum(getEnumValues('formStatus')) ) .field('active', validate('active') .boolean() ) .field('exclude', validate('exclude') .array() .custom((value) => { if (Array.isArray(value)) { value.forEach((id, index) => { validate(`exclude[${index}]`) .required() .positiveInteger() .validate(id); }); } return true; }) ); return schema; } /** * Get validation schema for form data */ static getFormDataSchema(isUpdate = false) { const schema = new ValidationSchema(); if (isUpdate) { schema.field('id', validate('id') .required() .positiveInteger() ); } schema .field('title', validate('title') [isUpdate ? 'string' : 'required']() .string() .trim() .minLength(1) .maxLength(255) ) .field('description', validate('description') .string() .trim() .maxLength(2000) ) .field('is_active', validate('is_active') .boolean() ) .field('fields', validate('fields') .array() ) .field('confirmations', validate('confirmations') .array() .custom((confirmations) => { if (Array.isArray(confirmations)) { confirmations.forEach((conf, index) => { if (conf.type === 'redirect' && conf.url !== undefined) { validate(`confirmations[${index}].url`) .required() .string() .url() .validate(conf.url); } }); } return true; }) ) .field('schedule_start', validate('schedule_start') .string() .date() ) .field('schedule_end', validate('schedule_end') .string() .date() ); return schema; } /** * Validate list forms parameters */ static validateListFormsParams(params = {}) { return this.getListFormsSchema().validate(params); } /** * Validate form data */ static validateFormData(data, isUpdate = false) { return this.getFormDataSchema(isUpdate).validate(data); } } /** * Entries Validator */ export class EntriesValidator { /** * Get validation schema for list entries parameters */ static getListEntriesSchema() { const limits = getPaginationLimits('entries'); const schema = new ValidationSchema(); schema .field('form_ids', validate('form_ids') .array() .custom((value) => { if (Array.isArray(value)) { value.forEach((id, index) => { validate(`form_ids[${index}]`) .required() .positiveInteger() .validate(id); }); } return true; }) ) .field('include', validate('include') .array() ) .field('exclude', validate('exclude') .array() ) .field('status', validate('status') .enum(getEnumValues('entryStatus')) ) .field('search', validate('search') .object() .custom((search) => { if (search && typeof search === 'object') { // Validate field_filters if (search.field_filters !== undefined) { validate('search.field_filters') .array() .validate(search.field_filters); if (Array.isArray(search.field_filters)) { search.field_filters.forEach((filter, index) => { if (!filter.key || filter.value === undefined) { throw new Error('Field filter must have key and value'); } if (filter.operator) { validate(`search.field_filters[${index}].operator`) .enum(getEnumValues('fieldOperators')) .validate(filter.operator); } }); } } // Validate mode if (search.mode !== undefined) { validate('search.mode') .enum(getEnumValues('searchMode')) .validate(search.mode); } // Validate dates if (search.start_date !== undefined) { validate('search.start_date') .string() .date() .validate(search.start_date); } if (search.end_date !== undefined) { validate('search.end_date') .string() .date() .validate(search.end_date); } // Complex validation: mode requires field_filters if (search.mode && !search.field_filters) { throw new Error(VALIDATION_CONFIG.errorMessages.custom.searchWithMode); } } return true; }) ) .field('sorting', validate('sorting') .object() .custom((sorting) => { if (sorting && typeof sorting === 'object') { if (sorting.direction) { validate('sorting.direction') .enum(getEnumValues('sortDirection')) .validate(sorting.direction); } } return true; }) ) .field('paging', validate('paging') .object() .custom((paging) => { if (paging && typeof paging === 'object') { if (paging.page_size !== undefined) { validate('paging.page_size') .required() .number() .min(1) .max(limits.maxPerPage) .validate(paging.page_size); } if (paging.current_page !== undefined) { validate('paging.current_page') .required() .positiveInteger() .validate(paging.current_page); } } return true; }) ); return schema; } /** * Get validation schema for entry data */ static getEntryDataSchema(isUpdate = false) { const schema = new ValidationSchema(); if (isUpdate) { schema.field('id', validate('id') .required() .positiveInteger() ); } else { schema.field('form_id', validate('form_id') .required() .positiveInteger() ); } schema .field('status', validate('status') .enum(getEnumValues('entryStatus')) ) .field('created_by', validate('created_by') .positiveInteger() ) .field('date_created', validate('date_created') .string() .date() ); return schema; } /** * Validate list entries parameters */ static validateListEntriesParams(params = {}) { return this.getListEntriesSchema().validate(params); } /** * Validate entry data */ static validateEntryData(data, isUpdate = false) { return this.getEntryDataSchema(isUpdate).validate(data); } } /** * Feeds Validator */ export class FeedsValidator { /** * Get validation schema for feed data */ static getFeedDataSchema(isCreate = true) { const schema = new ValidationSchema(); if (isCreate) { schema .field('addon_slug', validate('addon_slug') .required() .string() .lowercase() .pattern(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, 'addon_slug must be a valid slug format') ) .field('form_id', validate('form_id') .required() .positiveInteger() ) .field('meta', validate('meta') .required() .object() .custom((meta) => { if (meta && meta.conditionalLogic && meta.conditionalLogic.enabled === true) { if (!meta.conditionalLogic.rules) { throw new Error('conditionalLogic with enabled=true requires rules'); } } return true; }) ); } else { schema .field('id', validate('id') .required() .positiveInteger() ) .field('meta', validate('meta') .object() .custom((meta) => { if (meta && meta.conditionalLogic && meta.conditionalLogic.enabled === true) { if (!meta.conditionalLogic.rules) { throw new Error('conditionalLogic with enabled=true requires rules'); } } return true; }) ) .field('is_active', validate('is_active') .boolean() ); } return schema; } /** * Validate feed data */ static validateFeedData(data, isCreate = true) { return this.getFeedDataSchema(isCreate).validate(data); } } /** * Notifications Validator */ export class NotificationsValidator { /** * Get validation schema for send notifications parameters */ static getSendNotificationsSchema() { const schema = new ValidationSchema(); schema .field('entry_id', validate('entry_id') .required() .positiveInteger() ) .field('notification_ids', validate('notification_ids') .array() ) .field('to', validate('to') .email() ) .field('from', validate('from') .email() ) .field('reply_to', validate('reply_to') .email() ); return schema; } /** * Validate send notifications parameters */ static validateSendNotificationsParams(params = {}) { return this.getSendNotificationsSchema().validate(params); } } /** * Submissions Validator */ export class SubmissionsValidator { /** * Get validation schema for submission data */ static getSubmissionDataSchema() { const schema = new ValidationSchema(); schema .field('form_id', validate('form_id') .required() .positiveInteger() ); return schema; } /** * Validate submission data */ static validateSubmissionData(data) { return this.getSubmissionDataSchema().validate(data); } } /** * Generic validators */ export class GenericValidators { /** * Validate a single ID */ static validateId(params) { const schema = new ValidationSchema(); schema.field('id', validate('id') .required() .positiveInteger() ); return schema.validate(params); } /** * Validate ID with optional force parameter */ static validateIdWithForce(params) { const schema = new ValidationSchema(); schema .field('id', validate('id') .required() .positiveInteger() ) .field('force', validate('force') .boolean() ); return schema.validate(params); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/GravityKit/gravity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server