11import type { IServerOptions } from 'types/Server.ts' ;
2+ import type { TErrorFunction } from 'types/Response.ts' ;
3+ import type { Context } from 'core/Context.ts' ;
4+ import type { TResponseBody } from 'types/http/Response.ts' ;
5+ import {
6+ DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT ,
7+ DEFAULT_HEADERS_TIMEOUT ,
8+ DEFAULT_KEEP_ALIVE_TIMEOUT ,
9+ DEFAULT_PORT ,
10+ DEFAULT_SOCKET_TIMEOUT ,
11+ } from 'constants/connection.ts' ;
12+ import { HttpStatusCode } from 'constants/http.ts' ;
213
314/**
415 * Manages application configuration in a centralized way
@@ -8,44 +19,94 @@ import type { IServerOptions } from 'types/Server.ts';
819 * passing options through multiple layers.
920 */
1021export class ConfigManager {
11- private readonly options : IServerOptions ;
22+ readonly port : number ;
23+ readonly errorHandler : TErrorFunction ;
24+ readonly connectionOptions : Required < IServerOptions > [ 'connectionOptions' ] ;
25+ readonly parserOptions : Required < IServerOptions > [ 'parserOptions' ] ;
1226
1327 constructor ( options ?: IServerOptions ) {
14- this . options = options ?? { } ;
28+ this . port = this . _setPort ( options ?. port ) ;
29+ this . errorHandler = this . _setErrorHandler ( options ?. errorHandler ) ;
30+ this . connectionOptions = this . _setConnectionOptions ( options ?. connectionOptions ) ;
31+ this . parserOptions = this . _setParserOptions ( options ?. parserOptions ) ;
1532 }
1633
1734 /**
18- * Get parser options
35+ * Sets the port number and normalizes it to a number
1936 */
20- get parserOptions ( ) : IServerOptions [ 'parserOptions' ] {
21- return this . options . parserOptions ;
37+ private _setPort ( port ?: number | string ) : number {
38+ const normalizedPort = typeof port === 'string' ? parseInt ( port , 10 ) : ( port ?? DEFAULT_PORT ) ;
39+ if ( isNaN ( normalizedPort ) || normalizedPort < 0 || normalizedPort > 65535 ) {
40+ throw new Error ( 'Invalid port number' ) ;
41+ }
42+ return normalizedPort ;
2243 }
2344
2445 /**
25- * Get connection options
46+ * Sets the error handler with validation
2647 */
27- get connectionOptions ( ) : IServerOptions [ 'connectionOptions' ] {
28- return this . options . connectionOptions ;
48+ private _setErrorHandler ( handler ?: TErrorFunction ) : TErrorFunction {
49+ if ( handler && typeof handler !== 'function' ) {
50+ throw new Error ( 'Error handler must be a function' ) ;
51+ }
52+ return (
53+ handler ??
54+ ( ( { response } : Context , error : unknown ) : TResponseBody < unknown > => {
55+ console . error ( 'Server error: \n' , error ) ;
56+ response . setStatus ( HttpStatusCode . INTERNAL_SERVER_ERROR ) ;
57+ if ( error instanceof Error ) {
58+ return { success : false , message : error . message } ;
59+ }
60+ return { success : false , message : 'An unknown error occurred' } ;
61+ } )
62+ ) ;
2963 }
3064
3165 /**
32- * Get error handler
66+ * Sets and validates connection options
3367 */
34- get errorHandler ( ) : IServerOptions [ 'errorHandler' ] {
35- return this . options . errorHandler ;
68+ private _setConnectionOptions ( options ?: IServerOptions [ 'connectionOptions' ] ) : Required < IServerOptions > [ 'connectionOptions' ] {
69+ const normalizedOptions = {
70+ socketTimeout : this . _normalizeTimeout ( options ?. socketTimeout , DEFAULT_SOCKET_TIMEOUT ) ,
71+ gracefulShutdownTimeout : this . _normalizeTimeout ( options ?. gracefulShutdownTimeout , DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT ) ,
72+ keepAliveTimeout : this . _normalizeTimeout ( options ?. keepAliveTimeout , DEFAULT_KEEP_ALIVE_TIMEOUT ) ,
73+ headersTimeout : this . _normalizeTimeout ( options ?. headersTimeout , DEFAULT_HEADERS_TIMEOUT ) ,
74+ } ;
75+
76+ if ( normalizedOptions . headersTimeout <= normalizedOptions . keepAliveTimeout ) {
77+ throw new Error ( 'headersTimeout must be greater than keepAliveTimeout' ) ;
78+ }
79+
80+ return normalizedOptions ;
3681 }
3782
3883 /**
39- * Get port
84+ * Normalizes a timeout value to a positive number
4085 */
41- get port ( ) : number | undefined {
42- return this . options . port ;
86+ private _normalizeTimeout ( value : number | string | undefined , defaultValue : number ) : number {
87+ const normalized = typeof value === 'string' ? parseInt ( value , 10 ) : ( value ?? defaultValue ) ;
88+ if ( isNaN ( normalized ) || normalized < 0 ) {
89+ throw new Error ( 'Timeout must be a positive number' ) ;
90+ }
91+ return normalized ;
4392 }
4493
4594 /**
46- * Get the full options object
95+ * Sets and validates parser options
4796 */
48- getOptions ( ) : IServerOptions {
49- return { ...this . options } ;
97+ private _setParserOptions ( options ?: IServerOptions [ 'parserOptions' ] ) : Required < IServerOptions > [ 'parserOptions' ] {
98+ const normalizedOptions = options ?? { } ;
99+
100+ // Validate JSON parser options
101+ if ( normalizedOptions . json ?. raw !== undefined && typeof normalizedOptions . json . raw !== 'boolean' ) {
102+ throw new Error ( 'JSON parser raw option must be a boolean' ) ;
103+ }
104+
105+ // Validate YAML parser options
106+ if ( normalizedOptions . yaml ?. raw !== undefined && typeof normalizedOptions . yaml . raw !== 'boolean' ) {
107+ throw new Error ( 'YAML parser raw option must be a boolean' ) ;
108+ }
109+
110+ return normalizedOptions ;
50111 }
51112}
0 commit comments