posthog-node 2.2.2 → 2.3.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/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 2.3.0 - 2022-1-26
2
+
3
+ 1. uses v3 decide endpoint
4
+ 2. JSON payloads will be returned with feature flags
5
+ 3. Feature flags will gracefully fail and optimistically save evaluated flags if server is down
6
+
7
+ # 2.2.3 - 2022-12-01
8
+ 1. Fix issues with timeouts for local evaluation requests
1
9
  # 2.2.2 - 2022-11-28
2
10
  1. Fix issues with timeout
3
11
 
package/lib/index.cjs.js CHANGED
@@ -163,7 +163,7 @@ function __spreadArray(to, from, pack) {
163
163
  return to.concat(ar || Array.prototype.slice.call(from));
164
164
  }
165
165
 
166
- var version = "2.2.2";
166
+ var version = "2.3.0";
167
167
 
168
168
  var PostHogPersistedProperty;
169
169
  (function (PostHogPersistedProperty) {
@@ -171,6 +171,7 @@ var PostHogPersistedProperty;
171
171
  PostHogPersistedProperty["DistinctId"] = "distinct_id";
172
172
  PostHogPersistedProperty["Props"] = "props";
173
173
  PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
174
+ PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
174
175
  PostHogPersistedProperty["OverrideFeatureFlags"] = "override_feature_flags";
175
176
  PostHogPersistedProperty["Queue"] = "queue";
176
177
  PostHogPersistedProperty["OptedOut"] = "opted_out";
@@ -779,6 +780,7 @@ var PostHogCore = /** @class */ (function () {
779
780
  return ((res[key] = ((_b = (_a = options.bootstrap) === null || _a === void 0 ? void 0 : _a.featureFlags) === null || _b === void 0 ? void 0 : _b[key]) || false), res);
780
781
  }, {});
781
782
  this.setKnownFeatureFlags(activeFlags);
783
+ (options === null || options === void 0 ? void 0 : options.bootstrap.featureFlagPayloads) && this.setKnownFeatureFlagPayloads(options === null || options === void 0 ? void 0 : options.bootstrap.featureFlagPayloads);
782
784
  }
783
785
  };
784
786
  Object.defineProperty(PostHogCore.prototype, "props", {
@@ -958,11 +960,10 @@ var PostHogCore = /** @class */ (function () {
958
960
  return this;
959
961
  };
960
962
  PostHogCore.prototype.groupIdentify = function (groupType, groupKey, groupProperties) {
961
- var payload = {
963
+ var payload = this.buildPayload({
962
964
  event: '$groupidentify',
963
- distinctId: "$".concat(groupType, "_").concat(groupKey),
964
965
  properties: __assign({ $group_type: groupType, $group_key: groupKey, $group_set: groupProperties || {} }, this.getCommonEventProperties()),
965
- };
966
+ });
966
967
  this.enqueue('capture', payload);
967
968
  return this;
968
969
  };
@@ -1003,7 +1004,7 @@ var PostHogCore = /** @class */ (function () {
1003
1004
  var url, distinctId, groups, personProperties, groupProperties, fetchOptions;
1004
1005
  var _this = this;
1005
1006
  return __generator(this, function (_a) {
1006
- url = "".concat(this.host, "/decide/?v=2");
1007
+ url = "".concat(this.host, "/decide/?v=3");
1007
1008
  distinctId = this.getDistinctId();
1008
1009
  groups = this.props.$groups || {};
1009
1010
  personProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
@@ -1024,7 +1025,17 @@ var PostHogCore = /** @class */ (function () {
1024
1025
  .then(function (r) { return r.json(); })
1025
1026
  .then(function (res) {
1026
1027
  if (res.featureFlags) {
1027
- _this.setKnownFeatureFlags(res.featureFlags);
1028
+ var newFeatureFlags = res.featureFlags;
1029
+ var newFeatureFlagPayloads = res.featureFlagPayloads;
1030
+ if (res.errorsWhileComputingFlags) {
1031
+ // if not all flags were computed, we upsert flags instead of replacing them
1032
+ var currentFlags = _this.getPersistedProperty(PostHogPersistedProperty.FeatureFlags);
1033
+ var currentFlagPayloads = _this.getPersistedProperty(PostHogPersistedProperty.FeatureFlagPayloads);
1034
+ newFeatureFlags = __assign(__assign({}, currentFlags), res.featureFlags);
1035
+ newFeatureFlagPayloads = __assign(__assign({}, currentFlagPayloads), res.featureFlagPayloads);
1036
+ }
1037
+ _this.setKnownFeatureFlags(newFeatureFlags);
1038
+ _this.setKnownFeatureFlagPayloads(newFeatureFlagPayloads);
1028
1039
  }
1029
1040
  return res;
1030
1041
  })
@@ -1039,6 +1050,9 @@ var PostHogCore = /** @class */ (function () {
1039
1050
  this.setPersistedProperty(PostHogPersistedProperty.FeatureFlags, featureFlags);
1040
1051
  this._events.emit('featureflags', featureFlags);
1041
1052
  };
1053
+ PostHogCore.prototype.setKnownFeatureFlagPayloads = function (featureFlagPayloads) {
1054
+ this.setPersistedProperty(PostHogPersistedProperty.FeatureFlagPayloads, featureFlagPayloads);
1055
+ };
1042
1056
  PostHogCore.prototype.getFeatureFlag = function (key) {
1043
1057
  var featureFlags = this.getFeatureFlags();
1044
1058
  if (!featureFlags) {
@@ -1046,8 +1060,9 @@ var PostHogCore = /** @class */ (function () {
1046
1060
  return undefined;
1047
1061
  }
1048
1062
  var response = featureFlags[key];
1063
+ // `/decide` v3 returns all flags
1049
1064
  if (response === undefined) {
1050
- // `/decide` returns nothing for flags which are false.
1065
+ // For cases where the flag is unknown, return false
1051
1066
  response = false;
1052
1067
  }
1053
1068
  if (this.sendFeatureFlagEvent && !this.flagCallReported[key]) {
@@ -1060,6 +1075,37 @@ var PostHogCore = /** @class */ (function () {
1060
1075
  // If we have flags we either return the value (true or string) or false
1061
1076
  return response;
1062
1077
  };
1078
+ PostHogCore.prototype.getFeatureFlagPayload = function (key) {
1079
+ var payloads = this.getFeatureFlagPayloads();
1080
+ if (!payloads) {
1081
+ return undefined;
1082
+ }
1083
+ var response = payloads[key];
1084
+ // Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
1085
+ if (response === undefined) {
1086
+ return null;
1087
+ }
1088
+ return this._parsePayload(response);
1089
+ };
1090
+ PostHogCore.prototype.getFeatureFlagPayloads = function () {
1091
+ var _this = this;
1092
+ var payloads = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlagPayloads);
1093
+ if (payloads) {
1094
+ return Object.fromEntries(Object.entries(payloads).map(function (_a) {
1095
+ var k = _a[0], v = _a[1];
1096
+ return [k, _this._parsePayload(v)];
1097
+ }));
1098
+ }
1099
+ return payloads;
1100
+ };
1101
+ PostHogCore.prototype._parsePayload = function (response) {
1102
+ try {
1103
+ return JSON.parse(response);
1104
+ }
1105
+ catch (_a) {
1106
+ return response;
1107
+ }
1108
+ };
1063
1109
  PostHogCore.prototype.getFeatureFlags = function () {
1064
1110
  var flags = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlags);
1065
1111
  var overriddenFlags = this.getPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags);
@@ -1077,6 +1123,14 @@ var PostHogCore = /** @class */ (function () {
1077
1123
  }
1078
1124
  return flags;
1079
1125
  };
1126
+ PostHogCore.prototype.getFeatureFlagsAndPayloads = function () {
1127
+ var flags = this.getFeatureFlags();
1128
+ var payloads = this.getFeatureFlagPayloads();
1129
+ return {
1130
+ flags: flags,
1131
+ payloads: payloads,
1132
+ };
1133
+ };
1080
1134
  PostHogCore.prototype.isFeatureEnabled = function (key) {
1081
1135
  var response = this.getFeatureFlag(key);
1082
1136
  if (response === undefined) {
@@ -1365,6 +1419,7 @@ function () {
1365
1419
  this.pollingInterval = pollingInterval;
1366
1420
  this.personalApiKey = personalApiKey;
1367
1421
  this.featureFlags = [];
1422
+ this.featureFlagsByKey = {};
1368
1423
  this.groupTypeMapping = {};
1369
1424
  this.loadedSuccessfullyOnce = false;
1370
1425
  this.timeout = timeout;
@@ -1423,10 +1478,9 @@ function () {
1423
1478
  if (featureFlag !== undefined) {
1424
1479
  try {
1425
1480
  response = this.computeFlagLocally(featureFlag, distinctId, groups, personProperties, groupProperties);
1426
- console.debug("Successfully computed flag locally: ".concat(key, " -> ").concat(response));
1427
1481
  } catch (e) {
1428
1482
  if (e instanceof InconclusiveMatchError) {
1429
- console.debug("Can't compute flag locally: ".concat(key, ": ").concat(e));
1483
+ console.error("InconclusiveMatchError when computing flag locally: ".concat(key, ": ").concat(e));
1430
1484
  } else if (e instanceof Error) {
1431
1485
  console.error("Error computing flag locally: ".concat(key, ": ").concat(e));
1432
1486
  }
@@ -1441,7 +1495,51 @@ function () {
1441
1495
  });
1442
1496
  };
1443
1497
 
1444
- FeatureFlagsPoller.prototype.getAllFlags = function (distinctId, groups, personProperties, groupProperties) {
1498
+ FeatureFlagsPoller.prototype.computeFeatureFlagPayloadLocally = function (key, matchValue) {
1499
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1500
+
1501
+ return __awaiter(this, void 0, void 0, function () {
1502
+ var response;
1503
+ return __generator(this, function (_j) {
1504
+ switch (_j.label) {
1505
+ case 0:
1506
+ return [4
1507
+ /*yield*/
1508
+ , this.loadFeatureFlags()];
1509
+
1510
+ case 1:
1511
+ _j.sent();
1512
+
1513
+ response = undefined;
1514
+
1515
+ if (!this.loadedSuccessfullyOnce) {
1516
+ return [2
1517
+ /*return*/
1518
+ , undefined];
1519
+ }
1520
+
1521
+ if (typeof matchValue == 'boolean') {
1522
+ response = (_d = (_c = (_b = (_a = this.featureFlagsByKey) === null || _a === void 0 ? void 0 : _a[key]) === null || _b === void 0 ? void 0 : _b.filters) === null || _c === void 0 ? void 0 : _c.payloads) === null || _d === void 0 ? void 0 : _d[matchValue.toString()];
1523
+ } else if (typeof matchValue == 'string') {
1524
+ response = (_h = (_g = (_f = (_e = this.featureFlagsByKey) === null || _e === void 0 ? void 0 : _e[key]) === null || _f === void 0 ? void 0 : _f.filters) === null || _g === void 0 ? void 0 : _g.payloads) === null || _h === void 0 ? void 0 : _h[matchValue];
1525
+ } // Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
1526
+
1527
+
1528
+ if (response === undefined) {
1529
+ return [2
1530
+ /*return*/
1531
+ , null];
1532
+ }
1533
+
1534
+ return [2
1535
+ /*return*/
1536
+ , response];
1537
+ }
1538
+ });
1539
+ });
1540
+ };
1541
+
1542
+ FeatureFlagsPoller.prototype.getAllFlagsAndPayloads = function (distinctId, groups, personProperties, groupProperties) {
1445
1543
  if (groups === void 0) {
1446
1544
  groups = {};
1447
1545
  }
@@ -1455,7 +1553,7 @@ function () {
1455
1553
  }
1456
1554
 
1457
1555
  return __awaiter(this, void 0, void 0, function () {
1458
- var response, fallbackToDecide;
1556
+ var response, payloads, fallbackToDecide;
1459
1557
 
1460
1558
  var _this = this;
1461
1559
 
@@ -1470,22 +1568,58 @@ function () {
1470
1568
  _a.sent();
1471
1569
 
1472
1570
  response = {};
1571
+ payloads = {};
1473
1572
  fallbackToDecide = this.featureFlags.length == 0;
1474
1573
  this.featureFlags.map(function (flag) {
1475
- try {
1476
- response[flag.key] = _this.computeFlagLocally(flag, distinctId, groups, personProperties, groupProperties);
1477
- } catch (e) {
1478
- if (e instanceof InconclusiveMatchError) ; else if (e instanceof Error) {
1479
- console.error("Error computing flag locally: ".concat(flag.key, ": ").concat(e));
1480
- }
1481
-
1482
- fallbackToDecide = true;
1483
- }
1574
+ return __awaiter(_this, void 0, void 0, function () {
1575
+ var matchValue, matchPayload, e_1;
1576
+ return __generator(this, function (_a) {
1577
+ switch (_a.label) {
1578
+ case 0:
1579
+ _a.trys.push([0, 2,, 3]);
1580
+
1581
+ matchValue = this.computeFlagLocally(flag, distinctId, groups, personProperties, groupProperties);
1582
+ response[flag.key] = matchValue;
1583
+ return [4
1584
+ /*yield*/
1585
+ , this.computeFeatureFlagPayloadLocally(flag.key, matchValue)];
1586
+
1587
+ case 1:
1588
+ matchPayload = _a.sent();
1589
+
1590
+ if (matchPayload) {
1591
+ payloads[flag.key] = matchPayload;
1592
+ }
1593
+
1594
+ return [3
1595
+ /*break*/
1596
+ , 3];
1597
+
1598
+ case 2:
1599
+ e_1 = _a.sent();
1600
+
1601
+ if (e_1 instanceof InconclusiveMatchError) ; else if (e_1 instanceof Error) {
1602
+ console.error("Error computing flag locally: ".concat(flag.key, ": ").concat(e_1));
1603
+ }
1604
+
1605
+ fallbackToDecide = true;
1606
+ return [3
1607
+ /*break*/
1608
+ , 3];
1609
+
1610
+ case 3:
1611
+ return [2
1612
+ /*return*/
1613
+ ];
1614
+ }
1615
+ });
1616
+ });
1484
1617
  });
1485
1618
  return [2
1486
1619
  /*return*/
1487
1620
  , {
1488
1621
  response: response,
1622
+ payloads: payloads,
1489
1623
  fallbackToDecide: fallbackToDecide
1490
1624
  }];
1491
1625
  }
@@ -1726,6 +1860,14 @@ function () {
1726
1860
  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");
1727
1861
  }
1728
1862
 
1863
+ if (res && res.status !== 200) {
1864
+ // something else went wrong, or the server is down.
1865
+ // In this case, don't override existing flags
1866
+ return [2
1867
+ /*return*/
1868
+ ];
1869
+ }
1870
+
1729
1871
  return [4
1730
1872
  /*yield*/
1731
1873
  , res.json()];
@@ -1738,6 +1880,9 @@ function () {
1738
1880
  }
1739
1881
 
1740
1882
  this.featureFlags = responseJson.flags || [];
1883
+ this.featureFlagsByKey = this.featureFlags.reduce(function (acc, curr) {
1884
+ return acc[curr.key] = curr, acc;
1885
+ }, {});
1741
1886
  this.groupTypeMapping = responseJson.group_type_mapping || {};
1742
1887
  this.loadedSuccessfullyOnce = true;
1743
1888
  return [3
@@ -2009,7 +2154,7 @@ function () {
2009
2154
  pollingInterval: typeof options.featureFlagsPollingInterval === 'number' ? options.featureFlagsPollingInterval : THIRTY_SECONDS,
2010
2155
  personalApiKey: options.personalApiKey,
2011
2156
  projectApiKey: apiKey,
2012
- timeout: (_a = options.requestTimeout) !== null && _a !== void 0 ? _a : 10,
2157
+ timeout: (_a = options.requestTimeout) !== null && _a !== void 0 ? _a : 10000,
2013
2158
  host: this._sharedClient.host,
2014
2159
  fetch: options.fetch
2015
2160
  });
@@ -2151,6 +2296,101 @@ function () {
2151
2296
  });
2152
2297
  };
2153
2298
 
2299
+ PostHog.prototype.getFeatureFlagPayload = function (key, distinctId, matchValue, options) {
2300
+ var _a;
2301
+
2302
+ return __awaiter(this, void 0, void 0, function () {
2303
+ var _b, groups, personProperties, groupProperties, _c, onlyEvaluateLocally, response, payloadWasLocallyEvaluated;
2304
+
2305
+ return __generator(this, function (_d) {
2306
+ switch (_d.label) {
2307
+ case 0:
2308
+ _b = options || {}, groups = _b.groups, personProperties = _b.personProperties, groupProperties = _b.groupProperties;
2309
+ _c = options || {}, onlyEvaluateLocally = _c.onlyEvaluateLocally, _c.sendFeatureFlagEvents;
2310
+ response = undefined;
2311
+ if (!!matchValue) return [3
2312
+ /*break*/
2313
+ , 2];
2314
+ return [4
2315
+ /*yield*/
2316
+ , this.getFeatureFlag(key, distinctId, __assign(__assign({}, options), {
2317
+ onlyEvaluateLocally: true
2318
+ }))];
2319
+
2320
+ case 1:
2321
+ matchValue = _d.sent();
2322
+ _d.label = 2;
2323
+
2324
+ case 2:
2325
+ if (!matchValue) return [3
2326
+ /*break*/
2327
+ , 4];
2328
+ return [4
2329
+ /*yield*/
2330
+ , (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.computeFeatureFlagPayloadLocally(key, matchValue)];
2331
+
2332
+ case 3:
2333
+ response = _d.sent();
2334
+ _d.label = 4;
2335
+
2336
+ case 4:
2337
+ // set defaults
2338
+ if (onlyEvaluateLocally == undefined) {
2339
+ onlyEvaluateLocally = false;
2340
+ }
2341
+
2342
+
2343
+ if (onlyEvaluateLocally == undefined) {
2344
+ onlyEvaluateLocally = false;
2345
+ }
2346
+
2347
+ payloadWasLocallyEvaluated = response !== undefined;
2348
+ if (!(!payloadWasLocallyEvaluated && !onlyEvaluateLocally)) return [3
2349
+ /*break*/
2350
+ , 6];
2351
+ this.reInit(distinctId);
2352
+
2353
+ if (groups != undefined) {
2354
+ this._sharedClient.groups(groups);
2355
+ }
2356
+
2357
+ if (personProperties) {
2358
+ this._sharedClient.personProperties(personProperties);
2359
+ }
2360
+
2361
+ if (groupProperties) {
2362
+ this._sharedClient.groupProperties(groupProperties);
2363
+ }
2364
+
2365
+ return [4
2366
+ /*yield*/
2367
+ , this._sharedClient.reloadFeatureFlagsAsync(false)];
2368
+
2369
+ case 5:
2370
+ _d.sent();
2371
+
2372
+ response = this._sharedClient.getFeatureFlagPayload(key);
2373
+ _d.label = 6;
2374
+
2375
+ case 6:
2376
+ try {
2377
+ return [2
2378
+ /*return*/
2379
+ , JSON.parse(response)];
2380
+ } catch (_e) {
2381
+ return [2
2382
+ /*return*/
2383
+ , response];
2384
+ }
2385
+
2386
+ return [2
2387
+ /*return*/
2388
+ ];
2389
+ }
2390
+ });
2391
+ });
2392
+ };
2393
+
2154
2394
  PostHog.prototype.isFeatureEnabled = function (key, distinctId, options) {
2155
2395
  return __awaiter(this, void 0, void 0, function () {
2156
2396
  var feat;
@@ -2179,10 +2419,30 @@ function () {
2179
2419
  };
2180
2420
 
2181
2421
  PostHog.prototype.getAllFlags = function (distinctId, options) {
2422
+ return __awaiter(this, void 0, void 0, function () {
2423
+ var response;
2424
+ return __generator(this, function (_a) {
2425
+ switch (_a.label) {
2426
+ case 0:
2427
+ return [4
2428
+ /*yield*/
2429
+ , this.getAllFlagsAndPayloads(distinctId, options)];
2430
+
2431
+ case 1:
2432
+ response = _a.sent();
2433
+ return [2
2434
+ /*return*/
2435
+ , response.featureFlags];
2436
+ }
2437
+ });
2438
+ });
2439
+ };
2440
+
2441
+ PostHog.prototype.getAllFlagsAndPayloads = function (distinctId, options) {
2182
2442
  var _a;
2183
2443
 
2184
2444
  return __awaiter(this, void 0, void 0, function () {
2185
- var _b, groups, personProperties, groupProperties, onlyEvaluateLocally, localEvaluationResult, response, fallbackToDecide, remoteEvaluationResult;
2445
+ var _b, groups, personProperties, groupProperties, onlyEvaluateLocally, localEvaluationResult, featureFlags, featureFlagPayloads, fallbackToDecide, remoteEvaluationResult;
2186
2446
 
2187
2447
  return __generator(this, function (_c) {
2188
2448
  switch (_c.label) {
@@ -2196,15 +2456,17 @@ function () {
2196
2456
 
2197
2457
  return [4
2198
2458
  /*yield*/
2199
- , (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.getAllFlags(distinctId, groups, personProperties, groupProperties)];
2459
+ , (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.getAllFlagsAndPayloads(distinctId, groups, personProperties, groupProperties)];
2200
2460
 
2201
2461
  case 1:
2202
2462
  localEvaluationResult = _c.sent();
2203
- response = {};
2463
+ featureFlags = {};
2464
+ featureFlagPayloads = {};
2204
2465
  fallbackToDecide = true;
2205
2466
 
2206
2467
  if (localEvaluationResult) {
2207
- response = localEvaluationResult.response;
2468
+ featureFlags = localEvaluationResult.response;
2469
+ featureFlagPayloads = localEvaluationResult.payloads;
2208
2470
  fallbackToDecide = localEvaluationResult.fallbackToDecide;
2209
2471
  }
2210
2472
 
@@ -2232,15 +2494,18 @@ function () {
2232
2494
  case 2:
2233
2495
  _c.sent();
2234
2496
 
2235
- remoteEvaluationResult = this._sharedClient.getFeatureFlags();
2236
- return [2
2237
- /*return*/
2238
- , __assign(__assign({}, response), remoteEvaluationResult)];
2497
+ remoteEvaluationResult = this._sharedClient.getFeatureFlagsAndPayloads();
2498
+ featureFlags = __assign(__assign({}, featureFlags), remoteEvaluationResult.flags || {});
2499
+ featureFlagPayloads = __assign(__assign({}, featureFlagPayloads), remoteEvaluationResult.payloads || {});
2500
+ _c.label = 3;
2239
2501
 
2240
2502
  case 3:
2241
2503
  return [2
2242
2504
  /*return*/
2243
- , response];
2505
+ , {
2506
+ featureFlags: featureFlags,
2507
+ featureFlagPayloads: featureFlagPayloads
2508
+ }];
2244
2509
  }
2245
2510
  });
2246
2511
  });
@@ -2250,6 +2515,7 @@ function () {
2250
2515
  var groupType = _a.groupType,
2251
2516
  groupKey = _a.groupKey,
2252
2517
  properties = _a.properties;
2518
+ this.reInit("$".concat(groupType, "_").concat(groupKey));
2253
2519
 
2254
2520
  this._sharedClient.groupIdentify(groupType, groupKey, properties);
2255
2521
  };