@uniformdev/context 20.8.1 → 20.8.2-alpha.15

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/dist/index.js CHANGED
@@ -53,7 +53,9 @@ __export(src_exports, {
53
53
  PAIR_SEP: () => PAIR_SEP,
54
54
  QUIRK_SEP: () => QUIRK_SEP,
55
55
  SERVER_STATE_ID: () => SERVER_STATE_ID,
56
+ STRONGEST_SCORE_PERSONALIZATION_ALGORITHM: () => STRONGEST_SCORE_PERSONALIZATION_ALGORITHM,
56
57
  ScriptType: () => ScriptType,
58
+ TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM: () => TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM,
57
59
  TYPE_SEP: () => TYPE_SEP,
58
60
  TransitionDataStore: () => TransitionDataStore,
59
61
  UNIFORM_DEFAULT_COOKIE_NAME: () => UNIFORM_DEFAULT_COOKIE_NAME,
@@ -95,7 +97,9 @@ __export(src_exports, {
95
97
  serializePersonalizeVariants: () => serializePersonalizeVariants,
96
98
  serializeQuickConnect: () => serializeQuickConnect,
97
99
  serializeQuirks: () => serializeQuirks,
98
- testVariations: () => testVariations
100
+ strongestScorePersonalizationSelectionAlgorithm: () => strongestScorePersonalizationSelectionAlgorithm,
101
+ testVariations: () => testVariations,
102
+ topDownCriteriaPersonalizationSelectionAlgorithm: () => topDownCriteriaPersonalizationSelectionAlgorithm
99
103
  });
100
104
  module.exports = __toCommonJS(src_exports);
101
105
 
@@ -605,7 +609,7 @@ var GroupCriteriaEvaluator = class {
605
609
  _evaluators = new WeakMap();
606
610
 
607
611
  // src/placement/criteria/evaluateVariantMatch.ts
608
- function evaluateVariantMatch(variantId, match, vec, onLogMessage) {
612
+ function evaluateVariantMatch(variantId, match, vec, onLogMessage, quirks) {
609
613
  onLogMessage == null ? void 0 : onLogMessage(["info", 301, "GROUP", { id: variantId, op: match == null ? void 0 : match.op }]);
610
614
  let result;
611
615
  try {
@@ -613,9 +617,9 @@ function evaluateVariantMatch(variantId, match, vec, onLogMessage) {
613
617
  onLogMessage == null ? void 0 : onLogMessage(["info", 302, { matched: true, description: "default variation" }]);
614
618
  result = true;
615
619
  } else if (!match.op || match.op === "&") {
616
- result = match.crit.every((c) => evaluateDimensionMatch(c, vec, onLogMessage));
620
+ result = match.crit.every((c) => evaluateMatch(c, vec, quirks != null ? quirks : {}, onLogMessage));
617
621
  } else {
618
- result = match.crit.some((c) => evaluateDimensionMatch(c, vec, onLogMessage));
622
+ result = match.crit.some((c) => evaluateMatch(c, vec, quirks != null ? quirks : {}, onLogMessage));
619
623
  }
620
624
  onLogMessage == null ? void 0 : onLogMessage(["info", 303, result]);
621
625
  } finally {
@@ -623,9 +627,16 @@ function evaluateVariantMatch(variantId, match, vec, onLogMessage) {
623
627
  }
624
628
  return result;
625
629
  }
630
+ function evaluateMatch(crit, vec, quirks, onLogMessage) {
631
+ if ("t" in crit && crit.t === "q") {
632
+ return evaluateQuirkMatch(crit, quirks, onLogMessage);
633
+ } else {
634
+ return evaluateDimensionMatch(crit, vec, onLogMessage);
635
+ }
636
+ }
626
637
  function evaluateDimensionMatch(crit, vec, onLogMessage) {
627
638
  var _a, _b;
628
- const { op, l: lhs } = crit;
639
+ const { l: lhs, op } = crit;
629
640
  const lhsScore = (_a = vec[lhs]) != null ? _a : 0;
630
641
  if (op === "^") {
631
642
  const [cat] = lhs.split(ENR_SEPARATOR);
@@ -692,33 +703,65 @@ function evaluateDimensionMatch(crit, vec, onLogMessage) {
692
703
  }
693
704
  if (op === ">") {
694
705
  const result = lhsScore > rhsScore;
695
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
706
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
696
707
  return result;
697
708
  } else if (op === ">=") {
698
709
  const result = lhsScore >= rhsScore;
699
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
710
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
700
711
  return result;
701
712
  } else if (op === "<") {
702
713
  const result = lhsScore < rhsScore;
703
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
714
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
704
715
  return result;
705
716
  } else if (op === "<=") {
706
717
  const result = lhsScore <= rhsScore;
707
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
718
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
708
719
  return result;
709
720
  } else if (op === "=") {
710
721
  const result = lhsScore === rhsScore;
711
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
722
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
712
723
  return result;
713
724
  } else if (op === "!=") {
714
725
  const result = lhsScore !== rhsScore;
715
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
726
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
727
+ return result;
728
+ } else {
729
+ onLogMessage == null ? void 0 : onLogMessage([
730
+ "error",
731
+ 302,
732
+ {
733
+ matched: false,
734
+ description: `${crit.l} ${crit.op} ${crit.rDim ? `${crit.rDim}` : crit.r}: Unknown op ${crit.op}.`
735
+ }
736
+ ]);
737
+ return false;
738
+ }
739
+ }
740
+ function evaluateQuirkMatch(crit, quirks, onLogMessage) {
741
+ var _a;
742
+ const { l: targetQuirk, op, r: targetValue } = crit;
743
+ const targetQuirkValue = (_a = quirks[targetQuirk]) != null ? _a : "";
744
+ if (op === "=") {
745
+ const result = targetQuirkValue === targetValue;
746
+ explainQuirk(onLogMessage, result, crit, targetQuirkValue);
747
+ return result;
748
+ } else if (op === "!=") {
749
+ const result = targetQuirkValue !== targetValue;
750
+ explainQuirk(onLogMessage, result, crit, targetQuirkValue);
716
751
  return result;
717
752
  } else {
718
- throw new Error(`Unknown op: ${op}`);
753
+ onLogMessage == null ? void 0 : onLogMessage([
754
+ "error",
755
+ 302,
756
+ {
757
+ matched: false,
758
+ description: `Quirk ${crit.l} ${crit.op} ${crit.r}: Unknown quirk op ${crit.op}.`
759
+ }
760
+ ]);
761
+ return false;
719
762
  }
720
763
  }
721
- function explain(onLogMessage, result, crit, lhsScore, rhsScore) {
764
+ function explainScore(onLogMessage, result, crit, lhsScore, rhsScore) {
722
765
  onLogMessage == null ? void 0 : onLogMessage([
723
766
  "info",
724
767
  302,
@@ -728,9 +771,20 @@ function explain(onLogMessage, result, crit, lhsScore, rhsScore) {
728
771
  }
729
772
  ]);
730
773
  }
774
+ function explainQuirk(onLogMessage, result, crit, lhs) {
775
+ onLogMessage == null ? void 0 : onLogMessage([
776
+ "info",
777
+ 302,
778
+ {
779
+ matched: result,
780
+ description: `Quirk ${crit.l}[${lhs}] ${crit.op} ${crit.r}`
781
+ }
782
+ ]);
783
+ }
731
784
 
732
- // src/placement/personalize.ts
733
- function personalizeVariations({
785
+ // src/placement/topDownCriteriaPersonalizationSelectionAlgorithm.ts
786
+ var TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM = "default";
787
+ function topDownCriteriaPersonalizationSelectionAlgorithm({
734
788
  name,
735
789
  context,
736
790
  variations,
@@ -740,27 +794,35 @@ function personalizeVariations({
740
794
  var _a, _b, _c;
741
795
  onLogMessage == null ? void 0 : onLogMessage(["info", 300, "GROUP", { name, take }]);
742
796
  try {
743
- const variantMatches = [];
744
- const defaultVariants = [];
745
- const needsConsent = context.requireConsentForPersonalization;
746
- const canEvaluate = !needsConsent || context.storage.data.consent;
747
- for (const variant of variations) {
748
- if ((_a = variant.pz) == null ? void 0 : _a.crit.length) {
749
- if (canEvaluate && variantMatches.length !== take && evaluateVariantMatch(variant.id, variant.pz, context.scores, onLogMessage)) {
750
- variantMatches.push(variant);
797
+ const variationMatches = [];
798
+ const defaultVariations = [];
799
+ const needsConsentToPersonalize = context.requireConsentForPersonalization;
800
+ const personalizationAllowed = !needsConsentToPersonalize || context.storage.data.consent;
801
+ for (const variation of variations) {
802
+ const isInvalidFormat = variation.pz && (typeof variation.pz !== "object" || variation.pz === null || !("crit" in variation.pz && Array.isArray(variation.pz.crit)));
803
+ let validVariation;
804
+ if (isInvalidFormat) {
805
+ const { pz, ...validParts } = variation;
806
+ validVariation = validParts;
807
+ } else {
808
+ validVariation = variation;
809
+ }
810
+ if ((_a = validVariation.pz) == null ? void 0 : _a.crit.length) {
811
+ if (personalizationAllowed && variationMatches.length !== take && evaluateVariantMatch(variation.id, validVariation.pz, context.scores, onLogMessage, context.quirks)) {
812
+ variationMatches.push(validVariation);
751
813
  }
752
814
  } else {
753
- defaultVariants.push(variant);
815
+ defaultVariations.push(validVariation);
754
816
  }
755
817
  }
756
818
  const result = [];
757
- for (let i = 0; i < variantMatches.length; i++) {
819
+ for (let i = 0; i < variationMatches.length; i++) {
758
820
  let isControl = (_b = context.storage.data.controlGroup) != null ? _b : false;
759
- const variant = variantMatches[i];
760
- if (!isControl && typeof ((_c = variant.pz) == null ? void 0 : _c.control) === "number") {
821
+ const variation = variationMatches[i];
822
+ if (!isControl && typeof ((_c = variation.pz) == null ? void 0 : _c.control) === "number") {
761
823
  isControl = context.getPersonalizeVariantControl(name, i);
762
824
  if (typeof isControl === "undefined") {
763
- isControl = rollForControlGroup(variant.pz.control);
825
+ isControl = rollForControlGroup(variation.pz.control);
764
826
  context.storage.updateData([
765
827
  {
766
828
  type: "setpersonalizecontrol",
@@ -773,13 +835,13 @@ function personalizeVariations({
773
835
  ]);
774
836
  }
775
837
  }
776
- let variantToAdd = variant;
838
+ let variantToAdd = variation;
777
839
  if (isControl) {
778
- const defaultReplacement = defaultVariants.shift();
840
+ const defaultReplacement = defaultVariations.shift();
779
841
  if (defaultReplacement) {
780
842
  variantToAdd = {
781
843
  ...defaultReplacement,
782
- id: variant.id
844
+ id: variation.id
783
845
  };
784
846
  } else {
785
847
  variantToAdd = void 0;
@@ -789,8 +851,8 @@ function personalizeVariations({
789
851
  result.push({ ...variantToAdd, control: isControl });
790
852
  }
791
853
  }
792
- while (result.length < take && defaultVariants.length) {
793
- result.push({ ...defaultVariants.shift(), control: false });
854
+ while (result.length < take && defaultVariations.length) {
855
+ result.push({ ...defaultVariations.shift(), control: false });
794
856
  }
795
857
  const personalized = result.some((v) => {
796
858
  var _a2;
@@ -805,7 +867,94 @@ function personalizeVariations({
805
867
  }
806
868
  }
807
869
 
808
- // src/placement/test.ts
870
+ // src/placement/personalizeVariations.ts
871
+ function personalizeVariations(options) {
872
+ return topDownCriteriaPersonalizationSelectionAlgorithm(options);
873
+ }
874
+
875
+ // src/placement/strongestScorePersonalizationSelectionAlgorithm.ts
876
+ var STRONGEST_SCORE_PERSONALIZATION_ALGORITHM = "ssc";
877
+ function strongestScorePersonalizationSelectionAlgorithm({
878
+ name,
879
+ context,
880
+ variations,
881
+ take = 1,
882
+ onLogMessage
883
+ }) {
884
+ var _a, _b;
885
+ onLogMessage == null ? void 0 : onLogMessage(["info", 300, "GROUP", { name, take }]);
886
+ try {
887
+ const variationMatches = [];
888
+ const defaultVariations = [];
889
+ const needsConsentToPersonalize = context.requireConsentForPersonalization;
890
+ const isInGlobalControlGroup = (_a = context.storage.data.controlGroup) != null ? _a : false;
891
+ const personalizationAllowed = !needsConsentToPersonalize || context.storage.data.consent;
892
+ let originalIndex = 0;
893
+ for (const variation of variations) {
894
+ const isInvalidFormat = variation.pz && typeof variation.pz !== "object";
895
+ let validVariation;
896
+ if (isInvalidFormat) {
897
+ const { pz, ...validParts } = variation;
898
+ validVariation = validParts;
899
+ } else {
900
+ validVariation = variation;
901
+ }
902
+ if ((_b = validVariation.pz) == null ? void 0 : _b.dim) {
903
+ if (!personalizationAllowed) {
904
+ continue;
905
+ }
906
+ const score = context.scores[validVariation.pz.dim];
907
+ if (score === void 0 || score <= 0) {
908
+ continue;
909
+ }
910
+ variationMatches.push({ variation: validVariation, score, originalIndex });
911
+ originalIndex++;
912
+ } else {
913
+ defaultVariations.push(validVariation);
914
+ }
915
+ }
916
+ variationMatches.sort((a, b) => {
917
+ const scoreComparison = b.score - a.score;
918
+ if (scoreComparison === 0) {
919
+ return a.originalIndex - b.originalIndex;
920
+ }
921
+ return scoreComparison;
922
+ });
923
+ const result = [];
924
+ for (let i = 0; i < variationMatches.length; i++) {
925
+ const variationMatch = variationMatches[i];
926
+ let variantToAdd = variationMatch.variation;
927
+ if (i >= take) {
928
+ continue;
929
+ }
930
+ if (isInGlobalControlGroup) {
931
+ const defaultReplacement = defaultVariations.shift();
932
+ if (defaultReplacement) {
933
+ variantToAdd = {
934
+ ...defaultReplacement,
935
+ id: variationMatch.variation.id
936
+ };
937
+ } else {
938
+ variantToAdd = void 0;
939
+ }
940
+ }
941
+ if (variantToAdd) {
942
+ result.push({ ...variantToAdd, control: isInGlobalControlGroup });
943
+ }
944
+ }
945
+ while (result.length < take && defaultVariations.length) {
946
+ result.push({ ...defaultVariations.shift(), control: false });
947
+ }
948
+ return {
949
+ personalized: variationMatches.length > 0 && !isInGlobalControlGroup,
950
+ variations: result
951
+ };
952
+ } finally {
953
+ onLogMessage == null ? void 0 : onLogMessage(["info", 300, "ENDGROUP"]);
954
+ }
955
+ }
956
+
957
+ // src/placement/normalizeVariationDistributions.ts
809
958
  var normalizeVariationDistributions = (variations) => {
810
959
  const { values, total, missingDistribution } = variations.reduce(
811
960
  (previous, current) => {
@@ -824,7 +973,12 @@ var normalizeVariationDistributions = (variations) => {
824
973
  }
825
974
  );
826
975
  if (total > 100) {
827
- throw new Error(`Total distribution ${total} is over the maximum 100.`);
976
+ const autoScaleFactor = 100 / total;
977
+ values.forEach((value, index) => {
978
+ if (typeof value === "number") {
979
+ values[index] = value * autoScaleFactor;
980
+ }
981
+ });
828
982
  } else if (total < 100) {
829
983
  const remainder = 100 - total;
830
984
  const missingSlice = remainder / missingDistribution;
@@ -836,6 +990,8 @@ var normalizeVariationDistributions = (variations) => {
836
990
  }
837
991
  return values;
838
992
  };
993
+
994
+ // src/placement/testVariations.ts
839
995
  var testVariations = ({
840
996
  name,
841
997
  context,
@@ -1602,11 +1758,12 @@ var import_lite5 = require("dequal/lite");
1602
1758
  var import_mitt3 = __toESM(require("mitt"));
1603
1759
  var CONTEXTUAL_EDITING_TEST_NAME = "contextual_editing_test";
1604
1760
  var CONTEXTUAL_EDITING_TEST_SELECTED_VARIANT_ID = "contextual_editing_test_selected_variant";
1605
- var _serverTransitionState, _scores, _state, _pzCache, _plugins, _commands, _requireConsentForPersonalization, _mitt3, _Context_instances, emitTest_fn, updateGoals_fn, updateComputedScores_fn, calculateScores_fn;
1761
+ var _personalizationSelectionAlgorithms, _serverTransitionState, _scores, _state, _pzCache, _plugins, _commands, _requireConsentForPersonalization, _mitt3, _Context_instances, emitTest_fn, updateGoals_fn, updateComputedScores_fn, calculateScores_fn;
1606
1762
  var Context = class {
1607
1763
  constructor(options) {
1608
1764
  __privateAdd(this, _Context_instances);
1609
1765
  __publicField(this, "manifest");
1766
+ __privateAdd(this, _personalizationSelectionAlgorithms);
1610
1767
  __privateAdd(this, _serverTransitionState);
1611
1768
  __privateAdd(this, _scores, {});
1612
1769
  __privateAdd(this, _state);
@@ -1623,7 +1780,7 @@ var Context = class {
1623
1780
  off: __privateGet(this, _mitt3).off
1624
1781
  });
1625
1782
  __publicField(this, "storage");
1626
- var _a, _b;
1783
+ var _a, _b, _c;
1627
1784
  const { manifest, ...storageOptions } = options;
1628
1785
  __privateSet(this, _state, {});
1629
1786
  __privateSet(this, _plugins, options.plugins);
@@ -1631,7 +1788,20 @@ var Context = class {
1631
1788
  if (typeof options.transitionStore !== "undefined") {
1632
1789
  __privateSet(this, _commands, []);
1633
1790
  }
1791
+ __privateSet(this, _personalizationSelectionAlgorithms, {
1792
+ [TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM]: topDownCriteriaPersonalizationSelectionAlgorithm,
1793
+ [STRONGEST_SCORE_PERSONALIZATION_ALGORITHM]: strongestScorePersonalizationSelectionAlgorithm
1794
+ });
1634
1795
  (_a = __privateGet(this, _plugins)) == null ? void 0 : _a.forEach((plugin) => {
1796
+ if (!plugin.personalizationSelectionAlgorithms) {
1797
+ return;
1798
+ }
1799
+ __privateSet(this, _personalizationSelectionAlgorithms, {
1800
+ ...__privateGet(this, _personalizationSelectionAlgorithms),
1801
+ ...plugin.personalizationSelectionAlgorithms
1802
+ });
1803
+ });
1804
+ (_b = __privateGet(this, _plugins)) == null ? void 0 : _b.forEach((plugin) => {
1635
1805
  if (!plugin.logDrain) {
1636
1806
  return;
1637
1807
  }
@@ -1682,7 +1852,7 @@ var Context = class {
1682
1852
  __privateGet(this, _mitt3).emit("quirksUpdated", quirks.quirks);
1683
1853
  __privateGet(this, _mitt3).emit("log", ["info", 4, quirks.quirks]);
1684
1854
  });
1685
- (_b = __privateGet(this, _plugins)) == null ? void 0 : _b.forEach((plugin) => {
1855
+ (_c = __privateGet(this, _plugins)) == null ? void 0 : _c.forEach((plugin) => {
1686
1856
  if (!plugin.init) {
1687
1857
  return;
1688
1858
  }
@@ -1932,7 +2102,17 @@ var Context = class {
1932
2102
  }
1933
2103
  /** Executes a personalized placement with a given set of variants */
1934
2104
  personalize(options) {
1935
- const value = personalizeVariations({
2105
+ var _a;
2106
+ const algorithmName = (_a = options.algorithm) != null ? _a : TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM;
2107
+ const algorithm = __privateGet(this, _personalizationSelectionAlgorithms)[algorithmName];
2108
+ if (!algorithm) {
2109
+ __privateGet(this, _mitt3).emit("log", ["warn", 304, { algorithm: algorithmName }]);
2110
+ return {
2111
+ personalized: false,
2112
+ variations: []
2113
+ };
2114
+ }
2115
+ const value = algorithm({
1936
2116
  ...options,
1937
2117
  context: this,
1938
2118
  onLogMessage: (message) => __privateGet(this, _mitt3).emit("log", message)
@@ -2006,6 +2186,7 @@ var Context = class {
2006
2186
  __privateGet(this, _mitt3).emit("personalizationResult", event);
2007
2187
  }
2008
2188
  };
2189
+ _personalizationSelectionAlgorithms = new WeakMap();
2009
2190
  _serverTransitionState = new WeakMap();
2010
2191
  _scores = new WeakMap();
2011
2192
  _state = new WeakMap();
@@ -2601,6 +2782,10 @@ var messageContent = {
2601
2782
  301: ({ id, op }) => ["personalization", `testing variation ${id} (${op === "|" ? "OR" : "AND"})`],
2602
2783
  302: ({ matched, description }) => ["personalization", `${description} is ${matched}`],
2603
2784
  303: (selected) => ["personalization", selected ? "selected variation" : "did not select variation"],
2785
+ 304: ({ algorithm }) => [
2786
+ "personalization",
2787
+ `personalization selection algorithm '${algorithm}' not found. Hiding placement.`
2788
+ ],
2604
2789
  // TESTING
2605
2790
  400: (name) => ["testing", `executing A/B test '${name}'`],
2606
2791
  401: (testName) => ["testing", `${testName} is not registered in the manifest; it will not be run.`],
@@ -2706,7 +2891,9 @@ function parseQuickConnect(serialized) {
2706
2891
  PAIR_SEP,
2707
2892
  QUIRK_SEP,
2708
2893
  SERVER_STATE_ID,
2894
+ STRONGEST_SCORE_PERSONALIZATION_ALGORITHM,
2709
2895
  ScriptType,
2896
+ TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM,
2710
2897
  TYPE_SEP,
2711
2898
  TransitionDataStore,
2712
2899
  UNIFORM_DEFAULT_COOKIE_NAME,
@@ -2748,5 +2935,7 @@ function parseQuickConnect(serialized) {
2748
2935
  serializePersonalizeVariants,
2749
2936
  serializeQuickConnect,
2750
2937
  serializeQuirks,
2751
- testVariations
2938
+ strongestScorePersonalizationSelectionAlgorithm,
2939
+ testVariations,
2940
+ topDownCriteriaPersonalizationSelectionAlgorithm
2752
2941
  });