posthog-node 5.8.2 → 5.8.4

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.
@@ -25,13 +25,15 @@ import { PostHogCoreStateless, getFeatureFlagValue, safeSetTimeout as safeSetTim
25
25
  * @param {Number} [projectId] Optional: The Sentry project id, used to send a direct link from PostHog to Sentry
26
26
  * @param {string} [prefix] Optional: Url of a self-hosted sentry instance (default: https://sentry.io/organizations/)
27
27
  * @param {SeverityLevel[] | '*'} [severityAllowList] Optional: send events matching the provided levels. Use '*' to send all events (default: ['error'])
28
+ * @param {boolean} [sendExceptionsToPostHog] Optional: capture exceptions as events in PostHog (default: true)
28
29
  */
29
30
  const NAME = 'posthog-node';
30
31
  function createEventProcessor(_posthog, {
31
32
  organization,
32
33
  projectId,
33
34
  prefix,
34
- severityAllowList = ['error']
35
+ severityAllowList = ['error'],
36
+ sendExceptionsToPostHog = true
35
37
  } = {}) {
36
38
  return event => {
37
39
  const shouldProcessLevel = severityAllowList === '*' || severityAllowList.includes(event.level);
@@ -81,11 +83,13 @@ function createEventProcessor(_posthog, {
81
83
  if (organization && projectId) {
82
84
  properties['$sentry_url'] = (prefix || 'https://sentry.io/organizations/') + organization + '/issues/?project=' + projectId + '&query=' + event.event_id;
83
85
  }
84
- _posthog.capture({
85
- event: '$exception',
86
- distinctId: userId,
87
- properties
88
- });
86
+ if (sendExceptionsToPostHog) {
87
+ _posthog.capture({
88
+ event: '$exception',
89
+ distinctId: userId,
90
+ properties
91
+ });
92
+ }
89
93
  return event;
90
94
  };
91
95
  }
@@ -101,7 +105,7 @@ function sentryIntegration(_posthog, options) {
101
105
  }
102
106
  // V7 integration - class based
103
107
  class PostHogSentryIntegration {
104
- constructor(_posthog, organization, prefix, severityAllowList) {
108
+ constructor(_posthog, organization, prefix, severityAllowList, sendExceptionsToPostHog) {
105
109
  this.name = NAME;
106
110
  // setupOnce gets called by Sentry when it intializes the plugin
107
111
  this.name = NAME;
@@ -111,7 +115,8 @@ class PostHogSentryIntegration {
111
115
  organization,
112
116
  projectId,
113
117
  prefix,
114
- severityAllowList
118
+ severityAllowList,
119
+ sendExceptionsToPostHog: sendExceptionsToPostHog ?? true
115
120
  }));
116
121
  };
117
122
  }
@@ -1184,7 +1189,7 @@ function snipLine(line, colno) {
1184
1189
  return newLine;
1185
1190
  }
1186
1191
 
1187
- var version = "5.8.2";
1192
+ var version = "5.8.4";
1188
1193
 
1189
1194
  /**
1190
1195
  * A lazy value that is only computed when needed. Inspired by C#'s Lazy<T> class.
@@ -1371,12 +1376,14 @@ class FeatureFlagsPoller {
1371
1376
  const payloads = {};
1372
1377
  let fallbackToFlags = this.featureFlags.length == 0;
1373
1378
  const flagsToEvaluate = flagKeysToExplicitlyEvaluate ? flagKeysToExplicitlyEvaluate.map(key => this.featureFlagsByKey[key]).filter(Boolean) : this.featureFlags;
1379
+ // Create a shared evaluation cache to prevent memory leaks when processing many flags
1380
+ const sharedEvaluationCache = {};
1374
1381
  await Promise.all(flagsToEvaluate.map(async flag => {
1375
1382
  try {
1376
1383
  const {
1377
1384
  value: matchValue,
1378
1385
  payload: matchPayload
1379
- } = await this.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties);
1386
+ } = await this.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties, undefined /* matchValue */, sharedEvaluationCache);
1380
1387
  response[flag.key] = matchValue;
1381
1388
  if (matchPayload) {
1382
1389
  payloads[flag.key] = matchPayload;
@@ -1396,9 +1403,11 @@ class FeatureFlagsPoller {
1396
1403
  fallbackToFlags
1397
1404
  };
1398
1405
  }
1399
- async computeFlagAndPayloadLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, matchValue) {
1400
- // Always ensure flags are loaded for payload computation
1401
- await this.loadFeatureFlags();
1406
+ async computeFlagAndPayloadLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, matchValue, evaluationCache, skipLoadCheck = false) {
1407
+ // Only load flags if not already loaded and not skipping the check
1408
+ if (!skipLoadCheck) {
1409
+ await this.loadFeatureFlags();
1410
+ }
1402
1411
  if (!this.loadedSuccessfullyOnce) {
1403
1412
  return {
1404
1413
  value: false,
@@ -1410,7 +1419,7 @@ class FeatureFlagsPoller {
1410
1419
  if (matchValue !== undefined) {
1411
1420
  flagValue = matchValue;
1412
1421
  } else {
1413
- flagValue = await this.computeFlagValueLocally(flag, distinctId, groups, personProperties, groupProperties);
1422
+ flagValue = await this.computeFlagValueLocally(flag, distinctId, groups, personProperties, groupProperties, evaluationCache);
1414
1423
  }
1415
1424
  // Always compute payload based on the final flagValue (whether provided or computed)
1416
1425
  const payload = this.getFeatureFlagPayload(flag.key, flagValue);
@@ -1419,7 +1428,7 @@ class FeatureFlagsPoller {
1419
1428
  payload
1420
1429
  };
1421
1430
  }
1422
- async computeFlagValueLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
1431
+ async computeFlagValueLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, evaluationCache = {}) {
1423
1432
  if (flag.ensure_experience_continuity) {
1424
1433
  throw new InconclusiveMatchError('Flag has experience continuity enabled');
1425
1434
  }
@@ -1439,9 +1448,9 @@ class FeatureFlagsPoller {
1439
1448
  return false;
1440
1449
  }
1441
1450
  const focusedGroupProperties = groupProperties[groupName];
1442
- return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties);
1451
+ return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties, evaluationCache);
1443
1452
  } else {
1444
- return await this.matchFeatureFlagProperties(flag, distinctId, personProperties);
1453
+ return await this.matchFeatureFlagProperties(flag, distinctId, personProperties, evaluationCache);
1445
1454
  }
1446
1455
  }
1447
1456
  getFeatureFlagPayload(key, flagValue) {