Skip to content

update FeatureFlag type to match v2 schema #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/featureManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ export class FeatureManager {
return true;
}

const requirementType = featureFlag.conditions?.requirement_type ?? RequirementType.Any; // default to any.
const requirementType: RequirementType = featureFlag.conditions?.requirement_type ?? "Any"; // default to any.

/**
* While iterating through the client filters, we short-circuit the evaluation based on the requirement type.
* - When requirement type is "All", the feature is enabled if all client filters are matched. If any client filter is not matched, the feature is disabled, otherwise it is enabled. `shortCircuitEvaluationResult` is false.
* - When requirement type is "Any", the feature is enabled if any client filter is matched. If any client filter is matched, the feature is enabled, otherwise it is disabled. `shortCircuitEvaluationResult` is true.
*/
const shortCircuitEvaluationResult: boolean = requirementType === RequirementType.Any;
const shortCircuitEvaluationResult: boolean = requirementType === "Any";

for (const clientFilter of clientFilters) {
const matchedFeatureFilter = this.#featureFilters.get(clientFilter.name);
Expand Down
157 changes: 134 additions & 23 deletions src/model.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,172 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

// Converted from https://github.com/Azure/AppConfiguration/blob/main/docs/FeatureManagement/FeatureFlag.v1.1.0.schema.json
// Converted from:
// https://github.com/Azure/AppConfiguration/blob/6e544296a5607f922a423df165f60801717c7800/docs/FeatureManagement/FeatureFlag.v2.0.0.schema.json

/**
* A feature flag is a named property that can be toggled to enable or disable some feature of an application.
*/
export interface FeatureFlag {
/**
* An ID used to uniquely identify and reference the feature.
*/
id: string

id: string;
/**
* A description of the feature.
*/
description?: string

description?: string;
/**
* A display name for the feature to use for display rather than the ID.
*/
display_name?: string

display_name?: string;
/**
* A feature is OFF if enabled is false. If enabled is true, then the feature is ON if there are no conditions (null or empty) or if the conditions are satisfied.
*/
enabled: boolean
enabled?: boolean;
/**
* The declaration of conditions used to dynamically enable the feature.
*/
conditions?: FeatureEnablementConditions;
/**
* The list of variants defined for this feature. A variant represents a configuration value of a feature flag that can be a string, a number, a boolean, or a JSON object.
*/
variants?: Variant[];
/**
* Determines how variants should be allocated for the feature to various users.
*/
allocation?: VariantAllocation;
/**
* The declaration of options used to configure telemetry for this feature.
*/
telemetry?: TelemetryOptions
}

/**
* The declaration of conditions used to dynamically enable the feature
*/
interface FeatureEnablementConditions {
/**
* The declaration of conditions used to dynamically enable features.
* Determines whether any or all registered client filters must be evaluated as true for the feature to be considered enabled.
*/
conditions?: FeatureEnablementConditions
requirement_type?: RequirementType;
/**
* Filters that must run on the client and be evaluated as true for the feature to be considered enabled.
*/
client_filters?: ClientFilter[];
}

export enum RequirementType {
Any = "Any",
All = "All"
export type RequirementType = "Any" | "All";

interface ClientFilter {
/**
* The name used to refer to a client filter.
*/
name: string;
/**
* Parameters for a given client filter. A client filter can require any set of parameters of any type.
*/
parameters?: Record<string, unknown>;
}

export interface FeatureEnablementConditions {
interface Variant {
/**
* Determines whether any or all registered client filters must be evaluated as true for the feature to be considered enabled.
* The name used to refer to a feature variant.
*/
requirement_type?: RequirementType
name: string;
/**
* The configuration value for this feature variant.
*/
configuration_value?: unknown;
/**
* The path to a configuration section used as the configuration value for this feature variant.
*/
configuration_reference?: string;
/**
* Overrides the enabled state of the feature if the given variant is assigned. Does not override the state if value is None.
*/
status_override?: "None" | "Enabled" | "Disabled";
}

/**
* Determines how variants should be allocated for the feature to various users.
*/
interface VariantAllocation {
/**
* Filters that must run on the client and be evaluated as true for the feature to be considered enabled.
* Specifies which variant should be used when the feature is considered disabled.
*/
default_when_disabled?: string;
/**
* Specifies which variant should be used when the feature is considered enabled and no other allocation rules are applicable.
*/
default_when_enabled?: string;
/**
* A list of objects, each containing a variant name and list of users for whom that variant should be used.
*/
user?: UserAllocation[];
/**
* A list of objects, each containing a variant name and list of groups for which that variant should be used.
*/
group?: GroupAllocation[];
/**
* A list of objects, each containing a variant name and percentage range for which that variant should be used.
*/
percentile?: PercentileAllocation[]
/**
* The value percentile calculations are based on. The calculated percentile is consistent across features for a given user if the same nonempty seed is used.
*/
seed?: string;
}

interface UserAllocation {
/**
* The name of the variant to use if the user allocation matches the current user.
*/
variant: string;
/**
* Collection of users where if any match the current user, the variant specified in the user allocation is used.
*/
users: string[];
}

interface GroupAllocation {
/**
* The name of the variant to use if the group allocation matches a group the current user is in.
*/
variant: string;
/**
* Collection of groups where if the current user is in any of these groups, the variant specified in the group allocation is used.
*/
groups: string[];
}

interface PercentileAllocation {
/**
* The name of the variant to use if the calculated percentile for the current user falls in the provided range.
*/
variant: string;
/**
* The lower end of the percentage range for which this variant will be used.
*/
from: number;
/**
* The upper end of the percentage range for which this variant will be used.
*/
client_filters?: ClientFilter[]
to: number;
}

export interface ClientFilter {
/**
* The declaration of options used to configure telemetry for this feature.
*/
interface TelemetryOptions {
/**
* The name used to refer to and require a client filter.
* Indicates if telemetry is enabled.
*/
name: string
enabled?: boolean;
/**
* Custom parameters for a given client filter. A client filter can require any set of parameters of any type.
* A container for metadata that should be bundled with flag telemetry.
*/
parameters?: unknown
metadata?: Record<string, string>;
}

// Feature Management Section fed into feature manager.
Expand Down