posthog-node 2.0.0-alpha9 → 2.0.1

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/lib/index.esm.js CHANGED
@@ -1,4 +1,5 @@
1
- import undici from 'undici';
1
+ import undici, { request } from 'undici';
2
+ import { createHash } from 'crypto';
2
3
 
3
4
  /******************************************************************************
4
5
  Copyright (c) Microsoft Corporation.
@@ -129,9 +130,20 @@ function __generator(thisArg, body) {
129
130
  throw op[1];
130
131
  return { value: op[0] ? op[1] : void 0, done: true };
131
132
  }
133
+ }
134
+ function __spreadArray(to, from, pack) {
135
+ if (pack || arguments.length === 2)
136
+ for (var i = 0, l = from.length, ar; i < l; i++) {
137
+ if (ar || !(i in from)) {
138
+ if (!ar)
139
+ ar = Array.prototype.slice.call(from, 0, i);
140
+ ar[i] = from[i];
141
+ }
142
+ }
143
+ return to.concat(ar || Array.prototype.slice.call(from));
132
144
  }
133
145
 
134
- var version = "2.0.0-alpha9";
146
+ var version = "2.0.1";
135
147
 
136
148
  var PostHogPersistedProperty;
137
149
  (function (PostHogPersistedProperty) {
@@ -144,6 +156,8 @@ var PostHogPersistedProperty;
144
156
  PostHogPersistedProperty["OptedOut"] = "opted_out";
145
157
  PostHogPersistedProperty["SessionId"] = "session_id";
146
158
  PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
159
+ PostHogPersistedProperty["PersonProperties"] = "person_properties";
160
+ PostHogPersistedProperty["GroupProperties"] = "group_properties";
147
161
  })(PostHogPersistedProperty || (PostHogPersistedProperty = {}));
148
162
 
149
163
  function assert(truthyValue, message) {
@@ -717,12 +731,14 @@ var PostHogCore = /** @class */ (function () {
717
731
  }
718
732
  PostHogCore.prototype.getCommonEventProperties = function () {
719
733
  var featureFlags = this.getFeatureFlags();
720
- return {
721
- $lib: this.getLibraryId(),
722
- $lib_version: this.getLibraryVersion(),
723
- $active_feature_flags: featureFlags ? Object.keys(featureFlags) : undefined,
724
- $enabled_feature_flags: featureFlags,
725
- };
734
+ var featureVariantProperties = {};
735
+ if (featureFlags) {
736
+ for (var _i = 0, _a = Object.entries(featureFlags); _i < _a.length; _i++) {
737
+ var _b = _a[_i], feature = _b[0], variant = _b[1];
738
+ featureVariantProperties["$feature/".concat(feature)] = variant;
739
+ }
740
+ }
741
+ return __assign({ $lib: this.getLibraryId(), $lib_version: this.getLibraryVersion(), $active_feature_flags: featureFlags ? Object.keys(featureFlags) : undefined }, featureVariantProperties);
726
742
  };
727
743
  Object.defineProperty(PostHogCore.prototype, "props", {
728
744
  // NOTE: Props are lazy loaded from localstorage hence the complex getter setter logic
@@ -738,6 +754,9 @@ var PostHogCore = /** @class */ (function () {
738
754
  enumerable: false,
739
755
  configurable: true
740
756
  });
757
+ PostHogCore.prototype.clearProps = function () {
758
+ this.props = undefined;
759
+ };
741
760
  Object.defineProperty(PostHogCore.prototype, "optedOut", {
742
761
  get: function () {
743
762
  var _a, _b;
@@ -755,9 +774,15 @@ var PostHogCore = /** @class */ (function () {
755
774
  PostHogCore.prototype.on = function (event, cb) {
756
775
  return this._events.on(event, cb);
757
776
  };
758
- PostHogCore.prototype.reset = function () {
759
- for (var key in PostHogPersistedProperty) {
760
- this.setPersistedProperty(PostHogPersistedProperty[key], null);
777
+ PostHogCore.prototype.reset = function (propertiesToKeep) {
778
+ var allPropertiesToKeep = __spreadArray([PostHogPersistedProperty.Queue], (propertiesToKeep || []), true);
779
+ // clean up props
780
+ this.clearProps();
781
+ for (var _i = 0, _a = Object.keys(PostHogPersistedProperty); _i < _a.length; _i++) {
782
+ var key = _a[_i];
783
+ if (!allPropertiesToKeep.includes(PostHogPersistedProperty[key])) {
784
+ this.setPersistedProperty(PostHogPersistedProperty[key], null);
785
+ }
761
786
  }
762
787
  };
763
788
  PostHogCore.prototype.debug = function (enabled) {
@@ -832,12 +857,18 @@ var PostHogCore = /** @class */ (function () {
832
857
  this.enqueue('identify', payload);
833
858
  return this;
834
859
  };
835
- PostHogCore.prototype.capture = function (event, properties) {
860
+ PostHogCore.prototype.capture = function (event, properties, forceSendFeatureFlags) {
861
+ if (forceSendFeatureFlags === void 0) { forceSendFeatureFlags = false; }
836
862
  if (properties === null || properties === void 0 ? void 0 : properties.$groups) {
837
863
  this.groups(properties.$groups);
838
864
  }
839
- var payload = this.buildPayload({ event: event, properties: properties });
840
- this.enqueue('capture', payload);
865
+ if (forceSendFeatureFlags) {
866
+ this._sendFeatureFlags(event, properties);
867
+ }
868
+ else {
869
+ var payload = this.buildPayload({ event: event, properties: properties });
870
+ this.enqueue('capture', payload);
871
+ }
841
872
  return this;
842
873
  };
843
874
  PostHogCore.prototype.alias = function (alias) {
@@ -867,7 +898,6 @@ var PostHogCore = /** @class */ (function () {
867
898
  PostHogCore.prototype.groups = function (groups) {
868
899
  // Get persisted groups
869
900
  var existingGroups = this.props.$groups || {};
870
- // NOTE: Should we do the same for groups listed in identify / capture?
871
901
  this.register({
872
902
  $groups: __assign(__assign({}, existingGroups), groups),
873
903
  });
@@ -895,31 +925,58 @@ var PostHogCore = /** @class */ (function () {
895
925
  this.enqueue('capture', payload);
896
926
  return this;
897
927
  };
928
+ /***
929
+ * PROPERTIES
930
+ ***/
931
+ PostHogCore.prototype.personProperties = function (properties) {
932
+ // Get persisted person properties
933
+ var existingProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
934
+ this.setPersistedProperty(PostHogPersistedProperty.PersonProperties, __assign(__assign({}, existingProperties), properties));
935
+ return this;
936
+ };
937
+ PostHogCore.prototype.groupProperties = function (properties) {
938
+ // Get persisted group properties
939
+ var existingProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) || {};
940
+ if (Object.keys(existingProperties).length !== 0) {
941
+ Object.keys(existingProperties).forEach(function (groupType) {
942
+ existingProperties[groupType] = __assign(__assign({}, existingProperties[groupType]), properties[groupType]);
943
+ delete properties[groupType];
944
+ });
945
+ }
946
+ this.setPersistedProperty(PostHogPersistedProperty.GroupProperties, __assign(__assign({}, existingProperties), properties));
947
+ return this;
948
+ };
898
949
  /***
899
950
  *** FEATURE FLAGS
900
951
  ***/
901
- PostHogCore.prototype.decideAsync = function () {
952
+ PostHogCore.prototype.decideAsync = function (sendAnonDistinctId) {
953
+ if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
902
954
  if (this._decideResponsePromise) {
903
955
  return this._decideResponsePromise;
904
956
  }
905
- return this._decideAsync();
957
+ return this._decideAsync(sendAnonDistinctId);
906
958
  };
907
- PostHogCore.prototype._decideAsync = function () {
959
+ PostHogCore.prototype._decideAsync = function (sendAnonDistinctId) {
960
+ if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
908
961
  return __awaiter(this, void 0, void 0, function () {
909
- var url, distinctId, groups, fetchOptions;
962
+ var url, distinctId, groups, personProperties, groupProperties, fetchOptions;
910
963
  var _this = this;
911
964
  return __generator(this, function (_a) {
912
965
  url = "".concat(this.host, "/decide/?v=2");
913
966
  distinctId = this.getDistinctId();
914
967
  groups = this.props.$groups || {};
968
+ personProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
969
+ groupProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) || {};
915
970
  fetchOptions = {
916
971
  method: 'POST',
917
972
  headers: { 'Content-Type': 'application/json' },
918
973
  body: JSON.stringify({
919
974
  token: this.apiKey,
920
975
  distinct_id: distinctId,
921
- $anon_distinct_id: this.getAnonymousId(),
976
+ $anon_distinct_id: sendAnonDistinctId ? this.getAnonymousId() : undefined,
922
977
  groups: groups,
978
+ person_properties: personProperties,
979
+ group_properties: groupProperties,
923
980
  }),
924
981
  };
925
982
  this._decideResponsePromise = this.fetchWithRetry(url, fetchOptions)
@@ -938,23 +995,26 @@ var PostHogCore = /** @class */ (function () {
938
995
  });
939
996
  });
940
997
  };
941
- PostHogCore.prototype.getFeatureFlag = function (key, defaultResult) {
942
- var _a;
943
- if (defaultResult === void 0) { defaultResult = false; }
998
+ PostHogCore.prototype.getFeatureFlag = function (key) {
944
999
  var featureFlags = this.getFeatureFlags();
945
1000
  if (!featureFlags) {
946
- // If we haven't loaded flags yet we respond undefined to indicate this
1001
+ // If we haven't loaded flags yet, or errored out, we respond with undefined
947
1002
  return undefined;
948
1003
  }
1004
+ var response = featureFlags[key];
1005
+ if (response === undefined) {
1006
+ // `/decide` returns nothing for flags which are false.
1007
+ response = false;
1008
+ }
949
1009
  if (this.sendFeatureFlagEvent && !this.flagCallReported[key]) {
950
1010
  this.flagCallReported[key] = true;
951
1011
  this.capture('$feature_flag_called', {
952
1012
  $feature_flag: key,
953
- $feature_flag_response: featureFlags[key],
1013
+ $feature_flag_response: response,
954
1014
  });
955
1015
  }
956
- // If we have flags we either return the value (true or string) or the defaultResult
957
- return (_a = featureFlags[key]) !== null && _a !== void 0 ? _a : defaultResult;
1016
+ // If we have flags we either return the value (true or string) or false
1017
+ return response;
958
1018
  };
959
1019
  PostHogCore.prototype.getFeatureFlags = function () {
960
1020
  var flags = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlags);
@@ -973,17 +1033,19 @@ var PostHogCore = /** @class */ (function () {
973
1033
  }
974
1034
  return flags;
975
1035
  };
976
- PostHogCore.prototype.isFeatureEnabled = function (key, defaultResult) {
977
- var _a;
978
- if (defaultResult === void 0) { defaultResult = false; }
979
- var flag = (_a = this.getFeatureFlag(key, defaultResult)) !== null && _a !== void 0 ? _a : defaultResult;
980
- return !!flag;
1036
+ PostHogCore.prototype.isFeatureEnabled = function (key) {
1037
+ var response = this.getFeatureFlag(key);
1038
+ if (response === undefined) {
1039
+ return undefined;
1040
+ }
1041
+ return !!response;
981
1042
  };
982
- PostHogCore.prototype.reloadFeatureFlagsAsync = function () {
1043
+ PostHogCore.prototype.reloadFeatureFlagsAsync = function (sendAnonDistinctId) {
1044
+ if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
983
1045
  return __awaiter(this, void 0, void 0, function () {
984
1046
  return __generator(this, function (_a) {
985
1047
  switch (_a.label) {
986
- case 0: return [4 /*yield*/, this.decideAsync()];
1048
+ case 0: return [4 /*yield*/, this.decideAsync(sendAnonDistinctId)];
987
1049
  case 1: return [2 /*return*/, (_a.sent()).featureFlags];
988
1050
  }
989
1051
  });
@@ -1021,6 +1083,14 @@ var PostHogCore = /** @class */ (function () {
1021
1083
  }
1022
1084
  return this.setPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags, flags);
1023
1085
  };
1086
+ PostHogCore.prototype._sendFeatureFlags = function (event, properties) {
1087
+ var _this = this;
1088
+ this.reloadFeatureFlagsAsync(false).finally(function () {
1089
+ // Try to enqueue message irrespective of errors during feature flag fetching
1090
+ var payload = _this.buildPayload({ event: event, properties: properties });
1091
+ _this.enqueue('capture', payload);
1092
+ });
1093
+ };
1024
1094
  /***
1025
1095
  *** QUEUEING AND FLUSHING
1026
1096
  ***/
@@ -1049,13 +1119,15 @@ var PostHogCore = /** @class */ (function () {
1049
1119
  PostHogCore.prototype.flushAsync = function () {
1050
1120
  var _this = this;
1051
1121
  return new Promise(function (resolve, reject) {
1052
- _this.flush(function (err, data) { return (err ? reject(err) : resolve(data)); });
1122
+ _this.flush(function (err, data) {
1123
+ return err ? reject(err) : resolve(data);
1124
+ });
1053
1125
  });
1054
1126
  };
1055
1127
  PostHogCore.prototype.flush = function (callback) {
1056
1128
  var _this = this;
1057
1129
  if (this.optedOut) {
1058
- return callback && safeSetTimeout(callback, 0);
1130
+ return callback === null || callback === void 0 ? void 0 : callback();
1059
1131
  }
1060
1132
  if (this._flushTimer) {
1061
1133
  clearTimeout(this._flushTimer);
@@ -1063,7 +1135,7 @@ var PostHogCore = /** @class */ (function () {
1063
1135
  }
1064
1136
  var queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
1065
1137
  if (!queue.length) {
1066
- return callback && safeSetTimeout(callback, 0);
1138
+ return callback === null || callback === void 0 ? void 0 : callback();
1067
1139
  }
1068
1140
  var items = queue.splice(0, this.flushAt);
1069
1141
  this.setPersistedProperty(PostHogPersistedProperty.Queue, queue);
@@ -1150,6 +1222,553 @@ var PostHogMemoryStorage = /** @class */ (function () {
1150
1222
  return PostHogMemoryStorage;
1151
1223
  }());
1152
1224
 
1225
+ var LONG_SCALE = 0xfffffffffffffff;
1226
+
1227
+ var ClientError =
1228
+ /** @class */
1229
+ function (_super) {
1230
+ __extends(ClientError, _super);
1231
+
1232
+ function ClientError(message) {
1233
+ var _this = _super.call(this) || this;
1234
+
1235
+ Error.captureStackTrace(_this, _this.constructor);
1236
+ _this.name = 'ClientError';
1237
+ _this.message = message;
1238
+ Object.setPrototypeOf(_this, ClientError.prototype);
1239
+ return _this;
1240
+ }
1241
+
1242
+ return ClientError;
1243
+ }(Error);
1244
+
1245
+ var InconclusiveMatchError =
1246
+ /** @class */
1247
+ function (_super) {
1248
+ __extends(InconclusiveMatchError, _super);
1249
+
1250
+ function InconclusiveMatchError(message) {
1251
+ var _this = _super.call(this, message) || this;
1252
+
1253
+ _this.name = _this.constructor.name;
1254
+ Error.captureStackTrace(_this, _this.constructor); // instanceof doesn't work in ES3 or ES5
1255
+ // https://www.dannyguo.com/blog/how-to-fix-instanceof-not-working-for-custom-errors-in-typescript/
1256
+ // this is the workaround
1257
+
1258
+ Object.setPrototypeOf(_this, InconclusiveMatchError.prototype);
1259
+ return _this;
1260
+ }
1261
+
1262
+ return InconclusiveMatchError;
1263
+ }(Error);
1264
+
1265
+ var FeatureFlagsPoller =
1266
+ /** @class */
1267
+ function () {
1268
+ function FeatureFlagsPoller(_a) {
1269
+ var pollingInterval = _a.pollingInterval,
1270
+ personalApiKey = _a.personalApiKey,
1271
+ projectApiKey = _a.projectApiKey,
1272
+ timeout = _a.timeout,
1273
+ host = _a.host;
1274
+ this.pollingInterval = pollingInterval;
1275
+ this.personalApiKey = personalApiKey;
1276
+ this.featureFlags = [];
1277
+ this.groupTypeMapping = {};
1278
+ this.loadedSuccessfullyOnce = false;
1279
+ this.timeout = timeout;
1280
+ this.projectApiKey = projectApiKey;
1281
+ this.host = host;
1282
+ this.poller = undefined;
1283
+ void this.loadFeatureFlags();
1284
+ }
1285
+
1286
+ FeatureFlagsPoller.prototype.getFeatureFlag = function (key, distinctId, groups, personProperties, groupProperties) {
1287
+ if (groups === void 0) {
1288
+ groups = {};
1289
+ }
1290
+
1291
+ if (personProperties === void 0) {
1292
+ personProperties = {};
1293
+ }
1294
+
1295
+ if (groupProperties === void 0) {
1296
+ groupProperties = {};
1297
+ }
1298
+
1299
+ return __awaiter(this, void 0, void 0, function () {
1300
+ var response, featureFlag, _i, _a, flag;
1301
+
1302
+ return __generator(this, function (_b) {
1303
+ switch (_b.label) {
1304
+ case 0:
1305
+ return [4
1306
+ /*yield*/
1307
+ , this.loadFeatureFlags()];
1308
+
1309
+ case 1:
1310
+ _b.sent();
1311
+
1312
+ response = undefined;
1313
+ featureFlag = undefined;
1314
+
1315
+ if (!this.loadedSuccessfullyOnce) {
1316
+ return [2
1317
+ /*return*/
1318
+ , response];
1319
+ }
1320
+
1321
+ for (_i = 0, _a = this.featureFlags; _i < _a.length; _i++) {
1322
+ flag = _a[_i];
1323
+
1324
+ if (key === flag.key) {
1325
+ featureFlag = flag;
1326
+ break;
1327
+ }
1328
+ }
1329
+
1330
+ if (featureFlag !== undefined) {
1331
+ try {
1332
+ response = this.computeFlagLocally(featureFlag, distinctId, groups, personProperties, groupProperties);
1333
+ console.debug("Successfully computed flag locally: ".concat(key, " -> ").concat(response));
1334
+ } catch (e) {
1335
+ if (e instanceof InconclusiveMatchError) {
1336
+ console.debug("Can't compute flag locally: ".concat(key, ": ").concat(e));
1337
+ } else if (e instanceof Error) {
1338
+ console.error("Error computing flag locally: ".concat(key, ": ").concat(e));
1339
+ }
1340
+ }
1341
+ }
1342
+
1343
+ return [2
1344
+ /*return*/
1345
+ , response];
1346
+ }
1347
+ });
1348
+ });
1349
+ };
1350
+
1351
+ FeatureFlagsPoller.prototype.getAllFlags = function (distinctId, groups, personProperties, groupProperties) {
1352
+ if (groups === void 0) {
1353
+ groups = {};
1354
+ }
1355
+
1356
+ if (personProperties === void 0) {
1357
+ personProperties = {};
1358
+ }
1359
+
1360
+ if (groupProperties === void 0) {
1361
+ groupProperties = {};
1362
+ }
1363
+
1364
+ return __awaiter(this, void 0, void 0, function () {
1365
+ var response, fallbackToDecide;
1366
+
1367
+ var _this = this;
1368
+
1369
+ return __generator(this, function (_a) {
1370
+ switch (_a.label) {
1371
+ case 0:
1372
+ return [4
1373
+ /*yield*/
1374
+ , this.loadFeatureFlags()];
1375
+
1376
+ case 1:
1377
+ _a.sent();
1378
+
1379
+ response = {};
1380
+ fallbackToDecide = this.featureFlags.length == 0;
1381
+ this.featureFlags.map(function (flag) {
1382
+ try {
1383
+ response[flag.key] = _this.computeFlagLocally(flag, distinctId, groups, personProperties, groupProperties);
1384
+ } catch (e) {
1385
+ if (e instanceof InconclusiveMatchError) ; else if (e instanceof Error) {
1386
+ console.error("Error computing flag locally: ".concat(flag.key, ": ").concat(e));
1387
+ }
1388
+
1389
+ fallbackToDecide = true;
1390
+ }
1391
+ });
1392
+ return [2
1393
+ /*return*/
1394
+ , {
1395
+ response: response,
1396
+ fallbackToDecide: fallbackToDecide
1397
+ }];
1398
+ }
1399
+ });
1400
+ });
1401
+ };
1402
+
1403
+ FeatureFlagsPoller.prototype.computeFlagLocally = function (flag, distinctId, groups, personProperties, groupProperties) {
1404
+ if (groups === void 0) {
1405
+ groups = {};
1406
+ }
1407
+
1408
+ if (personProperties === void 0) {
1409
+ personProperties = {};
1410
+ }
1411
+
1412
+ if (groupProperties === void 0) {
1413
+ groupProperties = {};
1414
+ }
1415
+
1416
+ if (flag.ensure_experience_continuity) {
1417
+ throw new InconclusiveMatchError('Flag has experience continuity enabled');
1418
+ }
1419
+
1420
+ if (!flag.active) {
1421
+ return false;
1422
+ }
1423
+
1424
+ var flagFilters = flag.filters || {};
1425
+ var aggregation_group_type_index = flagFilters.aggregation_group_type_index;
1426
+
1427
+ if (aggregation_group_type_index != undefined) {
1428
+ var groupName = this.groupTypeMapping[String(aggregation_group_type_index)];
1429
+
1430
+ if (!groupName) {
1431
+ console.warn("[FEATURE FLAGS] Unknown group type index ".concat(aggregation_group_type_index, " for feature flag ").concat(flag.key));
1432
+ throw new InconclusiveMatchError('Flag has unknown group type index');
1433
+ }
1434
+
1435
+ if (!(groupName in groups)) {
1436
+ console.warn("[FEATURE FLAGS] Can't compute group feature flag: ".concat(flag.key, " without group names passed in"));
1437
+ return false;
1438
+ }
1439
+
1440
+ var focusedGroupProperties = groupProperties[groupName];
1441
+ return this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties);
1442
+ } else {
1443
+ return this.matchFeatureFlagProperties(flag, distinctId, personProperties);
1444
+ }
1445
+ };
1446
+
1447
+ FeatureFlagsPoller.prototype.matchFeatureFlagProperties = function (flag, distinctId, properties) {
1448
+ var _this = this;
1449
+
1450
+ var flagFilters = flag.filters || {};
1451
+ var flagConditions = flagFilters.groups || [];
1452
+ var isInconclusive = false;
1453
+ var result = undefined;
1454
+ flagConditions.forEach(function (condition) {
1455
+ try {
1456
+ if (_this.isConditionMatch(flag, distinctId, condition, properties)) {
1457
+ result = _this.getMatchingVariant(flag, distinctId) || true;
1458
+ }
1459
+ } catch (e) {
1460
+ if (e instanceof InconclusiveMatchError) {
1461
+ isInconclusive = true;
1462
+ } else {
1463
+ throw e;
1464
+ }
1465
+ }
1466
+ });
1467
+
1468
+ if (result !== undefined) {
1469
+ return result;
1470
+ } else if (isInconclusive) {
1471
+ throw new InconclusiveMatchError("Can't determine if feature flag is enabled or not with given properties");
1472
+ } // We can only return False when all conditions are False
1473
+
1474
+
1475
+ return false;
1476
+ };
1477
+
1478
+ FeatureFlagsPoller.prototype.isConditionMatch = function (flag, distinctId, condition, properties) {
1479
+ var rolloutPercentage = condition.rollout_percentage;
1480
+
1481
+ if ((condition.properties || []).length > 0) {
1482
+ var matchAll = condition.properties.every(function (property) {
1483
+ return matchProperty(property, properties);
1484
+ });
1485
+
1486
+ if (!matchAll) {
1487
+ return false;
1488
+ } else if (rolloutPercentage == undefined) {
1489
+ // == to include `null` as a match, not just `undefined`
1490
+ return true;
1491
+ }
1492
+ }
1493
+
1494
+ if (rolloutPercentage != undefined && _hash(flag.key, distinctId) > rolloutPercentage / 100.0) {
1495
+ return false;
1496
+ }
1497
+
1498
+ return true;
1499
+ };
1500
+
1501
+ FeatureFlagsPoller.prototype.getMatchingVariant = function (flag, distinctId) {
1502
+ var hashValue = _hash(flag.key, distinctId, 'variant');
1503
+
1504
+ var matchingVariant = this.variantLookupTable(flag).find(function (variant) {
1505
+ return hashValue >= variant.valueMin && hashValue < variant.valueMax;
1506
+ });
1507
+
1508
+ if (matchingVariant) {
1509
+ return matchingVariant.key;
1510
+ }
1511
+
1512
+ return undefined;
1513
+ };
1514
+
1515
+ FeatureFlagsPoller.prototype.variantLookupTable = function (flag) {
1516
+ var _a;
1517
+
1518
+ var lookupTable = [];
1519
+ var valueMin = 0;
1520
+ var valueMax = 0;
1521
+ var flagFilters = flag.filters || {};
1522
+ var multivariates = ((_a = flagFilters.multivariate) === null || _a === void 0 ? void 0 : _a.variants) || [];
1523
+ multivariates.forEach(function (variant) {
1524
+ valueMax = valueMin + variant.rollout_percentage / 100.0;
1525
+ lookupTable.push({
1526
+ valueMin: valueMin,
1527
+ valueMax: valueMax,
1528
+ key: variant.key
1529
+ });
1530
+ valueMin = valueMax;
1531
+ });
1532
+ return lookupTable;
1533
+ };
1534
+
1535
+ FeatureFlagsPoller.prototype.loadFeatureFlags = function (forceReload) {
1536
+ if (forceReload === void 0) {
1537
+ forceReload = false;
1538
+ }
1539
+
1540
+ return __awaiter(this, void 0, void 0, function () {
1541
+ return __generator(this, function (_a) {
1542
+ switch (_a.label) {
1543
+ case 0:
1544
+ if (!(!this.loadedSuccessfullyOnce || forceReload)) return [3
1545
+ /*break*/
1546
+ , 2];
1547
+ return [4
1548
+ /*yield*/
1549
+ , this._loadFeatureFlags()];
1550
+
1551
+ case 1:
1552
+ _a.sent();
1553
+
1554
+ _a.label = 2;
1555
+
1556
+ case 2:
1557
+ return [2
1558
+ /*return*/
1559
+ ];
1560
+ }
1561
+ });
1562
+ });
1563
+ };
1564
+
1565
+ FeatureFlagsPoller.prototype._loadFeatureFlags = function () {
1566
+ return __awaiter(this, void 0, void 0, function () {
1567
+ var res, responseJson, err_1;
1568
+
1569
+ var _this = this;
1570
+
1571
+ return __generator(this, function (_a) {
1572
+ switch (_a.label) {
1573
+ case 0:
1574
+ if (this.poller) {
1575
+ clearTimeout(this.poller);
1576
+ this.poller = undefined;
1577
+ }
1578
+
1579
+ this.poller = setTimeout(function () {
1580
+ return _this._loadFeatureFlags();
1581
+ }, this.pollingInterval);
1582
+ _a.label = 1;
1583
+
1584
+ case 1:
1585
+ _a.trys.push([1, 4,, 5]);
1586
+
1587
+ return [4
1588
+ /*yield*/
1589
+ , this._requestFeatureFlagDefinitions()];
1590
+
1591
+ case 2:
1592
+ res = _a.sent();
1593
+
1594
+ if (res && res.statusCode === 401) {
1595
+ throw new ClientError("Your personalApiKey is invalid. Are you sure you're not using your Project API key? More information: https://posthog.com/docs/api/overview");
1596
+ }
1597
+
1598
+ return [4
1599
+ /*yield*/
1600
+ , res.body.json()];
1601
+
1602
+ case 3:
1603
+ responseJson = _a.sent();
1604
+
1605
+ if (!('flags' in responseJson)) {
1606
+ console.error("Invalid response when getting feature flags: ".concat(JSON.stringify(responseJson)));
1607
+ }
1608
+
1609
+ this.featureFlags = responseJson.flags || [];
1610
+ this.groupTypeMapping = responseJson.group_type_mapping || {};
1611
+ this.loadedSuccessfullyOnce = true;
1612
+ return [3
1613
+ /*break*/
1614
+ , 5];
1615
+
1616
+ case 4:
1617
+ err_1 = _a.sent(); // if an error that is not an instance of ClientError is thrown
1618
+ // we silently ignore the error when reloading feature flags
1619
+
1620
+ if (err_1 instanceof ClientError) {
1621
+ throw err_1;
1622
+ }
1623
+
1624
+ return [3
1625
+ /*break*/
1626
+ , 5];
1627
+
1628
+ case 5:
1629
+ return [2
1630
+ /*return*/
1631
+ ];
1632
+ }
1633
+ });
1634
+ });
1635
+ };
1636
+
1637
+ FeatureFlagsPoller.prototype._requestFeatureFlagDefinitions = function () {
1638
+ return __awaiter(this, void 0, void 0, function () {
1639
+ var url, headers, options, res, err_2;
1640
+ return __generator(this, function (_a) {
1641
+ switch (_a.label) {
1642
+ case 0:
1643
+ url = "".concat(this.host, "/api/feature_flag/local_evaluation?token=").concat(this.projectApiKey);
1644
+ headers = {
1645
+ 'Content-Type': 'application/json',
1646
+ Authorization: "Bearer ".concat(this.personalApiKey),
1647
+ 'user-agent': "posthog-node/".concat(version)
1648
+ };
1649
+ options = {
1650
+ method: 'GET',
1651
+ headers: headers
1652
+ };
1653
+
1654
+ if (this.timeout && typeof this.timeout === 'number') {
1655
+ options.bodyTimeout = this.timeout;
1656
+ }
1657
+
1658
+ _a.label = 1;
1659
+
1660
+ case 1:
1661
+ _a.trys.push([1, 3,, 4]);
1662
+
1663
+ return [4
1664
+ /*yield*/
1665
+ , request(url, options)];
1666
+
1667
+ case 2:
1668
+ res = _a.sent();
1669
+ return [3
1670
+ /*break*/
1671
+ , 4];
1672
+
1673
+ case 3:
1674
+ err_2 = _a.sent();
1675
+ throw new Error("Request failed with error: ".concat(err_2));
1676
+
1677
+ case 4:
1678
+ return [2
1679
+ /*return*/
1680
+ , res];
1681
+ }
1682
+ });
1683
+ });
1684
+ };
1685
+
1686
+ FeatureFlagsPoller.prototype.stopPoller = function () {
1687
+ clearTimeout(this.poller);
1688
+ };
1689
+
1690
+ return FeatureFlagsPoller;
1691
+ }(); // # This function takes a distinct_id and a feature flag key and returns a float between 0 and 1.
1692
+ // # Given the same distinct_id and key, it'll always return the same float. These floats are
1693
+ // # uniformly distributed between 0 and 1, so if we want to show this feature to 20% of traffic
1694
+ // # we can do _hash(key, distinct_id) < 0.2
1695
+
1696
+
1697
+ function _hash(key, distinctId, salt) {
1698
+ if (salt === void 0) {
1699
+ salt = '';
1700
+ }
1701
+
1702
+ var sha1Hash = createHash('sha1');
1703
+ sha1Hash.update("".concat(key, ".").concat(distinctId).concat(salt));
1704
+ return parseInt(sha1Hash.digest('hex').slice(0, 15), 16) / LONG_SCALE;
1705
+ }
1706
+
1707
+ function matchProperty(property, propertyValues) {
1708
+ var key = property.key;
1709
+ var value = property.value;
1710
+ var operator = property.operator || 'exact';
1711
+
1712
+ if (!(key in propertyValues)) {
1713
+ throw new InconclusiveMatchError("Property ".concat(key, " not found in propertyValues"));
1714
+ } else if (operator === 'is_not_set') {
1715
+ throw new InconclusiveMatchError("Operator is_not_set is not supported");
1716
+ }
1717
+
1718
+ var overrideValue = propertyValues[key];
1719
+
1720
+ switch (operator) {
1721
+ case 'exact':
1722
+ return Array.isArray(value) ? value.indexOf(overrideValue) !== -1 : value === overrideValue;
1723
+
1724
+ case 'is_not':
1725
+ return Array.isArray(value) ? value.indexOf(overrideValue) === -1 : value !== overrideValue;
1726
+
1727
+ case 'is_set':
1728
+ return key in propertyValues;
1729
+
1730
+ case 'icontains':
1731
+ return String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
1732
+
1733
+ case 'not_icontains':
1734
+ return !String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
1735
+
1736
+ case 'regex':
1737
+ return isValidRegex(String(value)) && String(overrideValue).match(String(value)) !== null;
1738
+
1739
+ case 'not_regex':
1740
+ return isValidRegex(String(value)) && String(overrideValue).match(String(value)) === null;
1741
+
1742
+ case 'gt':
1743
+ return typeof overrideValue == typeof value && overrideValue > value;
1744
+
1745
+ case 'gte':
1746
+ return typeof overrideValue == typeof value && overrideValue >= value;
1747
+
1748
+ case 'lt':
1749
+ return typeof overrideValue == typeof value && overrideValue < value;
1750
+
1751
+ case 'lte':
1752
+ return typeof overrideValue == typeof value && overrideValue <= value;
1753
+
1754
+ default:
1755
+ console.error("Unknown operator: ".concat(operator));
1756
+ return false;
1757
+ }
1758
+ }
1759
+
1760
+ function isValidRegex(regex) {
1761
+ try {
1762
+ new RegExp(regex);
1763
+ return true;
1764
+ } catch (err) {
1765
+ return false;
1766
+ }
1767
+ }
1768
+
1769
+ var THIRTY_SECONDS = 30 * 1000;
1770
+ var MAX_CACHE_SIZE = 50 * 1000;
1771
+
1153
1772
  var PostHog =
1154
1773
  /** @class */
1155
1774
  function (_super) {
@@ -1165,6 +1784,8 @@ function (_super) {
1165
1784
  options.captureMode = (options === null || options === void 0 ? void 0 : options.captureMode) || 'json';
1166
1785
  options.preloadFeatureFlags = false; // Don't preload as this makes no sense without a distinctId
1167
1786
 
1787
+ options.sendFeatureFlagEvent = false; // Let `posthog-node` handle this on its own, since we're dealing with multiple distinctIDs
1788
+
1168
1789
  _this = _super.call(this, apiKey, options) || this;
1169
1790
  _this._memoryStorage = new PostHogMemoryStorage();
1170
1791
  return _this;
@@ -1212,17 +1833,24 @@ function () {
1212
1833
  }
1213
1834
 
1214
1835
  this._sharedClient = new PostHog(apiKey, options);
1836
+
1837
+ if (options.personalApiKey) {
1838
+ this.featureFlagsPoller = new FeatureFlagsPoller({
1839
+ pollingInterval: typeof options.featureFlagsPollingInterval === 'number' ? options.featureFlagsPollingInterval : THIRTY_SECONDS,
1840
+ personalApiKey: options.personalApiKey,
1841
+ projectApiKey: apiKey,
1842
+ timeout: options.requestTimeout,
1843
+ host: this._sharedClient.host
1844
+ });
1845
+ }
1846
+
1847
+ this.distinctIdHasSentFlagCalls = {};
1848
+ this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE;
1215
1849
  }
1216
1850
 
1217
1851
  PostHogGlobal.prototype.reInit = function (distinctId) {
1218
- // Certain properties we want to persist
1219
- var propertiesToKeep = [PostHogPersistedProperty.Queue, PostHogPersistedProperty.OptedOut];
1220
-
1221
- for (var key in PostHogPersistedProperty) {
1222
- if (!propertiesToKeep.includes(key)) {
1223
- this._sharedClient.setPersistedProperty(PostHogPersistedProperty[key], null);
1224
- }
1225
- }
1852
+ // Certain properties we want to persist. Queue is persisted always by default.
1853
+ this._sharedClient.reset([PostHogPersistedProperty.OptedOut]);
1226
1854
 
1227
1855
  this._sharedClient.setPersistedProperty(PostHogPersistedProperty.DistinctId, distinctId);
1228
1856
  };
@@ -1239,14 +1867,15 @@ function () {
1239
1867
  var distinctId = _a.distinctId,
1240
1868
  event = _a.event,
1241
1869
  properties = _a.properties,
1242
- groups = _a.groups;
1870
+ groups = _a.groups,
1871
+ sendFeatureFlags = _a.sendFeatureFlags;
1243
1872
  this.reInit(distinctId);
1244
1873
 
1245
1874
  if (groups) {
1246
1875
  this._sharedClient.groups(groups);
1247
1876
  }
1248
1877
 
1249
- this._sharedClient.capture(event, properties);
1878
+ this._sharedClient.capture(event, properties, sendFeatureFlags || false);
1250
1879
  };
1251
1880
 
1252
1881
  PostHogGlobal.prototype.identify = function (_a) {
@@ -1263,33 +1892,95 @@ function () {
1263
1892
  this._sharedClient.alias(data.alias);
1264
1893
  };
1265
1894
 
1266
- PostHogGlobal.prototype.getFeatureFlag = function (key, distinctId, groups) {
1895
+ PostHogGlobal.prototype.getFeatureFlag = function (key, distinctId, options) {
1896
+ var _a;
1897
+
1267
1898
  return __awaiter(this, void 0, void 0, function () {
1268
- return __generator(this, function (_a) {
1269
- switch (_a.label) {
1899
+ var _b, groups, personProperties, groupProperties, _c, onlyEvaluateLocally, sendFeatureFlagEvents, response, flagWasLocallyEvaluated, featureFlagReportedKey;
1900
+
1901
+ return __generator(this, function (_d) {
1902
+ switch (_d.label) {
1270
1903
  case 0:
1904
+ _b = options || {}, groups = _b.groups, personProperties = _b.personProperties, groupProperties = _b.groupProperties;
1905
+ _c = options || {}, onlyEvaluateLocally = _c.onlyEvaluateLocally, sendFeatureFlagEvents = _c.sendFeatureFlagEvents; // set defaults
1906
+
1907
+ if (onlyEvaluateLocally == undefined) {
1908
+ onlyEvaluateLocally = false;
1909
+ }
1910
+
1911
+ if (sendFeatureFlagEvents == undefined) {
1912
+ sendFeatureFlagEvents = true;
1913
+ }
1914
+
1915
+ return [4
1916
+ /*yield*/
1917
+ , (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties)];
1918
+
1919
+ case 1:
1920
+ response = _d.sent();
1921
+ flagWasLocallyEvaluated = response !== undefined;
1922
+ if (!(!flagWasLocallyEvaluated && !onlyEvaluateLocally)) return [3
1923
+ /*break*/
1924
+ , 3];
1271
1925
  this.reInit(distinctId);
1272
1926
 
1273
- if (groups) {
1927
+ if (groups != undefined) {
1274
1928
  this._sharedClient.groups(groups);
1275
1929
  }
1276
1930
 
1931
+ if (personProperties) {
1932
+ this._sharedClient.personProperties(personProperties);
1933
+ }
1934
+
1935
+ if (groupProperties) {
1936
+ this._sharedClient.groupProperties(groupProperties);
1937
+ }
1938
+
1277
1939
  return [4
1278
1940
  /*yield*/
1279
- , this._sharedClient.reloadFeatureFlagsAsync()];
1941
+ , this._sharedClient.reloadFeatureFlagsAsync(false)];
1280
1942
 
1281
- case 1:
1282
- _a.sent();
1943
+ case 2:
1944
+ _d.sent();
1945
+
1946
+ response = this._sharedClient.getFeatureFlag(key);
1947
+ _d.label = 3;
1948
+
1949
+ case 3:
1950
+ featureFlagReportedKey = "".concat(key, "_").concat(response);
1951
+
1952
+ if (sendFeatureFlagEvents && (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey))) {
1953
+ if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) {
1954
+ this.distinctIdHasSentFlagCalls = {};
1955
+ }
1956
+
1957
+ if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) {
1958
+ this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
1959
+ } else {
1960
+ this.distinctIdHasSentFlagCalls[distinctId] = [featureFlagReportedKey];
1961
+ }
1962
+
1963
+ this.capture({
1964
+ distinctId: distinctId,
1965
+ event: '$feature_flag_called',
1966
+ properties: {
1967
+ $feature_flag: key,
1968
+ $feature_flag_response: response,
1969
+ locally_evaluated: flagWasLocallyEvaluated
1970
+ },
1971
+ groups: groups
1972
+ });
1973
+ }
1283
1974
 
1284
1975
  return [2
1285
1976
  /*return*/
1286
- , this._sharedClient.getFeatureFlag(key)];
1977
+ , response];
1287
1978
  }
1288
1979
  });
1289
1980
  });
1290
1981
  };
1291
1982
 
1292
- PostHogGlobal.prototype.isFeatureEnabled = function (key, distinctId, defaultResult, groups) {
1983
+ PostHogGlobal.prototype.isFeatureEnabled = function (key, distinctId, options) {
1293
1984
  return __awaiter(this, void 0, void 0, function () {
1294
1985
  var feat;
1295
1986
  return __generator(this, function (_a) {
@@ -1297,13 +1988,88 @@ function () {
1297
1988
  case 0:
1298
1989
  return [4
1299
1990
  /*yield*/
1300
- , this.getFeatureFlag(key, distinctId, groups)];
1991
+ , this.getFeatureFlag(key, distinctId, options)];
1301
1992
 
1302
1993
  case 1:
1303
1994
  feat = _a.sent();
1995
+
1996
+ if (feat === undefined) {
1997
+ return [2
1998
+ /*return*/
1999
+ , undefined];
2000
+ }
2001
+
2002
+ return [2
2003
+ /*return*/
2004
+ , !!feat || false];
2005
+ }
2006
+ });
2007
+ });
2008
+ };
2009
+
2010
+ PostHogGlobal.prototype.getAllFlags = function (distinctId, options) {
2011
+ var _a;
2012
+
2013
+ return __awaiter(this, void 0, void 0, function () {
2014
+ var _b, groups, personProperties, groupProperties, onlyEvaluateLocally, localEvaluationResult, response, fallbackToDecide, remoteEvaluationResult;
2015
+
2016
+ return __generator(this, function (_c) {
2017
+ switch (_c.label) {
2018
+ case 0:
2019
+ _b = options || {}, groups = _b.groups, personProperties = _b.personProperties, groupProperties = _b.groupProperties;
2020
+ onlyEvaluateLocally = (options || {}).onlyEvaluateLocally; // set defaults
2021
+
2022
+ if (onlyEvaluateLocally == undefined) {
2023
+ onlyEvaluateLocally = false;
2024
+ }
2025
+
2026
+ return [4
2027
+ /*yield*/
2028
+ , (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.getAllFlags(distinctId, groups, personProperties, groupProperties)];
2029
+
2030
+ case 1:
2031
+ localEvaluationResult = _c.sent();
2032
+ response = {};
2033
+ fallbackToDecide = true;
2034
+
2035
+ if (localEvaluationResult) {
2036
+ response = localEvaluationResult.response;
2037
+ fallbackToDecide = localEvaluationResult.fallbackToDecide;
2038
+ }
2039
+
2040
+ if (!(fallbackToDecide && !onlyEvaluateLocally)) return [3
2041
+ /*break*/
2042
+ , 3];
2043
+ this.reInit(distinctId);
2044
+
2045
+ if (groups) {
2046
+ this._sharedClient.groups(groups);
2047
+ }
2048
+
2049
+ if (personProperties) {
2050
+ this._sharedClient.personProperties(personProperties);
2051
+ }
2052
+
2053
+ if (groupProperties) {
2054
+ this._sharedClient.groupProperties(groupProperties);
2055
+ }
2056
+
2057
+ return [4
2058
+ /*yield*/
2059
+ , this._sharedClient.reloadFeatureFlagsAsync(false)];
2060
+
2061
+ case 2:
2062
+ _c.sent();
2063
+
2064
+ remoteEvaluationResult = this._sharedClient.getFeatureFlags();
1304
2065
  return [2
1305
2066
  /*return*/
1306
- , !!feat || defaultResult || false];
2067
+ , __assign(__assign({}, response), remoteEvaluationResult)];
2068
+
2069
+ case 3:
2070
+ return [2
2071
+ /*return*/
2072
+ , response];
1307
2073
  }
1308
2074
  });
1309
2075
  });
@@ -1318,15 +2084,46 @@ function () {
1318
2084
  };
1319
2085
 
1320
2086
  PostHogGlobal.prototype.reloadFeatureFlags = function () {
1321
- throw new Error('Method not implemented.');
2087
+ var _a;
2088
+
2089
+ return __awaiter(this, void 0, void 0, function () {
2090
+ return __generator(this, function (_b) {
2091
+ switch (_b.label) {
2092
+ case 0:
2093
+ return [4
2094
+ /*yield*/
2095
+ , (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.loadFeatureFlags(true)];
2096
+
2097
+ case 1:
2098
+ _b.sent();
2099
+
2100
+ return [2
2101
+ /*return*/
2102
+ ];
2103
+ }
2104
+ });
2105
+ });
2106
+ };
2107
+
2108
+ PostHogGlobal.prototype.flush = function () {
2109
+ this._sharedClient.flush();
1322
2110
  };
1323
2111
 
1324
2112
  PostHogGlobal.prototype.shutdown = function () {
1325
- void this._sharedClient.shutdownAsync();
2113
+ void this.shutdownAsync();
1326
2114
  };
1327
2115
 
1328
2116
  PostHogGlobal.prototype.shutdownAsync = function () {
1329
- return this._sharedClient.shutdownAsync();
2117
+ var _a;
2118
+
2119
+ return __awaiter(this, void 0, void 0, function () {
2120
+ return __generator(this, function (_b) {
2121
+ (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.stopPoller();
2122
+ return [2
2123
+ /*return*/
2124
+ , this._sharedClient.shutdownAsync()];
2125
+ });
2126
+ });
1330
2127
  };
1331
2128
 
1332
2129
  PostHogGlobal.prototype.debug = function (enabled) {