UNPKG

hikma-engine

Version:

Code Knowledge Graph Indexer - A sophisticated TypeScript-based indexer that transforms Git repositories into multi-dimensional knowledge stores for AI agents

206 lines (205 loc) 9.04 kB
"use strict"; /** * @file Request validation middleware using Joi for API input validation. * Validates query parameters, request bodies, and headers. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateComprehensiveSearch = exports.validateHybridSearch = exports.validateGitSearch = exports.validateStructuralSearch = exports.validateSemanticSearch = exports.ValidationSchemas = void 0; exports.createValidationMiddleware = createValidationMiddleware; const joi_1 = __importDefault(require("joi")); const logger_1 = require("../../utils/logger"); const logger = (0, logger_1.getLogger)('ValidationMiddleware'); /** * Creates validation middleware for request validation. */ function createValidationMiddleware(options) { return (req, res, next) => { const requestId = req.headers['x-request-id'] || 'unknown'; const validationErrors = []; // Validate query parameters if (options.querySchema) { const { error } = options.querySchema.validate(req.query, { abortEarly: options.abortEarly ?? false, allowUnknown: options.allowUnknown ?? false, stripUnknown: true, }); if (error) { validationErrors.push(...error.details.map(detail => ({ field: `query.${detail.path.join('.')}`, value: detail.context?.value, constraint: detail.message, }))); } } // Validate request body if (options.bodySchema) { const { error } = options.bodySchema.validate(req.body, { abortEarly: options.abortEarly ?? false, allowUnknown: options.allowUnknown ?? false, stripUnknown: true, }); if (error) { validationErrors.push(...error.details.map(detail => ({ field: `body.${detail.path.join('.')}`, value: detail.context?.value, constraint: detail.message, }))); } } // Validate path parameters if (options.paramsSchema) { const { error } = options.paramsSchema.validate(req.params, { abortEarly: options.abortEarly ?? false, allowUnknown: options.allowUnknown ?? false, stripUnknown: true, }); if (error) { validationErrors.push(...error.details.map(detail => ({ field: `params.${detail.path.join('.')}`, value: detail.context?.value, constraint: detail.message, }))); } } // If validation errors exist, return 400 response if (validationErrors.length > 0) { logger.warn('Request validation failed', { requestId, method: req.method, url: req.url, errors: validationErrors, }); const errorResponse = { success: false, error: { code: 'VALIDATION_ERROR', message: 'Request validation failed', details: validationErrors, }, meta: { timestamp: new Date().toISOString(), requestId, }, }; return res.status(400).json(errorResponse); } logger.debug('Request validation passed', { requestId, method: req.method, url: req.url, }); next(); }; } /** * Common validation schemas for search endpoints. */ exports.ValidationSchemas = { /** * Common query parameters for all search endpoints. */ commonQuery: joi_1.default.object({ q: joi_1.default.string().required().min(1).max(500).trim().description('Search query'), limit: joi_1.default.number().integer().min(1).max(100).default(10).description('Maximum number of results'), offset: joi_1.default.number().integer().min(0).default(0).description('Pagination offset'), page: joi_1.default.number().integer().min(1).description('Page number (alternative to offset)'), }), /** * Semantic search query validation schema. */ semanticSearch: joi_1.default.object({ q: joi_1.default.string().required().min(1).max(500).trim(), limit: joi_1.default.number().integer().min(1).max(100).default(10), nodeTypes: joi_1.default.array().items(joi_1.default.string().valid('function', 'class', 'interface', 'variable', 'file', 'commit')).description('Filter by node types'), minSimilarity: joi_1.default.number().min(0).max(1).default(0.1).description('Minimum similarity threshold'), includeMetadata: joi_1.default.boolean().default(true).description('Include metadata in results'), }), /** * Structural search query validation schema. */ structuralSearch: joi_1.default.object({ q: joi_1.default.string().required().min(1).max(500).trim(), limit: joi_1.default.number().integer().min(1).max(100).default(10), language: joi_1.default.string().valid('javascript', 'typescript', 'python', 'java', 'cpp', 'c', 'go', 'rust', 'php', 'ruby').description('Programming language filter'), elementType: joi_1.default.string().valid('function', 'class', 'interface', 'variable', 'import', 'export').description('Code element type'), filePath: joi_1.default.string().max(1000).description('File path pattern'), }), /** * Git history search query validation schema. */ gitSearch: joi_1.default.object({ q: joi_1.default.string().required().min(1).max(500).trim(), limit: joi_1.default.number().integer().min(1).max(100).default(10), author: joi_1.default.string().max(100).description('Author filter'), dateFrom: joi_1.default.date().iso().description('Start date for date range filter'), dateTo: joi_1.default.date().iso().min(joi_1.default.ref('dateFrom')).description('End date for date range filter'), branch: joi_1.default.string().max(100).description('Branch filter'), }), /** * Hybrid search query validation schema. */ hybridSearch: joi_1.default.object({ q: joi_1.default.string().required().min(1).max(500).trim(), limit: joi_1.default.number().integer().min(1).max(100).default(10), filters: joi_1.default.object({ languages: joi_1.default.array().items(joi_1.default.string()), fileTypes: joi_1.default.array().items(joi_1.default.string()), dateRange: joi_1.default.object({ start: joi_1.default.date().iso(), end: joi_1.default.date().iso(), }), authors: joi_1.default.array().items(joi_1.default.string()), }).description('Metadata filters'), weights: joi_1.default.object({ semantic: joi_1.default.number().min(0).max(1).default(0.4), structural: joi_1.default.number().min(0).max(1).default(0.3), temporal: joi_1.default.number().min(0).max(1).default(0.3), }).description('Search dimension weights'), }), /** * Comprehensive search query validation schema. */ comprehensiveSearch: joi_1.default.object({ q: joi_1.default.string().required().min(1).max(500).trim(), limit: joi_1.default.number().integer().min(1).max(100).default(20), includeTypes: joi_1.default.array().items(joi_1.default.string().valid('semantic', 'structural', 'git', 'metadata')).description('Search types to include'), }), }; /** * Creates validation middleware for semantic search endpoints. */ exports.validateSemanticSearch = createValidationMiddleware({ querySchema: exports.ValidationSchemas.semanticSearch, allowUnknown: false, }); /** * Creates validation middleware for structural search endpoints. */ exports.validateStructuralSearch = createValidationMiddleware({ querySchema: exports.ValidationSchemas.structuralSearch, allowUnknown: false, }); /** * Creates validation middleware for git search endpoints. */ exports.validateGitSearch = createValidationMiddleware({ querySchema: exports.ValidationSchemas.gitSearch, allowUnknown: false, }); /** * Creates validation middleware for hybrid search endpoints. */ exports.validateHybridSearch = createValidationMiddleware({ querySchema: exports.ValidationSchemas.hybridSearch, allowUnknown: false, }); /** * Creates validation middleware for comprehensive search endpoints. */ exports.validateComprehensiveSearch = createValidationMiddleware({ querySchema: exports.ValidationSchemas.comprehensiveSearch, allowUnknown: false, });