posthog-node 5.4.0 → 5.5.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,6 +1,53 @@
1
1
  # Next
2
2
 
3
- # 5.4.0 – 2025-09-07
3
+ # 5.5.0 – 2025-07-10
4
+
5
+ 1. feat: make the `sendFeatureFlags` parameter more declarative and ergonomic. Implementation notes below:
6
+
7
+ Modified `sendFeatureFlags` to be type `boolean | SendFeatureFlagsOptions`, (which is defined thusly)
8
+
9
+ ```ts
10
+ export interface SendFeatureFlagsOptions {
11
+ onlyEvaluateLocally?: boolean
12
+ personProperties?: Record<string, any>
13
+ groupProperties?: Record<string, Record<string, any>>
14
+ }
15
+ ```
16
+
17
+ This lets users declare (1) whether to use local evaluation, and (2) which properties to supply explicitly for that evaluation, every time they want to send feature flags. It also supports the old boolean behavior if folks don't care and would rather the SDK infer it.
18
+
19
+ Now, you can make calls like this
20
+
21
+ ```ts
22
+ posthog.captureImmediate({
23
+ distinctId: "user123",
24
+ event: "test event",
25
+ sendFeatureFlags: {
26
+ onlyEvaluateLocally: true,
27
+ personProperties: {
28
+ plan: "premium",
29
+ },
30
+ },
31
+ properties: {
32
+ foo: "bar",
33
+ },
34
+ });
35
+ ```
36
+
37
+ or simply
38
+
39
+ ```
40
+ posthog.captureImmediate({
41
+ distinctId: "user123",
42
+ event: "test event",
43
+ sendFeatureFlags: true // this will still infer local evaluation if it appears to be configured, but it won't try to pull properties from the event message
44
+ properties: {
45
+ foo: "bar",
46
+ },
47
+ });
48
+ ```
49
+
50
+ # 5.4.0 – 2025-07-09
4
51
 
5
52
  feat: respect local evaluation preferences with `sendFeatureFlags`; add property overrides from the event to those local computations so that the locally evaluated flags can be more accuratee. NB: this change chagnes the default behavior of `capture` and `captureImmediately` – we will now only send feature flag data along with those events if `sendFeatureFlags` is explicitly specified, instead of optimistically sending along locally evaluated flags by default.
6
53
 
@@ -31,6 +78,7 @@ feat: respect local evaluation preferences with `sendFeatureFlags`; add property
31
78
  ## Breaking changes
32
79
 
33
80
  1. feat: migrate to native fetch, Node 20+ required
81
+ 2. PostHog Node now compresses messages with GZip before sending them to our servers when the runtime supports compression. This reduces network bandwidth and improves performance. Network traffic interceptors and test assertions on payloads must handle GZip decompression to inspect the data. Alternatively, you can disable compression by setting `disableCompression: true` in the client configuration during tests.
34
82
 
35
83
  # 5.0.0-alpha.1 - 2025-04-29
36
84
 
@@ -937,7 +937,7 @@ function setupExpressErrorHandler(_posthog, app) {
937
937
  });
938
938
  }
939
939
 
940
- var version = "5.4.0";
940
+ var version = "5.5.0";
941
941
 
942
942
  var PostHogPersistedProperty;
943
943
  (function (PostHogPersistedProperty) {
@@ -2861,7 +2861,8 @@ class PostHogBackendClient extends PostHogCoreStateless {
2861
2861
  const capturePromise = Promise.resolve().then(async () => {
2862
2862
  if (sendFeatureFlags) {
2863
2863
  // If we are sending feature flags, we evaluate them locally if the user prefers it, otherwise we fall back to remote evaluation
2864
- return await this.getFeatureFlagsForEvent(distinctId, groups, properties, disableGeoip);
2864
+ const sendFeatureFlagsOptions = typeof sendFeatureFlags === 'object' ? sendFeatureFlags : undefined;
2865
+ return await this.getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions);
2865
2866
  }
2866
2867
  if (event === '$feature_flag_called') {
2867
2868
  // If we're capturing a $feature_flag_called event, we don't want to enrich the event with cached flags that may be out of date.
@@ -2918,7 +2919,8 @@ class PostHogBackendClient extends PostHogCoreStateless {
2918
2919
  const capturePromise = Promise.resolve().then(async () => {
2919
2920
  if (sendFeatureFlags) {
2920
2921
  // If we are sending feature flags, we evaluate them locally if the user prefers it, otherwise we fall back to remote evaluation
2921
- return await this.getFeatureFlagsForEvent(distinctId, groups, properties, disableGeoip);
2922
+ const sendFeatureFlagsOptions = typeof sendFeatureFlags === 'object' ? sendFeatureFlags : undefined;
2923
+ return await this.getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions);
2922
2924
  }
2923
2925
  if (event === '$feature_flag_called') {
2924
2926
  // If we're capturing a $feature_flag_called event, we don't want to enrich the event with cached flags that may be out of date.
@@ -3285,13 +3287,32 @@ class PostHogBackendClient extends PostHogCoreStateless {
3285
3287
  groupProperties
3286
3288
  };
3287
3289
  }
3288
- async getFeatureFlagsForEvent(distinctId, groups, eventProperties, disableGeoip) {
3289
- // Extract person and group properties from the event properties
3290
- const {
3291
- personProperties: cleanPersonProperties,
3292
- groupProperties: cleanGroupProperties
3293
- } = this.extractPropertiesFromEvent(eventProperties, groups);
3294
- // Prefer local evaluation if available
3290
+ async getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions) {
3291
+ // Use properties directly from options if they exist
3292
+ const finalPersonProperties = sendFeatureFlagsOptions?.personProperties || {};
3293
+ const finalGroupProperties = sendFeatureFlagsOptions?.groupProperties || {};
3294
+ // Check if we should only evaluate locally
3295
+ const onlyEvaluateLocally = sendFeatureFlagsOptions?.onlyEvaluateLocally ?? false;
3296
+ // If onlyEvaluateLocally is true, only use local evaluation
3297
+ if (onlyEvaluateLocally) {
3298
+ if ((this.featureFlagsPoller?.featureFlags?.length || 0) > 0) {
3299
+ const groupsWithStringValues = {};
3300
+ for (const [key, value] of Object.entries(groups || {})) {
3301
+ groupsWithStringValues[key] = String(value);
3302
+ }
3303
+ return await this.getAllFlags(distinctId, {
3304
+ groups: groupsWithStringValues,
3305
+ personProperties: finalPersonProperties,
3306
+ groupProperties: finalGroupProperties,
3307
+ disableGeoip,
3308
+ onlyEvaluateLocally: true
3309
+ });
3310
+ } else {
3311
+ // If onlyEvaluateLocally is true but we don't have local flags, return empty
3312
+ return {};
3313
+ }
3314
+ }
3315
+ // Prefer local evaluation if available (default behavior; I'd rather not penalize users who haven't updated to the new API but still want to use local evaluation)
3295
3316
  if ((this.featureFlagsPoller?.featureFlags?.length || 0) > 0) {
3296
3317
  const groupsWithStringValues = {};
3297
3318
  for (const [key, value] of Object.entries(groups || {})) {
@@ -3299,14 +3320,14 @@ class PostHogBackendClient extends PostHogCoreStateless {
3299
3320
  }
3300
3321
  return await this.getAllFlags(distinctId, {
3301
3322
  groups: groupsWithStringValues,
3302
- personProperties: cleanPersonProperties,
3303
- groupProperties: cleanGroupProperties,
3323
+ personProperties: finalPersonProperties,
3324
+ groupProperties: finalGroupProperties,
3304
3325
  disableGeoip,
3305
3326
  onlyEvaluateLocally: true
3306
3327
  });
3307
3328
  }
3308
- // Fall back to remote evaluation if local evaluation is not available/is not being used
3309
- return (await super.getFeatureFlagsStateless(distinctId, groups, cleanPersonProperties, cleanGroupProperties, disableGeoip)).flags;
3329
+ // Fall back to remote evaluation if local evaluation is not available
3330
+ return (await super.getFeatureFlagsStateless(distinctId, groups, finalPersonProperties, finalGroupProperties, disableGeoip)).flags;
3310
3331
  }
3311
3332
  addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties) {
3312
3333
  const allPersonProperties = {