posthog-react-native 2.0.0 → 2.1.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/lib/index.d.ts CHANGED
@@ -23,7 +23,9 @@ declare enum PostHogPersistedProperty {
23
23
  Queue = "queue",
24
24
  OptedOut = "opted_out",
25
25
  SessionId = "session_id",
26
- SessionLastTimestamp = "session_timestamp"
26
+ SessionLastTimestamp = "session_timestamp",
27
+ PersonProperties = "person_properties",
28
+ GroupProperties = "group_properties"
27
29
  }
28
30
  declare type PostHogFetchOptions = {
29
31
  method: 'GET' | 'POST' | 'PUT' | 'PATCH';
@@ -85,7 +87,7 @@ declare class SimpleEventEmitter {
85
87
 
86
88
  declare abstract class PostHogCore {
87
89
  private apiKey;
88
- private host;
90
+ host: string;
89
91
  private flushAt;
90
92
  private flushInterval;
91
93
  private captureMode;
@@ -108,12 +110,13 @@ declare abstract class PostHogCore {
108
110
  protected getCommonEventProperties(): any;
109
111
  private get props();
110
112
  private set props(value);
113
+ private clearProps;
111
114
  private _props;
112
115
  get optedOut(): boolean;
113
116
  optIn(): void;
114
117
  optOut(): void;
115
118
  on(event: string, cb: (...args: any[]) => void): () => void;
116
- reset(): void;
119
+ reset(propertiesToKeep?: PostHogPersistedProperty[]): void;
117
120
  debug(enabled?: boolean): void;
118
121
  private buildPayload;
119
122
  getSessionId(): string | undefined;
@@ -130,7 +133,7 @@ declare abstract class PostHogCore {
130
133
  identify(distinctId?: string, properties?: PostHogEventProperties): this;
131
134
  capture(event: string, properties?: {
132
135
  [key: string]: any;
133
- }): this;
136
+ }, forceSendFeatureFlags?: boolean): this;
134
137
  alias(alias: string): this;
135
138
  autocapture(eventType: string, elements: PostHogAutocaptureElement[], properties?: PostHogEventProperties): this;
136
139
  /***
@@ -141,18 +144,30 @@ declare abstract class PostHogCore {
141
144
  }): this;
142
145
  group(groupType: string, groupKey: string | number, groupProperties?: PostHogEventProperties): this;
143
146
  groupIdentify(groupType: string, groupKey: string | number, groupProperties?: PostHogEventProperties): this;
147
+ /***
148
+ * PROPERTIES
149
+ ***/
150
+ personProperties(properties: {
151
+ [type: string]: string;
152
+ }): this;
153
+ groupProperties(properties: {
154
+ [type: string]: Record<string, string>;
155
+ }): this;
144
156
  /***
145
157
  *** FEATURE FLAGS
146
158
  ***/
147
159
  private decideAsync;
148
160
  private _decideAsync;
149
- getFeatureFlag(key: string, defaultResult?: string | boolean): boolean | string | undefined;
161
+ getFeatureFlag(key: string): boolean | string | undefined;
150
162
  getFeatureFlags(): PostHogDecideResponse['featureFlags'] | undefined;
151
- isFeatureEnabled(key: string, defaultResult?: boolean): boolean;
152
- reloadFeatureFlagsAsync(): Promise<PostHogDecideResponse['featureFlags']>;
163
+ isFeatureEnabled(key: string): boolean | undefined;
164
+ reloadFeatureFlagsAsync(sendAnonDistinctId?: boolean): Promise<PostHogDecideResponse['featureFlags']>;
153
165
  onFeatureFlags(cb: (flags: PostHogDecideResponse['featureFlags']) => void): () => void;
154
166
  onFeatureFlag(key: string, cb: (value: string | boolean) => void): () => void;
155
167
  overrideFeatureFlag(flags: PostHogDecideResponse['featureFlags'] | null): void;
168
+ _sendFeatureFlags(event: string, properties?: {
169
+ [key: string]: any;
170
+ }): void;
156
171
  /***
157
172
  *** QUEUEING AND FLUSHING
158
173
  ***/
@@ -195,7 +210,9 @@ declare type PostHogAutocaptureOptions = {
195
210
  maxElementsCaptured?: number;
196
211
  ignoreLabels?: string[];
197
212
  propsToCapture?: string[];
213
+ captureScreens?: boolean;
198
214
  navigation?: PostHogAutocaptureNavigationTrackerOptions;
215
+ captureLifecycleEvents?: boolean;
199
216
  };
200
217
 
201
218
  declare function _useNavigationTracker(options?: PostHogAutocaptureNavigationTrackerOptions, client?: PostHog): void;
@@ -203,7 +220,7 @@ declare const useNavigationTracker: typeof _useNavigationTracker;
203
220
 
204
221
  declare function useFeatureFlags(client?: PostHog): PostHogDecideResponse$1['featureFlags'] | undefined;
205
222
 
206
- declare function useFeatureFlag(flag: string, defaultValue?: boolean | string): string | boolean | undefined;
223
+ declare function useFeatureFlag(flag: string): string | boolean | undefined;
207
224
 
208
225
  declare const usePostHog: () => PostHog | undefined;
209
226
 
package/lib/index.esm.js CHANGED
@@ -134,6 +134,17 @@ function __generator(thisArg, body) {
134
134
  throw op[1];
135
135
  return { value: op[0] ? op[1] : void 0, done: true };
136
136
  }
137
+ }
138
+ function __spreadArray(to, from, pack) {
139
+ if (pack || arguments.length === 2)
140
+ for (var i = 0, l = from.length, ar; i < l; i++) {
141
+ if (ar || !(i in from)) {
142
+ if (!ar)
143
+ ar = Array.prototype.slice.call(from, 0, i);
144
+ ar[i] = from[i];
145
+ }
146
+ }
147
+ return to.concat(ar || Array.prototype.slice.call(from));
137
148
  }
138
149
 
139
150
  var PostHogPersistedProperty;
@@ -147,6 +158,8 @@ var PostHogPersistedProperty;
147
158
  PostHogPersistedProperty["OptedOut"] = "opted_out";
148
159
  PostHogPersistedProperty["SessionId"] = "session_id";
149
160
  PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
161
+ PostHogPersistedProperty["PersonProperties"] = "person_properties";
162
+ PostHogPersistedProperty["GroupProperties"] = "group_properties";
150
163
  })(PostHogPersistedProperty || (PostHogPersistedProperty = {}));
151
164
 
152
165
  function assert(truthyValue, message) {
@@ -720,12 +733,14 @@ var PostHogCore = /** @class */ (function () {
720
733
  }
721
734
  PostHogCore.prototype.getCommonEventProperties = function () {
722
735
  var featureFlags = this.getFeatureFlags();
723
- return {
724
- $lib: this.getLibraryId(),
725
- $lib_version: this.getLibraryVersion(),
726
- $active_feature_flags: featureFlags ? Object.keys(featureFlags) : undefined,
727
- $enabled_feature_flags: featureFlags,
728
- };
736
+ var featureVariantProperties = {};
737
+ if (featureFlags) {
738
+ for (var _i = 0, _a = Object.entries(featureFlags); _i < _a.length; _i++) {
739
+ var _b = _a[_i], feature = _b[0], variant = _b[1];
740
+ featureVariantProperties["$feature/".concat(feature)] = variant;
741
+ }
742
+ }
743
+ return __assign({ $lib: this.getLibraryId(), $lib_version: this.getLibraryVersion(), $active_feature_flags: featureFlags ? Object.keys(featureFlags) : undefined }, featureVariantProperties);
729
744
  };
730
745
  Object.defineProperty(PostHogCore.prototype, "props", {
731
746
  // NOTE: Props are lazy loaded from localstorage hence the complex getter setter logic
@@ -741,6 +756,9 @@ var PostHogCore = /** @class */ (function () {
741
756
  enumerable: false,
742
757
  configurable: true
743
758
  });
759
+ PostHogCore.prototype.clearProps = function () {
760
+ this.props = undefined;
761
+ };
744
762
  Object.defineProperty(PostHogCore.prototype, "optedOut", {
745
763
  get: function () {
746
764
  var _a, _b;
@@ -758,9 +776,15 @@ var PostHogCore = /** @class */ (function () {
758
776
  PostHogCore.prototype.on = function (event, cb) {
759
777
  return this._events.on(event, cb);
760
778
  };
761
- PostHogCore.prototype.reset = function () {
762
- for (var key in PostHogPersistedProperty) {
763
- this.setPersistedProperty(PostHogPersistedProperty[key], null);
779
+ PostHogCore.prototype.reset = function (propertiesToKeep) {
780
+ var allPropertiesToKeep = __spreadArray([PostHogPersistedProperty.Queue], (propertiesToKeep || []), true);
781
+ // clean up props
782
+ this.clearProps();
783
+ for (var _i = 0, _a = Object.keys(PostHogPersistedProperty); _i < _a.length; _i++) {
784
+ var key = _a[_i];
785
+ if (!allPropertiesToKeep.includes(PostHogPersistedProperty[key])) {
786
+ this.setPersistedProperty(PostHogPersistedProperty[key], null);
787
+ }
764
788
  }
765
789
  };
766
790
  PostHogCore.prototype.debug = function (enabled) {
@@ -835,12 +859,18 @@ var PostHogCore = /** @class */ (function () {
835
859
  this.enqueue('identify', payload);
836
860
  return this;
837
861
  };
838
- PostHogCore.prototype.capture = function (event, properties) {
862
+ PostHogCore.prototype.capture = function (event, properties, forceSendFeatureFlags) {
863
+ if (forceSendFeatureFlags === void 0) { forceSendFeatureFlags = false; }
839
864
  if (properties === null || properties === void 0 ? void 0 : properties.$groups) {
840
865
  this.groups(properties.$groups);
841
866
  }
842
- var payload = this.buildPayload({ event: event, properties: properties });
843
- this.enqueue('capture', payload);
867
+ if (forceSendFeatureFlags) {
868
+ this._sendFeatureFlags(event, properties);
869
+ }
870
+ else {
871
+ var payload = this.buildPayload({ event: event, properties: properties });
872
+ this.enqueue('capture', payload);
873
+ }
844
874
  return this;
845
875
  };
846
876
  PostHogCore.prototype.alias = function (alias) {
@@ -870,7 +900,6 @@ var PostHogCore = /** @class */ (function () {
870
900
  PostHogCore.prototype.groups = function (groups) {
871
901
  // Get persisted groups
872
902
  var existingGroups = this.props.$groups || {};
873
- // NOTE: Should we do the same for groups listed in identify / capture?
874
903
  this.register({
875
904
  $groups: __assign(__assign({}, existingGroups), groups),
876
905
  });
@@ -898,31 +927,58 @@ var PostHogCore = /** @class */ (function () {
898
927
  this.enqueue('capture', payload);
899
928
  return this;
900
929
  };
930
+ /***
931
+ * PROPERTIES
932
+ ***/
933
+ PostHogCore.prototype.personProperties = function (properties) {
934
+ // Get persisted person properties
935
+ var existingProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
936
+ this.setPersistedProperty(PostHogPersistedProperty.PersonProperties, __assign(__assign({}, existingProperties), properties));
937
+ return this;
938
+ };
939
+ PostHogCore.prototype.groupProperties = function (properties) {
940
+ // Get persisted group properties
941
+ var existingProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) || {};
942
+ if (Object.keys(existingProperties).length !== 0) {
943
+ Object.keys(existingProperties).forEach(function (groupType) {
944
+ existingProperties[groupType] = __assign(__assign({}, existingProperties[groupType]), properties[groupType]);
945
+ delete properties[groupType];
946
+ });
947
+ }
948
+ this.setPersistedProperty(PostHogPersistedProperty.GroupProperties, __assign(__assign({}, existingProperties), properties));
949
+ return this;
950
+ };
901
951
  /***
902
952
  *** FEATURE FLAGS
903
953
  ***/
904
- PostHogCore.prototype.decideAsync = function () {
954
+ PostHogCore.prototype.decideAsync = function (sendAnonDistinctId) {
955
+ if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
905
956
  if (this._decideResponsePromise) {
906
957
  return this._decideResponsePromise;
907
958
  }
908
- return this._decideAsync();
959
+ return this._decideAsync(sendAnonDistinctId);
909
960
  };
910
- PostHogCore.prototype._decideAsync = function () {
961
+ PostHogCore.prototype._decideAsync = function (sendAnonDistinctId) {
962
+ if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
911
963
  return __awaiter(this, void 0, void 0, function () {
912
- var url, distinctId, groups, fetchOptions;
964
+ var url, distinctId, groups, personProperties, groupProperties, fetchOptions;
913
965
  var _this = this;
914
966
  return __generator(this, function (_a) {
915
967
  url = "".concat(this.host, "/decide/?v=2");
916
968
  distinctId = this.getDistinctId();
917
969
  groups = this.props.$groups || {};
970
+ personProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
971
+ groupProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) || {};
918
972
  fetchOptions = {
919
973
  method: 'POST',
920
974
  headers: { 'Content-Type': 'application/json' },
921
975
  body: JSON.stringify({
922
976
  token: this.apiKey,
923
977
  distinct_id: distinctId,
924
- $anon_distinct_id: this.getAnonymousId(),
978
+ $anon_distinct_id: sendAnonDistinctId ? this.getAnonymousId() : undefined,
925
979
  groups: groups,
980
+ person_properties: personProperties,
981
+ group_properties: groupProperties,
926
982
  }),
927
983
  };
928
984
  this._decideResponsePromise = this.fetchWithRetry(url, fetchOptions)
@@ -941,23 +997,26 @@ var PostHogCore = /** @class */ (function () {
941
997
  });
942
998
  });
943
999
  };
944
- PostHogCore.prototype.getFeatureFlag = function (key, defaultResult) {
945
- var _a;
946
- if (defaultResult === void 0) { defaultResult = false; }
1000
+ PostHogCore.prototype.getFeatureFlag = function (key) {
947
1001
  var featureFlags = this.getFeatureFlags();
948
1002
  if (!featureFlags) {
949
- // If we haven't loaded flags yet we respond undefined to indicate this
1003
+ // If we haven't loaded flags yet, or errored out, we respond with undefined
950
1004
  return undefined;
951
1005
  }
1006
+ var response = featureFlags[key];
1007
+ if (response === undefined) {
1008
+ // `/decide` returns nothing for flags which are false.
1009
+ response = false;
1010
+ }
952
1011
  if (this.sendFeatureFlagEvent && !this.flagCallReported[key]) {
953
1012
  this.flagCallReported[key] = true;
954
1013
  this.capture('$feature_flag_called', {
955
1014
  $feature_flag: key,
956
- $feature_flag_response: featureFlags[key],
1015
+ $feature_flag_response: response,
957
1016
  });
958
1017
  }
959
- // If we have flags we either return the value (true or string) or the defaultResult
960
- return (_a = featureFlags[key]) !== null && _a !== void 0 ? _a : defaultResult;
1018
+ // If we have flags we either return the value (true or string) or false
1019
+ return response;
961
1020
  };
962
1021
  PostHogCore.prototype.getFeatureFlags = function () {
963
1022
  var flags = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlags);
@@ -976,17 +1035,19 @@ var PostHogCore = /** @class */ (function () {
976
1035
  }
977
1036
  return flags;
978
1037
  };
979
- PostHogCore.prototype.isFeatureEnabled = function (key, defaultResult) {
980
- var _a;
981
- if (defaultResult === void 0) { defaultResult = false; }
982
- var flag = (_a = this.getFeatureFlag(key, defaultResult)) !== null && _a !== void 0 ? _a : defaultResult;
983
- return !!flag;
1038
+ PostHogCore.prototype.isFeatureEnabled = function (key) {
1039
+ var response = this.getFeatureFlag(key);
1040
+ if (response === undefined) {
1041
+ return undefined;
1042
+ }
1043
+ return !!response;
984
1044
  };
985
- PostHogCore.prototype.reloadFeatureFlagsAsync = function () {
1045
+ PostHogCore.prototype.reloadFeatureFlagsAsync = function (sendAnonDistinctId) {
1046
+ if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
986
1047
  return __awaiter(this, void 0, void 0, function () {
987
1048
  return __generator(this, function (_a) {
988
1049
  switch (_a.label) {
989
- case 0: return [4 /*yield*/, this.decideAsync()];
1050
+ case 0: return [4 /*yield*/, this.decideAsync(sendAnonDistinctId)];
990
1051
  case 1: return [2 /*return*/, (_a.sent()).featureFlags];
991
1052
  }
992
1053
  });
@@ -1024,6 +1085,14 @@ var PostHogCore = /** @class */ (function () {
1024
1085
  }
1025
1086
  return this.setPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags, flags);
1026
1087
  };
1088
+ PostHogCore.prototype._sendFeatureFlags = function (event, properties) {
1089
+ var _this = this;
1090
+ this.reloadFeatureFlagsAsync(false).finally(function () {
1091
+ // Try to enqueue message irrespective of errors during feature flag fetching
1092
+ var payload = _this.buildPayload({ event: event, properties: properties });
1093
+ _this.enqueue('capture', payload);
1094
+ });
1095
+ };
1027
1096
  /***
1028
1097
  *** QUEUEING AND FLUSHING
1029
1098
  ***/
@@ -1052,13 +1121,15 @@ var PostHogCore = /** @class */ (function () {
1052
1121
  PostHogCore.prototype.flushAsync = function () {
1053
1122
  var _this = this;
1054
1123
  return new Promise(function (resolve, reject) {
1055
- _this.flush(function (err, data) { return (err ? reject(err) : resolve(data)); });
1124
+ _this.flush(function (err, data) {
1125
+ return err ? reject(err) : resolve(data);
1126
+ });
1056
1127
  });
1057
1128
  };
1058
1129
  PostHogCore.prototype.flush = function (callback) {
1059
1130
  var _this = this;
1060
1131
  if (this.optedOut) {
1061
- return callback && safeSetTimeout(callback, 0);
1132
+ return callback === null || callback === void 0 ? void 0 : callback();
1062
1133
  }
1063
1134
  if (this._flushTimer) {
1064
1135
  clearTimeout(this._flushTimer);
@@ -1066,7 +1137,7 @@ var PostHogCore = /** @class */ (function () {
1066
1137
  }
1067
1138
  var queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
1068
1139
  if (!queue.length) {
1069
- return callback && safeSetTimeout(callback, 0);
1140
+ return callback === null || callback === void 0 ? void 0 : callback();
1070
1141
  }
1071
1142
  var items = queue.splice(0, this.flushAt);
1072
1143
  this.setPersistedProperty(PostHogPersistedProperty.Queue, queue);
@@ -1337,7 +1408,7 @@ var preloadSemiAsyncStorage = function () {
1337
1408
  return _preloadSemiAsyncStoragePromise;
1338
1409
  };
1339
1410
 
1340
- var version = "2.0.0";
1411
+ var version = "2.1.0";
1341
1412
 
1342
1413
  var PostHog =
1343
1414
  /** @class */
@@ -1574,10 +1645,10 @@ function useFeatureFlags(client) {
1574
1645
  return featureFlags;
1575
1646
  }
1576
1647
 
1577
- function useFeatureFlag(flag, defaultValue) {
1648
+ function useFeatureFlag(flag) {
1578
1649
  var posthog = usePostHog();
1579
1650
 
1580
- var _a = useState(posthog === null || posthog === void 0 ? void 0 : posthog.getFeatureFlag(flag, defaultValue)),
1651
+ var _a = useState(posthog === null || posthog === void 0 ? void 0 : posthog.getFeatureFlag(flag)),
1581
1652
  featureFlag = _a[0],
1582
1653
  setFeatureFlag = _a[1];
1583
1654
 
@@ -1586,11 +1657,11 @@ function useFeatureFlag(flag, defaultValue) {
1586
1657
  }
1587
1658
 
1588
1659
  useEffect(function () {
1589
- setFeatureFlag(posthog.getFeatureFlag(flag, defaultValue));
1660
+ setFeatureFlag(posthog.getFeatureFlag(flag));
1590
1661
  return posthog.onFeatureFlags(function () {
1591
- setFeatureFlag(posthog.getFeatureFlag(flag, defaultValue));
1662
+ setFeatureFlag(posthog.getFeatureFlag(flag));
1592
1663
  });
1593
- }, [posthog, flag, defaultValue]);
1664
+ }, [posthog, flag]);
1594
1665
  return featureFlag;
1595
1666
  }
1596
1667
 
@@ -1705,14 +1776,20 @@ var autocaptureFromTouchEvent = function (e, posthog, options) {
1705
1776
  }
1706
1777
  };
1707
1778
 
1708
- function PostHogHooks(_a) {
1779
+ function PostHogNavigationHook(_a) {
1709
1780
  var options = _a.options;
1710
1781
  useNavigationTracker(options === null || options === void 0 ? void 0 : options.navigation);
1782
+ return null;
1783
+ }
1784
+
1785
+ function PostHogLifecycleHook() {
1711
1786
  useLifecycleTracker();
1712
1787
  return null;
1713
1788
  }
1714
1789
 
1715
1790
  var PostHogProvider = function (_a) {
1791
+ var _b, _c;
1792
+
1716
1793
  var children = _a.children,
1717
1794
  client = _a.client,
1718
1795
  options = _a.options,
@@ -1725,10 +1802,13 @@ var PostHogProvider = function (_a) {
1725
1802
  posthogRef.current = client ? client : apiKey ? new PostHog(apiKey, options) : undefined;
1726
1803
  }
1727
1804
 
1728
- var autocaptureEnabled = !!autocapture;
1729
1805
  var autocaptureOptions = autocapture && typeof autocapture !== 'boolean' ? autocapture : {};
1730
1806
  var posthog = posthogRef.current;
1731
1807
  var captureTouches = posthog && (autocapture === true || (autocaptureOptions === null || autocaptureOptions === void 0 ? void 0 : autocaptureOptions.captureTouches));
1808
+ var captureScreens = posthog && (autocapture === true || ((_b = autocaptureOptions === null || autocaptureOptions === void 0 ? void 0 : autocaptureOptions.captureScreens) !== null && _b !== void 0 ? _b : true)); // Default to true if not set
1809
+
1810
+ var captureLifecycle = posthog && (autocapture === true || ((_c = autocaptureOptions === null || autocaptureOptions === void 0 ? void 0 : autocaptureOptions.captureLifecycleEvents) !== null && _c !== void 0 ? _c : true)); // Default to true if not set
1811
+
1732
1812
  var onTouch = useCallback(function (type, e) {
1733
1813
  // TODO: Improve this to ensure we only capture presses and not just ends of a drag for example
1734
1814
  if (!captureTouches) {
@@ -1738,8 +1818,7 @@ var PostHogProvider = function (_a) {
1738
1818
  if (type === 'end') {
1739
1819
  autocaptureFromTouchEvent(e, posthog, autocaptureOptions);
1740
1820
  }
1741
- }, [posthog, autocapture]); // TODO: Improve this to ensure we only capture presses and not just ends of a drag for example
1742
-
1821
+ }, [posthog, autocapture]);
1743
1822
  return /*#__PURE__*/React.createElement(View, {
1744
1823
  "ph-label": "PostHogProvider",
1745
1824
  style: style || {
@@ -1752,9 +1831,9 @@ var PostHogProvider = function (_a) {
1752
1831
  value: {
1753
1832
  client: posthogRef.current
1754
1833
  }
1755
- }, autocaptureEnabled ? /*#__PURE__*/React.createElement(PostHogHooks, {
1834
+ }, /*#__PURE__*/React.createElement(React.Fragment, null, captureScreens ? /*#__PURE__*/React.createElement(PostHogNavigationHook, {
1756
1835
  options: autocaptureOptions
1757
- }) : null, children));
1836
+ }) : null, captureLifecycle ? /*#__PURE__*/React.createElement(PostHogLifecycleHook, null) : null), children));
1758
1837
  };
1759
1838
 
1760
1839
  export { PostHog, PostHogProvider, PostHog as default, useFeatureFlag, useFeatureFlags, useLifecycleTracker, useNavigationTracker, usePostHog };