@@ -1208,4 +1208,104 @@ describe('HttpDispatcher', () => {
12081208 expect ( result . response ?. status ) . toBe ( 200 ) ;
12091209 } ) ;
12101210 } ) ;
1211+
1212+ describe ( 'handleMetadata without broker (serverless degradation)' , ( ) => {
1213+ let brokerlessKernel : any ;
1214+ let brokerlessDispatcher : HttpDispatcher ;
1215+
1216+ beforeEach ( ( ) => {
1217+ // Kernel with NO broker — simulates a lightweight/serverless setup
1218+ // where only the protocol service and/or ObjectQL registry are available.
1219+ brokerlessKernel = {
1220+ broker : null ,
1221+ context : {
1222+ getService : vi . fn ( ) . mockReturnValue ( null ) ,
1223+ } ,
1224+ } ;
1225+ brokerlessDispatcher = new HttpDispatcher ( brokerlessKernel ) ;
1226+ } ) ;
1227+
1228+ it ( 'GET /meta should return default types when broker is missing' , async ( ) => {
1229+ const context = { request : { } } ;
1230+ const result = await brokerlessDispatcher . handleMetadata ( '' , context , 'GET' ) ;
1231+ expect ( result . handled ) . toBe ( true ) ;
1232+ expect ( result . response ?. status ) . toBe ( 200 ) ;
1233+ expect ( result . response ?. body ?. data ?. types ) . toContain ( 'object' ) ;
1234+ } ) ;
1235+
1236+ it ( 'GET /meta/types should return default types when broker is missing' , async ( ) => {
1237+ const context = { request : { } } ;
1238+ const result = await brokerlessDispatcher . handleMetadata ( '/types' , context , 'GET' ) ;
1239+ expect ( result . handled ) . toBe ( true ) ;
1240+ expect ( result . response ?. status ) . toBe ( 200 ) ;
1241+ expect ( result . response ?. body ?. data ?. types ) . toContain ( 'object' ) ;
1242+ } ) ;
1243+
1244+ it ( 'GET /meta/objects should use ObjectQL registry when broker is missing' , async ( ) => {
1245+ const mockRegistry = {
1246+ getAllObjects : vi . fn ( ) . mockReturnValue ( [ { name : 'account' } ] ) ,
1247+ getObject : vi . fn ( ) ,
1248+ } ;
1249+ brokerlessKernel . context . getService = vi . fn ( ) . mockImplementation ( ( name : string ) => {
1250+ if ( name === 'objectql' ) return { registry : mockRegistry } ;
1251+ return null ;
1252+ } ) ;
1253+
1254+ const context = { request : { } } ;
1255+ const result = await brokerlessDispatcher . handleMetadata ( '/objects' , context , 'GET' ) ;
1256+ expect ( result . handled ) . toBe ( true ) ;
1257+ expect ( result . response ?. status ) . toBe ( 200 ) ;
1258+ expect ( mockRegistry . getAllObjects ) . toHaveBeenCalled ( ) ;
1259+ } ) ;
1260+
1261+ it ( 'GET /meta/objects/:name should use ObjectQL registry when broker is missing' , async ( ) => {
1262+ const mockRegistry = {
1263+ registry : {
1264+ getObject : vi . fn ( ) . mockReturnValue ( { name : 'account' , fields : { } } ) ,
1265+ } ,
1266+ } ;
1267+ brokerlessKernel . context . getService = vi . fn ( ) . mockImplementation ( ( name : string ) => {
1268+ if ( name === 'objectql' ) return mockRegistry ;
1269+ return null ;
1270+ } ) ;
1271+
1272+ const context = { request : { } } ;
1273+ const result = await brokerlessDispatcher . handleMetadata ( '/objects/account' , context , 'GET' ) ;
1274+ expect ( result . handled ) . toBe ( true ) ;
1275+ expect ( result . response ?. status ) . toBe ( 200 ) ;
1276+ expect ( mockRegistry . registry . getObject ) . toHaveBeenCalledWith ( 'account' ) ;
1277+ } ) ;
1278+
1279+ it ( 'GET /meta/:type/:name/published should return 404 when broker is missing and metadata service is unavailable' , async ( ) => {
1280+ const context = { request : { } } ;
1281+ const result = await brokerlessDispatcher . handleMetadata ( '/object/my_obj/published' , context , 'GET' ) ;
1282+ expect ( result . handled ) . toBe ( true ) ;
1283+ expect ( result . response ?. status ) . toBe ( 404 ) ;
1284+ } ) ;
1285+
1286+ it ( 'PUT /meta/:type/:name should return 501 when broker is missing and protocol is unavailable' , async ( ) => {
1287+ const context = { request : { } } ;
1288+ const body = { label : 'Test' } ;
1289+ const result = await brokerlessDispatcher . handleMetadata ( '/objects/my_obj' , context , 'PUT' , body ) ;
1290+ expect ( result . handled ) . toBe ( true ) ;
1291+ expect ( result . response ?. status ) . toBe ( 501 ) ;
1292+ } ) ;
1293+
1294+ it ( 'should use protocol service even when broker is missing' , async ( ) => {
1295+ const mockProtocolLocal = {
1296+ getMetaTypes : vi . fn ( ) . mockResolvedValue ( { types : [ 'custom_type' ] } ) ,
1297+ } ;
1298+ brokerlessKernel . context . getService = vi . fn ( ) . mockImplementation ( ( name : string ) => {
1299+ if ( name === 'protocol' ) return mockProtocolLocal ;
1300+ return null ;
1301+ } ) ;
1302+
1303+ const context = { request : { } } ;
1304+ const result = await brokerlessDispatcher . handleMetadata ( '/types' , context , 'GET' ) ;
1305+ expect ( result . handled ) . toBe ( true ) ;
1306+ expect ( result . response ?. status ) . toBe ( 200 ) ;
1307+ expect ( mockProtocolLocal . getMetaTypes ) . toHaveBeenCalled ( ) ;
1308+ expect ( result . response ?. body ?. data ?. types ) . toContain ( 'custom_type' ) ;
1309+ } ) ;
1310+ } ) ;
12111311} ) ;
0 commit comments