@@ -173,12 +173,30 @@ export class HttpDispatcher {
173173
174174 try {
175175 // Try specific calls based on type
176- if ( type === 'objects' ) {
176+ if ( type === 'objects' || type === 'object' ) {
177177 const data = await broker . call ( 'metadata.getObject' , { objectName : name } , { request : context . request } ) ;
178178 return { handled : true , response : this . success ( data ) } ;
179179 }
180- // Generic call for other types if supported
181- const data = await broker . call ( `metadata.get${ this . capitalize ( type . slice ( 0 , - 1 ) ) } ` , { name } , { request : context . request } ) ;
180+
181+ // If type is singular (e.g. 'app'), use it directly
182+ // If plural (e.g. 'apps'), slice it
183+ const singularType = type . endsWith ( 's' ) ? type . slice ( 0 , - 1 ) : type ;
184+
185+ // Try Protocol Service First (Preferred)
186+ const protocol = this . kernel ?. context ?. getService ? this . kernel . context . getService ( 'protocol' ) : null ;
187+ if ( protocol && typeof protocol . getMetaItem === 'function' ) {
188+ try {
189+ const data = await protocol . getMetaItem ( { type : singularType , name } ) ;
190+ return { handled : true , response : this . success ( data ) } ;
191+ } catch ( e : any ) {
192+ // Protocol might throw if not found or not supported
193+ // Fallback to broker?
194+ }
195+ }
196+
197+ // Generic call for other types if supported via Broker (Legacy)
198+ const method = `metadata.get${ this . capitalize ( singularType ) } ` ;
199+ const data = await broker . call ( method , { name } , { request : context . request } ) ;
182200 return { handled : true , response : this . success ( data ) } ;
183201 } catch ( e : any ) {
184202 // Fallback: treat first part as object name if only 1 part (handled below)
@@ -537,6 +555,17 @@ export class HttpDispatcher {
537555 async dispatch ( method : string , path : string , body : any , query : any , context : HttpProtocolContext ) : Promise < HttpDispatcherResult > {
538556 const cleanPath = path . replace ( / \/ $ / , '' ) ; // Remove trailing slash if present, but strict on clean paths
539557
558+ // 0. Root Discovery Endpoint (GET /)
559+ // Handles request to base URL (e.g. /api/v1) which MSW strips to empty string
560+ if ( cleanPath === '' && method === 'GET' ) {
561+ // We use '' as prefix since we are internal dispatcher
562+ const info = this . getDiscoveryInfo ( '' ) ;
563+ return {
564+ handled : true ,
565+ response : this . success ( info )
566+ } ;
567+ }
568+
540569 // 1. System Protocols (Prefix-based)
541570 if ( cleanPath . startsWith ( '/auth' ) ) {
542571 return this . handleAuth ( cleanPath . substring ( 5 ) , method , body , context ) ;
0 commit comments