@@ -536,3 +536,150 @@ describe('DiscoverySchema with services', () => {
536536 expect ( discovery . services [ 'ai' ] . enabled ) . toBe ( false ) ;
537537 } ) ;
538538} ) ;
539+
540+ // ==========================================
541+ // ServiceInfoSchema — version & rateLimit
542+ // ==========================================
543+
544+ describe ( 'ServiceInfoSchema (version field)' , ( ) => {
545+ it ( 'should accept a service with version' , ( ) => {
546+ const info = ServiceInfoSchema . parse ( {
547+ enabled : true ,
548+ status : 'available' ,
549+ route : '/api/v1/data' ,
550+ provider : 'objectql' ,
551+ version : '3.0.6' ,
552+ } ) ;
553+ expect ( info . version ) . toBe ( '3.0.6' ) ;
554+ } ) ;
555+
556+ it ( 'should allow version to be omitted' , ( ) => {
557+ const info = ServiceInfoSchema . parse ( {
558+ enabled : true ,
559+ status : 'available' ,
560+ } ) ;
561+ expect ( info . version ) . toBeUndefined ( ) ;
562+ } ) ;
563+ } ) ;
564+
565+ describe ( 'ServiceInfoSchema (rateLimit field)' , ( ) => {
566+ it ( 'should accept a service with rateLimit' , ( ) => {
567+ const info = ServiceInfoSchema . parse ( {
568+ enabled : true ,
569+ status : 'available' ,
570+ rateLimit : {
571+ requestsPerMinute : 60 ,
572+ requestsPerHour : 1000 ,
573+ burstLimit : 10 ,
574+ retryAfterMs : 5000 ,
575+ } ,
576+ } ) ;
577+ expect ( info . rateLimit ?. requestsPerMinute ) . toBe ( 60 ) ;
578+ expect ( info . rateLimit ?. burstLimit ) . toBe ( 10 ) ;
579+ } ) ;
580+
581+ it ( 'should allow rateLimit to be omitted' , ( ) => {
582+ const info = ServiceInfoSchema . parse ( {
583+ enabled : true ,
584+ status : 'available' ,
585+ } ) ;
586+ expect ( info . rateLimit ) . toBeUndefined ( ) ;
587+ } ) ;
588+
589+ it ( 'should allow partial rateLimit fields' , ( ) => {
590+ const info = ServiceInfoSchema . parse ( {
591+ enabled : true ,
592+ status : 'available' ,
593+ rateLimit : {
594+ requestsPerMinute : 100 ,
595+ } ,
596+ } ) ;
597+ expect ( info . rateLimit ?. requestsPerMinute ) . toBe ( 100 ) ;
598+ expect ( info . rateLimit ?. requestsPerHour ) . toBeUndefined ( ) ;
599+ } ) ;
600+ } ) ;
601+
602+ // ==========================================
603+ // DiscoverySchema — capabilities
604+ // ==========================================
605+
606+ describe ( 'DiscoverySchema (capabilities field)' , ( ) => {
607+ const fixture = {
608+ name : 'ObjectStack' ,
609+ version : '1.0.0' ,
610+ environment : 'production' as const ,
611+ routes : { data : '/api/v1/data' , metadata : '/api/v1/meta' } ,
612+ services : minimalServices ,
613+ locale : { default : 'en-US' , supported : [ 'en-US' ] , timezone : 'UTC' } ,
614+ } ;
615+
616+ it ( 'should accept discovery with capabilities' , ( ) => {
617+ const discovery = DiscoverySchema . parse ( {
618+ ...fixture ,
619+ capabilities : {
620+ comments : {
621+ enabled : true ,
622+ features : { threaded : true , reactions : true , mentions : true } ,
623+ description : 'Feed and comments support' ,
624+ } ,
625+ automation : {
626+ enabled : false ,
627+ description : 'Flow automation engine' ,
628+ } ,
629+ } ,
630+ } ) ;
631+ expect ( discovery . capabilities ?. comments . enabled ) . toBe ( true ) ;
632+ expect ( discovery . capabilities ?. comments . features ?. threaded ) . toBe ( true ) ;
633+ expect ( discovery . capabilities ?. automation . enabled ) . toBe ( false ) ;
634+ } ) ;
635+
636+ it ( 'should allow capabilities to be omitted' , ( ) => {
637+ const discovery = DiscoverySchema . parse ( fixture ) ;
638+ expect ( discovery . capabilities ) . toBeUndefined ( ) ;
639+ } ) ;
640+ } ) ;
641+
642+ // ==========================================
643+ // DiscoverySchema — schemaDiscovery
644+ // ==========================================
645+
646+ describe ( 'DiscoverySchema (schemaDiscovery field)' , ( ) => {
647+ const fixture = {
648+ name : 'ObjectStack' ,
649+ version : '1.0.0' ,
650+ environment : 'production' as const ,
651+ routes : { data : '/api/v1/data' , metadata : '/api/v1/meta' } ,
652+ services : minimalServices ,
653+ locale : { default : 'en-US' , supported : [ 'en-US' ] , timezone : 'UTC' } ,
654+ } ;
655+
656+ it ( 'should accept discovery with schemaDiscovery' , ( ) => {
657+ const discovery = DiscoverySchema . parse ( {
658+ ...fixture ,
659+ schemaDiscovery : {
660+ openapi : '/api/v1/openapi.json' ,
661+ graphql : '/graphql' ,
662+ jsonSchema : '/api/v1/schemas' ,
663+ } ,
664+ } ) ;
665+ expect ( discovery . schemaDiscovery ?. openapi ) . toBe ( '/api/v1/openapi.json' ) ;
666+ expect ( discovery . schemaDiscovery ?. graphql ) . toBe ( '/graphql' ) ;
667+ expect ( discovery . schemaDiscovery ?. jsonSchema ) . toBe ( '/api/v1/schemas' ) ;
668+ } ) ;
669+
670+ it ( 'should allow schemaDiscovery to be omitted' , ( ) => {
671+ const discovery = DiscoverySchema . parse ( fixture ) ;
672+ expect ( discovery . schemaDiscovery ) . toBeUndefined ( ) ;
673+ } ) ;
674+
675+ it ( 'should allow partial schemaDiscovery fields' , ( ) => {
676+ const discovery = DiscoverySchema . parse ( {
677+ ...fixture ,
678+ schemaDiscovery : {
679+ openapi : '/api/v1/openapi.json' ,
680+ } ,
681+ } ) ;
682+ expect ( discovery . schemaDiscovery ?. openapi ) . toBe ( '/api/v1/openapi.json' ) ;
683+ expect ( discovery . schemaDiscovery ?. graphql ) . toBeUndefined ( ) ;
684+ } ) ;
685+ } ) ;
0 commit comments