Skip to content

Add enhanced feature flag import support - #26

Open
Christine Wanjau (ChristineWanjau) wants to merge 9 commits into
mainfrom
feature/enhanced-feature-flags
Open

Christine Wanjau (ChristineWanjau) wants to merge 9 commits into
mainfrom
feature/enhanced-feature-flags

Conversation

@ChristineWanjau

@ChristineWanjau Christine Wanjau (ChristineWanjau) commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add FeatureFlagImporter using FeatureFlagClient from @azure/app-configuration 1.13.0-beta.1
  • add Default and appconfig/ffset serialized feature flag sources with root profile detection
  • support iterable and pre-calculated feature flag sources, strict deletion, import modes, progress, retries, timeouts, and correlation IDs
  • require profile: appconfig/kvset for KVSet documents and add FFSet validation and design documentation

cwanjau added 3 commits August 25, 2026 14:55
…pping, stream kvset guard

- Add ReadableStreamFeatureFlagSource and FileFeatureFlagSource specs with ffset/default fixtures
- Fix StringFeatureFlagSource.setFilterOptions to use FfSet (not dead KvSet branch) for wildcard filters
- Map MS FM allocation to camelCase in DefaultFeatureFlagsConverter
- Reject KvSet at construction in ReadableStreamFeatureFlagSource
@ChristineWanjau
Christine Wanjau (ChristineWanjau) marked this pull request as ready for review August 25, 2026 18:57
cwanjau added 3 commits August 25, 2026 21:58
Resolves eslint indent errors in readableStreamFeatureFlagSource and stringFeatureFlagSource.
Use sinon .rejects() and await the server-error import so a synchronous throw no longer escapes AdaptiveTaskManager and surfaces as an uncaught rejection in later tests (ERR_MOCHA_MULTIPLE_DONE).
* @param options - Import options including timeout, progress callback, strict mode, and import mode.
* @returns Promise<void>
*/
public async Import(featureFlagSource: FeatureFlagSource, options: FeatureFlagImportOptions): Promise<void> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public async Import(featureFlagSource: FeatureFlagSource, options: FeatureFlagImportOptions): Promise<void> {
public async Import(featureFlagsSource: FeatureFlagSource, options: FeatureFlagImportOptions): Promise<void> {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

*
* @returns Collection of FeatureFlagParam or FeatureFlagChange objects.
*/
GetFeatureFlags(): Promise<FeatureFlagParam[] | FeatureFlagChange[]>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the configuration setting path the name is SetConfigurationSettingParam. What is the reason for the different pattern here?

Comment on lines +32 to +35
/** @internal */
export function getSettingIdentity(nameOrKey: string, label?: string): string {
return `${nameOrKey}\u0000${label ?? ""}`;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should just be private helper in the respective importer. No need to generalize cross name and key.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Updated

Comment on lines +37 to +42
/** @internal */
export function validateImportMode(importMode: ImportMode): void {
if (importMode !== ImportMode.IgnoreMatch && importMode !== ImportMode.All) {
throw new ArgumentError("Only options supported for Import Mode are 'All' and 'Ignore-Match'.");
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in a helper named validation.ts

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added validation.ts

Comment on lines +44 to +70
/** @internal */
export function createAdaptiveTaskManager<TValue, TResult>(
task: (value: TValue) => Promise<TResult>,
values: TValue[]
): AdaptiveTaskManager<TResult> {
let index = 0;
return new AdaptiveTaskManager(() => {
if (index === values.length) {
return undefined;
}
const value = values[index++];
return () => task(value);
}, values.length);
}

/** @internal */
export async function executeTasksWithTimeout<T>(
taskManager: AdaptiveTaskManager<T>,
timeInSeconds: number,
callback?: (progress: ImportProgress) => unknown
): Promise<void> {
let timer: NodeJS.Timeout;
const timeoutPromise = new Promise((_, reject) => {
timer = setTimeout(() => reject(new OperationTimeoutError()), timeInSeconds * 1000);
});
await Promise.race([taskManager.Start(callback), timeoutPromise]).finally(() => clearTimeout(timer));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TaskManagement.ts

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added TaskManagement.ts

}

/** @internal */
export function isChangeArray<TChange>(value: unknown): value is TChange[] {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use Any instead? Looks like a type that exists somewhere when TChange is used.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Updated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants