posthog-node 5.1.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,13 @@
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
+
7
+ # 5.2.1 - 2025-07-07
8
+
9
+ 1. feat: add captureExceptionImmediate method on posthog client
10
+
3
11
  # 5.1.1 - 2025-06-16
4
12
 
5
13
  1. fix: Handle double-encoded JSON payloads from the remote config endpoint
@@ -877,7 +877,7 @@ function applyChunkIds(frames, parser) {
877
877
 
878
878
  const SHUTDOWN_TIMEOUT = 2000;
879
879
  class ErrorTracking {
880
- static async captureException(client, error, hint, distinctId, additionalProperties) {
880
+ static async buildEventMessage(error, hint, distinctId, additionalProperties) {
881
881
  const properties = {
882
882
  ...additionalProperties
883
883
  };
@@ -887,14 +887,14 @@ class ErrorTracking {
887
887
  properties.$process_person_profile = false;
888
888
  }
889
889
  const exceptionProperties = await propertiesFromUnknownInput(this.stackParser, this.frameModifiers, error, hint);
890
- client.capture({
890
+ return {
891
891
  event: '$exception',
892
892
  distinctId: distinctId || uuidv7(),
893
893
  properties: {
894
894
  ...exceptionProperties,
895
895
  ...properties
896
896
  }
897
- });
897
+ };
898
898
  }
899
899
  constructor(client, options) {
900
900
  this.client = client;
@@ -908,7 +908,9 @@ class ErrorTracking {
908
908
  }
909
909
  }
910
910
  onException(exception, hint) {
911
- ErrorTracking.captureException(this.client, exception, hint);
911
+ void ErrorTracking.buildEventMessage(exception, hint).then(msg => {
912
+ this.client.capture(msg);
913
+ });
912
914
  }
913
915
  async onFatalError() {
914
916
  await this.client.shutdown(SHUTDOWN_TIMEOUT);
@@ -928,14 +930,14 @@ function setupExpressErrorHandler(_posthog, app) {
928
930
  };
929
931
  // Given stateless nature of Node SDK we capture exceptions using personless processing
930
932
  // when no user can be determined e.g. in the case of exception autocapture
931
- ErrorTracking.captureException(_posthog, error, hint, uuidv7(), {
933
+ ErrorTracking.buildEventMessage(error, hint, uuidv7(), {
932
934
  $process_person_profile: false
933
- });
935
+ }).then(msg => _posthog.capture(msg));
934
936
  next(error);
935
937
  });
936
938
  }
937
939
 
938
- var version = "5.1.1";
940
+ var version = "5.3.1";
939
941
 
940
942
  var PostHogPersistedProperty;
941
943
  (function (PostHogPersistedProperty) {
@@ -973,6 +975,12 @@ var Compression;
973
975
  })(Compression || (Compression = {}));
974
976
  var SurveyPosition;
975
977
  (function (SurveyPosition) {
978
+ SurveyPosition["TopLeft"] = "top_left";
979
+ SurveyPosition["TopCenter"] = "top_center";
980
+ SurveyPosition["TopRight"] = "top_right";
981
+ SurveyPosition["MiddleLeft"] = "middle_left";
982
+ SurveyPosition["MiddleCenter"] = "middle_center";
983
+ SurveyPosition["MiddleRight"] = "middle_right";
976
984
  SurveyPosition["Left"] = "left";
977
985
  SurveyPosition["Right"] = "right";
978
986
  SurveyPosition["Center"] = "center";
@@ -2493,23 +2501,6 @@ class FeatureFlagsPoller {
2493
2501
  stopPoller() {
2494
2502
  clearTimeout(this.poller);
2495
2503
  }
2496
- _requestRemoteConfigPayload(flagKey) {
2497
- const url = `${this.host}/api/projects/@current/feature_flags/${flagKey}/remote_config/`;
2498
- const options = this.getPersonalApiKeyRequestOptions();
2499
- let abortTimeout = null;
2500
- if (this.timeout && typeof this.timeout === 'number') {
2501
- const controller = new AbortController();
2502
- abortTimeout = safeSetTimeout(() => {
2503
- controller.abort();
2504
- }, this.timeout);
2505
- options.signal = controller.signal;
2506
- }
2507
- try {
2508
- return this.fetch(url, options);
2509
- } finally {
2510
- clearTimeout(abortTimeout);
2511
- }
2512
- }
2513
2504
  }
2514
2505
  // # This function takes a distinct_id and a feature flag key and returns a float between 0 and 1.
2515
2506
  // # Given the same distinct_id and key, it'll always return the same float. These floats are
@@ -2794,21 +2785,25 @@ class PostHogBackendClient extends PostHogCoreStateless {
2794
2785
  if (options.personalApiKey.includes('phc_')) {
2795
2786
  throw new Error('Your Personal API key is invalid. These keys are prefixed with "phx_" and can be created in PostHog project settings.');
2796
2787
  }
2797
- this.featureFlagsPoller = new FeatureFlagsPoller({
2798
- pollingInterval: this.options.featureFlagsPollingInterval,
2799
- personalApiKey: options.personalApiKey,
2800
- projectApiKey: apiKey,
2801
- timeout: options.requestTimeout ?? 10000,
2802
- host: this.host,
2803
- fetch: options.fetch,
2804
- onError: err => {
2805
- this._events.emit('error', err);
2806
- },
2807
- onLoad: count => {
2808
- this._events.emit('localEvaluationFlagsLoaded', count);
2809
- },
2810
- customHeaders: this.getCustomHeaders()
2811
- });
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
+ }
2812
2807
  }
2813
2808
  this.errorTracking = new ErrorTracking(this, options);
2814
2809
  this.distinctIdHasSentFlagCalls = {};
@@ -3164,7 +3159,10 @@ class PostHogBackendClient extends PostHogCoreStateless {
3164
3159
  return response;
3165
3160
  }
3166
3161
  async getRemoteConfigPayload(flagKey) {
3167
- 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);
3168
3166
  if (!response) {
3169
3167
  return undefined;
3170
3168
  }
@@ -3258,6 +3256,38 @@ class PostHogBackendClient extends PostHogCoreStateless {
3258
3256
  this.featureFlagsPoller?.stopPoller();
3259
3257
  return super._shutdown(shutdownTimeoutMs);
3260
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
+ }
3261
3291
  addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties) {
3262
3292
  const allPersonProperties = {
3263
3293
  distinct_id: distinctId,
@@ -3279,9 +3309,18 @@ class PostHogBackendClient extends PostHogCoreStateless {
3279
3309
  }
3280
3310
  captureException(error, distinctId, additionalProperties) {
3281
3311
  const syntheticException = new Error('PostHog syntheticException');
3282
- ErrorTracking.captureException(this, error, {
3312
+ ErrorTracking.buildEventMessage(error, {
3313
+ syntheticException
3314
+ }, distinctId, additionalProperties).then(msg => {
3315
+ this.capture(msg);
3316
+ });
3317
+ }
3318
+ async captureExceptionImmediate(error, distinctId, additionalProperties) {
3319
+ const syntheticException = new Error('PostHog syntheticException');
3320
+ const evtMsg = await ErrorTracking.buildEventMessage(error, {
3283
3321
  syntheticException
3284
3322
  }, distinctId, additionalProperties);
3323
+ return await this.captureImmediate(evtMsg);
3285
3324
  }
3286
3325
  }
3287
3326