@uniformdev/context 19.61.1 → 19.62.1-alpha.127

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
@@ -193,6 +193,15 @@ var SignalInstance = class {
193
193
  _evaluator = new WeakMap();
194
194
  _onLogMessage = new WeakMap();
195
195
 
196
+ // src/manifest/utils/control.ts
197
+ var rollForControlGroup = (value) => {
198
+ let control = value;
199
+ if (control >= 1) {
200
+ control = control / 100;
201
+ }
202
+ return Math.random() < control;
203
+ };
204
+
196
205
  // src/manifest/ManifestInstance.ts
197
206
  var _mf, _signalInstances, _onLogMessage2;
198
207
  var ManifestInstance = class {
@@ -216,8 +225,8 @@ var ManifestInstance = class {
216
225
  __privateSet(this, _onLogMessage2, onLogMessage);
217
226
  }
218
227
  rollForControlGroup() {
219
- var _a, _b;
220
- return Math.random() < ((_b = (_a = __privateGet(this, _mf).pz) == null ? void 0 : _a.control) != null ? _b : 0);
228
+ var _a;
229
+ return rollForControlGroup(((_a = __privateGet(this, _mf).pz) == null ? void 0 : _a.control) || 0);
221
230
  }
222
231
  getTest(name) {
223
232
  var _a;
@@ -565,7 +574,30 @@ function evaluateDimensionMatch(crit, vec, onLogMessage) {
565
574
  var _a, _b;
566
575
  const { op, l: lhs } = crit;
567
576
  const lhsScore = (_a = vec[lhs]) != null ? _a : 0;
568
- if (op === "+") {
577
+ if (op === "^") {
578
+ const [cat] = lhs.split(ENR_SEPARATOR);
579
+ let topVectorName = void 0;
580
+ let topScore = 0;
581
+ Object.keys(vec).forEach((vectorName) => {
582
+ if (vectorName.startsWith(`${cat}${ENR_SEPARATOR}`)) {
583
+ const score = vec[vectorName];
584
+ if (score > topScore) {
585
+ topVectorName = vectorName;
586
+ topScore = score;
587
+ }
588
+ }
589
+ });
590
+ const result = topVectorName === lhs;
591
+ onLogMessage == null ? void 0 : onLogMessage([
592
+ "info",
593
+ 302,
594
+ {
595
+ matched: result,
596
+ description: `${crit.l} has the highest score in the category`
597
+ }
598
+ ]);
599
+ return result;
600
+ } else if (op === "+") {
569
601
  const result = Math.max(...Object.values(vec)) === lhsScore && lhsScore > 0;
570
602
  onLogMessage == null ? void 0 : onLogMessage([
571
603
  "info",
@@ -652,31 +684,70 @@ function personalizeVariations({
652
684
  take = 1,
653
685
  onLogMessage
654
686
  }) {
655
- var _a, _b, _c;
687
+ var _a, _b, _c, _d;
656
688
  onLogMessage == null ? void 0 : onLogMessage(["info", 300, "GROUP", { name, take }]);
657
689
  try {
658
690
  const control = (_a = context.storage.data.controlGroup) != null ? _a : false;
659
691
  const results = [];
660
692
  let personalized = false;
661
693
  const scores = context.scores;
694
+ let index = 0;
695
+ const defaultVariants = [];
696
+ for (const variant of variations) {
697
+ if (!((_b = variant.pz) == null ? void 0 : _b.crit.length)) {
698
+ defaultVariants.push(variant);
699
+ }
700
+ }
662
701
  for (const variant of variations) {
702
+ const currentIndex = index++;
663
703
  if (results.length === take) {
664
704
  break;
665
705
  }
666
- if (!((_b = variant.pz) == null ? void 0 : _b.crit.length)) {
667
- onLogMessage == null ? void 0 : onLogMessage(["info", 301, "GROUP", { id: variant.id, op: (_c = variant.pz) == null ? void 0 : _c.op }]);
706
+ if (!((_c = variant.pz) == null ? void 0 : _c.crit.length)) {
707
+ onLogMessage == null ? void 0 : onLogMessage(["info", 301, "GROUP", { id: variant.id, op: (_d = variant.pz) == null ? void 0 : _d.op }]);
668
708
  onLogMessage == null ? void 0 : onLogMessage(["info", 302, { matched: true, description: "default variation" }]);
669
709
  onLogMessage == null ? void 0 : onLogMessage(["info", 303, true]);
670
710
  onLogMessage == null ? void 0 : onLogMessage(["info", 301, "ENDGROUP"]);
671
- results.push(variant);
711
+ results.push({
712
+ ...variant,
713
+ control: false
714
+ });
672
715
  continue;
673
716
  }
674
717
  if (control) {
675
718
  continue;
676
719
  }
677
720
  if (evaluateVariantMatch(variant.id, variant.pz, scores, onLogMessage)) {
678
- personalized = true;
679
- results.push(variant);
721
+ let variantToAdd = variant;
722
+ let isControl = false;
723
+ const isDefault = defaultVariants.find((v) => v.id === variant.id);
724
+ if (take === 1 && !isDefault && defaultVariants.length && typeof variant.pz.control === "number") {
725
+ isControl = context.getPersonalizeVariantControl(name, currentIndex);
726
+ if (typeof isControl === "undefined") {
727
+ isControl = rollForControlGroup(variant.pz.control);
728
+ context.storage.updateData([
729
+ {
730
+ type: "setpersonalizecontrol",
731
+ data: {
732
+ personlizationName: name,
733
+ index: currentIndex,
734
+ control: isControl
735
+ }
736
+ }
737
+ ]);
738
+ }
739
+ if (isControl) {
740
+ variantToAdd = {
741
+ ...defaultVariants[0],
742
+ id: variant.id
743
+ };
744
+ }
745
+ }
746
+ personalized = personalized || typeof variantToAdd.pz !== "undefined";
747
+ results.push({
748
+ ...variantToAdd,
749
+ control: isControl
750
+ });
680
751
  }
681
752
  }
682
753
  return {
@@ -923,16 +994,19 @@ function parseScoreCookie(cookieValue) {
923
994
  if (!cookieValue)
924
995
  return;
925
996
  const types = cookieValue.split(TYPE_SEP);
926
- if (types.length > 3)
997
+ if (types.length > 5)
927
998
  return;
928
- const [abTestData, sessionScores, visitorScores] = types;
929
- return {
999
+ const [abTestData, sessionScores, visitorScores, controlGroup, personalizeVariants] = types;
1000
+ const data = {
930
1001
  // this is true since we're reading a cookie, which wouldn't exist if consent wasn't given
931
1002
  consent: true,
932
1003
  sessionScores: decodeCookieType(parseCookieType(sessionScores)),
933
1004
  scores: decodeCookieType(parseCookieType(visitorScores)),
934
- tests: parseCookieType(abTestData)
1005
+ tests: parseCookieType(abTestData),
1006
+ controlGroup: controlGroup === "1",
1007
+ personalizeVariants: decodePersonalizeVariants(personalizeVariants)
935
1008
  };
1009
+ return data;
936
1010
  }
937
1011
  function parseCookieType(type) {
938
1012
  if (!type) {
@@ -956,9 +1030,48 @@ function serializeCookie(data) {
956
1030
  return [
957
1031
  serializeCookieType(data.tests),
958
1032
  serializeCookieType(encodeCookieType(data.sessionScores)),
959
- serializeCookieType(encodeCookieType(data.scores))
1033
+ serializeCookieType(encodeCookieType(data.scores)),
1034
+ data.controlGroup ? "1" : "0",
1035
+ serializePersonalizeVariants(data)
960
1036
  ].join(TYPE_SEP);
961
1037
  }
1038
+ function serializePersonalizeVariants({
1039
+ personalizeVariants
1040
+ }) {
1041
+ const data = {};
1042
+ if (typeof personalizeVariants === "object") {
1043
+ Object.keys(personalizeVariants).forEach((personalizationName) => {
1044
+ const results = [];
1045
+ const variants = personalizeVariants[personalizationName];
1046
+ variants.forEach((variant) => {
1047
+ results.push(`${variant.index}:${variant.control ? "1" : "0"}`);
1048
+ });
1049
+ data[personalizationName] = results.join(",");
1050
+ });
1051
+ }
1052
+ const serialized = serializeCookieType(data);
1053
+ return serialized;
1054
+ }
1055
+ function decodePersonalizeVariants(data) {
1056
+ const parsed = parseCookieType(data);
1057
+ const keys = Object.keys(parsed);
1058
+ if (!keys.length) {
1059
+ return void 0;
1060
+ }
1061
+ const results = {};
1062
+ Object.keys(parsed).forEach((k) => {
1063
+ const variants = parsed[k].split(",");
1064
+ const key = decodeURIComponent(k);
1065
+ results[key] = variants.map((variant) => {
1066
+ const [index, control] = variant.split(":");
1067
+ return {
1068
+ index: parseInt(index, 10),
1069
+ control: control === "1"
1070
+ };
1071
+ });
1072
+ });
1073
+ return results;
1074
+ }
962
1075
  function encodeCookieType(type) {
963
1076
  return Object.entries(type).reduce((acc, [key, value]) => {
964
1077
  acc[key] = ntob(value);
@@ -1046,7 +1159,8 @@ var emptyVisitorData = () => ({
1046
1159
  sessionScores: {},
1047
1160
  tests: {},
1048
1161
  consent: false,
1049
- controlGroup: false
1162
+ controlGroup: false,
1163
+ personalizeVariants: {}
1050
1164
  });
1051
1165
 
1052
1166
  // src/storage/VisitorDataStore.ts
@@ -1095,6 +1209,25 @@ function applyCommandsToData(commands, state, inControlGroup) {
1095
1209
  case "setcontrol":
1096
1210
  newData.controlGroup = command.data;
1097
1211
  break;
1212
+ case "setpersonalizecontrol":
1213
+ if (!newData.personalizeVariants) {
1214
+ newData.personalizeVariants = {};
1215
+ }
1216
+ if (!newData.personalizeVariants[command.data.personlizationName]) {
1217
+ newData.personalizeVariants[command.data.personlizationName] = [];
1218
+ }
1219
+ const existingDef = newData.personalizeVariants[command.data.personlizationName].find(
1220
+ (i) => i.index === command.data.index
1221
+ );
1222
+ if (!existingDef) {
1223
+ newData.personalizeVariants[command.data.personlizationName].push({
1224
+ index: command.data.index,
1225
+ control: command.data.control
1226
+ });
1227
+ } else {
1228
+ console.warn("Overwriting existing control group definition is not allowed");
1229
+ }
1230
+ break;
1098
1231
  default:
1099
1232
  throw new Error(`Unknown command`);
1100
1233
  }
@@ -1456,7 +1589,7 @@ var Context = class {
1456
1589
  * will NOT result in a recomputation of signal state.
1457
1590
  */
1458
1591
  async update(newData) {
1459
- var _a, _b, _c;
1592
+ var _a, _b, _c, _d;
1460
1593
  const commands = [];
1461
1594
  const newServerSideTests = {};
1462
1595
  if ((_a = __privateGet(this, _serverTransitionState)) == null ? void 0 : _a.quirks) {
@@ -1486,6 +1619,17 @@ var Context = class {
1486
1619
  );
1487
1620
  }
1488
1621
  }
1622
+ if ((_c = __privateGet(this, _serverTransitionState)) == null ? void 0 : _c.personalizeVariants) {
1623
+ Object.keys(__privateGet(this, _serverTransitionState).personalizeVariants).forEach((personalizationName) => {
1624
+ const variants = __privateGet(this, _serverTransitionState).personalizeVariants[personalizationName];
1625
+ variants.forEach((e) => {
1626
+ commands.push({
1627
+ type: "setpersonalizecontrol",
1628
+ data: { personlizationName: personalizationName, index: e.index, control: e.control }
1629
+ });
1630
+ });
1631
+ });
1632
+ }
1489
1633
  try {
1490
1634
  __privateGet(this, _mitt3).emit("log", [
1491
1635
  "info",
@@ -1495,7 +1639,7 @@ var Context = class {
1495
1639
  ...newData,
1496
1640
  // need to convert url to string so it can be json serialized
1497
1641
  // to go over postMessage to chrome extension
1498
- url: (_c = newData.url) == null ? void 0 : _c.toString()
1642
+ url: (_d = newData.url) == null ? void 0 : _d.toString()
1499
1643
  }
1500
1644
  ]);
1501
1645
  if (newData.quirks) {
@@ -1577,6 +1721,13 @@ var Context = class {
1577
1721
  }
1578
1722
  ]);
1579
1723
  }
1724
+ getPersonalizeVariantControl(name, index) {
1725
+ var _a, _b, _c;
1726
+ const source = (_b = (_a = __privateGet(this, _serverTransitionState)) == null ? void 0 : _a.personalizeVariants) != null ? _b : this.storage.data.personalizeVariants;
1727
+ const variants = (_c = source == null ? void 0 : source[name]) != null ? _c : [];
1728
+ const variant = variants.find((v) => v.index === index);
1729
+ return variant == null ? void 0 : variant.control;
1730
+ }
1580
1731
  /**
1581
1732
  * Writes a message to the Context log sink.
1582
1733
  * Used by Uniform internal SDK; not intended for public use.
@@ -1619,10 +1770,10 @@ var Context = class {
1619
1770
  const previousPlacement = __privateGet(this, _pzCache)[options.name];
1620
1771
  const eventData = {
1621
1772
  name: options.name,
1622
- variantIds: value.variations.map((variation) => {
1623
- var _a;
1624
- return (_a = variation.id) != null ? _a : "Unknown";
1625
- }),
1773
+ variantIds: value.variations.map((variation) => ({
1774
+ id: variation.id || "Unknown",
1775
+ control: variation.control
1776
+ })),
1626
1777
  control: this.storage.data.controlGroup,
1627
1778
  changed: true
1628
1779
  };
@@ -1650,7 +1801,8 @@ var Context = class {
1650
1801
  const transitionState = {
1651
1802
  quirks: this.storage.data.quirks,
1652
1803
  ssv: __privateGet(this, _scores),
1653
- tests: {}
1804
+ tests: {},
1805
+ personalizeVariants: this.storage.data.personalizeVariants
1654
1806
  };
1655
1807
  const allTests = this.storage.data.tests;
1656
1808
  Object.entries(allTests).map(([testName, testValue]) => {
@@ -1661,6 +1813,18 @@ var Context = class {
1661
1813
  });
1662
1814
  return transitionState;
1663
1815
  }
1816
+ /** @deprecated */
1817
+ internal_processTestEvent(event) {
1818
+ if (event.variantId) {
1819
+ this.setTestVariantId(event.name, event.variantId);
1820
+ __privateMethod(this, _emitTest, emitTest_fn).call(this, event);
1821
+ }
1822
+ }
1823
+ /** @deprecated */
1824
+ internal_processPersonalizationEvent(event) {
1825
+ __privateGet(this, _pzCache)[event.name] = event.variantIds;
1826
+ __privateGet(this, _mitt3).emit("personalizationResult", event);
1827
+ }
1664
1828
  };
1665
1829
  _serverTransitionState = new WeakMap();
1666
1830
  _scores = new WeakMap();
@@ -1694,7 +1858,7 @@ calculateScores_fn = function(newData) {
1694
1858
 
1695
1859
  // src/devTools/enableContextDevTools.ts
1696
1860
  var isBrowser = typeof top !== "undefined";
1697
- function enableContextDevTools() {
1861
+ function enableContextDevTools(options) {
1698
1862
  return {
1699
1863
  logDrain: (message) => {
1700
1864
  if (!isBrowser) {
@@ -1747,7 +1911,11 @@ function enableContextDevTools() {
1747
1911
  return;
1748
1912
  }
1749
1913
  const message = event.data;
1750
- await handleMessageFromDevTools(message, context);
1914
+ await handleMessageFromDevTools({
1915
+ message,
1916
+ context,
1917
+ afterMessageReceived: options == null ? void 0 : options.onAfterMessageReceived
1918
+ });
1751
1919
  });
1752
1920
  } catch (e) {
1753
1921
  console.warn(
@@ -1767,26 +1935,35 @@ function enableContextDevTools() {
1767
1935
  context.events.on("personalizationResult", onPersonalizationResult);
1768
1936
  context.events.on("testResult", onTestResult);
1769
1937
  context.events.on("scoresUpdated", onContextDataUpdated);
1770
- context.storage.events.on("*", onContextDataUpdated);
1771
1938
  return () => {
1772
1939
  context.events.off("scoresUpdated", onContextDataUpdated);
1773
- context.storage.events.off("*", onContextDataUpdated);
1774
1940
  context.events.off("personalizationResult", onPersonalizationResult);
1775
1941
  context.events.off("testResult", onTestResult);
1776
1942
  };
1777
1943
  }
1778
1944
  };
1779
1945
  }
1780
- async function handleMessageFromDevTools(message, context) {
1946
+ async function handleMessageFromDevTools({
1947
+ message,
1948
+ context,
1949
+ afterMessageReceived
1950
+ }) {
1951
+ let receivedUniformMessage = false;
1781
1952
  if (message.type === "uniform-in:context:update" && message.newData) {
1953
+ receivedUniformMessage = true;
1782
1954
  await context.update(message.newData);
1783
1955
  }
1784
1956
  if (message.type === "uniform-in:context:commands" && message.commands && Array.isArray(message.commands)) {
1957
+ receivedUniformMessage = true;
1785
1958
  await context.storage.updateData(message.commands);
1786
1959
  }
1787
1960
  if (message.type === "uniform-in:context:forget") {
1961
+ receivedUniformMessage = true;
1788
1962
  await context.forget(false);
1789
1963
  }
1964
+ if (receivedUniformMessage && typeof afterMessageReceived === "function") {
1965
+ afterMessageReceived(message);
1966
+ }
1790
1967
  }
1791
1968
 
1792
1969
  // src/edge/index.ts