@@ -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 result . variant = variantDef !== undefined ? new Variant ( variantDef . name , variantDef . configuration_value ) : undefined ;
171174 result . variantAssignmentReason = reason ;
172175
@@ -179,12 +182,73 @@ export class FeatureManager implements IFeatureManager {
179182 }
180183 }
181184
185+ // The callback will only be executed if telemetry is enabled for the feature flag
186+ if ( featureFlag . telemetry ?. enabled && this . #onFeatureEvaluated !== undefined ) {
187+ this . #onFeatureEvaluated( result ) ;
188+ }
189+
182190 return result ;
183191 }
184192}
185193
186- interface FeatureManagerOptions {
194+ export interface FeatureManagerOptions {
195+ /**
196+ * The custom filters to be used by the feature manager.
197+ */
187198 customFilters ?: IFeatureFilter [ ] ;
199+
200+ /**
201+ * The callback function that is called when a feature flag is evaluated.
202+ * The callback function is called only when telemetry is enabled for the feature flag.
203+ */
204+ onFeatureEvaluated ?: ( event : EvaluationResult ) => void ;
205+ }
206+
207+ export class EvaluationResult {
208+ constructor (
209+ // feature flag definition
210+ public readonly feature : FeatureFlag | undefined ,
211+
212+ // enabled state
213+ public enabled : boolean = false ,
214+
215+ // variant assignment
216+ public userId : string | undefined = undefined ,
217+ public variant : Variant | undefined = undefined ,
218+ public variantAssignmentReason : VariantAssignmentReason = VariantAssignmentReason . None
219+ ) { }
220+ }
221+
222+ export enum VariantAssignmentReason {
223+ /**
224+ * Variant allocation did not happen. No variant is assigned.
225+ */
226+ None = "None" ,
227+
228+ /**
229+ * The default variant is assigned when a feature flag is disabled.
230+ */
231+ DefaultWhenDisabled = "DefaultWhenDisabled" ,
232+
233+ /**
234+ * The default variant is assigned because of no applicable user/group/percentile allocation when a feature flag is enabled.
235+ */
236+ DefaultWhenEnabled = "DefaultWhenEnabled" ,
237+
238+ /**
239+ * The variant is assigned because of the user allocation when a feature flag is enabled.
240+ */
241+ User = "User" ,
242+
243+ /**
244+ * The variant is assigned because of the group allocation when a feature flag is enabled.
245+ */
246+ Group = "Group" ,
247+
248+ /**
249+ * The variant is assigned because of the percentile allocation when a feature flag is enabled.
250+ */
251+ Percentile = "Percentile"
188252}
189253
190254/**
@@ -225,49 +289,3 @@ type VariantAssignment = {
225289 variant : VariantDefinition | undefined ;
226290 reason : VariantAssignmentReason ;
227291} ;
228-
229- enum VariantAssignmentReason {
230- /**
231- * Variant allocation did not happen. No variant is assigned.
232- */
233- None ,
234-
235- /**
236- * The default variant is assigned when a feature flag is disabled.
237- */
238- DefaultWhenDisabled ,
239-
240- /**
241- * The default variant is assigned because of no applicable user/group/percentile allocation when a feature flag is enabled.
242- */
243- DefaultWhenEnabled ,
244-
245- /**
246- * The variant is assigned because of the user allocation when a feature flag is enabled.
247- */
248- User ,
249-
250- /**
251- * The variant is assigned because of the group allocation when a feature flag is enabled.
252- */
253- Group ,
254-
255- /**
256- * The variant is assigned because of the percentile allocation when a feature flag is enabled.
257- */
258- Percentile
259- }
260-
261- class EvaluationResult {
262- constructor (
263- // feature flag definition
264- public readonly feature : FeatureFlag | undefined ,
265-
266- // enabled state
267- public enabled : boolean = false ,
268-
269- // variant assignment
270- public variant : Variant | undefined = undefined ,
271- public variantAssignmentReason : VariantAssignmentReason = VariantAssignmentReason . None
272- ) { }
273- }
0 commit comments