@@ -479,10 +479,12 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
479479 * If true, loads feature flag using the feature flag selectors;
480480 * If false, loads key-value using the key-value selectors. Defaults to false.
481481 */
482- async #loadConfigurationSettings( loadFeatureFlag : boolean = false ) : Promise < ConfigurationSetting [ ] > {
482+ async #loadConfigurationSettings( loadFeatureFlag : boolean = false ) : Promise < Map < string , ConfigurationSetting > > {
483483 const selectors = loadFeatureFlag ? this . #ffSelectors : this . #kvSelectors;
484484 const funcToExecute = async ( client ) => {
485- const loadedSettings : ConfigurationSetting [ ] = [ ] ;
485+ // Use a Map to deduplicate configuration settings by key. When multiple selectors return settings with the same key,
486+ // the configuration setting loaded by the later selector in the iteration order will override the one from the earlier selector.
487+ const loadedSettings : Map < string , ConfigurationSetting > = new Map < string , ConfigurationSetting > ( ) ;
486488 // deep copy selectors to avoid modification if current client fails
487489 const selectorsToUpdate = JSON . parse (
488490 JSON . stringify ( selectors )
@@ -506,7 +508,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
506508 pageEtags . push ( page . etag ?? "" ) ;
507509 for ( const setting of page . items ) {
508510 if ( loadFeatureFlag === isFeatureFlag ( setting ) ) {
509- loadedSettings . push ( setting ) ;
511+ loadedSettings . set ( setting . key , setting ) ;
510512 }
511513 }
512514 }
@@ -528,7 +530,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
528530 for await ( const page of pageIterator ) {
529531 for ( const setting of page . items ) {
530532 if ( loadFeatureFlag === isFeatureFlag ( setting ) ) {
531- loadedSettings . push ( setting ) ;
533+ loadedSettings . set ( setting . key , setting ) ;
532534 }
533535 }
534536 }
@@ -543,7 +545,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
543545 return loadedSettings ;
544546 } ;
545547
546- return await this . #executeWithFailoverPolicy( funcToExecute ) as ConfigurationSetting [ ] ;
548+ return await this . #executeWithFailoverPolicy( funcToExecute ) as Map < string , ConfigurationSetting > ;
547549 }
548550
549551 /**
@@ -552,7 +554,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
552554 async #loadSelectedAndWatchedKeyValues( ) {
553555 this . #secretReferences = [ ] ; // clear all cached key vault reference configuration settings
554556 const keyValues : [ key : string , value : unknown ] [ ] = [ ] ;
555- const loadedSettings : ConfigurationSetting [ ] = await this . #loadConfigurationSettings( ) ;
557+ const loadedSettings : Map < string , ConfigurationSetting > = await this . #loadConfigurationSettings( ) ;
556558 if ( this . #refreshEnabled && ! this . #watchAll) {
557559 await this . #updateWatchedKeyValuesEtag( loadedSettings ) ;
558560 }
@@ -562,7 +564,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
562564 this . #aiConfigurationTracing. reset ( ) ;
563565 }
564566
565- for ( const setting of loadedSettings ) {
567+ for ( const setting of loadedSettings . values ( ) ) {
566568 if ( isSecretReference ( setting ) ) {
567569 this . #secretReferences. push ( setting ) ; // cache secret references for resolve/refresh secret separately
568570 continue ;
@@ -587,9 +589,10 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
587589 /**
588590 * Updates etag of watched settings from loaded data. If a watched setting is not covered by any selector, a request will be sent to retrieve it.
589591 */
590- async #updateWatchedKeyValuesEtag( existingSettings : ConfigurationSetting [ ] ) : Promise < void > {
592+ async #updateWatchedKeyValuesEtag( existingSettings : Map < string , ConfigurationSetting > ) : Promise < void > {
591593 for ( const sentinel of this . #sentinels) {
592- const matchedSetting = existingSettings . find ( s => s . key === sentinel . key && s . label === sentinel . label ) ;
594+ // try to find matching setting by key and label from the map's values
595+ const matchedSetting = Array . from ( existingSettings . values ( ) ) . find ( s => s . key === sentinel . key && s . label === sentinel . label ) ;
593596 if ( matchedSetting ) {
594597 sentinel . etag = matchedSetting . etag ;
595598 } else {
@@ -621,7 +624,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
621624 */
622625 async #loadFeatureFlags( ) {
623626 const loadFeatureFlag = true ;
624- const featureFlagSettings : ConfigurationSetting [ ] = await this . #loadConfigurationSettings( loadFeatureFlag ) ;
627+ const featureFlagSettings : Map < string , ConfigurationSetting > = await this . #loadConfigurationSettings( loadFeatureFlag ) ;
625628
626629 if ( this . #requestTracingEnabled && this . #featureFlagTracing !== undefined ) {
627630 // Reset old feature flag tracing in order to track the information present in the current response from server.
@@ -630,7 +633,8 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
630633
631634 // parse feature flags
632635 const featureFlags = await Promise . all (
633- featureFlagSettings . map ( setting => this . #parseFeatureFlag( setting ) )
636+ featureFlagSettings . values ( )
637+ . map ( setting => this . #parseFeatureFlag( setting ) )
634638 ) ;
635639
636640 // feature_management is a reserved key, and feature_flags is an array of feature flags
0 commit comments