UNPKG

@unidev-hub/api-framework

Version:

A comprehensive framework for building API services with Express

1,813 lines (1,772 loc) 50.3 kB
import { Logger } from '@unidev-hub/logger'; import { ConfigManager } from '@unidev-hub/config'; import { RequestHandler, Application, ErrorRequestHandler, Router } from 'express'; import { CorsOptions } from 'cors'; import { Validator, ValidationOptions as ValidationOptions$1 } from '@unidev-hub/validator'; export { v } from '@unidev-hub/validator'; import { Server } from 'http'; import { DatabaseConnection as DatabaseConnection$2 } from '@unidev-hub/database'; import { Status } from '@unidev-hub/health'; export { AggregatedHealthResult, DatabaseHealthIndicator, DiskHealthIndicator, EnhancedHealthEndpointOptions, HealthDashboardProps, HealthHistoryOptions, HealthHistoryRecord, HealthHistoryService, HealthIndicator, HealthResult, HealthService, HttpHealthIndicator, MemoryHealthIndicator, Status, createHealthEndpoint } from '@unidev-hub/health'; import { Pool } from 'pg'; import Joi from 'joi'; import { Registry, Counter, Gauge, Histogram } from 'prom-client'; /** * Options for rate limiting middleware */ interface RateLimiterOptions { /** * Time window in milliseconds * @default 900000 (15 minutes) */ windowMs?: number; /** * Maximum number of requests per IP in the time window * @default 100 */ max?: number; /** * Whether to add standard rate limiting headers * @default true */ standardHeaders?: boolean; /** * Message to send when rate limit is exceeded * @default 'Too many requests, please try again later.' */ message?: string; /** * Skip rate limiting for certain requests (return true to skip) */ skip?: (req: any) => boolean; /** * Additional options to pass to express-rate-limit */ additionalOptions?: Record<string, any>; } /** * Create rate limiting middleware * * @param options Rate limiting options * @returns Express middleware */ declare function rateLimiterMiddleware(options?: RateLimiterOptions): RequestHandler; /** * Middleware enum defining all available middleware names */ declare enum Middleware { HELMET = "helmet", CORS = "cors", COMPRESSION = "compression", BODY_PARSER = "bodyParser", CORRELATION = "correlation", LOGGING = "logging", RESPONSE_FORMAT = "responseFormat", RATE_LIMIT = "rateLimit", METRICS = "metrics", ERROR_HANDLING = "errorHandling", AUTH = "auth", VALIDATION = "validation", UPLOAD = "upload" } /** * Standard middleware configurations - Provides commonly used middleware combinations */ declare const MiddlewareGroups: { /** * Default middleware stack for most applications */ DEFAULT: Middleware[]; /** * Middleware stack for APIs with rate limiting and metrics */ API: Middleware[]; /** * Basic middleware stack with minimal processing */ MINIMAL: Middleware[]; }; /** * Error handling options */ interface ErrorHandlingOptions { /** * Whether to include stack trace in error responses * @default true in development, false in production */ includeStack?: boolean; /** * Whether to log errors * @default true */ logErrors?: boolean; /** * Default error message * @default 'An unexpected error occurred' */ defaultMessage?: string; /** * Default error code * @default 'INTERNAL_ERROR' */ defaultCode?: string; } /** * Response formatting options */ interface ResponseFormatOptions { /** * Whether to wrap successful responses * @default true */ wrapSuccess?: boolean; /** * Whether to include request ID in response * @default true */ includeRequestId?: boolean; /** * Default success message * @default 'Operation successful' */ defaultSuccessMessage?: string; /** * Default error message * @default 'Operation failed' */ defaultErrorMessage?: string; } /** * Rate limiting options */ interface RateLimitOptions { /** * Time window in milliseconds * @default 900000 (15 minutes) */ windowMs?: number; /** * Maximum number of requests per IP in the time window * @default 100 */ max?: number; /** * Whether to add standard rate limiting headers * @default true */ standardHeaders?: boolean; /** * Message to send when rate limit is exceeded * @default 'Too many requests, please try again later.' */ message?: string; /** * Skip rate limiting for certain requests (return true to skip) */ skip?: (req: any) => boolean; /** * Additional options to pass to express-rate-limit */ additionalOptions?: Record<string, any>; } /** * Metrics options */ interface MetricsOptions { /** * Prefix for metric names * @default '' */ prefix?: string; /** * Whether to collect default metrics (in framework) * @default true */ defaultMetrics?: boolean; /** * Whether to collect default metrics (in custom middleware) * @default false */ collectDefaults?: boolean; /** * Endpoint for metrics * @default '/metrics' */ endpoint?: string; /** * Default labels to add to all metrics */ defaultLabels?: Record<string, string>; enabled?: boolean; } /** * Request logger options */ interface RequestLoggerOptions$1 { /** * Skip logging for specific paths */ skip?: string[]; /** * Log level to use * @default 'info' */ level?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'; /** * Include request body in logs * @default false */ includeBody?: boolean; /** * Include request headers in logs * @default false */ includeHeaders?: boolean; } /** * Validation options */ interface ValidationOptions { /** * Whether to use HttpError for validation errors * @default true */ useHttpError?: boolean; /** * Whether to abort on first error * @default false */ abortEarly?: boolean; /** * Whether to strip unknown properties * @default true */ stripUnknown?: boolean; /** * Whether to allow unknown properties * @default false */ allowUnknown?: boolean; } /** * Upload options */ interface UploadOptions { /** * Maximum file size in bytes * @default 10485760 (10MB) */ maxSize?: number; /** * Allowed MIME types */ allowedMimeTypes?: string[]; /** * Destination directory for disk storage * If not provided, use memory storage */ destination?: string; } /** * Authentication options */ interface AuthOptions { /** * Authentication type * @default 'jwt' */ type?: 'jwt' | 'azure' | 'none' | 'custom'; /** * Whether authentication is required * @default true */ required?: boolean; /** * JWT authentication options */ jwt?: { /** * JWT secret */ secret?: string; /** * JWT public key for RS256 */ publicKey?: string; /** * JWT issuer */ issuer?: string; /** * JWT audience */ audience?: string; }; /** * Azure AD authentication options */ azure?: { /** * Azure AD tenant ID */ tenantId?: string; /** * Azure AD client ID */ clientId?: string; /** * Azure AD client secret */ clientSecret?: string; /** * Azure AD API scope */ apiScope?: string; }; /** * Custom authentication function */ customAuthFn?: (app: Application, config: ConfigManager, logger: Logger) => Promise<RequestHandler>; } /** * Error codes */ declare enum ErrorCode$1 { BAD_REQUEST = "BAD_REQUEST", UNAUTHORIZED = "UNAUTHORIZED", FORBIDDEN = "FORBIDDEN", NOT_FOUND = "NOT_FOUND", VALIDATION_ERROR = "VALIDATION_ERROR", CONFLICT = "CONFLICT", INTERNAL_ERROR = "INTERNAL_ERROR", SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE", DATABASE_ERROR = "DATABASE_ERROR", NOT_IMPLEMENTED = "NOT_IMPLEMENTED", TOO_MANY_REQUESTS = "TOO_MANY_REQUESTS", UPLOAD_ERROR = "UPLOAD_ERROR", AUTHENTICATION_REQUIRED = "AUTHENTICATION_REQUIRED", INSUFFICIENT_PERMISSIONS = "INSUFFICIENT_PERMISSIONS" } /** * API documentation configuration */ interface DocsOptions { enabled?: boolean; endpoint?: string; title?: string; version?: string; description?: string; } interface AuthUser { id: string; role?: string; permissions?: string[]; [key: string]: any; } /** * Declare module augmentation for Express Request * We use module augmentation instead of global declaration to avoid conflicts */ declare module 'express' { interface Request { authUser?: AuthUser; correlationId?: string; auth?: Record<string, any>; } } /** * Correlation ID options */ interface CorrelationIdOptions { /** * Header name for correlation ID * @default 'X-Correlation-ID' */ header?: string; /** * Property name to store on request object * @default 'correlationId' */ propertyName?: string; /** * Whether to generate a correlation ID if none is provided * @default true */ generateId?: boolean; } /** * Options for correlation ID middleware */ interface CorrelationIdOptions { /** * HTTP header to get/set correlation ID * @default 'X-Correlation-ID' */ header?: string; /** * Property name to store correlation ID in request * @default 'correlationId' */ propertyName?: string; /** * Whether to generate ID if not provided * @default true */ generateId?: boolean; } /** * Custom error class with status code and error code */ declare class HttpError extends Error { statusCode: number; code: string; details?: Record<string, any>; constructor(message: string, statusCode?: number, code?: string | ErrorCode$1, details?: Record<string, any>); } /** * Create error handler middleware * @param options Error handler options * @param logger Logger instance * @returns Express error middleware */ declare function errorHandlerMiddleware(options: ErrorHandlingOptions | undefined, logger: Logger): ErrorRequestHandler; /** * Apply error handler to the application * Adds a 404 handler and the main error handler * @param app Express application * @param logger Logger instance */ declare function applyErrorHandler(app: any, logger: Logger): void; /** * Wrapper for async request handlers to catch errors * @param fn Async request handler * @returns Express middleware that catches errors */ declare function asyncHandler(fn: Function): RequestHandler; /** * Generic validator function that can validate different parts of the request * @param schema Validator schema * @param source Request property to validate ('body', 'query', 'params', 'headers') * @param options Validation options */ declare function validate(schema: Validator<any>, source?: 'body' | 'query' | 'params' | 'headers', options?: ValidationOptions$1): RequestHandler; /** * Shorthand for validating query parameters * @param schema Validator schema * @param options Validation options */ declare function validateQuery(schema: Validator<any>, options?: ValidationOptions$1): RequestHandler; /** * Validates multiple request properties at once * @param schemas Object mapping request properties to validator schemas * @param options Validation options */ declare function validateAll(schemas: { body?: Validator<any>; query?: Validator<any>; params?: Validator<any>; headers?: Validator<any>; }, options?: ValidationOptions$1): RequestHandler; /** * Creates a middleware that validates both query parameters and request body * @param querySchema Schema for validating query parameters * @param bodySchema Schema for validating request body * @param options Optional validation options */ declare function validateRequestAndQuery(querySchema: Validator<any>, bodySchema: Validator<any>, options?: ValidationOptions$1): RequestHandler; /** * Set up authentication for the application * @param app Express application * @param config Configuration manager * @param logger Logger instance * @param options Authentication options * @returns Authentication middleware */ declare function setupAuth(app: Application, config: ConfigManager, logger: Logger, options?: AuthOptions): Promise<RequestHandler>; /** * Authentication middleware * @param options Authentication options */ declare function authenticate(options?: { required?: boolean; }): RequestHandler; /** * Role-based authorization middleware * @param roles Array of roles allowed to access the resource */ declare function authorizeRoles(roles: string[]): RequestHandler; /** * Permission-based authorization middleware * @param requiredPermissions Array of permissions required to access the resource */ declare function authorizePermissions(requiredPermissions: string[]): RequestHandler; /** * Resource ownership validation middleware * @param paramIdField The request parameter field containing the resource ID * @param userIdField The field in the user object to compare with */ declare function authorizeOwnership(paramIdField?: string, userIdField?: string): RequestHandler; /** * Create file upload middleware * @param fieldName Name of the field for the file * @param options Upload options */ declare function upload(fieldName?: string, options?: { maxCount?: number; maxSize?: number; allowedMimeTypes?: string[]; required?: boolean; destination?: string; }): RequestHandler; /** * Interface for regular middleware factory functions */ type RegularMiddlewareFactory = { create: (config: ConfigManager, logger: Logger, options?: any) => RequestHandler | RequestHandler[]; dependencies?: string[]; order?: number; isErrorHandler: false; }; /** * Interface for error middleware factory functions */ type ErrorMiddlewareFactory = { create: (config: ConfigManager, logger: Logger, options?: any) => ErrorRequestHandler | ErrorRequestHandler[]; dependencies?: string[]; order?: number; isErrorHandler: true; }; /** * Combined middleware factory type */ type MiddlewareFactory = RegularMiddlewareFactory | ErrorMiddlewareFactory; /** * Register a middleware factory function */ declare function registerMiddleware(name: string, factory: MiddlewareFactory): void; /** * Check if middleware is enabled based on configuration */ declare function isMiddlewareEnabled(middlewareName: string, config: ConfigManager): boolean; /** * Apply regular middleware from registry */ declare function applyRegularMiddleware(app: Application, config: ConfigManager, logger: Logger): void; /** * Apply error handling middleware from registry */ declare function applyErrorHandlers(app: Application, config: ConfigManager, logger: Logger): void; /** * Middleware to track correlation ID across requests * * @param options Correlation ID options * @returns Express middleware */ declare function correlationIdMiddleware(options?: CorrelationIdOptions): RequestHandler; declare const metrics: { registry: Registry<"text/plain; version=0.0.4; charset=utf-8">; /** * Create a new counter metric */ createCounter: (name: string, help: string, labelNames?: string[]) => Counter<string>; /** * Create a new gauge metric */ createGauge: (name: string, help: string, labelNames?: string[]) => Gauge<string>; /** * Create a new histogram metric */ createHistogram: (name: string, help: string, labelNames?: string[], buckets?: number[]) => Histogram<string>; }; /** * Create metrics middleware * * @param options Metrics options * @returns Express middleware and metrics endpoint handler */ declare function metricsMiddleware(options?: MetricsOptions): { middleware: RequestHandler; endpoint: RequestHandler; }; /** * Options for response formatter middleware */ interface ResponseFormatterOptions { /** * Whether to wrap successful responses * @default true */ wrapSuccess?: boolean; /** * Whether to include request ID in response * @default true */ includeRequestId?: boolean; /** * Default success message * @default 'Operation successful' */ defaultSuccessMessage?: string; /** * Default error message * @default 'Operation failed' */ defaultErrorMessage?: string; } /** * Create middleware to format responses * * @param options Response formatter options * @returns Express middleware */ declare function responseFormatterMiddleware(options?: ResponseFormatterOptions): RequestHandler; declare global { namespace Express { interface Response { success(data?: any, message?: string, meta?: Record<string, any>): Response; created(data?: any, message?: string): Response; noContent(): Response; error(message?: string, statusCode?: number, code?: string, details?: any): Response; paginated(items: any[], page: number, limit: number, totalItems: number, message?: string): Response; } } } /** * Options for request logger middleware */ interface RequestLoggerOptions { /** * Skip logging for specific paths */ skip?: string[]; /** * Log level to use * @default 'info' */ level?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'; /** * Include request body in logs * @default false */ includeBody?: boolean; /** * Include request headers in logs * @default false */ includeHeaders?: boolean; } /** * Middleware to log HTTP requests * * @param logger Logger instance * @param options Request logger options * @returns Express middleware */ declare function requestLoggerMiddleware(logger: Logger, options?: RequestLoggerOptions): RequestHandler; /** * Unified middleware configuration type */ interface MiddlewareConfig { auth?: AuthOptions; uploads?: UploadOptions; validation?: ValidationOptions; correlation?: CorrelationIdOptions; metrics?: MetricsOptions; logging?: RequestLoggerOptions$1; errors?: ErrorHandlingOptions; responses?: ResponseFormatOptions; rateLimiting?: RateLimitOptions; } /** * Initialize middleware with configuration * @param configManager Configuration manager * @param loggerInstance Logger instance */ declare function initializeMiddleware(configManager: ConfigManager, loggerInstance: Logger): void; /** * Update middleware configuration * @param newConfig New configuration to merge with existing config */ declare function configMiddleware(newConfig: Partial<MiddlewareConfig>): void; /** * Get current middleware configuration */ declare function getConfig(): MiddlewareConfig; /** * Initialize and apply all middleware to an Express application * For backward compatibility with existing code * * @param app Express application * @param configManager * @param logger Logger instance */ declare function applyMiddleware(app: Application, configManager: ConfigManager, logger: Logger): Promise<Application>; declare const middleware: { applyMiddleware: typeof applyMiddleware; applyRegularMiddleware: typeof applyRegularMiddleware; applyErrorHandlers: typeof applyErrorHandlers; registerMiddleware: typeof registerMiddleware; isMiddlewareEnabled: typeof isMiddlewareEnabled; validate: typeof validate; validateAll: typeof validateAll; validateQuery: typeof validateQuery; validateRequestAndQuery: typeof validateRequestAndQuery; authenticate: typeof authenticate; authorizeRoles: typeof authorizeRoles; authorizePermissions: typeof authorizePermissions; authorizeOwnership: typeof authorizeOwnership; upload: typeof upload; asyncHandler: typeof asyncHandler; HttpError: typeof HttpError; }; /** * API options for Express configuration */ interface ApiOptions { /** * Enable CORS * @default true */ cors?: boolean; /** * CORS configuration options */ corsOptions?: CorsOptions; /** * Request body size limit * @default '1mb' */ bodyLimit?: string; /** * Enable compression * @default true */ compression?: boolean; /** * Enable Helmet security headers * @default true in production */ helmet?: boolean; /** * Enable request logging * @default true */ requestLogging?: boolean; /** * Enable correlation ID * @default true */ correlationId?: boolean; /** * Options for correlation ID middleware */ correlationIdOptions?: { /** * HTTP header to get/set correlation ID * @default 'X-Correlation-ID' */ header?: string; /** * Property name to store correlation ID in request * @default 'correlationId' */ propertyName?: string; /** * Whether to generate ID if not provided * @default true */ generateId?: boolean; }; /** * Response formatting options */ responseFormat?: ResponseFormatOptions; /** * Base path for all API routes * @default '/api' */ basePath?: string; /** * Additional express middlewares to apply before routes */ preMiddlewares?: RequestHandler[]; /** * Additional express middlewares to apply after routes */ postMiddlewares?: RequestHandler[]; /** * Rate limiting configuration */ rateLimit?: RateLimiterOptions; /** * Metrics configuration */ metrics?: MetricsOptions; /** * Error handling configuration */ errorHandling?: ErrorHandlingOptions; /** * Middleware configuration options * Control which middleware components are enabled and their configuration */ middleware?: { /** * List of middleware to explicitly enable */ enabled?: string[]; /** * List of middleware to explicitly disable */ disabled?: string[]; /** * Custom order for middleware application * Middleware not in this list will be applied based on default order */ order?: string[]; /** * Custom middleware implementations * Register additional middleware not provided by the framework */ custom?: Array<{ /** * Name of the custom middleware */ name: string; /** * Factory function to create the middleware */ factory: (config: any, logger: any) => RequestHandler | RequestHandler[]; /** * Dependencies on other middleware */ dependencies?: string[]; /** * Order priority (lower numbers run earlier) */ order?: number; /** * Whether this middleware should be applied after routes */ afterRoutes?: boolean; }>; }; } /** * Result of creating an API */ interface ApiResult { app: Application; mountRoutes: (router: Router) => void; } /** * Configuration options */ interface ConfigOptions { /** * Path to configuration file * @default Auto-detected from project structure */ path?: string; /** * Default values to use if config file is missing */ defaults?: Record<string, any>; /** * Keys that contain sensitive data to be masked in logs */ secretKeys?: string[]; /** * Force a specific environment * @default process.env.NODE_ENV || 'development' */ environment?: string; /** * Service name (used for default config) */ serviceName?: string; } /** * API Documentation options */ interface DocumentationOptions { /** * Enable API documentation * @default true in development, false in production */ enabled?: boolean; /** * Documentation type * @default 'swagger' */ type?: 'swagger' | 'redoc' | 'custom'; /** * Documentation endpoint * @default '/api-docs' */ endpoint?: string; /** * API title */ title?: string; /** * API version */ version?: string; /** * API description */ description?: string; /** * Custom CSS for documentation UI */ customCss?: string; /** * Files to scan for API documentation */ apiPaths?: string[]; /** * OAuth2 configuration */ oauth2?: { enabled?: boolean; clientId?: string; appName?: string; scopes?: string[]; }; } /** * Custom API error class with status code and error code */ declare class ApiError extends Error { statusCode: number; code: string; details?: Record<string, any>; /** * Create a new API error * * @param message Error message * @param statusCode HTTP status code * @param code Error code for client * @param details Additional error details */ constructor(message: string, statusCode?: number, code?: string, details?: Record<string, any>); /** * Create a not found error * * @param message Error message * @param code Error code * @returns ApiError */ static notFound(message?: string, code?: string): ApiError; /** * Create a bad request error * * @param message Error message * @param code Error code * @param details Additional error details * @returns ApiError */ static badRequest(message?: string, code?: string, details?: Record<string, any>): ApiError; /** * Create an unauthorized error * * @param message Error message * @param code Error code * @returns ApiError */ static unauthorized(message?: string, code?: string): ApiError; /** * Create a forbidden error * * @param message Error message * @param code Error code * @returns ApiError */ static forbidden(message?: string, code?: string): ApiError; /** * Create a conflict error * * @param message Error message * @param code Error code * @returns ApiError */ static conflict(message?: string, code?: string): ApiError; /** * Create a validation error * * @param message Error message * @param details Validation error details * @returns ApiError */ static validation(message?: string, details?: Record<string, any>): ApiError; /** * Create an internal server error * * @param message Error message * @param code Error code * @returns ApiError */ static internal(message?: string, code?: string): ApiError; /** * Create a service unavailable error * * @param message Error message * @param code Error code * @returns ApiError */ static serviceUnavailable(message?: string, code?: string): ApiError; } /** * Error codes enum */ declare enum ErrorCode { INTERNAL_ERROR = "INTERNAL_ERROR", VALIDATION_ERROR = "VALIDATION_ERROR", UNAUTHORIZED = "UNAUTHORIZED", FORBIDDEN = "FORBIDDEN", NOT_FOUND = "NOT_FOUND", BAD_REQUEST = "BAD_REQUEST", CONFLICT = "CONFLICT", TOO_MANY_REQUESTS = "TOO_MANY_REQUESTS", SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE" } /** * HTTP dependency configuration */ interface HttpDependencyConfig { /** * Name of the dependency */ name: string; /** * URL to check */ url: string; /** * HTTP method * @default 'GET' */ method?: string; /** * Request timeout in milliseconds * @default 5000 (5 seconds) */ timeout?: number; /** * Expected HTTP status code * @default 200 */ expectedStatus?: number; /** * Custom headers */ headers?: Record<string, string>; /** * Whether this is a critical component * Critical components affect readiness status * @default false */ critical?: boolean; } /** * Custom health indicator configuration */ interface CustomHealthIndicator { /** * Name of the indicator */ name: string; /** * Check function */ check: () => Promise<{ status: Status | string; details?: Record<string, any>; }>; /** * Whether this is a critical component * Critical components affect readiness status * @default false */ critical?: boolean; } /** * Dashboard configuration options */ interface DashboardOptions { /** * Enable dashboard UI * @default true */ enabled?: boolean; /** * Dashboard path * @default '/health/dashboard' */ path?: string; /** * Dashboard title * @default 'Application Health Dashboard' */ title?: string; /** * Refresh interval in milliseconds * @default 10000 (10 seconds) */ refreshInterval?: number; } /** * History tracking configuration options */ interface HistoryOptions { /** * Enable history tracking * @default true */ enabled?: boolean; /** * Data collection interval in milliseconds * @default 60000 (1 minute) */ interval?: number; /** * Maximum number of entries to keep * @default 100 */ maxEntries?: number; /** * Maximum items to return in API response * @default 50 */ limit?: number; } /** * Status monitor configuration options */ interface StatusMonitorOptions { /** * Enable the status monitor * @default true */ enabled?: boolean; /** * Status monitor path * @default '/status' */ path?: string; /** * Status monitor title * @default 'Application Status Monitor' */ title?: string; /** * Theme to use * @default 'default' */ theme?: string; } /** * Health check options */ interface HealthOptions { /** * Enable health checks * @default true */ enabled?: boolean; /** * Health check endpoint * @default '/health' */ endpoint?: string; /** * Memory usage threshold percentage * @default 85 */ memoryThreshold?: number; /** * Cache time for health check results in milliseconds * @default 10000 (10 seconds) */ cacheTime?: number; /** * HTTP dependency configurations */ httpDependencies?: Array<HttpDependencyConfig>; /** * Custom health indicators */ customIndicators?: Array<CustomHealthIndicator>; /** * Dashboard configuration */ dashboard?: DashboardOptions; /** * History tracking configuration */ history?: HistoryOptions; /** * Status monitor configuration */ statusMonitor?: StatusMonitorOptions; } /** * Standard success response wrapper */ interface SuccessResponse<T = any> { success: true; message?: string; data?: T; correlationId?: string; } /** * Standard error response wrapper */ interface ErrorResponse { success: false; message: string; code: string; details?: any; correlationId?: string; stack?: string; } /** * HTTP status code map */ interface HttpStatusDefinition { code: string; message: string; } /** * Pagination metadata */ interface PaginationMeta { page: number; limit: number; totalPages: number; totalItems: number; } /** * Paginated response */ interface PaginatedResponse<T = any> extends SuccessResponse { data: T[]; pagination: PaginationMeta; } interface DatabaseConnectionOptions { /** * Database server hostname */ host?: string; /** * Database server port */ port?: number; /** * Database username */ username?: string; /** * Database password */ password?: string; /** * Database name */ database?: string; /** * Full connection URL (if using connection string) */ url?: string; /** * SSL configuration: * - true: Use default SSL config (rejectUnauthorized: false) * - false: Disable SSL * - object: Custom SSL config with specific options */ ssl?: boolean | object; /** * Maximum number of clients in the connection pool */ poolSize?: number; } interface DatabaseOptions { type?: string; connection?: DatabaseConnectionOptions; required?: boolean; init?: (config: ConfigManager, logger: Logger) => Promise<DatabaseConnection$1>; schema?: any; schemaPath?: string; } interface DatabaseConnection$1 { client: unknown; config: Record<string, any>; db: any; pool?: Pool; query(text: string, params?: any[]): Promise<any>; ping(): Promise<boolean>; beginTransaction?(): Promise<any>; disconnect?(): Promise<void>; } /** * Main server configuration options */ interface ServerOptions { /** * Service name used for logging and identification */ serviceName: string; /** * Log level (debug, info, warn, error) * @default process.env.LOG_LEVEL || 'info' */ logLevel?: string; /** * Configuration options */ config?: ConfigOptions; /** * API framework options for express configuration */ api?: ApiOptions; /** * Database configuration */ database?: DatabaseOptions; /** * Authentication configuration */ auth?: AuthOptions; /** * API documentation options */ docs?: DocumentationOptions; /** * Health check configuration */ health?: HealthOptions; /** * Function to set up routes */ setupRoutes: (apiContext: ApiResult, dbConnection: DatabaseConnection$2 | null, authMiddleware: RequestHandler, logger: Logger) => Promise<void>; /** * Lifecycle hooks for server startup and shutdown */ hooks?: ServerHooks; } /** * Server lifecycle hooks */ interface ServerHooks { /** * Called before any initialization */ beforeInit?: (logger: Logger) => Promise<void>; /** * Called after config is loaded but before anything else */ afterConfigLoaded?: (config: ConfigManager, logger: Logger) => Promise<void>; /** * Called after API is created but before routes are added */ afterApiCreated?: (app: Application, config: ConfigManager, logger: Logger) => Promise<void>; /** * Called after database is initialized */ afterDatabaseInit?: (dbConnection: DatabaseConnection$2, config: ConfigManager, logger: Logger) => Promise<void>; /** * Called after routes are set up */ afterRoutesSetup?: (app: Application, config: ConfigManager, logger: Logger) => Promise<void>; /** * Called just before server starts listening */ beforeServerStart?: (app: Application, config: ConfigManager, logger: Logger) => Promise<void>; /** * Called after server has started listening */ afterServerStart?: (port: number, host: string, environment: string, app: Application, logger: Logger) => Promise<void>; /** * Called when SIGTERM is received, before closing connections */ beforeShutdown?: (logger: Logger) => Promise<void>; /** * Called after database connection is closed during shutdown */ afterDatabaseClosed?: (logger: Logger) => Promise<void>; /** * Called after server is closed during shutdown */ afterServerClosed?: (logger: Logger) => Promise<void>; } /** * Type exports from the API framework */ type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]>; } : T; interface DatabaseConnection { client: any; type?: string; query: (text: string, params: any[]) => Promise<any>; beginTransaction?: () => Promise<any>; ping?: () => Promise<boolean>; disconnect?: () => Promise<void>; close?: () => Promise<void>; } /** * Creates and configures an Express application with middleware */ declare function createApi(config: ConfigManager, logger: Logger, options?: ApiOptions): Promise<ApiResult>; /** * Start an API server with provided configuration * * @param options Server configuration options * @returns A promise that resolves to the server instance */ declare function startServer(options: ServerOptions): Promise<Server>; /** * Initialize and load application configuration * * @param logger Logger instance * @param options Configuration options * @returns Initialized ConfigManager */ declare function initializeConfig(logger: Logger, options?: ConfigOptions): Promise<ConfigManager>; /** * Initialize database connection * * @param config Configuration manager * @param logger Logger instance * @param options Database options * @returns Database connection */ declare function initializeDatabase(config: ConfigManager, logger: Logger, options?: DatabaseOptions): Promise<DatabaseConnection$2 | null>; /** * Close the current database connection * * @param logger Logger instance */ declare function closeDatabase(logger: Logger): Promise<void>; /** * Get the current database connection * This is useful for direct access to the Drizzle ORM instance in other parts of the application * * @returns The current database connection or null if not initialized */ declare function getCurrentDatabaseConnection(): DatabaseConnection$2 | null; /** * Setup health checks for the application using @unidev-hub/health * Includes status monitoring UI and enhanced visualization * * @param app Express application * @param dbConnection Database connection (optional) * @param config Configuration manager * @param logger Logger instance * @param options Health check options */ declare function setupHealthChecks(app: Application, dbConnection: DatabaseConnection$2 | null, config: ConfigManager, logger: Logger, options?: HealthOptions): Promise<void>; /** * Setup Swagger documentation * * @param app Express application * @param config Configuration manager * @param logger Logger instance * @param options Documentation options */ declare function setupSwagger(app: Application, config: ConfigManager, logger: Logger, options?: DocumentationOptions): Promise<void>; /** * Setup ReDoc documentation * * @param app Express application * @param config Configuration manager * @param logger Logger instance * @param options Documentation options */ declare function setupRedoc(app: Application, config: ConfigManager, logger: Logger, options?: DocumentationOptions): Promise<void>; /** * Setup API documentation * * @param app Express application * @param config Configuration manager * @param logger Logger instance * @param options Documentation options */ declare function setupDocumentation(app: Application, config: ConfigManager, logger: Logger, options?: DocumentationOptions): Promise<void>; /** * Execute beforeInit hook if provided * * @param hooks ServerHooks object * @param logger Logger instance */ declare function executeBeforeInit(hooks: ServerHooks | undefined, logger: Logger): Promise<void>; /** * Execute afterConfigLoaded hook if provided * * @param hooks ServerHooks object * @param config ConfigManager instance * @param logger Logger instance */ declare function executeAfterConfigLoaded(hooks: ServerHooks | undefined, config: ConfigManager, logger: Logger): Promise<void>; /** * Execute afterApiCreated hook if provided * * @param hooks ServerHooks object * @param app Express application * @param config ConfigManager instance * @param logger Logger instance */ declare function executeAfterApiCreated(hooks: ServerHooks | undefined, app: Application, config: ConfigManager, logger: Logger): Promise<void>; /** * Execute afterDatabaseInit hook if provided * * @param hooks ServerHooks object * @param dbConnection Database connection * @param config ConfigManager instance * @param logger Logger instance */ declare function executeAfterDatabaseInit(hooks: ServerHooks | undefined, dbConnection: DatabaseConnection$2, config: ConfigManager, logger: Logger): Promise<void>; /** * Execute afterRoutesSetup hook if provided * * @param hooks ServerHooks object * @param app Express application * @param config ConfigManager instance * @param logger Logger instance */ declare function executeAfterRoutesSetup(hooks: ServerHooks | undefined, app: Application, config: ConfigManager, logger: Logger): Promise<void>; /** * Execute beforeServerStart hook if provided * * @param hooks ServerHooks object * @param app Express application * @param config ConfigManager instance * @param logger Logger instance */ declare function executeBeforeServerStart(hooks: ServerHooks | undefined, app: Application, config: ConfigManager, logger: Logger): Promise<void>; /** * Execute afterServerStart hook if provided * * @param hooks ServerHooks object * @param port Server port * @param host Server host * @param environment Environment name * @param app Express application * @param logger Logger instance */ declare function executeAfterServerStart(hooks: ServerHooks | undefined, port: number, host: string, environment: string, app: Application, logger: Logger): Promise<void>; /** * Execute beforeShutdown hook if provided * * @param hooks ServerHooks object * @param logger Logger instance */ declare function executeBeforeShutdown(hooks: ServerHooks | undefined, logger: Logger): Promise<void>; /** * Execute afterDatabaseClosed hook if provided * * @param hooks ServerHooks object * @param logger Logger instance */ declare function executeAfterDatabaseClosed(hooks: ServerHooks | undefined, logger: Logger): Promise<void>; /** * Execute afterServerClosed hook if provided * * @param hooks ServerHooks object * @param logger Logger instance */ declare function executeAfterServerClosed(hooks: ServerHooks | undefined, logger: Logger): Promise<void>; /** * Standard HTTP status codes with corresponding error codes and messages */ declare const STATUS_CODES: { [key: number]: HttpStatusDefinition; }; /** * Enum of common HTTP status codes */ declare enum HttpStatus { OK = 200, CREATED = 201, ACCEPTED = 202, NO_CONTENT = 204, BAD_REQUEST = 400, UNAUTHORIZED = 401, FORBIDDEN = 403, NOT_FOUND = 404, METHOD_NOT_ALLOWED = 405, NOT_ACCEPTABLE = 406, CONFLICT = 409, UNPROCESSABLE_ENTITY = 422, TOO_MANY_REQUESTS = 429, INTERNAL_SERVER_ERROR = 500, NOT_IMPLEMENTED = 501, SERVICE_UNAVAILABLE = 503 } /** * Formats an error into a standardized error response */ declare function formatError(error: Error | ApiError, includeStack?: boolean, correlationId?: string): ErrorResponse; /** * Convert any error to an ApiError */ declare function normalizeError(error: any, defaultStatusCode?: number, defaultCode?: ErrorCode): ApiError; /** * Options for schema validation */ interface SchemaValidationOptions { abortEarly?: boolean; stripUnknown?: boolean; context?: Record<string, any>; } /** * Validates data against a Joi schema and returns the validated/sanitized result * Throws a HttpError if validation fails */ declare function validateSchema<T = any>(data: any, schema: Joi.Schema, options?: SchemaValidationOptions): T; /** * Common schema builders for standard patterns */ declare const schemaBuilders: { /** * Pagination schema with standard parameters */ pagination: () => Joi.ObjectSchema<any>; /** * UUID parameter schema */ uuidParam: () => Joi.StringSchema<string>; /** * ID parameter schema (for common ID patterns) */ idParam: (prefix?: string) => Joi.StringSchema<string>; }; /** * Utility functions for masking sensitive data in logs and outputs */ /** * Mask a database connection string * * @param connectionString Database connection string * @returns Masked connection string */ declare function maskConnectionString(connectionString: string): string; /** * Mask a JWT or other authentication token * * @param token Authentication token * @returns Masked token */ declare function maskAuthToken(token: string): string; /** * Mask any sensitive data based on field name or content * * @param key Field key * @param value Field value * @returns Masked value if sensitive, original value otherwise */ declare function maskSensitiveData(value: any, key?: string): any; /** * Deep mask sensitive data in an object * * @param obj Object to mask * @returns New object with sensitive data masked */ declare function maskSensitiveObject<T extends Record<string, any>>(obj: T): T; /** * Resolves paths intelligently with fallbacks and environment support */ declare class PathResolver { private projectRoot; private logger; constructor(logger: Logger); /** * Resolve config file path with automatic environment detection * * @param customPath Optional explicit path to config file * @param filename Default filename to use * @returns Resolved config file path */ resolveConfigPath(customPath?: string, filename?: string): string; /** * Resolve a path relative to the project root * * @param relativePath Path relative to project root * @returns Absolute path */ resolveFromRoot(relativePath: string): string; /** * Check if a file or directory exists * * @param filePath Path to check * @returns true if exists, false otherwise */ exists(filePath: string): boolean; /** * Find the first existing file from a list of possible paths * * @param paths List of paths to check * @returns First existing path or undefined if none exist */ findFirstExisting(paths: string[]): string | undefined; } /** * Create a new PathResolver instance */ declare function createPathResolver(logger: Logger): PathResolver; declare const toDate: (value: string | Date | null | undefined) => Date | undefined; /** * Loads and parses configuration files */ declare class ConfigLoader { private logger; private pathResolver; constructor(logger: Logger); /** * Load configuration from a YAML file * * @param configPath Path to configuration file (optional) * @returns Parsed configuration object or null if loading failed */ loadConfig(configPath?: string): Record<string, any> | null; /** * Create a default configuration file if it doesn't exist * * @param templatePath Path to template configuration file * @param targetPath Path where the config should be created * @returns true if created, false otherwise */ createDefaultConfig(templatePath: string, targetPath: string): boolean; } /** * Create a new ConfigLoader instance */ declare function createConfigLoader(logger: Logger): ConfigLoader; /** * Sets up Swagger/OpenAPI documentation for the Express application */ declare function setupSwaggerDocs(app: Application, options: DocsOptions): void; /** * Helper to generate route documentation from a schema */ declare function generateRouteDoc(options: { tags: string[]; summary: string; description?: string; operationId?: string; requestBody?: any; parameters?: any[]; responses?: any; security?: any[]; }): { tags: string[]; summary: string; description?: string; operationId?: string; requestBody?: any; parameters?: any[]; responses?: any; security?: any[]; }; export { ApiError, type ApiOptions, type ApiResult, type AuthOptions, ConfigLoader, type ConfigOptions, type CorrelationIdOptions, type CustomHealthIndicator, type DashboardOptions, type DatabaseConnection, type DatabaseConnectionOptions, type DatabaseOptions, type DeepPartial, type DocumentationOptions, ErrorCode, type ErrorHandlingOptions, type ErrorMiddlewareFactory, type ErrorResponse, type HealthOptions, type HistoryOptions, type HttpDependencyConfig, HttpError, HttpStatus, type HttpStatusDefinition, type MetricsOptions, Middleware, type MiddlewareFactory, MiddlewareGroups, type PaginatedResponse, type PaginationMeta, PathResolver, type RateLimitOptions, type RegularMiddlewareFactory, type RequestLoggerOptions$1 as RequestLoggerOptions, type ResponseFormatOptions, STATUS_CODES, type SchemaValidationOptions, type ServerHooks, type ServerOptions, type StatusMonitorOptions, type SuccessResponse, type UploadOptions, type ValidationOptions, applyErrorHandler, applyErrorHandlers, applyMiddleware, applyRegularMiddleware, asyncHandler, authenticate, authorizeOwnership, authorizePermissions, authorizeRoles, closeDatabase, configMiddleware, correlationIdMiddleware, createApi, createConfigLoader, createPathResolver, errorHandlerMiddleware, executeAfterApiCreated, executeAfterConfigLoaded, executeAfterDatabaseClosed, executeAfterDatabaseInit, executeAfterRoutesSetup, executeAfterServerClosed, executeAfterServerStart, executeBeforeInit, executeBeforeServerStart, executeBeforeShutdown, formatError, generateRouteDoc, getConfig, getCurrentDatabaseConnection, initializeConfig, initializeDatabase, initializeMiddleware, isMiddlewareEnabled, maskAuthToken, maskConnectionString, maskSensitiveData, maskSensitiveObject, metrics, metricsMiddlewa