UNPKG

@iota-big3/sdk-gateway

Version:

Universal API Gateway with protocol translation, intelligent routing, rate limiting, health checking, and caching

321 lines 12.7 kB
"use strict"; /** * Runtime Validation Utilities * Following Phase 2g: Provides runtime type checking that matches compile-time types * Focused on Education industry validation patterns */ Object.defineProperty(exports, "__esModule", { value: true }); exports.educationValidators = exports.assertEducationContext = exports.assertEducationUser = exports.isEducationUser = void 0; exports.createValidationResult = createValidationResult; exports.createValidationError = createValidationError; exports.validateEducationUser = validateEducationUser; exports.validateEducationContext = validateEducationContext; exports.validateResult = validateResult; exports.validateOption = validateOption; exports.createSafeValidator = createSafeValidator; exports.chainValidators = chainValidators; exports.createArrayValidator = createArrayValidator; // ============================================ // Core Validation Functions // ============================================ /** * Create a validation result */ function createValidationResult(valid, value, errors = [], warnings) { return { valid, value, errors, warnings, metadata: { validatedAt: new Date().toISOString(), validatorVersion: '1.0.0', checksPerformed: errors.length + (warnings?.length || 0) } }; } /** * Create a validation error */ function createValidationError(path, message, expected, actual, code = 'VALIDATION_ERROR') { return { path, message, expected, actual, code }; } // ============================================ // Enhanced Type Guards with Validation // ============================================ /** * Validate and type guard for EducationUser */ function validateEducationUser(value) { const errors = []; if (!value || typeof value !== 'object') { errors.push(createValidationError('root', 'Value must be an object', 'object', typeof value, 'INVALID_TYPE')); return createValidationResult(false, undefined, errors); } const obj = value; // Validate base AuthUser properties if (!obj.id || typeof obj.id !== 'string') { errors.push(createValidationError('id', 'ID is required and must be a string', 'string', typeof obj.id, 'MISSING_ID')); } // Validate userType const validUserTypes = ['student', 'teacher', 'parent', 'administrator']; if (!obj.userType || !validUserTypes.includes(obj.userType)) { errors.push(createValidationError('userType', `User type must be one of: ${validUserTypes.join(', ')}`, validUserTypes.join(' | '), String(obj.userType), 'INVALID_USER_TYPE')); } // Validate optional fields if (obj.schoolId !== undefined && typeof obj.schoolId !== 'string') { errors.push(createValidationError('schoolId', 'School ID must be a string', 'string', typeof obj.schoolId, 'INVALID_SCHOOL_ID')); } if (obj.gradeLevel !== undefined && typeof obj.gradeLevel !== 'number') { errors.push(createValidationError('gradeLevel', 'Grade level must be a number', 'number', typeof obj.gradeLevel, 'INVALID_GRADE_LEVEL')); } if (obj.subjects !== undefined && !Array.isArray(obj.subjects)) { errors.push(createValidationError('subjects', 'Subjects must be an array', 'string[]', typeof obj.subjects, 'INVALID_SUBJECTS')); } // Education-specific validations const warnings = []; // FERPA compliance checks if (obj.userType === 'student') { if (!obj.parentalConsent && obj.age && obj.age < 13) { warnings.push('COPPA: Student under 13 requires parental consent'); } if (!obj.ferpaConsent) { warnings.push('FERPA: Educational records access requires consent documentation'); } } // Role-based validation if (obj.userType === 'teacher' && !obj.subjects) { warnings.push('Teachers should have assigned subjects'); } if (obj.userType === 'parent' && !obj.linkedStudentIds) { warnings.push('Parents should be linked to student accounts'); } const valid = errors.length === 0; const typedValue = valid ? obj : undefined; return createValidationResult(valid, typedValue, errors, warnings); } /** * Type guard for EducationUser */ const isEducationUser = (value) => { const result = validateEducationUser(value); return result.valid; }; exports.isEducationUser = isEducationUser; // ============================================ // Education-Specific Validators // ============================================ /** * Validate education context for compliance */ function validateEducationContext(context) { const errors = []; const warnings = []; if (!context || typeof context !== 'object') { errors.push(createValidationError('root', 'Context must be an object', 'object', typeof context, 'INVALID_CONTEXT')); return createValidationResult(false, undefined, errors); } const ctx = context; // Check for education-specific fields if (ctx.action === 'access_grades' || ctx.action === 'view_records') { if (!ctx.userRole || !['teacher', 'administrator', 'parent'].includes(ctx.userRole)) { errors.push(createValidationError('userRole', 'Only teachers, administrators, and parents can access grades', 'teacher | administrator | parent', String(ctx.userRole), 'UNAUTHORIZED_ROLE')); } if (ctx.userRole === 'parent' && !ctx.parentOfStudent) { errors.push(createValidationError('parentOfStudent', 'Parents must specify which student they are accessing', 'string', 'undefined', 'MISSING_STUDENT_LINK')); } } // FERPA validation if (ctx.dataType === 'educational_record') { if (!ctx.ferpaConsent) { warnings.push('FERPA: Access to educational records requires documented consent'); } if (ctx.disclosureTarget && !ctx.disclosureReason) { errors.push(createValidationError('disclosureReason', 'FERPA requires disclosure reason when sharing records', 'string', 'undefined', 'MISSING_DISCLOSURE_REASON')); } } // COPPA validation for young students if (ctx.studentAge && ctx.studentAge < 13) { if (!ctx.parentalConsent) { errors.push(createValidationError('parentalConsent', 'COPPA requires parental consent for students under 13', 'boolean', String(ctx.parentalConsent), 'COPPA_VIOLATION')); } } const valid = errors.length === 0; const typedValue = valid ? ctx : undefined; return createValidationResult(valid, typedValue, errors, warnings); } // ============================================ // Composite Validators // ============================================ /** * Validate a Result type */ function validateResult(value, validateSuccess, validateError) { if (!value || typeof value !== 'object') { return createValidationResult(false, undefined, [ createValidationError('root', 'Result must be an object', 'object', typeof value, 'INVALID_RESULT') ]); } const obj = value; if (obj.success === true) { const successValidation = validateSuccess(obj.value); if (successValidation.valid) { return createValidationResult(true, obj); } return createValidationResult(false, undefined, successValidation.errors); } else if (obj.success === false) { const errorValidation = validateError(obj.error); if (errorValidation.valid) { return createValidationResult(true, obj); } return createValidationResult(false, undefined, errorValidation.errors); } else { return createValidationResult(false, undefined, [ createValidationError('success', 'Result must have success boolean', 'boolean', typeof obj.success, 'INVALID_RESULT') ]); } } /** * Validate an Option type */ function validateOption(value, validateSome) { if (!value || typeof value !== 'object') { return createValidationResult(false, undefined, [ createValidationError('root', 'Option must be an object', 'object', typeof value, 'INVALID_OPTION') ]); } const obj = value; if (obj.some === true) { const someValidation = validateSome(obj.value); if (someValidation.valid) { return createValidationResult(true, obj); } return createValidationResult(false, undefined, someValidation.errors); } else if (obj.some === false) { return createValidationResult(true, obj); } else { return createValidationResult(false, undefined, [ createValidationError('some', 'Option must have some boolean', 'boolean', typeof obj.some, 'INVALID_OPTION') ]); } } // ============================================ // Type Assertion Functions // ============================================ /** * Assert that a value is an EducationUser */ const assertEducationUser = (value) => { const result = validateEducationUser(value); if (!result.valid) { const errorMessages = result.errors.map(e => `${e.path}: ${e.message}`).join(', '); throw new Error(`Invalid EducationUser: ${errorMessages}`); } }; exports.assertEducationUser = assertEducationUser; /** * Assert that a context is valid for education operations */ const assertEducationContext = (value) => { const result = validateEducationContext(value); if (!result.valid) { const errorMessages = result.errors.map(e => `${e.path}: ${e.message}`).join(', '); throw new Error(`Invalid Education Context: ${errorMessages}`); } }; exports.assertEducationContext = assertEducationContext; // ============================================ // Utility Functions // ============================================ /** * Create a safe validator that returns Result<T, ValidationError[]> */ function createSafeValidator(validator) { return (value) => { const result = validator(value); if (result.valid && result.value !== undefined) { return { success: true, value: result.value }; } else { return { success: false, error: result.errors }; } }; } /** * Chain multiple validators */ function chainValidators(...validators) { return (value) => { let current = value; const allErrors = []; const allWarnings = []; for (const validator of validators) { const result = validator(current); if (!result.valid) { allErrors.push(...result.errors); if (result.warnings) { allWarnings.push(...result.warnings); } return createValidationResult(false, undefined, allErrors, allWarnings); } current = result.value; if (result.warnings) { allWarnings.push(...result.warnings); } } return createValidationResult(true, current, [], allWarnings); }; } /** * Create a validator for arrays of a specific type */ function createArrayValidator(itemValidator) { return (value) => { if (!Array.isArray(value)) { return createValidationResult(false, undefined, [ createValidationError('root', 'Value must be an array', 'array', typeof value, 'INVALID_ARRAY') ]); } const results = []; const errors = []; const warnings = []; for (let i = 0; i < value.length; i++) { const itemResult = itemValidator(value[i]); if (itemResult.valid && itemResult.value !== undefined) { results.push(itemResult.value); if (itemResult.warnings) { warnings.push(...itemResult.warnings.map(w => `[${i}] ${w}`)); } } else { errors.push(...itemResult.errors.map(e => ({ ...e, path: `[${i}].${e.path}` }))); } } if (errors.length > 0) { return createValidationResult(false, undefined, errors, warnings); } return createValidationResult(true, results, [], warnings); }; } // Export education-specific validators for easy access exports.educationValidators = { user: validateEducationUser, context: validateEducationContext, isEducationUser: exports.isEducationUser, assertEducationUser: exports.assertEducationUser, assertEducationContext: exports.assertEducationContext }; //# sourceMappingURL=validation-utilities.js.map