@@ -14,6 +14,7 @@ import { AssignmentCache } from '../cache/abstract-assignment-cache';
14
14
import { LRUInMemoryAssignmentCache } from '../cache/lru-in-memory-assignment-cache' ;
15
15
import { NonExpiringInMemoryAssignmentCache } from '../cache/non-expiring-in-memory-cache-assignment' ;
16
16
import { TLRUInMemoryAssignmentCache } from '../cache/tlru-in-memory-assignment-cache' ;
17
+ import { Configuration } from '../configuration' ;
17
18
import ConfigurationRequestor from '../configuration-requestor' ;
18
19
import { ConfigurationStore } from '../configuration-store' ;
19
20
import { IConfigurationStore , ISyncStore } from '../configuration-store/configuration-store' ;
@@ -30,7 +31,6 @@ import {
30
31
DEFAULT_POLL_INTERVAL_MS ,
31
32
DEFAULT_REQUEST_TIMEOUT_MS ,
32
33
} from '../constants' ;
33
- import { decodeFlag } from '../decoding' ;
34
34
import { EppoValue } from '../eppo_value' ;
35
35
import { Evaluator , FlagEvaluation , noneResult , overrideResult } from '../evaluator' ;
36
36
import { BoundedEventQueue } from '../events/bounded-event-queue' ;
@@ -42,19 +42,18 @@ import {
42
42
} from '../flag-evaluation-details-builder' ;
43
43
import { FlagEvaluationError } from '../flag-evaluation-error' ;
44
44
import FetchHttpClient from '../http-client' ;
45
- import { Configuration , IConfiguration } from '../i-configuration' ;
46
45
import {
47
46
BanditModelData ,
48
47
BanditParameters ,
49
48
BanditVariation ,
50
49
Flag ,
50
+ FormatEnum ,
51
51
IPrecomputedBandit ,
52
52
ObfuscatedFlag ,
53
53
PrecomputedFlag ,
54
54
Variation ,
55
55
VariationType ,
56
56
} from '../interfaces' ;
57
- import { getMD5Hash } from '../obfuscation' ;
58
57
import { OverridePayload , OverrideValidator } from '../override-validator' ;
59
58
import initPoller , { IPoller } from '../poller' ;
60
59
import {
@@ -106,6 +105,7 @@ export type EppoClientParameters = {
106
105
banditModelConfigurationStore ?: IConfigurationStore < BanditParameters > ;
107
106
overrideStore ?: ISyncStore < Variation > ;
108
107
configurationRequestParameters ?: FlagConfigurationRequestParameters ;
108
+ initialConfiguration ?: Configuration ;
109
109
/**
110
110
* Setting this value will have no side effects other than triggering a warning when the actual
111
111
* configuration's obfuscated does not match the value set here.
@@ -135,7 +135,7 @@ export default class EppoClient {
135
135
private configurationRequestor ?: ConfigurationRequestor ;
136
136
private readonly overrideValidator = new OverrideValidator ( ) ;
137
137
138
- private readonly configurationStore = new ConfigurationStore ( null ) ;
138
+ private readonly configurationStore ;
139
139
/** @deprecated use configurationStore instead. */
140
140
private flagConfigurationStore : IConfigurationStore < Flag | ObfuscatedFlag > ;
141
141
/** @deprecated use configurationStore instead. */
@@ -151,7 +151,10 @@ export default class EppoClient {
151
151
banditModelConfigurationStore,
152
152
overrideStore,
153
153
configurationRequestParameters,
154
+ initialConfiguration,
154
155
} : EppoClientParameters ) {
156
+ this . configurationStore = new ConfigurationStore ( initialConfiguration ) ;
157
+
155
158
this . eventDispatcher = eventDispatcher ;
156
159
this . flagConfigurationStore = flagConfigurationStore ;
157
160
this . banditVariationConfigurationStore = banditVariationConfigurationStore ;
@@ -167,10 +170,14 @@ export default class EppoClient {
167
170
}
168
171
}
169
172
170
- private getConfiguration ( ) : Configuration | null {
173
+ public getConfiguration ( ) : Configuration {
171
174
return this . configurationStore . getConfiguration ( ) ;
172
175
}
173
176
177
+ public setConfiguration ( configuration : Configuration ) {
178
+ this . configurationStore . setConfiguration ( configuration ) ;
179
+ }
180
+
174
181
/**
175
182
* Validates and parses x-eppo-overrides header sent by Eppo's Chrome extension
176
183
*/
@@ -606,16 +613,13 @@ export default class EppoClient {
606
613
defaultAction : string ,
607
614
) : string {
608
615
const config = this . getConfiguration ( ) ;
609
- if ( ! config ) {
610
- return defaultAction ;
611
- }
612
616
let result : string | null = null ;
613
617
614
618
const flagBanditVariations = config . getFlagBanditVariations ( flagKey ) ;
615
- const banditKey = flagBanditVariations ? .at ( 0 ) ?. key ;
619
+ const banditKey = flagBanditVariations . at ( 0 ) ?. key ;
616
620
617
621
if ( banditKey ) {
618
- const banditParameters = config . getBandit ( banditKey ) ;
622
+ const banditParameters = config . getBanditConfiguration ( ) ?. response . bandits [ banditKey ] ;
619
623
if ( banditParameters ) {
620
624
const contextualSubjectAttributes = ensureContextualSubjectAttributes ( subjectAttributes ) ;
621
625
const actionsWithContextualAttributes = ensureActionsWithContextualAttributes ( actions ) ;
@@ -673,7 +677,6 @@ export default class EppoClient {
673
677
// Note: the reason for non-bandit assignments include the subject being bucketed into a non-bandit variation or
674
678
// a rollout having been done.
675
679
const bandit = config . getFlagVariationBandit ( flagKey , variation ) ;
676
-
677
680
if ( ! bandit ) {
678
681
return { variation, action : null , evaluationDetails } ;
679
682
}
@@ -901,29 +904,19 @@ export default class EppoClient {
901
904
subjectAttributes : Attributes = { } ,
902
905
) : Record < FlagKey , PrecomputedFlag > {
903
906
const config = this . getConfiguration ( ) ;
904
- if ( ! config ) {
905
- return { } ;
906
- }
907
- const configDetails = config . getFlagConfigDetails ( ) ;
908
907
const flagKeys = config . getFlagKeys ( ) ;
909
908
const flags : Record < FlagKey , PrecomputedFlag > = { } ;
910
909
911
910
// Evaluate all the enabled flags for the user
912
911
flagKeys . forEach ( ( flagKey ) => {
913
- const flag = this . getNormalizedFlag ( config , flagKey ) ;
912
+ const flag = config . getFlag ( flagKey ) ;
914
913
if ( ! flag ) {
915
914
logger . debug ( `${ loggerPrefix } No assigned variation. Flag does not exist.` ) ;
916
915
return ;
917
916
}
918
917
919
918
// Evaluate the flag for this subject.
920
- const evaluation = this . evaluator . evaluateFlag (
921
- flag ,
922
- configDetails ,
923
- subjectKey ,
924
- subjectAttributes ,
925
- config . isObfuscated ( ) ,
926
- ) ;
919
+ const evaluation = this . evaluator . evaluateFlag ( config , flag , subjectKey , subjectAttributes ) ;
927
920
928
921
// allocationKey is set along with variation when there is a result. this check appeases typescript below
929
922
if ( ! evaluation . variation || ! evaluation . allocationKey ) {
@@ -960,24 +953,10 @@ export default class EppoClient {
960
953
banditActions : Record < FlagKey , BanditActions > = { } ,
961
954
salt ?: string ,
962
955
) : string {
963
- const subjectContextualAttributes = ensureContextualSubjectAttributes ( subjectAttributes ) ;
964
- const subjectFlatAttributes = ensureNonContextualSubjectAttributes ( subjectAttributes ) ;
965
-
966
956
const config = this . getConfiguration ( ) ;
967
- if ( ! config ) {
968
- const precomputedConfig = PrecomputedConfiguration . obfuscated (
969
- subjectKey ,
970
- { } ,
971
- { } ,
972
- salt ?? '' ,
973
- subjectContextualAttributes ,
974
- undefined ,
975
- ) ;
976
- return JSON . stringify ( ConfigurationWireV1 . precomputed ( precomputedConfig ) ) ;
977
- }
978
-
979
- const configDetails = config . getFlagConfigDetails ( ) ;
980
957
958
+ const subjectContextualAttributes = ensureContextualSubjectAttributes ( subjectAttributes ) ;
959
+ const subjectFlatAttributes = ensureNonContextualSubjectAttributes ( subjectAttributes ) ;
981
960
const flags = this . getAllAssignments ( subjectKey , subjectFlatAttributes ) ;
982
961
983
962
const bandits = this . computeBanditsForFlags (
@@ -994,7 +973,7 @@ export default class EppoClient {
994
973
bandits ,
995
974
salt ?? '' , // no salt if not provided
996
975
subjectContextualAttributes ,
997
- configDetails . configEnvironment ,
976
+ config . getFlagsConfiguration ( ) ?. response . environment ,
998
977
) ;
999
978
1000
979
const configWire : IConfigurationWire = ConfigurationWireV1 . precomputed ( precomputedConfig ) ;
@@ -1043,8 +1022,7 @@ export default class EppoClient {
1043
1022
) ;
1044
1023
}
1045
1024
1046
- const configDetails = config . getFlagConfigDetails ( ) ;
1047
- const flag = this . getNormalizedFlag ( config , flagKey ) ;
1025
+ const flag = config . getFlag ( flagKey ) ;
1048
1026
1049
1027
if ( flag === null ) {
1050
1028
logger . warn ( `${ loggerPrefix } No assigned variation. Flag not found: ${ flagKey } ` ) ;
@@ -1058,7 +1036,7 @@ export default class EppoClient {
1058
1036
subjectKey ,
1059
1037
subjectAttributes ,
1060
1038
flagEvaluationDetails ,
1061
- configDetails . configFormat ,
1039
+ config . getFlagsConfiguration ( ) ?. response . environment . name ?? '' ,
1062
1040
) ;
1063
1041
}
1064
1042
@@ -1074,7 +1052,7 @@ export default class EppoClient {
1074
1052
subjectKey ,
1075
1053
subjectAttributes ,
1076
1054
flagEvaluationDetails ,
1077
- configDetails . configFormat ,
1055
+ config . getFlagsConfiguration ( ) ?. response . format ?? '' ,
1078
1056
) ;
1079
1057
}
1080
1058
throw new TypeError ( errorMessage ) ;
@@ -1092,23 +1070,20 @@ export default class EppoClient {
1092
1070
subjectKey ,
1093
1071
subjectAttributes ,
1094
1072
flagEvaluationDetails ,
1095
- configDetails . configFormat ,
1073
+ config . getFlagsConfiguration ( ) ?. response . format ?? '' ,
1096
1074
) ;
1097
1075
}
1098
1076
1099
- const isObfuscated = config . isObfuscated ( ) ;
1100
1077
const result = this . evaluator . evaluateFlag (
1078
+ config ,
1101
1079
flag ,
1102
- configDetails ,
1103
1080
subjectKey ,
1104
1081
subjectAttributes ,
1105
- isObfuscated ,
1106
1082
expectedVariationType ,
1107
1083
) ;
1108
- if ( isObfuscated ) {
1109
- // flag.key is obfuscated, replace with requested flag key
1110
- result . flagKey = flagKey ;
1111
- }
1084
+
1085
+ // if flag.key is obfuscated, replace with requested flag key
1086
+ result . flagKey = flagKey ;
1112
1087
1113
1088
try {
1114
1089
if ( result ?. doLog ) {
@@ -1134,36 +1109,22 @@ export default class EppoClient {
1134
1109
}
1135
1110
1136
1111
private newFlagEvaluationDetailsBuilder (
1137
- config : IConfiguration | null ,
1112
+ config : Configuration ,
1138
1113
flagKey : string ,
1139
1114
) : FlagEvaluationDetailsBuilder {
1140
- if ( ! config ) {
1141
- return new FlagEvaluationDetailsBuilder ( '' , [ ] , '' , '' ) ;
1142
- }
1143
-
1144
- const flag = this . getNormalizedFlag ( config , flagKey ) ;
1145
- const configDetails = config . getFlagConfigDetails ( ) ;
1115
+ const flag = config . getFlag ( flagKey ) ;
1116
+ const flagsConfiguration = config . getFlagsConfiguration ( ) ;
1146
1117
return new FlagEvaluationDetailsBuilder (
1147
- configDetails . configEnvironment . name ,
1118
+ flagsConfiguration ?. response . environment . name ?? '' ,
1148
1119
flag ?. allocations ?? [ ] ,
1149
- configDetails . configFetchedAt ,
1150
- configDetails . configPublishedAt ,
1120
+ flagsConfiguration ?. fetchedAt ?? '' ,
1121
+ flagsConfiguration ?. response . createdAt ?? '' ,
1151
1122
) ;
1152
1123
}
1153
1124
1154
- private getNormalizedFlag ( config : IConfiguration , flagKey : string ) : Flag | null {
1155
- return config . isObfuscated ( )
1156
- ? this . getObfuscatedFlag ( config , flagKey )
1157
- : config . getFlag ( flagKey ) ;
1158
- }
1159
-
1160
- private getObfuscatedFlag ( config : IConfiguration , flagKey : string ) : Flag | null {
1161
- const flag : ObfuscatedFlag | null = config . getFlag ( getMD5Hash ( flagKey ) ) as ObfuscatedFlag ;
1162
- return flag ? decodeFlag ( flag ) : null ;
1163
- }
1164
-
1165
1125
isInitialized ( ) {
1166
- return this . getConfiguration ( ) ?. isInitialized ( ) ?? false ;
1126
+ // We treat configuration as initialized if we have flags config.
1127
+ return ! ! this . configurationStore . getConfiguration ( ) ?. getFlagsConfiguration ( ) ;
1167
1128
}
1168
1129
1169
1130
/** @deprecated Use `setAssignmentLogger` */
@@ -1304,14 +1265,15 @@ export default class EppoClient {
1304
1265
1305
1266
private buildLoggerMetadata ( ) : Record < string , unknown > {
1306
1267
return {
1307
- obfuscated : this . getConfiguration ( ) ?. isObfuscated ( ) ,
1268
+ obfuscated :
1269
+ this . getConfiguration ( ) ?. getFlagsConfiguration ( ) ?. response . format === FormatEnum . CLIENT ,
1308
1270
sdkLanguage : 'javascript' ,
1309
1271
sdkLibVersion : LIB_VERSION ,
1310
1272
} ;
1311
1273
}
1312
1274
1313
1275
private computeBanditsForFlags (
1314
- config : IConfiguration ,
1276
+ config : Configuration ,
1315
1277
subjectKey : string ,
1316
1278
subjectAttributes : ContextAttributes ,
1317
1279
banditActions : Record < FlagKey , BanditActions > ,
@@ -1341,7 +1303,7 @@ export default class EppoClient {
1341
1303
}
1342
1304
1343
1305
private getPrecomputedBandit (
1344
- config : IConfiguration ,
1306
+ config : Configuration ,
1345
1307
flagKey : string ,
1346
1308
variationValue : string ,
1347
1309
subjectKey : string ,
0 commit comments