posthog-js 1.29.3 → 1.31.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/dist/module.d.ts CHANGED
@@ -188,6 +188,11 @@ interface PostHogConfig {
188
188
  _onCapture: (eventName: string, eventData: CaptureResult) => void;
189
189
  _capture_metrics: boolean;
190
190
  _capture_performance: boolean;
191
+ bootstrap: {
192
+ distinctID?: string;
193
+ isIdentifiedID?: boolean;
194
+ featureFlags?: Record<string, boolean | string>;
195
+ };
191
196
  }
192
197
  interface OptInOutCapturingOptions {
193
198
  capture: (event: string, properties: Properties, options: CaptureOptions) => void;
@@ -418,7 +423,7 @@ declare class PostHogFeatureFlags {
418
423
  send_event?: boolean;
419
424
  }): boolean;
420
425
  addFeatureFlagsHandler(handler: FeatureFlagsCallback): void;
421
- receivedFeatureFlags(response: DecideResponse): void;
426
+ receivedFeatureFlags(response: Partial<DecideResponse>): void;
422
427
  override(flags: boolean | string[] | Record<string, string | boolean>): void;
423
428
  onFeatureFlags(callback: FeatureFlagsCallback): void;
424
429
  }
@@ -813,6 +818,7 @@ declare class SessionIdManager {
813
818
  _windowId: string | null | undefined;
814
819
  _sessionId: string | null | undefined;
815
820
  window_id_storage_key: string;
821
+ primary_window_exists_storage_key: string;
816
822
  _sessionStartTimestamp: number | null;
817
823
  _sessionActivityTimestamp: number | null;
818
824
  constructor(config: Partial<PostHogConfig>, persistence: PostHogPersistence);
@@ -821,6 +827,7 @@ declare class SessionIdManager {
821
827
  _setSessionId(sessionId: string | null, sessionActivityTimestamp: number | null, sessionStartTimestamp: number | null): void;
822
828
  _getSessionId(): [number, string, number];
823
829
  resetSessionId(): void;
830
+ _listenToReloadWindow(): void;
824
831
  checkAndGetSessionAndWindowId(readOnly?: boolean, _timestamp?: number | null): {
825
832
  sessionId: string;
826
833
  windowId: string;
@@ -925,6 +932,7 @@ declare class PostHog {
925
932
  * @param {Array} array
926
933
  */
927
934
  _execute_array(array: SnippetArrayItem[]): void;
935
+ _hasBootstrappedFeatureFlags(): boolean;
928
936
  /**
929
937
  * push() keeps the standard async-array-push
930
938
  * behavior around after the lib is loaded.
package/dist/module.js CHANGED
@@ -885,7 +885,7 @@ var LZString = {
885
885
  }
886
886
  };
887
887
 
888
- var version = "1.29.3";
888
+ var version = "1.31.0";
889
889
 
890
890
  // e.g. Config.DEBUG = Config.DEBUG || instance.get_config('debug')
891
891
 
@@ -3294,6 +3294,7 @@ var PostHogFeatureFlags = /*#__PURE__*/function () {
3294
3294
  }, {
3295
3295
  key: "receivedFeatureFlags",
3296
3296
  value: function receivedFeatureFlags(response) {
3297
+ this.instance.decideEndpointWasHit = true;
3297
3298
  parseFeatureFlagDecideResponse(response, this.instance.persistence);
3298
3299
  var flags = this.getFlags();
3299
3300
  var variants = this.getFlagVariants();
@@ -3971,8 +3972,9 @@ var Decide = /*#__PURE__*/function () {
3971
3972
  function Decide(instance) {
3972
3973
  _classCallCheck(this, Decide);
3973
3974
 
3974
- this.instance = instance;
3975
- this.instance.decideEndpointWasHit = false;
3975
+ this.instance = instance; // don't need to wait for `decide` to return if flags were provided on initialisation
3976
+
3977
+ this.instance.decideEndpointWasHit = this.instance._hasBootstrappedFeatureFlags();
3976
3978
  }
3977
3979
 
3978
3980
  _createClass(Decide, [{
@@ -5547,12 +5549,28 @@ var SessionIdManager = /*#__PURE__*/function () {
5547
5549
  this._sessionId = undefined;
5548
5550
  this._sessionStartTimestamp = null;
5549
5551
  this._sessionActivityTimestamp = null;
5552
+ var persistenceName = config['persistence_name'] || config['token'];
5553
+ this.window_id_storage_key = 'ph_' + persistenceName + '_window_id';
5554
+ this.primary_window_exists_storage_key = 'ph_' + persistenceName + '_primary_window_exists'; // primary_window_exists is set when the DOM has been loaded and is cleared on unload
5555
+ // if it exists here it means there was no unload which suggests this window is opened as a tab duplication, window.open, etc.
5556
+
5557
+ if (!this.persistence.disabled && sessionStore.is_supported()) {
5558
+ var lastWindowId = sessionStore.parse(this.window_id_storage_key);
5559
+ var primaryWindowExists = sessionStore.parse(this.primary_window_exists_storage_key);
5560
+
5561
+ if (lastWindowId && !primaryWindowExists) {
5562
+ // Persist window from previous storage state
5563
+ this._windowId = lastWindowId;
5564
+ } else {
5565
+ // Wipe any reference to previous window id
5566
+ sessionStore.remove(this.window_id_storage_key);
5567
+ } // Flag this session as having a primary window
5550
5568
 
5551
- if (config['persistence_name']) {
5552
- this.window_id_storage_key = 'ph_' + config['persistence_name'] + '_window_id';
5553
- } else {
5554
- this.window_id_storage_key = 'ph_' + config['token'] + '_window_id';
5569
+
5570
+ sessionStore.set(this.primary_window_exists_storage_key, true);
5555
5571
  }
5572
+
5573
+ this._listenToReloadWindow();
5556
5574
  } // Note: this tries to store the windowId in sessionStorage. SessionStorage is unique to the current window/tab,
5557
5575
  // and persists page loads/reloads. So it's uniquely suited for storing the windowId. This function also respects
5558
5576
  // when persistence is disabled (by user config) and when sessionStorage is not supported (it *should* be supported on all browsers),
@@ -5579,7 +5597,8 @@ var SessionIdManager = /*#__PURE__*/function () {
5579
5597
 
5580
5598
  if (!this.persistence.disabled && sessionStore.is_supported()) {
5581
5599
  return sessionStore.parse(this.window_id_storage_key);
5582
- }
5600
+ } // New window id will be generated
5601
+
5583
5602
 
5584
5603
  return null;
5585
5604
  } // Note: 'this.persistence.register' can be disabled in the config.
@@ -5618,6 +5637,24 @@ var SessionIdManager = /*#__PURE__*/function () {
5618
5637
  value: function resetSessionId() {
5619
5638
  this._setSessionId(null, null, null);
5620
5639
  }
5640
+ /*
5641
+ * Listens to window unloads and removes the primaryWindowExists key from sessionStorage.
5642
+ * Reloaded or fresh tabs created after a DOM unloads (reloading the same tab) WILL NOT have this primaryWindowExists flag in session storage.
5643
+ * Cloned sessions (new tab, tab duplication, window.open(), ...) WILL have this primaryWindowExists flag in their copied session storage.
5644
+ * We conditionally check the primaryWindowExists value in the constructor to decide if the window id in the last session storage should be carried over.
5645
+ */
5646
+
5647
+ }, {
5648
+ key: "_listenToReloadWindow",
5649
+ value: function _listenToReloadWindow() {
5650
+ var _this = this;
5651
+
5652
+ window.addEventListener('beforeunload', function () {
5653
+ if (!_this.persistence.disabled && sessionStore.is_supported()) {
5654
+ sessionStore.remove(_this.primary_window_exists_storage_key);
5655
+ }
5656
+ });
5657
+ }
5621
5658
  /*
5622
5659
  * This function returns the current sessionId and windowId. It should be used to
5623
5660
  * access these values over directly calling `._sessionId` or `._windowId`. In addition
@@ -5828,6 +5865,8 @@ var SentryIntegration = /*#__PURE__*/_createClass(function SentryIntegration(_po
5828
5865
 
5829
5866
  this.setupOnce = function (addGlobalEventProcessor) {
5830
5867
  addGlobalEventProcessor(function (event) {
5868
+ var _event$exception, _exceptions$, _exceptions$2;
5869
+
5831
5870
  if (event.level !== 'error' || !_posthog.__loaded) return event;
5832
5871
  if (!event.tags) event.tags = {};
5833
5872
  event.tags['PostHog Person URL'] = _posthog.config.api_host + '/person/' + _posthog.get_distinct_id();
@@ -5836,9 +5875,13 @@ var SentryIntegration = /*#__PURE__*/_createClass(function SentryIntegration(_po
5836
5875
  event.tags['PostHog Recording URL'] = _posthog.config.api_host + '/recordings/#sessionRecordingId=' + _posthog.sessionManager.checkAndGetSessionAndWindowId(true).sessionId;
5837
5876
  }
5838
5877
 
5878
+ var exceptions = ((_event$exception = event.exception) === null || _event$exception === void 0 ? void 0 : _event$exception.values) || [];
5839
5879
  var data = {
5840
5880
  $sentry_event_id: event.event_id,
5841
- $sentry_exception: event.exception
5881
+ $sentry_exception: event.exception,
5882
+ $sentry_exception_message: (_exceptions$ = exceptions[0]) === null || _exceptions$ === void 0 ? void 0 : _exceptions$.value,
5883
+ $sentry_exception_type: (_exceptions$2 = exceptions[0]) === null || _exceptions$2 === void 0 ? void 0 : _exceptions$2.type,
5884
+ $sentry_tags: event.tags
5842
5885
  };
5843
5886
  if (organization && projectId) data['$sentry_url'] = (prefix || 'https://sentry.io/organizations/') + organization + '/issues/?project=' + projectId + '&query=' + event.event_id;
5844
5887
 
@@ -5958,7 +6001,8 @@ var defaultConfig = function defaultConfig() {
5958
6001
  _capture_metrics: false,
5959
6002
  _capture_performance: false,
5960
6003
  name: 'posthog',
5961
- callback_fn: 'posthog._jsc'
6004
+ callback_fn: 'posthog._jsc',
6005
+ bootstrap: {}
5962
6006
  };
5963
6007
  };
5964
6008
  /**
@@ -6107,6 +6151,8 @@ var PostHog = /*#__PURE__*/function () {
6107
6151
  }, {
6108
6152
  key: "_init",
6109
6153
  value: function _init(token) {
6154
+ var _config$bootstrap;
6155
+
6110
6156
  var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6111
6157
  var name = arguments.length > 2 ? arguments[2] : undefined;
6112
6158
  this.__loaded = true;
@@ -6131,14 +6177,43 @@ var PostHog = /*#__PURE__*/function () {
6131
6177
 
6132
6178
  this._gdpr_init();
6133
6179
 
6180
+ if (((_config$bootstrap = config.bootstrap) === null || _config$bootstrap === void 0 ? void 0 : _config$bootstrap.distinctID) !== undefined) {
6181
+ var _config$bootstrap2;
6182
+
6183
+ var uuid = this.get_config('get_device_id')(_UUID());
6184
+ var deviceID = (_config$bootstrap2 = config.bootstrap) !== null && _config$bootstrap2 !== void 0 && _config$bootstrap2.isIdentifiedID ? uuid : config.bootstrap.distinctID;
6185
+ this.register({
6186
+ distinct_id: config.bootstrap.distinctID,
6187
+ $device_id: deviceID
6188
+ });
6189
+ }
6190
+
6191
+ if (this._hasBootstrappedFeatureFlags()) {
6192
+ var _config$bootstrap3;
6193
+
6194
+ var activeFlags = Object.keys(((_config$bootstrap3 = config.bootstrap) === null || _config$bootstrap3 === void 0 ? void 0 : _config$bootstrap3.featureFlags) || {}).filter(function (flag) {
6195
+ var _config$bootstrap4, _config$bootstrap4$fe;
6196
+
6197
+ return !!((_config$bootstrap4 = config.bootstrap) !== null && _config$bootstrap4 !== void 0 && (_config$bootstrap4$fe = _config$bootstrap4.featureFlags) !== null && _config$bootstrap4$fe !== void 0 && _config$bootstrap4$fe[flag]);
6198
+ }).reduce(function (res, key) {
6199
+ var _config$bootstrap5, _config$bootstrap5$fe;
6200
+
6201
+ return res[key] = ((_config$bootstrap5 = config.bootstrap) === null || _config$bootstrap5 === void 0 ? void 0 : (_config$bootstrap5$fe = _config$bootstrap5.featureFlags) === null || _config$bootstrap5$fe === void 0 ? void 0 : _config$bootstrap5$fe[key]) || false, res;
6202
+ }, {});
6203
+ this.featureFlags.receivedFeatureFlags({
6204
+ featureFlags: activeFlags
6205
+ });
6206
+ }
6207
+
6134
6208
  if (!this.get_distinct_id()) {
6135
6209
  // There is no need to set the distinct id
6136
6210
  // or the device id if something was already stored
6137
6211
  // in the persitence
6138
- var uuid = this.get_config('get_device_id')(_UUID());
6212
+ var _uuid = this.get_config('get_device_id')(_UUID());
6213
+
6139
6214
  this.register_once({
6140
- distinct_id: uuid,
6141
- $device_id: uuid
6215
+ distinct_id: _uuid,
6216
+ $device_id: _uuid
6142
6217
  }, '');
6143
6218
  } // Set up event handler for pageleave
6144
6219
  // Use `onpagehide` if available, see https://calendar.perfplanet.com/2020/beaconing-in-practice/#beaconing-reliability-avoiding-abandons
@@ -6419,6 +6494,13 @@ var PostHog = /*#__PURE__*/function () {
6419
6494
  execute(other_calls, this);
6420
6495
  execute(capturing_calls, this);
6421
6496
  }
6497
+ }, {
6498
+ key: "_hasBootstrappedFeatureFlags",
6499
+ value: function _hasBootstrappedFeatureFlags() {
6500
+ var _this$config$bootstra, _this$config$bootstra2;
6501
+
6502
+ return ((_this$config$bootstra = this.config.bootstrap) === null || _this$config$bootstra === void 0 ? void 0 : _this$config$bootstra.featureFlags) && Object.keys((_this$config$bootstra2 = this.config.bootstrap) === null || _this$config$bootstra2 === void 0 ? void 0 : _this$config$bootstra2.featureFlags).length > 0 || false;
6503
+ }
6422
6504
  /**
6423
6505
  * push() keeps the standard async-array-push
6424
6506
  * behavior around after the lib is loaded.