@@ -11,6 +11,9 @@ import {
1111 featureFlagPrefix ,
1212 isFeatureFlag ,
1313 isSecretReference ,
14+ isSnapshotReference ,
15+ parseSnapshotReference ,
16+ SnapshotReferenceValue ,
1417 GetSnapshotOptions ,
1518 ListConfigurationSettingsForSnapshotOptions ,
1619 GetSnapshotResponse ,
@@ -66,7 +69,7 @@ import { AIConfigurationTracingOptions } from "./requestTracing/aiConfigurationT
6669import { KeyFilter , LabelFilter , SettingWatcher , SettingSelector , PagedSettingsWatcher , WatchedSetting } from "./types.js" ;
6770import { ConfigurationClientManager } from "./configurationClientManager.js" ;
6871import { getFixedBackoffDuration , getExponentialBackoffDuration } from "./common/backoffUtils.js" ;
69- import { InvalidOperationError , ArgumentError , isFailoverableError , isInputError } from "./common/errors.js" ;
72+ import { InvalidOperationError , ArgumentError , isFailoverableError , isInputError , SnapshotReferenceError } from "./common/errors.js" ;
7073import { ErrorMessages } from "./common/errorMessages.js" ;
7174import { X_MS_DATE_HEADER } from "./afd/constants.js" ;
7275
@@ -92,6 +95,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
9295 #featureFlagTracing: FeatureFlagTracingOptions | undefined ;
9396 #fmVersion: string | undefined ;
9497 #aiConfigurationTracing: AIConfigurationTracingOptions | undefined ;
98+ #useSnapshotReference: boolean = false ;
9599
96100 // Refresh
97101 #refreshInProgress: boolean = false ;
@@ -229,7 +233,8 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
229233 featureFlagTracing : this . #featureFlagTracing,
230234 fmVersion : this . #fmVersion,
231235 aiConfigurationTracing : this . #aiConfigurationTracing,
232- isAfdUsed : this . #isAfdUsed
236+ isAfdUsed : this . #isAfdUsed,
237+ useSnapshotReference : this . #useSnapshotReference
233238 } ;
234239 }
235240
@@ -521,17 +526,29 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
521526 selector . pageWatchers = pageWatchers ;
522527 settings = items ;
523528 } else { // snapshot selector
524- const snapshot = await this . #getSnapshot( selector . snapshotName ) ;
525- if ( snapshot === undefined ) {
526- throw new InvalidOperationError ( `Could not find snapshot with name ${ selector . snapshotName } .` ) ;
527- }
528- if ( snapshot . compositionType != KnownSnapshotComposition . Key ) {
529- throw new InvalidOperationError ( `Composition type for the selected snapshot with name ${ selector . snapshotName } must be 'key'.` ) ;
530- }
531- settings = await this . #listConfigurationSettingsForSnapshot( selector . snapshotName ) ;
529+ settings = await this . #loadConfigurationSettingsFromSnapshot( selector . snapshotName ) ;
532530 }
533531
534532 for ( const setting of settings ) {
533+ if ( isSnapshotReference ( setting ) && ! loadFeatureFlag ) {
534+ this . #useSnapshotReference = true ;
535+
536+ const snapshotRef : ConfigurationSetting < SnapshotReferenceValue > = parseSnapshotReference ( setting ) ;
537+ const snapshotName = snapshotRef . value . snapshotName ;
538+ if ( ! snapshotName ) {
539+ throw new SnapshotReferenceError ( `Invalid format for Snapshot reference setting '${ setting . key } '.` ) ;
540+ }
541+ const settingsFromSnapshot = await this . #loadConfigurationSettingsFromSnapshot( snapshotName ) ;
542+
543+ for ( const snapshotSetting of settingsFromSnapshot ) {
544+ if ( ! isFeatureFlag ( snapshotSetting ) ) {
545+ // Feature flags inside snapshot are ignored. This is consistent the behavior that key value selectors ignore feature flags.
546+ loadedSettings . set ( snapshotSetting . key , snapshotSetting ) ;
547+ }
548+ }
549+ continue ;
550+ }
551+
535552 if ( loadFeatureFlag === isFeatureFlag ( setting ) ) {
536553 loadedSettings . set ( setting . key , setting ) ;
537554 }
@@ -592,6 +609,18 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
592609 }
593610 }
594611
612+ async #loadConfigurationSettingsFromSnapshot( snapshotName : string ) : Promise < ConfigurationSetting [ ] > {
613+ const snapshot = await this . #getSnapshot( snapshotName ) ;
614+ if ( snapshot === undefined ) {
615+ return [ ] ; // treat non-existing snapshot as empty
616+ }
617+ if ( snapshot . compositionType != KnownSnapshotComposition . Key ) {
618+ throw new InvalidOperationError ( `Composition type for the selected snapshot with name ${ snapshotName } must be 'key'.` ) ;
619+ }
620+ const settings : ConfigurationSetting [ ] = await this . #listConfigurationSettingsForSnapshot( snapshotName ) ;
621+ return settings ;
622+ }
623+
595624 /**
596625 * Clears all existing key-values in the local configuration except feature flags.
597626 */
0 commit comments