posthog-node 5.4.0 → 5.5.1
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 +53 -1
- package/lib/edge/index.cjs +44 -15
- package/lib/edge/index.cjs.map +1 -1
- package/lib/edge/index.mjs +44 -15
- package/lib/edge/index.mjs.map +1 -1
- package/lib/index.d.ts +7 -2
- package/lib/node/index.cjs +44 -15
- package/lib/node/index.cjs.map +1 -1
- package/lib/node/index.mjs +44 -15
- package/lib/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,57 @@
|
|
|
1
1
|
# Next
|
|
2
2
|
|
|
3
|
-
# 5.
|
|
3
|
+
# 5.5.1 – 2025-07-15
|
|
4
|
+
|
|
5
|
+
1. wrap `InconclusiveMatchError`s in `logMsgIfDebug` for local flag evaluations on `sendFeatureFlags`
|
|
6
|
+
|
|
7
|
+
# 5.5.0 – 2025-07-10
|
|
8
|
+
|
|
9
|
+
1. feat: make the `sendFeatureFlags` parameter more declarative and ergonomic. Implementation notes below:
|
|
10
|
+
|
|
11
|
+
Modified `sendFeatureFlags` to be type `boolean | SendFeatureFlagsOptions`, (which is defined thusly)
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
export interface SendFeatureFlagsOptions {
|
|
15
|
+
onlyEvaluateLocally?: boolean
|
|
16
|
+
personProperties?: Record<string, any>
|
|
17
|
+
groupProperties?: Record<string, Record<string, any>>
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
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.
|
|
22
|
+
|
|
23
|
+
Now, you can make calls like this
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
posthog.captureImmediate({
|
|
27
|
+
distinctId: "user123",
|
|
28
|
+
event: "test event",
|
|
29
|
+
sendFeatureFlags: {
|
|
30
|
+
onlyEvaluateLocally: true,
|
|
31
|
+
personProperties: {
|
|
32
|
+
plan: "premium",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
properties: {
|
|
36
|
+
foo: "bar",
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
or simply
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
posthog.captureImmediate({
|
|
45
|
+
distinctId: "user123",
|
|
46
|
+
event: "test event",
|
|
47
|
+
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
|
|
48
|
+
properties: {
|
|
49
|
+
foo: "bar",
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
# 5.4.0 – 2025-07-09
|
|
4
55
|
|
|
5
56
|
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
57
|
|
|
@@ -31,6 +82,7 @@ feat: respect local evaluation preferences with `sendFeatureFlags`; add property
|
|
|
31
82
|
## Breaking changes
|
|
32
83
|
|
|
33
84
|
1. feat: migrate to native fetch, Node 20+ required
|
|
85
|
+
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
86
|
|
|
35
87
|
# 5.0.0-alpha.1 - 2025-04-29
|
|
36
88
|
|
package/lib/edge/index.cjs
CHANGED
|
@@ -937,7 +937,7 @@ function setupExpressErrorHandler(_posthog, app) {
|
|
|
937
937
|
});
|
|
938
938
|
}
|
|
939
939
|
|
|
940
|
-
var version = "5.
|
|
940
|
+
var version = "5.5.1";
|
|
941
941
|
|
|
942
942
|
var PostHogPersistedProperty;
|
|
943
943
|
(function (PostHogPersistedProperty) {
|
|
@@ -2232,7 +2232,7 @@ class FeatureFlagsPoller {
|
|
|
2232
2232
|
}
|
|
2233
2233
|
} catch (e) {
|
|
2234
2234
|
if (e instanceof InconclusiveMatchError) {
|
|
2235
|
-
this.
|
|
2235
|
+
this.logMsgIfDebug(() => console.debug(`InconclusiveMatchError when computing flag locally: ${flag.key}: ${e}`));
|
|
2236
2236
|
} else if (e instanceof Error) {
|
|
2237
2237
|
this.onError?.(new Error(`Error computing flag locally: ${flag.key}: ${e}`));
|
|
2238
2238
|
}
|
|
@@ -2329,6 +2329,9 @@ class FeatureFlagsPoller {
|
|
|
2329
2329
|
let matches = false;
|
|
2330
2330
|
if (propertyType === 'cohort') {
|
|
2331
2331
|
matches = matchCohort(prop, properties, this.cohorts, this.debugMode);
|
|
2332
|
+
} else if (propertyType === 'flag') {
|
|
2333
|
+
this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Flag dependency filters are not supported in local evaluation. ` + `Skipping condition for flag '${flag.key}' with dependency on flag '${prop.key || 'unknown'}'`));
|
|
2334
|
+
continue;
|
|
2332
2335
|
} else {
|
|
2333
2336
|
matches = matchProperty(prop, properties, warnFunction);
|
|
2334
2337
|
}
|
|
@@ -2666,6 +2669,11 @@ function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties, deb
|
|
|
2666
2669
|
let matches;
|
|
2667
2670
|
if (prop.type === 'cohort') {
|
|
2668
2671
|
matches = matchCohort(prop, propertyValues, cohortProperties, debugMode);
|
|
2672
|
+
} else if (prop.type === 'flag') {
|
|
2673
|
+
if (debugMode) {
|
|
2674
|
+
console.warn(`[FEATURE FLAGS] Flag dependency filters are not supported in local evaluation. ` + `Skipping condition with dependency on flag '${prop.key || 'unknown'}'`);
|
|
2675
|
+
}
|
|
2676
|
+
continue;
|
|
2669
2677
|
} else {
|
|
2670
2678
|
matches = matchProperty(prop, propertyValues);
|
|
2671
2679
|
}
|
|
@@ -2861,7 +2869,8 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2861
2869
|
const capturePromise = Promise.resolve().then(async () => {
|
|
2862
2870
|
if (sendFeatureFlags) {
|
|
2863
2871
|
// If we are sending feature flags, we evaluate them locally if the user prefers it, otherwise we fall back to remote evaluation
|
|
2864
|
-
|
|
2872
|
+
const sendFeatureFlagsOptions = typeof sendFeatureFlags === 'object' ? sendFeatureFlags : undefined;
|
|
2873
|
+
return await this.getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions);
|
|
2865
2874
|
}
|
|
2866
2875
|
if (event === '$feature_flag_called') {
|
|
2867
2876
|
// 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 +2927,8 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
2918
2927
|
const capturePromise = Promise.resolve().then(async () => {
|
|
2919
2928
|
if (sendFeatureFlags) {
|
|
2920
2929
|
// If we are sending feature flags, we evaluate them locally if the user prefers it, otherwise we fall back to remote evaluation
|
|
2921
|
-
|
|
2930
|
+
const sendFeatureFlagsOptions = typeof sendFeatureFlags === 'object' ? sendFeatureFlags : undefined;
|
|
2931
|
+
return await this.getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions);
|
|
2922
2932
|
}
|
|
2923
2933
|
if (event === '$feature_flag_called') {
|
|
2924
2934
|
// 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 +3295,32 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3285
3295
|
groupProperties
|
|
3286
3296
|
};
|
|
3287
3297
|
}
|
|
3288
|
-
async getFeatureFlagsForEvent(distinctId, groups,
|
|
3289
|
-
//
|
|
3290
|
-
const {
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
//
|
|
3298
|
+
async getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions) {
|
|
3299
|
+
// Use properties directly from options if they exist
|
|
3300
|
+
const finalPersonProperties = sendFeatureFlagsOptions?.personProperties || {};
|
|
3301
|
+
const finalGroupProperties = sendFeatureFlagsOptions?.groupProperties || {};
|
|
3302
|
+
// Check if we should only evaluate locally
|
|
3303
|
+
const onlyEvaluateLocally = sendFeatureFlagsOptions?.onlyEvaluateLocally ?? false;
|
|
3304
|
+
// If onlyEvaluateLocally is true, only use local evaluation
|
|
3305
|
+
if (onlyEvaluateLocally) {
|
|
3306
|
+
if ((this.featureFlagsPoller?.featureFlags?.length || 0) > 0) {
|
|
3307
|
+
const groupsWithStringValues = {};
|
|
3308
|
+
for (const [key, value] of Object.entries(groups || {})) {
|
|
3309
|
+
groupsWithStringValues[key] = String(value);
|
|
3310
|
+
}
|
|
3311
|
+
return await this.getAllFlags(distinctId, {
|
|
3312
|
+
groups: groupsWithStringValues,
|
|
3313
|
+
personProperties: finalPersonProperties,
|
|
3314
|
+
groupProperties: finalGroupProperties,
|
|
3315
|
+
disableGeoip,
|
|
3316
|
+
onlyEvaluateLocally: true
|
|
3317
|
+
});
|
|
3318
|
+
} else {
|
|
3319
|
+
// If onlyEvaluateLocally is true but we don't have local flags, return empty
|
|
3320
|
+
return {};
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
// 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
3324
|
if ((this.featureFlagsPoller?.featureFlags?.length || 0) > 0) {
|
|
3296
3325
|
const groupsWithStringValues = {};
|
|
3297
3326
|
for (const [key, value] of Object.entries(groups || {})) {
|
|
@@ -3299,14 +3328,14 @@ class PostHogBackendClient extends PostHogCoreStateless {
|
|
|
3299
3328
|
}
|
|
3300
3329
|
return await this.getAllFlags(distinctId, {
|
|
3301
3330
|
groups: groupsWithStringValues,
|
|
3302
|
-
personProperties:
|
|
3303
|
-
groupProperties:
|
|
3331
|
+
personProperties: finalPersonProperties,
|
|
3332
|
+
groupProperties: finalGroupProperties,
|
|
3304
3333
|
disableGeoip,
|
|
3305
3334
|
onlyEvaluateLocally: true
|
|
3306
3335
|
});
|
|
3307
3336
|
}
|
|
3308
|
-
// Fall back to remote evaluation if local evaluation is not available
|
|
3309
|
-
return (await super.getFeatureFlagsStateless(distinctId, groups,
|
|
3337
|
+
// Fall back to remote evaluation if local evaluation is not available
|
|
3338
|
+
return (await super.getFeatureFlagsStateless(distinctId, groups, finalPersonProperties, finalGroupProperties, disableGeoip)).flags;
|
|
3310
3339
|
}
|
|
3311
3340
|
addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties) {
|
|
3312
3341
|
const allPersonProperties = {
|