@uniformdev/context 20.7.1-alpha.12 → 20.7.1-alpha.121

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
@@ -227,6 +227,10 @@ var ManifestInstance = class {
227
227
  }
228
228
  return (_d = (_c = __privateGet(this, _mf).pz) == null ? void 0 : _c.enr) == null ? void 0 : _d[scoreKey.substring(0, enrichmentIndex)];
229
229
  }
230
+ getAggregateDimensionByKey(scoreKey) {
231
+ var _a, _b;
232
+ return (_b = (_a = __privateGet(this, _mf).pz) == null ? void 0 : _a.agg) == null ? void 0 : _b[scoreKey];
233
+ }
230
234
  };
231
235
  _mf = new WeakMap();
232
236
  _signalInstances = new WeakMap();
@@ -516,7 +520,7 @@ var GroupCriteriaEvaluator = class {
516
520
  _evaluators = new WeakMap();
517
521
 
518
522
  // src/placement/criteria/evaluateVariantMatch.ts
519
- function evaluateVariantMatch(variantId, match, vec, onLogMessage) {
523
+ function evaluateVariantMatch(variantId, match, vec, onLogMessage, quirks) {
520
524
  onLogMessage == null ? void 0 : onLogMessage(["info", 301, "GROUP", { id: variantId, op: match == null ? void 0 : match.op }]);
521
525
  let result;
522
526
  try {
@@ -524,9 +528,9 @@ function evaluateVariantMatch(variantId, match, vec, onLogMessage) {
524
528
  onLogMessage == null ? void 0 : onLogMessage(["info", 302, { matched: true, description: "default variation" }]);
525
529
  result = true;
526
530
  } else if (!match.op || match.op === "&") {
527
- result = match.crit.every((c) => evaluateDimensionMatch(c, vec, onLogMessage));
531
+ result = match.crit.every((c) => evaluateMatch(c, vec, quirks != null ? quirks : {}, onLogMessage));
528
532
  } else {
529
- result = match.crit.some((c) => evaluateDimensionMatch(c, vec, onLogMessage));
533
+ result = match.crit.some((c) => evaluateMatch(c, vec, quirks != null ? quirks : {}, onLogMessage));
530
534
  }
531
535
  onLogMessage == null ? void 0 : onLogMessage(["info", 303, result]);
532
536
  } finally {
@@ -534,9 +538,16 @@ function evaluateVariantMatch(variantId, match, vec, onLogMessage) {
534
538
  }
535
539
  return result;
536
540
  }
541
+ function evaluateMatch(crit, vec, quirks, onLogMessage) {
542
+ if ("t" in crit && crit.t === "q") {
543
+ return evaluateQuirkMatch(crit, quirks, onLogMessage);
544
+ } else {
545
+ return evaluateDimensionMatch(crit, vec, onLogMessage);
546
+ }
547
+ }
537
548
  function evaluateDimensionMatch(crit, vec, onLogMessage) {
538
549
  var _a, _b;
539
- const { op, l: lhs } = crit;
550
+ const { l: lhs, op } = crit;
540
551
  const lhsScore = (_a = vec[lhs]) != null ? _a : 0;
541
552
  if (op === "^") {
542
553
  const [cat] = lhs.split(ENR_SEPARATOR);
@@ -603,33 +614,65 @@ function evaluateDimensionMatch(crit, vec, onLogMessage) {
603
614
  }
604
615
  if (op === ">") {
605
616
  const result = lhsScore > rhsScore;
606
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
617
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
607
618
  return result;
608
619
  } else if (op === ">=") {
609
620
  const result = lhsScore >= rhsScore;
610
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
621
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
611
622
  return result;
612
623
  } else if (op === "<") {
613
624
  const result = lhsScore < rhsScore;
614
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
625
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
615
626
  return result;
616
627
  } else if (op === "<=") {
617
628
  const result = lhsScore <= rhsScore;
618
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
629
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
619
630
  return result;
620
631
  } else if (op === "=") {
621
632
  const result = lhsScore === rhsScore;
622
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
633
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
623
634
  return result;
624
635
  } else if (op === "!=") {
625
636
  const result = lhsScore !== rhsScore;
626
- explain(onLogMessage, result, crit, lhsScore, rhsScore);
637
+ explainScore(onLogMessage, result, crit, lhsScore, rhsScore);
627
638
  return result;
628
639
  } else {
629
- throw new Error(`Unknown op: ${op}`);
640
+ onLogMessage == null ? void 0 : onLogMessage([
641
+ "error",
642
+ 302,
643
+ {
644
+ matched: false,
645
+ description: `${crit.l} ${crit.op} ${crit.rDim ? `${crit.rDim}` : crit.r}: Unknown op ${crit.op}.`
646
+ }
647
+ ]);
648
+ return false;
630
649
  }
631
650
  }
632
- function explain(onLogMessage, result, crit, lhsScore, rhsScore) {
651
+ function evaluateQuirkMatch(crit, quirks, onLogMessage) {
652
+ var _a;
653
+ const { l: targetQuirk, op, r: targetValue } = crit;
654
+ const targetQuirkValue = (_a = quirks[targetQuirk]) != null ? _a : "";
655
+ if (op === "=") {
656
+ const result = targetQuirkValue === targetValue;
657
+ explainQuirk(onLogMessage, result, crit, targetQuirkValue);
658
+ return result;
659
+ } else if (op === "!=") {
660
+ const result = targetQuirkValue !== targetValue;
661
+ explainQuirk(onLogMessage, result, crit, targetQuirkValue);
662
+ return result;
663
+ } else {
664
+ onLogMessage == null ? void 0 : onLogMessage([
665
+ "error",
666
+ 302,
667
+ {
668
+ matched: false,
669
+ description: `Quirk ${crit.l} ${crit.op} ${crit.r}: Unknown quirk op ${crit.op}.`
670
+ }
671
+ ]);
672
+ return false;
673
+ }
674
+ }
675
+ function explainScore(onLogMessage, result, crit, lhsScore, rhsScore) {
633
676
  onLogMessage == null ? void 0 : onLogMessage([
634
677
  "info",
635
678
  302,
@@ -639,9 +682,20 @@ function explain(onLogMessage, result, crit, lhsScore, rhsScore) {
639
682
  }
640
683
  ]);
641
684
  }
685
+ function explainQuirk(onLogMessage, result, crit, lhs) {
686
+ onLogMessage == null ? void 0 : onLogMessage([
687
+ "info",
688
+ 302,
689
+ {
690
+ matched: result,
691
+ description: `Quirk ${crit.l}[${lhs}] ${crit.op} ${crit.r}`
692
+ }
693
+ ]);
694
+ }
642
695
 
643
- // src/placement/personalize.ts
644
- function personalizeVariations({
696
+ // src/placement/topDownCriteriaPersonalizationSelectionAlgorithm.ts
697
+ var TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM = "default";
698
+ function topDownCriteriaPersonalizationSelectionAlgorithm({
645
699
  name,
646
700
  context,
647
701
  variations,
@@ -651,27 +705,35 @@ function personalizeVariations({
651
705
  var _a, _b, _c;
652
706
  onLogMessage == null ? void 0 : onLogMessage(["info", 300, "GROUP", { name, take }]);
653
707
  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);
708
+ const variationMatches = [];
709
+ const defaultVariations = [];
710
+ const needsConsentToPersonalize = context.requireConsentForPersonalization;
711
+ const personalizationAllowed = !needsConsentToPersonalize || context.storage.data.consent;
712
+ for (const variation of variations) {
713
+ const isInvalidFormat = variation.pz && (typeof variation.pz !== "object" || variation.pz === null || !("crit" in variation.pz && Array.isArray(variation.pz.crit)));
714
+ let validVariation;
715
+ if (isInvalidFormat) {
716
+ const { pz, ...validParts } = variation;
717
+ validVariation = validParts;
718
+ } else {
719
+ validVariation = variation;
720
+ }
721
+ if ((_a = validVariation.pz) == null ? void 0 : _a.crit.length) {
722
+ if (personalizationAllowed && variationMatches.length !== take && evaluateVariantMatch(variation.id, validVariation.pz, context.scores, onLogMessage, context.quirks)) {
723
+ variationMatches.push(validVariation);
662
724
  }
663
725
  } else {
664
- defaultVariants.push(variant);
726
+ defaultVariations.push(validVariation);
665
727
  }
666
728
  }
667
729
  const result = [];
668
- for (let i = 0; i < variantMatches.length; i++) {
730
+ for (let i = 0; i < variationMatches.length; i++) {
669
731
  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") {
732
+ const variation = variationMatches[i];
733
+ if (!isControl && typeof ((_c = variation.pz) == null ? void 0 : _c.control) === "number") {
672
734
  isControl = context.getPersonalizeVariantControl(name, i);
673
735
  if (typeof isControl === "undefined") {
674
- isControl = rollForControlGroup(variant.pz.control);
736
+ isControl = rollForControlGroup(variation.pz.control);
675
737
  context.storage.updateData([
676
738
  {
677
739
  type: "setpersonalizecontrol",
@@ -684,13 +746,13 @@ function personalizeVariations({
684
746
  ]);
685
747
  }
686
748
  }
687
- let variantToAdd = variant;
749
+ let variantToAdd = variation;
688
750
  if (isControl) {
689
- const defaultReplacement = defaultVariants.shift();
751
+ const defaultReplacement = defaultVariations.shift();
690
752
  if (defaultReplacement) {
691
753
  variantToAdd = {
692
754
  ...defaultReplacement,
693
- id: variant.id
755
+ id: variation.id
694
756
  };
695
757
  } else {
696
758
  variantToAdd = void 0;
@@ -700,8 +762,8 @@ function personalizeVariations({
700
762
  result.push({ ...variantToAdd, control: isControl });
701
763
  }
702
764
  }
703
- while (result.length < take && defaultVariants.length) {
704
- result.push({ ...defaultVariants.shift(), control: false });
765
+ while (result.length < take && defaultVariations.length) {
766
+ result.push({ ...defaultVariations.shift(), control: false });
705
767
  }
706
768
  const personalized = result.some((v) => {
707
769
  var _a2;
@@ -716,7 +778,94 @@ function personalizeVariations({
716
778
  }
717
779
  }
718
780
 
719
- // src/placement/test.ts
781
+ // src/placement/personalizeVariations.ts
782
+ function personalizeVariations(options) {
783
+ return topDownCriteriaPersonalizationSelectionAlgorithm(options);
784
+ }
785
+
786
+ // src/placement/strongestScorePersonalizationSelectionAlgorithm.ts
787
+ var STRONGEST_SCORE_PERSONALIZATION_ALGORITHM = "ssc";
788
+ function strongestScorePersonalizationSelectionAlgorithm({
789
+ name,
790
+ context,
791
+ variations,
792
+ take = 1,
793
+ onLogMessage
794
+ }) {
795
+ var _a, _b;
796
+ onLogMessage == null ? void 0 : onLogMessage(["info", 300, "GROUP", { name, take }]);
797
+ try {
798
+ const variationMatches = [];
799
+ const defaultVariations = [];
800
+ const needsConsentToPersonalize = context.requireConsentForPersonalization;
801
+ const isInGlobalControlGroup = (_a = context.storage.data.controlGroup) != null ? _a : false;
802
+ const personalizationAllowed = !needsConsentToPersonalize || context.storage.data.consent;
803
+ let originalIndex = 0;
804
+ for (const variation of variations) {
805
+ const isInvalidFormat = variation.pz && typeof variation.pz !== "object";
806
+ let validVariation;
807
+ if (isInvalidFormat) {
808
+ const { pz, ...validParts } = variation;
809
+ validVariation = validParts;
810
+ } else {
811
+ validVariation = variation;
812
+ }
813
+ if ((_b = validVariation.pz) == null ? void 0 : _b.dim) {
814
+ if (!personalizationAllowed) {
815
+ continue;
816
+ }
817
+ const score = context.scores[validVariation.pz.dim];
818
+ if (score === void 0 || score <= 0) {
819
+ continue;
820
+ }
821
+ variationMatches.push({ variation: validVariation, score, originalIndex });
822
+ originalIndex++;
823
+ } else {
824
+ defaultVariations.push(validVariation);
825
+ }
826
+ }
827
+ variationMatches.sort((a, b) => {
828
+ const scoreComparison = b.score - a.score;
829
+ if (scoreComparison === 0) {
830
+ return a.originalIndex - b.originalIndex;
831
+ }
832
+ return scoreComparison;
833
+ });
834
+ const result = [];
835
+ for (let i = 0; i < variationMatches.length; i++) {
836
+ const variationMatch = variationMatches[i];
837
+ let variantToAdd = variationMatch.variation;
838
+ if (i >= take) {
839
+ continue;
840
+ }
841
+ if (isInGlobalControlGroup) {
842
+ const defaultReplacement = defaultVariations.shift();
843
+ if (defaultReplacement) {
844
+ variantToAdd = {
845
+ ...defaultReplacement,
846
+ id: variationMatch.variation.id
847
+ };
848
+ } else {
849
+ variantToAdd = void 0;
850
+ }
851
+ }
852
+ if (variantToAdd) {
853
+ result.push({ ...variantToAdd, control: isInGlobalControlGroup });
854
+ }
855
+ }
856
+ while (result.length < take && defaultVariations.length) {
857
+ result.push({ ...defaultVariations.shift(), control: false });
858
+ }
859
+ return {
860
+ personalized: variationMatches.length > 0 && !isInGlobalControlGroup,
861
+ variations: result
862
+ };
863
+ } finally {
864
+ onLogMessage == null ? void 0 : onLogMessage(["info", 300, "ENDGROUP"]);
865
+ }
866
+ }
867
+
868
+ // src/placement/normalizeVariationDistributions.ts
720
869
  var normalizeVariationDistributions = (variations) => {
721
870
  const { values, total, missingDistribution } = variations.reduce(
722
871
  (previous, current) => {
@@ -735,7 +884,12 @@ var normalizeVariationDistributions = (variations) => {
735
884
  }
736
885
  );
737
886
  if (total > 100) {
738
- throw new Error(`Total distribution ${total} is over the maximum 100.`);
887
+ const autoScaleFactor = 100 / total;
888
+ values.forEach((value, index) => {
889
+ if (typeof value === "number") {
890
+ values[index] = value * autoScaleFactor;
891
+ }
892
+ });
739
893
  } else if (total < 100) {
740
894
  const remainder = 100 - total;
741
895
  const missingSlice = remainder / missingDistribution;
@@ -747,6 +901,8 @@ var normalizeVariationDistributions = (variations) => {
747
901
  }
748
902
  return values;
749
903
  };
904
+
905
+ // src/placement/testVariations.ts
750
906
  var testVariations = ({
751
907
  name,
752
908
  context,
@@ -773,11 +929,11 @@ var testVariations = ({
773
929
  }
774
930
  if (!selectedVariant) {
775
931
  const distributions = normalizeVariationDistributions(variations);
776
- const random = Math.floor(Math.random() * 100);
932
+ const random = Math.random() * 100;
777
933
  let distributionOffset = 0;
778
934
  selectedVariant = variations.find((variant, index) => {
779
935
  const distribution = distributions[index];
780
- if ((random > distributionOffset || random === 0) && random <= distributionOffset + distribution) {
936
+ if (random >= distributionOffset && random < distributionOffset + distribution) {
781
937
  return variant;
782
938
  }
783
939
  distributionOffset += distribution;
@@ -789,6 +945,9 @@ var testVariations = ({
789
945
  }
790
946
  if (selectedVariant) {
791
947
  onLogMessage == null ? void 0 : onLogMessage(["info", 404, selectedVariant.id]);
948
+ if (selectedVariant.control === void 0) {
949
+ selectedVariant.control = variations.findIndex((variation) => variation.id === selectedVariantId) === 0;
950
+ }
792
951
  }
793
952
  return {
794
953
  result: selectedVariant,
@@ -970,6 +1129,7 @@ _quirksEnabled = new WeakMap();
970
1129
  var TYPE_SEP = "~";
971
1130
  var PAIR_SEP = "!";
972
1131
  var KV_SEP = "-";
1132
+ var QUIRK_KV_SEP = "=";
973
1133
  var QUIRK_SEP = "!!";
974
1134
  function parseScoreCookie(cookieValue, quirkCookieValue) {
975
1135
  if (!cookieValue) return;
@@ -993,7 +1153,7 @@ function parseScoreCookie(cookieValue, quirkCookieValue) {
993
1153
  function parseQuirkCookie(quirkCookieValue) {
994
1154
  const pairs = quirkCookieValue.split(QUIRK_SEP);
995
1155
  const splitPairs = pairs.map((pair) => {
996
- const sep = pair.indexOf(KV_SEP);
1156
+ const sep = pair.indexOf(QUIRK_KV_SEP);
997
1157
  if (sep === -1) {
998
1158
  return void 0;
999
1159
  }
@@ -1094,7 +1254,7 @@ function serializeCookieType(type) {
1094
1254
  return Object.entries(type).map((kv) => kv.join(KV_SEP)).join(PAIR_SEP);
1095
1255
  }
1096
1256
  function serializeQuirks(quirks) {
1097
- return Object.entries(quirks).map((kv) => kv.join(KV_SEP)).join(QUIRK_SEP);
1257
+ return Object.entries(quirks).map((kv) => kv.join(QUIRK_KV_SEP)).join(QUIRK_SEP);
1098
1258
  }
1099
1259
 
1100
1260
  // src/storage/EdgeTransitionDataStore.ts
@@ -1513,11 +1673,12 @@ import { dequal as dequal5 } from "dequal/lite";
1513
1673
  import mitt3 from "mitt";
1514
1674
  var CONTEXTUAL_EDITING_TEST_NAME = "contextual_editing_test";
1515
1675
  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;
1676
+ var _personalizationSelectionAlgorithms, _serverTransitionState, _scores, _state, _pzCache, _plugins, _commands, _requireConsentForPersonalization, _mitt3, _Context_instances, emitTest_fn, updateGoals_fn, updateComputedScores_fn, calculateScores_fn;
1517
1677
  var Context = class {
1518
1678
  constructor(options) {
1519
1679
  __privateAdd(this, _Context_instances);
1520
1680
  __publicField(this, "manifest");
1681
+ __privateAdd(this, _personalizationSelectionAlgorithms);
1521
1682
  __privateAdd(this, _serverTransitionState);
1522
1683
  __privateAdd(this, _scores, {});
1523
1684
  __privateAdd(this, _state);
@@ -1534,7 +1695,7 @@ var Context = class {
1534
1695
  off: __privateGet(this, _mitt3).off
1535
1696
  });
1536
1697
  __publicField(this, "storage");
1537
- var _a, _b;
1698
+ var _a, _b, _c;
1538
1699
  const { manifest, ...storageOptions } = options;
1539
1700
  __privateSet(this, _state, {});
1540
1701
  __privateSet(this, _plugins, options.plugins);
@@ -1542,7 +1703,20 @@ var Context = class {
1542
1703
  if (typeof options.transitionStore !== "undefined") {
1543
1704
  __privateSet(this, _commands, []);
1544
1705
  }
1706
+ __privateSet(this, _personalizationSelectionAlgorithms, {
1707
+ [TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM]: topDownCriteriaPersonalizationSelectionAlgorithm,
1708
+ [STRONGEST_SCORE_PERSONALIZATION_ALGORITHM]: strongestScorePersonalizationSelectionAlgorithm
1709
+ });
1545
1710
  (_a = __privateGet(this, _plugins)) == null ? void 0 : _a.forEach((plugin) => {
1711
+ if (!plugin.personalizationSelectionAlgorithms) {
1712
+ return;
1713
+ }
1714
+ __privateSet(this, _personalizationSelectionAlgorithms, {
1715
+ ...__privateGet(this, _personalizationSelectionAlgorithms),
1716
+ ...plugin.personalizationSelectionAlgorithms
1717
+ });
1718
+ });
1719
+ (_b = __privateGet(this, _plugins)) == null ? void 0 : _b.forEach((plugin) => {
1546
1720
  if (!plugin.logDrain) {
1547
1721
  return;
1548
1722
  }
@@ -1571,6 +1745,9 @@ var Context = class {
1571
1745
  __privateSet(this, _scores, state.ssv);
1572
1746
  __privateGet(this, _mitt3).emit("log", ["debug", 130, state]);
1573
1747
  }
1748
+ if (state.compositionMetadata) {
1749
+ __privateGet(this, _state).compositionMetadata = state.compositionMetadata;
1750
+ }
1574
1751
  },
1575
1752
  onLogMessage: (message) => __privateGet(this, _mitt3).emit("log", message)
1576
1753
  });
@@ -1593,7 +1770,7 @@ var Context = class {
1593
1770
  __privateGet(this, _mitt3).emit("quirksUpdated", quirks.quirks);
1594
1771
  __privateGet(this, _mitt3).emit("log", ["info", 4, quirks.quirks]);
1595
1772
  });
1596
- (_b = __privateGet(this, _plugins)) == null ? void 0 : _b.forEach((plugin) => {
1773
+ (_c = __privateGet(this, _plugins)) == null ? void 0 : _c.forEach((plugin) => {
1597
1774
  if (!plugin.init) {
1598
1775
  return;
1599
1776
  }
@@ -1723,10 +1900,16 @@ var Context = class {
1723
1900
  scores: __privateGet(this, _serverTransitionState) ? __privateMethod(this, _Context_instances, calculateScores_fn).call(this, this.storage.data) : __privateGet(this, _scores)
1724
1901
  })
1725
1902
  );
1903
+ const previousCompositionMetadata = __privateGet(this, _state).compositionMetadata;
1726
1904
  __privateSet(this, _state, {
1727
1905
  ...__privateGet(this, _state),
1728
1906
  ...newData
1729
1907
  });
1908
+ if (newData.compositionMetadata && // deep equal is not too bad, as we only have 1 level of depth in dynamic inputs
1909
+ !dequal5(previousCompositionMetadata, __privateGet(this, _state).compositionMetadata)) {
1910
+ __privateGet(this, _mitt3).emit("canvasDataUpdated", __privateGet(this, _state).compositionMetadata);
1911
+ __privateGet(this, _state).compositionMetadata = newData.compositionMetadata;
1912
+ }
1730
1913
  await this.storage.updateData(commands);
1731
1914
  if (__privateGet(this, _serverTransitionState)) {
1732
1915
  await this.processServerCommands({
@@ -1738,7 +1921,9 @@ var Context = class {
1738
1921
  __privateMethod(this, _Context_instances, emitTest_fn).call(this, {
1739
1922
  name: testName,
1740
1923
  variantId: testVariantId,
1741
- variantAssigned: true
1924
+ variantAssigned: true,
1925
+ control: false,
1926
+ compositionMetadata: void 0
1742
1927
  });
1743
1928
  });
1744
1929
  const haveQuirksChanged = __privateGet(this, _serverTransitionState) && !dequal5(__privateGet(this, _serverTransitionState).quirks, this.storage.data.quirks);
@@ -1754,7 +1939,7 @@ var Context = class {
1754
1939
  if (!plugin.update) {
1755
1940
  continue;
1756
1941
  }
1757
- await plugin.update(newData);
1942
+ await plugin.update(newData, __privateGet(this, _scores));
1758
1943
  }
1759
1944
  }
1760
1945
  (_e = __privateGet(this, _commands)) == null ? void 0 : _e.push(...commands);
@@ -1820,7 +2005,7 @@ var Context = class {
1820
2005
  }
1821
2006
  /** 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) */
1822
2007
  test(options) {
1823
- var _a, _b, _c;
2008
+ var _a, _b, _c, _d, _e;
1824
2009
  if (options.name === CONTEXTUAL_EDITING_TEST_NAME) {
1825
2010
  const selectedVariant = (_a = options.variations.find((variant) => variant.id === CONTEXTUAL_EDITING_TEST_SELECTED_VARIANT_ID)) != null ? _a : options.variations.at(-1);
1826
2011
  const value2 = {
@@ -1837,13 +2022,25 @@ var Context = class {
1837
2022
  __privateMethod(this, _Context_instances, emitTest_fn).call(this, {
1838
2023
  name: options.name,
1839
2024
  variantId: (_c = (_b = value.result) == null ? void 0 : _b.id) != null ? _c : void 0,
1840
- variantAssigned: value.variantAssigned
2025
+ variantAssigned: value.variantAssigned,
2026
+ control: (_e = (_d = value.result) == null ? void 0 : _d.control) != null ? _e : false,
2027
+ compositionMetadata: options.compositionMetadata
1841
2028
  });
1842
2029
  return value;
1843
2030
  }
1844
2031
  /** Executes a personalized placement with a given set of variants */
1845
2032
  personalize(options) {
1846
- const value = personalizeVariations({
2033
+ var _a;
2034
+ const algorithmName = (_a = options.algorithm) != null ? _a : TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM;
2035
+ const algorithm = __privateGet(this, _personalizationSelectionAlgorithms)[algorithmName];
2036
+ if (!algorithm) {
2037
+ __privateGet(this, _mitt3).emit("log", ["warn", 304, { algorithm: algorithmName }]);
2038
+ return {
2039
+ personalized: false,
2040
+ variations: []
2041
+ };
2042
+ }
2043
+ const value = algorithm({
1847
2044
  ...options,
1848
2045
  context: this,
1849
2046
  onLogMessage: (message) => __privateGet(this, _mitt3).emit("log", message)
@@ -1856,7 +2053,8 @@ var Context = class {
1856
2053
  control: variation.control
1857
2054
  })),
1858
2055
  control: this.storage.data.controlGroup,
1859
- changed: true
2056
+ changed: true,
2057
+ compositionMetadata: options.compositionMetadata
1860
2058
  };
1861
2059
  if (previousPlacement && dequal5(eventData.variantIds, previousPlacement)) {
1862
2060
  eventData.changed = false;
@@ -1870,7 +2068,10 @@ var Context = class {
1870
2068
  * @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
1871
2069
  */
1872
2070
  async forget(fromAllDevices) {
1873
- __privateSet(this, _state, {});
2071
+ const previousCompositionMetadata = __privateGet(this, _state).compositionMetadata;
2072
+ __privateSet(this, _state, {
2073
+ compositionMetadata: previousCompositionMetadata
2074
+ });
1874
2075
  if (__privateGet(this, _plugins)) {
1875
2076
  for (let i = 0; i < __privateGet(this, _plugins).length; i++) {
1876
2077
  const plugin = __privateGet(this, _plugins)[i];
@@ -1893,7 +2094,8 @@ var Context = class {
1893
2094
  ssv: __privateGet(this, _scores),
1894
2095
  tests: {},
1895
2096
  personalizeVariants: this.storage.data.personalizeVariants,
1896
- commands: __privateGet(this, _commands)
2097
+ commands: __privateGet(this, _commands),
2098
+ compositionMetadata: __privateGet(this, _state).compositionMetadata
1897
2099
  };
1898
2100
  const allTests = this.storage.data.tests;
1899
2101
  Object.entries(allTests).map(([testName, testValue]) => {
@@ -1916,7 +2118,29 @@ var Context = class {
1916
2118
  __privateGet(this, _pzCache)[event.name] = event.variantIds;
1917
2119
  __privateGet(this, _mitt3).emit("personalizationResult", event);
1918
2120
  }
2121
+ /**
2122
+ * Gets the current canvas data
2123
+ */
2124
+ getCompositionMetadata() {
2125
+ return __privateGet(this, _state).compositionMetadata;
2126
+ }
2127
+ /**
2128
+ * Updates the canvas data and emits a canvasDataUpdated event
2129
+ */
2130
+ async updateCompositionMetadata(newData) {
2131
+ const currentCanvas = __privateGet(this, _state).compositionMetadata || {};
2132
+ const updatedCanvas = { ...currentCanvas, ...newData };
2133
+ if (!dequal5(currentCanvas, updatedCanvas)) {
2134
+ __privateSet(this, _state, {
2135
+ ...__privateGet(this, _state),
2136
+ compositionMetadata: updatedCanvas
2137
+ });
2138
+ __privateGet(this, _mitt3).emit("canvasDataUpdated", updatedCanvas);
2139
+ __privateGet(this, _mitt3).emit("log", ["info", 4, "Canvas data updated"]);
2140
+ }
2141
+ }
1919
2142
  };
2143
+ _personalizationSelectionAlgorithms = new WeakMap();
1920
2144
  _serverTransitionState = new WeakMap();
1921
2145
  _scores = new WeakMap();
1922
2146
  _state = new WeakMap();
@@ -2079,8 +2303,31 @@ var ScriptType = /* @__PURE__ */ ((ScriptType2) => {
2079
2303
  })(ScriptType || {});
2080
2304
  var EdgeNodeTagName = "nesitag";
2081
2305
 
2082
- // src/insights/index.ts
2083
- import { v4 } from "uuid";
2306
+ // src/insights/storage.ts
2307
+ var createInsightsStorage = () => {
2308
+ const STORAGE_KEY2 = "ufin";
2309
+ return {
2310
+ get: () => {
2311
+ const data = localStorage.getItem(STORAGE_KEY2);
2312
+ if (!data) {
2313
+ return;
2314
+ }
2315
+ return JSON.parse(data);
2316
+ },
2317
+ set: (data) => {
2318
+ const toSet = {
2319
+ ...data,
2320
+ updated: Date.now()
2321
+ };
2322
+ localStorage.setItem(STORAGE_KEY2, JSON.stringify(toSet));
2323
+ },
2324
+ clear: () => {
2325
+ localStorage.removeItem(STORAGE_KEY2);
2326
+ }
2327
+ };
2328
+ };
2329
+
2330
+ // src/insights/types.ts
2084
2331
  var getBasePayload = () => {
2085
2332
  const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
2086
2333
  const locale = navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.userLanguage || navigator.language || navigator.browserLanguage || "en";
@@ -2093,13 +2340,34 @@ var getBasePayload = () => {
2093
2340
  href: window.location.href
2094
2341
  };
2095
2342
  };
2343
+ var generateVisitorId = () => {
2344
+ return `visitor_${generalRandomId()}`;
2345
+ };
2346
+ var generateSessionId = () => {
2347
+ return `session_${generalRandomId()}`;
2348
+ };
2349
+ var generatePageId = () => {
2350
+ return `page_${generalRandomId()}`;
2351
+ };
2352
+ var generalRandomId = () => {
2353
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
2354
+ const id = crypto.randomUUID();
2355
+ return id.replaceAll("-", "").toLowerCase();
2356
+ }
2357
+ return Math.random().toString(32).substring(2);
2358
+ };
2359
+
2360
+ // src/insights/v1.ts
2096
2361
  var createInsightsClient = ({ endpoint }) => {
2097
2362
  let endpointUrl;
2098
2363
  const apiKey = endpoint.apiKey;
2099
2364
  const projectId = endpoint.projectId;
2100
2365
  if (endpoint.type === "api") {
2101
2366
  const url = new URL(endpoint.host);
2102
- url.pathname = "/v0/events";
2367
+ url.pathname = `/v0/events`;
2368
+ if (endpoint.host.includes("tinybird.co")) {
2369
+ url.pathname = "/v0/events";
2370
+ }
2103
2371
  url.searchParams.set("name", "analytics_events");
2104
2372
  endpointUrl = url.toString();
2105
2373
  } else {
@@ -2229,38 +2497,7 @@ var createInsightsClient = ({ endpoint }) => {
2229
2497
  }
2230
2498
  };
2231
2499
  };
2232
- var createInsightsStorage = () => {
2233
- const STORAGE_KEY2 = "ufin";
2234
- return {
2235
- get: () => {
2236
- const data = localStorage.getItem(STORAGE_KEY2);
2237
- if (!data) {
2238
- return;
2239
- }
2240
- return JSON.parse(data);
2241
- },
2242
- set: (data) => {
2243
- const toSet = {
2244
- ...data,
2245
- updated: Date.now()
2246
- };
2247
- localStorage.setItem(STORAGE_KEY2, JSON.stringify(toSet));
2248
- },
2249
- clear: () => {
2250
- localStorage.removeItem(STORAGE_KEY2);
2251
- }
2252
- };
2253
- };
2254
- var generateVisitorId = () => {
2255
- return `visitor_${generalRandomId()}`;
2256
- };
2257
- var generateSessionId = () => {
2258
- return `session_${generalRandomId()}`;
2259
- };
2260
- var generatePageId = () => {
2261
- return `page_${generalRandomId()}`;
2262
- };
2263
- var createInsights = ({
2500
+ var createInsightsV1 = ({
2264
2501
  endpoint,
2265
2502
  sessionDurationSeconds = 30 * 60
2266
2503
  }) => {
@@ -2361,8 +2598,10 @@ var createInsights = ({
2361
2598
  }
2362
2599
  };
2363
2600
  };
2601
+
2602
+ // src/insights/index.ts
2364
2603
  var enableUniformInsights = (options) => {
2365
- const insights = createInsights({
2604
+ const insights = createInsightsV1({
2366
2605
  endpoint: options.endpoint
2367
2606
  });
2368
2607
  let previousUrl = void 0;
@@ -2408,8 +2647,8 @@ var enableUniformInsights = (options) => {
2408
2647
  };
2409
2648
  },
2410
2649
  update: (context) => {
2411
- if (context.url && context.url !== previousUrl) {
2412
- previousUrl = context.url;
2650
+ if (context.url && context.url.toString() !== previousUrl) {
2651
+ previousUrl = context.url.toString();
2413
2652
  insights.pageHit();
2414
2653
  }
2415
2654
  },
@@ -2418,10 +2657,6 @@ var enableUniformInsights = (options) => {
2418
2657
  }
2419
2658
  };
2420
2659
  };
2421
- var generalRandomId = () => {
2422
- const id = v4();
2423
- return id.replaceAll("-", "").toLowerCase();
2424
- };
2425
2660
 
2426
2661
  // src/logging/enableConsoleLogDrain.ts
2427
2662
  import rfdc2 from "rfdc";
@@ -2512,6 +2747,10 @@ var messageContent = {
2512
2747
  301: ({ id, op }) => ["personalization", `testing variation ${id} (${op === "|" ? "OR" : "AND"})`],
2513
2748
  302: ({ matched, description }) => ["personalization", `${description} is ${matched}`],
2514
2749
  303: (selected) => ["personalization", selected ? "selected variation" : "did not select variation"],
2750
+ 304: ({ algorithm }) => [
2751
+ "personalization",
2752
+ `personalization selection algorithm '${algorithm}' not found. Hiding placement.`
2753
+ ],
2515
2754
  // TESTING
2516
2755
  400: (name) => ["testing", `executing A/B test '${name}'`],
2517
2756
  401: (testName) => ["testing", `${testName} is not registered in the manifest; it will not be run.`],
@@ -2614,9 +2853,12 @@ export {
2614
2853
  KV_SEP,
2615
2854
  ManifestInstance,
2616
2855
  PAIR_SEP,
2856
+ QUIRK_KV_SEP,
2617
2857
  QUIRK_SEP,
2618
2858
  SERVER_STATE_ID,
2859
+ STRONGEST_SCORE_PERSONALIZATION_ALGORITHM,
2619
2860
  ScriptType,
2861
+ TOP_DOWN_CRITERIA_PERSONALIZATION_ALGORITHM,
2620
2862
  TYPE_SEP,
2621
2863
  TransitionDataStore,
2622
2864
  UNIFORM_DEFAULT_COOKIE_NAME,
@@ -2658,5 +2900,7 @@ export {
2658
2900
  serializePersonalizeVariants,
2659
2901
  serializeQuickConnect,
2660
2902
  serializeQuirks,
2661
- testVariations
2903
+ strongestScorePersonalizationSelectionAlgorithm,
2904
+ testVariations,
2905
+ topDownCriteriaPersonalizationSelectionAlgorithm
2662
2906
  };