posthog-node 4.2.0 → 4.2.2

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,6 +1,6 @@
1
1
  import { createHash } from 'rusha';
2
2
 
3
- var version = "4.2.0";
3
+ var version = "4.2.2";
4
4
 
5
5
  var PostHogPersistedProperty;
6
6
  (function (PostHogPersistedProperty) {
@@ -18,6 +18,7 @@ var PostHogPersistedProperty;
18
18
  PostHogPersistedProperty["GroupProperties"] = "group_properties";
19
19
  PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
20
20
  PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
21
+ PostHogPersistedProperty["SessionReplay"] = "session_replay";
21
22
  })(PostHogPersistedProperty || (PostHogPersistedProperty = {}));
22
23
 
23
24
  function assert(truthyValue, message) {
@@ -962,7 +963,7 @@ class PostHogCoreStateless {
962
963
  this.maxBatchSize = Math.max(this.flushAt, options?.maxBatchSize ?? 100);
963
964
  this.maxQueueSize = Math.max(this.flushAt, options?.maxQueueSize ?? 1000);
964
965
  this.flushInterval = options?.flushInterval ?? 10000;
965
- this.captureMode = options?.captureMode || 'form';
966
+ this.captureMode = options?.captureMode || 'json';
966
967
  // If enable is explicitly set to false we override the optout
967
968
  this.defaultOptIn = options?.defaultOptIn ?? true;
968
969
  this._retryOptions = {
@@ -979,11 +980,14 @@ class PostHogCoreStateless {
979
980
  this._initPromise = Promise.resolve();
980
981
  this._isInitialized = true;
981
982
  }
983
+ logMsgIfDebug(fn) {
984
+ if (this.isDebug) {
985
+ fn();
986
+ }
987
+ }
982
988
  wrap(fn) {
983
989
  if (this.disabled) {
984
- if (this.isDebug) {
985
- console.warn('[PostHog] The client is disabled');
986
- }
990
+ this.logMsgIfDebug(() => console.warn('[PostHog] The client is disabled'));
987
991
  return;
988
992
  }
989
993
  if (this._isInitialized) {
@@ -1027,6 +1031,9 @@ class PostHogCoreStateless {
1027
1031
  get isDebug() {
1028
1032
  return !!this.removeDebugCallback;
1029
1033
  }
1034
+ get isDisabled() {
1035
+ return this.disabled;
1036
+ }
1030
1037
  buildPayload(payload) {
1031
1038
  return {
1032
1039
  distinct_id: payload.distinct_id,
@@ -1223,7 +1230,7 @@ class PostHogCoreStateless {
1223
1230
  const queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
1224
1231
  if (queue.length >= this.maxQueueSize) {
1225
1232
  queue.shift();
1226
- console.info('Queue is full, the oldest event is dropped.');
1233
+ this.logMsgIfDebug(() => console.info('Queue is full, the oldest event is dropped.'));
1227
1234
  }
1228
1235
  queue.push({ message });
1229
1236
  this.setPersistedProperty(PostHogPersistedProperty.Queue, queue);
@@ -1355,33 +1362,45 @@ class PostHogCoreStateless {
1355
1362
  }, { ...this._retryOptions, ...retryOptions });
1356
1363
  }
1357
1364
  async shutdown(shutdownTimeoutMs = 30000) {
1365
+ // A little tricky - we want to have a max shutdown time and enforce it, even if that means we have some
1366
+ // dangling promises. We'll keep track of the timeout and resolve/reject based on that.
1358
1367
  await this._initPromise;
1368
+ let hasTimedOut = false;
1359
1369
  this.clearFlushTimer();
1360
- try {
1361
- await Promise.all(Object.values(this.pendingPromises));
1362
- const startTimeWithDelay = Date.now() + shutdownTimeoutMs;
1363
- while (true) {
1364
- const queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
1365
- if (queue.length === 0) {
1366
- break;
1367
- }
1368
- // flush again to make sure we send all events, some of which might've been added
1369
- // while we were waiting for the pending promises to resolve
1370
- // For example, see sendFeatureFlags in posthog-node/src/posthog-node.ts::capture
1371
- await this.flush();
1372
- // If we've been waiting for more than the shutdownTimeoutMs, stop it
1373
- const now = Date.now();
1374
- if (startTimeWithDelay < now) {
1375
- break;
1370
+ const doShutdown = async () => {
1371
+ try {
1372
+ await Promise.all(Object.values(this.pendingPromises));
1373
+ while (true) {
1374
+ const queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
1375
+ if (queue.length === 0) {
1376
+ break;
1377
+ }
1378
+ // flush again to make sure we send all events, some of which might've been added
1379
+ // while we were waiting for the pending promises to resolve
1380
+ // For example, see sendFeatureFlags in posthog-node/src/posthog-node.ts::capture
1381
+ await this.flush();
1382
+ if (hasTimedOut) {
1383
+ break;
1384
+ }
1376
1385
  }
1377
1386
  }
1378
- }
1379
- catch (e) {
1380
- if (!isPostHogFetchError(e)) {
1381
- throw e;
1387
+ catch (e) {
1388
+ if (!isPostHogFetchError(e)) {
1389
+ throw e;
1390
+ }
1391
+ this.logMsgIfDebug(() => console.error('Error while shutting down PostHog', e));
1382
1392
  }
1383
- console.error('Error while shutting down PostHog', e);
1384
- }
1393
+ };
1394
+ return Promise.race([
1395
+ new Promise((_, reject) => {
1396
+ safeSetTimeout(() => {
1397
+ this.logMsgIfDebug(() => console.error('Timed out while shutting down PostHog'));
1398
+ hasTimedOut = true;
1399
+ reject('Timeout while shutting down PostHog. Some events may not have been sent.');
1400
+ }, shutdownTimeoutMs);
1401
+ }),
1402
+ doShutdown(),
1403
+ ]);
1385
1404
  }
1386
1405
  }
1387
1406
 
@@ -1405,14 +1424,13 @@ class PostHogMemoryStorage {
1405
1424
  * This is currently solved by using the global fetch if available instead.
1406
1425
  * See https://github.com/PostHog/posthog-js-lite/issues/127 for more info
1407
1426
  */
1408
- let _fetch = // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
1427
+ let _fetch =
1428
+ // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
1409
1429
  // @ts-ignore
1410
1430
  typeof fetch !== 'undefined' ? fetch : typeof global.fetch !== 'undefined' ? global.fetch : undefined;
1411
-
1412
1431
  if (!_fetch) {
1413
1432
  // eslint-disable-next-line @typescript-eslint/no-var-requires
1414
1433
  const axios = require('axios');
1415
-
1416
1434
  _fetch = async (url, options) => {
1417
1435
  const res = await axios.request({
1418
1436
  url,
@@ -1429,14 +1447,13 @@ if (!_fetch) {
1429
1447
  json: async () => res.data
1430
1448
  };
1431
1449
  };
1432
- } // NOTE: We have to export this as default, even though we prefer named exports as we are relying on detecting "fetch" in the global scope
1433
-
1434
-
1450
+ }
1451
+ // NOTE: We have to export this as default, even though we prefer named exports as we are relying on detecting "fetch" in the global scope
1435
1452
  var fetch$1 = _fetch;
1436
1453
 
1454
+ // eslint-disable-next-line
1437
1455
  const LONG_SCALE = 0xfffffffffffffff;
1438
1456
  const NULL_VALUES_ALLOWED_OPERATORS = ['is_not'];
1439
-
1440
1457
  class ClientError extends Error {
1441
1458
  constructor(message) {
1442
1459
  super();
@@ -1445,22 +1462,18 @@ class ClientError extends Error {
1445
1462
  this.message = message;
1446
1463
  Object.setPrototypeOf(this, ClientError.prototype);
1447
1464
  }
1448
-
1449
1465
  }
1450
-
1451
1466
  class InconclusiveMatchError extends Error {
1452
1467
  constructor(message) {
1453
1468
  super(message);
1454
1469
  this.name = this.constructor.name;
1455
- Error.captureStackTrace(this, this.constructor); // instanceof doesn't work in ES3 or ES5
1470
+ Error.captureStackTrace(this, this.constructor);
1471
+ // instanceof doesn't work in ES3 or ES5
1456
1472
  // https://www.dannyguo.com/blog/how-to-fix-instanceof-not-working-for-custom-errors-in-typescript/
1457
1473
  // this is the workaround
1458
-
1459
1474
  Object.setPrototypeOf(this, InconclusiveMatchError.prototype);
1460
1475
  }
1461
-
1462
1476
  }
1463
-
1464
1477
  class FeatureFlagsPoller {
1465
1478
  constructor({
1466
1479
  pollingInterval,
@@ -1482,81 +1495,69 @@ class FeatureFlagsPoller {
1482
1495
  this.timeout = timeout;
1483
1496
  this.projectApiKey = projectApiKey;
1484
1497
  this.host = host;
1485
- this.poller = undefined; // NOTE: as any is required here as the AbortSignal typing is slightly misaligned but works just fine
1486
-
1498
+ this.poller = undefined;
1499
+ // NOTE: as any is required here as the AbortSignal typing is slightly misaligned but works just fine
1487
1500
  this.fetch = options.fetch || fetch$1;
1488
1501
  this.onError = options.onError;
1489
1502
  this.customHeaders = customHeaders;
1490
1503
  void this.loadFeatureFlags();
1491
1504
  }
1492
-
1493
1505
  debug(enabled = true) {
1494
1506
  this.debugMode = enabled;
1495
1507
  }
1496
-
1508
+ logMsgIfDebug(fn) {
1509
+ if (this.debugMode) {
1510
+ fn();
1511
+ }
1512
+ }
1497
1513
  async getFeatureFlag(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
1498
1514
  await this.loadFeatureFlags();
1499
1515
  let response = undefined;
1500
1516
  let featureFlag = undefined;
1501
-
1502
1517
  if (!this.loadedSuccessfullyOnce) {
1503
1518
  return response;
1504
1519
  }
1505
-
1506
1520
  for (const flag of this.featureFlags) {
1507
1521
  if (key === flag.key) {
1508
1522
  featureFlag = flag;
1509
1523
  break;
1510
1524
  }
1511
1525
  }
1512
-
1513
1526
  if (featureFlag !== undefined) {
1514
1527
  try {
1515
1528
  response = this.computeFlagLocally(featureFlag, distinctId, groups, personProperties, groupProperties);
1516
-
1517
- if (this.debugMode) {
1518
- console.debug(`Successfully computed flag locally: ${key} -> ${response}`);
1519
- }
1529
+ this.logMsgIfDebug(() => console.debug(`Successfully computed flag locally: ${key} -> ${response}`));
1520
1530
  } catch (e) {
1521
1531
  if (e instanceof InconclusiveMatchError) {
1522
- if (this.debugMode) {
1523
- console.debug(`InconclusiveMatchError when computing flag locally: ${key}: ${e}`);
1524
- }
1532
+ this.logMsgIfDebug(() => console.debug(`InconclusiveMatchError when computing flag locally: ${key}: ${e}`));
1525
1533
  } else if (e instanceof Error) {
1526
1534
  this.onError?.(new Error(`Error computing flag locally: ${key}: ${e}`));
1527
1535
  }
1528
1536
  }
1529
1537
  }
1530
-
1531
1538
  return response;
1532
1539
  }
1533
-
1534
1540
  async computeFeatureFlagPayloadLocally(key, matchValue) {
1535
1541
  await this.loadFeatureFlags();
1536
1542
  let response = undefined;
1537
-
1538
1543
  if (!this.loadedSuccessfullyOnce) {
1539
1544
  return undefined;
1540
1545
  }
1541
-
1542
1546
  if (typeof matchValue == 'boolean') {
1543
1547
  response = this.featureFlagsByKey?.[key]?.filters?.payloads?.[matchValue.toString()];
1544
1548
  } else if (typeof matchValue == 'string') {
1545
1549
  response = this.featureFlagsByKey?.[key]?.filters?.payloads?.[matchValue];
1546
- } // Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
1547
-
1548
-
1550
+ }
1551
+ // Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
1549
1552
  if (response === undefined || response === null) {
1550
1553
  return null;
1551
1554
  }
1552
-
1553
1555
  try {
1554
1556
  return JSON.parse(response);
1555
1557
  } catch {
1556
1558
  return response;
1557
1559
  }
1558
1560
  }
1559
-
1560
1561
  async getAllFlagsAndPayloads(distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
1561
1562
  await this.loadFeatureFlags();
1562
1563
  const response = {};
@@ -1567,7 +1568,6 @@ class FeatureFlagsPoller {
1567
1568
  const matchValue = this.computeFlagLocally(flag, distinctId, groups, personProperties, groupProperties);
1568
1569
  response[flag.key] = matchValue;
1569
1570
  const matchPayload = await this.computeFeatureFlagPayloadLocally(flag.key, matchValue);
1570
-
1571
1571
  if (matchPayload) {
1572
1572
  payloads[flag.key] = matchPayload;
1573
1573
  }
@@ -1575,7 +1575,6 @@ class FeatureFlagsPoller {
1575
1575
  if (e instanceof InconclusiveMatchError) ; else if (e instanceof Error) {
1576
1576
  this.onError?.(new Error(`Error computing flag locally: ${flag.key}: ${e}`));
1577
1577
  }
1578
-
1579
1578
  fallbackToDecide = true;
1580
1579
  }
1581
1580
  });
@@ -1585,56 +1584,41 @@ class FeatureFlagsPoller {
1585
1584
  fallbackToDecide
1586
1585
  };
1587
1586
  }
1588
-
1589
1587
  computeFlagLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
1590
1588
  if (flag.ensure_experience_continuity) {
1591
1589
  throw new InconclusiveMatchError('Flag has experience continuity enabled');
1592
1590
  }
1593
-
1594
1591
  if (!flag.active) {
1595
1592
  return false;
1596
1593
  }
1597
-
1598
1594
  const flagFilters = flag.filters || {};
1599
1595
  const aggregation_group_type_index = flagFilters.aggregation_group_type_index;
1600
-
1601
1596
  if (aggregation_group_type_index != undefined) {
1602
1597
  const groupName = this.groupTypeMapping[String(aggregation_group_type_index)];
1603
-
1604
1598
  if (!groupName) {
1605
- if (this.debugMode) {
1606
- console.warn(`[FEATURE FLAGS] Unknown group type index ${aggregation_group_type_index} for feature flag ${flag.key}`);
1607
- }
1608
-
1599
+ this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Unknown group type index ${aggregation_group_type_index} for feature flag ${flag.key}`));
1609
1600
  throw new InconclusiveMatchError('Flag has unknown group type index');
1610
1601
  }
1611
-
1612
1602
  if (!(groupName in groups)) {
1613
- if (this.debugMode) {
1614
- console.warn(`[FEATURE FLAGS] Can't compute group feature flag: ${flag.key} without group names passed in`);
1615
- }
1616
-
1603
+ this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Can't compute group feature flag: ${flag.key} without group names passed in`));
1617
1604
  return false;
1618
1605
  }
1619
-
1620
1606
  const focusedGroupProperties = groupProperties[groupName];
1621
1607
  return this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties);
1622
1608
  } else {
1623
1609
  return this.matchFeatureFlagProperties(flag, distinctId, personProperties);
1624
1610
  }
1625
1611
  }
1626
-
1627
1612
  matchFeatureFlagProperties(flag, distinctId, properties) {
1628
1613
  const flagFilters = flag.filters || {};
1629
1614
  const flagConditions = flagFilters.groups || [];
1630
1615
  let isInconclusive = false;
1631
- let result = undefined; // # Stable sort conditions with variant overrides to the top. This ensures that if overrides are present, they are
1616
+ let result = undefined;
1617
+ // # Stable sort conditions with variant overrides to the top. This ensures that if overrides are present, they are
1632
1618
  // # evaluated first, and the variant override is applied to the first matching condition.
1633
-
1634
1619
  const sortedFlagConditions = [...flagConditions].sort((conditionA, conditionB) => {
1635
1620
  const AHasVariantOverride = !!conditionA.variant;
1636
1621
  const BHasVariantOverride = !!conditionB.variant;
1637
-
1638
1622
  if (AHasVariantOverride && BHasVariantOverride) {
1639
1623
  return 0;
1640
1624
  } else if (AHasVariantOverride) {
@@ -1645,19 +1629,16 @@ class FeatureFlagsPoller {
1645
1629
  return 0;
1646
1630
  }
1647
1631
  });
1648
-
1649
1632
  for (const condition of sortedFlagConditions) {
1650
1633
  try {
1651
1634
  if (this.isConditionMatch(flag, distinctId, condition, properties)) {
1652
1635
  const variantOverride = condition.variant;
1653
1636
  const flagVariants = flagFilters.multivariate?.variants || [];
1654
-
1655
1637
  if (variantOverride && flagVariants.some(variant => variant.key === variantOverride)) {
1656
1638
  result = variantOverride;
1657
1639
  } else {
1658
1640
  result = this.getMatchingVariant(flag, distinctId) || true;
1659
1641
  }
1660
-
1661
1642
  break;
1662
1643
  }
1663
1644
  } catch (e) {
@@ -1668,68 +1649,51 @@ class FeatureFlagsPoller {
1668
1649
  }
1669
1650
  }
1670
1651
  }
1671
-
1672
1652
  if (result !== undefined) {
1673
1653
  return result;
1674
1654
  } else if (isInconclusive) {
1675
1655
  throw new InconclusiveMatchError("Can't determine if feature flag is enabled or not with given properties");
1676
- } // We can only return False when all conditions are False
1677
-
1678
-
1656
+ }
1657
+ // We can only return False when all conditions are False
1679
1658
  return false;
1680
1659
  }
1681
-
1682
1660
  isConditionMatch(flag, distinctId, condition, properties) {
1683
1661
  const rolloutPercentage = condition.rollout_percentage;
1684
-
1685
1662
  const warnFunction = msg => {
1686
- if (this.debugMode) {
1687
- console.warn(msg);
1688
- }
1663
+ this.logMsgIfDebug(() => console.warn(msg));
1689
1664
  };
1690
-
1691
1665
  if ((condition.properties || []).length > 0) {
1692
1666
  for (const prop of condition.properties) {
1693
1667
  const propertyType = prop.type;
1694
1668
  let matches = false;
1695
-
1696
1669
  if (propertyType === 'cohort') {
1697
1670
  matches = matchCohort(prop, properties, this.cohorts, this.debugMode);
1698
1671
  } else {
1699
1672
  matches = matchProperty(prop, properties, warnFunction);
1700
1673
  }
1701
-
1702
1674
  if (!matches) {
1703
1675
  return false;
1704
1676
  }
1705
1677
  }
1706
-
1707
1678
  if (rolloutPercentage == undefined) {
1708
1679
  return true;
1709
1680
  }
1710
1681
  }
1711
-
1712
1682
  if (rolloutPercentage != undefined && _hash(flag.key, distinctId) > rolloutPercentage / 100.0) {
1713
1683
  return false;
1714
1684
  }
1715
-
1716
1685
  return true;
1717
1686
  }
1718
-
1719
1687
  getMatchingVariant(flag, distinctId) {
1720
1688
  const hashValue = _hash(flag.key, distinctId, 'variant');
1721
-
1722
1689
  const matchingVariant = this.variantLookupTable(flag).find(variant => {
1723
1690
  return hashValue >= variant.valueMin && hashValue < variant.valueMax;
1724
1691
  });
1725
-
1726
1692
  if (matchingVariant) {
1727
1693
  return matchingVariant.key;
1728
1694
  }
1729
-
1730
1695
  return undefined;
1731
1696
  }
1732
-
1733
1697
  variantLookupTable(flag) {
1734
1698
  const lookupTable = [];
1735
1699
  let valueMin = 0;
@@ -1747,40 +1711,31 @@ class FeatureFlagsPoller {
1747
1711
  });
1748
1712
  return lookupTable;
1749
1713
  }
1750
-
1751
1714
  async loadFeatureFlags(forceReload = false) {
1752
1715
  if (!this.loadedSuccessfullyOnce || forceReload) {
1753
1716
  await this._loadFeatureFlags();
1754
1717
  }
1755
1718
  }
1756
-
1757
1719
  async _loadFeatureFlags() {
1758
1720
  if (this.poller) {
1759
1721
  clearTimeout(this.poller);
1760
1722
  this.poller = undefined;
1761
1723
  }
1762
-
1763
1724
  this.poller = setTimeout(() => this._loadFeatureFlags(), this.pollingInterval);
1764
-
1765
1725
  try {
1766
1726
  const res = await this._requestFeatureFlagDefinitions();
1767
-
1768
1727
  if (res && res.status === 401) {
1769
1728
  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`);
1770
1729
  }
1771
-
1772
1730
  if (res && res.status !== 200) {
1773
1731
  // something else went wrong, or the server is down.
1774
1732
  // In this case, don't override existing flags
1775
1733
  return;
1776
1734
  }
1777
-
1778
1735
  const responseJson = await res.json();
1779
-
1780
1736
  if (!('flags' in responseJson)) {
1781
1737
  this.onError?.(new Error(`Invalid response when getting feature flags: ${JSON.stringify(responseJson)}`));
1782
1738
  }
1783
-
1784
1739
  this.featureFlags = responseJson.flags || [];
1785
1740
  this.featureFlagsByKey = this.featureFlags.reduce((acc, curr) => (acc[curr.key] = curr, acc), {});
1786
1741
  this.groupTypeMapping = responseJson.group_type_mapping || {};
@@ -1794,18 +1749,17 @@ class FeatureFlagsPoller {
1794
1749
  }
1795
1750
  }
1796
1751
  }
1797
-
1798
1752
  async _requestFeatureFlagDefinitions() {
1799
1753
  const url = `${this.host}/api/feature_flag/local_evaluation?token=${this.projectApiKey}&send_cohorts`;
1800
1754
  const options = {
1801
1755
  method: 'GET',
1802
- headers: { ...this.customHeaders,
1756
+ headers: {
1757
+ ...this.customHeaders,
1803
1758
  'Content-Type': 'application/json',
1804
1759
  Authorization: `Bearer ${this.personalApiKey}`
1805
1760
  }
1806
1761
  };
1807
1762
  let abortTimeout = null;
1808
-
1809
1763
  if (this.timeout && typeof this.timeout === 'number') {
1810
1764
  const controller = new AbortController();
1811
1765
  abortTimeout = safeSetTimeout(() => {
@@ -1813,62 +1767,50 @@ class FeatureFlagsPoller {
1813
1767
  }, this.timeout);
1814
1768
  options.signal = controller.signal;
1815
1769
  }
1816
-
1817
1770
  try {
1818
1771
  return await this.fetch(url, options);
1819
1772
  } finally {
1820
1773
  clearTimeout(abortTimeout);
1821
1774
  }
1822
1775
  }
1823
-
1824
1776
  stopPoller() {
1825
1777
  clearTimeout(this.poller);
1826
1778
  }
1827
-
1828
- } // # This function takes a distinct_id and a feature flag key and returns a float between 0 and 1.
1779
+ }
1780
+ // # This function takes a distinct_id and a feature flag key and returns a float between 0 and 1.
1829
1781
  // # Given the same distinct_id and key, it'll always return the same float. These floats are
1830
1782
  // # uniformly distributed between 0 and 1, so if we want to show this feature to 20% of traffic
1831
1783
  // # we can do _hash(key, distinct_id) < 0.2
1832
-
1833
-
1834
1784
  function _hash(key, distinctId, salt = '') {
1835
1785
  // rusha is a fast sha1 implementation in pure javascript
1836
1786
  const sha1Hash = createHash();
1837
1787
  sha1Hash.update(`${key}.${distinctId}${salt}`);
1838
1788
  return parseInt(sha1Hash.digest('hex').slice(0, 15), 16) / LONG_SCALE;
1839
1789
  }
1840
-
1841
1790
  function matchProperty(property, propertyValues, warnFunction) {
1842
1791
  const key = property.key;
1843
1792
  const value = property.value;
1844
1793
  const operator = property.operator || 'exact';
1845
-
1846
1794
  if (!(key in propertyValues)) {
1847
1795
  throw new InconclusiveMatchError(`Property ${key} not found in propertyValues`);
1848
1796
  } else if (operator === 'is_not_set') {
1849
1797
  throw new InconclusiveMatchError(`Operator is_not_set is not supported`);
1850
1798
  }
1851
-
1852
1799
  const overrideValue = propertyValues[key];
1853
-
1854
1800
  if (overrideValue == null && !NULL_VALUES_ALLOWED_OPERATORS.includes(operator)) {
1855
1801
  // if the value is null, just fail the feature flag comparison
1856
1802
  // this isn't an InconclusiveMatchError because the property value was provided.
1857
1803
  if (warnFunction) {
1858
1804
  warnFunction(`Property ${key} cannot have a value of null/undefined with the ${operator} operator`);
1859
1805
  }
1860
-
1861
1806
  return false;
1862
1807
  }
1863
-
1864
1808
  function computeExactMatch(value, overrideValue) {
1865
1809
  if (Array.isArray(value)) {
1866
1810
  return value.map(val => String(val).toLowerCase()).includes(String(overrideValue).toLowerCase());
1867
1811
  }
1868
-
1869
1812
  return String(value).toLowerCase() === String(overrideValue).toLowerCase();
1870
1813
  }
1871
-
1872
1814
  function compare(lhs, rhs, operator) {
1873
1815
  if (operator === 'gt') {
1874
1816
  return lhs > rhs;
@@ -1882,29 +1824,21 @@ function matchProperty(property, propertyValues, warnFunction) {
1882
1824
  throw new Error(`Invalid operator: ${operator}`);
1883
1825
  }
1884
1826
  }
1885
-
1886
1827
  switch (operator) {
1887
1828
  case 'exact':
1888
1829
  return computeExactMatch(value, overrideValue);
1889
-
1890
1830
  case 'is_not':
1891
1831
  return !computeExactMatch(value, overrideValue);
1892
-
1893
1832
  case 'is_set':
1894
1833
  return key in propertyValues;
1895
-
1896
1834
  case 'icontains':
1897
1835
  return String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
1898
-
1899
1836
  case 'not_icontains':
1900
1837
  return !String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
1901
-
1902
1838
  case 'regex':
1903
1839
  return isValidRegex(String(value)) && String(overrideValue).match(String(value)) !== null;
1904
-
1905
1840
  case 'not_regex':
1906
1841
  return isValidRegex(String(value)) && String(overrideValue).match(String(value)) === null;
1907
-
1908
1842
  case 'gt':
1909
1843
  case 'gte':
1910
1844
  case 'lt':
@@ -1913,14 +1847,13 @@ function matchProperty(property, propertyValues, warnFunction) {
1913
1847
  // :TRICKY: We adjust comparison based on the override value passed in,
1914
1848
  // to make sure we handle both numeric and string comparisons appropriately.
1915
1849
  let parsedValue = typeof value === 'number' ? value : null;
1916
-
1917
1850
  if (typeof value === 'string') {
1918
1851
  try {
1919
1852
  parsedValue = parseFloat(value);
1920
- } catch (err) {// pass
1853
+ } catch (err) {
1854
+ // pass
1921
1855
  }
1922
1856
  }
1923
-
1924
1857
  if (parsedValue != null && overrideValue != null) {
1925
1858
  // check both null and undefined
1926
1859
  if (typeof overrideValue === 'string') {
@@ -1932,66 +1865,50 @@ function matchProperty(property, propertyValues, warnFunction) {
1932
1865
  return compare(String(overrideValue), String(value), operator);
1933
1866
  }
1934
1867
  }
1935
-
1936
1868
  case 'is_date_after':
1937
1869
  case 'is_date_before':
1938
1870
  {
1939
1871
  let parsedDate = relativeDateParseForFeatureFlagMatching(String(value));
1940
-
1941
1872
  if (parsedDate == null) {
1942
1873
  parsedDate = convertToDateTime(value);
1943
1874
  }
1944
-
1945
1875
  if (parsedDate == null) {
1946
1876
  throw new InconclusiveMatchError(`Invalid date: ${value}`);
1947
1877
  }
1948
-
1949
1878
  const overrideDate = convertToDateTime(overrideValue);
1950
-
1951
1879
  if (['is_date_before'].includes(operator)) {
1952
1880
  return overrideDate < parsedDate;
1953
1881
  }
1954
-
1955
1882
  return overrideDate > parsedDate;
1956
1883
  }
1957
-
1958
1884
  default:
1959
1885
  throw new InconclusiveMatchError(`Unknown operator: ${operator}`);
1960
1886
  }
1961
1887
  }
1962
-
1963
1888
  function matchCohort(property, propertyValues, cohortProperties, debugMode = false) {
1964
1889
  const cohortId = String(property.value);
1965
-
1966
1890
  if (!(cohortId in cohortProperties)) {
1967
1891
  throw new InconclusiveMatchError("can't match cohort without a given cohort property value");
1968
1892
  }
1969
-
1970
1893
  const propertyGroup = cohortProperties[cohortId];
1971
1894
  return matchPropertyGroup(propertyGroup, propertyValues, cohortProperties, debugMode);
1972
1895
  }
1973
-
1974
1896
  function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties, debugMode = false) {
1975
1897
  if (!propertyGroup) {
1976
1898
  return true;
1977
1899
  }
1978
-
1979
1900
  const propertyGroupType = propertyGroup.type;
1980
1901
  const properties = propertyGroup.values;
1981
-
1982
1902
  if (!properties || properties.length === 0) {
1983
1903
  // empty groups are no-ops, always match
1984
1904
  return true;
1985
1905
  }
1986
-
1987
1906
  let errorMatchingLocally = false;
1988
-
1989
1907
  if ('values' in properties[0]) {
1990
1908
  // a nested property group
1991
1909
  for (const prop of properties) {
1992
1910
  try {
1993
1911
  const matches = matchPropertyGroup(prop, propertyValues, cohortProperties, debugMode);
1994
-
1995
1912
  if (propertyGroupType === 'AND') {
1996
1913
  if (!matches) {
1997
1914
  return false;
@@ -2007,39 +1924,32 @@ function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties, deb
2007
1924
  if (debugMode) {
2008
1925
  console.debug(`Failed to compute property ${prop} locally: ${err}`);
2009
1926
  }
2010
-
2011
1927
  errorMatchingLocally = true;
2012
1928
  } else {
2013
1929
  throw err;
2014
1930
  }
2015
1931
  }
2016
1932
  }
2017
-
2018
1933
  if (errorMatchingLocally) {
2019
1934
  throw new InconclusiveMatchError("Can't match cohort without a given cohort property value");
2020
- } // if we get here, all matched in AND case, or none matched in OR case
2021
-
2022
-
1935
+ }
1936
+ // if we get here, all matched in AND case, or none matched in OR case
2023
1937
  return propertyGroupType === 'AND';
2024
1938
  } else {
2025
1939
  for (const prop of properties) {
2026
1940
  try {
2027
1941
  let matches;
2028
-
2029
1942
  if (prop.type === 'cohort') {
2030
1943
  matches = matchCohort(prop, propertyValues, cohortProperties, debugMode);
2031
1944
  } else {
2032
1945
  matches = matchProperty(prop, propertyValues);
2033
1946
  }
2034
-
2035
1947
  const negation = prop.negation || false;
2036
-
2037
1948
  if (propertyGroupType === 'AND') {
2038
1949
  // if negated property, do the inverse
2039
1950
  if (!matches && !negation) {
2040
1951
  return false;
2041
1952
  }
2042
-
2043
1953
  if (matches && negation) {
2044
1954
  return false;
2045
1955
  }
@@ -2048,7 +1958,6 @@ function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties, deb
2048
1958
  if (matches && !negation) {
2049
1959
  return true;
2050
1960
  }
2051
-
2052
1961
  if (!matches && negation) {
2053
1962
  return true;
2054
1963
  }
@@ -2058,23 +1967,19 @@ function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties, deb
2058
1967
  if (debugMode) {
2059
1968
  console.debug(`Failed to compute property ${prop} locally: ${err}`);
2060
1969
  }
2061
-
2062
1970
  errorMatchingLocally = true;
2063
1971
  } else {
2064
1972
  throw err;
2065
1973
  }
2066
1974
  }
2067
1975
  }
2068
-
2069
1976
  if (errorMatchingLocally) {
2070
1977
  throw new InconclusiveMatchError("can't match cohort without a given cohort property value");
2071
- } // if we get here, all matched in AND case, or none matched in OR case
2072
-
2073
-
1978
+ }
1979
+ // if we get here, all matched in AND case, or none matched in OR case
2074
1980
  return propertyGroupType === 'AND';
2075
1981
  }
2076
1982
  }
2077
-
2078
1983
  function isValidRegex(regex) {
2079
1984
  try {
2080
1985
  new RegExp(regex);
@@ -2083,42 +1988,33 @@ function isValidRegex(regex) {
2083
1988
  return false;
2084
1989
  }
2085
1990
  }
2086
-
2087
1991
  function convertToDateTime(value) {
2088
1992
  if (value instanceof Date) {
2089
1993
  return value;
2090
1994
  } else if (typeof value === 'string' || typeof value === 'number') {
2091
1995
  const date = new Date(value);
2092
-
2093
1996
  if (!isNaN(date.valueOf())) {
2094
1997
  return date;
2095
1998
  }
2096
-
2097
1999
  throw new InconclusiveMatchError(`${value} is in an invalid date format`);
2098
2000
  } else {
2099
2001
  throw new InconclusiveMatchError(`The date provided ${value} must be a string, number, or date object`);
2100
2002
  }
2101
2003
  }
2102
-
2103
2004
  function relativeDateParseForFeatureFlagMatching(value) {
2104
2005
  const regex = /^-?(?<number>[0-9]+)(?<interval>[a-z])$/;
2105
2006
  const match = value.match(regex);
2106
2007
  const parsedDt = new Date(new Date().toISOString());
2107
-
2108
2008
  if (match) {
2109
2009
  if (!match.groups) {
2110
2010
  return null;
2111
2011
  }
2112
-
2113
2012
  const number = parseInt(match.groups['number']);
2114
-
2115
2013
  if (number >= 10000) {
2116
2014
  // Guard against overflow, disallow numbers greater than 10_000
2117
2015
  return null;
2118
2016
  }
2119
-
2120
2017
  const interval = match.groups['interval'];
2121
-
2122
2018
  if (interval == 'h') {
2123
2019
  parsedDt.setUTCHours(parsedDt.getUTCHours() - number);
2124
2020
  } else if (interval == 'd') {
@@ -2132,7 +2028,6 @@ function relativeDateParseForFeatureFlagMatching(value) {
2132
2028
  } else {
2133
2029
  return null;
2134
2030
  }
2135
-
2136
2031
  return parsedDt;
2137
2032
  } else {
2138
2033
  return null;
@@ -2140,15 +2035,13 @@ function relativeDateParseForFeatureFlagMatching(value) {
2140
2035
  }
2141
2036
 
2142
2037
  const THIRTY_SECONDS = 30 * 1000;
2143
- const MAX_CACHE_SIZE = 50 * 1000; // The actual exported Nodejs API.
2144
-
2038
+ const MAX_CACHE_SIZE = 50 * 1000;
2039
+ // The actual exported Nodejs API.
2145
2040
  class PostHog extends PostHogCoreStateless {
2146
2041
  constructor(apiKey, options = {}) {
2147
- options.captureMode = options?.captureMode || 'json';
2148
2042
  super(apiKey, options);
2149
2043
  this._memoryStorage = new PostHogMemoryStorage();
2150
2044
  this.options = options;
2151
-
2152
2045
  if (options.personalApiKey) {
2153
2046
  this.featureFlagsPoller = new FeatureFlagsPoller({
2154
2047
  pollingInterval: typeof options.featureFlagsPollingInterval === 'number' ? options.featureFlagsPollingInterval : THIRTY_SECONDS,
@@ -2163,48 +2056,37 @@ class PostHog extends PostHogCoreStateless {
2163
2056
  customHeaders: this.getCustomHeaders()
2164
2057
  });
2165
2058
  }
2166
-
2167
2059
  this.distinctIdHasSentFlagCalls = {};
2168
2060
  this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE;
2169
2061
  }
2170
-
2171
2062
  getPersistedProperty(key) {
2172
2063
  return this._memoryStorage.getProperty(key);
2173
2064
  }
2174
-
2175
2065
  setPersistedProperty(key, value) {
2176
2066
  return this._memoryStorage.setProperty(key, value);
2177
2067
  }
2178
-
2179
2068
  fetch(url, options) {
2180
2069
  return this.options.fetch ? this.options.fetch(url, options) : fetch$1(url, options);
2181
2070
  }
2182
-
2183
2071
  getLibraryId() {
2184
2072
  return 'posthog-node';
2185
2073
  }
2186
-
2187
2074
  getLibraryVersion() {
2188
2075
  return version;
2189
2076
  }
2190
-
2191
2077
  getCustomUserAgent() {
2192
2078
  return `${this.getLibraryId()}/${this.getLibraryVersion()}`;
2193
2079
  }
2194
-
2195
2080
  enable() {
2196
2081
  return super.optIn();
2197
2082
  }
2198
-
2199
2083
  disable() {
2200
2084
  return super.optOut();
2201
2085
  }
2202
-
2203
2086
  debug(enabled = true) {
2204
2087
  super.debug(enabled);
2205
2088
  this.featureFlagsPoller?.debug(enabled);
2206
2089
  }
2207
-
2208
2090
  capture({
2209
2091
  distinctId,
2210
2092
  event,
@@ -2222,65 +2104,55 @@ class PostHog extends PostHogCoreStateless {
2222
2104
  uuid
2223
2105
  });
2224
2106
  };
2225
-
2226
2107
  const _getFlags = (distinctId, groups, disableGeoip) => {
2227
2108
  return super.getFeatureFlagsStateless(distinctId, groups, undefined, undefined, disableGeoip);
2228
- }; // :TRICKY: If we flush, or need to shut down, to not lose events we want this promise to resolve before we flush
2229
-
2230
-
2109
+ };
2110
+ // :TRICKY: If we flush, or need to shut down, to not lose events we want this promise to resolve before we flush
2231
2111
  const capturePromise = Promise.resolve().then(async () => {
2232
2112
  if (sendFeatureFlags) {
2233
2113
  // If we are sending feature flags, we need to make sure we have the latest flags
2234
2114
  // return await super.getFeatureFlagsStateless(distinctId, groups, undefined, undefined, disableGeoip)
2235
2115
  return await _getFlags(distinctId, groups, disableGeoip);
2236
2116
  }
2237
-
2238
2117
  if ((this.featureFlagsPoller?.featureFlags?.length || 0) > 0) {
2239
2118
  // Otherwise we may as well check for the flags locally and include them if there
2240
2119
  const groupsWithStringValues = {};
2241
-
2242
2120
  for (const [key, value] of Object.entries(groups || {})) {
2243
2121
  groupsWithStringValues[key] = String(value);
2244
2122
  }
2245
-
2246
2123
  return await this.getAllFlags(distinctId, {
2247
2124
  groups: groupsWithStringValues,
2248
2125
  disableGeoip,
2249
2126
  onlyEvaluateLocally: true
2250
2127
  });
2251
2128
  }
2252
-
2253
2129
  return {};
2254
2130
  }).then(flags => {
2255
2131
  // Derive the relevant flag properties to add
2256
2132
  const additionalProperties = {};
2257
-
2258
2133
  if (flags) {
2259
2134
  for (const [feature, variant] of Object.entries(flags)) {
2260
2135
  additionalProperties[`$feature/${feature}`] = variant;
2261
2136
  }
2262
2137
  }
2263
-
2264
2138
  const activeFlags = Object.keys(flags || {}).filter(flag => flags?.[flag] !== false);
2265
-
2266
2139
  if (activeFlags.length > 0) {
2267
2140
  additionalProperties['$active_feature_flags'] = activeFlags;
2268
2141
  }
2269
-
2270
2142
  return additionalProperties;
2271
2143
  }).catch(() => {
2272
2144
  // Something went wrong getting the flag info - we should capture the event anyways
2273
2145
  return {};
2274
2146
  }).then(additionalProperties => {
2275
2147
  // No matter what - capture the event
2276
- _capture({ ...additionalProperties,
2148
+ _capture({
2149
+ ...additionalProperties,
2277
2150
  ...properties,
2278
2151
  $groups: groups
2279
2152
  });
2280
2153
  });
2281
2154
  this.addPendingPromise(capturePromise);
2282
2155
  }
2283
-
2284
2156
  identify({
2285
2157
  distinctId,
2286
2158
  properties,
@@ -2294,13 +2166,11 @@ class PostHog extends PostHogCoreStateless {
2294
2166
  disableGeoip
2295
2167
  });
2296
2168
  }
2297
-
2298
2169
  alias(data) {
2299
2170
  super.aliasStateless(data.alias, data.distinctId, undefined, {
2300
2171
  disableGeoip: data.disableGeoip
2301
2172
  });
2302
2173
  }
2303
-
2304
2174
  async getFeatureFlag(key, distinctId, options) {
2305
2175
  const {
2306
2176
  groups,
@@ -2314,36 +2184,29 @@ class PostHog extends PostHogCoreStateless {
2314
2184
  } = options || {};
2315
2185
  const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
2316
2186
  personProperties = adjustedProperties.allPersonProperties;
2317
- groupProperties = adjustedProperties.allGroupProperties; // set defaults
2318
-
2187
+ groupProperties = adjustedProperties.allGroupProperties;
2188
+ // set defaults
2319
2189
  if (onlyEvaluateLocally == undefined) {
2320
2190
  onlyEvaluateLocally = false;
2321
2191
  }
2322
-
2323
2192
  if (sendFeatureFlagEvents == undefined) {
2324
2193
  sendFeatureFlagEvents = true;
2325
2194
  }
2326
-
2327
2195
  let response = await this.featureFlagsPoller?.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties);
2328
2196
  const flagWasLocallyEvaluated = response !== undefined;
2329
-
2330
2197
  if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
2331
2198
  response = await super.getFeatureFlagStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
2332
2199
  }
2333
-
2334
2200
  const featureFlagReportedKey = `${key}_${response}`;
2335
-
2336
2201
  if (sendFeatureFlagEvents && (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey))) {
2337
2202
  if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) {
2338
2203
  this.distinctIdHasSentFlagCalls = {};
2339
2204
  }
2340
-
2341
2205
  if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) {
2342
2206
  this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
2343
2207
  } else {
2344
2208
  this.distinctIdHasSentFlagCalls[distinctId] = [featureFlagReportedKey];
2345
2209
  }
2346
-
2347
2210
  this.capture({
2348
2211
  distinctId,
2349
2212
  event: '$feature_flag_called',
@@ -2357,10 +2220,8 @@ class PostHog extends PostHogCoreStateless {
2357
2220
  disableGeoip
2358
2221
  });
2359
2222
  }
2360
-
2361
2223
  return response;
2362
2224
  }
2363
-
2364
2225
  async getFeatureFlagPayload(key, distinctId, matchValue, options) {
2365
2226
  const {
2366
2227
  groups,
@@ -2375,56 +2236,45 @@ class PostHog extends PostHogCoreStateless {
2375
2236
  const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
2376
2237
  personProperties = adjustedProperties.allPersonProperties;
2377
2238
  groupProperties = adjustedProperties.allGroupProperties;
2378
- let response = undefined; // Try to get match value locally if not provided
2379
-
2239
+ let response = undefined;
2240
+ // Try to get match value locally if not provided
2380
2241
  if (!matchValue) {
2381
- matchValue = await this.getFeatureFlag(key, distinctId, { ...options,
2242
+ matchValue = await this.getFeatureFlag(key, distinctId, {
2243
+ ...options,
2382
2244
  onlyEvaluateLocally: true
2383
2245
  });
2384
2246
  }
2385
-
2386
2247
  if (matchValue) {
2387
2248
  response = await this.featureFlagsPoller?.computeFeatureFlagPayloadLocally(key, matchValue);
2388
- } // set defaults
2389
-
2390
-
2249
+ }
2250
+ // set defaults
2391
2251
  if (onlyEvaluateLocally == undefined) {
2392
2252
  onlyEvaluateLocally = false;
2393
2253
  }
2394
-
2395
2254
  if (sendFeatureFlagEvents == undefined) {
2396
2255
  sendFeatureFlagEvents = true;
2397
- } // set defaults
2398
-
2399
-
2256
+ }
2257
+ // set defaults
2400
2258
  if (onlyEvaluateLocally == undefined) {
2401
2259
  onlyEvaluateLocally = false;
2402
2260
  }
2403
-
2404
2261
  const payloadWasLocallyEvaluated = response !== undefined;
2405
-
2406
2262
  if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) {
2407
2263
  response = await super.getFeatureFlagPayloadStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
2408
2264
  }
2409
-
2410
2265
  return response;
2411
2266
  }
2412
-
2413
2267
  async isFeatureEnabled(key, distinctId, options) {
2414
2268
  const feat = await this.getFeatureFlag(key, distinctId, options);
2415
-
2416
2269
  if (feat === undefined) {
2417
2270
  return undefined;
2418
2271
  }
2419
-
2420
2272
  return !!feat || false;
2421
2273
  }
2422
-
2423
2274
  async getAllFlags(distinctId, options) {
2424
2275
  const response = await this.getAllFlagsAndPayloads(distinctId, options);
2425
2276
  return response.featureFlags;
2426
2277
  }
2427
-
2428
2278
  async getAllFlagsAndPayloads(distinctId, options) {
2429
2279
  const {
2430
2280
  groups,
@@ -2437,39 +2287,36 @@ class PostHog extends PostHogCoreStateless {
2437
2287
  } = options || {};
2438
2288
  const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
2439
2289
  personProperties = adjustedProperties.allPersonProperties;
2440
- groupProperties = adjustedProperties.allGroupProperties; // set defaults
2441
-
2290
+ groupProperties = adjustedProperties.allGroupProperties;
2291
+ // set defaults
2442
2292
  if (onlyEvaluateLocally == undefined) {
2443
2293
  onlyEvaluateLocally = false;
2444
2294
  }
2445
-
2446
2295
  const localEvaluationResult = await this.featureFlagsPoller?.getAllFlagsAndPayloads(distinctId, groups, personProperties, groupProperties);
2447
2296
  let featureFlags = {};
2448
2297
  let featureFlagPayloads = {};
2449
2298
  let fallbackToDecide = true;
2450
-
2451
2299
  if (localEvaluationResult) {
2452
2300
  featureFlags = localEvaluationResult.response;
2453
2301
  featureFlagPayloads = localEvaluationResult.payloads;
2454
2302
  fallbackToDecide = localEvaluationResult.fallbackToDecide;
2455
2303
  }
2456
-
2457
2304
  if (fallbackToDecide && !onlyEvaluateLocally) {
2458
2305
  const remoteEvaluationResult = await super.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip);
2459
- featureFlags = { ...featureFlags,
2306
+ featureFlags = {
2307
+ ...featureFlags,
2460
2308
  ...(remoteEvaluationResult.flags || {})
2461
2309
  };
2462
- featureFlagPayloads = { ...featureFlagPayloads,
2310
+ featureFlagPayloads = {
2311
+ ...featureFlagPayloads,
2463
2312
  ...(remoteEvaluationResult.payloads || {})
2464
2313
  };
2465
2314
  }
2466
-
2467
2315
  return {
2468
2316
  featureFlags,
2469
2317
  featureFlagPayloads
2470
2318
  };
2471
2319
  }
2472
-
2473
2320
  groupIdentify({
2474
2321
  groupType,
2475
2322
  groupKey,
@@ -2481,23 +2328,19 @@ class PostHog extends PostHogCoreStateless {
2481
2328
  disableGeoip
2482
2329
  }, distinctId);
2483
2330
  }
2484
-
2485
2331
  async reloadFeatureFlags() {
2486
2332
  await this.featureFlagsPoller?.loadFeatureFlags(true);
2487
2333
  }
2488
-
2489
2334
  async shutdown(shutdownTimeoutMs) {
2490
2335
  this.featureFlagsPoller?.stopPoller();
2491
2336
  return super.shutdown(shutdownTimeoutMs);
2492
2337
  }
2493
-
2494
2338
  addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties) {
2495
2339
  const allPersonProperties = {
2496
2340
  distinct_id: distinctId,
2497
2341
  ...(personProperties || {})
2498
2342
  };
2499
2343
  const allGroupProperties = {};
2500
-
2501
2344
  if (groups) {
2502
2345
  for (const groupName of Object.keys(groups)) {
2503
2346
  allGroupProperties[groupName] = {
@@ -2506,13 +2349,11 @@ class PostHog extends PostHogCoreStateless {
2506
2349
  };
2507
2350
  }
2508
2351
  }
2509
-
2510
2352
  return {
2511
2353
  allPersonProperties,
2512
2354
  allGroupProperties
2513
2355
  };
2514
2356
  }
2515
-
2516
2357
  }
2517
2358
 
2518
2359
  /**
@@ -2543,26 +2384,21 @@ class PostHogSentryIntegration {
2543
2384
  this.name = 'posthog-node';
2544
2385
  this.posthogHost = posthog.options.host ?? 'https://us.i.posthog.com';
2545
2386
  }
2546
-
2547
2387
  setupOnce(addGlobalEventProcessor, getCurrentHub) {
2548
2388
  addGlobalEventProcessor(event => {
2549
2389
  if (event.exception?.values === undefined || event.exception.values.length === 0) {
2550
2390
  return event;
2551
2391
  }
2552
-
2553
2392
  if (!event.tags) {
2554
2393
  event.tags = {};
2555
2394
  }
2556
-
2557
- const sentry = getCurrentHub(); // Get the PostHog user ID from a specific tag, which users can set on their Sentry scope as they need.
2558
-
2395
+ const sentry = getCurrentHub();
2396
+ // Get the PostHog user ID from a specific tag, which users can set on their Sentry scope as they need.
2559
2397
  const userId = event.tags[PostHogSentryIntegration.POSTHOG_ID_TAG];
2560
-
2561
2398
  if (userId === undefined) {
2562
2399
  // If we can't find a user ID, don't bother linking the event. We won't be able to send anything meaningful to PostHog without it.
2563
2400
  return event;
2564
2401
  }
2565
-
2566
2402
  event.tags['PostHog Person URL'] = new URL(`/person/${userId}`, this.posthogHost).toString();
2567
2403
  const properties = {
2568
2404
  // PostHog Exception Properties
@@ -2577,11 +2413,9 @@ class PostHogSentryIntegration {
2577
2413
  $sentry_tags: event.tags
2578
2414
  };
2579
2415
  const projectId = sentry.getClient()?.getDsn()?.projectId;
2580
-
2581
2416
  if (this.organization !== undefined && projectId !== undefined && event.event_id !== undefined) {
2582
2417
  properties.$sentry_url = `${this.prefix ?? 'https://sentry.io/organizations'}/${this.organization}/issues/?project=${projectId}&query=${event.event_id}`;
2583
2418
  }
2584
-
2585
2419
  this.posthog.capture({
2586
2420
  event: '$exception',
2587
2421
  distinctId: userId,
@@ -2590,7 +2424,6 @@ class PostHogSentryIntegration {
2590
2424
  return event;
2591
2425
  });
2592
2426
  }
2593
-
2594
2427
  }
2595
2428
  PostHogSentryIntegration.POSTHOG_ID_TAG = 'posthog_distinct_id';
2596
2429