@@ -14,6 +14,7 @@ import { isTargetedGroup, isTargetedPercentile, isTargetedUser } from "./common/
14
14
export class FeatureManager implements IFeatureManager {
15
15
#provider: IFeatureFlagProvider ;
16
16
#featureFilters: Map < string , IFeatureFilter > = new Map ( ) ;
17
+ #onFeatureEvaluated?: ( event : EvaluationResult ) => void ;
17
18
18
19
constructor ( provider : IFeatureFlagProvider , options ?: FeatureManagerOptions ) {
19
20
this . #provider = provider ;
@@ -24,6 +25,8 @@ export class FeatureManager implements IFeatureManager {
24
25
for ( const filter of [ ...builtinFilters , ...( options ?. customFilters ?? [ ] ) ] ) {
25
26
this . #featureFilters. set ( filter . name , filter ) ;
26
27
}
28
+
29
+ this . #onFeatureEvaluated = options ?. onFeatureEvaluated ;
27
30
}
28
31
29
32
async listFeatureNames ( ) : Promise < string [ ] > {
@@ -127,6 +130,9 @@ export class FeatureManager implements IFeatureManager {
127
130
// Evaluate if the feature is enabled.
128
131
result . enabled = await this . #isEnabled( featureFlag , context ) ;
129
132
133
+ const targetingContext = context as ITargetingContext ;
134
+ result . userId = targetingContext ?. userId ;
135
+
130
136
// Determine Variant
131
137
let variantDef : VariantDefinition | undefined ;
132
138
let reason : VariantAssignmentReason = VariantAssignmentReason . None ;
@@ -146,7 +152,7 @@ export class FeatureManager implements IFeatureManager {
146
152
} else {
147
153
// enabled, assign based on allocation
148
154
if ( context !== undefined && featureFlag . allocation !== undefined ) {
149
- const variantAndReason = await this . #assignVariant( featureFlag , context as ITargetingContext ) ;
155
+ const variantAndReason = await this . #assignVariant( featureFlag , targetingContext ) ;
150
156
variantDef = variantAndReason . variant ;
151
157
reason = variantAndReason . reason ;
152
158
}
@@ -164,9 +170,6 @@ export class FeatureManager implements IFeatureManager {
164
170
}
165
171
}
166
172
167
- // TODO: send telemetry for variant assignment reason in the future.
168
- console . log ( `Variant assignment for feature ${ featureName } : ${ variantDef ?. name ?? "default" } (${ reason } )` ) ;
169
-
170
173
result . variant = variantDef !== undefined ? new Variant ( variantDef . name , variantDef . configuration_value ) : undefined ;
171
174
result . variantAssignmentReason = reason ;
172
175
@@ -179,12 +182,73 @@ export class FeatureManager implements IFeatureManager {
179
182
}
180
183
}
181
184
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
+
182
190
return result ;
183
191
}
184
192
}
185
193
186
- interface FeatureManagerOptions {
194
+ export interface FeatureManagerOptions {
195
+ /**
196
+ * The custom filters to be used by the feature manager.
197
+ */
187
198
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"
188
252
}
189
253
190
254
/**
@@ -225,49 +289,3 @@ type VariantAssignment = {
225
289
variant : VariantDefinition | undefined ;
226
290
reason : VariantAssignmentReason ;
227
291
} ;
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