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