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

266 lines (265 loc) 8.93 kB
"use strict"; /** * @file Response formatting utilities for consistent API responses. * Provides standardized response formatting with metadata injection. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.formatResponse = exports.responseFormatter = exports.ResponseFormatter = void 0; exports.timingMiddleware = timingMiddleware; exports.compressResponse = compressResponse; exports.validateResponse = validateResponse; exports.calculateResponseSize = calculateResponseSize; /** * Creates standard response metadata from request context. */ function createResponseMetadata(req, startTime, options = {}) { const processingTime = startTime ? Date.now() - startTime : undefined; const metadata = { timestamp: new Date().toISOString(), requestId: req.context?.requestId || req.headers['x-request-id'] || 'unknown', }; // Add optional metadata if (processingTime !== undefined) { metadata.processingTime = processingTime; } if (req.path) { metadata.path = req.path; } if (req.method) { metadata.method = req.method; } return metadata; } /** * Creates pagination metadata for paginated responses. */ function createPaginationMetadata(currentPage, pageSize, totalResults, offset) { const totalPages = totalResults ? Math.ceil(totalResults / pageSize) : undefined; const hasNextPage = totalPages ? currentPage < totalPages : false; const hasPreviousPage = currentPage > 1; return { currentPage, totalPages, pageSize, totalResults, hasNextPage, hasPreviousPage, nextPage: hasNextPage ? currentPage + 1 : undefined, previousPage: hasPreviousPage ? currentPage - 1 : undefined, offset, }; } /** * Response formatter class for creating standardized API responses. */ class ResponseFormatter { constructor(options = {}) { this.options = { includeDebugInfo: process.env.NODE_ENV === 'development', includeCacheInfo: true, includePerformance: true, includeTimestamp: true, ...options, }; } /** * Creates a successful API response. */ success(req, data, startTime, pagination) { const metadata = createResponseMetadata(req, startTime, this.options); const response = { success: true, data, meta: metadata, }; // Add pagination metadata if provided if (pagination) { response.meta.pagination = createPaginationMetadata(pagination.page, pagination.limit, pagination.total, pagination.offset); } return response; } /** * Creates an error API response. */ error(req, code, message, statusCode, details, startTime) { const metadata = createResponseMetadata(req, startTime, this.options); const response = { success: false, error: { code, message, details, }, meta: metadata, }; return response; } /** * Creates a paginated response with search results. */ paginatedResults(req, results, pagination, startTime, additionalData) { const data = { results, ...additionalData, }; return this.success(req, data, startTime, pagination); } /** * Creates a health check response. */ healthCheck(req, status, checks, startTime) { const data = { status, timestamp: new Date().toISOString(), uptime: Math.floor(process.uptime()), version: process.env.npm_package_version || '1.0.0', environment: process.env.NODE_ENV || 'development', checks, }; return this.success(req, data, startTime); } /** * Creates an extended response with additional metadata. */ extended(req, data, startTime, extensions) { const response = this.success(req, data, startTime); if (extensions && this.options.includeDebugInfo) { const extendedMeta = response.meta; if (extensions.cache && this.options.includeCacheInfo) { extendedMeta.cache = extensions.cache; } if (extensions.performance && this.options.includePerformance) { extendedMeta.performance = extensions.performance; } if (extensions.debug && this.options.includeDebugInfo) { extendedMeta.debug = extensions.debug; } } return response; } } exports.ResponseFormatter = ResponseFormatter; /** * Default response formatter instance. */ exports.responseFormatter = new ResponseFormatter(); /** * Utility functions for quick response formatting. */ exports.formatResponse = { /** * Quick success response. */ success: (req, data, startTime) => exports.responseFormatter.success(req, data, startTime), /** * Quick error response. */ error: (req, code, message, details, startTime) => exports.responseFormatter.error(req, code, message, undefined, details, startTime), /** * Quick paginated response. */ paginated: (req, results, page, limit, total, startTime) => exports.responseFormatter.paginatedResults(req, results, { page, limit, total, offset: (page - 1) * limit }, startTime), /** * Quick health check response. */ health: (req, status, checks, startTime) => exports.responseFormatter.healthCheck(req, status, checks, startTime), }; /** * Middleware to inject timing information into responses. */ function timingMiddleware(req, res, next) { // Store start time in request context if (req.context) { req.context.startTime = Date.now(); } // Override response methods to inject timing const originalJson = res.json; res.json = function (data) { const startTime = req.context?.startTime; // If data is already a formatted response, add timing if missing if (data && typeof data === 'object' && 'success' in data && 'meta' in data) { if (startTime && !data.meta.processingTime) { data.meta.processingTime = Date.now() - startTime; } } return originalJson.call(this, data); }; next(); } /** * Response compression utility for large responses. */ function compressResponse(data) { // Remove undefined values and empty arrays/objects function cleanObject(obj) { if (Array.isArray(obj)) { return obj.map(cleanObject).filter(item => item !== undefined); } if (obj && typeof obj === 'object') { const cleaned = {}; for (const [key, value] of Object.entries(obj)) { const cleanedValue = cleanObject(value); if (cleanedValue !== undefined) { cleaned[key] = cleanedValue; } } return Object.keys(cleaned).length > 0 ? cleaned : undefined; } return obj; } return cleanObject(data); } /** * Response validation utility to ensure responses meet API standards. */ function validateResponse(response) { const errors = []; // Check basic structure if (!response || typeof response !== 'object') { errors.push('Response must be an object'); return { valid: false, errors }; } // Check required fields if (!('success' in response)) { errors.push('Response must have a "success" field'); } if (!('meta' in response)) { errors.push('Response must have a "meta" field'); } // Check meta structure if (response.meta) { if (!response.meta.timestamp) { errors.push('Response meta must include timestamp'); } if (!response.meta.requestId) { errors.push('Response meta must include requestId'); } } // Check success response structure if (response.success === true) { if (!('data' in response)) { errors.push('Success response must have a "data" field'); } } // Check error response structure if (response.success === false) { if (!response.error) { errors.push('Error response must have an "error" field'); } else { if (!response.error.code) { errors.push('Error response must have an error code'); } if (!response.error.message) { errors.push('Error response must have an error message'); } } } return { valid: errors.length === 0, errors }; } /** * Response size calculator for monitoring. */ function calculateResponseSize(response) { return Buffer.byteLength(JSON.stringify(response), 'utf8'); }