UNPKG

@allan1361/iota-big3-sdk-middleware

Version:

🏆 A+ Grade Certified Enterprise Middleware Framework - Phase 3 Certified (90/100) with advanced resilience patterns, comprehensive type safety, and production-ready observability

294 lines 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValidationMiddleware = void 0; exports.createValidationMiddleware = createValidationMiddleware; const events_1 = require("events"); class ValidationMiddleware extends events_1.EventEmitter { constructor(config = {}) { super(); this.validators = new Map(); this.config = { abortEarly: config.abortEarly ?? true, stripUnknown: config.stripUnknown ?? true, coerceTypes: config.coerceTypes ?? true, customErrorHandler: config.customErrorHandler }; } registerValidator(name, validator) { this.validators.set(name, validator); } validate(schema) { return async (req, res, next) => { const errors = []; if (schema.body) { const bodyErrors = await this.validateDataAsync(req.body, schema.body, 'body'); errors.push(...bodyErrors); } if (schema.params) { const paramsErrors = await this.validateDataAsync(req.params, schema.params, 'params'); errors.push(...paramsErrors); } if (schema.query) { const queryErrors = await this.validateDataAsync(req.query, schema.query, 'query'); errors.push(...queryErrors); } if (schema.headers) { const headersErrors = await this.validateDataAsync(req.headers, schema.headers, 'headers'); errors.push(...headersErrors); } if (errors.length > 0) { this.emit('validation:failed', { path: req.path, method: req.method, errors }); if (this.config.customErrorHandler) { this.config.customErrorHandler(errors, req, res); } else { res.status(400).json({ error: 'Validation failed', errors: errors.map(e => ({ field: e.field, message: e.message })) }); } return; } this.emit('validation:passed', { path: req.path, method: req.method }); next(); }; } async validateDataAsync(data, schema, prefix) { const errors = []; if (typeof schema === 'string' && this.validators.has(schema)) { const validator = this.validators.get(schema); const validationErrors = validator(data); if (validationErrors) { return validationErrors.map(e => ({ ...e, field: `${prefix}.${e.field}` })); } return []; } if (typeof schema === 'function') { try { const result = await schema(data); if (result !== true) { errors.push({ field: prefix, message: typeof result === 'string' ? result : 'Validation failed' }); } } catch (error) { errors.push({ field: prefix, message: error.message || 'Validation error' }); } return errors; } if (typeof schema === 'object' && schema !== null) { if (schema.required && Array.isArray(schema.required)) { for (const field of schema.required) { if (!(field in data)) { errors.push({ field: `${prefix}.${field}`, message: `${field} is required`, type: 'required' }); if (this.config.abortEarly) return errors; } } } if (schema.properties) { for (const [field, fieldSchema] of Object.entries(schema.properties)) { if (field in data) { const fieldErrors = await this.validateFieldAsync(data[field], fieldSchema, `${prefix}.${field}`); errors.push(...fieldErrors); if (this.config.abortEarly && errors.length > 0) return errors; } } } if (this.config.stripUnknown && schema.properties) { for (const field of Object.keys(data)) { if (!(field in schema.properties)) { delete data[field]; } } } } return errors; } async validateFieldAsync(value, schema, field) { const errors = []; if (schema.type) { const actualType = Array.isArray(value) ? 'array' : typeof value; const expectedTypes = Array.isArray(schema.type) ? schema.type : [schema.type]; if (!expectedTypes.includes(actualType)) { if (this.config.coerceTypes) { const coerced = this.coerceType(value, schema.type); if (coerced !== undefined) { value = coerced; } else { errors.push({ field, message: `Expected ${schema.type} but got ${actualType}`, value, type: 'type' }); } } else { errors.push({ field, message: `Expected ${schema.type} but got ${actualType}`, value, type: 'type' }); } } } if (typeof value === 'string') { if (schema.minLength && value.length < schema.minLength) { errors.push({ field, message: `String must be at least ${schema.minLength} characters`, value, type: 'minLength' }); } if (schema.maxLength && value.length > schema.maxLength) { errors.push({ field, message: `String must be at most ${schema.maxLength} characters`, value, type: 'maxLength' }); } if (schema.pattern && !new RegExp(schema.pattern).test(value)) { errors.push({ field, message: `String does not match pattern ${schema.pattern}`, value, type: 'pattern' }); } } if (typeof value === 'number') { if (schema.minimum !== undefined && value < schema.minimum) { errors.push({ field, message: `Number must be at least ${schema.minimum}`, value, type: 'minimum' }); } if (schema.maximum !== undefined && value > schema.maximum) { errors.push({ field, message: `Number must be at most ${schema.maximum}`, value, type: 'maximum' }); } } if (Array.isArray(value)) { if (schema.minItems && value.length < schema.minItems) { errors.push({ field, message: `Array must have at least ${schema.minItems} items`, value, type: 'minItems' }); } if (schema.maxItems && value.length > schema.maxItems) { errors.push({ field, message: `Array must have at most ${schema.maxItems} items`, value, type: 'maxItems' }); } } if (schema.enum && !schema.enum.includes(value)) { errors.push({ field, message: `Value must be one of: ${schema.enum.join(', ')}`, value, type: 'enum' }); } if (schema.validate) { try { const result = await schema.validate(value); if (result !== true) { errors.push({ field, message: typeof result === 'string' ? result : 'Custom validation failed', value, type: 'custom' }); } } catch (error) { errors.push({ field, message: error.message || 'Validation error', value, type: 'custom' }); } } return errors; } coerceType(value, targetType) { if (targetType === 'string') { return String(value); } if (targetType === 'number') { const num = Number(value); return isNaN(num) ? undefined : num; } if (targetType === 'boolean') { if (value === 'true' || value === '1' || value === 1) return true; if (value === 'false' || value === '0' || value === 0) return false; return undefined; } if (targetType === 'array' && typeof value === 'string') { try { const parsed = JSON.parse(value); return Array.isArray(parsed) ? parsed : undefined; } catch { return undefined; } } if (targetType === 'object' && typeof value === 'string') { try { const parsed = JSON.parse(value); return typeof parsed === 'object' ? parsed : undefined; } catch { return undefined; } } return undefined; } } exports.ValidationMiddleware = ValidationMiddleware; function createValidationMiddleware(config) { return new ValidationMiddleware(config); } //# sourceMappingURL=validation-middleware.js.map