posthog-node 5.2.1 → 5.3.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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # Next
2
2
 
3
+ # 5.3.1 - 2025-07-07
4
+
5
+ 1. feat: decouple feature flag local evaluation from personal API keys; support decrypting remote config payloads without relying on the feature flags poller
6
+
3
7
  # 5.2.1 - 2025-07-07
4
8
 
5
9
  1. feat: add captureExceptionImmediate method on posthog client
@@ -937,7 +937,7 @@ function setupExpressErrorHandler(_posthog, app) {
937
937
  });
938
938
  }
939
939
 
940
- var version = "5.2.1";
940
+ var version = "5.3.1";
941
941
 
942
942
  var PostHogPersistedProperty;
943
943
  (function (PostHogPersistedProperty) {
@@ -2501,23 +2501,6 @@ class FeatureFlagsPoller {
2501
2501
  stopPoller() {
2502
2502
  clearTimeout(this.poller);
2503
2503
  }
2504
- _requestRemoteConfigPayload(flagKey) {
2505
- const url = `${this.host}/api/projects/@current/feature_flags/${flagKey}/remote_config/`;
2506
- const options = this.getPersonalApiKeyRequestOptions();
2507
- let abortTimeout = null;
2508
- if (this.timeout && typeof this.timeout === 'number') {
2509
- const controller = new AbortController();
2510
- abortTimeout = safeSetTimeout(() => {
2511
- controller.abort();
2512
- }, this.timeout);
2513
- options.signal = controller.signal;
2514
- }
2515
- try {
2516
- return this.fetch(url, options);
2517
- } finally {
2518
- clearTimeout(abortTimeout);
2519
- }
2520
- }
2521
2504
  }
2522
2505
  // # This function takes a distinct_id and a feature flag key and returns a float between 0 and 1.
2523
2506
  // # Given the same distinct_id and key, it'll always return the same float. These floats are
@@ -2802,21 +2785,25 @@ class PostHogBackendClient extends PostHogCoreStateless {
2802
2785
  if (options.personalApiKey.includes('phc_')) {
2803
2786
  throw new Error('Your Personal API key is invalid. These keys are prefixed with "phx_" and can be created in PostHog project settings.');
2804
2787
  }
2805
- this.featureFlagsPoller = new FeatureFlagsPoller({
2806
- pollingInterval: this.options.featureFlagsPollingInterval,
2807
- personalApiKey: options.personalApiKey,
2808
- projectApiKey: apiKey,
2809
- timeout: options.requestTimeout ?? 10000,
2810
- host: this.host,
2811
- fetch: options.fetch,
2812
- onError: err => {
2813
- this._events.emit('error', err);
2814
- },
2815
- onLoad: count => {
2816
- this._events.emit('localEvaluationFlagsLoaded', count);
2817
- },
2818
- customHeaders: this.getCustomHeaders()
2819
- });
2788
+ // Only start the poller if local evaluation is enabled (defaults to true for backward compatibility)
2789
+ const shouldEnableLocalEvaluation = options.enableLocalEvaluation !== false;
2790
+ if (shouldEnableLocalEvaluation) {
2791
+ this.featureFlagsPoller = new FeatureFlagsPoller({
2792
+ pollingInterval: this.options.featureFlagsPollingInterval,
2793
+ personalApiKey: options.personalApiKey,
2794
+ projectApiKey: apiKey,
2795
+ timeout: options.requestTimeout ?? 10000,
2796
+ host: this.host,
2797
+ fetch: options.fetch,
2798
+ onError: err => {
2799
+ this._events.emit('error', err);
2800
+ },
2801
+ onLoad: count => {
2802
+ this._events.emit('localEvaluationFlagsLoaded', count);
2803
+ },
2804
+ customHeaders: this.getCustomHeaders()
2805
+ });
2806
+ }
2820
2807
  }
2821
2808
  this.errorTracking = new ErrorTracking(this, options);
2822
2809
  this.distinctIdHasSentFlagCalls = {};
@@ -3172,7 +3159,10 @@ class PostHogBackendClient extends PostHogCoreStateless {
3172
3159
  return response;
3173
3160
  }
3174
3161
  async getRemoteConfigPayload(flagKey) {
3175
- const response = await this.featureFlagsPoller?._requestRemoteConfigPayload(flagKey);
3162
+ if (!this.options.personalApiKey) {
3163
+ throw new Error('Personal API key is required for remote config payload decryption');
3164
+ }
3165
+ const response = await this._requestRemoteConfigPayload(flagKey);
3176
3166
  if (!response) {
3177
3167
  return undefined;
3178
3168
  }
@@ -3266,6 +3256,38 @@ class PostHogBackendClient extends PostHogCoreStateless {
3266
3256
  this.featureFlagsPoller?.stopPoller();
3267
3257
  return super._shutdown(shutdownTimeoutMs);
3268
3258
  }
3259
+ async _requestRemoteConfigPayload(flagKey) {
3260
+ if (!this.options.personalApiKey) {
3261
+ return undefined;
3262
+ }
3263
+ const url = `${this.host}/api/projects/@current/feature_flags/${flagKey}/remote_config/`;
3264
+ const options = {
3265
+ method: 'GET',
3266
+ headers: {
3267
+ ...this.getCustomHeaders(),
3268
+ 'Content-Type': 'application/json',
3269
+ Authorization: `Bearer ${this.options.personalApiKey}`
3270
+ }
3271
+ };
3272
+ let abortTimeout = null;
3273
+ if (this.options.requestTimeout && typeof this.options.requestTimeout === 'number') {
3274
+ const controller = new AbortController();
3275
+ abortTimeout = safeSetTimeout(() => {
3276
+ controller.abort();
3277
+ }, this.options.requestTimeout);
3278
+ options.signal = controller.signal;
3279
+ }
3280
+ try {
3281
+ return await this.fetch(url, options);
3282
+ } catch (error) {
3283
+ this._events.emit('error', error);
3284
+ return undefined;
3285
+ } finally {
3286
+ if (abortTimeout) {
3287
+ clearTimeout(abortTimeout);
3288
+ }
3289
+ }
3290
+ }
3269
3291
  addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties) {
3270
3292
  const allPersonProperties = {
3271
3293
  distinct_id: distinctId,