1
+ import EppoClient , { IAssignmentDetails , IContainerExperiment } from './eppo-client' ;
2
+ import { Attributes , BanditActions , ContextAttributes , FlagKey } from '../types' ;
3
+ import { ensureNonContextualSubjectAttributes } from '../attributes' ;
4
+ import { Configuration } from '../configuration' ;
5
+
6
+ /**
7
+ * A wrapper around EppoClient that automatically supplies subject key, attributes, and bandit
8
+ * actions for all assignment and bandit methods.
9
+ *
10
+ * This is useful when you always want to use the same subject and attributes for all flag
11
+ * evaluations.
12
+ */
13
+ export class Subject {
14
+ private client : EppoClient ;
15
+ private subjectKey : string ;
16
+ private subjectAttributes : Attributes | ContextAttributes ;
17
+ private banditActions ?: Record < FlagKey , BanditActions > ;
18
+
19
+ /**
20
+ * @internal Creates a new Subject instance.
21
+ *
22
+ * @param client The EppoClient instance to wrap
23
+ * @param subjectKey The subject key to use for all assignments
24
+ * @param subjectAttributes The subject attributes to use for all assignments
25
+ * @param banditActions Optional default bandit actions to use for all bandit evaluations
26
+ */
27
+ constructor (
28
+ client : EppoClient ,
29
+ subjectKey : string ,
30
+ subjectAttributes : Attributes | ContextAttributes ,
31
+ banditActions : Record < FlagKey , BanditActions >
32
+ ) {
33
+ this . client = client ;
34
+ this . subjectKey = subjectKey ;
35
+ this . subjectAttributes = subjectAttributes ;
36
+ this . banditActions = banditActions ;
37
+ }
38
+
39
+ /**
40
+ * Gets the underlying EppoClient instance.
41
+ */
42
+ public getClient ( ) : EppoClient {
43
+ return this . client ;
44
+ }
45
+
46
+ /**
47
+ * Maps a subject to a string variation for a given experiment.
48
+ *
49
+ * @param flagKey feature flag identifier
50
+ * @param defaultValue default value to return if the subject is not part of the experiment sample
51
+ * @returns a variation value if the subject is part of the experiment sample, otherwise the default value
52
+ */
53
+ public getStringAssignment ( flagKey : string , defaultValue : string ) : string {
54
+ return this . client . getStringAssignment (
55
+ flagKey ,
56
+ this . subjectKey ,
57
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes ) ,
58
+ defaultValue
59
+ ) ;
60
+ }
61
+
62
+ /**
63
+ * Maps a subject to a string variation for a given experiment and provides additional details about the
64
+ * variation assigned and the reason for the assignment.
65
+ *
66
+ * @param flagKey feature flag identifier
67
+ * @param defaultValue default value to return if the subject is not part of the experiment sample
68
+ * @returns an object that includes the variation value along with additional metadata about the assignment
69
+ */
70
+ public getStringAssignmentDetails ( flagKey : string , defaultValue : string ) : IAssignmentDetails < string > {
71
+ return this . client . getStringAssignmentDetails (
72
+ flagKey ,
73
+ this . subjectKey ,
74
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes ) ,
75
+ defaultValue
76
+ ) ;
77
+ }
78
+
79
+ /**
80
+ * Maps a subject to a boolean variation for a given experiment.
81
+ *
82
+ * @param flagKey feature flag identifier
83
+ * @param defaultValue default value to return if the subject is not part of the experiment sample
84
+ * @returns a boolean variation value if the subject is part of the experiment sample, otherwise the default value
85
+ */
86
+ public getBooleanAssignment ( flagKey : string , defaultValue : boolean ) : boolean {
87
+ return this . client . getBooleanAssignment (
88
+ flagKey ,
89
+ this . subjectKey ,
90
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes ) ,
91
+ defaultValue
92
+ ) ;
93
+ }
94
+
95
+ /**
96
+ * Maps a subject to a boolean variation for a given experiment and provides additional details about the
97
+ * variation assigned and the reason for the assignment.
98
+ *
99
+ * @param flagKey feature flag identifier
100
+ * @param defaultValue default value to return if the subject is not part of the experiment sample
101
+ * @returns an object that includes the variation value along with additional metadata about the assignment
102
+ */
103
+ public getBooleanAssignmentDetails ( flagKey : string , defaultValue : boolean ) : IAssignmentDetails < boolean > {
104
+ return this . client . getBooleanAssignmentDetails (
105
+ flagKey ,
106
+ this . subjectKey ,
107
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes ) ,
108
+ defaultValue
109
+ ) ;
110
+ }
111
+
112
+ /**
113
+ * Maps a subject to an Integer variation for a given experiment.
114
+ *
115
+ * @param flagKey feature flag identifier
116
+ * @param defaultValue default value to return if the subject is not part of the experiment sample
117
+ * @returns an integer variation value if the subject is part of the experiment sample, otherwise the default value
118
+ */
119
+ public getIntegerAssignment ( flagKey : string , defaultValue : number ) : number {
120
+ return this . client . getIntegerAssignment (
121
+ flagKey ,
122
+ this . subjectKey ,
123
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes ) ,
124
+ defaultValue
125
+ ) ;
126
+ }
127
+
128
+ /**
129
+ * Maps a subject to an Integer variation for a given experiment and provides additional details about the
130
+ * variation assigned and the reason for the assignment.
131
+ *
132
+ * @param flagKey feature flag identifier
133
+ * @param defaultValue default value to return if the subject is not part of the experiment sample
134
+ * @returns an object that includes the variation value along with additional metadata about the assignment
135
+ */
136
+ public getIntegerAssignmentDetails ( flagKey : string , defaultValue : number ) : IAssignmentDetails < number > {
137
+ return this . client . getIntegerAssignmentDetails (
138
+ flagKey ,
139
+ this . subjectKey ,
140
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes ) ,
141
+ defaultValue
142
+ ) ;
143
+ }
144
+
145
+ /**
146
+ * Maps a subject to a numeric variation for a given experiment.
147
+ *
148
+ * @param flagKey feature flag identifier
149
+ * @param defaultValue default value to return if the subject is not part of the experiment sample
150
+ * @returns a number variation value if the subject is part of the experiment sample, otherwise the default value
151
+ */
152
+ public getNumericAssignment ( flagKey : string , defaultValue : number ) : number {
153
+ return this . client . getNumericAssignment (
154
+ flagKey ,
155
+ this . subjectKey ,
156
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes ) ,
157
+ defaultValue
158
+ ) ;
159
+ }
160
+
161
+ /**
162
+ * Maps a subject to a numeric variation for a given experiment and provides additional details about the
163
+ * variation assigned and the reason for the assignment.
164
+ *
165
+ * @param flagKey feature flag identifier
166
+ * @param defaultValue default value to return if the subject is not part of the experiment sample
167
+ * @returns an object that includes the variation value along with additional metadata about the assignment
168
+ */
169
+ public getNumericAssignmentDetails ( flagKey : string , defaultValue : number ) : IAssignmentDetails < number > {
170
+ return this . client . getNumericAssignmentDetails (
171
+ flagKey ,
172
+ this . subjectKey ,
173
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes ) ,
174
+ defaultValue
175
+ ) ;
176
+ }
177
+
178
+ /**
179
+ * Maps a subject to a JSON variation for a given experiment.
180
+ *
181
+ * @param flagKey feature flag identifier
182
+ * @param defaultValue default value to return if the subject is not part of the experiment sample
183
+ * @returns a JSON object variation value if the subject is part of the experiment sample, otherwise the default value
184
+ */
185
+ public getJSONAssignment ( flagKey : string , defaultValue : object ) : object {
186
+ return this . client . getJSONAssignment (
187
+ flagKey ,
188
+ this . subjectKey ,
189
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes ) ,
190
+ defaultValue
191
+ ) ;
192
+ }
193
+
194
+ /**
195
+ * Maps a subject to a JSON variation for a given experiment and provides additional details about the
196
+ * variation assigned and the reason for the assignment.
197
+ *
198
+ * @param flagKey feature flag identifier
199
+ * @param defaultValue default value to return if the subject is not part of the experiment sample
200
+ * @returns an object that includes the variation value along with additional metadata about the assignment
201
+ */
202
+ public getJSONAssignmentDetails ( flagKey : string , defaultValue : object ) : IAssignmentDetails < object > {
203
+ return this . client . getJSONAssignmentDetails (
204
+ flagKey ,
205
+ this . subjectKey ,
206
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes ) ,
207
+ defaultValue
208
+ ) ;
209
+ }
210
+
211
+ public getBanditAction (
212
+ flagKey : string ,
213
+ defaultValue : string ,
214
+ ) : Omit < IAssignmentDetails < string > , 'evaluationDetails' > {
215
+ return this . client . getBanditAction ( flagKey , this . subjectKey , this . subjectAttributes , this . banditActions ?. [ flagKey ] ?? { } , defaultValue ) ;
216
+ }
217
+
218
+
219
+ public getBanditActionDetails (
220
+ flagKey : string ,
221
+ defaultValue : string ,
222
+ ) : IAssignmentDetails < string > {
223
+ return this . client . getBanditActionDetails ( flagKey , this . subjectKey , this . subjectAttributes , this . banditActions ?. [ flagKey ] ?? { } , defaultValue ) ;
224
+ }
225
+
226
+ /**
227
+ * Evaluates the supplied actions using the first bandit associated with `flagKey` and returns the best ranked action.
228
+ *
229
+ * This method should be considered **preview** and is subject to change as requirements mature.
230
+ *
231
+ * NOTE: This method does not do any logging or assignment computation and so calling this method will have
232
+ * NO IMPACT on bandit and experiment training.
233
+ *
234
+ * Only use this method under certain circumstances (i.e. where the impact of the choice of bandit cannot be measured,
235
+ * but you want to put the "best foot forward", for example, when being web-crawled).
236
+ */
237
+ public getBestAction (
238
+ flagKey : string ,
239
+ defaultAction : string ,
240
+ ) : string {
241
+ return this . client . getBestAction ( flagKey , this . subjectAttributes , this . banditActions ?. [ flagKey ] ?? { } , defaultAction ) ;
242
+ }
243
+
244
+ /**
245
+ * For use with 3rd party CMS tooling, such as the Contentful Eppo plugin.
246
+ *
247
+ * CMS plugins that integrate with Eppo will follow a common format for
248
+ * creating a feature flag. The flag created by the CMS plugin will have
249
+ * variations with values 'control', 'treatment-1', 'treatment-2', etc.
250
+ * This function allows users to easily return the CMS container entry
251
+ * for the assigned variation.
252
+ *
253
+ * @param flagExperiment the flag key, control container entry and treatment container entries.
254
+ * @returns The container entry associated with the experiment.
255
+ */
256
+ public getExperimentContainerEntry < T > ( flagExperiment : IContainerExperiment < T > ) : T {
257
+ return this . client . getExperimentContainerEntry (
258
+ flagExperiment ,
259
+ this . subjectKey ,
260
+ ensureNonContextualSubjectAttributes ( this . subjectAttributes )
261
+ ) ;
262
+ }
263
+
264
+ /**
265
+ * Computes and returns assignments and bandits for the configured subject from all loaded flags.
266
+ *
267
+ * @returns A JSON string containing the precomputed configuration
268
+ */
269
+ public getPrecomputedConfiguration ( ) : Configuration {
270
+ return this . client . getPrecomputedConfiguration (
271
+ this . subjectKey ,
272
+ this . subjectAttributes ,
273
+ this . banditActions || { } ,
274
+ ) ;
275
+ }
276
+
277
+ /**
278
+ * Waits for the client to finish initialization sequence and be ready to serve assignments.
279
+ *
280
+ * @returns A promise that resolves when the client is initialized.
281
+ */
282
+ public waitForInitialization ( ) : Promise < void > {
283
+ return this . client . waitForInitialization ( ) ;
284
+ }
285
+ }
0 commit comments