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.
@@ -24,13 +24,15 @@ var core = require('@posthog/core');
24
24
  * @param {Number} [projectId] Optional: The Sentry project id, used to send a direct link from PostHog to Sentry
25
25
  * @param {string} [prefix] Optional: Url of a self-hosted sentry instance (default: https://sentry.io/organizations/)
26
26
  * @param {SeverityLevel[] | '*'} [severityAllowList] Optional: send events matching the provided levels. Use '*' to send all events (default: ['error'])
27
+ * @param {boolean} [sendExceptionsToPostHog] Optional: capture exceptions as events in PostHog (default: true)
27
28
  */
28
29
  const NAME = 'posthog-node';
29
30
  function createEventProcessor(_posthog, {
30
31
  organization,
31
32
  projectId,
32
33
  prefix,
33
- severityAllowList = ['error']
34
+ severityAllowList = ['error'],
35
+ sendExceptionsToPostHog = true
34
36
  } = {}) {
35
37
  return event => {
36
38
  const shouldProcessLevel = severityAllowList === '*' || severityAllowList.includes(event.level);
@@ -80,11 +82,13 @@ function createEventProcessor(_posthog, {
80
82
  if (organization && projectId) {
81
83
  properties['$sentry_url'] = (prefix || 'https://sentry.io/organizations/') + organization + '/issues/?project=' + projectId + '&query=' + event.event_id;
82
84
  }
83
- _posthog.capture({
84
- event: '$exception',
85
- distinctId: userId,
86
- properties
87
- });
85
+ if (sendExceptionsToPostHog) {
86
+ _posthog.capture({
87
+ event: '$exception',
88
+ distinctId: userId,
89
+ properties
90
+ });
91
+ }
88
92
  return event;
89
93
  };
90
94
  }
@@ -100,7 +104,7 @@ function sentryIntegration(_posthog, options) {
100
104
  }
101
105
  // V7 integration - class based
102
106
  class PostHogSentryIntegration {
103
- constructor(_posthog, organization, prefix, severityAllowList) {
107
+ constructor(_posthog, organization, prefix, severityAllowList, sendExceptionsToPostHog) {
104
108
  this.name = NAME;
105
109
  // setupOnce gets called by Sentry when it intializes the plugin
106
110
  this.name = NAME;
@@ -110,7 +114,8 @@ class PostHogSentryIntegration {
110
114
  organization,
111
115
  projectId,
112
116
  prefix,
113
- severityAllowList
117
+ severityAllowList,
118
+ sendExceptionsToPostHog: sendExceptionsToPostHog ?? true
114
119
  }));
115
120
  };
116
121
  }
@@ -780,7 +785,7 @@ function setupExpressErrorHandler(_posthog, app) {
780
785
  });
781
786
  }
782
787
 
783
- var version = "5.8.2";
788
+ var version = "5.8.4";
784
789
 
785
790
  /**
786
791
  * A lazy value that is only computed when needed. Inspired by C#'s Lazy<T> class.
@@ -967,12 +972,14 @@ class FeatureFlagsPoller {
967
972
  const payloads = {};
968
973
  let fallbackToFlags = this.featureFlags.length == 0;
969
974
  const flagsToEvaluate = flagKeysToExplicitlyEvaluate ? flagKeysToExplicitlyEvaluate.map(key => this.featureFlagsByKey[key]).filter(Boolean) : this.featureFlags;
975
+ // Create a shared evaluation cache to prevent memory leaks when processing many flags
976
+ const sharedEvaluationCache = {};
970
977
  await Promise.all(flagsToEvaluate.map(async flag => {
971
978
  try {
972
979
  const {
973
980
  value: matchValue,
974
981
  payload: matchPayload
975
- } = await this.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties);
982
+ } = await this.computeFlagAndPayloadLocally(flag, distinctId, groups, personProperties, groupProperties, undefined /* matchValue */, sharedEvaluationCache);
976
983
  response[flag.key] = matchValue;
977
984
  if (matchPayload) {
978
985
  payloads[flag.key] = matchPayload;
@@ -992,9 +999,11 @@ class FeatureFlagsPoller {
992
999
  fallbackToFlags
993
1000
  };
994
1001
  }
995
- async computeFlagAndPayloadLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, matchValue) {
996
- // Always ensure flags are loaded for payload computation
997
- await this.loadFeatureFlags();
1002
+ async computeFlagAndPayloadLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, matchValue, evaluationCache, skipLoadCheck = false) {
1003
+ // Only load flags if not already loaded and not skipping the check
1004
+ if (!skipLoadCheck) {
1005
+ await this.loadFeatureFlags();
1006
+ }
998
1007
  if (!this.loadedSuccessfullyOnce) {
999
1008
  return {
1000
1009
  value: false,
@@ -1006,7 +1015,7 @@ class FeatureFlagsPoller {
1006
1015
  if (matchValue !== undefined) {
1007
1016
  flagValue = matchValue;
1008
1017
  } else {
1009
- flagValue = await this.computeFlagValueLocally(flag, distinctId, groups, personProperties, groupProperties);
1018
+ flagValue = await this.computeFlagValueLocally(flag, distinctId, groups, personProperties, groupProperties, evaluationCache);
1010
1019
  }
1011
1020
  // Always compute payload based on the final flagValue (whether provided or computed)
1012
1021
  const payload = this.getFeatureFlagPayload(flag.key, flagValue);
@@ -1015,7 +1024,7 @@ class FeatureFlagsPoller {
1015
1024
  payload
1016
1025
  };
1017
1026
  }
1018
- async computeFlagValueLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
1027
+ async computeFlagValueLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}, evaluationCache = {}) {
1019
1028
  if (flag.ensure_experience_continuity) {
1020
1029
  throw new InconclusiveMatchError('Flag has experience continuity enabled');
1021
1030
  }
@@ -1035,9 +1044,9 @@ class FeatureFlagsPoller {
1035
1044
  return false;
1036
1045
  }
1037
1046
  const focusedGroupProperties = groupProperties[groupName];
1038
- return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties);
1047
+ return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties, evaluationCache);
1039
1048
  } else {
1040
- return await this.matchFeatureFlagProperties(flag, distinctId, personProperties);
1049
+ return await this.matchFeatureFlagProperties(flag, distinctId, personProperties, evaluationCache);
1041
1050
  }
1042
1051
  }
1043
1052
  getFeatureFlagPayload(key, flagValue) {