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