@@ -14,6 +14,7 @@ import { isTargetedGroup, isTargetedPercentile, isTargetedUser } from "./common/
1414export class FeatureManager implements IFeatureManager {
1515 #provider: IFeatureFlagProvider ;
1616 #featureFilters: Map < string , IFeatureFilter > = new Map ( ) ;
17+ #onFeatureEvaluated?: ( event : EvaluationResult ) => void ;
1718
1819 constructor ( provider : IFeatureFlagProvider , options ?: FeatureManagerOptions ) {
1920 this . #provider = provider ;
@@ -24,6 +25,8 @@ export class FeatureManager implements IFeatureManager {
2425 for ( const filter of [ ...builtinFilters , ...( options ?. customFilters ?? [ ] ) ] ) {
2526 this . #featureFilters. set ( filter . name , filter ) ;
2627 }
28+
29+ this . #onFeatureEvaluated = options ?. onFeatureEvaluated ;
2730 }
2831
2932 async listFeatureNames ( ) : Promise < string [ ] > {
@@ -127,6 +130,9 @@ export class FeatureManager implements IFeatureManager {
127130 // Evaluate if the feature is enabled.
128131 result . enabled = await this . #isEnabled( featureFlag , context ) ;
129132
133+ const targetingContext = context as ITargetingContext ;
134+ result . userId = targetingContext ?. userId ;
135+
130136 // Determine Variant
131137 let variantDef : VariantDefinition | undefined ;
132138 let reason : VariantAssignmentReason = VariantAssignmentReason . None ;
@@ -146,7 +152,7 @@ export class FeatureManager implements IFeatureManager {
146152 } else {
147153 // enabled, assign based on allocation
148154 if ( context !== undefined && featureFlag . allocation !== undefined ) {
149- const variantAndReason = await this . #assignVariant( featureFlag , context as ITargetingContext ) ;
155+ const variantAndReason = await this . #assignVariant( featureFlag , targetingContext ) ;
150156 variantDef = variantAndReason . variant ;
151157 reason = variantAndReason . reason ;
152158 }
@@ -164,9 +170,6 @@ export class FeatureManager implements IFeatureManager {
164170 }
165171 }
166172
167- // TODO: send telemetry for variant assignment reason in the future.
168- console . log ( `Variant assignment for feature ${ featureName } : ${ variantDef ?. name ?? "default" } (${ reason } )` ) ;
169-
170173 if ( variantDef ?. configuration_reference !== undefined ) {
171174 console . warn ( "Configuration reference is not supported yet." ) ;
172175 }
@@ -183,12 +186,71 @@ export class FeatureManager implements IFeatureManager {
183186 }
184187 }
185188
189+ if ( featureFlag . telemetry ?. enabled && this . #onFeatureEvaluated !== undefined ) {
190+ this . #onFeatureEvaluated( result ) ;
191+ }
192+
186193 return result ;
187194 }
188195}
189196
190- interface FeatureManagerOptions {
197+ export interface FeatureManagerOptions {
198+ /**
199+ * The custom filters to be used by the feature manager.
200+ */
191201 customFilters ?: IFeatureFilter [ ] ;
202+
203+ /**
204+ * The callback function that is called when a feature flag is evaluated.
205+ */
206+ onFeatureEvaluated ?: ( event : EvaluationResult ) => void ;
207+ }
208+
209+ export class EvaluationResult {
210+ constructor (
211+ // feature flag definition
212+ public readonly feature : FeatureFlag | undefined ,
213+
214+ // enabled state
215+ public enabled : boolean = false ,
216+
217+ // variant assignment
218+ public userId : string | undefined = undefined ,
219+ public variant : Variant | undefined = undefined ,
220+ public variantAssignmentReason : VariantAssignmentReason = VariantAssignmentReason . None
221+ ) { }
222+ }
223+
224+ export enum VariantAssignmentReason {
225+ /**
226+ * Variant allocation did not happen. No variant is assigned.
227+ */
228+ None = "None" ,
229+
230+ /**
231+ * The default variant is assigned when a feature flag is disabled.
232+ */
233+ DefaultWhenDisabled = "DefaultWhenDisabled" ,
234+
235+ /**
236+ * The default variant is assigned because of no applicable user/group/percentile allocation when a feature flag is enabled.
237+ */
238+ DefaultWhenEnabled = "DefaultWhenEnabled" ,
239+
240+ /**
241+ * The variant is assigned because of the user allocation when a feature flag is enabled.
242+ */
243+ User = "User" ,
244+
245+ /**
246+ * The variant is assigned because of the group allocation when a feature flag is enabled.
247+ */
248+ Group = "Group" ,
249+
250+ /**
251+ * The variant is assigned because of the percentile allocation when a feature flag is enabled.
252+ */
253+ Percentile = "Percentile"
192254}
193255
194256/**
@@ -229,49 +291,3 @@ type VariantAssignment = {
229291 variant : VariantDefinition | undefined ;
230292 reason : VariantAssignmentReason ;
231293} ;
232-
233- enum VariantAssignmentReason {
234- /**
235- * Variant allocation did not happen. No variant is assigned.
236- */
237- None ,
238-
239- /**
240- * The default variant is assigned when a feature flag is disabled.
241- */
242- DefaultWhenDisabled ,
243-
244- /**
245- * The default variant is assigned because of no applicable user/group/percentile allocation when a feature flag is enabled.
246- */
247- DefaultWhenEnabled ,
248-
249- /**
250- * The variant is assigned because of the user allocation when a feature flag is enabled.
251- */
252- User ,
253-
254- /**
255- * The variant is assigned because of the group allocation when a feature flag is enabled.
256- */
257- Group ,
258-
259- /**
260- * The variant is assigned because of the percentile allocation when a feature flag is enabled.
261- */
262- Percentile
263- }
264-
265- class EvaluationResult {
266- constructor (
267- // feature flag definition
268- public readonly feature : FeatureFlag | undefined ,
269-
270- // enabled state
271- public enabled : boolean = false ,
272-
273- // variant assignment
274- public variant : Variant | undefined = undefined ,
275- public variantAssignmentReason : VariantAssignmentReason = VariantAssignmentReason . None
276- ) { }
277- }
0 commit comments