@featurevisor/sdk 1.20.0 → 1.27.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.eslintcache +1 -1
  2. package/CHANGELOG.md +11 -0
  3. package/coverage/clover.xml +2 -2
  4. package/coverage/lcov-report/bucket.ts.html +1 -1
  5. package/coverage/lcov-report/conditions.ts.html +1 -1
  6. package/coverage/lcov-report/datafileReader.ts.html +1 -1
  7. package/coverage/lcov-report/emitter.ts.html +1 -1
  8. package/coverage/lcov-report/feature.ts.html +1 -1
  9. package/coverage/lcov-report/index.html +1 -1
  10. package/coverage/lcov-report/instance.ts.html +1 -1
  11. package/coverage/lcov-report/logger.ts.html +1 -1
  12. package/coverage/lcov-report/segments.ts.html +1 -1
  13. package/dist/bucket.d.ts +2 -0
  14. package/dist/conditions.d.ts +4 -0
  15. package/dist/datafileReader.d.ts +16 -0
  16. package/dist/emitter.d.ts +12 -0
  17. package/dist/feature.d.ts +16 -0
  18. package/{lib/index.js → dist/index.d.ts} +0 -1
  19. package/dist/index.js +1 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +2 -0
  22. package/dist/index.mjs.gz +0 -0
  23. package/dist/index.mjs.map +1 -0
  24. package/dist/instance.d.ts +140 -0
  25. package/dist/logger.d.ts +25 -0
  26. package/dist/segments.d.ts +5 -0
  27. package/package.json +15 -7
  28. package/webpack.config.js +77 -10
  29. package/dist/index.js.gz +0 -0
  30. package/lib/bucket.js +0 -10
  31. package/lib/bucket.js.map +0 -1
  32. package/lib/bucket.spec.d.ts +0 -1
  33. package/lib/conditions.js +0 -115
  34. package/lib/conditions.js.map +0 -1
  35. package/lib/conditions.spec.d.ts +0 -1
  36. package/lib/datafileReader.js +0 -49
  37. package/lib/datafileReader.js.map +0 -1
  38. package/lib/datafileReader.spec.d.ts +0 -1
  39. package/lib/emitter.js +0 -46
  40. package/lib/emitter.js.map +0 -1
  41. package/lib/emitter.spec.d.ts +0 -1
  42. package/lib/feature.js +0 -68
  43. package/lib/feature.js.map +0 -1
  44. package/lib/index.js.map +0 -1
  45. package/lib/index.spec.d.ts +0 -0
  46. package/lib/instance.js +0 -926
  47. package/lib/instance.js.map +0 -1
  48. package/lib/instance.spec.d.ts +0 -1
  49. package/lib/logger.js +0 -61
  50. package/lib/logger.js.map +0 -1
  51. package/lib/logger.spec.d.ts +0 -1
  52. package/lib/segments.js +0 -40
  53. package/lib/segments.js.map +0 -1
  54. package/lib/segments.spec.d.ts +0 -1
package/lib/instance.js DELETED
@@ -1,926 +0,0 @@
1
- import { createLogger } from "./logger";
2
- import { DatafileReader } from "./datafileReader";
3
- import { Emitter } from "./emitter";
4
- import { getBucketedNumber } from "./bucket";
5
- import { findForceFromFeature, getMatchedTraffic, getMatchedTrafficAndAllocation, parseFromStringifiedSegments, } from "./feature";
6
- import { allConditionsAreMatched } from "./conditions";
7
- import { allGroupSegmentsAreMatched } from "./segments";
8
- var DEFAULT_BUCKET_KEY_SEPARATOR = ".";
9
- var emptyDatafile = {
10
- schemaVersion: "1",
11
- revision: "unknown",
12
- attributes: [],
13
- segments: [],
14
- features: [],
15
- };
16
- export var EvaluationReason;
17
- (function (EvaluationReason) {
18
- EvaluationReason["NOT_FOUND"] = "not_found";
19
- EvaluationReason["NO_VARIATIONS"] = "no_variations";
20
- EvaluationReason["NO_MATCH"] = "no_match";
21
- EvaluationReason["DISABLED"] = "disabled";
22
- EvaluationReason["REQUIRED"] = "required";
23
- EvaluationReason["OUT_OF_RANGE"] = "out_of_range";
24
- EvaluationReason["FORCED"] = "forced";
25
- EvaluationReason["INITIAL"] = "initial";
26
- EvaluationReason["STICKY"] = "sticky";
27
- EvaluationReason["RULE"] = "rule";
28
- EvaluationReason["ALLOCATED"] = "allocated";
29
- EvaluationReason["DEFAULTED"] = "defaulted";
30
- EvaluationReason["OVERRIDE"] = "override";
31
- EvaluationReason["ERROR"] = "error";
32
- })(EvaluationReason || (EvaluationReason = {}));
33
- function fetchDatafileContent(datafileUrl, handleDatafileFetch) {
34
- if (handleDatafileFetch) {
35
- return handleDatafileFetch(datafileUrl);
36
- }
37
- return fetch(datafileUrl).then(function (res) { return res.json(); });
38
- }
39
- export function getValueByType(value, fieldType) {
40
- try {
41
- if (value === undefined) {
42
- return undefined;
43
- }
44
- switch (fieldType) {
45
- case "string":
46
- return typeof value === "string" ? value : undefined;
47
- case "integer":
48
- return parseInt(value, 10);
49
- case "double":
50
- return parseFloat(value);
51
- case "boolean":
52
- return value === true;
53
- case "array":
54
- return Array.isArray(value) ? value : undefined;
55
- case "object":
56
- return typeof value === "object" ? value : undefined;
57
- // @NOTE: `json` is not handled here intentionally
58
- default:
59
- return value;
60
- }
61
- }
62
- catch (e) {
63
- return undefined;
64
- }
65
- }
66
- var FeaturevisorInstance = /** @class */ (function () {
67
- function FeaturevisorInstance(options) {
68
- var _this = this;
69
- // from options
70
- this.bucketKeySeparator = options.bucketKeySeparator || DEFAULT_BUCKET_KEY_SEPARATOR;
71
- this.configureBucketKey = options.configureBucketKey;
72
- this.configureBucketValue = options.configureBucketValue;
73
- this.datafileUrl = options.datafileUrl;
74
- this.handleDatafileFetch = options.handleDatafileFetch;
75
- this.initialFeatures = options.initialFeatures;
76
- this.interceptContext = options.interceptContext;
77
- this.logger = options.logger || createLogger();
78
- this.refreshInterval = options.refreshInterval;
79
- this.stickyFeatures = options.stickyFeatures;
80
- // internal
81
- this.emitter = new Emitter();
82
- this.statuses = {
83
- ready: false,
84
- refreshInProgress: false,
85
- };
86
- // register events
87
- if (options.onReady) {
88
- this.emitter.addListener("ready", options.onReady);
89
- }
90
- if (options.onRefresh) {
91
- this.emitter.addListener("refresh", options.onRefresh);
92
- }
93
- if (options.onUpdate) {
94
- this.emitter.addListener("update", options.onUpdate);
95
- }
96
- if (options.onActivation) {
97
- this.emitter.addListener("activation", options.onActivation);
98
- }
99
- // expose emitter methods
100
- var on = this.emitter.addListener.bind(this.emitter);
101
- this.on = on;
102
- this.addListener = on;
103
- var off = this.emitter.removeListener.bind(this.emitter);
104
- this.off = off;
105
- this.removeListener = off;
106
- this.removeAllListeners = this.emitter.removeAllListeners.bind(this.emitter);
107
- // datafile
108
- if (options.datafileUrl) {
109
- this.setDatafile(options.datafile || emptyDatafile);
110
- fetchDatafileContent(options.datafileUrl, options.handleDatafileFetch)
111
- .then(function (datafile) {
112
- _this.setDatafile(datafile);
113
- _this.statuses.ready = true;
114
- _this.emitter.emit("ready");
115
- if (_this.refreshInterval) {
116
- _this.startRefreshing();
117
- }
118
- })
119
- .catch(function (e) {
120
- _this.logger.error("failed to fetch datafile", { error: e });
121
- });
122
- }
123
- else if (options.datafile) {
124
- this.setDatafile(options.datafile);
125
- this.statuses.ready = true;
126
- setTimeout(function () {
127
- _this.emitter.emit("ready");
128
- }, 0);
129
- }
130
- else {
131
- throw new Error("Featurevisor SDK instance cannot be created without both `datafile` and `datafileUrl` options");
132
- }
133
- }
134
- FeaturevisorInstance.prototype.setLogLevels = function (levels) {
135
- this.logger.setLevels(levels);
136
- };
137
- FeaturevisorInstance.prototype.onReady = function () {
138
- var _this = this;
139
- return new Promise(function (resolve) {
140
- if (_this.statuses.ready) {
141
- return resolve(_this);
142
- }
143
- var cb = function () {
144
- _this.emitter.removeListener("ready", cb);
145
- resolve(_this);
146
- };
147
- _this.emitter.addListener("ready", cb);
148
- });
149
- };
150
- FeaturevisorInstance.prototype.setDatafile = function (datafile) {
151
- try {
152
- this.datafileReader = new DatafileReader(typeof datafile === "string" ? JSON.parse(datafile) : datafile);
153
- }
154
- catch (e) {
155
- this.logger.error("could not parse datafile", { error: e });
156
- }
157
- };
158
- FeaturevisorInstance.prototype.setStickyFeatures = function (stickyFeatures) {
159
- this.stickyFeatures = stickyFeatures;
160
- };
161
- FeaturevisorInstance.prototype.getRevision = function () {
162
- return this.datafileReader.getRevision();
163
- };
164
- FeaturevisorInstance.prototype.getFeature = function (featureKey) {
165
- return typeof featureKey === "string"
166
- ? this.datafileReader.getFeature(featureKey) // only key provided
167
- : featureKey; // full feature provided
168
- };
169
- /**
170
- * Bucketing
171
- */
172
- FeaturevisorInstance.prototype.getBucketKey = function (feature, context) {
173
- var featureKey = feature.key;
174
- var type;
175
- var attributeKeys;
176
- if (typeof feature.bucketBy === "string") {
177
- type = "plain";
178
- attributeKeys = [feature.bucketBy];
179
- }
180
- else if (Array.isArray(feature.bucketBy)) {
181
- type = "and";
182
- attributeKeys = feature.bucketBy;
183
- }
184
- else if (typeof feature.bucketBy === "object" && Array.isArray(feature.bucketBy.or)) {
185
- type = "or";
186
- attributeKeys = feature.bucketBy.or;
187
- }
188
- else {
189
- this.logger.error("invalid bucketBy", { featureKey: featureKey, bucketBy: feature.bucketBy });
190
- throw new Error("invalid bucketBy");
191
- }
192
- var bucketKey = [];
193
- attributeKeys.forEach(function (attributeKey) {
194
- var attributeValue = context[attributeKey];
195
- if (typeof attributeValue === "undefined") {
196
- return;
197
- }
198
- if (type === "plain" || type === "and") {
199
- bucketKey.push(attributeValue);
200
- }
201
- else {
202
- // or
203
- if (bucketKey.length === 0) {
204
- bucketKey.push(attributeValue);
205
- }
206
- }
207
- });
208
- bucketKey.push(featureKey);
209
- var result = bucketKey.join(this.bucketKeySeparator);
210
- if (this.configureBucketKey) {
211
- return this.configureBucketKey(feature, context, result);
212
- }
213
- return result;
214
- };
215
- FeaturevisorInstance.prototype.getBucketValue = function (feature, context) {
216
- var bucketKey = this.getBucketKey(feature, context);
217
- var value = getBucketedNumber(bucketKey);
218
- if (this.configureBucketValue) {
219
- var configuredValue = this.configureBucketValue(feature, context, value);
220
- return {
221
- bucketKey: bucketKey,
222
- bucketValue: configuredValue,
223
- };
224
- }
225
- return {
226
- bucketKey: bucketKey,
227
- bucketValue: value,
228
- };
229
- };
230
- /**
231
- * Statuses
232
- */
233
- FeaturevisorInstance.prototype.isReady = function () {
234
- return this.statuses.ready;
235
- };
236
- /**
237
- * Refresh
238
- */
239
- FeaturevisorInstance.prototype.refresh = function () {
240
- var _this = this;
241
- this.logger.debug("refreshing datafile");
242
- if (this.statuses.refreshInProgress) {
243
- return this.logger.warn("refresh in progress, skipping");
244
- }
245
- if (!this.datafileUrl) {
246
- return this.logger.error("cannot refresh since `datafileUrl` is not provided");
247
- }
248
- this.statuses.refreshInProgress = true;
249
- fetchDatafileContent(this.datafileUrl, this.handleDatafileFetch)
250
- .then(function (datafile) {
251
- var currentRevision = _this.getRevision();
252
- var newRevision = datafile.revision;
253
- var isNotSameRevision = currentRevision !== newRevision;
254
- _this.setDatafile(datafile);
255
- _this.logger.info("refreshed datafile");
256
- _this.emitter.emit("refresh");
257
- if (isNotSameRevision) {
258
- _this.emitter.emit("update");
259
- }
260
- _this.statuses.refreshInProgress = false;
261
- })
262
- .catch(function (e) {
263
- _this.logger.error("failed to refresh datafile", { error: e });
264
- _this.statuses.refreshInProgress = false;
265
- });
266
- };
267
- FeaturevisorInstance.prototype.startRefreshing = function () {
268
- var _this = this;
269
- if (!this.datafileUrl) {
270
- return this.logger.error("cannot start refreshing since `datafileUrl` is not provided");
271
- }
272
- if (this.intervalId) {
273
- return this.logger.warn("refreshing has already started");
274
- }
275
- if (!this.refreshInterval) {
276
- return this.logger.warn("no `refreshInterval` option provided");
277
- }
278
- this.intervalId = setInterval(function () {
279
- _this.refresh();
280
- }, this.refreshInterval * 1000);
281
- };
282
- FeaturevisorInstance.prototype.stopRefreshing = function () {
283
- if (!this.intervalId) {
284
- return this.logger.warn("refreshing has not started yet");
285
- }
286
- clearInterval(this.intervalId);
287
- };
288
- /**
289
- * Flag
290
- */
291
- FeaturevisorInstance.prototype.evaluateFlag = function (featureKey, context) {
292
- var _this = this;
293
- if (context === void 0) { context = {}; }
294
- var evaluation;
295
- try {
296
- var key = typeof featureKey === "string" ? featureKey : featureKey.key;
297
- // sticky
298
- if (this.stickyFeatures &&
299
- this.stickyFeatures[key] &&
300
- typeof this.stickyFeatures[key].enabled !== "undefined") {
301
- evaluation = {
302
- featureKey: key,
303
- reason: EvaluationReason.STICKY,
304
- sticky: this.stickyFeatures[key],
305
- enabled: this.stickyFeatures[key].enabled,
306
- };
307
- this.logger.debug("using sticky enabled", evaluation);
308
- return evaluation;
309
- }
310
- // initial
311
- if (this.statuses &&
312
- !this.statuses.ready &&
313
- this.initialFeatures &&
314
- this.initialFeatures[key] &&
315
- typeof this.initialFeatures[key].enabled !== "undefined") {
316
- evaluation = {
317
- featureKey: key,
318
- reason: EvaluationReason.INITIAL,
319
- initial: this.initialFeatures[key],
320
- enabled: this.initialFeatures[key].enabled,
321
- };
322
- this.logger.debug("using initial enabled", evaluation);
323
- return evaluation;
324
- }
325
- var feature = this.getFeature(featureKey);
326
- // not found
327
- if (!feature) {
328
- evaluation = {
329
- featureKey: key,
330
- reason: EvaluationReason.NOT_FOUND,
331
- };
332
- this.logger.warn("feature not found", evaluation);
333
- return evaluation;
334
- }
335
- // deprecated
336
- if (feature.deprecated) {
337
- this.logger.warn("feature is deprecated", { featureKey: feature.key });
338
- }
339
- var finalContext_1 = this.interceptContext ? this.interceptContext(context) : context;
340
- // forced
341
- var _a = findForceFromFeature(feature, context, this.datafileReader, this.logger), force = _a.force, forceIndex = _a.forceIndex;
342
- if (force && typeof force.enabled !== "undefined") {
343
- evaluation = {
344
- featureKey: feature.key,
345
- reason: EvaluationReason.FORCED,
346
- forceIndex: forceIndex,
347
- force: force,
348
- enabled: force.enabled,
349
- };
350
- this.logger.debug("forced enabled found", evaluation);
351
- return evaluation;
352
- }
353
- // required
354
- if (feature.required && feature.required.length > 0) {
355
- var requiredFeaturesAreEnabled = feature.required.every(function (required) {
356
- var requiredKey;
357
- var requiredVariation;
358
- if (typeof required === "string") {
359
- requiredKey = required;
360
- }
361
- else {
362
- requiredKey = required.key;
363
- requiredVariation = required.variation;
364
- }
365
- var requiredIsEnabled = _this.isEnabled(requiredKey, finalContext_1);
366
- if (!requiredIsEnabled) {
367
- return false;
368
- }
369
- if (typeof requiredVariation !== "undefined") {
370
- var requiredVariationValue = _this.getVariation(requiredKey, finalContext_1);
371
- return requiredVariationValue === requiredVariation;
372
- }
373
- return true;
374
- });
375
- if (!requiredFeaturesAreEnabled) {
376
- evaluation = {
377
- featureKey: feature.key,
378
- reason: EvaluationReason.REQUIRED,
379
- required: feature.required,
380
- enabled: requiredFeaturesAreEnabled,
381
- };
382
- this.logger.debug("required features not enabled", evaluation);
383
- return evaluation;
384
- }
385
- }
386
- // bucketing
387
- var _b = this.getBucketValue(feature, finalContext_1), bucketKey = _b.bucketKey, bucketValue_1 = _b.bucketValue;
388
- var matchedTraffic = getMatchedTraffic(feature.traffic, finalContext_1, this.datafileReader, this.logger);
389
- if (matchedTraffic) {
390
- // check if mutually exclusive
391
- if (feature.ranges && feature.ranges.length > 0) {
392
- var matchedRange = feature.ranges.find(function (range) {
393
- return bucketValue_1 >= range[0] && bucketValue_1 < range[1];
394
- });
395
- // matched
396
- if (matchedRange) {
397
- evaluation = {
398
- featureKey: feature.key,
399
- reason: EvaluationReason.ALLOCATED,
400
- bucketKey: bucketKey,
401
- bucketValue: bucketValue_1,
402
- ruleKey: matchedTraffic.key,
403
- traffic: matchedTraffic,
404
- enabled: typeof matchedTraffic.enabled === "undefined" ? true : matchedTraffic.enabled,
405
- };
406
- this.logger.debug("matched", evaluation);
407
- return evaluation;
408
- }
409
- // no match
410
- evaluation = {
411
- featureKey: feature.key,
412
- reason: EvaluationReason.OUT_OF_RANGE,
413
- bucketKey: bucketKey,
414
- bucketValue: bucketValue_1,
415
- enabled: false,
416
- };
417
- this.logger.debug("not matched", evaluation);
418
- return evaluation;
419
- }
420
- // override from rule
421
- if (typeof matchedTraffic.enabled !== "undefined") {
422
- evaluation = {
423
- featureKey: feature.key,
424
- reason: EvaluationReason.OVERRIDE,
425
- bucketKey: bucketKey,
426
- bucketValue: bucketValue_1,
427
- ruleKey: matchedTraffic.key,
428
- traffic: matchedTraffic,
429
- enabled: matchedTraffic.enabled,
430
- };
431
- this.logger.debug("override from rule", evaluation);
432
- return evaluation;
433
- }
434
- // treated as enabled because of matched traffic
435
- if (bucketValue_1 <= matchedTraffic.percentage) {
436
- evaluation = {
437
- featureKey: feature.key,
438
- reason: EvaluationReason.RULE,
439
- bucketKey: bucketKey,
440
- bucketValue: bucketValue_1,
441
- ruleKey: matchedTraffic.key,
442
- traffic: matchedTraffic,
443
- enabled: true,
444
- };
445
- this.logger.debug("matched traffic", evaluation);
446
- return evaluation;
447
- }
448
- }
449
- // nothing matched
450
- evaluation = {
451
- featureKey: feature.key,
452
- reason: EvaluationReason.NO_MATCH,
453
- bucketKey: bucketKey,
454
- bucketValue: bucketValue_1,
455
- enabled: false,
456
- };
457
- this.logger.debug("nothing matched", evaluation);
458
- return evaluation;
459
- }
460
- catch (e) {
461
- evaluation = {
462
- featureKey: typeof featureKey === "string" ? featureKey : featureKey.key,
463
- reason: EvaluationReason.ERROR,
464
- error: e,
465
- };
466
- this.logger.error("error", evaluation);
467
- return evaluation;
468
- }
469
- };
470
- FeaturevisorInstance.prototype.isEnabled = function (featureKey, context) {
471
- if (context === void 0) { context = {}; }
472
- try {
473
- var evaluation = this.evaluateFlag(featureKey, context);
474
- return evaluation.enabled === true;
475
- }
476
- catch (e) {
477
- this.logger.error("isEnabled", { featureKey: featureKey, error: e });
478
- return false;
479
- }
480
- };
481
- /**
482
- * Variation
483
- */
484
- FeaturevisorInstance.prototype.evaluateVariation = function (featureKey, context) {
485
- if (context === void 0) { context = {}; }
486
- var evaluation;
487
- try {
488
- var key = typeof featureKey === "string" ? featureKey : featureKey.key;
489
- var flag = this.evaluateFlag(featureKey, context);
490
- if (flag.enabled === false) {
491
- evaluation = {
492
- featureKey: key,
493
- reason: EvaluationReason.DISABLED,
494
- };
495
- this.logger.debug("feature is disabled", evaluation);
496
- return evaluation;
497
- }
498
- // sticky
499
- if (this.stickyFeatures && this.stickyFeatures[key]) {
500
- var variationValue = this.stickyFeatures[key].variation;
501
- if (typeof variationValue !== "undefined") {
502
- evaluation = {
503
- featureKey: key,
504
- reason: EvaluationReason.STICKY,
505
- variationValue: variationValue,
506
- };
507
- this.logger.debug("using sticky variation", evaluation);
508
- return evaluation;
509
- }
510
- }
511
- // initial
512
- if (this.statuses &&
513
- !this.statuses.ready &&
514
- this.initialFeatures &&
515
- this.initialFeatures[key] &&
516
- typeof this.initialFeatures[key].variation !== "undefined") {
517
- var variationValue = this.initialFeatures[key].variation;
518
- evaluation = {
519
- featureKey: key,
520
- reason: EvaluationReason.INITIAL,
521
- variationValue: variationValue,
522
- };
523
- this.logger.debug("using initial variation", evaluation);
524
- return evaluation;
525
- }
526
- var feature = this.getFeature(featureKey);
527
- // not found
528
- if (!feature) {
529
- evaluation = {
530
- featureKey: key,
531
- reason: EvaluationReason.NOT_FOUND,
532
- };
533
- this.logger.warn("feature not found", evaluation);
534
- return evaluation;
535
- }
536
- // no variations
537
- if (!feature.variations || feature.variations.length === 0) {
538
- evaluation = {
539
- featureKey: key,
540
- reason: EvaluationReason.NO_VARIATIONS,
541
- };
542
- this.logger.warn("no variations", evaluation);
543
- return evaluation;
544
- }
545
- var finalContext = this.interceptContext ? this.interceptContext(context) : context;
546
- // forced
547
- var _a = findForceFromFeature(feature, context, this.datafileReader, this.logger), force_1 = _a.force, forceIndex = _a.forceIndex;
548
- if (force_1 && force_1.variation) {
549
- var variation = feature.variations.find(function (v) { return v.value === force_1.variation; });
550
- if (variation) {
551
- evaluation = {
552
- featureKey: feature.key,
553
- reason: EvaluationReason.FORCED,
554
- forceIndex: forceIndex,
555
- force: force_1,
556
- variation: variation,
557
- };
558
- this.logger.debug("forced variation found", evaluation);
559
- return evaluation;
560
- }
561
- }
562
- // bucketing
563
- var _b = this.getBucketValue(feature, finalContext), bucketKey = _b.bucketKey, bucketValue = _b.bucketValue;
564
- var _c = getMatchedTrafficAndAllocation(feature.traffic, finalContext, bucketValue, this.datafileReader, this.logger), matchedTraffic_1 = _c.matchedTraffic, matchedAllocation_1 = _c.matchedAllocation;
565
- if (matchedTraffic_1) {
566
- // override from rule
567
- if (matchedTraffic_1.variation) {
568
- var variation = feature.variations.find(function (v) { return v.value === matchedTraffic_1.variation; });
569
- if (variation) {
570
- evaluation = {
571
- featureKey: feature.key,
572
- reason: EvaluationReason.RULE,
573
- bucketKey: bucketKey,
574
- bucketValue: bucketValue,
575
- ruleKey: matchedTraffic_1.key,
576
- traffic: matchedTraffic_1,
577
- variation: variation,
578
- };
579
- this.logger.debug("override from rule", evaluation);
580
- return evaluation;
581
- }
582
- }
583
- // regular allocation
584
- if (matchedAllocation_1 && matchedAllocation_1.variation) {
585
- var variation = feature.variations.find(function (v) { return v.value === matchedAllocation_1.variation; });
586
- if (variation) {
587
- evaluation = {
588
- featureKey: feature.key,
589
- reason: EvaluationReason.ALLOCATED,
590
- bucketKey: bucketKey,
591
- bucketValue: bucketValue,
592
- ruleKey: matchedTraffic_1.key,
593
- traffic: matchedTraffic_1,
594
- variation: variation,
595
- };
596
- this.logger.debug("allocated variation", evaluation);
597
- return evaluation;
598
- }
599
- }
600
- }
601
- // nothing matched
602
- evaluation = {
603
- featureKey: feature.key,
604
- reason: EvaluationReason.NO_MATCH,
605
- bucketKey: bucketKey,
606
- bucketValue: bucketValue,
607
- };
608
- this.logger.debug("no matched variation", evaluation);
609
- return evaluation;
610
- }
611
- catch (e) {
612
- evaluation = {
613
- featureKey: typeof featureKey === "string" ? featureKey : featureKey.key,
614
- reason: EvaluationReason.ERROR,
615
- error: e,
616
- };
617
- this.logger.error("error", evaluation);
618
- return evaluation;
619
- }
620
- };
621
- FeaturevisorInstance.prototype.getVariation = function (featureKey, context) {
622
- if (context === void 0) { context = {}; }
623
- try {
624
- var evaluation = this.evaluateVariation(featureKey, context);
625
- if (typeof evaluation.variationValue !== "undefined") {
626
- return evaluation.variationValue;
627
- }
628
- if (evaluation.variation) {
629
- return evaluation.variation.value;
630
- }
631
- return undefined;
632
- }
633
- catch (e) {
634
- this.logger.error("getVariation", { featureKey: featureKey, error: e });
635
- return undefined;
636
- }
637
- };
638
- /**
639
- * Activate
640
- */
641
- FeaturevisorInstance.prototype.activate = function (featureKey, context) {
642
- if (context === void 0) { context = {}; }
643
- try {
644
- var evaluation = this.evaluateVariation(featureKey, context);
645
- var variationValue = evaluation.variation
646
- ? evaluation.variation.value
647
- : evaluation.variationValue;
648
- if (typeof variationValue === "undefined") {
649
- return undefined;
650
- }
651
- var finalContext_2 = this.interceptContext ? this.interceptContext(context) : context;
652
- var captureContext_1 = {};
653
- var attributesForCapturing = this.datafileReader
654
- .getAllAttributes()
655
- .filter(function (a) { return a.capture === true; });
656
- attributesForCapturing.forEach(function (a) {
657
- if (typeof finalContext_2[a.key] !== "undefined") {
658
- captureContext_1[a.key] = context[a.key];
659
- }
660
- });
661
- this.emitter.emit("activation", featureKey, variationValue, finalContext_2, captureContext_1, evaluation);
662
- return variationValue;
663
- }
664
- catch (e) {
665
- this.logger.error("activate", { featureKey: featureKey, error: e });
666
- return undefined;
667
- }
668
- };
669
- /**
670
- * Variable
671
- */
672
- FeaturevisorInstance.prototype.evaluateVariable = function (featureKey, variableKey, context) {
673
- var _this = this;
674
- if (context === void 0) { context = {}; }
675
- var evaluation;
676
- try {
677
- var key = typeof featureKey === "string" ? featureKey : featureKey.key;
678
- var flag = this.evaluateFlag(featureKey, context);
679
- if (flag.enabled === false) {
680
- evaluation = {
681
- featureKey: key,
682
- reason: EvaluationReason.DISABLED,
683
- };
684
- this.logger.debug("feature is disabled", evaluation);
685
- return evaluation;
686
- }
687
- // sticky
688
- if (this.stickyFeatures && this.stickyFeatures[key]) {
689
- var variables = this.stickyFeatures[key].variables;
690
- if (variables) {
691
- var result = variables[variableKey];
692
- if (typeof result !== "undefined") {
693
- evaluation = {
694
- featureKey: key,
695
- reason: EvaluationReason.STICKY,
696
- variableKey: variableKey,
697
- variableValue: result,
698
- };
699
- this.logger.debug("using sticky variable", evaluation);
700
- return evaluation;
701
- }
702
- }
703
- }
704
- // initial
705
- if (this.statuses &&
706
- !this.statuses.ready &&
707
- this.initialFeatures &&
708
- this.initialFeatures[key]) {
709
- var variables = this.initialFeatures[key].variables;
710
- if (variables) {
711
- if (typeof variables[variableKey] !== "undefined") {
712
- evaluation = {
713
- featureKey: key,
714
- reason: EvaluationReason.INITIAL,
715
- variableKey: variableKey,
716
- variableValue: variables[variableKey],
717
- };
718
- this.logger.debug("using initial variable", evaluation);
719
- return evaluation;
720
- }
721
- }
722
- }
723
- var feature = this.getFeature(featureKey);
724
- // not found
725
- if (!feature) {
726
- evaluation = {
727
- featureKey: key,
728
- reason: EvaluationReason.NOT_FOUND,
729
- variableKey: variableKey,
730
- };
731
- this.logger.warn("feature not found in datafile", evaluation);
732
- return evaluation;
733
- }
734
- var variableSchema = Array.isArray(feature.variablesSchema)
735
- ? feature.variablesSchema.find(function (v) { return v.key === variableKey; })
736
- : undefined;
737
- // variable schema not found
738
- if (!variableSchema) {
739
- evaluation = {
740
- featureKey: key,
741
- reason: EvaluationReason.NOT_FOUND,
742
- variableKey: variableKey,
743
- };
744
- this.logger.warn("variable schema not found", evaluation);
745
- return evaluation;
746
- }
747
- var finalContext_3 = this.interceptContext ? this.interceptContext(context) : context;
748
- // forced
749
- var _a = findForceFromFeature(feature, context, this.datafileReader, this.logger), force = _a.force, forceIndex = _a.forceIndex;
750
- if (force && force.variables && typeof force.variables[variableKey] !== "undefined") {
751
- evaluation = {
752
- featureKey: feature.key,
753
- reason: EvaluationReason.FORCED,
754
- forceIndex: forceIndex,
755
- force: force,
756
- variableKey: variableKey,
757
- variableSchema: variableSchema,
758
- variableValue: force.variables[variableKey],
759
- };
760
- this.logger.debug("forced variable", evaluation);
761
- return evaluation;
762
- }
763
- // bucketing
764
- var _b = this.getBucketValue(feature, finalContext_3), bucketKey = _b.bucketKey, bucketValue = _b.bucketValue;
765
- var _c = getMatchedTrafficAndAllocation(feature.traffic, finalContext_3, bucketValue, this.datafileReader, this.logger), matchedTraffic = _c.matchedTraffic, matchedAllocation = _c.matchedAllocation;
766
- if (matchedTraffic) {
767
- // override from rule
768
- if (matchedTraffic.variables &&
769
- typeof matchedTraffic.variables[variableKey] !== "undefined") {
770
- evaluation = {
771
- featureKey: feature.key,
772
- reason: EvaluationReason.RULE,
773
- bucketKey: bucketKey,
774
- bucketValue: bucketValue,
775
- ruleKey: matchedTraffic.key,
776
- traffic: matchedTraffic,
777
- variableKey: variableKey,
778
- variableSchema: variableSchema,
779
- variableValue: matchedTraffic.variables[variableKey],
780
- };
781
- this.logger.debug("override from rule", evaluation);
782
- return evaluation;
783
- }
784
- // regular allocation
785
- var variationValue_1;
786
- if (force && force.variation) {
787
- variationValue_1 = force.variation;
788
- }
789
- else if (matchedAllocation && matchedAllocation.variation) {
790
- variationValue_1 = matchedAllocation.variation;
791
- }
792
- if (variationValue_1 && Array.isArray(feature.variations)) {
793
- var variation = feature.variations.find(function (v) { return v.value === variationValue_1; });
794
- if (variation && variation.variables) {
795
- var variableFromVariation = variation.variables.find(function (v) { return v.key === variableKey; });
796
- if (variableFromVariation) {
797
- if (variableFromVariation.overrides) {
798
- var override = variableFromVariation.overrides.find(function (o) {
799
- if (o.conditions) {
800
- return allConditionsAreMatched(typeof o.conditions === "string" ? JSON.parse(o.conditions) : o.conditions, finalContext_3, _this.logger);
801
- }
802
- if (o.segments) {
803
- return allGroupSegmentsAreMatched(parseFromStringifiedSegments(o.segments), finalContext_3, _this.datafileReader, _this.logger);
804
- }
805
- return false;
806
- });
807
- if (override) {
808
- evaluation = {
809
- featureKey: feature.key,
810
- reason: EvaluationReason.OVERRIDE,
811
- bucketKey: bucketKey,
812
- bucketValue: bucketValue,
813
- ruleKey: matchedTraffic.key,
814
- traffic: matchedTraffic,
815
- variableKey: variableKey,
816
- variableSchema: variableSchema,
817
- variableValue: override.value,
818
- };
819
- this.logger.debug("variable override", evaluation);
820
- return evaluation;
821
- }
822
- }
823
- if (typeof variableFromVariation.value !== "undefined") {
824
- evaluation = {
825
- featureKey: feature.key,
826
- reason: EvaluationReason.ALLOCATED,
827
- bucketKey: bucketKey,
828
- bucketValue: bucketValue,
829
- ruleKey: matchedTraffic.key,
830
- traffic: matchedTraffic,
831
- variableKey: variableKey,
832
- variableSchema: variableSchema,
833
- variableValue: variableFromVariation.value,
834
- };
835
- this.logger.debug("allocated variable", evaluation);
836
- return evaluation;
837
- }
838
- }
839
- }
840
- }
841
- }
842
- // fall back to default
843
- evaluation = {
844
- featureKey: feature.key,
845
- reason: EvaluationReason.DEFAULTED,
846
- bucketKey: bucketKey,
847
- bucketValue: bucketValue,
848
- variableKey: variableKey,
849
- variableSchema: variableSchema,
850
- variableValue: variableSchema.defaultValue,
851
- };
852
- this.logger.debug("using default value", evaluation);
853
- return evaluation;
854
- }
855
- catch (e) {
856
- evaluation = {
857
- featureKey: typeof featureKey === "string" ? featureKey : featureKey.key,
858
- reason: EvaluationReason.ERROR,
859
- variableKey: variableKey,
860
- error: e,
861
- };
862
- this.logger.error("error", evaluation);
863
- return evaluation;
864
- }
865
- };
866
- FeaturevisorInstance.prototype.getVariable = function (featureKey, variableKey, context) {
867
- if (context === void 0) { context = {}; }
868
- try {
869
- var evaluation = this.evaluateVariable(featureKey, variableKey, context);
870
- if (typeof evaluation.variableValue !== "undefined") {
871
- if (evaluation.variableSchema &&
872
- evaluation.variableSchema.type === "json" &&
873
- typeof evaluation.variableValue === "string") {
874
- return JSON.parse(evaluation.variableValue);
875
- }
876
- return evaluation.variableValue;
877
- }
878
- return undefined;
879
- }
880
- catch (e) {
881
- this.logger.error("getVariable", { featureKey: featureKey, variableKey: variableKey, error: e });
882
- return undefined;
883
- }
884
- };
885
- FeaturevisorInstance.prototype.getVariableBoolean = function (featureKey, variableKey, context) {
886
- if (context === void 0) { context = {}; }
887
- var variableValue = this.getVariable(featureKey, variableKey, context);
888
- return getValueByType(variableValue, "boolean");
889
- };
890
- FeaturevisorInstance.prototype.getVariableString = function (featureKey, variableKey, context) {
891
- if (context === void 0) { context = {}; }
892
- var variableValue = this.getVariable(featureKey, variableKey, context);
893
- return getValueByType(variableValue, "string");
894
- };
895
- FeaturevisorInstance.prototype.getVariableInteger = function (featureKey, variableKey, context) {
896
- if (context === void 0) { context = {}; }
897
- var variableValue = this.getVariable(featureKey, variableKey, context);
898
- return getValueByType(variableValue, "integer");
899
- };
900
- FeaturevisorInstance.prototype.getVariableDouble = function (featureKey, variableKey, context) {
901
- if (context === void 0) { context = {}; }
902
- var variableValue = this.getVariable(featureKey, variableKey, context);
903
- return getValueByType(variableValue, "double");
904
- };
905
- FeaturevisorInstance.prototype.getVariableArray = function (featureKey, variableKey, context) {
906
- if (context === void 0) { context = {}; }
907
- var variableValue = this.getVariable(featureKey, variableKey, context);
908
- return getValueByType(variableValue, "array");
909
- };
910
- FeaturevisorInstance.prototype.getVariableObject = function (featureKey, variableKey, context) {
911
- if (context === void 0) { context = {}; }
912
- var variableValue = this.getVariable(featureKey, variableKey, context);
913
- return getValueByType(variableValue, "object");
914
- };
915
- FeaturevisorInstance.prototype.getVariableJSON = function (featureKey, variableKey, context) {
916
- if (context === void 0) { context = {}; }
917
- var variableValue = this.getVariable(featureKey, variableKey, context);
918
- return getValueByType(variableValue, "json");
919
- };
920
- return FeaturevisorInstance;
921
- }());
922
- export { FeaturevisorInstance };
923
- export function createInstance(options) {
924
- return new FeaturevisorInstance(options);
925
- }
926
- //# sourceMappingURL=instance.js.map