@@ -56,12 +56,23 @@ const FLAGSMITH_CONFIG_ANALYTICS_KEY = "flagsmith_value_";
56
56
const FLAGSMITH_FLAG_ANALYTICS_KEY = "flagsmith_enabled_" ;
57
57
const FLAGSMITH_TRAIT_ANALYTICS_KEY = "flagsmith_trait_" ;
58
58
59
+
60
+ /*API configuration includes the /v1/
61
+ This function replaces that version with another.
62
+ In future, we may exclude /v1/ from api configuration however this would be a breaking change*/
63
+ function apiVersion ( api :string , version :number ) {
64
+ return api . replace ( "/v1/" , `/v${ version } /` )
65
+ }
66
+
59
67
const Flagsmith = class {
60
68
_trigger ?:( ( ) => void ) | null = null
61
69
_triggerLoadingState ?:( ( ) => void ) | null = null
62
70
timestamp : number | null = null
63
71
isLoading = false
64
72
eventSource :EventSource | null = null
73
+ events : string [ ] = [ ]
74
+ splitTestingAnalytics = false ;
75
+
65
76
constructor ( props : Config ) {
66
77
if ( props . fetch ) {
67
78
_fetch = props . fetch as LikeFetch ;
@@ -225,11 +236,11 @@ const Flagsmith = class {
225
236
const { api } = this ;
226
237
227
238
if ( ! this . evaluationEvent || ! this . evaluationContext . environment || ! this . evaluationEvent [ this . evaluationContext . environment . apiKey ] ) {
228
- return
239
+ return Promise . resolve ( )
229
240
}
230
241
231
242
if ( this . evaluationEvent && Object . getOwnPropertyNames ( this . evaluationEvent ) . length !== 0 && Object . getOwnPropertyNames ( this . evaluationEvent [ this . evaluationContext . environment . apiKey ] ) . length !== 0 ) {
232
- return this . getJSON ( api + 'analytics/flags/' , 'POST' , JSON . stringify ( this . evaluationEvent [ this . evaluationContext . environment . apiKey ] ) )
243
+ return this . getJSON ( apiVersion ( ` ${ api } ` , this . splitTestingAnalytics ? 2 : 1 ) + 'analytics/flags/' , 'POST' , JSON . stringify ( this . toAnalyticsPayload ( this . evaluationEvent [ this . evaluationContext . environment . apiKey ] ) ) )
233
244
. then ( ( res ) => {
234
245
if ( ! this . evaluationContext . environment ) {
235
246
return ;
@@ -248,6 +259,7 @@ const Flagsmith = class {
248
259
this . log ( "Exception fetching evaluationEvent" , err ) ;
249
260
} ) ;
250
261
}
262
+ return Promise . resolve ( )
251
263
} ;
252
264
253
265
datadogRum : IDatadogRum | null = null ;
@@ -298,9 +310,11 @@ const Flagsmith = class {
298
310
state,
299
311
cacheOptions,
300
312
angularHttpClient,
313
+ splitTestingAnalytics,
301
314
_trigger,
302
315
_triggerLoadingState,
303
316
} = config ;
317
+ this . splitTestingAnalytics = ! ! splitTestingAnalytics ;
304
318
evaluationContext . environment = environmentID ? { apiKey : environmentID } : evaluationContext . environment ;
305
319
if ( ! evaluationContext . environment || ! evaluationContext . environment . apiKey ) {
306
320
throw new Error ( 'Please provide `evaluationContext.environment` with non-empty `apiKey`' ) ;
@@ -553,6 +567,7 @@ const Flagsmith = class {
553
567
// clear out old traits when switching identity
554
568
traits : this . evaluationContext . identity && this . evaluationContext . identity . identifier == userId ? this . evaluationContext . identity . traits : { }
555
569
}
570
+ this . events . map ( this . trackEvent )
556
571
this . evaluationContext . identity . identifier = userId ;
557
572
this . log ( "Identify: " + this . evaluationContext . identity . identifier )
558
573
@@ -723,6 +738,25 @@ const Flagsmith = class {
723
738
} ) ;
724
739
} ;
725
740
741
+ trackEvent = ( event : string ) => {
742
+ if ( ! this . splitTestingAnalytics ) {
743
+ const error = new Error ( "This feature is only enabled for self-hosted customers using split testing." ) ;
744
+ console . error ( error . message ) ;
745
+ return Promise . reject ( error ) ;
746
+ } else if ( ! this . evaluationContext . identity ?. identifier ) {
747
+ this . events . push ( event ) ;
748
+ this . log ( "Waiting for user to be identified before tracking event" , event ) ;
749
+ return Promise . resolve ( ) ;
750
+ } else {
751
+ return this . analyticsFlags ( ) . then ( ( ) => {
752
+ return this . getJSON ( this . api + 'split-testing/conversion-events/' , "POST" , JSON . stringify ( {
753
+ 'identity_identifier' : this . evaluationContext . identity ?. identifier ,
754
+ 'type' : event
755
+ } ) ) ;
756
+ } ) ;
757
+ }
758
+ } ;
759
+
726
760
hasFeature = ( key : string , options ?: HasFeatureOptions ) => {
727
761
// Support legacy skipAnalytics boolean parameter
728
762
const usingNewOptions = typeof options === 'object'
@@ -759,6 +793,26 @@ const Flagsmith = class {
759
793
}
760
794
}
761
795
796
+
797
+
798
+ private toAnalyticsPayload = ( evaluations : Record < string , number > | null ) => {
799
+ if ( ! this . splitTestingAnalytics ) {
800
+ return evaluations || { }
801
+ }
802
+ if ( ! evaluations ) return { evaluations : [ ] }
803
+ return {
804
+ evaluations : Object . keys ( evaluations ) . map ( ( feature_name ) => (
805
+ {
806
+ feature_name,
807
+ "identity_identifier" : this . evaluationContext ?. identity ?. identifier || null ,
808
+ "count" : evaluations [ feature_name ] ,
809
+ "enabled_when_evaluated" : this . hasFeature ( feature_name ) ,
810
+ }
811
+ ) )
812
+ }
813
+ } ;
814
+
815
+
762
816
private updateStorage ( ) {
763
817
if ( this . cacheFlags ) {
764
818
this . ts = new Date ( ) . valueOf ( ) ;
0 commit comments