@dreamhorizonorg/pulse-react-native 0.0.1 → 0.0.3

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.
Files changed (148) hide show
  1. package/PulseReactNativeOtel.podspec +1 -1
  2. package/README.md +34 -879
  3. package/android/build.gradle +10 -15
  4. package/android/proguard-rules.pro +3 -99
  5. package/android/src/main/java/com/pulsereactnativeotel/Pulse.kt +89 -0
  6. package/android/src/main/java/com/pulsereactnativeotel/PulseOtelConstants.kt +1 -1
  7. package/android/src/main/java/com/pulsereactnativeotel/PulseReactNativeOtelLogger.kt +3 -1
  8. package/android/src/main/java/com/pulsereactnativeotel/PulseReactNativeOtelModule.kt +69 -3
  9. package/android/src/main/java/com/pulsereactnativeotel/PulseReactNativeOtelPackage.kt +1 -1
  10. package/android/src/main/java/com/pulsereactnativeotel/PulseReactNativeOtelTracer.kt +24 -8
  11. package/android/src/main/java/com/pulsereactnativeotel/ReactNativeScreenAttributesLogRecordProcessor.kt +21 -0
  12. package/android/src/main/java/com/pulsereactnativeotel/ReactNativeScreenAttributesSpanProcessor.kt +30 -0
  13. package/android/src/main/java/com/pulsereactnativeotel/ReactNativeScreenNameTracker.kt +17 -0
  14. package/app.plugin.js +1 -0
  15. package/ios/PulseReactNativeOtel.mm +7 -1
  16. package/lib/module/NativePulseReactNativeOtel.js.map +1 -1
  17. package/lib/module/config.js +57 -19
  18. package/lib/module/config.js.map +1 -1
  19. package/lib/module/errorBoundary.js.map +1 -1
  20. package/lib/module/events.js +6 -0
  21. package/lib/module/events.js.map +1 -1
  22. package/lib/module/index.js +4 -2
  23. package/lib/module/index.js.map +1 -1
  24. package/lib/module/navigation/index.js +179 -0
  25. package/lib/module/navigation/index.js.map +1 -0
  26. package/lib/module/navigation/navigation.interface.js +8 -0
  27. package/lib/module/navigation/navigation.interface.js.map +1 -0
  28. package/lib/module/navigation/screen-interactive.js +101 -0
  29. package/lib/module/navigation/screen-interactive.js.map +1 -0
  30. package/lib/module/navigation/screen-load.js +67 -0
  31. package/lib/module/navigation/screen-load.js.map +1 -0
  32. package/lib/module/navigation/screen-session.js +60 -0
  33. package/lib/module/navigation/screen-session.js.map +1 -0
  34. package/lib/module/navigation/useNavigationTracking.js +34 -0
  35. package/lib/module/navigation/useNavigationTracking.js.map +1 -0
  36. package/lib/module/navigation/utils.js +17 -0
  37. package/lib/module/navigation/utils.js.map +1 -0
  38. package/lib/module/network-interceptor/graphql-helper.js +92 -0
  39. package/lib/module/network-interceptor/graphql-helper.js.map +1 -0
  40. package/lib/module/network-interceptor/header-helper.js +24 -0
  41. package/lib/module/network-interceptor/header-helper.js.map +1 -0
  42. package/lib/module/network-interceptor/initialization.js +18 -1
  43. package/lib/module/network-interceptor/initialization.js.map +1 -1
  44. package/lib/module/network-interceptor/request-tracker-xhr.js +61 -4
  45. package/lib/module/network-interceptor/request-tracker-xhr.js.map +1 -1
  46. package/lib/module/network-interceptor/span-helpers.js +36 -16
  47. package/lib/module/network-interceptor/span-helpers.js.map +1 -1
  48. package/lib/module/network-interceptor/url-helper.js +58 -2
  49. package/lib/module/network-interceptor/url-helper.js.map +1 -1
  50. package/lib/module/pulse.constants.js +47 -0
  51. package/lib/module/pulse.constants.js.map +1 -0
  52. package/lib/module/trace.js +17 -2
  53. package/lib/module/trace.js.map +1 -1
  54. package/lib/typescript/plugin/src/index.d.ts +5 -0
  55. package/lib/typescript/plugin/src/index.d.ts.map +1 -0
  56. package/lib/typescript/plugin/src/types.d.ts +27 -0
  57. package/lib/typescript/plugin/src/types.d.ts.map +1 -0
  58. package/lib/typescript/plugin/src/utils.d.ts +10 -0
  59. package/lib/typescript/plugin/src/utils.d.ts.map +1 -0
  60. package/lib/typescript/plugin/src/withAndroidPulse.d.ts +4 -0
  61. package/lib/typescript/plugin/src/withAndroidPulse.d.ts.map +1 -0
  62. package/lib/typescript/src/NativePulseReactNativeOtel.d.ts +15 -2
  63. package/lib/typescript/src/NativePulseReactNativeOtel.d.ts.map +1 -1
  64. package/lib/typescript/src/config.d.ts +14 -8
  65. package/lib/typescript/src/config.d.ts.map +1 -1
  66. package/lib/typescript/src/errorBoundary.d.ts.map +1 -1
  67. package/lib/typescript/src/events.d.ts.map +1 -1
  68. package/lib/typescript/src/index.d.ts +6 -4
  69. package/lib/typescript/src/index.d.ts.map +1 -1
  70. package/lib/typescript/src/navigation/index.d.ts +13 -0
  71. package/lib/typescript/src/navigation/index.d.ts.map +1 -0
  72. package/lib/typescript/src/navigation/navigation.interface.d.ts +18 -0
  73. package/lib/typescript/src/navigation/navigation.interface.d.ts.map +1 -0
  74. package/lib/typescript/src/navigation/screen-interactive.d.ts +16 -0
  75. package/lib/typescript/src/navigation/screen-interactive.d.ts.map +1 -0
  76. package/lib/typescript/src/navigation/screen-load.d.ts +13 -0
  77. package/lib/typescript/src/navigation/screen-load.d.ts.map +1 -0
  78. package/lib/typescript/src/navigation/screen-session.d.ts +15 -0
  79. package/lib/typescript/src/navigation/screen-session.d.ts.map +1 -0
  80. package/lib/typescript/src/navigation/useNavigationTracking.d.ts +5 -0
  81. package/lib/typescript/src/navigation/useNavigationTracking.d.ts.map +1 -0
  82. package/lib/typescript/src/navigation/utils.d.ts +8 -0
  83. package/lib/typescript/src/navigation/utils.d.ts.map +1 -0
  84. package/lib/typescript/src/network-interceptor/graphql-helper.d.ts +8 -0
  85. package/lib/typescript/src/network-interceptor/graphql-helper.d.ts.map +1 -0
  86. package/lib/typescript/src/network-interceptor/header-helper.d.ts +15 -0
  87. package/lib/typescript/src/network-interceptor/header-helper.d.ts.map +1 -0
  88. package/lib/typescript/src/network-interceptor/initialization.d.ts +4 -1
  89. package/lib/typescript/src/network-interceptor/initialization.d.ts.map +1 -1
  90. package/lib/typescript/src/network-interceptor/network.interface.d.ts +3 -0
  91. package/lib/typescript/src/network-interceptor/network.interface.d.ts.map +1 -1
  92. package/lib/typescript/src/network-interceptor/request-tracker-xhr.d.ts.map +1 -1
  93. package/lib/typescript/src/network-interceptor/span-helpers.d.ts +1 -1
  94. package/lib/typescript/src/network-interceptor/span-helpers.d.ts.map +1 -1
  95. package/lib/typescript/src/network-interceptor/url-helper.d.ts +9 -0
  96. package/lib/typescript/src/network-interceptor/url-helper.d.ts.map +1 -1
  97. package/lib/typescript/src/pulse.constants.d.ts +43 -0
  98. package/lib/typescript/src/pulse.constants.d.ts.map +1 -0
  99. package/lib/typescript/src/pulse.interface.d.ts +2 -1
  100. package/lib/typescript/src/pulse.interface.d.ts.map +1 -1
  101. package/lib/typescript/src/trace.d.ts +7 -0
  102. package/lib/typescript/src/trace.d.ts.map +1 -1
  103. package/package.json +29 -9
  104. package/plugin/build/index.d.ts +4 -0
  105. package/plugin/build/index.js +10 -0
  106. package/plugin/build/types.d.ts +26 -0
  107. package/plugin/build/types.js +2 -0
  108. package/plugin/build/utils.d.ts +9 -0
  109. package/plugin/build/utils.js +102 -0
  110. package/plugin/build/withAndroidPulse.d.ts +3 -0
  111. package/plugin/build/withAndroidPulse.js +53 -0
  112. package/scripts/pulse-cli.js +82 -0
  113. package/scripts/uploadService.js +122 -0
  114. package/scripts/utils.js +125 -0
  115. package/src/NativePulseReactNativeOtel.ts +18 -2
  116. package/src/config.ts +94 -23
  117. package/src/errorBoundary.tsx +11 -5
  118. package/src/events.ts +7 -0
  119. package/src/global.d.ts +0 -1
  120. package/src/index.tsx +7 -4
  121. package/src/navigation/index.ts +335 -0
  122. package/src/navigation/navigation.interface.ts +26 -0
  123. package/src/navigation/screen-interactive.ts +149 -0
  124. package/src/navigation/screen-load.ts +97 -0
  125. package/src/navigation/screen-session.ts +87 -0
  126. package/src/navigation/useNavigationTracking.ts +59 -0
  127. package/src/navigation/utils.ts +19 -0
  128. package/src/network-interceptor/graphql-helper.ts +110 -0
  129. package/src/network-interceptor/header-helper.ts +26 -0
  130. package/src/network-interceptor/initialization.ts +22 -1
  131. package/src/network-interceptor/network.interface.ts +3 -0
  132. package/src/network-interceptor/request-tracker-xhr.ts +93 -3
  133. package/src/network-interceptor/span-helpers.ts +47 -18
  134. package/src/network-interceptor/url-helper.ts +67 -1
  135. package/src/pulse.constants.ts +52 -0
  136. package/src/pulse.interface.ts +6 -1
  137. package/src/trace.ts +25 -2
  138. package/LICENSE +0 -20
  139. package/lib/module/network-interceptor/request-tracker-fetch.js +0 -72
  140. package/lib/module/network-interceptor/request-tracker-fetch.js.map +0 -1
  141. package/lib/module/reactNavigation.js +0 -100
  142. package/lib/module/reactNavigation.js.map +0 -1
  143. package/lib/typescript/src/network-interceptor/request-tracker-fetch.d.ts +0 -7
  144. package/lib/typescript/src/network-interceptor/request-tracker-fetch.d.ts.map +0 -1
  145. package/lib/typescript/src/reactNavigation.d.ts +0 -10
  146. package/lib/typescript/src/reactNavigation.d.ts.map +0 -1
  147. package/src/network-interceptor/request-tracker-fetch.ts +0 -96
  148. package/src/reactNavigation.tsx +0 -146
@@ -0,0 +1,125 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const packageJson = require('../package.json');
4
+
5
+ const FILE_TYPE_TO_BACKEND_TYPE = {
6
+ 'js-sourcemap': 'JS',
7
+ 'mapping': 'mapping',
8
+ 'android-ndk': 'ndk',
9
+ };
10
+
11
+ function checkAndAssertNodeVersion() {
12
+ const nodeVersion = process.versions.node.split('.');
13
+ const majorVersion = parseInt(nodeVersion[0], 10);
14
+
15
+ const requiredVersion = packageJson.engines?.node;
16
+ let minMajorVersion = 18; // fallback
17
+
18
+ if (requiredVersion) {
19
+ const match = requiredVersion.match(/>=(\d+)/);
20
+ if (match) {
21
+ minMajorVersion = parseInt(match[1], 10);
22
+ }
23
+ }
24
+
25
+ if (majorVersion < minMajorVersion) {
26
+ console.error(
27
+ `✗ Error: Pulse CLI requires Node.js ${minMajorVersion}.0.0 or higher.`
28
+ );
29
+ console.error(` Current version: ${process.versions.node}`);
30
+ console.error(
31
+ ` Required: ${requiredVersion || `>=${minMajorVersion}.0.0`}`
32
+ );
33
+ console.error(` Please upgrade Node.js: https://nodejs.org/`);
34
+ process.exit(1);
35
+ }
36
+ }
37
+
38
+ function getPlatform(commandName) {
39
+ if (commandName.includes('android')) {
40
+ return 'android';
41
+ }
42
+ if (commandName.includes('ios')) {
43
+ return 'ios';
44
+ }
45
+ return 'Unknown';
46
+ }
47
+
48
+ function validateFiles(options) {
49
+ const files = [];
50
+ const errors = [];
51
+
52
+ Object.keys(FILE_TYPE_TO_BACKEND_TYPE).forEach((fileOption) => {
53
+ const optionKey = fileOption.replace(/-([a-z])/g, (_, letter) =>
54
+ letter.toUpperCase()
55
+ );
56
+ const optionValue = options[optionKey];
57
+
58
+ if (!optionValue) {
59
+ return;
60
+ }
61
+
62
+ const filePath = path.resolve(optionValue);
63
+ if (!fs.existsSync(filePath)) {
64
+ errors.push(`File not found for filepath: ${filePath}`);
65
+ return;
66
+ }
67
+
68
+ files.push({
69
+ optionName: fileOption,
70
+ path: filePath,
71
+ fileName: path.basename(filePath),
72
+ metadataType: FILE_TYPE_TO_BACKEND_TYPE[fileOption],
73
+ });
74
+ });
75
+
76
+ if (errors.length > 0) {
77
+ throw new Error(`Validation errors:\n ${errors.join('\n ')}`);
78
+ }
79
+
80
+ if (files.length === 0) {
81
+ throw new Error('No files to upload');
82
+ }
83
+
84
+ return files;
85
+ }
86
+
87
+ function validateVersionVersionCodeBundleId(options, commandName) {
88
+ const platform = getPlatform(commandName);
89
+ const isIOS = platform === 'ios';
90
+ const version = isIOS ? options.bundleVersion : options.appVersion;
91
+
92
+ if (!options.versionCode) {
93
+ throw new Error('Version code is required');
94
+ }
95
+ const versionCodeNum = parseInt(options.versionCode, 10);
96
+ if (isNaN(versionCodeNum) || versionCodeNum <= 0) {
97
+ throw new Error(
98
+ `Invalid version code: "${options.versionCode}". Must be a positive integer.`
99
+ );
100
+ }
101
+
102
+ if (!version || typeof version !== 'string' || version.trim().length === 0) {
103
+ throw new Error(
104
+ !version
105
+ ? `Missing required option: ${isIOS ? '--bundle-version' : '--app-version'}`
106
+ : `Invalid ${isIOS ? 'bundle version' : 'app version'}: "${version}". Must be a non-empty string.`
107
+ );
108
+ }
109
+
110
+ if (options.bundleId) {
111
+ const bundleIdPattern = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/i;
112
+ if (!bundleIdPattern.test(options.bundleId)) {
113
+ throw new Error(
114
+ `Invalid bundle-id: "${options.bundleId}". Must be in reverse domain notation (e.g., com.example.app).`
115
+ );
116
+ }
117
+ }
118
+ }
119
+
120
+ module.exports = {
121
+ checkAndAssertNodeVersion,
122
+ getPlatform,
123
+ validateFiles,
124
+ validateVersionVersionCodeBundleId,
125
+ };
@@ -22,8 +22,8 @@ export interface Spec extends TurboModule {
22
22
  attributes?: Object
23
23
  ): boolean;
24
24
 
25
- /** Start an active span; returns spanId (simplified). */
26
- startSpan(name: string, attributes?: Object): string;
25
+ /** Start an active span; returns spanId. */
26
+ startSpan(name: string, inheritContext: boolean, attributes?: Object): string;
27
27
 
28
28
  /** End a span with optional status code. */
29
29
  endSpan(spanId: string, statusCode?: string): boolean;
@@ -41,6 +41,9 @@ export interface Spec extends TurboModule {
41
41
  stackTrace?: string
42
42
  ): boolean;
43
43
 
44
+ /** Discard a span without sending it to backend. */
45
+ discardSpan(spanId: string): boolean;
46
+
44
47
  /** Set user id for the session. Setting null will reset the id */
45
48
  setUserId(id: string | null): void;
46
49
 
@@ -52,6 +55,19 @@ export interface Spec extends TurboModule {
52
55
 
53
56
  /** Trigger ANR test (freezes main thread for 6 seconds) */
54
57
  triggerAnr(): void;
58
+
59
+ /** Set the current React Native screen name to sync active screen name on Android/iOS */
60
+ setCurrentScreenName(screenName: string): boolean;
61
+
62
+ /** Get all SDK Remote Config features */
63
+ getAllFeatures(): {
64
+ rn_screen_load: boolean;
65
+ screen_session: boolean;
66
+ rn_screen_interactive: boolean;
67
+ network_instrumentation: boolean;
68
+ custom_events: boolean;
69
+ js_crash: boolean;
70
+ } | null;
55
71
  }
56
72
 
57
73
  export default TurboModuleRegistry.getEnforcing<Spec>('PulseReactNativeOtel');
package/src/config.ts CHANGED
@@ -3,29 +3,53 @@ import { isSupportedPlatform } from './initialization';
3
3
  import {
4
4
  createReactNavigationIntegration,
5
5
  type ReactNavigationIntegration,
6
- } from './reactNavigation';
6
+ type NavigationIntegrationOptions,
7
+ } from './navigation';
7
8
  import { initializeNetworkInterceptor } from './network-interceptor/initialization';
9
+ import PulseReactNativeOtel from './NativePulseReactNativeOtel';
10
+ import type { PulseFeatureConfig } from './pulse.interface';
11
+ import { PULSE_FEATURE_NAMES } from './pulse.constants';
8
12
 
9
- export type PulseConfig = {
10
- autoDetectExceptions?: boolean;
11
- autoDetectNavigation?: boolean;
12
- autoDetectNetwork?: boolean;
13
+ export type NetworkHeaderConfig = {
14
+ requestHeaders?: string[];
15
+ responseHeaders?: string[];
13
16
  };
14
17
 
15
- export type PulseStartOptions = {
18
+ export type PulseConfig = {
16
19
  autoDetectExceptions?: boolean;
17
20
  autoDetectNavigation?: boolean;
18
21
  autoDetectNetwork?: boolean;
22
+ networkHeaders?: NetworkHeaderConfig;
19
23
  };
20
24
 
21
- const defaultConfig: PulseConfig = {
25
+ const defaultConfig: Required<PulseConfig> = {
22
26
  autoDetectExceptions: true,
23
27
  autoDetectNavigation: true,
24
28
  autoDetectNetwork: true,
29
+ networkHeaders: {
30
+ requestHeaders: [],
31
+ responseHeaders: [],
32
+ },
25
33
  };
26
34
 
27
35
  let currentConfig: PulseConfig = { ...defaultConfig };
28
36
 
37
+ // Cache for features from remote SDK config
38
+ let cachedFeatures: PulseFeatureConfig;
39
+
40
+ /**
41
+ * Gets all features from the remote SDK config.
42
+ * @returns Record of feature names to their enabled status, or null if config not available
43
+ */
44
+ export function getFeaturesFromRemoteConfig(): PulseFeatureConfig {
45
+ if (cachedFeatures !== undefined) {
46
+ return cachedFeatures;
47
+ }
48
+
49
+ cachedFeatures = PulseReactNativeOtel.getAllFeatures();
50
+ return cachedFeatures;
51
+ }
52
+
29
53
  function configure(config: PulseConfig): void {
30
54
  currentConfig = {
31
55
  ...currentConfig,
@@ -34,28 +58,74 @@ function configure(config: PulseConfig): void {
34
58
  setupErrorHandler(currentConfig.autoDetectExceptions ?? true);
35
59
 
36
60
  if (currentConfig.autoDetectNetwork) {
37
- initializeNetworkInterceptor();
61
+ initializeNetworkInterceptor(
62
+ currentConfig.networkHeaders ?? {
63
+ requestHeaders: [],
64
+ responseHeaders: [],
65
+ }
66
+ );
38
67
  }
39
68
  }
40
69
 
41
- export function start(options?: PulseStartOptions): void {
42
- if (!isSupportedPlatform()) {
43
- return;
70
+ function resolveFeatureState(
71
+ features: PulseFeatureConfig,
72
+ featureName: string,
73
+ optionValue: boolean
74
+ ): boolean {
75
+ if (features !== undefined && features !== null)
76
+ return features[featureName] ?? optionValue;
77
+ return optionValue;
78
+ }
79
+
80
+ function resolveNavigationState(
81
+ features: PulseFeatureConfig,
82
+ optionValue: boolean
83
+ ): boolean {
84
+ if (features !== undefined && features !== null) {
85
+ const hasAny =
86
+ features[PULSE_FEATURE_NAMES.SCREEN_SESSION] === true ||
87
+ features[PULSE_FEATURE_NAMES.RN_SCREEN_LOAD] === true ||
88
+ features[PULSE_FEATURE_NAMES.RN_SCREEN_INTERACTIVE] === true;
89
+ return hasAny ?? optionValue;
44
90
  }
45
- const autoDetectExceptions = options?.autoDetectExceptions ?? true;
46
- const autoDetectNavigation = options?.autoDetectNavigation ?? true;
47
- const autoDetectNetwork = options?.autoDetectNetwork ?? true;
48
- configure({
49
- autoDetectExceptions,
50
- autoDetectNavigation,
51
- autoDetectNetwork,
52
- });
91
+ return optionValue;
92
+ }
93
+
94
+ export function start(options?: PulseConfig): void {
95
+ if (!isSupportedPlatform()) return;
96
+
97
+ const features = getFeaturesFromRemoteConfig();
98
+ const config: PulseConfig = {
99
+ autoDetectExceptions: resolveFeatureState(
100
+ features,
101
+ PULSE_FEATURE_NAMES.JS_CRASH,
102
+ options?.autoDetectExceptions ?? defaultConfig.autoDetectExceptions
103
+ ),
104
+ autoDetectNavigation: resolveNavigationState(
105
+ features,
106
+ options?.autoDetectNavigation ?? defaultConfig.autoDetectNavigation
107
+ ),
108
+ autoDetectNetwork: resolveFeatureState(
109
+ features,
110
+ PULSE_FEATURE_NAMES.NETWORK_INSTRUMENTATION,
111
+ options?.autoDetectNetwork ?? defaultConfig.autoDetectNetwork
112
+ ),
113
+ networkHeaders: options?.networkHeaders ?? {
114
+ requestHeaders: [],
115
+ responseHeaders: [],
116
+ },
117
+ };
118
+
119
+ configure(config);
53
120
  }
54
121
 
55
- export function createNavigationIntegrationWithConfig(): ReactNavigationIntegration {
122
+ export function createNavigationIntegrationWithConfig(
123
+ options?: NavigationIntegrationOptions
124
+ ): ReactNavigationIntegration {
56
125
  if (!isSupportedPlatform()) {
57
126
  return {
58
- registerNavigationContainer: (_: unknown) => {},
127
+ registerNavigationContainer: (_: unknown) => () => {},
128
+ markContentReady: () => {},
59
129
  };
60
130
  }
61
131
  if (!currentConfig.autoDetectNavigation) {
@@ -63,13 +133,14 @@ export function createNavigationIntegrationWithConfig(): ReactNavigationIntegrat
63
133
  '[Pulse Navigation] auto-detection disabled via Pulse.start; createNavigationIntegration() returning no-op.'
64
134
  );
65
135
  const noop: ReactNavigationIntegration = {
66
- registerNavigationContainer: (_: unknown) => {
136
+ registerNavigationContainer: (_: unknown) => () => {
67
137
  console.warn(
68
138
  '[Pulse Navigation] auto-detection disabled via Pulse.start; registerNavigationContainer() returning no-op.'
69
139
  );
70
140
  },
141
+ markContentReady: () => {},
71
142
  };
72
143
  return noop;
73
144
  }
74
- return createReactNavigationIntegration();
145
+ return createReactNavigationIntegration(options);
75
146
  }
@@ -30,17 +30,22 @@ const INITIAL_STATE: ErrorBoundaryState = {
30
30
  error: null,
31
31
  };
32
32
 
33
- export class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
33
+ export class ErrorBoundary extends React.Component<
34
+ ErrorBoundaryProps,
35
+ ErrorBoundaryState
36
+ > {
34
37
  public state: ErrorBoundaryState = INITIAL_STATE;
35
38
 
36
39
  public componentDidCatch(error: unknown, errorInfo: React.ErrorInfo): void {
37
- const componentStack = errorInfo.componentStack || COMPONENT_STACK_UNAVAILABLE;
40
+ const componentStack =
41
+ errorInfo.componentStack || COMPONENT_STACK_UNAVAILABLE;
38
42
  const { onError } = this.props;
39
43
 
40
44
  // Error is handled if a fallback is provided, otherwise it's unhandled (fatal)
41
45
  const handled = !!this.props.fallback;
42
46
 
43
- const errorToReport = error instanceof Error ? error : new Error(String(error));
47
+ const errorToReport =
48
+ error instanceof Error ? error : new Error(String(error));
44
49
  Pulse.reportException(errorToReport, !handled);
45
50
 
46
51
  if (onError) {
@@ -76,9 +81,10 @@ export class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoun
76
81
 
77
82
  export function withErrorBoundary<P extends Record<string, any>>(
78
83
  WrappedComponent: React.ComponentType<P>,
79
- errorBoundaryOptions: ErrorBoundaryProps,
84
+ errorBoundaryOptions: ErrorBoundaryProps
80
85
  ): React.FC<P> {
81
- const componentDisplayName = WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;
86
+ const componentDisplayName =
87
+ WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;
82
88
 
83
89
  const Wrapped = React.memo((props: P) => (
84
90
  <ErrorBoundary {...errorBoundaryOptions}>
package/src/events.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import PulseReactNativeOtel from './NativePulseReactNativeOtel';
2
+ import { getFeaturesFromRemoteConfig } from './config';
2
3
  import { mergeWithGlobalAttributes } from './globalAttributes';
3
4
  import { isSupportedPlatform } from './initialization';
4
5
  import type { PulseAttributes } from './pulse.interface';
@@ -7,6 +8,12 @@ export function trackEvent(event: string, attributes?: PulseAttributes): void {
7
8
  if (!isSupportedPlatform()) {
8
9
  return;
9
10
  }
11
+ const features = getFeaturesFromRemoteConfig();
12
+ const customEventsEnabled = features?.custom_events ?? true;
13
+
14
+ if (!customEventsEnabled) {
15
+ return;
16
+ }
10
17
 
11
18
  const observedTimeMs = Date.now();
12
19
  const mergedAttributes = mergeWithGlobalAttributes(attributes || {});
package/src/global.d.ts CHANGED
@@ -6,4 +6,3 @@ declare global {
6
6
  }
7
7
 
8
8
  export {};
9
-
package/src/index.tsx CHANGED
@@ -1,19 +1,21 @@
1
1
  import { startSpan, trackSpan } from './trace';
2
2
  import { reportException } from './errorHandler';
3
3
  import { trackEvent } from './events';
4
- import { start, createNavigationIntegrationWithConfig } from './config';
4
+ import { start } from './config';
5
5
  import { isInitialized } from './initialization';
6
6
  import { setGlobalAttribute } from './globalAttributes';
7
7
  import { setUserId, setUserProperty, setUserProperties } from './user';
8
8
  import { ErrorBoundary, withErrorBoundary } from './errorBoundary';
9
+ import { useNavigationTracking, markContentReady } from './navigation';
9
10
 
10
11
  export type { Span } from './trace';
11
- export type { PulseConfig, PulseStartOptions } from './config';
12
+ export type { PulseConfig } from './config';
12
13
  export type { PulseAttributes, PulseAttributeValue } from './pulse.interface';
13
14
  export type {
14
15
  ReactNavigationIntegration,
15
16
  NavigationRoute,
16
- } from './reactNavigation';
17
+ NavigationIntegrationOptions,
18
+ } from './navigation';
17
19
 
18
20
  export type { ErrorBoundaryProps, FallbackRender } from './errorBoundary';
19
21
 
@@ -21,7 +23,8 @@ export { SpanStatusCode } from './trace';
21
23
  export const Pulse = {
22
24
  start,
23
25
  isInitialized,
24
- createNavigationIntegration: createNavigationIntegrationWithConfig,
26
+ useNavigationTracking,
27
+ markContentReady,
25
28
  trackEvent,
26
29
  reportException,
27
30
  trackSpan,