@@ -795,4 +795,289 @@ describe('ApiRegistry', () => {
795795 expect ( result . total ) . toBe ( 1 ) ;
796796 } ) ;
797797 } ) ;
798+
799+ describe ( 'Performance Optimizations' , ( ) => {
800+ it ( 'should use indices for fast type-based lookups' , ( ) => {
801+ // Register multiple APIs with different types
802+ registry . registerApi ( {
803+ id : 'rest_api_1' ,
804+ name : 'REST API 1' ,
805+ type : 'rest' ,
806+ version : 'v1' ,
807+ basePath : '/api/rest1' ,
808+ endpoints : [ { id : 'e1' , path : '/api/rest1' , responses : [ ] } ] ,
809+ } ) ;
810+
811+ registry . registerApi ( {
812+ id : 'rest_api_2' ,
813+ name : 'REST API 2' ,
814+ type : 'rest' ,
815+ version : 'v1' ,
816+ basePath : '/api/rest2' ,
817+ endpoints : [ { id : 'e2' , path : '/api/rest2' , responses : [ ] } ] ,
818+ } ) ;
819+
820+ registry . registerApi ( {
821+ id : 'graphql_api' ,
822+ name : 'GraphQL API' ,
823+ type : 'graphql' ,
824+ version : 'v1' ,
825+ basePath : '/graphql' ,
826+ endpoints : [ { id : 'e3' , path : '/graphql' , responses : [ ] } ] ,
827+ } ) ;
828+
829+ // Should efficiently find all REST APIs
830+ const restApis = registry . findApis ( { type : 'rest' } ) ;
831+ expect ( restApis . total ) . toBe ( 2 ) ;
832+ expect ( restApis . apis . every ( api => api . type === 'rest' ) ) . toBe ( true ) ;
833+
834+ // Should efficiently find GraphQL APIs
835+ const graphqlApis = registry . findApis ( { type : 'graphql' } ) ;
836+ expect ( graphqlApis . total ) . toBe ( 1 ) ;
837+ expect ( graphqlApis . apis [ 0 ] . id ) . toBe ( 'graphql_api' ) ;
838+ } ) ;
839+
840+ it ( 'should use indices for fast tag-based lookups' , ( ) => {
841+ registry . registerApi ( {
842+ id : 'api_1' ,
843+ name : 'API 1' ,
844+ type : 'rest' ,
845+ version : 'v1' ,
846+ basePath : '/api1' ,
847+ endpoints : [ { id : 'e1' , path : '/api1' , responses : [ ] } ] ,
848+ metadata : { tags : [ 'customer' , 'crm' ] } ,
849+ } ) ;
850+
851+ registry . registerApi ( {
852+ id : 'api_2' ,
853+ name : 'API 2' ,
854+ type : 'rest' ,
855+ version : 'v1' ,
856+ basePath : '/api2' ,
857+ endpoints : [ { id : 'e2' , path : '/api2' , responses : [ ] } ] ,
858+ metadata : { tags : [ 'order' , 'sales' ] } ,
859+ } ) ;
860+
861+ registry . registerApi ( {
862+ id : 'api_3' ,
863+ name : 'API 3' ,
864+ type : 'rest' ,
865+ version : 'v1' ,
866+ basePath : '/api3' ,
867+ endpoints : [ { id : 'e3' , path : '/api3' , responses : [ ] } ] ,
868+ metadata : { tags : [ 'customer' , 'analytics' ] } ,
869+ } ) ;
870+
871+ // Should efficiently find APIs by tag
872+ const customerApis = registry . findApis ( { tags : [ 'customer' ] } ) ;
873+ expect ( customerApis . total ) . toBe ( 2 ) ;
874+ expect ( customerApis . apis . map ( a => a . id ) . sort ( ) ) . toEqual ( [ 'api_1' , 'api_3' ] ) ;
875+
876+ // Should support multiple tags (ANY match)
877+ const multiTagApis = registry . findApis ( { tags : [ 'crm' , 'sales' ] } ) ;
878+ expect ( multiTagApis . total ) . toBe ( 2 ) ;
879+ } ) ;
880+
881+ it ( 'should use indices for fast status-based lookups' , ( ) => {
882+ registry . registerApi ( {
883+ id : 'active_api' ,
884+ name : 'Active API' ,
885+ type : 'rest' ,
886+ version : 'v1' ,
887+ basePath : '/active' ,
888+ endpoints : [ { id : 'e1' , path : '/active' , responses : [ ] } ] ,
889+ metadata : { status : 'active' } ,
890+ } ) ;
891+
892+ registry . registerApi ( {
893+ id : 'beta_api' ,
894+ name : 'Beta API' ,
895+ type : 'rest' ,
896+ version : 'v1' ,
897+ basePath : '/beta' ,
898+ endpoints : [ { id : 'e2' , path : '/beta' , responses : [ ] } ] ,
899+ metadata : { status : 'beta' } ,
900+ } ) ;
901+
902+ registry . registerApi ( {
903+ id : 'deprecated_api' ,
904+ name : 'Deprecated API' ,
905+ type : 'rest' ,
906+ version : 'v1' ,
907+ basePath : '/deprecated' ,
908+ endpoints : [ { id : 'e3' , path : '/deprecated' , responses : [ ] } ] ,
909+ metadata : { status : 'deprecated' } ,
910+ } ) ;
911+
912+ // Should efficiently find by status
913+ const activeApis = registry . findApis ( { status : 'active' } ) ;
914+ expect ( activeApis . total ) . toBe ( 1 ) ;
915+ expect ( activeApis . apis [ 0 ] . id ) . toBe ( 'active_api' ) ;
916+
917+ const betaApis = registry . findApis ( { status : 'beta' } ) ;
918+ expect ( betaApis . total ) . toBe ( 1 ) ;
919+ } ) ;
920+
921+ it ( 'should combine multiple indexed filters efficiently' , ( ) => {
922+ registry . registerApi ( {
923+ id : 'rest_crm_active' ,
924+ name : 'REST CRM Active' ,
925+ type : 'rest' ,
926+ version : 'v1' ,
927+ basePath : '/crm' ,
928+ endpoints : [ { id : 'e1' , path : '/crm' , responses : [ ] } ] ,
929+ metadata : { status : 'active' , tags : [ 'crm' , 'customer' ] } ,
930+ } ) ;
931+
932+ registry . registerApi ( {
933+ id : 'rest_crm_beta' ,
934+ name : 'REST CRM Beta' ,
935+ type : 'rest' ,
936+ version : 'v1' ,
937+ basePath : '/crm-beta' ,
938+ endpoints : [ { id : 'e2' , path : '/crm-beta' , responses : [ ] } ] ,
939+ metadata : { status : 'beta' , tags : [ 'crm' ] } ,
940+ } ) ;
941+
942+ registry . registerApi ( {
943+ id : 'graphql_crm_active' ,
944+ name : 'GraphQL CRM Active' ,
945+ type : 'graphql' ,
946+ version : 'v1' ,
947+ basePath : '/graphql' ,
948+ endpoints : [ { id : 'e3' , path : '/graphql' , responses : [ ] } ] ,
949+ metadata : { status : 'active' , tags : [ 'crm' ] } ,
950+ } ) ;
951+
952+ // Combine type + status + tags filters
953+ const result = registry . findApis ( {
954+ type : 'rest' ,
955+ status : 'active' ,
956+ tags : [ 'crm' ] ,
957+ } ) ;
958+
959+ expect ( result . total ) . toBe ( 1 ) ;
960+ expect ( result . apis [ 0 ] . id ) . toBe ( 'rest_crm_active' ) ;
961+ } ) ;
962+
963+ it ( 'should maintain indices when APIs are unregistered' , ( ) => {
964+ registry . registerApi ( {
965+ id : 'temp_api' ,
966+ name : 'Temporary API' ,
967+ type : 'rest' ,
968+ version : 'v1' ,
969+ basePath : '/temp' ,
970+ endpoints : [ { id : 'e1' , path : '/temp' , responses : [ ] } ] ,
971+ metadata : { status : 'beta' , tags : [ 'temp' , 'test' ] } ,
972+ } ) ;
973+
974+ // Verify it's in indices
975+ expect ( registry . findApis ( { type : 'rest' } ) . total ) . toBe ( 1 ) ;
976+ expect ( registry . findApis ( { status : 'beta' } ) . total ) . toBe ( 1 ) ;
977+ expect ( registry . findApis ( { tags : [ 'temp' ] } ) . total ) . toBe ( 1 ) ;
978+
979+ // Unregister
980+ registry . unregisterApi ( 'temp_api' ) ;
981+
982+ // Verify removed from indices
983+ expect ( registry . findApis ( { type : 'rest' } ) . total ) . toBe ( 0 ) ;
984+ expect ( registry . findApis ( { status : 'beta' } ) . total ) . toBe ( 0 ) ;
985+ expect ( registry . findApis ( { tags : [ 'temp' ] } ) . total ) . toBe ( 0 ) ;
986+ } ) ;
987+ } ) ;
988+
989+ describe ( 'Safety Guards' , ( ) => {
990+ it ( 'should allow clear() in non-production environment' , ( ) => {
991+ const originalEnv = process . env . NODE_ENV ;
992+ process . env . NODE_ENV = 'test' ;
993+
994+ registry . registerApi ( {
995+ id : 'test_api' ,
996+ name : 'Test API' ,
997+ type : 'rest' ,
998+ version : 'v1' ,
999+ basePath : '/test' ,
1000+ endpoints : [ { id : 'e1' , path : '/test' , responses : [ ] } ] ,
1001+ } ) ;
1002+
1003+ expect ( registry . getStats ( ) . totalApis ) . toBe ( 1 ) ;
1004+
1005+ // Should work without force flag in non-production
1006+ registry . clear ( ) ;
1007+ expect ( registry . getStats ( ) . totalApis ) . toBe ( 0 ) ;
1008+
1009+ process . env . NODE_ENV = originalEnv ;
1010+ } ) ;
1011+
1012+ it ( 'should prevent clear() in production without force flag' , ( ) => {
1013+ const originalEnv = process . env . NODE_ENV ;
1014+ process . env . NODE_ENV = 'production' ;
1015+
1016+ registry . registerApi ( {
1017+ id : 'prod_api' ,
1018+ name : 'Production API' ,
1019+ type : 'rest' ,
1020+ version : 'v1' ,
1021+ basePath : '/prod' ,
1022+ endpoints : [ { id : 'e1' , path : '/prod' , responses : [ ] } ] ,
1023+ } ) ;
1024+
1025+ // Should throw error in production without force flag
1026+ expect ( ( ) => registry . clear ( ) ) . toThrow (
1027+ 'Cannot clear registry in production environment without force flag'
1028+ ) ;
1029+
1030+ // API should still exist
1031+ expect ( registry . getStats ( ) . totalApis ) . toBe ( 1 ) ;
1032+
1033+ process . env . NODE_ENV = originalEnv ;
1034+ } ) ;
1035+
1036+ it ( 'should allow clear() in production with force flag' , ( ) => {
1037+ const originalEnv = process . env . NODE_ENV ;
1038+ process . env . NODE_ENV = 'production' ;
1039+
1040+ registry . registerApi ( {
1041+ id : 'prod_api' ,
1042+ name : 'Production API' ,
1043+ type : 'rest' ,
1044+ version : 'v1' ,
1045+ basePath : '/prod' ,
1046+ endpoints : [ { id : 'e1' , path : '/prod' , responses : [ ] } ] ,
1047+ } ) ;
1048+
1049+ expect ( registry . getStats ( ) . totalApis ) . toBe ( 1 ) ;
1050+
1051+ // Should work with force flag
1052+ registry . clear ( { force : true } ) ;
1053+ expect ( registry . getStats ( ) . totalApis ) . toBe ( 0 ) ;
1054+
1055+ // Verify logger warned about forced clear
1056+ expect ( logger . warn ) . toHaveBeenCalledWith (
1057+ 'API registry forcefully cleared in production' ,
1058+ { force : true }
1059+ ) ;
1060+
1061+ process . env . NODE_ENV = originalEnv ;
1062+ } ) ;
1063+
1064+ it ( 'should clear all indices when clear() is called' , ( ) => {
1065+ registry . registerApi ( {
1066+ id : 'api_1' ,
1067+ name : 'API 1' ,
1068+ type : 'rest' ,
1069+ version : 'v1' ,
1070+ basePath : '/api1' ,
1071+ endpoints : [ { id : 'e1' , path : '/api1' , responses : [ ] } ] ,
1072+ metadata : { status : 'active' , tags : [ 'test' ] } ,
1073+ } ) ;
1074+
1075+ registry . clear ( ) ;
1076+
1077+ // All lookups should return empty
1078+ expect ( registry . findApis ( { type : 'rest' } ) . total ) . toBe ( 0 ) ;
1079+ expect ( registry . findApis ( { status : 'active' } ) . total ) . toBe ( 0 ) ;
1080+ expect ( registry . findApis ( { tags : [ 'test' ] } ) . total ) . toBe ( 0 ) ;
1081+ } ) ;
1082+ } ) ;
7981083} ) ;
0 commit comments