expf-sigma-node.js 3.2.4 → 3.2.6

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 +157 -116
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expf-sigma-node.js",
3
- "version": "3.2.4",
3
+ "version": "3.2.6",
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
@@ -784,9 +784,41 @@ var MD5 = new sigmaHashes_default.MD5();
784
784
  var expirationDate = 24 * 60 * 60 * 1e3;
785
785
  var secondsIn24Hours = 24 * 60 * 60;
786
786
  var sigmaGeoData = "sigmaGeoData";
787
+ var defaultGeoCacheTTL = 5 * 60;
788
+ var cacheStandardTimeToLive = 3600;
789
+ var cacheCheckPeriod = 600;
790
+ var errorMessages = {
791
+ emptyToken: "Please specify a token",
792
+ APIRequestErrorConfig: {
793
+ token: "%token%",
794
+ userData: "%userData%",
795
+ detail: "Invalid request to sigma config json",
796
+ time: new Date().toLocaleString("ru-RU"),
797
+ cache: true
798
+ },
799
+ APIRequestErrorGeoData: {
800
+ token: "%token%",
801
+ userData: "%userData%",
802
+ detail: "Invalid request to sigma geo data",
803
+ time: new Date().toLocaleString("ru-RU")
804
+ },
805
+ saveLastUpdateError: "Save last update to cache",
806
+ isNoExperimentInCache: "Experiments not found in cache",
807
+ badConfig: "Bad config.json"
808
+ };
809
+ var signsForHash = ["equal", "not equal", "any of", "none of"];
810
+ var prefixGroup = "sigma_group";
811
+ var errorTypesInConfig = {
812
+ invalidJson: 'Sigma warning. Invalid type json "%value%" in config.',
813
+ invalidType: 'Sigma warning. Invalid type "%type%" in config.'
814
+ };
815
+ var sdkName = "node.js";
787
816
 
788
817
  // src/modules/sigmaCache.js
789
- var sigmaCache = new import_node_cache.default({ stdTTL: secondsIn24Hours });
818
+ var sigmaCache = new import_node_cache.default({
819
+ stdTTL: cacheStandardTimeToLive,
820
+ checkperiod: cacheCheckPeriod
821
+ });
790
822
  var SigmaCache = class {
791
823
  constructor(postfix) {
792
824
  this.postfix = "";
@@ -825,14 +857,16 @@ var SigmaCache = class {
825
857
 
826
858
  // src/modules/sigmaGeoCache.js
827
859
  var import_node_cache2 = __toESM(require("node-cache"));
828
- var defaultGeoCacheTTL = 5 * 60;
829
- var maxGeoCacheTTL = 120 * 60;
830
- var minGeoCacheTTL = 1 * 60;
831
- var sigmaGeoCache = new import_node_cache2.default({ stdTTL: secondsIn24Hours });
860
+ var sigmaGeoCache = new import_node_cache2.default({
861
+ stdTTL: cacheStandardTimeToLive,
862
+ checkperiod: cacheCheckPeriod
863
+ });
832
864
  var SigmaGeoCache = class {
865
+ maxGeoCacheTTL = 120 * 60;
866
+ minGeoCacheTTL = 1 * 60;
833
867
  constructor(postfix, geoCacheTTL) {
834
868
  this.geoCacheTTL = geoCacheTTL || defaultGeoCacheTTL;
835
- if (geoCacheTTL > maxGeoCacheTTL || geoCacheTTL < minGeoCacheTTL) {
869
+ if (geoCacheTTL > this.maxGeoCacheTTL || geoCacheTTL < this.minGeoCacheTTL) {
836
870
  this.geoCacheTTL = defaultGeoCacheTTL;
837
871
  }
838
872
  this.postfix = "";
@@ -856,6 +890,12 @@ var SigmaGeoCache = class {
856
890
  keys() {
857
891
  return sigmaGeoCache.keys();
858
892
  }
893
+ parse(data) {
894
+ if (!this.get(data)) {
895
+ throw new Error(`${data} not found in cache`);
896
+ }
897
+ return JSON.parse(String(this.get(data)));
898
+ }
859
899
  };
860
900
 
861
901
  // src/helpers/checkBoolValue.js
@@ -910,20 +950,20 @@ function conditionOperation(userValue, conditionValues, operation, date, time) {
910
950
  return false;
911
951
  userValue = String(userValue);
912
952
  if (!Array.isArray(conditionValues))
913
- conditionValues = String(conditionValues);
953
+ conditionValues = String(conditionValues).toLowerCase().trim();
914
954
  switch (operation.trim()) {
915
955
  case "equal":
916
- return userValue.toLowerCase().trim() == conditionValues.toLowerCase().trim();
956
+ return userValue.toLowerCase().trim() == conditionValues;
917
957
  case "not equal":
918
- return userValue.toLowerCase().trim() != conditionValues.toLowerCase().trim();
958
+ return userValue.toLowerCase().trim() != conditionValues;
919
959
  case "greater":
920
- return compareVersions(userValue.trim(), conditionValues.trim());
960
+ return compareVersions(userValue.trim(), conditionValues);
921
961
  case "less":
922
- return compareVersions(conditionValues.trim(), userValue.trim());
962
+ return compareVersions(conditionValues, userValue.trim());
923
963
  case "greater equal":
924
- return compareVersions(userValue.trim(), conditionValues.trim(), false);
964
+ return compareVersions(userValue.trim(), conditionValues, false);
925
965
  case "less equal":
926
- return compareVersions(conditionValues.trim(), userValue.trim(), false);
966
+ return compareVersions(conditionValues, userValue.trim(), false);
927
967
  case "any of":
928
968
  return conditionValues.includes(userValue);
929
969
  case "none of":
@@ -943,13 +983,11 @@ function conditionOperation(userValue, conditionValues, operation, date, time) {
943
983
  }
944
984
  return true;
945
985
  case "on date":
946
- return Math.floor(
947
- new Date(conditionValues.trim()).getTime() / (1e3 * 60 * 60 * 24)
948
- ) == date;
986
+ return Math.floor(new Date(conditionValues.toString()).getTime() / (1e3 * 60 * 60 * 24)) == date;
949
987
  case "after time":
950
- return new Date(conditionValues.trim()).getTime() / (1e3 * 60 * 60) < time;
988
+ return new Date(conditionValues.toString()).getTime() / (1e3 * 60 * 60) < time;
951
989
  case "before time":
952
- return new Date(conditionValues.trim()).getTime() / (1e3 * 60 * 60) > time;
990
+ return new Date(conditionValues.toString()).getTime() / (1e3 * 60 * 60) > time;
953
991
  case "starts with":
954
992
  return userValue.startsWith(conditionValues);
955
993
  case "not starts with":
@@ -987,14 +1025,24 @@ function digestHash(string) {
987
1025
 
988
1026
  // src/helpers/doTypeConversion.js
989
1027
  function doTypeConversion(type, value) {
990
- if (type === "string")
991
- return value;
992
- if (type === "bool") {
993
- return value === "true" ? true : false;
994
- }
995
- if (type === "integer" || type === "number")
996
- return parseFloat(value);
997
- return value;
1028
+ switch (type) {
1029
+ case "string":
1030
+ return value;
1031
+ case "bool":
1032
+ return value === "true" ? true : false;
1033
+ case "integer":
1034
+ case "number":
1035
+ return parseFloat(value);
1036
+ case "json":
1037
+ try {
1038
+ return JSON.parse(value);
1039
+ } catch (e) {
1040
+ console.error(errorTypesInConfig.invalidJson.replace("%value%", value), e);
1041
+ return null;
1042
+ }
1043
+ default:
1044
+ return value;
1045
+ }
998
1046
  }
999
1047
 
1000
1048
  // src/helpers/generateRandomId.js
@@ -1059,6 +1107,12 @@ function generateFilteredList(array, name) {
1059
1107
  return array;
1060
1108
  }
1061
1109
 
1110
+ // package.json
1111
+ var version = "3.2.6";
1112
+
1113
+ // src/helpers/sdkVersion.js
1114
+ var sdkVersion = version;
1115
+
1062
1116
  // src/sigma.js
1063
1117
  if (typeof import_node_fetch.default.default !== "undefined")
1064
1118
  import_node_fetch.default.default;
@@ -1070,17 +1124,17 @@ var Sigma = class {
1070
1124
  geoCacheTTL: null
1071
1125
  }) {
1072
1126
  if (!token) {
1073
- throw new Error("Please specify a token");
1127
+ throw new Error(errorMessages.emptyToken);
1074
1128
  }
1075
1129
  this.token = token;
1076
1130
  this.userData = userData || {};
1077
1131
  cacheTTL < 10 ? this.cacheTTL = 10 : this.cacheTTL = cacheTTL;
1078
- this.api = options.api || `${defaultApi}`;
1079
- this.retries = options.retries || 3;
1080
- this.sigmaUserData = new SigmaUserData();
1132
+ this.api = options.api || defaultApi;
1133
+ this.retries = options.retries || 2;
1081
1134
  this.postfix = options.postfix || "";
1135
+ this.geoCacheTTL = options.geoCacheTTL || defaultGeoCacheTTL;
1136
+ this.sigmaUserData = new SigmaUserData();
1082
1137
  this.cache = new SigmaCache(this.postfix);
1083
- this.geoCache = new SigmaGeoCache(`${this.userData.ip}__${this.token}`, options.geoCacheTTL);
1084
1138
  this.sigmaUserData.init({
1085
1139
  userId: this.userData.userId || null,
1086
1140
  profileId: this.userData.profileId || null,
@@ -1092,7 +1146,7 @@ var Sigma = class {
1092
1146
  deviceCategory: this.userData.deviceCategory || null,
1093
1147
  browser: this.userData.browser || { version: null, name: null },
1094
1148
  os: this.userData.os || { version: null, name: null },
1095
- geo: this.userData.ip ? this.geoCache.get(sigmaGeoData) : this.userData.geo || this.sigmaUserData.user.geo,
1149
+ geo: this.userData.geo || null,
1096
1150
  domain: this.userData.domain || null,
1097
1151
  url: this.userData.url || null,
1098
1152
  query: this.userData.query || null,
@@ -1100,6 +1154,7 @@ var Sigma = class {
1100
1154
  });
1101
1155
  this.setSplitIdsToCache(this.userData);
1102
1156
  this.makePrivateIdInCache();
1157
+ this.geoCache = new SigmaGeoCache(`${this.cache.get(sigmaPrivateId)}__${this.token}`, options.geoCacheTTL);
1103
1158
  }
1104
1159
  setSplitIdsToCache(userData) {
1105
1160
  for (let [key, value] of Object.entries(userData)) {
@@ -1120,12 +1175,9 @@ var Sigma = class {
1120
1175
  }
1121
1176
  }
1122
1177
  makePrivateIdInCache() {
1123
- let privateId = this.cache.get(sigmaPrivateId);
1124
- if (!privateId) {
1125
- privateId = generateRandomId();
1126
- this.cache.set(sigmaPrivateId, privateId);
1178
+ if (!this.cache.get(sigmaPrivateId)) {
1179
+ this.cache.set(sigmaPrivateId, generateRandomId());
1127
1180
  }
1128
- return privateId;
1129
1181
  }
1130
1182
  retryFetch(url, fetchOptions, retries = 3, timeout) {
1131
1183
  return new Promise((resolve, reject) => {
@@ -1134,7 +1186,7 @@ var Sigma = class {
1134
1186
  const wrapper = (n) => {
1135
1187
  (0, import_node_fetch.default)(url, fetchOptions).then((res) => resolve(res)).catch((err) => {
1136
1188
  if (n > 0) {
1137
- delay(1e3).then(() => {
1189
+ delay(0).then(() => {
1138
1190
  wrapper(--n);
1139
1191
  });
1140
1192
  } else {
@@ -1154,88 +1206,75 @@ var Sigma = class {
1154
1206
  "ip": this.userData.ip,
1155
1207
  "X-Real-IP": this.userData.ip,
1156
1208
  token: this.token,
1157
- "user-id": this.cache.get(sigmaPrivateId)
1209
+ "user-id": this.cache.get(sigmaPrivateId),
1210
+ "sdk-name": sdkName,
1211
+ "sdk-version": sdkVersion
1158
1212
  }
1159
1213
  };
1160
- if (method !== "GET") {
1161
- options.headers["Content-Type"] = "application/json; charset=utf-8";
1162
- }
1163
1214
  const data = await this.retryFetch(
1164
1215
  url,
1165
1216
  options,
1166
1217
  this.retries
1167
1218
  );
1168
- if (data.status !== 200) {
1169
- throw new Error(`${data.status} Token: ${this.token}`);
1170
- }
1171
1219
  return data.json();
1172
1220
  }
1221
+ async getConfig() {
1222
+ let data;
1223
+ const localStorageHash = this.cache.get(sigmaHash);
1224
+ let hash;
1225
+ data = await this.getDataFile(`${this.api}/config.json`);
1226
+ if (this.sigmaUserData.platform) {
1227
+ data = filterByPlatform(data, this.sigmaUserData.user.platform);
1228
+ }
1229
+ hash = await SHA256.hex(JSON.stringify(data));
1230
+ if (!localStorageHash || localStorageHash !== hash) {
1231
+ this.cache.set(sigmaHash, hash);
1232
+ this.cache.set(sigmaDataFile, JSON.stringify(data));
1233
+ }
1234
+ }
1173
1235
  async getUserGeoData() {
1174
- try {
1175
- const data = await this.getDataFile(`${this.api}/geo`);
1176
- return data;
1177
- } catch (error) {
1178
- throw new Error(`Get geo: ${error}`);
1236
+ if (this.userData.ip) {
1237
+ const userGeoData = await this.getDataFile(`${this.api}/geo`);
1238
+ this.geoCache.set(sigmaGeoData, JSON.stringify(userGeoData));
1239
+ } else if (this.userData.geo) {
1240
+ this.geoCache.set(sigmaGeoData, JSON.stringify(this.userData.geo));
1241
+ } else {
1242
+ this.geoCache.set(sigmaGeoData, JSON.stringify({ location: "none" }));
1179
1243
  }
1180
1244
  }
1245
+ recordLastUpdateInCache() {
1246
+ const timeRecord = Math.floor(Date.now() / 1e3);
1247
+ this.cache.set(sigmaDataFileLastUpdate, timeRecord);
1248
+ }
1181
1249
  async saveToCache() {
1182
- const { api } = this;
1183
- const localStorageHash = this.cache.get(sigmaHash);
1184
- let data;
1185
1250
  try {
1186
- data = await this.getDataFile(`${api}/config.json`);
1187
- } catch (error) {
1251
+ await this.getConfig();
1252
+ } catch {
1253
+ errorMessages.APIRequestErrorConfig.userData = JSON.stringify(this.userData);
1254
+ errorMessages.APIRequestErrorConfig.token = this.token;
1188
1255
  if (!this.cache.get(sigmaDataFile)) {
1189
- throw new Error(` Get config: ${error}`);
1256
+ errorMessages.APIRequestErrorConfig.cache = false;
1257
+ console.error(errorMessages.APIRequestErrorConfig);
1258
+ throw new Error(JSON.stringify(errorMessages.APIRequestErrorConfig));
1190
1259
  } else {
1191
- console.error(`Get config: ${error}`);
1192
- return true;
1193
- }
1194
- }
1195
- let hash;
1196
- try {
1197
- if (typeof data !== "object") {
1198
- throw new Error(`typeof config.json is not an object`);
1199
- }
1200
- data = filterByPlatform(data, this.userData.platform || this.sigmaUserData.platform);
1201
- hash = await SHA256.hex(JSON.stringify(data));
1202
- if (!localStorageHash || localStorageHash !== hash) {
1203
- this.cache.set(sigmaHash, hash);
1204
- this.cache.set(sigmaDataFile, JSON.stringify(data));
1205
- this.sigmaUserData.clearFlags();
1260
+ errorMessages.APIRequestErrorConfig.cache = true;
1261
+ console.error(errorMessages.APIRequestErrorConfig);
1206
1262
  }
1207
- } catch (error) {
1208
- throw new Error(`Save data to local storage`);
1209
1263
  }
1210
1264
  try {
1211
- if (this.userData.ip) {
1212
- const userGeoData = await this.getUserGeoData();
1213
- this.geoCache.set(sigmaGeoData, JSON.stringify(userGeoData));
1214
- this.sigmaUserData.setGeo(userGeoData);
1215
- } else if (this.userData.geo) {
1216
- this.geoCache.set(sigmaGeoData, JSON.stringify(this.userData.geo));
1217
- this.sigmaUserData.setGeo(this.userData.geo);
1218
- } else {
1265
+ await this.getUserGeoData();
1266
+ } catch {
1267
+ if (!this.geoCache.get(sigmaGeoData)) {
1219
1268
  this.geoCache.set(sigmaGeoData, JSON.stringify({ location: "none" }));
1220
- this.sigmaUserData.setGeo({ location: "none" });
1221
1269
  }
1222
- } catch {
1223
- this.geoCache.set(sigmaGeoData, JSON.stringify({ location: "none" }));
1224
- this.sigmaUserData.setGeo({ location: "none" });
1225
- }
1226
- try {
1227
- const timeRecord = Math.floor(Date.now() / 1e3);
1228
- this.cache.set(sigmaDataFileLastUpdate, timeRecord);
1229
- } catch (error) {
1230
- throw new Error(`save last update to cache: ${error},
1231
- token: ${this.token}
1232
- `);
1270
+ errorMessages.APIRequestErrorGeoData.token = this.token;
1271
+ errorMessages.APIRequestErrorGeoData.userData = JSON.stringify(this.userData);
1272
+ console.error(errorMessages.APIRequestErrorGeoData);
1233
1273
  }
1274
+ this.recordLastUpdateInCache();
1234
1275
  }
1235
1276
  hasExpireCache() {
1236
- const lastUpdate = parseInt(
1237
- this.cache.get(sigmaDataFileLastUpdate)
1238
- );
1277
+ const lastUpdate = Number(this.cache.get(sigmaDataFileLastUpdate));
1239
1278
  const currentTime = Math.floor(Date.now() / 1e3);
1240
1279
  if (currentTime > lastUpdate + this.cacheTTL) {
1241
1280
  return true;
@@ -1256,13 +1295,13 @@ var Sigma = class {
1256
1295
  return flags.feature_flags;
1257
1296
  }
1258
1297
  async checkFlag(flagName) {
1259
- if (!flagName) {
1298
+ if (!flagName)
1260
1299
  return null;
1261
- }
1262
1300
  await this.updateCache();
1263
1301
  const cacheKey = this.cache.parse(sigmaDataFile);
1264
1302
  if (!cacheKey.feature_flags)
1265
1303
  return;
1304
+ this.sigmaUserData.setGeo(this.geoCache.parse(sigmaGeoData));
1266
1305
  let flag = null;
1267
1306
  const expName = this.getExperimentByFeatureFlag(cacheKey, flagName);
1268
1307
  if (expName) {
@@ -1321,9 +1360,8 @@ var Sigma = class {
1321
1360
  if (!child)
1322
1361
  return false;
1323
1362
  const isSetParentInUserData = Object.keys(user).find((i) => i === parent);
1324
- if (!user[isSetParentInUserData]) {
1363
+ if (!user[isSetParentInUserData])
1325
1364
  return false;
1326
- }
1327
1365
  const userObject = Object.entries(user[isSetParentInUserData]);
1328
1366
  for (let [userParamKey, userParamValue] of userObject) {
1329
1367
  if (userParamKey == child) {
@@ -1368,17 +1406,13 @@ var Sigma = class {
1368
1406
  }
1369
1407
  return null;
1370
1408
  }
1371
- getSplitById(experiment) {
1372
- if (!experiment)
1373
- return;
1409
+ switchSplitById(splitBy) {
1374
1410
  let id = null;
1375
- if (!experiment.split_by) {
1376
- experiment.split_by = "userId";
1377
- }
1378
- switch (experiment.split_by) {
1411
+ const cacheSigmaExpiration = this.cache.get(sigmaExpiration);
1412
+ switch (splitBy) {
1379
1413
  case "userId":
1380
1414
  id = this.cache.get(sigmaUserId) || null;
1381
- if (this.cache.get(sigmaExpiration) && parseInt(new Date().getTime()) >= parseInt(this.cache.get(sigmaExpiration))) {
1415
+ if (typeof cacheSigmaExpiration !== "undefined" && new Date().getTime() >= Number(cacheSigmaExpiration)) {
1382
1416
  id = null;
1383
1417
  }
1384
1418
  break;
@@ -1391,6 +1425,14 @@ var Sigma = class {
1391
1425
  }
1392
1426
  return id;
1393
1427
  }
1428
+ getSplitById(experiment) {
1429
+ if (!experiment)
1430
+ return null;
1431
+ if (!experiment.split_by) {
1432
+ experiment.split_by = "userId";
1433
+ }
1434
+ return this.switchSplitById(experiment.split_by);
1435
+ }
1394
1436
  checkTargetConditions(experiment) {
1395
1437
  if (experiment.targets && experiment.targets.conditions && experiment.targets.conditions.length > 0) {
1396
1438
  const targets = experiment.targets;
@@ -1416,7 +1458,7 @@ var Sigma = class {
1416
1458
  return false;
1417
1459
  }
1418
1460
  checkConditionSignForHash(condition) {
1419
- return ["equal", "not equal", "any of", "none of"].includes(condition);
1461
+ return signsForHash.includes(condition);
1420
1462
  }
1421
1463
  experimentDefinition(experiment, forcedUserInGroup) {
1422
1464
  if (forcedUserInGroup) {
@@ -1429,14 +1471,13 @@ var Sigma = class {
1429
1471
  return null;
1430
1472
  }
1431
1473
  async getExperiment(experimentName) {
1432
- if (!experimentName) {
1474
+ if (!experimentName)
1433
1475
  return null;
1434
- }
1435
1476
  await this.updateCache();
1436
1477
  const sigmaDataLs = await this.cache.parse(sigmaDataFile);
1437
- if (!sigmaDataLs.experiments) {
1438
- throw new Error("Experiments not found in cache");
1439
- }
1478
+ this.sigmaUserData.setGeo(this.geoCache.parse(sigmaGeoData));
1479
+ if (!sigmaDataLs.experiments)
1480
+ throw new Error(errorMessages.isNoExperimentInCache);
1440
1481
  let experiment = null;
1441
1482
  let layer = null;
1442
1483
  let bounds = [];
@@ -1457,7 +1498,7 @@ var Sigma = class {
1457
1498
  break;
1458
1499
  }
1459
1500
  }
1460
- const localStorageGroupName = `sigma_group_${experimentName}`;
1501
+ const localStorageGroupName = `${prefixGroup}_${experimentName}`;
1461
1502
  if (experiment) {
1462
1503
  if (!groupName) {
1463
1504
  groupName = this.calcUserInGroup(
@@ -1597,7 +1638,7 @@ var Sigma = class {
1597
1638
  }
1598
1639
  }
1599
1640
  if (!flagDefaultResult) {
1600
- throw new Error("bad config.json");
1641
+ throw new Error(errorMessages.badConfig);
1601
1642
  }
1602
1643
  for (let flagIndex in flagRules) {
1603
1644
  const statement = flagRules[flagIndex].conditional_statement;