@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/.eslintcache +1 -1
- package/CHANGELOG.md +11 -0
- package/coverage/clover.xml +397 -390
- package/coverage/coverage-final.json +2 -2
- package/coverage/lcov-report/bucket.ts.html +1 -1
- package/coverage/lcov-report/conditions.ts.html +1 -1
- package/coverage/lcov-report/datafileReader.ts.html +1 -1
- package/coverage/lcov-report/emitter.ts.html +1 -1
- package/coverage/lcov-report/feature.ts.html +88 -22
- package/coverage/lcov-report/index.html +23 -23
- package/coverage/lcov-report/instance.ts.html +209 -32
- package/coverage/lcov-report/logger.ts.html +1 -1
- package/coverage/lcov-report/segments.ts.html +1 -1
- package/coverage/lcov.info +655 -646
- package/dist/index.js +1 -1
- package/dist/index.js.gz +0 -0
- package/dist/index.js.map +1 -1
- package/lib/feature.d.ts +5 -1
- package/lib/feature.js +19 -8
- package/lib/feature.js.map +1 -1
- package/lib/instance.d.ts +5 -1
- package/lib/instance.js +59 -25
- package/lib/instance.js.map +1 -1
- package/package.json +2 -2
- package/src/feature.ts +31 -9
- package/src/instance.ts +85 -26
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(
|
|
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
|
-
|
|
386
|
+
const configuredValue = this.configureBucketValue(feature, context, value);
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
bucketKey,
|
|
390
|
+
bucketValue: configuredValue,
|
|
391
|
+
};
|
|
378
392
|
}
|
|
379
393
|
|
|
380
|
-
return
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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);
|