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.
- package/package.json +1 -1
- 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
|
+
"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
|
|
962
|
-
invalidJson: 'Sigma warning
|
|
963
|
-
invalidType: 'Sigma warning
|
|
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
|
-
|
|
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
|
|
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(
|
|
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.
|
|
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}
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
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
|
-
|
|
1730
|
-
|
|
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
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
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 (
|
|
1818
|
-
|
|
1819
|
-
|
|
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) {
|