@@ -84,6 +84,7 @@ export interface RouteInfo {
8484 isComplex : boolean ; // Uses regex matching instead of native uWS
8585 handler : RouteHandler ; // Store the handler
8686 metadata ?: RouteMetadata ; // Middleware metadata
87+ implicitHead ?: boolean ; // Auto-registered HEAD fallback for GET routes
8788}
8889
8990/**
@@ -211,7 +212,13 @@ export class RouteRegistry {
211212 * @param metadata - Optional middleware metadata (guards, pipes, filters)
212213 * @throws Error if route is already registered
213214 */
214- register ( method : string , path : string , handler : RouteHandler , metadata ?: RouteMetadata ) : void {
215+ register (
216+ method : string ,
217+ path : string ,
218+ handler : RouteHandler ,
219+ metadata ?: RouteMetadata ,
220+ implicitHead = false
221+ ) : void {
215222 // Convert method to uWS format and normalize to uppercase for consistency
216223 const uwsMethod = this . convertMethod ( method ) ;
217224 const normalizedMethod = method . toUpperCase ( ) ;
@@ -226,15 +233,41 @@ export class RouteRegistry {
226233
227234 // Check for duplicate route registration using normalized method
228235 const routeKey = `${ normalizedMethod } :${ path } ` ;
229- if ( this . routes . has ( routeKey ) ) {
236+ const existingRoute = this . routes . get ( routeKey ) ;
237+ if ( existingRoute ) {
238+ if ( implicitHead ) {
239+ return ;
240+ }
241+
242+ if ( normalizedMethod === 'HEAD' && existingRoute . implicitHead ) {
243+ const routeInfo = {
244+ method : normalizedMethod ,
245+ path,
246+ uwsPath,
247+ pattern,
248+ paramNames,
249+ isComplex,
250+ handler,
251+ metadata,
252+ } ;
253+
254+ this . routes . set ( routeKey , routeInfo ) ;
255+ if ( isComplex ) {
256+ const staticPrefix = this . extractStaticPrefix ( path ) ;
257+ const registrationPath = staticPrefix ? `${ staticPrefix } /*` : '/*' ;
258+ const wildcardKey = `${ uwsMethod } :${ registrationPath } ` ;
259+ this . replaceComplexRoute ( wildcardKey , routeInfo ) ;
260+ }
261+ return ;
262+ }
263+
230264 throw new Error (
231265 `Route already registered: ${ normalizedMethod } ${ path } . ` +
232266 `Duplicate route registration is not allowed as it would cause multiple handlers to execute for the same route.`
233267 ) ;
234268 }
235269
236- // Track registered route with normalized method
237- this . routes . set ( routeKey , {
270+ const routeInfo = {
238271 method : normalizedMethod ,
239272 path,
240273 uwsPath,
@@ -243,7 +276,11 @@ export class RouteRegistry {
243276 isComplex,
244277 handler,
245278 metadata,
246- } ) ;
279+ implicitHead,
280+ } ;
281+
282+ // Track registered route with normalized method
283+ this . routes . set ( routeKey , routeInfo ) ;
247284
248285 // Get the uWS method function
249286 const uwsMethodFn = this . uwsApp [ uwsMethod as keyof uWS . TemplatedApp ] as any ;
@@ -345,22 +382,15 @@ export class RouteRegistry {
345382 }
346383
347384 // Add this route to the wildcard's route list
348- this . complexRoutesByWildcard . get ( wildcardKey ) ! . push ( {
349- method : normalizedMethod ,
350- path,
351- uwsPath,
352- pattern,
353- paramNames,
354- isComplex,
355- handler,
356- metadata,
357- } ) ;
385+ this . complexRoutesByWildcard . get ( wildcardKey ) ! . push ( routeInfo ) ;
358386 } else {
359387 // Simple route - use native uWS routing
360388 uwsMethodFn . call (
361389 this . uwsApp ,
362390 uwsPath ,
363391 async ( uwsRes : uWS . HttpResponse , uwsReq : uWS . HttpRequest ) => {
392+ const activeRoute = this . routes . get ( routeKey ) ! ;
393+
364394 // Create request/response wrappers
365395 const req = new UwsRequest ( uwsReq , uwsRes , paramNames ) ;
366396 const res = new UwsResponse ( uwsRes ) ;
@@ -383,10 +413,14 @@ export class RouteRegistry {
383413 ) ;
384414
385415 // Execute handler with error handling
386- await this . executeHandler ( handler , req , res , metadata ) ;
416+ await this . executeHandler ( activeRoute . handler , req , res , activeRoute . metadata ) ;
387417 }
388418 ) ;
389419 }
420+
421+ if ( normalizedMethod === 'GET' && ! implicitHead ) {
422+ this . register ( 'HEAD' , path , handler , metadata , true ) ;
423+ }
390424 }
391425
392426 /**
@@ -896,7 +930,7 @@ export class RouteRegistry {
896930 * @returns Map of route keys to route information
897931 */
898932 getRoutes ( ) : Map < string , RouteInfo > {
899- return new Map ( this . routes ) ;
933+ return new Map ( [ ... this . routes ] . filter ( ( [ , route ] ) => ! route . implicitHead ) ) ;
900934 }
901935
902936 /**
@@ -918,7 +952,21 @@ export class RouteRegistry {
918952 * @returns Number of registered routes
919953 */
920954 getRouteCount ( ) : number {
921- return this . routes . size ;
955+ return [ ...this . routes . values ( ) ] . filter ( ( route ) => ! route . implicitHead ) . length ;
956+ }
957+
958+ private replaceComplexRoute ( wildcardKey : string , routeInfo : RouteInfo ) : void {
959+ const routes = this . complexRoutesByWildcard . get ( wildcardKey ) ;
960+ if ( ! routes ) {
961+ return ;
962+ }
963+
964+ const routeIndex = routes . findIndex (
965+ ( route ) => route . method === routeInfo . method && route . path === routeInfo . path
966+ ) ;
967+ if ( routeIndex !== - 1 ) {
968+ routes [ routeIndex ] = routeInfo ;
969+ }
922970 }
923971
924972 /**
0 commit comments