@@ -9,10 +9,11 @@ import { IKeyValueAdapter } from "./IKeyValueAdapter.js";
99import { JsonKeyValueAdapter } from "./JsonKeyValueAdapter.js" ;
1010import { DEFAULT_REFRESH_INTERVAL_IN_MS , MIN_REFRESH_INTERVAL_IN_MS } from "./RefreshOptions.js" ;
1111import { Disposable } from "./common/disposable.js" ;
12- import { FEATURE_FLAGS_KEY_NAME , FEATURE_MANAGEMENT_KEY_NAME } from "./featureManagement/constants.js" ;
12+ import { FEATURE_FLAGS_KEY_NAME , FEATURE_MANAGEMENT_KEY_NAME , CONDITIONS_KEY_NAME , CLIENT_FILTERS_KEY_NAME , TELEMETRY_KEY_NAME , VARIANTS_KEY_NAME , ALLOCATION_KEY_NAME , SEED_KEY_NAME , NAME_KEY_NAME , ENABLED_KEY_NAME } from "./featureManagement/constants.js" ;
1313import { AzureKeyVaultKeyValueAdapter } from "./keyvault/AzureKeyVaultKeyValueAdapter.js" ;
1414import { RefreshTimer } from "./refresh/RefreshTimer.js" ;
1515import { getConfigurationSettingWithTrace , listConfigurationSettingsWithTrace , requestTracingEnabled } from "./requestTracing/utils.js" ;
16+ import { FeatureFlagTracingOptions } from "./requestTracing/FeatureFlagTracingOptions.js" ;
1617import { KeyFilter , LabelFilter , SettingSelector } from "./types.js" ;
1718
1819type PagedSettingSelector = SettingSelector & {
@@ -38,6 +39,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
3839 #client: AppConfigurationClient ;
3940 #options: AzureAppConfigurationOptions | undefined ;
4041 #isInitialLoadCompleted: boolean = false ;
42+ #featureFlagTracing: FeatureFlagTracingOptions | undefined ;
4143
4244 // Refresh
4345 #refreshInProgress: boolean = false ;
@@ -66,6 +68,9 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
6668
6769 // Enable request tracing if not opt-out
6870 this . #requestTracingEnabled = requestTracingEnabled ( ) ;
71+ if ( this . #requestTracingEnabled) {
72+ this . #featureFlagTracing = new FeatureFlagTracingOptions ( ) ;
73+ }
6974
7075 if ( options ?. trimKeyPrefixes ) {
7176 this . #sortedTrimKeyPrefixes = [ ...options . trimKeyPrefixes ] . sort ( ( a , b ) => b . localeCompare ( a ) ) ;
@@ -175,7 +180,8 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
175180 return {
176181 requestTracingEnabled : this . #requestTracingEnabled,
177182 initialLoadCompleted : this . #isInitialLoadCompleted,
178- appConfigOptions : this . #options
183+ appConfigOptions : this . #options,
184+ featureFlagTracingOptions : this . #featureFlagTracing
179185 } ;
180186 }
181187
@@ -257,8 +263,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
257263 }
258264
259265 async #loadFeatureFlags( ) {
260- // Temporary map to store feature flags, key is the key of the setting, value is the raw value of the setting
261- const featureFlagsMap = new Map < string , any > ( ) ;
266+ const featureFlagSettings : ConfigurationSetting [ ] = [ ] ;
262267 for ( const selector of this . #featureFlagSelectors) {
263268 const listOptions : ListConfigurationSettingsOptions = {
264269 keyFilter : `${ featureFlagPrefix } ${ selector . keyFilter } ` ,
@@ -275,15 +280,21 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
275280 pageEtags . push ( page . etag ?? "" ) ;
276281 for ( const setting of page . items ) {
277282 if ( isFeatureFlag ( setting ) ) {
278- featureFlagsMap . set ( setting . key , setting . value ) ;
283+ featureFlagSettings . push ( setting ) ;
279284 }
280285 }
281286 }
282287 selector . pageEtags = pageEtags ;
283288 }
284289
290+ if ( this . #requestTracingEnabled && this . #featureFlagTracing !== undefined ) {
291+ this . #featureFlagTracing. resetFeatureFlagTracing ( ) ;
292+ }
293+
285294 // parse feature flags
286- const featureFlags = Array . from ( featureFlagsMap . values ( ) ) . map ( rawFlag => JSON . parse ( rawFlag ) ) ;
295+ const featureFlags = await Promise . all (
296+ featureFlagSettings . map ( setting => this . #parseFeatureFlag( setting ) )
297+ ) ;
287298
288299 // feature_management is a reserved key, and feature_flags is an array of feature flags
289300 this . #configMap. set ( FEATURE_MANAGEMENT_KEY_NAME , { [ FEATURE_FLAGS_KEY_NAME ] : featureFlags } ) ;
@@ -546,6 +557,33 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
546557 }
547558 return response ;
548559 }
560+
561+ async #parseFeatureFlag( setting : ConfigurationSetting < string > ) : Promise < any > {
562+ const rawFlag = setting . value ;
563+ if ( rawFlag === undefined ) {
564+ throw new Error ( "The value of configuration setting cannot be undefined." ) ;
565+ }
566+ const featureFlag = JSON . parse ( rawFlag ) ;
567+ if ( this . #requestTracingEnabled && this . #featureFlagTracing !== undefined ) {
568+ if ( featureFlag [ CONDITIONS_KEY_NAME ] &&
569+ featureFlag [ CONDITIONS_KEY_NAME ] [ CLIENT_FILTERS_KEY_NAME ] &&
570+ Array . isArray ( featureFlag [ CONDITIONS_KEY_NAME ] [ CLIENT_FILTERS_KEY_NAME ] ) ) {
571+ for ( const filter of featureFlag [ CONDITIONS_KEY_NAME ] [ CLIENT_FILTERS_KEY_NAME ] ) {
572+ this . #featureFlagTracing. updateFeatureFilterTracing ( filter [ NAME_KEY_NAME ] ) ;
573+ }
574+ }
575+ if ( featureFlag [ VARIANTS_KEY_NAME ] && Array . isArray ( featureFlag [ VARIANTS_KEY_NAME ] ) ) {
576+ this . #featureFlagTracing. notifyMaxVariants ( featureFlag [ VARIANTS_KEY_NAME ] . length ) ;
577+ }
578+ if ( featureFlag [ TELEMETRY_KEY_NAME ] && featureFlag [ TELEMETRY_KEY_NAME ] [ ENABLED_KEY_NAME ] ) {
579+ this . #featureFlagTracing. usesTelemetry = true ;
580+ }
581+ if ( featureFlag [ ALLOCATION_KEY_NAME ] && featureFlag [ ALLOCATION_KEY_NAME ] [ SEED_KEY_NAME ] ) {
582+ this . #featureFlagTracing. usesSeed = true ;
583+ }
584+ }
585+ return featureFlag ;
586+ }
549587}
550588
551589function getValidSelectors ( selectors : SettingSelector [ ] ) : SettingSelector [ ] {
0 commit comments