@uniformdev/context 20.6.1-alpha.0 → 20.6.2-alpha.10

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);
716
727
  return result;
717
728
  } else {
718
- throw new Error(`Unknown op: ${op}`);
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);
751
+ return result;
752
+ } else {
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,34 @@ 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
+ validVariation = { id: variation.id };
806
+ } else {
807
+ validVariation = variation;
808
+ }
809
+ if ((_a = validVariation.pz) == null ? void 0 : _a.crit.length) {
810
+ if (personalizationAllowed && variationMatches.length !== take && evaluateVariantMatch(variation.id, validVariation.pz, context.scores, onLogMessage, context.quirks)) {
811
+ variationMatches.push(validVariation);
751
812
  }
752
813
  } else {
753
- defaultVariants.push(variant);
814
+ defaultVariations.push(validVariation);
754
815
  }
755
816
  }
756
817
  const result = [];
757
- for (let i = 0; i < variantMatches.length; i++) {
818
+ for (let i = 0; i < variationMatches.length; i++) {
758
819
  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") {
820
+ const variation = variationMatches[i];
821
+ if (!isControl && typeof ((_c = variation.pz) == null ? void 0 : _c.control) === "number") {
761
822
  isControl = context.getPersonalizeVariantControl(name, i);
762
823
  if (typeof isControl === "undefined") {
763
- isControl = rollForControlGroup(variant.pz.control);
824
+ isControl = rollForControlGroup(variation.pz.control);
764
825
  context.storage.updateData([
765
826
  {
766
827
  type: "setpersonalizecontrol",
@@ -773,13 +834,13 @@ function personalizeVariations({
773
834
  ]);
774
835
  }
775
836
  }
776
- let variantToAdd = variant;
837
+ let variantToAdd = variation;
777
838
  if (isControl) {
778
- const defaultReplacement = defaultVariants.shift();
839
+ const defaultReplacement = defaultVariations.shift();
779
840
  if (defaultReplacement) {
780
841
  variantToAdd = {
781
842
  ...defaultReplacement,
782
- id: variant.id
843
+ id: variation.id
783
844
  };
784
845
  } else {
785
846
  variantToAdd = void 0;
@@ -789,8 +850,8 @@ function personalizeVariations({
789
850
  result.push({ ...variantToAdd, control: isControl });
790
851
  }
791
852
  }
792
- while (result.length < take && defaultVariants.length) {
793
- result.push({ ...defaultVariants.shift(), control: false });
853
+ while (result.length < take && defaultVariations.length) {
854
+ result.push({ ...defaultVariations.shift(), control: false });
794
855
  }
795
856
  const personalized = result.some((v) => {
796
857
  var _a2;
@@ -805,7 +866,82 @@ function personalizeVariations({
805
866
  }
806
867
  }
807
868
 
808
- // src/placement/test.ts
869
+ // src/placement/personalizeVariations.ts
870
+ function personalizeVariations(options) {
871
+ return topDownCriteriaPersonalizationSelectionAlgorithm(options);
872
+ }
873
+
874
+ // src/placement/strongestScorePersonalizationSelectionAlgorithm.ts
875
+ var STRONGEST_SCORE_PERSONALIZATION_ALGORITHM = "ssc";
876
+ function strongestScorePersonalizationSelectionAlgorithm({
877
+ name,
878
+ context,
879
+ variations,
880
+ take = 1,
881
+ onLogMessage
882
+ }) {
883
+ var _a, _b;
884
+ onLogMessage == null ? void 0 : onLogMessage(["info", 300, "GROUP", { name, take }]);
885
+ try {
886
+ const variationMatches = [];
887
+ const defaultVariations = [];
888
+ const needsConsentToPersonalize = context.requireConsentForPersonalization;
889
+ const isInGlobalControlGroup = (_a = context.storage.data.controlGroup) != null ? _a : false;
890
+ const personalizationAllowed = !needsConsentToPersonalize || context.storage.data.consent;
891
+ for (const variation of variations) {
892
+ const isInvalidFormat = variation.pz && (typeof variation.pz !== "object" || variation.pz === null);
893
+ let validVariation;
894
+ if (isInvalidFormat) {
895
+ validVariation = { id: variation.id };
896
+ } else {
897
+ validVariation = variation;
898
+ }
899
+ if ((_b = validVariation.pz) == null ? void 0 : _b.dim) {
900
+ if (!personalizationAllowed) {
901
+ continue;
902
+ }
903
+ const score = context.scores[validVariation.pz.dim];
904
+ if (score === void 0 || score <= 0) {
905
+ continue;
906
+ }
907
+ variationMatches.push({ variation: validVariation, score });
908
+ } else {
909
+ defaultVariations.push(validVariation);
910
+ }
911
+ }
912
+ variationMatches.sort((a, b) => b.score - a.score);
913
+ const result = [];
914
+ for (let i = 0; i < variationMatches.length; i++) {
915
+ const variationMatch = variationMatches[i];
916
+ let variantToAdd = variationMatch.variation;
917
+ if (isInGlobalControlGroup) {
918
+ const defaultReplacement = defaultVariations.shift();
919
+ if (defaultReplacement) {
920
+ variantToAdd = {
921
+ ...defaultReplacement,
922
+ id: variationMatch.variation.id
923
+ };
924
+ } else {
925
+ variantToAdd = void 0;
926
+ }
927
+ }
928
+ if (variantToAdd) {
929
+ result.push({ ...variantToAdd, control: isInGlobalControlGroup });
930
+ }
931
+ }
932
+ while (result.length < take && defaultVariations.length) {
933
+ result.push({ ...defaultVariations.shift(), control: false });
934
+ }
935
+ return {
936
+ personalized: variationMatches.length > 0 && !isInGlobalControlGroup,
937
+ variations: result
938
+ };
939
+ } finally {
940
+ onLogMessage == null ? void 0 : onLogMessage(["info", 300, "ENDGROUP"]);
941
+ }
942
+ }
943
+
944
+ // src/placement/normalizeVariationDistributions.ts
809
945
  var normalizeVariationDistributions = (variations) => {
810
946
  const { values, total, missingDistribution } = variations.reduce(
811
947
  (previous, current) => {
@@ -824,7 +960,12 @@ var normalizeVariationDistributions = (variations) => {
824
960
  }
825
961
  );
826
962
  if (total > 100) {
827
- throw new Error(`Total distribution ${total} is over the maximum 100.`);
963
+ const autoScaleFactor = 100 / total;
964
+ values.forEach((value, index) => {
965
+ if (typeof value === "number") {
966
+ values[index] = value * autoScaleFactor;
967
+ }
968
+ });
828
969
  } else if (total < 100) {
829
970
  const remainder = 100 - total;
830
971
  const missingSlice = remainder / missingDistribution;
@@ -836,6 +977,8 @@ var normalizeVariationDistributions = (variations) => {
836
977
  }
837
978
  return values;
838
979
  };
980
+
981
+ // src/placement/testVariations.ts
839
982
  var testVariations = ({
840
983
  name,
841
984
  context,
@@ -1602,11 +1745,12 @@ var import_lite5 = require("dequal/lite");
1602
1745
  var import_mitt3 = __toESM(require("mitt"));
1603
1746
  var CONTEXTUAL_EDITING_TEST_NAME = "contextual_editing_test";
1604
1747
  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;
1748
+ var _personalizationSelectionAlgorithms, _serverTransitionState, _scores, _state, _pzCache, _plugins, _commands, _requireConsentForPersonalization, _mitt3, _Context_instances, emitTest_fn, updateGoals_fn, updateComputedScores_fn, calculateScores_fn;
1606
1749
  var Context = class {
1607
1750
  constructor(options) {
1608
1751
  __privateAdd(this, _Context_instances);
1609
1752
  __publicField(this, "manifest");
1753
+ __privateAdd(this, _personalizationSelectionAlgorithms);
1610
1754
  __privateAdd(this, _serverTransitionState);
1611
1755
  __privateAdd(this, _scores, {});
1612
1756
  __privateAdd(this, _state);
@@ -1623,7 +1767,7 @@ var Context = class {
1623
1767
  off: __privateGet(this, _mitt3).off
1624
1768
  });
1625
1769
  __publicField(this, "storage");
1626
- var _a, _b;
1770
+ var _a, _b, _c;
1627
1771
  const { manifest, ...storageOptions } = options;
1628
1772
  __privateSet(this, _state, {});
1629
1773
  __privateSet(this, _plugins, options.plugins);
@@ -1631,7 +1775,20 @@ var Context = class {
1631
1775
  if (typeof options.transitionStore !== "undefined") {
1632
1776
  __privateSet(this, _commands, []);
1633
1777
  }
1778
+ __privateSet(this, _personalizationSelectionAlgorithms, {
1779
+ [TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM]: topDownCriteriaPersonalizationSelectionAlgorithm,
1780
+ [STRONGEST_SCORE_PERSONALIZATION_ALGORITHM]: strongestScorePersonalizationSelectionAlgorithm
1781
+ });
1634
1782
  (_a = __privateGet(this, _plugins)) == null ? void 0 : _a.forEach((plugin) => {
1783
+ if (!plugin.personalizationSelectionAlgorithms) {
1784
+ return;
1785
+ }
1786
+ __privateSet(this, _personalizationSelectionAlgorithms, {
1787
+ ...__privateGet(this, _personalizationSelectionAlgorithms),
1788
+ ...plugin.personalizationSelectionAlgorithms
1789
+ });
1790
+ });
1791
+ (_b = __privateGet(this, _plugins)) == null ? void 0 : _b.forEach((plugin) => {
1635
1792
  if (!plugin.logDrain) {
1636
1793
  return;
1637
1794
  }
@@ -1682,7 +1839,7 @@ var Context = class {
1682
1839
  __privateGet(this, _mitt3).emit("quirksUpdated", quirks.quirks);
1683
1840
  __privateGet(this, _mitt3).emit("log", ["info", 4, quirks.quirks]);
1684
1841
  });
1685
- (_b = __privateGet(this, _plugins)) == null ? void 0 : _b.forEach((plugin) => {
1842
+ (_c = __privateGet(this, _plugins)) == null ? void 0 : _c.forEach((plugin) => {
1686
1843
  if (!plugin.init) {
1687
1844
  return;
1688
1845
  }
@@ -1932,7 +2089,17 @@ var Context = class {
1932
2089
  }
1933
2090
  /** Executes a personalized placement with a given set of variants */
1934
2091
  personalize(options) {
1935
- const value = personalizeVariations({
2092
+ var _a;
2093
+ const algorithmName = (_a = options.algorithm) != null ? _a : TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM;
2094
+ const algorithm = __privateGet(this, _personalizationSelectionAlgorithms)[algorithmName];
2095
+ if (!algorithm) {
2096
+ __privateGet(this, _mitt3).emit("log", ["warn", 304, { algorithm: algorithmName }]);
2097
+ return {
2098
+ personalized: false,
2099
+ variations: []
2100
+ };
2101
+ }
2102
+ const value = algorithm({
1936
2103
  ...options,
1937
2104
  context: this,
1938
2105
  onLogMessage: (message) => __privateGet(this, _mitt3).emit("log", message)
@@ -2006,6 +2173,7 @@ var Context = class {
2006
2173
  __privateGet(this, _mitt3).emit("personalizationResult", event);
2007
2174
  }
2008
2175
  };
2176
+ _personalizationSelectionAlgorithms = new WeakMap();
2009
2177
  _serverTransitionState = new WeakMap();
2010
2178
  _scores = new WeakMap();
2011
2179
  _state = new WeakMap();
@@ -2601,6 +2769,10 @@ var messageContent = {
2601
2769
  301: ({ id, op }) => ["personalization", `testing variation ${id} (${op === "|" ? "OR" : "AND"})`],
2602
2770
  302: ({ matched, description }) => ["personalization", `${description} is ${matched}`],
2603
2771
  303: (selected) => ["personalization", selected ? "selected variation" : "did not select variation"],
2772
+ 304: ({ algorithm }) => [
2773
+ "personalization",
2774
+ `personalization selection algorithm '${algorithm}' not found. Hiding placement.`
2775
+ ],
2604
2776
  // TESTING
2605
2777
  400: (name) => ["testing", `executing A/B test '${name}'`],
2606
2778
  401: (testName) => ["testing", `${testName} is not registered in the manifest; it will not be run.`],
@@ -2706,7 +2878,9 @@ function parseQuickConnect(serialized) {
2706
2878
  PAIR_SEP,
2707
2879
  QUIRK_SEP,
2708
2880
  SERVER_STATE_ID,
2881
+ STRONGEST_SCORE_PERSONALIZATION_ALGORITHM,
2709
2882
  ScriptType,
2883
+ TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM,
2710
2884
  TYPE_SEP,
2711
2885
  TransitionDataStore,
2712
2886
  UNIFORM_DEFAULT_COOKIE_NAME,
@@ -2748,5 +2922,7 @@ function parseQuickConnect(serialized) {
2748
2922
  serializePersonalizeVariants,
2749
2923
  serializeQuickConnect,
2750
2924
  serializeQuirks,
2751
- testVariations
2925
+ strongestScorePersonalizationSelectionAlgorithm,
2926
+ testVariations,
2927
+ topDownCriteriaPersonalizationSelectionAlgorithm
2752
2928
  });