expf-sigma-node.js 2.0.1 → 3.0.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 +180 -134
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expf-sigma-node.js",
3
- "version": "2.0.1",
3
+ "version": "3.0.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
@@ -35,6 +35,8 @@ var SigmaUserData = class {
35
35
  constructor() {
36
36
  this.user = {
37
37
  userId: null,
38
+ profileId: null,
39
+ deviceId: null,
38
40
  ip: null,
39
41
  email: null,
40
42
  appVersion: null,
@@ -68,6 +70,8 @@ var SigmaUserData = class {
68
70
  }
69
71
  init({
70
72
  userId,
73
+ profileId,
74
+ deviceId,
71
75
  ip,
72
76
  email,
73
77
  appVersion,
@@ -82,6 +86,8 @@ var SigmaUserData = class {
82
86
  pathname
83
87
  }) {
84
88
  this.user.userId = userId;
89
+ this.user.profileId = profileId;
90
+ this.user.deviceId = deviceId;
85
91
  this.user.ip = ip;
86
92
  this.user.email = email;
87
93
  this.user.appVersion = appVersion;
@@ -185,6 +191,107 @@ var SigmaGeoCache = class {
185
191
  }
186
192
  };
187
193
 
194
+ // src/helpers/checkBoolValue.js
195
+ function checkBoolValue(value) {
196
+ if (value)
197
+ return true;
198
+ return false;
199
+ }
200
+
201
+ // src/helpers/checkForcedList.js
202
+ function checkForcedList(usersList, data) {
203
+ if (usersList.length) {
204
+ for (let id in usersList) {
205
+ if (usersList[id] == data) {
206
+ return true;
207
+ }
208
+ }
209
+ }
210
+ return false;
211
+ }
212
+
213
+ // src/helpers/compareVersions.js
214
+ function compareVersions(versionA, versionB, strict = true) {
215
+ let resultCompare;
216
+ const versionsLength = Math.max(versionA.length, versionB.length);
217
+ versionA = (versionA + "").split(".");
218
+ versionB = (versionB + "").split(".");
219
+ for (let i = 0; i < versionsLength; i++) {
220
+ if (versionA[i] === void 0) {
221
+ versionA[i] = "0";
222
+ }
223
+ if (versionB[i] === void 0) {
224
+ versionB[i] = "0";
225
+ }
226
+ resultCompare = parseInt(versionA[i], 10) - parseInt(versionB[i], 10);
227
+ if (resultCompare !== 0) {
228
+ return resultCompare < 0 ? false : true;
229
+ }
230
+ }
231
+ if (strict) {
232
+ return false;
233
+ }
234
+ if (!strict) {
235
+ return true;
236
+ }
237
+ }
238
+
239
+ // src/helpers/delay.js
240
+ function delay(ms) {
241
+ new Promise((resolve) => setTimeout(() => resolve(void 0), ms));
242
+ }
243
+
244
+ // src/helpers/digestHash.js
245
+ function digestHash(string) {
246
+ let hash = 0, i, chr;
247
+ if (string.length === 0)
248
+ return hash;
249
+ for (i = 0; i < string.length; i++) {
250
+ chr = string.charCodeAt(i);
251
+ hash = (hash << 5) - hash + chr;
252
+ hash |= 0;
253
+ }
254
+ return hash;
255
+ }
256
+
257
+ // src/helpers/doTypeConversion.js
258
+ function doTypeConversion(type, value) {
259
+ if (type === "string")
260
+ return value;
261
+ if (type === "bool") {
262
+ return value === "true" ? true : false;
263
+ }
264
+ if (type === "integer" || type === "number")
265
+ return parseFloat(value);
266
+ return value;
267
+ }
268
+
269
+ // src/helpers/makeIdCookie.js
270
+ function makeIdCookie() {
271
+ let text = "";
272
+ let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
273
+ for (let i = 0; i < 80; i++)
274
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
275
+ return text;
276
+ }
277
+
278
+ // src/helpers/getUserGroup.js
279
+ function getUserGroup(salt, exposureRate, controlBucketPerc, forcedExp) {
280
+ let userInGroup = "a";
281
+ let currentDiapason = 0;
282
+ if (Math.abs(salt) / 100 <= parseFloat(exposureRate) * 100 || forcedExp) {
283
+ let bucket = Math.abs(salt) % 100;
284
+ for (let i = 0; i < controlBucketPerc.length; i++) {
285
+ currentDiapason += controlBucketPerc[i].weight * 100;
286
+ if (bucket <= currentDiapason) {
287
+ return userInGroup = controlBucketPerc[i].name;
288
+ }
289
+ }
290
+ return userInGroup;
291
+ }
292
+ return false;
293
+ }
294
+
188
295
  // src/modules/sigmaHashes.js
189
296
  var Hashes;
190
297
  function utf8Encode(str) {
@@ -820,118 +927,23 @@ Hashes = {
820
927
  };
821
928
  var sigmaHashes_default = Hashes;
822
929
 
823
- // src/helpers/checkBoolValue.js
824
- function checkBoolValue(value) {
825
- if (value)
826
- return true;
827
- return false;
828
- }
829
-
830
- // src/helpers/checkForcedList.js
831
- function checkForcedList(usersList, data) {
832
- if (usersList.length) {
833
- for (let id in usersList) {
834
- if (usersList[id] == data) {
835
- return true;
836
- }
837
- }
838
- }
839
- return false;
840
- }
841
-
842
- // src/helpers/compareVersions.js
843
- function compareVersions(versionA, versionB, strict = true) {
844
- let resultCompare;
845
- const versionsLength = Math.max(versionA.length, versionB.length);
846
- versionA = (versionA + "").split(".");
847
- versionB = (versionB + "").split(".");
848
- for (let i = 0; i < versionsLength; i++) {
849
- if (versionA[i] === void 0) {
850
- versionA[i] = "0";
851
- }
852
- if (versionB[i] === void 0) {
853
- versionB[i] = "0";
854
- }
855
- resultCompare = parseInt(versionA[i], 10) - parseInt(versionB[i], 10);
856
- if (resultCompare !== 0) {
857
- return resultCompare < 0 ? false : true;
858
- }
859
- }
860
- if (strict) {
861
- return false;
862
- }
863
- if (!strict) {
864
- return true;
865
- }
866
- }
867
-
868
- // src/helpers/delay.js
869
- function delay(ms) {
870
- new Promise((resolve) => setTimeout(() => resolve(void 0), ms));
871
- }
872
-
873
- // src/helpers/digestHash.js
874
- function digestHash(string) {
875
- let hash = 0, i, chr;
876
- if (string.length === 0)
877
- return hash;
878
- for (i = 0; i < string.length; i++) {
879
- chr = string.charCodeAt(i);
880
- hash = (hash << 5) - hash + chr;
881
- hash |= 0;
882
- }
883
- return hash;
884
- }
885
-
886
- // src/helpers/doTypeConversion.js
887
- function doTypeConversion(type, value) {
888
- if (type === "string")
889
- return value;
890
- if (type === "bool") {
891
- return value === "true" ? true : false;
892
- }
893
- if (type === "integer" || type === "number")
894
- return parseFloat(value);
895
- return value;
896
- }
897
-
898
- // src/helpers/makeIdCookie.js
899
- function makeIdCookie() {
900
- let text = "";
901
- let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
902
- for (let i = 0; i < 80; i++)
903
- text += possible.charAt(Math.floor(Math.random() * possible.length));
904
- return text;
905
- }
906
-
907
- // src/helpers/getUserGroup.js
908
- function getUserGroup(salt, exposureRate, controlBucketPerc, forcedExp) {
909
- let userInGroup = "a";
910
- let currentDiapason = 0;
911
- if (Math.abs(salt) / 100 <= parseFloat(exposureRate) * 100 || forcedExp) {
912
- let bucket = Math.abs(salt) % 100;
913
- for (let i = 0; i < controlBucketPerc.length; i++) {
914
- currentDiapason += controlBucketPerc[i].weight * 100;
915
- if (bucket <= currentDiapason) {
916
- return userInGroup = controlBucketPerc[i].name;
917
- }
918
- }
919
- return userInGroup;
920
- }
921
- return false;
922
- }
923
-
924
- // src/sigma.js
925
- if (typeof import_node_fetch.default.default !== "undefined")
926
- import_node_fetch.default.default;
930
+ // src/helpers/constants.js
927
931
  var defaultApi = "https://api.expf.ru/api/v1";
928
932
  var sigmaUserId = "sigmaUserId";
933
+ var sigmaProfileId = "sigmaProfileId";
934
+ var sigmaDeviceId = "sigmaDeviceId";
935
+ var sigmaHash = "sigmaHash";
936
+ var sigmaDataFileLastUpdate = "sigmaDataFileLastUpdate";
929
937
  var sigmaDataFile = "sigmaDataFile";
930
938
  var sigmaExperiments = "sigmaExperiments";
931
- var SHA256 = new sigmaHashes_default.SHA256();
932
- var MD5 = new sigmaHashes_default.MD5();
933
939
  var max_decimal_64 = 18446744073709552e3;
934
940
  var zeta = 8540717056e4;
941
+ var SHA256 = new sigmaHashes_default.SHA256();
942
+ var MD5 = new sigmaHashes_default.MD5();
943
+
944
+ // src/sigma.js
945
+ if (typeof import_node_fetch.default.default !== "undefined")
946
+ import_node_fetch.default.default;
935
947
  var Sigma = class {
936
948
  constructor(token, userData, cacheTTL = 10, options = {
937
949
  api: "",
@@ -950,9 +962,10 @@ var Sigma = class {
950
962
  this.sigmaUserData = new SigmaUserData();
951
963
  this.postfix = options.postfix || "";
952
964
  this.cache = new SigmaCache(this.postfix);
953
- this.userData.userId = this.validateUserDataUserId(this.userData.userId);
954
965
  this.sigmaUserData.init({
955
966
  userId: this.userData.userId || null,
967
+ profileId: this.userData.profileId || null,
968
+ deviceId: this.userData.deviceId || null,
956
969
  ip: this.userData.ip || null,
957
970
  email: this.userData.email || null,
958
971
  appVersion: this.userData.appVersion || null,
@@ -967,8 +980,25 @@ var Sigma = class {
967
980
  pathname: this.userData.pathname || null
968
981
  });
969
982
  this.geoCache = new SigmaGeoCache(this.token, options.geoCacheTTL);
970
- this.cache.set(sigmaUserId, this.userData.userId);
971
- this.setUserCookie();
983
+ this.setSplitIdsToCache(this.userData);
984
+ }
985
+ setSplitIdsToCache(userData) {
986
+ for (let [key, value] of Object.entries(userData)) {
987
+ switch (key) {
988
+ case "userId":
989
+ if (value)
990
+ this.cache.set(sigmaUserId, String(value).trim());
991
+ break;
992
+ case "profileId":
993
+ if (value)
994
+ this.cache.set(sigmaProfileId, String(value).trim());
995
+ break;
996
+ case "deviceId":
997
+ if (value)
998
+ this.cache.set(sigmaDeviceId, String(value).trim());
999
+ break;
1000
+ }
1001
+ }
972
1002
  }
973
1003
  validateUserDataUserId(userId) {
974
1004
  let hasMakeId = false;
@@ -1012,7 +1042,7 @@ var Sigma = class {
1012
1042
  "ip": this.userData.ip,
1013
1043
  "X-Real-IP": this.userData.ip,
1014
1044
  token: this.token,
1015
- "user-id": this.userData.userId ? this.userData.userId : this.sigmaUserData.user.userId
1045
+ "user-id": this.validateUserDataUserId(this.userData.userId)
1016
1046
  }
1017
1047
  };
1018
1048
  if (method !== "GET") {
@@ -1053,10 +1083,10 @@ var Sigma = class {
1053
1083
  }
1054
1084
  async saveToCache() {
1055
1085
  const { api } = this;
1056
- const localStorageHash = this.cache.get("sigmaHash");
1086
+ const localStorageHash = this.cache.get(sigmaHash);
1057
1087
  try {
1058
1088
  const timeRecord = Math.floor(Date.now() / 1e3);
1059
- this.cache.set("sigmaDataFileLastUpdate", timeRecord);
1089
+ this.cache.set(sigmaDataFileLastUpdate, timeRecord);
1060
1090
  } catch (error) {
1061
1091
  throw new Error(`save last update to cache: ${error},
1062
1092
  token: ${this.token}
@@ -1080,7 +1110,7 @@ var Sigma = class {
1080
1110
  }
1081
1111
  hash = await SHA256.hex(JSON.stringify(data));
1082
1112
  if (!localStorageHash || localStorageHash !== hash) {
1083
- this.cache.set("sigmaHash", hash);
1113
+ this.cache.set(sigmaHash, hash);
1084
1114
  this.cache.set(sigmaDataFile, JSON.stringify(data));
1085
1115
  this.sigmaUserData.clearFlags();
1086
1116
  }
@@ -1088,17 +1118,9 @@ var Sigma = class {
1088
1118
  throw new Error(`Save data to local storage`);
1089
1119
  }
1090
1120
  }
1091
- setUserCookie() {
1092
- let uin = this.cache.get(sigmaUserId);
1093
- if (!uin) {
1094
- uin = makeIdCookie();
1095
- this.cache.set(sigmaUserId, uin);
1096
- }
1097
- return;
1098
- }
1099
1121
  hasExpireCache() {
1100
1122
  const lastUpdate = parseInt(
1101
- this.cache.get("sigmaDataFileLastUpdate")
1123
+ this.cache.get(sigmaDataFileLastUpdate)
1102
1124
  );
1103
1125
  const currentTime = Math.floor(Date.now() / 1e3);
1104
1126
  if (currentTime > lastUpdate + this.cacheTTL) {
@@ -1107,14 +1129,14 @@ var Sigma = class {
1107
1129
  return false;
1108
1130
  }
1109
1131
  updateCache() {
1110
- if (!this.cache.get("sigmaDataFile") || this.hasExpireCache()) {
1132
+ if (!this.cache.get(sigmaDataFile) || this.hasExpireCache()) {
1111
1133
  return this.saveToCache();
1112
1134
  }
1113
1135
  return true;
1114
1136
  }
1115
1137
  async getFlags() {
1116
1138
  await this.updateCache();
1117
- const flags = this.cache.parse("sigmaDataFile");
1139
+ const flags = this.cache.parse(sigmaDataFile);
1118
1140
  if (!flags.feature_flags)
1119
1141
  return;
1120
1142
  return flags.feature_flags;
@@ -1179,7 +1201,8 @@ var Sigma = class {
1179
1201
  if (userValue === null || typeof userValue === "undefined" || !conditionValues)
1180
1202
  return false;
1181
1203
  userValue = String(userValue);
1182
- conditionValues = String(conditionValues);
1204
+ if (!Array.isArray(conditionValues))
1205
+ conditionValues = String(conditionValues);
1183
1206
  switch (operation.trim()) {
1184
1207
  case "equal":
1185
1208
  return userValue.toLowerCase().trim() == conditionValues.toLowerCase().trim();
@@ -1260,15 +1283,16 @@ var Sigma = class {
1260
1283
  }
1261
1284
  return defaultValue;
1262
1285
  }
1263
- calcUserInGroup(salt, exposureRate, controlBucketPerc, forcedExp = false, layer = null, layerBounds = []) {
1264
- const userId = this.sigmaUserData.user.userId ? this.sigmaUserData.user.userId : this.cache.get(sigmaUserId);
1265
- const md5R = MD5.hex(String(userId) + salt);
1286
+ calcUserInGroup(salt, exposureRate, controlBucketPerc, forcedExp = false, layer = null, layerBounds = [], splitBy) {
1287
+ if (!splitBy)
1288
+ return false;
1289
+ const md5R = MD5.hex(String(splitBy) + salt);
1266
1290
  const R = digestHash(md5R) * zeta / max_decimal_64;
1267
1291
  let md5L = null;
1268
1292
  if (!layer && !layerBounds.length || forcedExp) {
1269
1293
  return getUserGroup(R, exposureRate, controlBucketPerc, forcedExp);
1270
1294
  } else {
1271
- md5L = MD5.hex(String(userId) + layer);
1295
+ md5L = MD5.hex(String(splitBy) + layer);
1272
1296
  const L = digestHash(md5L) * zeta / max_decimal_64;
1273
1297
  for (let i in layerBounds) {
1274
1298
  const result = Math.abs(L / 10);
@@ -1281,6 +1305,23 @@ var Sigma = class {
1281
1305
  }
1282
1306
  return false;
1283
1307
  }
1308
+ getSplitById(experiment) {
1309
+ if (!experiment)
1310
+ return;
1311
+ let id = null;
1312
+ switch (experiment.split_by) {
1313
+ case "userId":
1314
+ id = this.cache.get(sigmaUserId) || null;
1315
+ break;
1316
+ case "profileId":
1317
+ id = this.cache.get(sigmaProfileId) || null;
1318
+ break;
1319
+ case "deviceId":
1320
+ id = this.cache.get(sigmaDeviceId) || null;
1321
+ break;
1322
+ }
1323
+ return id;
1324
+ }
1284
1325
  checkTargetConditions(experiment) {
1285
1326
  if (experiment.targets && experiment.targets.conditions && experiment.targets.conditions.length > 0) {
1286
1327
  const targets = experiment.targets;
@@ -1331,12 +1372,14 @@ var Sigma = class {
1331
1372
  let bounds = [];
1332
1373
  let userInGroupExperiment = null;
1333
1374
  let forcedUser = false;
1375
+ let splitById = null;
1334
1376
  for (let i = 0; i < sigmaDataLs.experiments.length; i++) {
1335
1377
  if (sigmaDataLs.experiments[i]["name"] === experimentName && checkBoolValue(sigmaDataLs.experiments[i]["layer_id"])) {
1336
1378
  layer = sigmaDataLs.experiments[i]["layer_id"];
1337
1379
  bounds = sigmaDataLs.experiments[i]["layer_bounds"];
1338
1380
  }
1339
1381
  if (sigmaDataLs.experiments[i]["name"] === experimentName && !experiment) {
1382
+ splitById = this.getSplitById(sigmaDataLs.experiments[i]);
1340
1383
  forcedUser = checkForcedList(sigmaDataLs.experiments[i].forced_user_list, this.sigmaUserData.user.userId);
1341
1384
  userInGroupExperiment = this.findUserInForcedGroup(sigmaDataLs.experiments[i]);
1342
1385
  experiment = this.experimentDefinition(sigmaDataLs.experiments[i], userInGroupExperiment);
@@ -1352,7 +1395,8 @@ var Sigma = class {
1352
1395
  experiment.groups,
1353
1396
  forcedUser,
1354
1397
  layer,
1355
- bounds
1398
+ bounds,
1399
+ splitById
1356
1400
  );
1357
1401
  }
1358
1402
  this.cache.set(localStorageGroupName, userInGroupExperiment);
@@ -1420,6 +1464,7 @@ var Sigma = class {
1420
1464
  for (let i in sigmaDataLs.experiments) {
1421
1465
  let layer = null;
1422
1466
  let bounds = [];
1467
+ let splitById = this.getSplitById(sigmaDataLs.experiments[i]);
1423
1468
  let userInGroupExperiment = this.findUserInForcedGroup(sigmaDataLs.experiments[i]);
1424
1469
  let experiment = this.experimentDefinition(sigmaDataLs.experiments[i], userInGroupExperiment);
1425
1470
  if (experiment) {
@@ -1432,9 +1477,10 @@ var Sigma = class {
1432
1477
  experiment.salt,
1433
1478
  experiment.allocation,
1434
1479
  experiment.groups,
1435
- checkForcedList(experiment.forced_user_list, this.sigmaUserData.user.userId),
1480
+ checkForcedList(experiment.forced_user_list, splitById),
1436
1481
  layer,
1437
- bounds
1482
+ bounds,
1483
+ splitById
1438
1484
  );
1439
1485
  }
1440
1486
  }
@@ -1455,7 +1501,7 @@ var Sigma = class {
1455
1501
  const forcedList = experiment.groups[groupItem].forced_user_list;
1456
1502
  if (forcedList && forcedList.length) {
1457
1503
  for (const item in forcedList) {
1458
- if (forcedList[item] === this.sigmaUserData.user.userId) {
1504
+ if (forcedList[item] === this.getSplitById(experiment)) {
1459
1505
  return groupName = experiment.groups[groupItem].name;
1460
1506
  }
1461
1507
  }
@@ -1527,7 +1573,7 @@ var Sigma = class {
1527
1573
  return this.cache.parse(sigmaDataFile);
1528
1574
  }
1529
1575
  async getCacheHash() {
1530
- const data = await this.cache.get("sigmaHash");
1576
+ const data = await this.cache.get(sigmaHash);
1531
1577
  return data;
1532
1578
  }
1533
1579
  async getCacheUserId() {