@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.mjs CHANGED
@@ -516,7 +516,7 @@ var GroupCriteriaEvaluator = class {
516
516
  _evaluators = new WeakMap();
517
517
 
518
518
  // src/placement/criteria/evaluateVariantMatch.ts
519
- function evaluateVariantMatch(variantId, match, vec, onLogMessage) {
519
+ function evaluateVariantMatch(variantId, match, vec, onLogMessage, quirks) {
520
520
  onLogMessage == null ? void 0 : onLogMessage(["info", 301, "GROUP", { id: variantId, op: match == null ? void 0 : match.op }]);
521
521
  let result;
522
522
  try {
@@ -524,9 +524,9 @@ function evaluateVariantMatch(variantId, match, vec, onLogMessage) {
524
524
  onLogMessage == null ? void 0 : onLogMessage(["info", 302, { matched: true, description: "default variation" }]);
525
525
  result = true;
526
526
  } else if (!match.op || match.op === "&") {
527
- result = match.crit.every((c) => evaluateDimensionMatch(c, vec, onLogMessage));
527
+ result = match.crit.every((c) => evaluateMatch(c, vec, quirks != null ? quirks : {}, onLogMessage));
528
528
  } else {
529
- result = match.crit.some((c) => evaluateDimensionMatch(c, vec, onLogMessage));
529
+ result = match.crit.some((c) => evaluateMatch(c, vec, quirks != null ? quirks : {}, onLogMessage));
530
530
  }
531
531
  onLogMessage == null ? void 0 : onLogMessage(["info", 303, result]);
532
532
  } finally {
@@ -534,9 +534,16 @@ function evaluateVariantMatch(variantId, match, vec, onLogMessage) {
534
534
  }
535
535
  return result;
536
536
  }
537
+ function evaluateMatch(crit, vec, quirks, onLogMessage) {
538
+ if ("t" in crit && crit.t === "q") {
539
+ return evaluateQuirkMatch(crit, quirks, onLogMessage);
540
+ } else {
541
+ return evaluateDimensionMatch(crit, vec, onLogMessage);
542
+ }
543
+ }
537
544
  function evaluateDimensionMatch(crit, vec, onLogMessage) {
538
545
  var _a, _b;
539
- const { op, l: lhs } = crit;
546
+ const { l: lhs, op } = crit;
540
547
  const lhsScore = (_a = vec[lhs]) != null ? _a : 0;
541
548
  if (op === "^") {
542
549
  const [cat] = lhs.split(ENR_SEPARATOR);
@@ -603,33 +610,65 @@ function evaluateDimensionMatch(crit, vec, onLogMessage) {
603
610
  }
604
611
  if (op === ">") {
605
612
  const result = lhsScore > rhsScore;
606
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
613
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
607
614
  return result;
608
615
  } else if (op === ">=") {
609
616
  const result = lhsScore >= rhsScore;
610
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
617
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
611
618
  return result;
612
619
  } else if (op === "<") {
613
620
  const result = lhsScore < rhsScore;
614
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
621
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
615
622
  return result;
616
623
  } else if (op === "<=") {
617
624
  const result = lhsScore <= rhsScore;
618
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
625
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
619
626
  return result;
620
627
  } else if (op === "=") {
621
628
  const result = lhsScore === rhsScore;
622
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
629
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
623
630
  return result;
624
631
  } else if (op === "!=") {
625
632
  const result = lhsScore !== rhsScore;
626
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
633
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
627
634
  return result;
628
635
  } else {
629
- throw new Error(`Unknown op: ${op}`);
636
+ onLogMessage == null ? void 0 : onLogMessage([
637
+ "error",
638
+ 302,
639
+ {
640
+ matched: false,
641
+ description: `${crit.l} ${crit.op} ${crit.rDim ? `${crit.rDim}` : crit.r}: Unknown op ${crit.op}.`
642
+ }
643
+ ]);
644
+ return false;
645
+ }
646
+ }
647
+ function evaluateQuirkMatch(crit, quirks, onLogMessage) {
648
+ var _a;
649
+ const { l: targetQuirk, op, r: targetValue } = crit;
650
+ const targetQuirkValue = (_a = quirks[targetQuirk]) != null ? _a : "";
651
+ if (op === "=") {
652
+ const result = targetQuirkValue === targetValue;
653
+ explainQuirk(onLogMessage, result, crit, targetQuirkValue);
654
+ return result;
655
+ } else if (op === "!=") {
656
+ const result = targetQuirkValue !== targetValue;
657
+ explainQuirk(onLogMessage, result, crit, targetQuirkValue);
658
+ return result;
659
+ } else {
660
+ onLogMessage == null ? void 0 : onLogMessage([
661
+ "error",
662
+ 302,
663
+ {
664
+ matched: false,
665
+ description: `Quirk ${crit.l} ${crit.op} ${crit.r}: Unknown quirk op ${crit.op}.`
666
+ }
667
+ ]);
668
+ return false;
630
669
  }
631
670
  }
632
- function explain(onLogMessage, result, crit, lhsScore, rhsScore) {
671
+ function explainScore(onLogMessage, result, crit, lhsScore, rhsScore) {
633
672
  onLogMessage == null ? void 0 : onLogMessage([
634
673
  "info",
635
674
  302,
@@ -639,9 +678,20 @@ function explain(onLogMessage, result, crit, lhsScore, rhsScore) {
639
678
  }
640
679
  ]);
641
680
  }
681
+ function explainQuirk(onLogMessage, result, crit, lhs) {
682
+ onLogMessage == null ? void 0 : onLogMessage([
683
+ "info",
684
+ 302,
685
+ {
686
+ matched: result,
687
+ description: `Quirk ${crit.l}[${lhs}] ${crit.op} ${crit.r}`
688
+ }
689
+ ]);
690
+ }
642
691
 
643
- // src/placement/personalize.ts
644
- function personalizeVariations({
692
+ // src/placement/topDownCriteriaPersonalizationSelectionAlgorithm.ts
693
+ var TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM = "default";
694
+ function topDownCriteriaPersonalizationSelectionAlgorithm({
645
695
  name,
646
696
  context,
647
697
  variations,
@@ -651,27 +701,34 @@ function personalizeVariations({
651
701
  var _a, _b, _c;
652
702
  onLogMessage == null ? void 0 : onLogMessage(["info", 300, "GROUP", { name, take }]);
653
703
  try {
654
- const variantMatches = [];
655
- const defaultVariants = [];
656
- const needsConsent = context.requireConsentForPersonalization;
657
- const canEvaluate = !needsConsent || context.storage.data.consent;
658
- for (const variant of variations) {
659
- if ((_a = variant.pz) == null ? void 0 : _a.crit.length) {
660
- if (canEvaluate && variantMatches.length !== take && evaluateVariantMatch(variant.id, variant.pz, context.scores, onLogMessage)) {
661
- variantMatches.push(variant);
704
+ const variationMatches = [];
705
+ const defaultVariations = [];
706
+ const needsConsentToPersonalize = context.requireConsentForPersonalization;
707
+ const personalizationAllowed = !needsConsentToPersonalize || context.storage.data.consent;
708
+ for (const variation of variations) {
709
+ const isInvalidFormat = variation.pz && (typeof variation.pz !== "object" || variation.pz === null || !("crit" in variation.pz && Array.isArray(variation.pz.crit)));
710
+ let validVariation;
711
+ if (isInvalidFormat) {
712
+ validVariation = { id: variation.id };
713
+ } else {
714
+ validVariation = variation;
715
+ }
716
+ if ((_a = validVariation.pz) == null ? void 0 : _a.crit.length) {
717
+ if (personalizationAllowed && variationMatches.length !== take && evaluateVariantMatch(variation.id, validVariation.pz, context.scores, onLogMessage, context.quirks)) {
718
+ variationMatches.push(validVariation);
662
719
  }
663
720
  } else {
664
- defaultVariants.push(variant);
721
+ defaultVariations.push(validVariation);
665
722
  }
666
723
  }
667
724
  const result = [];
668
- for (let i = 0; i < variantMatches.length; i++) {
725
+ for (let i = 0; i < variationMatches.length; i++) {
669
726
  let isControl = (_b = context.storage.data.controlGroup) != null ? _b : false;
670
- const variant = variantMatches[i];
671
- if (!isControl && typeof ((_c = variant.pz) == null ? void 0 : _c.control) === "number") {
727
+ const variation = variationMatches[i];
728
+ if (!isControl && typeof ((_c = variation.pz) == null ? void 0 : _c.control) === "number") {
672
729
  isControl = context.getPersonalizeVariantControl(name, i);
673
730
  if (typeof isControl === "undefined") {
674
- isControl = rollForControlGroup(variant.pz.control);
731
+ isControl = rollForControlGroup(variation.pz.control);
675
732
  context.storage.updateData([
676
733
  {
677
734
  type: "setpersonalizecontrol",
@@ -684,13 +741,13 @@ function personalizeVariations({
684
741
  ]);
685
742
  }
686
743
  }
687
- let variantToAdd = variant;
744
+ let variantToAdd = variation;
688
745
  if (isControl) {
689
- const defaultReplacement = defaultVariants.shift();
746
+ const defaultReplacement = defaultVariations.shift();
690
747
  if (defaultReplacement) {
691
748
  variantToAdd = {
692
749
  ...defaultReplacement,
693
- id: variant.id
750
+ id: variation.id
694
751
  };
695
752
  } else {
696
753
  variantToAdd = void 0;
@@ -700,8 +757,8 @@ function personalizeVariations({
700
757
  result.push({ ...variantToAdd, control: isControl });
701
758
  }
702
759
  }
703
- while (result.length < take && defaultVariants.length) {
704
- result.push({ ...defaultVariants.shift(), control: false });
760
+ while (result.length < take && defaultVariations.length) {
761
+ result.push({ ...defaultVariations.shift(), control: false });
705
762
  }
706
763
  const personalized = result.some((v) => {
707
764
  var _a2;
@@ -716,7 +773,82 @@ function personalizeVariations({
716
773
  }
717
774
  }
718
775
 
719
- // src/placement/test.ts
776
+ // src/placement/personalizeVariations.ts
777
+ function personalizeVariations(options) {
778
+ return topDownCriteriaPersonalizationSelectionAlgorithm(options);
779
+ }
780
+
781
+ // src/placement/strongestScorePersonalizationSelectionAlgorithm.ts
782
+ var STRONGEST_SCORE_PERSONALIZATION_ALGORITHM = "ssc";
783
+ function strongestScorePersonalizationSelectionAlgorithm({
784
+ name,
785
+ context,
786
+ variations,
787
+ take = 1,
788
+ onLogMessage
789
+ }) {
790
+ var _a, _b;
791
+ onLogMessage == null ? void 0 : onLogMessage(["info", 300, "GROUP", { name, take }]);
792
+ try {
793
+ const variationMatches = [];
794
+ const defaultVariations = [];
795
+ const needsConsentToPersonalize = context.requireConsentForPersonalization;
796
+ const isInGlobalControlGroup = (_a = context.storage.data.controlGroup) != null ? _a : false;
797
+ const personalizationAllowed = !needsConsentToPersonalize || context.storage.data.consent;
798
+ for (const variation of variations) {
799
+ const isInvalidFormat = variation.pz && (typeof variation.pz !== "object" || variation.pz === null);
800
+ let validVariation;
801
+ if (isInvalidFormat) {
802
+ validVariation = { id: variation.id };
803
+ } else {
804
+ validVariation = variation;
805
+ }
806
+ if ((_b = validVariation.pz) == null ? void 0 : _b.dim) {
807
+ if (!personalizationAllowed) {
808
+ continue;
809
+ }
810
+ const score = context.scores[validVariation.pz.dim];
811
+ if (score === void 0 || score <= 0) {
812
+ continue;
813
+ }
814
+ variationMatches.push({ variation: validVariation, score });
815
+ } else {
816
+ defaultVariations.push(validVariation);
817
+ }
818
+ }
819
+ variationMatches.sort((a, b) => b.score - a.score);
820
+ const result = [];
821
+ for (let i = 0; i < variationMatches.length; i++) {
822
+ const variationMatch = variationMatches[i];
823
+ let variantToAdd = variationMatch.variation;
824
+ if (isInGlobalControlGroup) {
825
+ const defaultReplacement = defaultVariations.shift();
826
+ if (defaultReplacement) {
827
+ variantToAdd = {
828
+ ...defaultReplacement,
829
+ id: variationMatch.variation.id
830
+ };
831
+ } else {
832
+ variantToAdd = void 0;
833
+ }
834
+ }
835
+ if (variantToAdd) {
836
+ result.push({ ...variantToAdd, control: isInGlobalControlGroup });
837
+ }
838
+ }
839
+ while (result.length < take && defaultVariations.length) {
840
+ result.push({ ...defaultVariations.shift(), control: false });
841
+ }
842
+ return {
843
+ personalized: variationMatches.length > 0 && !isInGlobalControlGroup,
844
+ variations: result
845
+ };
846
+ } finally {
847
+ onLogMessage == null ? void 0 : onLogMessage(["info", 300, "ENDGROUP"]);
848
+ }
849
+ }
850
+
851
+ // src/placement/normalizeVariationDistributions.ts
720
852
  var normalizeVariationDistributions = (variations) => {
721
853
  const { values, total, missingDistribution } = variations.reduce(
722
854
  (previous, current) => {
@@ -735,7 +867,12 @@ var normalizeVariationDistributions = (variations) => {
735
867
  }
736
868
  );
737
869
  if (total > 100) {
738
- throw new Error(`Total distribution ${total} is over the maximum 100.`);
870
+ const autoScaleFactor = 100 / total;
871
+ values.forEach((value, index) => {
872
+ if (typeof value === "number") {
873
+ values[index] = value * autoScaleFactor;
874
+ }
875
+ });
739
876
  } else if (total < 100) {
740
877
  const remainder = 100 - total;
741
878
  const missingSlice = remainder / missingDistribution;
@@ -747,6 +884,8 @@ var normalizeVariationDistributions = (variations) => {
747
884
  }
748
885
  return values;
749
886
  };
887
+
888
+ // src/placement/testVariations.ts
750
889
  var testVariations = ({
751
890
  name,
752
891
  context,
@@ -1513,11 +1652,12 @@ import { dequal as dequal5 } from "dequal/lite";
1513
1652
  import mitt3 from "mitt";
1514
1653
  var CONTEXTUAL_EDITING_TEST_NAME = "contextual_editing_test";
1515
1654
  var CONTEXTUAL_EDITING_TEST_SELECTED_VARIANT_ID = "contextual_editing_test_selected_variant";
1516
- var _serverTransitionState, _scores, _state, _pzCache, _plugins, _commands, _requireConsentForPersonalization, _mitt3, _Context_instances, emitTest_fn, updateGoals_fn, updateComputedScores_fn, calculateScores_fn;
1655
+ var _personalizationSelectionAlgorithms, _serverTransitionState, _scores, _state, _pzCache, _plugins, _commands, _requireConsentForPersonalization, _mitt3, _Context_instances, emitTest_fn, updateGoals_fn, updateComputedScores_fn, calculateScores_fn;
1517
1656
  var Context = class {
1518
1657
  constructor(options) {
1519
1658
  __privateAdd(this, _Context_instances);
1520
1659
  __publicField(this, "manifest");
1660
+ __privateAdd(this, _personalizationSelectionAlgorithms);
1521
1661
  __privateAdd(this, _serverTransitionState);
1522
1662
  __privateAdd(this, _scores, {});
1523
1663
  __privateAdd(this, _state);
@@ -1534,7 +1674,7 @@ var Context = class {
1534
1674
  off: __privateGet(this, _mitt3).off
1535
1675
  });
1536
1676
  __publicField(this, "storage");
1537
- var _a, _b;
1677
+ var _a, _b, _c;
1538
1678
  const { manifest, ...storageOptions } = options;
1539
1679
  __privateSet(this, _state, {});
1540
1680
  __privateSet(this, _plugins, options.plugins);
@@ -1542,7 +1682,20 @@ var Context = class {
1542
1682
  if (typeof options.transitionStore !== "undefined") {
1543
1683
  __privateSet(this, _commands, []);
1544
1684
  }
1685
+ __privateSet(this, _personalizationSelectionAlgorithms, {
1686
+ [TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM]: topDownCriteriaPersonalizationSelectionAlgorithm,
1687
+ [STRONGEST_SCORE_PERSONALIZATION_ALGORITHM]: strongestScorePersonalizationSelectionAlgorithm
1688
+ });
1545
1689
  (_a = __privateGet(this, _plugins)) == null ? void 0 : _a.forEach((plugin) => {
1690
+ if (!plugin.personalizationSelectionAlgorithms) {
1691
+ return;
1692
+ }
1693
+ __privateSet(this, _personalizationSelectionAlgorithms, {
1694
+ ...__privateGet(this, _personalizationSelectionAlgorithms),
1695
+ ...plugin.personalizationSelectionAlgorithms
1696
+ });
1697
+ });
1698
+ (_b = __privateGet(this, _plugins)) == null ? void 0 : _b.forEach((plugin) => {
1546
1699
  if (!plugin.logDrain) {
1547
1700
  return;
1548
1701
  }
@@ -1593,7 +1746,7 @@ var Context = class {
1593
1746
  __privateGet(this, _mitt3).emit("quirksUpdated", quirks.quirks);
1594
1747
  __privateGet(this, _mitt3).emit("log", ["info", 4, quirks.quirks]);
1595
1748
  });
1596
- (_b = __privateGet(this, _plugins)) == null ? void 0 : _b.forEach((plugin) => {
1749
+ (_c = __privateGet(this, _plugins)) == null ? void 0 : _c.forEach((plugin) => {
1597
1750
  if (!plugin.init) {
1598
1751
  return;
1599
1752
  }
@@ -1843,7 +1996,17 @@ var Context = class {
1843
1996
  }
1844
1997
  /** Executes a personalized placement with a given set of variants */
1845
1998
  personalize(options) {
1846
- const value = personalizeVariations({
1999
+ var _a;
2000
+ const algorithmName = (_a = options.algorithm) != null ? _a : TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM;
2001
+ const algorithm = __privateGet(this, _personalizationSelectionAlgorithms)[algorithmName];
2002
+ if (!algorithm) {
2003
+ __privateGet(this, _mitt3).emit("log", ["warn", 304, { algorithm: algorithmName }]);
2004
+ return {
2005
+ personalized: false,
2006
+ variations: []
2007
+ };
2008
+ }
2009
+ const value = algorithm({
1847
2010
  ...options,
1848
2011
  context: this,
1849
2012
  onLogMessage: (message) => __privateGet(this, _mitt3).emit("log", message)
@@ -1917,6 +2080,7 @@ var Context = class {
1917
2080
  __privateGet(this, _mitt3).emit("personalizationResult", event);
1918
2081
  }
1919
2082
  };
2083
+ _personalizationSelectionAlgorithms = new WeakMap();
1920
2084
  _serverTransitionState = new WeakMap();
1921
2085
  _scores = new WeakMap();
1922
2086
  _state = new WeakMap();
@@ -2512,6 +2676,10 @@ var messageContent = {
2512
2676
  301: ({ id, op }) => ["personalization", `testing variation ${id} (${op === "|" ? "OR" : "AND"})`],
2513
2677
  302: ({ matched, description }) => ["personalization", `${description} is ${matched}`],
2514
2678
  303: (selected) => ["personalization", selected ? "selected variation" : "did not select variation"],
2679
+ 304: ({ algorithm }) => [
2680
+ "personalization",
2681
+ `personalization selection algorithm '${algorithm}' not found. Hiding placement.`
2682
+ ],
2515
2683
  // TESTING
2516
2684
  400: (name) => ["testing", `executing A/B test '${name}'`],
2517
2685
  401: (testName) => ["testing", `${testName} is not registered in the manifest; it will not be run.`],
@@ -2616,7 +2784,9 @@ export {
2616
2784
  PAIR_SEP,
2617
2785
  QUIRK_SEP,
2618
2786
  SERVER_STATE_ID,
2787
+ STRONGEST_SCORE_PERSONALIZATION_ALGORITHM,
2619
2788
  ScriptType,
2789
+ TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM,
2620
2790
  TYPE_SEP,
2621
2791
  TransitionDataStore,
2622
2792
  UNIFORM_DEFAULT_COOKIE_NAME,
@@ -2658,5 +2828,7 @@ export {
2658
2828
  serializePersonalizeVariants,
2659
2829
  serializeQuickConnect,
2660
2830
  serializeQuirks,
2661
- testVariations
2831
+ strongestScorePersonalizationSelectionAlgorithm,
2832
+ testVariations,
2833
+ topDownCriteriaPersonalizationSelectionAlgorithm
2662
2834
  };
@@ -859,6 +859,10 @@ type LogMessages = {
859
859
  }>;
860
860
  /** Final result for a personalized variation */
861
861
  303: MessageFunc<boolean>;
862
+ /** Personalization algorithm not found */
863
+ 304: MessageFunc<{
864
+ algorithm: string;
865
+ }>;
862
866
  /** A/B test placement executing */
863
867
  400: MessageFunc<string>;
864
868
  /** A/B Test definition did not exist */
@@ -898,23 +902,34 @@ type LogMessageSingle<TID extends keyof LogMessages = keyof LogMessages> = [
898
902
  type LogMessageGroup<TID extends keyof LogMessages = keyof LogMessages> = [severity: Severity, id: TID, group: 'GROUP', ...args: Parameters<LogMessages[TID]>] | [severity: Severity, id: TID, group: 'ENDGROUP'];
899
903
  type LogDrain = (message: LogMessage) => void;
900
904
 
901
- type VariantMatchCriteria = {
905
+ /** Data for a personalization variation using the top-down criteria selection algorithm */
906
+ interface VariantMatchCriteria extends VariationMatchMetadata {
902
907
  /**
903
908
  * Operation for match criteria
904
909
  *
905
910
  * @defaultValue `&`
906
911
  */
907
912
  op?: '&' | '|';
908
- crit: DimensionMatch[];
909
- /**
910
- * Name of the variant for analytics tracking.
911
- */
912
- name?: string;
913
+ crit: Array<DimensionMatch | QuirkMatch>;
913
914
  /**
914
915
  * Control group percentage for the variant.
915
916
  */
916
917
  control?: number;
917
- };
918
+ }
919
+ /** Data for a personalization variation using the TODO selection algorithm */
920
+ interface VariationMatchDimensionCriteria extends VariationMatchMetadata {
921
+ /** The dimension this content is relevant to */
922
+ dim: string | undefined;
923
+ }
924
+ /** Data that must exist on a personalization variation regardless of selection algorithm */
925
+ interface VariationMatchMetadata {
926
+ /**
927
+ * Name of the variation for analytics tracking.
928
+ * NOTE: name is optional for backwards compatibility, but it is HIGHLY recommended to specify a name
929
+ * as the default fallback is not helpfully named and is reliant on the order of the variations array.
930
+ */
931
+ name?: string;
932
+ }
918
933
  type DimensionMatch = {
919
934
  /**
920
935
  * Left hand side of the match expression (name of dimension in score vector)
@@ -953,17 +968,48 @@ type DimensionMatch = {
953
968
  */
954
969
  rDim?: string;
955
970
  };
971
+ type QuirkMatch = {
972
+ /**
973
+ * Type of match expression; 'q' discriminates quirk matches from dimension matches
974
+ */
975
+ t: 'q';
976
+ /**
977
+ * Left hand side of the match expression (name of quirk)
978
+ * NOTE: if the quirk is not present
979
+ */
980
+ l: string;
981
+ /**
982
+ * Operator of the match expression
983
+ * Comparison operators:
984
+ * =: `l` is equal to the right hand side expression
985
+ * !=: `l` is not equal to the right hand side expression
986
+ */
987
+ op: '=' | '!=';
988
+ /**
989
+ * Right hand side of the match expression
990
+ * This value is treated as a constant value, if it is present. If it's a string, it is parsed to an integer.
991
+ * To reference another score dimension as the RHS, use the `rDim` property instead.
992
+ * `r` and `rDim` are mutually exclusive; if both are specified, then `rDim` wins.
993
+ */
994
+ r: string;
995
+ /**
996
+ * Only here to maintain object compatibility with DimensionMatch.
997
+ * Completely ignored.
998
+ * @deprecated this is not used with QuirkMatch.
999
+ */
1000
+ rDim?: string;
1001
+ };
956
1002
 
957
1003
  /** Content that is tagged for adding enrichment score when triggered by behavior (i.e. being shown that content) */
958
1004
  type BehaviorTag = {
959
1005
  beh?: EnrichmentData[];
960
1006
  };
961
1007
  /** Defines the shape of a personalized content variant */
962
- type PersonalizedVariant = {
1008
+ type PersonalizedVariant<TCriteria = VariantMatchCriteria> = {
963
1009
  /** A unique identifier for this variation */
964
1010
  id: string;
965
1011
  /** Match criteria for this variation */
966
- pz?: VariantMatchCriteria;
1012
+ pz?: TCriteria;
967
1013
  };
968
1014
  /** The result of computing personalized content from variations */
969
1015
  type PersonalizedResult<TVariant> = {
@@ -971,6 +1017,7 @@ type PersonalizedResult<TVariant> = {
971
1017
  personalized: boolean;
972
1018
  /** Matching variations */
973
1019
  variations: Array<TVariant & {
1020
+ /** Whether the visitor is part of this variation's local control group (also true if part of global control group) */
974
1021
  control: boolean;
975
1022
  }>;
976
1023
  };
@@ -995,19 +1042,28 @@ type TestResult<TVariant> = {
995
1042
  */
996
1043
  variantAssigned: boolean;
997
1044
  };
998
-
999
- type PersonalizeOptions<TVariant> = {
1045
+ interface PersonalizeOptions<TVariant> {
1046
+ /** Name of placement (sent to analytics) */
1047
+ name: string;
1048
+ /** Possible variations to place */
1049
+ variations: Iterable<TVariant>;
1050
+ /** Maximum number of variants to place (default: 1) */
1051
+ take?: number;
1052
+ /** Name of the personalization selection algorithm to use. Defaults to top-down criteria when not specified. */
1053
+ algorithm?: string;
1054
+ }
1055
+ interface PersonalizationSelectionAlgorithmOptions<TCriteria, TVariant extends PersonalizedVariant<TCriteria> = PersonalizedVariant<TCriteria>> {
1000
1056
  /** Name of placement (sent to analytics) */
1001
1057
  name: string;
1002
- /** Possible variants to place */
1058
+ /** Possible variations to place */
1003
1059
  variations: Iterable<TVariant>;
1004
1060
  /** Maximum number of variants to place (default: 1) */
1005
1061
  take?: number;
1062
+ /** Callback for logging messages */
1006
1063
  onLogMessage?: (message: LogMessage) => void;
1007
- };
1008
- declare function personalizeVariations<TVariant extends PersonalizedVariant>({ name, context, variations, take, onLogMessage, }: PersonalizeOptions<TVariant> & {
1064
+ /** Context instance */
1009
1065
  context: Context;
1010
- }): PersonalizedResult<TVariant>;
1066
+ }
1011
1067
 
1012
1068
  type TestOptions<TVariant extends TestVariant> = {
1013
1069
  /** The name of the test that is being run, must be included in the manifest. */
@@ -1022,18 +1078,31 @@ declare const testVariations: <TVariant extends TestVariant>({ name, context, va
1022
1078
 
1023
1079
  declare const CONTEXTUAL_EDITING_TEST_NAME = "contextual_editing_test";
1024
1080
  declare const CONTEXTUAL_EDITING_TEST_SELECTED_VARIANT_ID = "contextual_editing_test_selected_variant";
1081
+ type PersonalizationSelectionAlgorithm<TCriteria = unknown> = (options: PersonalizationSelectionAlgorithmOptions<TCriteria>) => PersonalizedResult<PersonalizedVariant<TCriteria>>;
1082
+ type PersonalizationSelectionAlgorithms<TCriteria = unknown> = Record<string, PersonalizationSelectionAlgorithm<TCriteria>>;
1025
1083
  /**
1026
1084
  * Defines a plugin for Uniform Context.
1027
1085
  * The plugin should attach event handlers in its creation function.
1028
1086
  * @returns A function that detaches any event handlers when called
1029
1087
  */
1030
1088
  type ContextPlugin = {
1089
+ /** Defines a log drain for the plugin, which all log messages are sent to */
1031
1090
  logDrain?: LogDrain;
1091
+ /** Initializes the plugin (attach event handlers here if needed) */
1032
1092
  init?: (context: Context) => () => void;
1093
+ /** Plugin-specific actions to perform when a user is forgotten */
1033
1094
  forget?: () => Promise<void> | void;
1095
+ /** Plugin-specific actions to perform when the visitor context is updated */
1034
1096
  update?: (newData: Partial<ContextState>) => Promise<void> | void;
1097
+ /**
1098
+ * Allows the plugin to register named personalization selection algorithms
1099
+ *
1100
+ * Important: the `default` and `strongestMatch` algorithms are automatically registered.
1101
+ * We strongly advise against replacing these.
1102
+ */
1103
+ personalizationSelectionAlgorithms?: PersonalizationSelectionAlgorithms<any>;
1035
1104
  };
1036
- type ContextOptions = {
1105
+ interface ContextOptions extends Omit<VisitorDataStoreOptions, 'manifest' | 'onServerTransitionScoresReceived'> {
1037
1106
  /** The Context Manifest to load (from the Context API) */
1038
1107
  manifest: ManifestV2;
1039
1108
  /**
@@ -1050,16 +1119,19 @@ type ContextOptions = {
1050
1119
  * `true`: personalization is not run at all unless storage consent is given
1051
1120
  */
1052
1121
  requireConsentForPersonalization?: boolean;
1053
- } & Omit<VisitorDataStoreOptions, 'manifest' | 'onServerTransitionScoresReceived'>;
1122
+ }
1123
+ type PersonalizationEventVariantId = {
1124
+ /** The variant ID that was selected */
1125
+ id: string;
1126
+ /** Whether the visitor is part of this variant's local control group (also true if part of global control group) */
1127
+ control: boolean;
1128
+ };
1054
1129
  /** Emitted when a personalization runs */
1055
1130
  type PersonalizationEvent = {
1056
1131
  /** Name of the personalized placement */
1057
1132
  name: string;
1058
1133
  /** Selected variant ID(s) */
1059
- variantIds: {
1060
- id: string;
1061
- control: boolean;
1062
- }[];
1134
+ variantIds: PersonalizationEventVariantId[];
1063
1135
  /** Whether the user was part of the control group (and did not receive any personalization) */
1064
1136
  control: boolean | undefined;
1065
1137
  /**
@@ -1113,7 +1185,7 @@ interface ContextInstance {
1113
1185
  setTestVariantId(testName: string, variantId: string): void;
1114
1186
  log(...message: LogMessage): void;
1115
1187
  test<TVariant extends TestVariant>(options: TestOptions<TVariant>): TestResult<TVariant>;
1116
- personalize<TVariant extends PersonalizedVariant>(options: PersonalizeOptions<TVariant>): PersonalizedResult<TVariant>;
1188
+ personalize<TVariant extends PersonalizedVariant<any>>(options: PersonalizeOptions<TVariant>): PersonalizedResult<TVariant>;
1117
1189
  forget(fromAllDevices: boolean): Promise<void>;
1118
1190
  getServerToClientTransitionState(): ServerToClientTransitionState;
1119
1191
  readonly manifest: ManifestInstance;
@@ -1178,7 +1250,7 @@ declare class Context implements ContextInstance {
1178
1250
  /** Executes an A/B test with a given set of variants, showing the visitor's assigned variant (or selecting one to assign, if none is set yet) */
1179
1251
  test<TVariant extends TestVariant>(options: TestOptions<TVariant>): TestResult<TVariant>;
1180
1252
  /** Executes a personalized placement with a given set of variants */
1181
- personalize<TVariant extends PersonalizedVariant>(options: PersonalizeOptions<TVariant>): PersonalizedResult<TVariant>;
1253
+ personalize<TVariant extends PersonalizedVariant<any>>(options: PersonalizeOptions<TVariant>): PersonalizedResult<TVariant>;
1182
1254
  /**
1183
1255
  * Forgets the visitor's data and resets the Context to its initial state.
1184
1256
  * @param fromAllDevices for an identified user, whether to delete all their data (for the entire account) - true, or data for this device (sign out) - false
@@ -1265,4 +1337,4 @@ declare global {
1265
1337
  }
1266
1338
  }
1267
1339
 
1268
- export { type AggregateDimensionInput as $, type AggregateDimension as A, type MessageFunc as B, type ContextPlugin as C, type DecayFunction as D, type LogMessageSingle as E, type LogMessageGroup as F, ManifestInstance as G, GroupCriteriaEvaluator as H, type CriteriaEvaluatorResult as I, type CriteriaEvaluatorParameters as J, type SignalData as K, type LogDrain as L, type MessageCategory as M, type ManifestV2 as N, type OutputSeverity as O, type PersonalizationEvent as P, type Quirks as Q, type PersonalizationManifest as R, type ScoreVector as S, TransitionDataStore as T, type Signal as U, type VisitorData as V, type SignalCriteriaGroup as W, type SignalCriteria as X, type EnrichmentCategory as Y, type NumberMatch as Z, type TestDefinition as _, type StorageCommands as a, type TestOptions as a0, testVariations as a1, type DimensionMatch as a2, type PersonalizeOptions as a3, personalizeVariations as a4, type BehaviorTag as a5, type PersonalizedVariant as a6, type PersonalizedResult as a7, type TestVariant as a8, type TestResult as a9, type ContextStateUpdate as aA, type GoalStateUpdate as aB, type paths as aC, type StorageCommand as aa, type SetGoalCommand as ab, type ModifyScoreCommand as ac, type ModifySessionScoreCommand as ad, type SetConsentCommand as ae, type SetQuirkCommand as af, type SetTestCommand as ag, type IdentifyCommand as ah, type SetControlGroupCommand as ai, type SetPersonalizeVariantControlCommand as aj, areCommandsEqual as ak, type ServerToClientTransitionState as al, SERVER_STATE_ID as am, type TransitionDataStoreEvents as an, type DecayOptions as ao, type VisitorDataStoreOptions as ap, type VisitorDataStoreEvents as aq, VisitorDataStore as ar, type Tests as as, type Goals as at, type EnrichmentData as au, type PersonalizeControlVariant as av, type PersonalizeVariants as aw, type EventData as ax, emptyVisitorData as ay, type ContextState as az, type TransitionDataStoreOptions as b, type CriteriaEvaluator as c, type StringMatch as d, type VariantMatchCriteria as e, type LogMessage as f, type DevToolsEvents as g, CONTEXTUAL_EDITING_TEST_NAME as h, CONTEXTUAL_EDITING_TEST_SELECTED_VARIANT_ID as i, type ContextOptions as j, type TestEvent as k, type ContextEvents as l, type ContextInstance as m, Context as n, type DevToolsUiVersion as o, type DevToolsState as p, type DevToolsActions as q, type DevToolsEvent as r, type DevToolsLogEvent as s, type DevToolsDataEvent as t, type DevToolsHelloEvent as u, type DevToolsUpdateEvent as v, type DevToolsRawCommandsEvent as w, type DevToolsForgetEvent as x, type LogMessages as y, type Severity as z };
1340
+ export { type ManifestV2 as $, type AggregateDimension as A, type DevToolsLogEvent as B, type ContextPlugin as C, type DecayFunction as D, type DevToolsDataEvent as E, type DevToolsHelloEvent as F, type DevToolsUpdateEvent as G, type DevToolsRawCommandsEvent as H, type DevToolsForgetEvent as I, type LogMessages as J, type Severity as K, type LogDrain as L, type MessageCategory as M, type MessageFunc as N, type OutputSeverity as O, type PersonalizedVariant as P, type Quirks as Q, type LogMessageSingle as R, type ScoreVector as S, TransitionDataStore as T, type LogMessageGroup as U, type VisitorData as V, ManifestInstance as W, GroupCriteriaEvaluator as X, type CriteriaEvaluatorResult as Y, type CriteriaEvaluatorParameters as Z, type SignalData as _, type StorageCommands as a, type PersonalizationManifest as a0, type Signal as a1, type SignalCriteriaGroup as a2, type SignalCriteria as a3, type EnrichmentCategory as a4, type NumberMatch as a5, type TestDefinition as a6, type AggregateDimensionInput as a7, type TestOptions as a8, testVariations as a9, type EnrichmentData as aA, type PersonalizeControlVariant as aB, type PersonalizeVariants as aC, type EventData as aD, emptyVisitorData as aE, type ContextState as aF, type ContextStateUpdate as aG, type GoalStateUpdate as aH, type paths as aI, type VariationMatchMetadata as aa, type DimensionMatch as ab, type QuirkMatch as ac, type BehaviorTag as ad, type TestVariant as ae, type TestResult as af, type StorageCommand as ag, type SetGoalCommand as ah, type ModifyScoreCommand as ai, type ModifySessionScoreCommand as aj, type SetConsentCommand as ak, type SetQuirkCommand as al, type SetTestCommand as am, type IdentifyCommand as an, type SetControlGroupCommand as ao, type SetPersonalizeVariantControlCommand as ap, areCommandsEqual as aq, type ServerToClientTransitionState as ar, SERVER_STATE_ID as as, type TransitionDataStoreEvents as at, type DecayOptions as au, type VisitorDataStoreOptions as av, type VisitorDataStoreEvents as aw, VisitorDataStore as ax, type Tests as ay, type Goals as az, type TransitionDataStoreOptions as b, type CriteriaEvaluator as c, type StringMatch as d, type VariantMatchCriteria as e, type LogMessage as f, type PersonalizeOptions as g, Context as h, type PersonalizedResult as i, type VariationMatchDimensionCriteria as j, type PersonalizationSelectionAlgorithmOptions as k, type DevToolsEvents as l, CONTEXTUAL_EDITING_TEST_NAME as m, CONTEXTUAL_EDITING_TEST_SELECTED_VARIANT_ID as n, type PersonalizationSelectionAlgorithm as o, type PersonalizationSelectionAlgorithms as p, type ContextOptions as q, type PersonalizationEventVariantId as r, type PersonalizationEvent as s, type TestEvent as t, type ContextEvents as u, type ContextInstance as v, type DevToolsUiVersion as w, type DevToolsState as x, type DevToolsActions as y, type DevToolsEvent as z };