@featurevisor/sdk 1.16.0 → 1.17.0

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.
package/src/instance.ts CHANGED
@@ -17,6 +17,8 @@ import {
17
17
  RuleKey,
18
18
  VariableKey,
19
19
  VariableSchema,
20
+ Force,
21
+ Required,
20
22
  } from "@featurevisor/types";
21
23
 
22
24
  import { createLogger, Logger, LogLevel } from "./logger";
@@ -104,11 +106,15 @@ export interface Evaluation {
104
106
  reason: EvaluationReason;
105
107
 
106
108
  // common
109
+ bucketKey?: BucketKey;
107
110
  bucketValue?: BucketValue;
108
111
  ruleKey?: RuleKey;
109
112
  error?: Error;
110
113
  enabled?: boolean;
111
114
  traffic?: Traffic;
115
+ forceIndex?: number;
116
+ force?: Force;
117
+ required?: Required[];
112
118
  sticky?: OverrideFeature;
113
119
  initial?: OverrideFeature;
114
120
 
@@ -368,16 +374,27 @@ export class FeaturevisorInstance {
368
374
  return result;
369
375
  }
370
376
 
371
- private getBucketValue(feature: Feature, context: Context): BucketValue {
377
+ private getBucketValue(
378
+ feature: Feature,
379
+ context: Context,
380
+ ): { bucketKey: BucketKey; bucketValue: BucketValue } {
372
381
  const bucketKey = this.getBucketKey(feature, context);
373
382
 
374
383
  const value = getBucketedNumber(bucketKey);
375
384
 
376
385
  if (this.configureBucketValue) {
377
- return this.configureBucketValue(feature, context, value);
386
+ const configuredValue = this.configureBucketValue(feature, context, value);
387
+
388
+ return {
389
+ bucketKey,
390
+ bucketValue: configuredValue,
391
+ };
378
392
  }
379
393
 
380
- return value;
394
+ return {
395
+ bucketKey,
396
+ bucketValue: value,
397
+ };
381
398
  }
382
399
 
383
400
  /**
@@ -470,8 +487,8 @@ export class FeaturevisorInstance {
470
487
  evaluation = {
471
488
  featureKey: key,
472
489
  reason: EvaluationReason.STICKY,
473
- enabled: this.stickyFeatures[key].enabled,
474
490
  sticky: this.stickyFeatures[key],
491
+ enabled: this.stickyFeatures[key].enabled,
475
492
  };
476
493
 
477
494
  this.logger.debug("using sticky enabled", evaluation);
@@ -490,8 +507,8 @@ export class FeaturevisorInstance {
490
507
  evaluation = {
491
508
  featureKey: key,
492
509
  reason: EvaluationReason.INITIAL,
493
- enabled: this.initialFeatures[key].enabled,
494
510
  initial: this.initialFeatures[key],
511
+ enabled: this.initialFeatures[key].enabled,
495
512
  };
496
513
 
497
514
  this.logger.debug("using initial enabled", evaluation);
@@ -521,12 +538,19 @@ export class FeaturevisorInstance {
521
538
  const finalContext = this.interceptContext ? this.interceptContext(context) : context;
522
539
 
523
540
  // forced
524
- const force = findForceFromFeature(feature, context, this.datafileReader, this.logger);
541
+ const { force, forceIndex } = findForceFromFeature(
542
+ feature,
543
+ context,
544
+ this.datafileReader,
545
+ this.logger,
546
+ );
525
547
 
526
548
  if (force && typeof force.enabled !== "undefined") {
527
549
  evaluation = {
528
550
  featureKey: feature.key,
529
551
  reason: EvaluationReason.FORCED,
552
+ forceIndex,
553
+ force,
530
554
  enabled: force.enabled,
531
555
  };
532
556
 
@@ -567,6 +591,7 @@ export class FeaturevisorInstance {
567
591
  evaluation = {
568
592
  featureKey: feature.key,
569
593
  reason: EvaluationReason.REQUIRED,
594
+ required: feature.required,
570
595
  enabled: requiredFeaturesAreEnabled,
571
596
  };
572
597
 
@@ -577,7 +602,7 @@ export class FeaturevisorInstance {
577
602
  }
578
603
 
579
604
  // bucketing
580
- const bucketValue = this.getBucketValue(feature, finalContext);
605
+ const { bucketKey, bucketValue } = this.getBucketValue(feature, finalContext);
581
606
 
582
607
  const matchedTraffic = getMatchedTraffic(
583
608
  feature.traffic,
@@ -598,9 +623,12 @@ export class FeaturevisorInstance {
598
623
  evaluation = {
599
624
  featureKey: feature.key,
600
625
  reason: EvaluationReason.ALLOCATED,
626
+ bucketKey,
627
+ bucketValue,
628
+ ruleKey: matchedTraffic.key,
629
+ traffic: matchedTraffic,
601
630
  enabled:
602
631
  typeof matchedTraffic.enabled === "undefined" ? true : matchedTraffic.enabled,
603
- bucketValue,
604
632
  };
605
633
 
606
634
  this.logger.debug("matched", evaluation);
@@ -612,8 +640,9 @@ export class FeaturevisorInstance {
612
640
  evaluation = {
613
641
  featureKey: feature.key,
614
642
  reason: EvaluationReason.OUT_OF_RANGE,
615
- enabled: false,
643
+ bucketKey,
616
644
  bucketValue,
645
+ enabled: false,
617
646
  };
618
647
 
619
648
  this.logger.debug("not matched", evaluation);
@@ -626,10 +655,11 @@ export class FeaturevisorInstance {
626
655
  evaluation = {
627
656
  featureKey: feature.key,
628
657
  reason: EvaluationReason.OVERRIDE,
629
- enabled: matchedTraffic.enabled,
658
+ bucketKey,
630
659
  bucketValue,
631
660
  ruleKey: matchedTraffic.key,
632
661
  traffic: matchedTraffic,
662
+ enabled: matchedTraffic.enabled,
633
663
  };
634
664
 
635
665
  this.logger.debug("override from rule", evaluation);
@@ -642,10 +672,11 @@ export class FeaturevisorInstance {
642
672
  evaluation = {
643
673
  featureKey: feature.key,
644
674
  reason: EvaluationReason.RULE,
645
- enabled: true,
675
+ bucketKey,
646
676
  bucketValue,
647
677
  ruleKey: matchedTraffic.key,
648
678
  traffic: matchedTraffic,
679
+ enabled: true,
649
680
  };
650
681
 
651
682
  this.logger.debug("matched traffic", evaluation);
@@ -657,9 +688,10 @@ export class FeaturevisorInstance {
657
688
  // nothing matched
658
689
  evaluation = {
659
690
  featureKey: feature.key,
660
- reason: EvaluationReason.ERROR,
661
- enabled: false,
691
+ reason: EvaluationReason.ERROR, // @TODO: any better reason?
692
+ bucketKey,
662
693
  bucketValue,
694
+ enabled: false,
663
695
  };
664
696
 
665
697
  this.logger.debug("nothing matched", evaluation);
@@ -779,7 +811,12 @@ export class FeaturevisorInstance {
779
811
  const finalContext = this.interceptContext ? this.interceptContext(context) : context;
780
812
 
781
813
  // forced
782
- const force = findForceFromFeature(feature, context, this.datafileReader, this.logger);
814
+ const { force, forceIndex } = findForceFromFeature(
815
+ feature,
816
+ context,
817
+ this.datafileReader,
818
+ this.logger,
819
+ );
783
820
 
784
821
  if (force && force.variation) {
785
822
  const variation = feature.variations.find((v) => v.value === force.variation);
@@ -788,6 +825,8 @@ export class FeaturevisorInstance {
788
825
  evaluation = {
789
826
  featureKey: feature.key,
790
827
  reason: EvaluationReason.FORCED,
828
+ forceIndex,
829
+ force,
791
830
  variation,
792
831
  };
793
832
 
@@ -798,7 +837,7 @@ export class FeaturevisorInstance {
798
837
  }
799
838
 
800
839
  // bucketing
801
- const bucketValue = this.getBucketValue(feature, finalContext);
840
+ const { bucketKey, bucketValue } = this.getBucketValue(feature, finalContext);
802
841
 
803
842
  const { matchedTraffic, matchedAllocation } = getMatchedTrafficAndAllocation(
804
843
  feature.traffic,
@@ -817,9 +856,11 @@ export class FeaturevisorInstance {
817
856
  evaluation = {
818
857
  featureKey: feature.key,
819
858
  reason: EvaluationReason.RULE,
820
- variation,
859
+ bucketKey,
821
860
  bucketValue,
822
861
  ruleKey: matchedTraffic.key,
862
+ traffic: matchedTraffic,
863
+ variation,
823
864
  };
824
865
 
825
866
  this.logger.debug("override from rule", evaluation);
@@ -836,7 +877,10 @@ export class FeaturevisorInstance {
836
877
  evaluation = {
837
878
  featureKey: feature.key,
838
879
  reason: EvaluationReason.ALLOCATED,
880
+ bucketKey,
839
881
  bucketValue,
882
+ ruleKey: matchedTraffic.key,
883
+ traffic: matchedTraffic,
840
884
  variation,
841
885
  };
842
886
 
@@ -850,7 +894,8 @@ export class FeaturevisorInstance {
850
894
  // nothing matched
851
895
  evaluation = {
852
896
  featureKey: feature.key,
853
- reason: EvaluationReason.ERROR,
897
+ reason: EvaluationReason.ERROR, // @TODO: any better reason?
898
+ bucketKey,
854
899
  bucketValue,
855
900
  };
856
901
 
@@ -1046,12 +1091,19 @@ export class FeaturevisorInstance {
1046
1091
  const finalContext = this.interceptContext ? this.interceptContext(context) : context;
1047
1092
 
1048
1093
  // forced
1049
- const force = findForceFromFeature(feature, context, this.datafileReader, this.logger);
1094
+ const { force, forceIndex } = findForceFromFeature(
1095
+ feature,
1096
+ context,
1097
+ this.datafileReader,
1098
+ this.logger,
1099
+ );
1050
1100
 
1051
1101
  if (force && force.variables && typeof force.variables[variableKey] !== "undefined") {
1052
1102
  evaluation = {
1053
1103
  featureKey: feature.key,
1054
1104
  reason: EvaluationReason.FORCED,
1105
+ forceIndex,
1106
+ force,
1055
1107
  variableKey,
1056
1108
  variableSchema,
1057
1109
  variableValue: force.variables[variableKey],
@@ -1063,7 +1115,7 @@ export class FeaturevisorInstance {
1063
1115
  }
1064
1116
 
1065
1117
  // bucketing
1066
- const bucketValue = this.getBucketValue(feature, finalContext);
1118
+ const { bucketKey, bucketValue } = this.getBucketValue(feature, finalContext);
1067
1119
 
1068
1120
  const { matchedTraffic, matchedAllocation } = getMatchedTrafficAndAllocation(
1069
1121
  feature.traffic,
@@ -1082,11 +1134,13 @@ export class FeaturevisorInstance {
1082
1134
  evaluation = {
1083
1135
  featureKey: feature.key,
1084
1136
  reason: EvaluationReason.RULE,
1137
+ bucketKey,
1138
+ bucketValue,
1139
+ ruleKey: matchedTraffic.key,
1140
+ traffic: matchedTraffic,
1085
1141
  variableKey,
1086
1142
  variableSchema,
1087
1143
  variableValue: matchedTraffic.variables[variableKey],
1088
- bucketValue,
1089
- ruleKey: matchedTraffic.key,
1090
1144
  };
1091
1145
 
1092
1146
  this.logger.debug("override from rule", evaluation);
@@ -1136,11 +1190,13 @@ export class FeaturevisorInstance {
1136
1190
  evaluation = {
1137
1191
  featureKey: feature.key,
1138
1192
  reason: EvaluationReason.OVERRIDE,
1193
+ bucketKey,
1194
+ bucketValue,
1195
+ ruleKey: matchedTraffic.key,
1196
+ traffic: matchedTraffic,
1139
1197
  variableKey,
1140
1198
  variableSchema,
1141
1199
  variableValue: override.value,
1142
- bucketValue,
1143
- ruleKey: matchedTraffic.key,
1144
1200
  };
1145
1201
 
1146
1202
  this.logger.debug("variable override", evaluation);
@@ -1153,11 +1209,13 @@ export class FeaturevisorInstance {
1153
1209
  evaluation = {
1154
1210
  featureKey: feature.key,
1155
1211
  reason: EvaluationReason.ALLOCATED,
1212
+ bucketKey,
1213
+ bucketValue,
1214
+ ruleKey: matchedTraffic.key,
1215
+ traffic: matchedTraffic,
1156
1216
  variableKey,
1157
1217
  variableSchema,
1158
1218
  variableValue: variableFromVariation.value,
1159
- bucketValue,
1160
- ruleKey: matchedTraffic.key,
1161
1219
  };
1162
1220
 
1163
1221
  this.logger.debug("allocated variable", evaluation);
@@ -1173,10 +1231,11 @@ export class FeaturevisorInstance {
1173
1231
  evaluation = {
1174
1232
  featureKey: feature.key,
1175
1233
  reason: EvaluationReason.DEFAULTED,
1234
+ bucketKey,
1235
+ bucketValue,
1176
1236
  variableKey,
1177
1237
  variableSchema,
1178
1238
  variableValue: variableSchema.defaultValue,
1179
- bucketValue,
1180
1239
  };
1181
1240
 
1182
1241
  this.logger.debug("using default value", evaluation);