From f555ad48573d5c8ea9cac4f269fb2822705fb5ba Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Thu, 2 Oct 2025 23:51:39 +0800 Subject: [PATCH 1/2] fix feature flag model --- sdk/appconfiguration/app-configuration/assets.json | 2 +- .../review/app-configuration-node.api.md | 3 ++- .../app-configuration/src/featureFlag.ts | 12 +++++++++++- .../app-configuration/src/internal/jsonModels.ts | 3 ++- .../test/public/featureFlag.spec.ts | 4 +++- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/sdk/appconfiguration/app-configuration/assets.json b/sdk/appconfiguration/app-configuration/assets.json index f1c3e2cc87aa..b1a64e39df00 100644 --- a/sdk/appconfiguration/app-configuration/assets.json +++ b/sdk/appconfiguration/app-configuration/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "js", "TagPrefix": "js/appconfiguration/app-configuration", - "Tag": "js/appconfiguration/app-configuration_bdaf29d71a" + "Tag": "js/appconfiguration/app-configuration_48f15db7c6" } diff --git a/sdk/appconfiguration/app-configuration/review/app-configuration-node.api.md b/sdk/appconfiguration/app-configuration/review/app-configuration-node.api.md index 1117a9201e28..2f13e09e7346 100644 --- a/sdk/appconfiguration/app-configuration/review/app-configuration-node.api.md +++ b/sdk/appconfiguration/app-configuration/review/app-configuration-node.api.md @@ -141,11 +141,12 @@ export interface FeatureFlagValue { name: string; parameters?: Record; }[]; + requirementType?: "All" | "Any"; }; description?: string; displayName?: string; enabled: boolean; - id?: string; + id: string; } // @public diff --git a/sdk/appconfiguration/app-configuration/src/featureFlag.ts b/sdk/appconfiguration/app-configuration/src/featureFlag.ts index f51c62588ab2..29752fe98770 100644 --- a/sdk/appconfiguration/app-configuration/src/featureFlag.ts +++ b/sdk/appconfiguration/app-configuration/src/featureFlag.ts @@ -22,7 +22,7 @@ export interface FeatureFlagValue { /** * Id for the feature flag. */ - id?: string; + id: string; /** * A Feature filter consistently evaluates the state of a feature flag. * Our feature management library supports three types of built-in filters: Targeting, TimeWindow, and Percentage. @@ -32,6 +32,7 @@ export interface FeatureFlagValue { */ conditions: { clientFilters: { name: string; parameters?: Record }[]; + requirementType?: "All" | "Any"; }; /** * Description of the feature. @@ -76,6 +77,11 @@ export const FeatureFlagHelper = { display_name: featureFlag.value.displayName, }; + if (featureFlag.value.conditions.requirementType) { + jsonFeatureFlagValue.conditions.requirement_type = + featureFlag.value.conditions.requirementType; + } + const configSetting = { ...featureFlag, key, @@ -117,6 +123,10 @@ export function parseFeatureFlag( key, contentType: featureFlagContentType, }; + + if (jsonFeatureFlagValue.conditions.requirement_type) { + featureflag.value.conditions.requirementType = jsonFeatureFlagValue.conditions.requirement_type; + } return featureflag; } diff --git a/sdk/appconfiguration/app-configuration/src/internal/jsonModels.ts b/sdk/appconfiguration/app-configuration/src/internal/jsonModels.ts index 99d6e87bfe72..01cb02652e45 100644 --- a/sdk/appconfiguration/app-configuration/src/internal/jsonModels.ts +++ b/sdk/appconfiguration/app-configuration/src/internal/jsonModels.ts @@ -7,10 +7,11 @@ export type JsonFeatureFlagValue = { conditions: { client_filters: { name: string; parameters?: Record }[]; + requirement_type?: "All" | "Any"; }; description?: string; enabled: boolean; - id?: string; + id: string; display_name?: string; }; diff --git a/sdk/appconfiguration/app-configuration/test/public/featureFlag.spec.ts b/sdk/appconfiguration/app-configuration/test/public/featureFlag.spec.ts index aa3ce5346623..bc6905159c5a 100644 --- a/sdk/appconfiguration/app-configuration/test/public/featureFlag.spec.ts +++ b/sdk/appconfiguration/app-configuration/test/public/featureFlag.spec.ts @@ -26,6 +26,7 @@ describe("AppConfigurationClient - FeatureFlag", () => { baseSetting = { value: { conditions: { + requirementType: "Any", clientFilters: [ { name: "Microsoft.TimeWindow", @@ -51,6 +52,7 @@ describe("AppConfigurationClient - FeatureFlag", () => { { name: "Microsoft.Percentage", parameters: { Value: 25 } }, ], }, + id: "name-1", enabled: false, description: "I'm a description", displayName: "for display", @@ -202,7 +204,7 @@ describe("AppConfigurationClient - FeatureFlag", () => { `name-1${Math.floor(Math.random() * 1000)}`, )}`, isReadOnly: false, - value: { conditions: { clientFilters: [] }, enabled: true }, + value: { conditions: { clientFilters: [] }, id: "name-1", enabled: true }, }; }); From 84b2fd66c17840bd4167529667911e63b6861458 Mon Sep 17 00:00:00 2001 From: Zhiyuan Liang Date: Fri, 3 Oct 2025 00:09:33 +0800 Subject: [PATCH 2/2] update sample --- .../samples-dev/featureFlag.ts | 1 + .../samples/v1-beta/javascript/featureFlag.js | 9 +++++---- .../v1-beta/typescript/src/featureFlag.ts | 11 ++++++----- .../samples/v1/javascript/featureFlag.js | 1 + .../samples/v1/typescript/src/featureFlag.ts | 18 ++++++++++++------ 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/sdk/appconfiguration/app-configuration/samples-dev/featureFlag.ts b/sdk/appconfiguration/app-configuration/samples-dev/featureFlag.ts index f22e6d8d5c54..f1c7d5ca41e3 100644 --- a/sdk/appconfiguration/app-configuration/samples-dev/featureFlag.ts +++ b/sdk/appconfiguration/app-configuration/samples-dev/featureFlag.ts @@ -36,6 +36,7 @@ export async function main() { isReadOnly: false, contentType: featureFlagContentType, value: { + id: featureFlagName, enabled: false, description: "I'm a description", conditions: { diff --git a/sdk/appconfiguration/app-configuration/samples/v1-beta/javascript/featureFlag.js b/sdk/appconfiguration/app-configuration/samples/v1-beta/javascript/featureFlag.js index 1e75a34ca9c6..3f11eecdd860 100644 --- a/sdk/appconfiguration/app-configuration/samples/v1-beta/javascript/featureFlag.js +++ b/sdk/appconfiguration/app-configuration/samples/v1-beta/javascript/featureFlag.js @@ -21,6 +21,7 @@ async function main() { isReadOnly: false, contentType: featureFlagContentType, value: { + id: "sample-feature-flag", enabled: false, description: "I'm a description", conditions: { @@ -79,8 +80,8 @@ async function main() { `\n...clientFilter - "${clientFilter.name}"...\nparams => ${JSON.stringify( clientFilter.parameters, null, - 1 - )}\n` + 1, + )}\n`, ); switch (clientFilter.name) { // Tweak the client filters of the feature flag @@ -126,8 +127,8 @@ async function main() { `\n...clientFilter - "${clientFilter.name}"...\nparams => ${JSON.stringify( clientFilter.parameters, null, - 1 - )}\n` + 1, + )}\n`, ); } await cleanupSampleValues([originalFeatureFlag.key], appConfigClient); diff --git a/sdk/appconfiguration/app-configuration/samples/v1-beta/typescript/src/featureFlag.ts b/sdk/appconfiguration/app-configuration/samples/v1-beta/typescript/src/featureFlag.ts index 6b0d39553be8..feddb23535b1 100644 --- a/sdk/appconfiguration/app-configuration/samples/v1-beta/typescript/src/featureFlag.ts +++ b/sdk/appconfiguration/app-configuration/samples/v1-beta/typescript/src/featureFlag.ts @@ -24,6 +24,7 @@ export async function main() { isReadOnly: false, contentType: featureFlagContentType, value: { + id: "sample-feature-flag", enabled: false, description: "I'm a description", conditions: { @@ -82,8 +83,8 @@ export async function main() { `\n...clientFilter - "${clientFilter.name}"...\nparams => ${JSON.stringify( clientFilter.parameters, null, - 1 - )}\n` + 1, + )}\n`, ); switch (clientFilter.name) { // Tweak the client filters of the feature flag @@ -129,8 +130,8 @@ export async function main() { `\n...clientFilter - "${clientFilter.name}"...\nparams => ${JSON.stringify( clientFilter.parameters, null, - 1 - )}\n` + 1, + )}\n`, ); } await cleanupSampleValues([originalFeatureFlag.key], appConfigClient); @@ -172,7 +173,7 @@ function isTargetingClientFilter(clientFilter: any): clientFilter is { * typeguard - for timewindow client filter */ export function isTimeWindowClientFilter( - clientFilter: any + clientFilter: any, ): clientFilter is { parameters: { Start: string; End: string } } { return ( clientFilter.name === "Microsoft.TimeWindow" && diff --git a/sdk/appconfiguration/app-configuration/samples/v1/javascript/featureFlag.js b/sdk/appconfiguration/app-configuration/samples/v1/javascript/featureFlag.js index 1d2e415814bc..1db95e4644c5 100644 --- a/sdk/appconfiguration/app-configuration/samples/v1/javascript/featureFlag.js +++ b/sdk/appconfiguration/app-configuration/samples/v1/javascript/featureFlag.js @@ -24,6 +24,7 @@ async function main() { isReadOnly: false, contentType: featureFlagContentType, value: { + id: featureFlagName, enabled: false, description: "I'm a description", conditions: { diff --git a/sdk/appconfiguration/app-configuration/samples/v1/typescript/src/featureFlag.ts b/sdk/appconfiguration/app-configuration/samples/v1/typescript/src/featureFlag.ts index 686c4a66a41c..7d8bdfff9006 100644 --- a/sdk/appconfiguration/app-configuration/samples/v1/typescript/src/featureFlag.ts +++ b/sdk/appconfiguration/app-configuration/samples/v1/typescript/src/featureFlag.ts @@ -9,13 +9,17 @@ import { ConfigurationSetting, featureFlagContentType, featureFlagPrefix, - FeatureFlagValue + FeatureFlagValue, } from "@azure/app-configuration"; import { DefaultAzureCredential } from "@azure/identity"; // Use configuration provider and feature management library to consume feature flags import { load } from "@azure/app-configuration-provider"; -import { ConfigurationMapFeatureFlagProvider, FeatureManager, ITargetingContext } from "@microsoft/feature-management"; +import { + ConfigurationMapFeatureFlagProvider, + FeatureManager, + ITargetingContext, +} from "@microsoft/feature-management"; // Load the .env file if it exists import * as dotenv from "dotenv"; @@ -30,6 +34,7 @@ export async function main() { isReadOnly: false, contentType: featureFlagContentType, value: { + id: featureFlagName, enabled: false, description: "I'm a description", conditions: { @@ -77,13 +82,14 @@ export async function main() { refresh: { enabled: true, // refreshIntervalInMs: 30_000, // Optional. Default: 30 seconds - } - } + }, + }, }); console.log(`Use feature management library to consume feature flags`); const featureManager = new FeatureManager( - new ConfigurationMapFeatureFlagProvider(appConfigProvider)); + new ConfigurationMapFeatureFlagProvider(appConfigProvider), + ); let isEnabled = await featureManager.isEnabled(featureFlagName); console.log(`Is featureFlag enabled? ${isEnabled}`); @@ -109,7 +115,7 @@ export async function main() { // The feature flag will not be enabled for everyone as targeting filter is configured isEnabled = await featureManager.isEnabled(featureFlagName); console.log(`Is featureFlag enabled? ${isEnabled}`); - + isEnabled = await featureManager.isEnabled(featureFlagName, targetingContext); console.log(`Is featureFlag enabled for test@contoso.com? ${isEnabled}`); }