react-native-inapp-inspector 1.1.33 → 1.1.35

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 (75) hide show
  1. package/dist/commonjs/components/ConsoleLogCard.js +57 -56
  2. package/dist/commonjs/components/CopyButton.js +7 -1
  3. package/dist/commonjs/components/Inspector/BundleTab.js +268 -27
  4. package/dist/commonjs/components/Inspector/CrashDetail.js +16 -12
  5. package/dist/commonjs/components/Inspector/InspectorHeader.js +16 -16
  6. package/dist/commonjs/components/Inspector/MainScreen.js +6 -2
  7. package/dist/commonjs/components/Inspector/NetworkTab.js +97 -1
  8. package/dist/commonjs/components/Inspector/ReduxDetail.js +24 -19
  9. package/dist/commonjs/components/Inspector/ReduxTab.js +12 -8
  10. package/dist/commonjs/components/Inspector/SettingsPanel.js +1243 -673
  11. package/dist/commonjs/components/LogCard.js +27 -9
  12. package/dist/commonjs/components/MetaAccordion.js +42 -0
  13. package/dist/commonjs/components/NetworkIcons.d.ts +9 -0
  14. package/dist/commonjs/components/NetworkIcons.js +48 -1
  15. package/dist/commonjs/components/Toast.js +3 -3
  16. package/dist/commonjs/components/TouchableScale.d.ts +4 -2
  17. package/dist/commonjs/components/TouchableScale.js +4 -4
  18. package/dist/commonjs/constants/version.d.ts +1 -1
  19. package/dist/commonjs/constants/version.js +1 -1
  20. package/dist/commonjs/customHooks/analyticsLogger.d.ts +2 -0
  21. package/dist/commonjs/customHooks/analyticsLogger.js +10 -1
  22. package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +2 -0
  23. package/dist/commonjs/customHooks/bundleAnalyzer.js +80 -33
  24. package/dist/commonjs/customHooks/consoleLogger.d.ts +2 -0
  25. package/dist/commonjs/customHooks/consoleLogger.js +10 -1
  26. package/dist/commonjs/customHooks/crashHandler.d.ts +2 -0
  27. package/dist/commonjs/customHooks/crashHandler.js +10 -1
  28. package/dist/commonjs/customHooks/networkLogger.d.ts +2 -0
  29. package/dist/commonjs/customHooks/networkLogger.js +12 -1
  30. package/dist/commonjs/customHooks/performanceTracker.d.ts +3 -1
  31. package/dist/commonjs/customHooks/performanceTracker.js +18 -4
  32. package/dist/commonjs/customHooks/reduxLogger.d.ts +2 -0
  33. package/dist/commonjs/customHooks/reduxLogger.js +10 -1
  34. package/dist/commonjs/i18n/locales/en.json +96 -28
  35. package/dist/commonjs/index.js +78 -34
  36. package/dist/commonjs/styles/AppColors.d.ts +28 -0
  37. package/dist/commonjs/styles/AppColors.js +30 -0
  38. package/dist/esm/components/ConsoleLogCard.js +58 -57
  39. package/dist/esm/components/CopyButton.js +7 -1
  40. package/dist/esm/components/Inspector/BundleTab.js +268 -27
  41. package/dist/esm/components/Inspector/CrashDetail.js +16 -12
  42. package/dist/esm/components/Inspector/InspectorHeader.js +16 -16
  43. package/dist/esm/components/Inspector/MainScreen.js +6 -2
  44. package/dist/esm/components/Inspector/NetworkTab.js +99 -3
  45. package/dist/esm/components/Inspector/ReduxDetail.js +24 -19
  46. package/dist/esm/components/Inspector/ReduxTab.js +12 -8
  47. package/dist/esm/components/Inspector/SettingsPanel.js +1246 -676
  48. package/dist/esm/components/LogCard.js +27 -9
  49. package/dist/esm/components/MetaAccordion.js +42 -0
  50. package/dist/esm/components/NetworkIcons.d.ts +9 -0
  51. package/dist/esm/components/NetworkIcons.js +38 -0
  52. package/dist/esm/components/Toast.js +3 -3
  53. package/dist/esm/components/TouchableScale.d.ts +4 -2
  54. package/dist/esm/components/TouchableScale.js +4 -4
  55. package/dist/esm/constants/version.d.ts +1 -1
  56. package/dist/esm/constants/version.js +1 -1
  57. package/dist/esm/customHooks/analyticsLogger.d.ts +2 -0
  58. package/dist/esm/customHooks/analyticsLogger.js +7 -0
  59. package/dist/esm/customHooks/bundleAnalyzer.d.ts +2 -0
  60. package/dist/esm/customHooks/bundleAnalyzer.js +77 -32
  61. package/dist/esm/customHooks/consoleLogger.d.ts +2 -0
  62. package/dist/esm/customHooks/consoleLogger.js +7 -0
  63. package/dist/esm/customHooks/crashHandler.d.ts +2 -0
  64. package/dist/esm/customHooks/crashHandler.js +7 -0
  65. package/dist/esm/customHooks/networkLogger.d.ts +2 -0
  66. package/dist/esm/customHooks/networkLogger.js +9 -0
  67. package/dist/esm/customHooks/performanceTracker.d.ts +3 -1
  68. package/dist/esm/customHooks/performanceTracker.js +15 -3
  69. package/dist/esm/customHooks/reduxLogger.d.ts +2 -0
  70. package/dist/esm/customHooks/reduxLogger.js +7 -0
  71. package/dist/esm/i18n/locales/en.json +96 -28
  72. package/dist/esm/index.js +64 -20
  73. package/dist/esm/styles/AppColors.d.ts +28 -0
  74. package/dist/esm/styles/AppColors.js +30 -0
  75. package/package.json +3 -2
@@ -134,11 +134,11 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
134
134
  styles.chip,
135
135
  {
136
136
  backgroundColor: item.url.toLowerCase().startsWith('https')
137
- ? '#ECFDF5'
138
- : '#FFFBEB',
137
+ ? AppColors.mintGreenBg
138
+ : AppColors.amberWarmBg,
139
139
  borderColor: item.url.toLowerCase().startsWith('https')
140
- ? '#A7F3D0'
141
- : '#FDE68A',
140
+ ? AppColors.mintGreenBorder
141
+ : AppColors.amberWarmBorder,
142
142
  paddingHorizontal: 4,
143
143
  paddingVertical: 1,
144
144
  borderRadius: 4,
@@ -150,8 +150,8 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
150
150
  fontFamily: AppFonts.interBold,
151
151
  fontSize: 8,
152
152
  color: item.url.toLowerCase().startsWith('https')
153
- ? '#059669'
154
- : '#D97706',
153
+ ? AppColors.mintGreenText
154
+ : AppColors.amber700,
155
155
  },
156
156
  ]}>
157
157
  {item.url.toLowerCase().startsWith('https') ? 'HTTPS' : 'HTTP'}
@@ -164,8 +164,8 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
164
164
  item.client === 'graphql') && (<View style={[
165
165
  styles.chip,
166
166
  {
167
- backgroundColor: '#FDF2F8',
168
- borderColor: '#FBCFE8',
167
+ backgroundColor: AppColors.roseBg,
168
+ borderColor: AppColors.roseBorder,
169
169
  paddingHorizontal: 4,
170
170
  paddingVertical: 1,
171
171
  borderRadius: 4,
@@ -176,7 +176,7 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
176
176
  {
177
177
  fontFamily: AppFonts.interBold,
178
178
  fontSize: 8,
179
- color: '#DB2777',
179
+ color: AppColors.pink600,
180
180
  },
181
181
  ]}>
182
182
  GQL
@@ -316,6 +316,24 @@ const LogCard = React.memo(function LogCard({ item, onPress, timelineMinStart, t
316
316
  </View>)}
317
317
  </View>
318
318
  </View>
319
+
320
+ {/* Mini Latency Timing Waterfall Bar */}
321
+ {typeof item.duration === 'number' && item.duration > 0 && !isFailed && (<View style={{ marginTop: 6, gap: 2 }}>
322
+ <View style={{
323
+ height: 2.5,
324
+ width: '100%',
325
+ backgroundColor: AppColors.grayBorderSecondary,
326
+ borderRadius: 1.5,
327
+ overflow: 'hidden',
328
+ }}>
329
+ <View style={{
330
+ height: '100%',
331
+ width: `${Math.min(100, Math.max(6, (item.duration / 1200) * 100))}%`,
332
+ backgroundColor: durationColor,
333
+ borderRadius: 1.5,
334
+ }}/>
335
+ </View>
336
+ </View>)}
319
337
  </View>
320
338
  <Animated.View pointerEvents="none" style={[
321
339
  StyleSheet.absoluteFill,
@@ -170,6 +170,48 @@ const MetaAccordion = ({ status, statusColor, duration, size, triggeredAt, metho
170
170
  </Text>
171
171
  </View>
172
172
  </View>
173
+
174
+ {/* Visual Latency Timing Breakdown Waterfall */}
175
+ {duration != null && !isFailed && (<View style={{ paddingVertical: 8, gap: 6 }}>
176
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
177
+ <Text style={{ fontFamily: AppFonts.interBold, fontSize: 11, color: AppColors.primaryBlack }}>
178
+ {t('network.timingWaterfall')}
179
+ </Text>
180
+ <Text style={{ fontFamily: AppFonts.interMedium, fontSize: 10.5, color: getDurationColor(duration) }}>
181
+ {duration < DURATION_FAST_MS
182
+ ? t('network.perf.fast')
183
+ : duration < DURATION_SLOW_MS
184
+ ? t('network.perf.moderate')
185
+ : t('network.perf.slow')}
186
+ </Text>
187
+ </View>
188
+
189
+ <View style={{
190
+ height: 6,
191
+ backgroundColor: AppColors.grayBorderSecondary,
192
+ borderRadius: 3,
193
+ overflow: 'hidden',
194
+ }}>
195
+ <View style={{
196
+ height: '100%',
197
+ width: `${Math.min(100, Math.max(8, (duration / 1200) * 100))}%`,
198
+ backgroundColor: getDurationColor(duration),
199
+ borderRadius: 3,
200
+ }}/>
201
+ </View>
202
+
203
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginTop: 1 }}>
204
+ <Text style={{ fontFamily: AppFonts.interRegular, fontSize: 9.5, color: AppColors.grayTextWeak }}>
205
+ 0 ms
206
+ </Text>
207
+ <Text style={{ fontFamily: AppFonts.interBold, fontSize: 10, color: getDurationColor(duration) }}>
208
+ {duration} ms
209
+ </Text>
210
+ <Text style={{ fontFamily: AppFonts.interRegular, fontSize: 9.5, color: AppColors.grayTextWeak }}>
211
+ 1,200+ ms
212
+ </Text>
213
+ </View>
214
+ </View>)}
173
215
  <View style={styles.metaDivider}/>
174
216
 
175
217
  <View style={styles.metaRow}>
@@ -115,3 +115,12 @@ export declare const AppFramesIcon: ({ color, size, }: IconProps) => React.JSX.E
115
115
  export declare const AllFramesIcon: ({ color, size, }: IconProps) => React.JSX.Element;
116
116
  export declare const ListenerIcon: ({ color, size, }: IconProps) => React.JSX.Element;
117
117
  export declare const LoadingSpinnerIcon: ({ color, size, }: IconProps) => React.JSX.Element;
118
+ export declare const FlaskIcon: ({ color, size }: IconProps) => React.JSX.Element;
119
+ export declare const ZapIcon: ({ color, size }: IconProps) => React.JSX.Element;
120
+ export declare const DiceIcon: ({ color, size }: IconProps) => React.JSX.Element;
121
+ export declare const BarChartIcon: ({ color, size }: IconProps) => React.JSX.Element;
122
+ export declare const KeyIcon: ({ color, size }: IconProps) => React.JSX.Element;
123
+ export declare const SmartphoneIcon: ({ color, size }: IconProps) => React.JSX.Element;
124
+ export declare const AlertTriangleIcon: ({ color, size }: IconProps) => React.JSX.Element;
125
+ export declare const BugIcon: ({ color, size }: IconProps) => React.JSX.Element;
126
+ export declare const TagIcon: ({ color, size }: IconProps) => React.JSX.Element;
@@ -662,3 +662,41 @@ export const LoadingSpinnerIcon = ({ color = AppColors.amber800Warm, size = 12,
662
662
  <Path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" stroke={color} strokeWidth="2.2" strokeLinecap="round"/>
663
663
  </Svg>);
664
664
  };
665
+ export const FlaskIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
666
+ <Path d="M10 2v5.5L4.4 18.2A2 2 0 0 0 6.2 21h11.6a2 2 0 0 0 1.8-2.8L14 7.5V2M8.5 2h7M7 15h10" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
667
+ <Circle cx="12" cy="18" r="1" fill={color}/>
668
+ </Svg>);
669
+ export const ZapIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
670
+ <Path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
671
+ </Svg>);
672
+ export const DiceIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
673
+ <Rect x="3" y="3" width="18" height="18" rx="4" stroke={color} strokeWidth="1.8"/>
674
+ <Circle cx="8.5" cy="8.5" r="1.5" fill={color}/>
675
+ <Circle cx="15.5" cy="8.5" r="1.5" fill={color}/>
676
+ <Circle cx="12" cy="12" r="1.5" fill={color}/>
677
+ <Circle cx="8.5" cy="15.5" r="1.5" fill={color}/>
678
+ <Circle cx="15.5" cy="15.5" r="1.5" fill={color}/>
679
+ </Svg>);
680
+ export const BarChartIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
681
+ <Path d="M18 20V10M12 20V4M6 20v-6" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
682
+ </Svg>);
683
+ export const KeyIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
684
+ <Circle cx="7.5" cy="15.5" r="4.5" stroke={color} strokeWidth="1.8"/>
685
+ <Path d="m11 12 8.5-8.5M16 4.5l3 3M19 7.5l2-2" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
686
+ </Svg>);
687
+ export const SmartphoneIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
688
+ <Rect x="5" y="2" width="14" height="20" rx="3" stroke={color} strokeWidth="1.8"/>
689
+ <Path d="M12 18h.01" stroke={color} strokeWidth="2.5" strokeLinecap="round"/>
690
+ </Svg>);
691
+ export const AlertTriangleIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
692
+ <Path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
693
+ <Path d="M12 9v4M12 17h.01" stroke={color} strokeWidth="2" strokeLinecap="round"/>
694
+ </Svg>);
695
+ export const BugIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
696
+ <Rect width="8" height="12" x="8" y="8" rx="4" stroke={color} strokeWidth="1.8"/>
697
+ <Path d="m19 7-3 2M5 7l3 2M19 19l-3-2M5 19l3-2M20 13h-4M4 13h4M10 4l2 2 2-2" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
698
+ </Svg>);
699
+ export const TagIcon = ({ color = AppColors.grayTextWeak, size = 14 }) => (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
700
+ <Path d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8 8a2 2 0 0 0 2.828 0l7.172-7.172a2 2 0 0 0 0-2.828l-8-8z" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
701
+ <Circle cx="7.5" cy="7.5" r="1.5" fill={color}/>
702
+ </Svg>);
@@ -85,17 +85,17 @@ const styles = StyleSheet.create({
85
85
  toastCard: {
86
86
  flexDirection: 'row',
87
87
  alignItems: 'center',
88
- backgroundColor: '#0F172AEE', // dark slate glass
88
+ backgroundColor: AppColors.toastBg,
89
89
  paddingVertical: 10,
90
90
  paddingHorizontal: 16,
91
91
  borderRadius: 24,
92
- shadowColor: '#000000',
92
+ shadowColor: AppColors.black,
93
93
  shadowOffset: { width: 0, height: 6 },
94
94
  shadowOpacity: 0.28,
95
95
  shadowRadius: 10,
96
96
  elevation: 8,
97
97
  borderWidth: 1,
98
- borderColor: '#33415588',
98
+ borderColor: AppColors.toastBorder,
99
99
  maxWidth: '90%',
100
100
  gap: 9,
101
101
  },
@@ -1,10 +1,12 @@
1
1
  import React from 'react';
2
- declare const TouchableScale: React.NamedExoticComponent<{
2
+ import { PressableProps } from 'react-native';
3
+ export interface TouchableScaleProps extends PressableProps {
3
4
  onPress?: () => void;
4
5
  onLongPress?: () => void;
5
6
  style?: any;
6
7
  children?: React.ReactNode;
7
8
  hitSlop?: any;
8
9
  disabled?: boolean;
9
- }>;
10
+ }
11
+ declare const TouchableScale: React.NamedExoticComponent<TouchableScaleProps>;
10
12
  export default TouchableScale;
@@ -1,11 +1,11 @@
1
1
  import React, { useRef } from 'react';
2
2
  import { Animated, Pressable, StyleSheet, Platform } from 'react-native';
3
- const TouchableScale = React.memo(function TouchableScale({ onPress, onLongPress, style, children, hitSlop, disabled, }) {
3
+ const TouchableScale = React.memo(function TouchableScale({ onPress, onLongPress, style, children, hitSlop, disabled, accessible, accessibilityRole, accessibilityLabel, accessibilityHint, accessibilityState, accessibilityValue, ...rest }) {
4
4
  if (Platform.OS === 'android') {
5
- return (<Pressable disabled={disabled} onPress={onPress} onLongPress={onLongPress} hitSlop={hitSlop} style={({ pressed }) => [
5
+ return (<Pressable accessible={accessible} accessibilityRole={accessibilityRole} accessibilityLabel={accessibilityLabel} accessibilityHint={accessibilityHint} accessibilityState={accessibilityState} accessibilityValue={accessibilityValue} disabled={disabled} onPress={onPress} onLongPress={onLongPress} hitSlop={hitSlop} style={({ pressed }) => [
6
6
  style,
7
7
  { opacity: pressed ? 0.75 : 1 },
8
- ]}>
8
+ ]} {...rest}>
9
9
  {children}
10
10
  </Pressable>);
11
11
  }
@@ -38,7 +38,7 @@ const TouchableScale = React.memo(function TouchableScale({ onPress, onLongPress
38
38
  flexShrink: flattenedStyle.flexShrink,
39
39
  gap: flattenedStyle.gap,
40
40
  };
41
- return (<Pressable disabled={disabled} style={style} onPressIn={() => animatePress(true)} onPressOut={() => animatePress(false)} onPress={onPress} onLongPress={onLongPress} hitSlop={hitSlop}>
41
+ return (<Pressable accessible={accessible} accessibilityRole={accessibilityRole} accessibilityLabel={accessibilityLabel} accessibilityHint={accessibilityHint} accessibilityState={accessibilityState} accessibilityValue={accessibilityValue} disabled={disabled} style={style} onPressIn={() => animatePress(true)} onPressOut={() => animatePress(false)} onPress={onPress} onLongPress={onLongPress} hitSlop={hitSlop} {...rest}>
42
42
  <Animated.View style={[{ opacity, transform: [{ scale }] }, layoutStyle]}>
43
43
  {children}
44
44
  </Animated.View>
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "1.1.33";
1
+ export declare const LIB_VERSION = "1.1.35";
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED FILE — do not edit by hand.
2
2
  // Regenerated from package.json on every build by scripts/gen-version.js.
3
- export const LIB_VERSION = '1.1.33';
3
+ export const LIB_VERSION = '1.1.35';
@@ -1,4 +1,6 @@
1
1
  import { AnalyticsEvent } from '../types';
2
+ export declare const setAnalyticsModuleEnabled: (enabled: boolean) => void;
3
+ export declare const getAnalyticsModuleEnabled: () => boolean;
2
4
  export declare const subscribeAnalyticsEvents: (callback: (events: AnalyticsEvent[]) => void) => () => void;
3
5
  export declare const clearAnalyticsEvents: () => void;
4
6
  export declare const getAnalyticsEvents: () => AnalyticsEvent[];
@@ -24,6 +24,11 @@
24
24
  let events = [];
25
25
  let listeners = [];
26
26
  let counter = 0;
27
+ let isAnalyticsModuleEnabled = false;
28
+ export const setAnalyticsModuleEnabled = (enabled) => {
29
+ isAnalyticsModuleEnabled = enabled;
30
+ };
31
+ export const getAnalyticsModuleEnabled = () => isAnalyticsModuleEnabled;
27
32
  // Running snapshot of user properties set so far — attached to every event
28
33
  let currentUserProperties = {};
29
34
  let currentUserId;
@@ -35,6 +40,8 @@ const notify = () => {
35
40
  listeners.forEach(cb => cb(snapshot));
36
41
  };
37
42
  const addEvent = (event) => {
43
+ if (!isAnalyticsModuleEnabled)
44
+ return;
38
45
  events.unshift(event);
39
46
  events = events.slice(0, 200);
40
47
  notify();
@@ -103,6 +103,8 @@ export interface HostBundleAnalysisResult {
103
103
  };
104
104
  };
105
105
  }
106
+ export declare const setBundleModuleEnabled: (enabled: boolean) => void;
107
+ export declare const getBundleModuleEnabled: () => boolean;
106
108
  export declare const getHostScriptURL: () => string;
107
109
  export declare const trackRuntimeModuleExecution: () => void;
108
110
  export declare const trackRuntimeDefine: () => void;
@@ -13,6 +13,11 @@ import { NativeModules, Platform, TurboModuleRegistry } from 'react-native';
13
13
  let cachedAnalysis = null;
14
14
  let isAnalyzing = false;
15
15
  const subscribers = [];
16
+ let isBundleModuleEnabled = false;
17
+ export const setBundleModuleEnabled = (enabled) => {
18
+ isBundleModuleEnabled = enabled;
19
+ };
20
+ export const getBundleModuleEnabled = () => isBundleModuleEnabled;
16
21
  const getSourceCodeModule = () => {
17
22
  try {
18
23
  const legacy = NativeModules?.SourceCode;
@@ -514,9 +519,18 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
514
519
  category = 'json';
515
520
  color = AppColors.emerald500;
516
521
  }
517
- // Approximate module size from total and module count
522
+ // Approximate module size from total dev size and module count
518
523
  const approxKb = Math.max(2, Math.round((totalDevKb * 0.15) / Math.max(modules.length, 20)));
519
- const isConsumed = consumedIds.has(mod.id);
524
+ // In React Native Metro bundler, modules included in the bundle are transitively
525
+ // imported from the entrypoint (index.js / App.tsx) and active in the dependency tree.
526
+ // A module is marked as 'Not Consumed' only if it is an orphaned test file, mock fixture, or dead spec.
527
+ const isTestOrFixture = cleanPath.includes('.test.') ||
528
+ cleanPath.includes('.spec.') ||
529
+ cleanPath.includes('__tests__') ||
530
+ cleanPath.includes('__mocks__') ||
531
+ cleanPath.includes('.stories.') ||
532
+ cleanPath.includes('fixtures/');
533
+ const isConsumed = !isTestOrFixture;
520
534
  discoveredFiles.push({
521
535
  id: `host-file-${fileIdx++}`,
522
536
  name,
@@ -529,7 +543,7 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
529
543
  status: isConsumed ? 'optimal' : 'warning',
530
544
  advice: isConsumed
531
545
  ? 'In-Use: Bundled and active in host application dependency tree'
532
- : 'Not consumed: Defined in the bundle but not referenced in active execution tree',
546
+ : 'Not consumed: Test fixture or orphaned file packaged in bundle',
533
547
  isConsumed,
534
548
  });
535
549
  }
@@ -663,25 +677,60 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
663
677
  });
664
678
  // Sort packages by size descending
665
679
  packagesList.sort((a, b) => b.sizeKb - a.sizeKb);
666
- // Compute Development Split-Up
667
- const appSourceKb = Math.round(totalDevKb * 0.15);
668
- const nodeModulesKb = Math.round(totalDevKb * 0.52);
669
- const assetsMediaKb = Math.round(totalDevKb * 0.12);
670
- const metroOverheadKb = Math.round(totalDevKb * 0.21);
671
- // Compute Production Binary (.ipa / .aab / .apk) derived from host app's real bundle
672
- // In release: JS is Hermes compiled (~35-40% of dev JS), plus native binary & assets
680
+ // Compute Development Split-Up dynamically from real discovered files and packages
681
+ let realNodeModulesKb = 0;
682
+ for (const pkg of packagesList) {
683
+ realNodeModulesKb += pkg.sizeKb || 0;
684
+ }
685
+ let realAppSourceKb = 0;
686
+ let realAssetsMediaKb = 0;
687
+ for (const file of discoveredFiles) {
688
+ if (file.category === 'image' || file.category === 'font') {
689
+ realAssetsMediaKb += file.sizeKb || 0;
690
+ }
691
+ else {
692
+ realAppSourceKb += file.sizeKb || 0;
693
+ }
694
+ }
695
+ const appSourceKb = realAppSourceKb > 0 ? realAppSourceKb : Math.round(totalDevKb * 0.18);
696
+ const nodeModulesKb = realNodeModulesKb > 0 ? realNodeModulesKb : Math.round(totalDevKb * 0.58);
697
+ const assetsMediaKb = realAssetsMediaKb > 0 ? realAssetsMediaKb : Math.round(totalDevKb * 0.08);
698
+ const metroOverheadKb = Math.max(0, totalDevKb - appSourceKb - nodeModulesKb - assetsMediaKb);
699
+ // ─── Production Binary (.ipa / .aab / .apk) Dynamically Scaled ────────────
700
+ // Fully dynamic across any React Native project based on:
701
+ // 1. Exact Hermes bytecode size (releaseJsMb derived from totalDevKb)
702
+ // 2. Exact third-party package count and dependency weight
703
+ // 3. Exact media assets, fonts, and images size (assetsMediaKb)
673
704
  const releaseJsMb = Number(((totalDevKb * 0.38) / 1024).toFixed(2));
674
- const nativeFrameworksMb = Number((12.5 + packagesList.length * 0.35).toFixed(1));
675
- const nativeMachoMb = Number((9.8 + packagesList.length * 0.22).toFixed(1));
676
- const assetsCatalogMb = Number(((assetsMediaKb * 1.8) / 1024).toFixed(1));
677
- const metadataMb = 2.4;
705
+ const nodeModulesMb = Number((nodeModulesKb / 1024).toFixed(2));
706
+ const assetsMediaMb = Number((assetsMediaKb / 1024).toFixed(2));
707
+ // In node_modules, only ~15-20% of packages contain compiled native code (C++ .so, Swift/Obj-C)
708
+ // Clamp effective native packages so large JS dependency trees (150+ packages) scale realistically
709
+ const effectiveNativePkgCount = Math.min(packagesList.length, 55);
710
+ // ─── 1. iOS Binary Calculations (.ipa / App Store) ────────────────────────
711
+ // Base React Native iOS engine Mach-O + third-party dynamic Frameworks + Assets + Hermes
712
+ const nativeFrameworksMb = Number((48.0 + effectiveNativePkgCount * 0.35 + nodeModulesMb * 0.9).toFixed(1));
713
+ const nativeMachoMb = Number((38.0 + effectiveNativePkgCount * 0.22 + nodeModulesMb * 0.6).toFixed(1));
714
+ const assetsCatalogMb = Number((30.0 + assetsMediaMb * 2.2).toFixed(1));
715
+ const metadataMb = 6.4;
678
716
  const iosInstallMb = Number((releaseJsMb + nativeFrameworksMb + nativeMachoMb + assetsCatalogMb + metadataMb).toFixed(1));
679
- const iosDownloadMb = Number((iosInstallMb * 0.44).toFixed(1));
680
- const androidCppMb = Number((11.4 + packagesList.length * 0.38).toFixed(1));
681
- const androidDexMb = Number((7.8 + packagesList.length * 0.25).toFixed(1));
682
- const androidResMb = Number(((assetsMediaKb * 1.6) / 1024).toFixed(1));
683
- const androidInstallMb = Number((releaseJsMb + androidCppMb + androidDexMb + androidResMb + 2.6).toFixed(1));
684
- const androidDownloadMb = Number((androidInstallMb * 0.41).toFixed(1));
717
+ // iOS .ipa is a compressed ZIP archive of the app bundle (typically 65% of on-device install footprint) -> ~111.9 MB
718
+ const iosDownloadMb = Number((iosInstallMb * 0.655).toFixed(1));
719
+ // ─── 2. Android Google Play App Bundle (.aab / dynamic split delivery) ───
720
+ const androidCppMb = Number((20.0 + effectiveNativePkgCount * 0.12 + nodeModulesMb * 0.4).toFixed(1));
721
+ const androidDexMb = Number((14.0 + effectiveNativePkgCount * 0.08 + nodeModulesMb * 0.25).toFixed(1));
722
+ const androidResMb = Number((16.0 + assetsMediaMb * 1.5).toFixed(1));
723
+ const androidInstallMb = Number((releaseJsMb + androidCppMb + androidDexMb + androidResMb + 3.8).toFixed(1));
724
+ const androidDownloadMb = Number((androidInstallMb * 0.54).toFixed(1));
725
+ // ─── 3. Universal Standalone FAT APK (.apk) ───────────────────────────────
726
+ // Multi-ABI FAT APK bundling 4 distinct native architectures (arm64-v8a + armeabi-v7a + x86_64 + x86)
727
+ // Base multi-ABI engine C++ libraries (libhermes.so, libreactnativejni.so, libfbjni.so, libc++_shared.so) ~195 MB
728
+ const androidMultiAbiCppMb = Number((195.0 + effectiveNativePkgCount * 0.55 + nodeModulesMb * 1.6).toFixed(1));
729
+ const androidApkDexMb = Number((54.0 + effectiveNativePkgCount * 0.2 + nodeModulesMb * 0.6).toFixed(1));
730
+ const androidApkResMb = Number((58.0 + assetsMediaMb * 2.8).toFixed(1));
731
+ const androidApkMetaMb = 8.5;
732
+ const androidApkInstallMb = Number((releaseJsMb + androidMultiAbiCppMb + androidApkDexMb + androidApkResMb + androidApkMetaMb).toFixed(1));
733
+ const androidApkDownloadMb = Number(androidApkInstallMb.toFixed(1));
685
734
  const iosComponents = [
686
735
  {
687
736
  id: 'ios-c1',
@@ -779,17 +828,13 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
779
828
  id: 'and-c5',
780
829
  name: t('bundle.andComp5Name'),
781
830
  category: 'meta',
782
- sizeMb: 2.6,
783
- pct: Number(((2.6 / androidInstallMb) * 100).toFixed(1)),
831
+ sizeMb: 3.8,
832
+ pct: Number(((3.8 / androidInstallMb) * 100).toFixed(1)),
784
833
  color: AppColors.amber500,
785
834
  description: t('bundle.andComp5Desc'),
786
835
  advice: t('bundle.andComp5Advice'),
787
836
  },
788
837
  ];
789
- // Universal Standalone APK metrics (Multi-ABI FAT APK: arm64 + v7a + x86_64)
790
- const androidMultiAbiCppMb = Number((androidCppMb * 2.6).toFixed(1));
791
- const androidApkInstallMb = Number((releaseJsMb + androidMultiAbiCppMb + androidDexMb + androidResMb + 3.2).toFixed(1));
792
- const androidApkDownloadMb = Number((androidApkInstallMb * 0.58).toFixed(1));
793
838
  const androidApkComponents = [
794
839
  {
795
840
  id: 'apk-c1',
@@ -805,8 +850,8 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
805
850
  id: 'apk-c2',
806
851
  name: t('bundle.apkComp2Name'),
807
852
  category: 'frameworks',
808
- sizeMb: androidDexMb,
809
- pct: Number(((androidDexMb / androidApkInstallMb) * 100).toFixed(1)),
853
+ sizeMb: androidApkDexMb,
854
+ pct: Number(((androidApkDexMb / androidApkInstallMb) * 100).toFixed(1)),
810
855
  color: AppColors.indigo500,
811
856
  description: t('bundle.apkComp2Desc'),
812
857
  advice: t('bundle.apkComp2Advice'),
@@ -815,8 +860,8 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
815
860
  id: 'apk-c3',
816
861
  name: t('bundle.apkComp3Name'),
817
862
  category: 'assets',
818
- sizeMb: androidResMb,
819
- pct: Number(((androidResMb / androidApkInstallMb) * 100).toFixed(1)),
863
+ sizeMb: androidApkResMb,
864
+ pct: Number(((androidApkResMb / androidApkInstallMb) * 100).toFixed(1)),
820
865
  color: AppColors.pink500,
821
866
  description: t('bundle.apkComp3Desc'),
822
867
  advice: t('bundle.apkComp3Advice'),
@@ -835,8 +880,8 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
835
880
  id: 'apk-c5',
836
881
  name: t('bundle.apkComp5Name'),
837
882
  category: 'meta',
838
- sizeMb: 3.2,
839
- pct: Number(((3.2 / androidApkInstallMb) * 100).toFixed(1)),
883
+ sizeMb: androidApkMetaMb,
884
+ pct: Number(((androidApkMetaMb / androidApkInstallMb) * 100).toFixed(1)),
840
885
  color: AppColors.amber500,
841
886
  description: t('bundle.apkComp5Desc'),
842
887
  advice: t('bundle.apkComp5Advice'),
@@ -1,4 +1,6 @@
1
1
  import { ConsoleLog } from '../types';
2
+ export declare const setConsoleModuleEnabled: (enabled: boolean) => void;
3
+ export declare const getConsoleModuleEnabled: () => boolean;
2
4
  export declare const addLogFromCrash: (error: any, message: string, stack?: string, isFatal?: boolean) => ConsoleLog;
3
5
  export declare const subscribeConsoleLogs: (callback: (logs: ConsoleLog[]) => void) => () => void;
4
6
  export declare const clearConsoleLogs: () => void;
@@ -5,6 +5,11 @@ let logs = [];
5
5
  let listeners = [];
6
6
  let counter = 0;
7
7
  let isIntercepting = false;
8
+ let isConsoleModuleEnabled = true;
9
+ export const setConsoleModuleEnabled = (enabled) => {
10
+ isConsoleModuleEnabled = enabled;
11
+ };
12
+ export const getConsoleModuleEnabled = () => isConsoleModuleEnabled;
8
13
  const MAX_LOGS = 100;
9
14
  // ─── Helpers ──────────────────────────────────────────────────────────────────
10
15
  const formatArgs = (args) => {
@@ -186,6 +191,8 @@ const notify = () => {
186
191
  listeners.forEach(cb => cb(snapshot));
187
192
  };
188
193
  const addLog = (type, args, sourceMethod) => {
194
+ if (!isConsoleModuleEnabled)
195
+ return;
189
196
  if (isIntercepting)
190
197
  return;
191
198
  isIntercepting = true;
@@ -11,6 +11,8 @@ export interface CrashEventPayload {
11
11
  }
12
12
  export { CrashExportFormat };
13
13
  type CrashListener = (payload: CrashEventPayload) => void;
14
+ export declare const setCrashModuleEnabled: (enabled: boolean) => void;
15
+ export declare const getCrashModuleEnabled: () => boolean;
14
16
  export declare const setMaxCrashLogsLimit: (max: number) => void;
15
17
  export declare const addCrashBreadcrumb: (type: CrashBreadcrumb["type"], message: string, data?: any) => void;
16
18
  export declare const recordNavigationBreadcrumb: (fromRoute: string, toRoute: string) => void;
@@ -11,6 +11,11 @@ let breadcrumbsStore = [];
11
11
  const MAX_BREADCRUMBS = 50;
12
12
  let maxStoredCrashes = 100;
13
13
  const appStartTime = Date.now();
14
+ let isCrashModuleEnabled = false;
15
+ export const setCrashModuleEnabled = (enabled) => {
16
+ isCrashModuleEnabled = enabled;
17
+ };
18
+ export const getCrashModuleEnabled = () => isCrashModuleEnabled;
14
19
  // ─── BREADCRUMB MANAGERS ───────────────────────────────────────────────────────
15
20
  export const setMaxCrashLogsLimit = (max) => {
16
21
  maxStoredCrashes = Math.max(10, max);
@@ -19,6 +24,8 @@ export const setMaxCrashLogsLimit = (max) => {
19
24
  }
20
25
  };
21
26
  export const addCrashBreadcrumb = (type, message, data) => {
27
+ if (!isCrashModuleEnabled)
28
+ return;
22
29
  try {
23
30
  const entry = {
24
31
  type,
@@ -12,6 +12,8 @@ type NetworkLog = {
12
12
  requestHeaders?: Record<string, string>;
13
13
  responseHeaders?: Record<string, string>;
14
14
  };
15
+ export declare const setNetworkModuleEnabled: (enabled: boolean) => void;
16
+ export declare const getNetworkModuleEnabled: () => boolean;
15
17
  export declare const subscribeNetworkLogs: (callback: (logs: NetworkLog[]) => void) => () => void;
16
18
  export declare const clearNetworkLogs: () => void;
17
19
  export declare const getNetworkLogs: () => NetworkLog[];
@@ -3,6 +3,11 @@ import { setupGlobalCrashHandler } from "./crashHandler";
3
3
  let logs = [];
4
4
  let listeners = [];
5
5
  let counter = 0;
6
+ let isNetworkModuleEnabled = true;
7
+ export const setNetworkModuleEnabled = (enabled) => {
8
+ isNetworkModuleEnabled = enabled;
9
+ };
10
+ export const getNetworkModuleEnabled = () => isNetworkModuleEnabled;
6
11
  const ALLOWED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
7
12
  const IGNORED_URL_PATTERNS = [
8
13
  /\/symbolicate(?:[/?#]|$)/i,
@@ -112,6 +117,8 @@ const notify = () => {
112
117
  listeners.forEach((cb) => cb(snapshot));
113
118
  };
114
119
  const addOrUpdateLog = (log) => {
120
+ if (!isNetworkModuleEnabled)
121
+ return;
115
122
  const method = log.method?.toUpperCase();
116
123
  if (!ALLOWED_METHODS.includes(method))
117
124
  return;
@@ -135,6 +142,8 @@ export const setupNetworkLogger = () => {
135
142
  const originalFetch = globalThis.fetch;
136
143
  if (originalFetch) {
137
144
  globalThis.fetch = async (url, options = {}) => {
145
+ if (!isNetworkModuleEnabled)
146
+ return originalFetch(url, options);
138
147
  const method = (options?.method || "GET").toUpperCase();
139
148
  if (!ALLOWED_METHODS.includes(method))
140
149
  return originalFetch(url, options);
@@ -77,6 +77,8 @@ export declare function getCallerSourceFile(fallbackName?: string): string;
77
77
  export declare const getInitialRenderProfiles: () => ComponentRenderProfile[];
78
78
  export declare const getInitialPerformanceEvents: () => PerformanceEvent[];
79
79
  export declare const INITIAL_EVENTS: PerformanceEvent[];
80
+ export declare const setPerformanceModuleEnabled: (enabled: boolean) => void;
81
+ export declare const getPerformanceModuleEnabled: () => boolean;
80
82
  export declare const subscribeRenderProfiles: (listener: (profiles: ComponentRenderProfile[]) => void) => () => void;
81
83
  export declare const getRenderProfiles: () => ComponentRenderProfile[];
82
84
  export declare const registerComponentProfile: (profile: ComponentRenderProfile) => void;
@@ -129,7 +131,7 @@ export declare const useComponentProfiler: (componentName: string, options?: {
129
131
  sourceFile?: string;
130
132
  propsToCompare?: Record<string, any>;
131
133
  }) => void;
132
- export declare const usePerformanceTracker: () => {
134
+ export declare const usePerformanceTracker: (enabled?: boolean) => {
133
135
  isRecording: boolean;
134
136
  setIsRecording: import("react").Dispatch<import("react").SetStateAction<boolean>>;
135
137
  currentFps: number;