expf-sigma-node.js 3.3.5 → 3.4.0

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/sigma.js +170 -54
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expf-sigma-node.js",
3
- "version": "3.3.5",
3
+ "version": "3.4.0",
4
4
  "description": "expf-sigma-node.js lets you manage features flags and remote config across web, server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.",
5
5
  "main": "public/sigma.js",
6
6
  "keywords": [
package/public/sigma.js CHANGED
@@ -927,16 +927,24 @@ var sigmaDataFileLastUpdate = "sigmaDataFileLastUpdate";
927
927
  var sigmaExpiration = "sigmaExpiration";
928
928
  var sigmaDataFile = "sigmaDataFile";
929
929
  var sigmaExperiments = "sigmaExperiments";
930
+ var sigmaHoldouts = "sigmaHoldouts";
931
+ var sigmaGeoData = "sigmaGeoData";
930
932
  var max_decimal_64 = 18446744073709552e3;
931
933
  var zeta = 8540717056e4;
932
934
  var SHA256 = new sigmaHashes_default.SHA256();
933
935
  var MD5 = new sigmaHashes_default.MD5();
934
936
  var expirationDate = 24 * 60 * 60 * 1e3;
935
937
  var secondsIn24Hours = 24 * 60 * 60;
936
- var sigmaGeoData = "sigmaGeoData";
937
938
  var defaultGeoCacheTTL = 5 * 60;
938
939
  var cacheStandardTimeToLive = 3600;
939
940
  var cacheCheckPeriod = 600;
941
+ var experimentType = {
942
+ featureFlag: 1,
943
+ param: 2,
944
+ splitUrl: 3,
945
+ webBuilder: 4,
946
+ holdout: 5
947
+ };
940
948
  var errorMessages = {
941
949
  emptyToken: "Please specify a token",
942
950
  APIRequestErrorConfig: {
@@ -958,9 +966,10 @@ var errorMessages = {
958
966
  };
959
967
  var signsForHash = ["equal", "not equal", "any of", "none of"];
960
968
  var prefixGroup = "sigma_group";
961
- var errorTypesInConfig = {
962
- invalidJson: 'Sigma warning. Invalid type json "%value%" in config.',
963
- invalidType: 'Sigma warning. Invalid type "%type%" in config.'
969
+ var warnings = {
970
+ invalidJson: 'Sigma warning: Invalid type json "%value%" in config.',
971
+ invalidType: 'Sigma warning: Invalid type "%type%" in config.',
972
+ emptyHoldoutId: "Sigma warning: Empty holdout id"
964
973
  };
965
974
  var sdkName = "node.js";
966
975
  var statusSuccess = "success";
@@ -1017,13 +1026,7 @@ var sigmaGeoCache = new import_node_cache2.default({
1017
1026
  checkperiod: cacheCheckPeriod
1018
1027
  });
1019
1028
  var SigmaGeoCache = class {
1020
- maxGeoCacheTTL = 120 * 60;
1021
- minGeoCacheTTL = 1 * 60;
1022
- constructor(postfix, geoCacheTTL) {
1023
- this.geoCacheTTL = geoCacheTTL || defaultGeoCacheTTL;
1024
- if (geoCacheTTL > this.maxGeoCacheTTL || geoCacheTTL < this.minGeoCacheTTL) {
1025
- this.geoCacheTTL = defaultGeoCacheTTL;
1026
- }
1029
+ constructor(postfix) {
1027
1030
  this.postfix = "";
1028
1031
  if (postfix)
1029
1032
  this.postfix = "__" + postfix;
@@ -1037,7 +1040,7 @@ var SigmaGeoCache = class {
1037
1040
  }
1038
1041
  set(key, value) {
1039
1042
  try {
1040
- return sigmaGeoCache.set(key + this.postfix, value, this.geoCacheTTL);
1043
+ return sigmaGeoCache.set(key + this.postfix, value);
1041
1044
  } catch (e) {
1042
1045
  console.log(e);
1043
1046
  }
@@ -1189,7 +1192,7 @@ function doTypeConversion(type, value) {
1189
1192
  return JSON.parse("{}");
1190
1193
  return JSON.parse(value);
1191
1194
  } catch (e) {
1192
- console.error(errorTypesInConfig.invalidJson.replace("%value%", value), e);
1195
+ console.error(warnings.invalidJson.replace("%value%", value), e);
1193
1196
  return null;
1194
1197
  }
1195
1198
  default:
@@ -1268,7 +1271,7 @@ function generateFilteredList(array, name) {
1268
1271
  }
1269
1272
 
1270
1273
  // package.json
1271
- var version = "3.3.5";
1274
+ var version = "3.4.0";
1272
1275
 
1273
1276
  // src/helpers/sdkVersion.js
1274
1277
  var sdkVersion = version;
@@ -1323,7 +1326,6 @@ var Sigma = class {
1323
1326
  this.api = options.api || defaultApi;
1324
1327
  this.retries = options.retries || 2;
1325
1328
  this.postfix = options.postfix || "";
1326
- this.geoCacheTTL = options.geoCacheTTL || defaultGeoCacheTTL;
1327
1329
  this.sigmaUserData = new SigmaUserData();
1328
1330
  this.cache = new SigmaCache(this.postfix);
1329
1331
  this.sigmaUserData.init({
@@ -1346,7 +1348,7 @@ var Sigma = class {
1346
1348
  });
1347
1349
  this.setSplitIdsToCache(this.userData);
1348
1350
  this.makePrivateIdInCache();
1349
- this.geoCache = new SigmaGeoCache(`${this.cache.get(sigmaPrivateId)}__${this.token}`, options.geoCacheTTL);
1351
+ this.geoCache = new SigmaGeoCache(`${this.cache.get(sigmaPrivateId)}__${this.token}`);
1350
1352
  }
1351
1353
  setSplitIdsToCache(userData) {
1352
1354
  for (let [key, value] of Object.entries(userData)) {
@@ -1463,14 +1465,20 @@ var Sigma = class {
1463
1465
  console.error(errorMessages.APIRequestErrorConfig);
1464
1466
  }
1465
1467
  }
1468
+ this.recordLastUpdateInCache();
1469
+ }
1470
+ async saveToGeoCache() {
1466
1471
  try {
1467
1472
  await this.getUserGeoData();
1468
- } catch {
1473
+ this.geoCache.get(sigmaGeoData) ? this.sigmaUserData.setGeo(this.geoCache.parse(sigmaGeoData)) : this.sigmaUserData.setGeo("{}");
1474
+ } catch (error) {
1469
1475
  if (!this.geoCache.get(sigmaGeoData)) {
1470
1476
  this.geoCache.set(sigmaGeoData, JSON.stringify({ location: "none" }));
1471
1477
  }
1478
+ errorMessages.APIRequestErrorGeoData.token = this.token;
1479
+ errorMessages.APIRequestErrorGeoData.userData = JSON.stringify(this.userData);
1480
+ console.error(error, errorMessages.APIRequestErrorGeoData);
1472
1481
  }
1473
- this.recordLastUpdateInCache();
1474
1482
  }
1475
1483
  hasExpireCache() {
1476
1484
  const lastUpdate = Number(this.cache.get(sigmaDataFileLastUpdate));
@@ -1484,7 +1492,11 @@ var Sigma = class {
1484
1492
  if (!this.cache.get(sigmaDataFile) || this.hasExpireCache()) {
1485
1493
  return this.saveToCache();
1486
1494
  }
1487
- return true;
1495
+ }
1496
+ updateGeoCache() {
1497
+ if (!this.geoCache.get(sigmaGeoData)) {
1498
+ return this.saveToGeoCache();
1499
+ }
1488
1500
  }
1489
1501
  async getFlags() {
1490
1502
  await this.updateCache();
@@ -1497,10 +1509,10 @@ var Sigma = class {
1497
1509
  if (!flagName)
1498
1510
  return null;
1499
1511
  await this.updateCache();
1512
+ await this.updateGeoCache();
1500
1513
  const cacheKey = this.cache.parse(sigmaDataFile);
1501
1514
  if (!cacheKey.feature_flags)
1502
1515
  return;
1503
- this.sigmaUserData.setGeo(this.geoCache.parse(sigmaGeoData));
1504
1516
  let flag = null;
1505
1517
  const expName = this.getExperimentByFeatureFlag(cacheKey, flagName);
1506
1518
  if (expName) {
@@ -1521,8 +1533,8 @@ var Sigma = class {
1521
1533
  async getUserFeatureFlagsDetails() {
1522
1534
  const featureFlags = [];
1523
1535
  await this.updateCache();
1536
+ await this.updateGeoCache();
1524
1537
  const sigmaDataLs = await this.cache.parse(sigmaDataFile);
1525
- this.sigmaUserData.setGeo(this.geoCache.parse(sigmaGeoData));
1526
1538
  if (sigmaDataLs.feature_flags.length > 0) {
1527
1539
  for (const flag in sigmaDataLs.feature_flags) {
1528
1540
  const ffName = sigmaDataLs.feature_flags[flag].name;
@@ -1689,6 +1701,7 @@ var Sigma = class {
1689
1701
  if (!experimentName)
1690
1702
  return null;
1691
1703
  await this.updateCache();
1704
+ await this.updateGeoCache();
1692
1705
  const sigmaDataLs = await this.cache.parse(sigmaDataFile);
1693
1706
  this.sigmaUserData.setGeo(this.geoCache.parse(sigmaGeoData));
1694
1707
  if (!sigmaDataLs.experiments)
@@ -1700,20 +1713,31 @@ var Sigma = class {
1700
1713
  let groupIndex = null;
1701
1714
  let forcedUser = false;
1702
1715
  let splitById = null;
1716
+ let userInHoldout = false;
1703
1717
  for (let i = 0; i < sigmaDataLs.experiments.length; i++) {
1704
- if (sigmaDataLs.experiments[i]["name"] === experimentName && checkBoolValue(sigmaDataLs.experiments[i]["layer_id"])) {
1705
- layer = sigmaDataLs.experiments[i]["layer_id"];
1706
- bounds = sigmaDataLs.experiments[i]["layer_bounds"];
1707
- }
1708
- if (sigmaDataLs.experiments[i]["name"] === experimentName && !experiment) {
1709
- splitById = this.getSplitById(sigmaDataLs.experiments[i]);
1710
- forcedUser = checkForcedList(sigmaDataLs.experiments[i].forced_user_list, splitById);
1711
- groupName = this.findUserInForcedGroup(sigmaDataLs.experiments[i]);
1712
- experiment = this.experimentDefinition(sigmaDataLs.experiments[i], groupName, forcedUser);
1718
+ const experimentIndex = sigmaDataLs.experiments[i];
1719
+ if (experimentIndex["name"] === experimentName && checkBoolValue(experimentIndex["layer_id"])) {
1720
+ layer = experimentIndex["layer_id"];
1721
+ bounds = experimentIndex["layer_bounds"];
1722
+ }
1723
+ if (experimentIndex["name"] === experimentName) {
1724
+ splitById = this.getSplitById(experimentIndex);
1725
+ forcedUser = checkForcedList(experimentIndex.forced_user_list, splitById);
1726
+ groupName = this.findUserInForcedGroup(experimentIndex);
1727
+ experiment = this.experimentDefinition(experimentIndex, groupName, forcedUser);
1728
+ if (experimentIndex.holdouts && experimentIndex.holdouts.length) {
1729
+ for (const holdoutName of experimentIndex.holdouts) {
1730
+ userInHoldout = await this.getHoldout(holdoutName);
1731
+ if (userInHoldout)
1732
+ break;
1733
+ }
1734
+ }
1713
1735
  break;
1714
1736
  }
1715
1737
  }
1716
1738
  const localStorageGroupName = `${prefixGroup}_${experimentName}`;
1739
+ if (this.cache.get(localStorageGroupName))
1740
+ this.cache.remove(localStorageGroupName);
1717
1741
  if (experiment) {
1718
1742
  if (!groupName) {
1719
1743
  groupName = this.calcUserInGroup(
@@ -1726,11 +1750,18 @@ var Sigma = class {
1726
1750
  splitById
1727
1751
  );
1728
1752
  }
1729
- this.cache.set(localStorageGroupName, groupName);
1730
- groupIndex = experiment.groups.findIndex((i) => i.name == groupName);
1753
+ if (experiment.type === experimentType.holdout) {
1754
+ if (groupName)
1755
+ this.cache.set(localStorageGroupName, groupName);
1756
+ return groupName;
1757
+ }
1758
+ if (!userInHoldout) {
1759
+ this.cache.set(localStorageGroupName, groupName);
1760
+ groupIndex = experiment.groups.findIndex((i) => i.name == groupName);
1761
+ }
1731
1762
  }
1732
1763
  const getParamValue = (paramName) => {
1733
- if (!paramName || !experiment) {
1764
+ if (!paramName || !experiment || userInHoldout) {
1734
1765
  return null;
1735
1766
  }
1736
1767
  const groupName2 = this.cache.get(localStorageGroupName);
@@ -1753,7 +1784,7 @@ var Sigma = class {
1753
1784
  return paramValue;
1754
1785
  };
1755
1786
  const getFeatureValue = (flagName) => {
1756
- if (!flagName || !experiment) {
1787
+ if (!flagName || !experiment || userInHoldout) {
1757
1788
  return null;
1758
1789
  }
1759
1790
  const groupName2 = this.cache.get(localStorageGroupName);
@@ -1781,43 +1812,82 @@ var Sigma = class {
1781
1812
  return {
1782
1813
  getParamValue,
1783
1814
  getFeatureValue,
1784
- groupIndex: groupIndex < 0 ? null : groupIndex
1815
+ groupIndex: groupIndex < 0 ? null : groupIndex,
1816
+ userInHoldout
1785
1817
  };
1786
1818
  }
1787
- async getAllUserExperiments() {
1819
+ async getAllUserExperiments(estimateHoldouts = true) {
1788
1820
  await this.updateCache();
1821
+ await this.updateGeoCache();
1789
1822
  const sigmaDataLs = this.cache.parse(sigmaDataFile);
1790
1823
  if (!sigmaDataLs.experiments.length)
1791
1824
  return null;
1792
1825
  let result = "";
1793
1826
  for (let i in sigmaDataLs.experiments) {
1827
+ if (!estimateHoldouts && sigmaDataLs.experiments[i].type === experimentType.holdout)
1828
+ continue;
1794
1829
  let layer = null;
1795
1830
  let bounds = [];
1796
1831
  let splitById = this.getSplitById(sigmaDataLs.experiments[i]);
1797
1832
  let forcedUser = checkForcedList(sigmaDataLs.experiments[i].forced_user_list, splitById);
1798
1833
  let userInGroupExperiment = this.findUserInForcedGroup(sigmaDataLs.experiments[i]);
1799
1834
  let experiment = this.experimentDefinition(sigmaDataLs.experiments[i], userInGroupExperiment, forcedUser);
1800
- if (experiment) {
1801
- if (checkBoolValue(experiment["layer_id"]) && !userInGroupExperiment) {
1802
- layer = experiment["layer_id"];
1803
- bounds = experiment["layer_bounds"];
1804
- }
1805
- if (!userInGroupExperiment) {
1806
- userInGroupExperiment = this.calcUserInGroup(
1807
- experiment.salt,
1808
- experiment.allocation,
1809
- experiment.groups,
1810
- forcedUser,
1811
- layer,
1812
- bounds,
1813
- splitById
1835
+ let userInHoldout;
1836
+ if (!experiment)
1837
+ continue;
1838
+ if (checkBoolValue(experiment["layer_id"]) && !userInGroupExperiment) {
1839
+ layer = experiment["layer_id"];
1840
+ bounds = experiment["layer_bounds"];
1841
+ }
1842
+ if (!userInGroupExperiment) {
1843
+ userInGroupExperiment = this.calcUserInGroup(
1844
+ experiment.salt,
1845
+ experiment.allocation,
1846
+ experiment.groups,
1847
+ forcedUser,
1848
+ layer,
1849
+ bounds,
1850
+ splitById
1851
+ );
1852
+ }
1853
+ if (!userInGroupExperiment)
1854
+ continue;
1855
+ if (sigmaDataLs.experiments[i].holdouts && sigmaDataLs.experiments[i].holdouts.length > 0) {
1856
+ for (const holdout of sigmaDataLs.experiments[i].holdouts) {
1857
+ const foundingExperimentHoldout = sigmaDataLs.experiments.find((exp) => exp.name === holdout);
1858
+ if (!foundingExperimentHoldout)
1859
+ break;
1860
+ const splitByHoldoutId = this.getSplitById(foundingExperimentHoldout);
1861
+ if (!splitByHoldoutId)
1862
+ continue;
1863
+ const holdoutForcedUser = checkForcedList(foundingExperimentHoldout.forced_user_list, splitByHoldoutId);
1864
+ let userInGroupHoldout = this.findUserInForcedGroup(foundingExperimentHoldout);
1865
+ if (userInGroupHoldout) {
1866
+ userInHoldout = true;
1867
+ break;
1868
+ }
1869
+ const experimentByHoldout = this.experimentDefinition(foundingExperimentHoldout, userInGroupHoldout, holdoutForcedUser);
1870
+ if (!experimentByHoldout)
1871
+ continue;
1872
+ userInGroupHoldout = this.calcUserInGroup(
1873
+ experimentByHoldout.salt,
1874
+ experimentByHoldout.allocation,
1875
+ experimentByHoldout.groups,
1876
+ holdoutForcedUser,
1877
+ null,
1878
+ [],
1879
+ splitByHoldoutId
1814
1880
  );
1881
+ if (userInGroupHoldout) {
1882
+ userInHoldout = true;
1883
+ break;
1884
+ }
1815
1885
  }
1816
1886
  }
1817
- if (userInGroupExperiment) {
1818
- const groupIndex = experiment.groups.findIndex((i2) => i2.name == userInGroupExperiment);
1819
- result = result.concat(experiment.name).concat(".").concat(groupIndex).concat("|");
1820
- }
1887
+ if (userInHoldout)
1888
+ continue;
1889
+ const groupIndex = experiment.groups.findIndex((i2) => i2.name == userInGroupExperiment);
1890
+ result = result.concat(experiment.name).concat(".").concat(groupIndex).concat("|");
1821
1891
  }
1822
1892
  if (result.length > 0) {
1823
1893
  this.cache.set(sigmaExperiments, result.slice(0, -1));
@@ -1827,6 +1897,52 @@ var Sigma = class {
1827
1897
  }
1828
1898
  return null;
1829
1899
  }
1900
+ async getHoldout(name) {
1901
+ if (!name)
1902
+ return console.log(warnings.emptyHoldoutId);
1903
+ const holdoutGroup = await this.getExperiment(name);
1904
+ if (holdoutGroup && typeof holdoutGroup === "string")
1905
+ return true;
1906
+ return false;
1907
+ }
1908
+ async getAllUserHoldouts() {
1909
+ await this.updateCache();
1910
+ const sigmaDataLs = await this.cache.parse(sigmaDataFile);
1911
+ if (!sigmaDataLs.experiments.length)
1912
+ return null;
1913
+ let result = "";
1914
+ for (const holdout of sigmaDataLs.experiments) {
1915
+ if (holdout.type !== experimentType.holdout)
1916
+ continue;
1917
+ let userInGroupExperiment = false;
1918
+ const layer = null;
1919
+ const bounds = [];
1920
+ const splitById = this.getSplitById(holdout);
1921
+ const forcedUser = checkForcedList(holdout.forced_user_list, splitById);
1922
+ const experiment = this.experimentDefinition(holdout, userInGroupExperiment, forcedUser);
1923
+ if (!experiment)
1924
+ continue;
1925
+ userInGroupExperiment = this.calcUserInGroup(
1926
+ experiment.salt,
1927
+ experiment.allocation,
1928
+ experiment.groups,
1929
+ forcedUser,
1930
+ layer,
1931
+ bounds,
1932
+ splitById
1933
+ );
1934
+ if (!userInGroupExperiment)
1935
+ continue;
1936
+ result = result.concat(holdout.name).concat(".").concat("0").concat("|");
1937
+ }
1938
+ if (result.length > 0) {
1939
+ this.cache.set(sigmaHoldouts, result.slice(0, -1));
1940
+ return result.slice(0, -1);
1941
+ } else {
1942
+ this.cache.remove(sigmaHoldouts);
1943
+ }
1944
+ return null;
1945
+ }
1830
1946
  findUserInForcedGroup(experiment) {
1831
1947
  let groupName = false;
1832
1948
  for (const groupItem in experiment.groups) {