@@ -795,4 +795,295 @@ 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+ try {
993+ process . env . NODE_ENV = 'test' ;
994+
995+ registry . registerApi ( {
996+ id : 'test_api' ,
997+ name : 'Test API' ,
998+ type : 'rest' ,
999+ version : 'v1' ,
1000+ basePath : '/test' ,
1001+ endpoints : [ { id : 'e1' , path : '/test' , responses : [ ] } ] ,
1002+ } ) ;
1003+
1004+ expect ( registry . getStats ( ) . totalApis ) . toBe ( 1 ) ;
1005+
1006+ // Should work without force flag in non-production
1007+ registry . clear ( ) ;
1008+ expect ( registry . getStats ( ) . totalApis ) . toBe ( 0 ) ;
1009+ } finally {
1010+ process . env . NODE_ENV = originalEnv ;
1011+ }
1012+ } ) ;
1013+
1014+ it ( 'should prevent clear() in production without force flag' , ( ) => {
1015+ const originalEnv = process . env . NODE_ENV ;
1016+ try {
1017+ process . env . NODE_ENV = 'production' ;
1018+
1019+ registry . registerApi ( {
1020+ id : 'prod_api' ,
1021+ name : 'Production API' ,
1022+ type : 'rest' ,
1023+ version : 'v1' ,
1024+ basePath : '/prod' ,
1025+ endpoints : [ { id : 'e1' , path : '/prod' , responses : [ ] } ] ,
1026+ } ) ;
1027+
1028+ // Should throw error in production without force flag
1029+ expect ( ( ) => registry . clear ( ) ) . toThrow (
1030+ 'Cannot clear registry in production environment without force flag'
1031+ ) ;
1032+
1033+ // API should still exist
1034+ expect ( registry . getStats ( ) . totalApis ) . toBe ( 1 ) ;
1035+ } finally {
1036+ process . env . NODE_ENV = originalEnv ;
1037+ }
1038+ } ) ;
1039+
1040+ it ( 'should allow clear() in production with force flag' , ( ) => {
1041+ const originalEnv = process . env . NODE_ENV ;
1042+ try {
1043+ process . env . NODE_ENV = 'production' ;
1044+
1045+ registry . registerApi ( {
1046+ id : 'prod_api' ,
1047+ name : 'Production API' ,
1048+ type : 'rest' ,
1049+ version : 'v1' ,
1050+ basePath : '/prod' ,
1051+ endpoints : [ { id : 'e1' , path : '/prod' , responses : [ ] } ] ,
1052+ } ) ;
1053+
1054+ expect ( registry . getStats ( ) . totalApis ) . toBe ( 1 ) ;
1055+
1056+ // Should work with force flag
1057+ registry . clear ( { force : true } ) ;
1058+ expect ( registry . getStats ( ) . totalApis ) . toBe ( 0 ) ;
1059+
1060+ // Verify logger warned about forced clear
1061+ expect ( logger . warn ) . toHaveBeenCalledWith (
1062+ 'API registry forcefully cleared in production' ,
1063+ { force : true }
1064+ ) ;
1065+ } finally {
1066+ process . env . NODE_ENV = originalEnv ;
1067+ }
1068+ } ) ;
1069+
1070+ it ( 'should clear all indices when clear() is called' , ( ) => {
1071+ registry . registerApi ( {
1072+ id : 'api_1' ,
1073+ name : 'API 1' ,
1074+ type : 'rest' ,
1075+ version : 'v1' ,
1076+ basePath : '/api1' ,
1077+ endpoints : [ { id : 'e1' , path : '/api1' , responses : [ ] } ] ,
1078+ metadata : { status : 'active' , tags : [ 'test' ] } ,
1079+ } ) ;
1080+
1081+ registry . clear ( ) ;
1082+
1083+ // All lookups should return empty
1084+ expect ( registry . findApis ( { type : 'rest' } ) . total ) . toBe ( 0 ) ;
1085+ expect ( registry . findApis ( { status : 'active' } ) . total ) . toBe ( 0 ) ;
1086+ expect ( registry . findApis ( { tags : [ 'test' ] } ) . total ) . toBe ( 0 ) ;
1087+ } ) ;
1088+ } ) ;
7981089} ) ;
0 commit comments