react-native-inapp-inspector 1.1.25 → 1.1.26

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 (70) hide show
  1. package/android/build.gradle +36 -0
  2. package/android/src/main/AndroidManifest.xml +3 -0
  3. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +114 -0
  4. package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.java +28 -0
  5. package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
  6. package/dist/commonjs/components/ErrorBoundary.js +9 -145
  7. package/dist/commonjs/components/Inspector/CrashDetail.d.ts +3 -0
  8. package/dist/commonjs/components/Inspector/CrashDetail.js +796 -0
  9. package/dist/commonjs/components/Inspector/CrashFilterModal.d.ts +20 -0
  10. package/dist/commonjs/components/Inspector/CrashFilterModal.js +597 -0
  11. package/dist/commonjs/components/Inspector/CrashTab.d.ts +3 -0
  12. package/dist/commonjs/components/Inspector/CrashTab.js +727 -0
  13. package/dist/commonjs/components/Inspector/InspectorHeader.js +52 -23
  14. package/dist/commonjs/components/Inspector/LogDetail.js +4 -3
  15. package/dist/commonjs/components/Inspector/MainScreen.js +12 -3
  16. package/dist/commonjs/components/Inspector/SettingsPanel.js +90 -1
  17. package/dist/commonjs/components/Inspector/TabBar.js +15 -3
  18. package/dist/commonjs/components/NetworkIcons.d.ts +11 -0
  19. package/dist/commonjs/components/NetworkIcons.js +96 -1
  20. package/dist/commonjs/components/SegmentedTabs.js +2 -1
  21. package/dist/commonjs/constants/version.d.ts +1 -1
  22. package/dist/commonjs/constants/version.js +1 -1
  23. package/dist/commonjs/customHooks/analyticsLogger.js +70 -44
  24. package/dist/commonjs/customHooks/consoleLogger.d.ts +1 -0
  25. package/dist/commonjs/customHooks/consoleLogger.js +70 -6
  26. package/dist/commonjs/customHooks/crashHandler.d.ts +64 -0
  27. package/dist/commonjs/customHooks/crashHandler.js +681 -0
  28. package/dist/commonjs/customHooks/networkLogger.js +64 -48
  29. package/dist/commonjs/helpers/gaAnalyticsRegistry.js +1 -1
  30. package/dist/commonjs/i18n/locales/en.json +131 -0
  31. package/dist/commonjs/index.d.ts +3 -1
  32. package/dist/commonjs/index.js +95 -1
  33. package/dist/commonjs/types/enums.d.ts +41 -0
  34. package/dist/commonjs/types/enums.js +37 -1
  35. package/dist/commonjs/types/interfaces.d.ts +51 -1
  36. package/dist/esm/components/ErrorBoundary.d.ts +1 -1
  37. package/dist/esm/components/ErrorBoundary.js +10 -113
  38. package/dist/esm/components/Inspector/CrashDetail.d.ts +3 -0
  39. package/dist/esm/components/Inspector/CrashDetail.js +758 -0
  40. package/dist/esm/components/Inspector/CrashFilterModal.d.ts +20 -0
  41. package/dist/esm/components/Inspector/CrashFilterModal.js +557 -0
  42. package/dist/esm/components/Inspector/CrashTab.d.ts +3 -0
  43. package/dist/esm/components/Inspector/CrashTab.js +689 -0
  44. package/dist/esm/components/Inspector/InspectorHeader.js +52 -23
  45. package/dist/esm/components/Inspector/LogDetail.js +4 -3
  46. package/dist/esm/components/Inspector/MainScreen.js +12 -3
  47. package/dist/esm/components/Inspector/SettingsPanel.js +91 -2
  48. package/dist/esm/components/Inspector/TabBar.js +16 -4
  49. package/dist/esm/components/NetworkIcons.d.ts +11 -0
  50. package/dist/esm/components/NetworkIcons.js +83 -0
  51. package/dist/esm/components/SegmentedTabs.js +2 -1
  52. package/dist/esm/constants/version.d.ts +1 -1
  53. package/dist/esm/constants/version.js +1 -1
  54. package/dist/esm/customHooks/analyticsLogger.js +70 -44
  55. package/dist/esm/customHooks/consoleLogger.d.ts +1 -0
  56. package/dist/esm/customHooks/consoleLogger.js +68 -5
  57. package/dist/esm/customHooks/crashHandler.d.ts +64 -0
  58. package/dist/esm/customHooks/crashHandler.js +659 -0
  59. package/dist/esm/customHooks/networkLogger.js +64 -48
  60. package/dist/esm/helpers/gaAnalyticsRegistry.js +1 -1
  61. package/dist/esm/i18n/locales/en.json +131 -0
  62. package/dist/esm/index.d.ts +3 -1
  63. package/dist/esm/index.js +73 -1
  64. package/dist/esm/types/enums.d.ts +41 -0
  65. package/dist/esm/types/enums.js +36 -0
  66. package/dist/esm/types/interfaces.d.ts +51 -1
  67. package/ios/NetworkInspectorModule.h +6 -0
  68. package/ios/NetworkInspectorModule.m +125 -0
  69. package/package.json +5 -2
  70. package/react-native-inapp-inspector.podspec +18 -0
@@ -12,7 +12,7 @@ import { LIB_VERSION } from '../../constants';
12
12
  import { getStatusColor, getAppName, getBundleIdentifier, formatTime, getSize } from '../../helpers';
13
13
  import { WhiteBackNavigation, TrashIcon, SettingsIcon, CloseWhite, ChevronIcon, ClockIcon, AppleIcon, AndroidIcon, PackageBoxIcon, } from '../NetworkIcons';
14
14
  const InspectorHeader = React.memo(() => {
15
- const { modalHeightPercent, appIcon, selected, setSelected, selectedEvent, setSelectedEvent, selectedLog, setSelectedLog, selectedReduxSlice, setSelectedReduxSlice, selectedReduxAction, setSelectedReduxAction, reduxState, reduxLastActionMap, showHeaderInfo, setShowHeaderInfo, updateAvailable, latestNpmVersion, clearAnim, activePulseAnim, unreadPulseAnim, runClearAllWithAnimation, setSettingsPage, closeModal, detailTitle, activeTab, environment, } = useInspector();
15
+ const { modalHeightPercent, appIcon, selected, setSelected, selectedEvent, setSelectedEvent, selectedLog, setSelectedLog, selectedReduxSlice, setSelectedReduxSlice, selectedReduxAction, setSelectedReduxAction, reduxState, reduxLastActionMap, showHeaderInfo, setShowHeaderInfo, updateAvailable, latestNpmVersion, clearAnim, activePulseAnim, unreadPulseAnim, runClearAllWithAnimation, setSettingsPage, closeModal, detailTitle, activeTab, environment, selectedCrash, setSelectedCrash, } = useInspector();
16
16
  const envConfig = useMemo(() => {
17
17
  const rawEnv = (environment || (__DEV__ ? 'DEV' : 'PROD')).trim();
18
18
  const clean = rawEnv.toUpperCase();
@@ -51,7 +51,8 @@ const InspectorHeader = React.memo(() => {
51
51
  const isDetailView = (activeTab === 'apis' && selected != null) ||
52
52
  (activeTab === 'analytics' && selectedEvent != null) ||
53
53
  (activeTab === 'logs' && selectedLog != null) ||
54
- (activeTab === 'redux' && (selectedReduxSlice != null || selectedReduxAction != null));
54
+ (activeTab === 'redux' && (selectedReduxSlice != null || selectedReduxAction != null)) ||
55
+ (activeTab === 'crash' && selectedCrash != null);
55
56
  const isAnySelected = isDetailView;
56
57
  const headerTopPadding = Platform.OS === 'ios' && modalHeightPercent >= 95 ? 44 : 0;
57
58
  return (<LinearGradient colors={[AppColors.purple, AppColors.brandPurple]} style={styles.headerGradient}>
@@ -62,8 +63,9 @@ const InspectorHeader = React.memo(() => {
62
63
  {
63
64
  flexDirection: 'row',
64
65
  alignItems: 'center',
65
- gap: 16,
66
- flex: !isDetailView ? 5 : 1,
66
+ gap: 12,
67
+ flex: !isDetailView ? 1 : 0,
68
+ minWidth: 0,
67
69
  },
68
70
  ]}>
69
71
  <TouchableScale onPress={() => {
@@ -73,6 +75,7 @@ const InspectorHeader = React.memo(() => {
73
75
  setSelectedLog(null);
74
76
  setSelectedReduxSlice(null);
75
77
  setSelectedReduxAction(null);
78
+ setSelectedCrash(null);
76
79
  });
77
80
  }} hitSlop={15} style={[
78
81
  {
@@ -486,18 +489,58 @@ const InspectorHeader = React.memo(() => {
486
489
  {selectedReduxAction.timestamp || 'Dispatched'}
487
490
  </Text>
488
491
  </View>
492
+ </View>) : activeTab === 'crash' && selectedCrash != null ? (<View style={styles.headerDetailCenter}>
493
+ <View style={styles.headerDetailRow}>
494
+ <View style={[
495
+ styles.headerMethodBadge,
496
+ {
497
+ backgroundColor: selectedCrash.isFatal
498
+ ? '#DC2626'
499
+ : '#D97706',
500
+ },
501
+ ]}>
502
+ <Text style={styles.headerMethodText}>
503
+ {selectedCrash.isFatal ? 'FATAL' : selectedCrash.type.toUpperCase()}
504
+ </Text>
505
+ </View>
506
+ <Text style={styles.headerDetailTitle} numberOfLines={1} ellipsizeMode="middle">
507
+ {selectedCrash.name || selectedCrash.message}
508
+ </Text>
509
+ </View>
510
+ <View style={styles.headerDetailSubRow}>
511
+ <View style={[
512
+ styles.headerStatusDot,
513
+ {
514
+ backgroundColor: selectedCrash.isFatal
515
+ ? '#DC2626'
516
+ : '#F59E0B',
517
+ },
518
+ ]}/>
519
+ <Text style={styles.headerSubTitle}>
520
+ {selectedCrash.timeStr || new Date(selectedCrash.timestamp).toLocaleTimeString()}
521
+ </Text>
522
+ {selectedCrash.deviceInfo?.platform && (<>
523
+ <Text style={[styles.headerSubTitle, { opacity: 0.6 }]}>•</Text>
524
+ <Text style={styles.headerSubTitle}>
525
+ {selectedCrash.deviceInfo.platform.toUpperCase()}
526
+ </Text>
527
+ </>)}
528
+ </View>
489
529
  </View>) : null}
490
530
  </View>)}
491
531
 
492
532
  <View style={[
493
533
  styles.headerRight,
494
- !isAnySelected && {
534
+ {
535
+ flexDirection: 'row',
536
+ alignItems: 'center',
537
+ justifyContent: 'flex-end',
495
538
  flexShrink: 0,
496
- minWidth: 116,
539
+ gap: 8,
497
540
  },
498
541
  ]}>
499
542
  {!isAnySelected && (<TouchableScale onPress={() => {
500
- Alert.alert('Clear Everything', 'This clears all tabs — APIs, Logs, Analytics and Redux timeline. Continue?', [
543
+ Alert.alert('Clear Everything', 'This clears all tabs — APIs, Logs, Analytics, Redux timeline and Crash history. Continue?', [
501
544
  { text: 'Cancel', style: 'cancel' },
502
545
  {
503
546
  text: 'Clear All',
@@ -505,13 +548,7 @@ const InspectorHeader = React.memo(() => {
505
548
  style: 'destructive',
506
549
  },
507
550
  ]);
508
- }} hitSlop={15} style={[
509
- styles.closeButtonSquare,
510
- {
511
- marginRight: 8,
512
- backgroundColor: `${AppColors.white}26`,
513
- },
514
- ]}>
551
+ }} hitSlop={15} style={styles.closeButtonSquare}>
515
552
  <Animated.View style={{
516
553
  transform: [
517
554
  {
@@ -532,15 +569,7 @@ const InspectorHeader = React.memo(() => {
532
569
  </Animated.View>
533
570
  </TouchableScale>)}
534
571
 
535
- {selected == null &&
536
- selectedEvent == null &&
537
- selectedLog == null && (<TouchableScale onPress={() => setSettingsPage('main')} hitSlop={15} style={[
538
- styles.closeButtonSquare,
539
- {
540
- marginRight: 8,
541
- backgroundColor: `${AppColors.white}26`,
542
- },
543
- ]}>
572
+ {!isAnySelected && (<TouchableScale onPress={() => setSettingsPage('main')} hitSlop={15} style={styles.closeButtonSquare}>
544
573
  <SettingsIcon color={AppColors.white} size={16}/>
545
574
  </TouchableScale>)}
546
575
 
@@ -262,7 +262,8 @@ const LogDetail = React.memo(() => {
262
262
  fontSize: 13,
263
263
  color: AppColors.primaryBlack,
264
264
  lineHeight: 18,
265
- }} numberOfLines={1}>
265
+ flexShrink: 1,
266
+ }}>
266
267
  {originFrame?.functionName && originFrame.functionName !== '<anonymous>'
267
268
  ? `${originFrame.functionName}()`
268
269
  : originFrame?.fileName || t('console.consoleLog')}
@@ -277,11 +278,11 @@ const LogDetail = React.memo(() => {
277
278
  paddingVertical: 2,
278
279
  },
279
280
  ]}>
280
- <View style={{ flexDirection: 'row', alignItems: 'center', gap: 3 }}>
281
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 3, flexWrap: 'wrap', flexShrink: 1 }}>
281
282
  <DocIcon color={AppColors.brandPurple} size={10}/>
282
283
  <Text style={[
283
284
  styles.metaChipText,
284
- { color: AppColors.brandPurple, fontSize: 10, fontFamily: AppFonts.interBold },
285
+ { color: AppColors.brandPurple, fontSize: 10, fontFamily: AppFonts.interBold, flexShrink: 1 },
285
286
  ]}>
286
287
  {originFrame.fileName}
287
288
  {originFrame.lineNumber ? `:${originFrame.lineNumber}` : ''}
@@ -15,12 +15,14 @@ import ReduxTab from './ReduxTab';
15
15
  import ReduxDetail from './ReduxDetail';
16
16
  import BundleTab from './BundleTab';
17
17
  import PerformanceTab from './PerformanceTab';
18
+ import CrashTab from './CrashTab';
19
+ import CrashDetail from './CrashDetail';
18
20
  import SettingsPanel from './SettingsPanel';
19
21
  import styles from '../../styles';
20
22
  import { AppColors } from '../../styles/AppColors';
21
23
  import NavigationTracker from './NavigationTracker';
22
24
  const MainScreen = () => {
23
- const { visible, modalAnimationType, closeModal, modalHeightPercent, selected, selectedEvent, selectedLog, selectedReduxSlice, selectedReduxAction, settingsPage, activeTab, isReady, isEnabled, hasNavigationContext, setNavState, } = useInspector();
25
+ const { visible, modalAnimationType, closeModal, modalHeightPercent, selected, selectedEvent, selectedLog, selectedReduxSlice, selectedReduxAction, selectedCrash, settingsPage, activeTab, isReady, isEnabled, hasNavigationContext, setNavState, } = useInspector();
24
26
  // Lazy-mount each tab on first visit and cache it in memory for 0ms instantaneous switching
25
27
  const [mountedTabs, setMountedTabs] = useState({
26
28
  [activeTab]: true,
@@ -35,7 +37,8 @@ const MainScreen = () => {
35
37
  const isDetailActive = (activeTab === 'apis' && selected != null) ||
36
38
  (activeTab === 'analytics' && selectedEvent != null) ||
37
39
  (activeTab === 'logs' && selectedLog != null) ||
38
- (activeTab === 'redux' && (selectedReduxSlice != null || selectedReduxAction != null));
40
+ (activeTab === 'redux' && (selectedReduxSlice != null || selectedReduxAction != null)) ||
41
+ (activeTab === 'crash' && selectedCrash != null);
39
42
  return (<>
40
43
  {(Platform.OS === 'ios' || Platform.OS === 'android') && isEnabled && <FabLauncher />}
41
44
  <Modal visible={visible} animationType={modalAnimationType} transparent>
@@ -53,7 +56,7 @@ const MainScreen = () => {
53
56
  {/* ─── Horizontal Scrollable Tab Bar inside Content ─── */}
54
57
  {!isDetailActive && settingsPage === null ? (<TabBar />) : null}
55
58
 
56
- {isReady ? (isDetailActive ? (activeTab === 'apis' && selected != null ? (<NetworkDetail />) : activeTab === 'analytics' && selectedEvent != null ? (<AnalyticsDetail event={selectedEvent}/>) : activeTab === 'logs' && selectedLog != null ? (<LogDetail />) : activeTab === 'redux' ? (<ReduxDetail />) : null) : (<>
59
+ {isReady ? (isDetailActive ? (activeTab === 'apis' && selected != null ? (<NetworkDetail />) : activeTab === 'analytics' && selectedEvent != null ? (<AnalyticsDetail event={selectedEvent}/>) : activeTab === 'logs' && selectedLog != null ? (<LogDetail />) : activeTab === 'redux' ? (<ReduxDetail />) : activeTab === 'crash' && selectedCrash != null ? (<CrashDetail />) : null) : (<>
57
60
  <View style={{
58
61
  flex: 1,
59
62
  display: activeTab === 'apis' ? 'flex' : 'none',
@@ -90,6 +93,12 @@ const MainScreen = () => {
90
93
  }}>
91
94
  {mountedTabs.performance && <PerformanceTab />}
92
95
  </View>
96
+ <View style={{
97
+ flex: 1,
98
+ display: activeTab === 'crash' ? 'flex' : 'none',
99
+ }}>
100
+ {mountedTabs.crash && <CrashTab />}
101
+ </View>
93
102
  </>)) : (<View style={styles.empty}>
94
103
  <ActivityIndicator size="large" color={AppColors.purple}/>
95
104
  <Text style={[styles.emptySub, { marginTop: 12 }]}>
@@ -12,9 +12,10 @@ import { isPersistentStorageAvailable } from '../../helpers/settingsStore';
12
12
  import { clearNetworkLogs } from '../../customHooks/networkLogger';
13
13
  import { clearConsoleLogs } from '../../customHooks/consoleLogger';
14
14
  import { clearAnalyticsEvents } from '../../customHooks/analyticsLogger';
15
- import { SignalIcon, TerminalIcon, AnalyticsIcon, SettingsIcon, SunIcon, MoonIcon, ScreenIcon, MotionIcon, LayersIcon, EyeIcon, CheckIcon, TrashIcon, WhiteBackNavigation, PackageIcon, ReduxIcon, PerformanceIcon, } from '../NetworkIcons';
15
+ import { clearCrashRecords, } from '../../customHooks/crashHandler';
16
+ import { SignalIcon, TerminalIcon, AnalyticsIcon, SettingsIcon, SunIcon, MoonIcon, ScreenIcon, MotionIcon, LayersIcon, EyeIcon, CheckIcon, TrashIcon, WhiteBackNavigation, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, ShieldAlertIcon, } from '../NetworkIcons';
16
17
  const SettingsPanel = () => {
17
- const { settingsPage, setSettingsPage, settingsActiveSubTab, setSettingsActiveSubTab, tabVisibility, toggleTabVisibility, defaultTab, setDefaultTab, isDark, setIsDark, modalHeightPercent, setModalHeightPercent, modalAnimationType, setModalAnimationType, showDuplicateLogs, setShowDuplicateLogs, showConsoleLevels, setShowConsoleLevels, resetToDefaults, storage, logs, consoleLogs, analyticsEvents, reduxState, maxNetworkLogs, setMaxNetworkLogs, maxConsoleLogs, setMaxConsoleLogs, reduxAutoRefresh, setReduxAutoRefreshState, reduxExpandDepth, setReduxExpandDepth, switchActiveTab, setSelected, setSelectedEvent, setReduxState, } = useInspector();
18
+ const { settingsPage, setSettingsPage, settingsActiveSubTab, setSettingsActiveSubTab, tabVisibility, toggleTabVisibility, defaultTab, setDefaultTab, isDark, setIsDark, modalHeightPercent, setModalHeightPercent, modalAnimationType, setModalAnimationType, showDuplicateLogs, setShowDuplicateLogs, showConsoleLevels, setShowConsoleLevels, resetToDefaults, storage, logs, consoleLogs, analyticsEvents, reduxState, maxNetworkLogs, setMaxNetworkLogs, maxConsoleLogs, setMaxConsoleLogs, reduxAutoRefresh, setReduxAutoRefreshState, reduxExpandDepth, setReduxExpandDepth, switchActiveTab, setSelected, setSelectedEvent, setReduxState, crashRecords, maxCrashLogs, setMaxCrashLogs, } = useInspector();
18
19
  const isPersistent = isPersistentStorageAvailable();
19
20
  const headerTopPadding = Platform.OS === 'ios' && modalHeightPercent >= 95 ? 44 : 0;
20
21
  if (settingsPage === 'main') {
@@ -25,6 +26,7 @@ const SettingsPanel = () => {
25
26
  { key: 'redux', label: 'Redux', icon: 'redux' },
26
27
  { key: 'bundle', label: 'Bundle', icon: 'bundle' },
27
28
  { key: 'performance', label: 'Performance', icon: 'performance' },
29
+ { key: 'crash', label: 'Crash', icon: 'crash' },
28
30
  ];
29
31
  return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
30
32
  {/* Settings Header with back button */}
@@ -235,6 +237,9 @@ const SettingsPanel = () => {
235
237
  {tab.icon === 'performance' && (<PerformanceIcon color={isLocked
236
238
  ? AppColors.grayTextWeak
237
239
  : AppColors.purple} size={11}/>)}
240
+ {tab.icon === 'crash' && (<CrashIcon color={isLocked
241
+ ? AppColors.grayTextWeak
242
+ : AppColors.purple} size={11}/>)}
238
243
  </View>
239
244
  {/* Label + Required badge */}
240
245
  <Text style={{
@@ -674,6 +679,7 @@ const SettingsPanel = () => {
674
679
  {tab.icon === 'redux' && (<ReduxIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
675
680
  {tab.icon === 'bundle' && (<PackageIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
676
681
  {tab.icon === 'performance' && (<PerformanceIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
682
+ {tab.icon === 'crash' && (<CrashIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
677
683
  </View>
678
684
  <Text style={{
679
685
  fontFamily: AppFonts.interBold,
@@ -1392,6 +1398,89 @@ const SettingsPanel = () => {
1392
1398
  </View>
1393
1399
  </ScrollView>);
1394
1400
  }
1401
+ else if (settingsPage === 'crash') {
1402
+ title = 'Crash Settings';
1403
+ icon = <CrashIcon color={AppColors.white} size={16}/>;
1404
+ rightInfo = `Total: ${crashRecords?.length || 0}`;
1405
+ content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
1406
+ <View style={{
1407
+ backgroundColor: AppColors.primaryLight,
1408
+ padding: 16,
1409
+ borderRadius: 12,
1410
+ borderWidth: 1,
1411
+ borderColor: AppColors.grayBorderSecondary,
1412
+ gap: 4,
1413
+ }}>
1414
+ {renderSettingRow({
1415
+ icon: <LayersIcon color={AppColors.purple} size={16}/>,
1416
+ label: 'Max Crash Logs',
1417
+ description: 'How many crash records to preserve in history',
1418
+ picker: {
1419
+ options: [25, 50, 100, 200],
1420
+ selectedValue: maxCrashLogs || 100,
1421
+ onSelect: val => setMaxCrashLogs(val),
1422
+ },
1423
+ })}
1424
+ <View style={{ height: 1, backgroundColor: AppColors.dividerColor }}/>
1425
+ {renderSettingRow({
1426
+ icon: <ShieldAlertIcon color={AppColors.greenColor} size={16}/>,
1427
+ label: 'Global Crash Guard',
1428
+ description: 'Intercepts native, JS, and render errors directly',
1429
+ isLast: true,
1430
+ right: (<View style={{
1431
+ paddingHorizontal: 8,
1432
+ paddingVertical: 4,
1433
+ borderRadius: 6,
1434
+ backgroundColor: `${AppColors.greenColor}1F`,
1435
+ }}>
1436
+ <Text style={{
1437
+ fontFamily: AppFonts.interBold,
1438
+ fontSize: 10,
1439
+ color: AppColors.greenColor,
1440
+ }}>
1441
+ PROTECTED
1442
+ </Text>
1443
+ </View>),
1444
+ })}
1445
+ </View>
1446
+
1447
+ <View style={{
1448
+ backgroundColor: AppColors.primaryLight,
1449
+ borderRadius: 12,
1450
+ borderWidth: 1,
1451
+ borderColor: AppColors.grayBorderSecondary,
1452
+ padding: 16,
1453
+ marginTop: 12,
1454
+ }}>
1455
+ {renderSettingRow({
1456
+ icon: <TrashIcon color={AppColors.errorColor} size={16}/>,
1457
+ label: 'Clear Crash History',
1458
+ description: `${crashRecords?.length || 0} crash logs stored`,
1459
+ isLast: true,
1460
+ onPress: () => {
1461
+ clearCrashRecords();
1462
+ Alert.alert('Success', 'Crash logs cleared.');
1463
+ },
1464
+ right: (<View style={{
1465
+ paddingHorizontal: 10,
1466
+ paddingVertical: 5,
1467
+ borderRadius: 7,
1468
+ backgroundColor: `${AppColors.errorColor}14`,
1469
+ borderWidth: 1,
1470
+ borderColor: `${AppColors.errorColor}33`,
1471
+ }}>
1472
+ <Text style={{
1473
+ fontFamily: AppFonts.interBold,
1474
+ fontSize: 11,
1475
+ color: AppColors.errorColor,
1476
+ }}>
1477
+ Clear
1478
+ </Text>
1479
+ </View>),
1480
+ })}
1481
+ </View>
1482
+ </ScrollView>);
1483
+ }
1395
1484
  return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
1396
1485
  <LinearGradient colors={[AppColors.purple, AppColors.brandPurple]} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.headerGradient}>
1397
1486
  <View style={{ paddingTop: headerTopPadding, width: '100%' }}>
@@ -4,9 +4,9 @@ import { useInspector } from './InspectorContext';
4
4
  import TouchableScale from '../TouchableScale';
5
5
  import styles from '../../styles';
6
6
  import { AppColors } from '../../styles/AppColors';
7
- import { SignalIcon, TerminalIcon, AnalyticsIcon, PackageIcon, ReduxIcon, PerformanceIcon, } from '../NetworkIcons';
7
+ import { SignalIcon, TerminalIcon, AnalyticsIcon, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, } from '../NetworkIcons';
8
8
  const TabBar = React.memo(() => {
9
- const { activeTab, switchActiveTab, tabVisibility, logs, consoleLogs, analyticsEvents, lastReadApisCount, lastReadLogsCount, unreadPulseAnim, } = useInspector();
9
+ const { activeTab, switchActiveTab, tabVisibility, logs, consoleLogs, analyticsEvents, crashRecords, lastReadApisCount, lastReadLogsCount, lastReadCrashesCount, unreadPulseAnim, } = useInspector();
10
10
  return (<View style={styles.tabBarContainer}>
11
11
  <ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{ paddingRight: 16 }}>
12
12
  {[
@@ -46,18 +46,28 @@ const TabBar = React.memo(() => {
46
46
  count: 0,
47
47
  icon: 'performance',
48
48
  },
49
+ {
50
+ key: 'crash',
51
+ label: 'Crash',
52
+ count: crashRecords?.length || 0,
53
+ icon: 'crash',
54
+ },
49
55
  ]
50
56
  .filter(tab => tabVisibility?.[tab.key])
51
57
  .map(tab => {
52
58
  const isActive = activeTab === tab.key;
53
59
  const iconColor = isActive
54
60
  ? AppColors.white
55
- : AppColors.grayText;
61
+ : tab.key === 'crash' && tab.count > 0
62
+ ? AppColors.errorColor
63
+ : AppColors.grayText;
56
64
  const countLabel = tab.count > 9 ? '9+' : String(tab.count);
57
65
  const hasUnreadApis = activeTab !== 'apis' &&
58
66
  logs.length > lastReadApisCount;
59
67
  const hasUnreadLogs = activeTab !== 'logs' &&
60
68
  consoleLogs.length > lastReadLogsCount;
69
+ const hasUnreadCrashes = activeTab !== 'crash' &&
70
+ (crashRecords?.length || 0) > (lastReadCrashesCount || 0);
61
71
  return (<TouchableScale key={tab.key} onPress={() => switchActiveTab(tab.key)} style={[
62
72
  styles.contentTabButton,
63
73
  isActive && styles.contentTabButtonActive,
@@ -73,6 +83,7 @@ const TabBar = React.memo(() => {
73
83
  {tab.icon === 'redux' && (<ReduxIcon color={iconColor} size={14}/>)}
74
84
  {tab.icon === 'bundle' && (<PackageIcon color={iconColor} size={14}/>)}
75
85
  {tab.icon === 'performance' && (<PerformanceIcon color={iconColor} size={14}/>)}
86
+ {tab.icon === 'crash' && (<CrashIcon color={iconColor} size={14}/>)}
76
87
  <Text numberOfLines={1} ellipsizeMode="tail" style={[
77
88
  styles.contentTabButtonText,
78
89
  isActive &&
@@ -82,7 +93,8 @@ const TabBar = React.memo(() => {
82
93
  {tab.count > 0 ? `(${countLabel})` : ''}
83
94
  </Text>
84
95
  {((tab.key === 'apis' && hasUnreadApis) ||
85
- (tab.key === 'logs' && hasUnreadLogs)) && (<Animated.View style={{
96
+ (tab.key === 'logs' && hasUnreadLogs) ||
97
+ (tab.key === 'crash' && hasUnreadCrashes)) && (<Animated.View style={{
86
98
  width: 6,
87
99
  height: 6,
88
100
  borderRadius: 3,
@@ -92,3 +92,14 @@ export declare const PinIcon: ({ color, size, }: any) => React.JSX.Element;
92
92
  export declare const RepeatIcon: ({ color, size, }: any) => React.JSX.Element;
93
93
  export declare const TargetGoalIcon: ({ color, size, }: any) => React.JSX.Element;
94
94
  export declare const UserCheckIcon: ({ color, size, }: any) => React.JSX.Element;
95
+ export declare const CrashIcon: ({ color, size, }: any) => React.JSX.Element;
96
+ export declare const ShieldAlertIcon: ({ color, size, }: any) => React.JSX.Element;
97
+ export declare const SkullIcon: ({ color, size, }: any) => React.JSX.Element;
98
+ export declare const ChipIcon: ({ color, size, }: any) => React.JSX.Element;
99
+ export declare const LayoutIcon: ({ color, size, }: any) => React.JSX.Element;
100
+ export declare const StackTraceIcon: ({ color, size, }: any) => React.JSX.Element;
101
+ export declare const DiagnosticsIcon: ({ color, size, }: any) => React.JSX.Element;
102
+ export declare const TrailIcon: ({ color, size, }: any) => React.JSX.Element;
103
+ export declare const RawJsonIcon: ({ color, size, }: any) => React.JSX.Element;
104
+ export declare const AppFramesIcon: ({ color, size, }: any) => React.JSX.Element;
105
+ export declare const AllFramesIcon: ({ color, size, }: any) => React.JSX.Element;
@@ -559,3 +559,86 @@ export const UserCheckIcon = ({ color = AppColors.grayTextWeak, size = 14, }) =>
559
559
  <Path d="M16 11l2 2 4-4" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
560
560
  </Svg>);
561
561
  };
562
+ export const CrashIcon = ({ color = AppColors.errorColor, size = 14, }) => {
563
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
564
+ {/* Bug / Crash Hybrid Icon */}
565
+ <Path d="M12 2v3M4.93 4.93l2.12 2.12M19.07 4.93l-2.12 2.12M9 10h6M8 14h8M9 18h6" stroke={color} strokeWidth="1.8" strokeLinecap="round"/>
566
+ <Path d="M12 8a6 6 0 0 1 6 6v3a6 6 0 0 1-12 0v-3a6 6 0 0 1 6-6z" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
567
+ <Path d="M3 13h3M18 13h3M4 19l2.5-1.5M20 19l-2.5-1.5M4 9l2.5 1.5M20 9l-2.5 1.5" stroke={color} strokeWidth="1.8" strokeLinecap="round"/>
568
+ </Svg>);
569
+ };
570
+ export const ShieldAlertIcon = ({ color = AppColors.errorColor, size = 14, }) => {
571
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
572
+ <Path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
573
+ <Line x1="12" y1="8" x2="12" y2="12" stroke={color} strokeWidth="2" strokeLinecap="round"/>
574
+ <Circle cx="12" cy="16" r="1" fill={color}/>
575
+ </Svg>);
576
+ };
577
+ export const SkullIcon = ({ color = AppColors.errorColor, size = 14, }) => {
578
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
579
+ <Circle cx="12" cy="12" r="9" stroke={color} strokeWidth="1.8"/>
580
+ <Circle cx="9" cy="11" r="1.6" fill={color}/>
581
+ <Circle cx="15" cy="11" r="1.6" fill={color}/>
582
+ <Path d="M8 16c1.2 1 3.2 1.2 4 1.2.8 0 2.8-.2 4-1.2" stroke={color} strokeWidth="1.8" strokeLinecap="round"/>
583
+ <Line x1="12" y1="16" x2="12" y2="18" stroke={color} strokeWidth="1.8" strokeLinecap="round"/>
584
+ </Svg>);
585
+ };
586
+ export const ChipIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
587
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
588
+ <Rect x="7" y="7" width="10" height="10" rx="2" stroke={color} strokeWidth="1.8"/>
589
+ <Rect x="10" y="10" width="4" height="4" fill={color}/>
590
+ <Line x1="9" y1="3" x2="9" y2="7" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
591
+ <Line x1="15" y1="3" x2="15" y2="7" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
592
+ <Line x1="9" y1="17" x2="9" y2="21" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
593
+ <Line x1="15" y1="17" x2="15" y2="21" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
594
+ <Line x1="3" y1="9" x2="7" y2="9" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
595
+ <Line x1="3" y1="15" x2="7" y2="15" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
596
+ <Line x1="17" y1="9" x2="21" y2="9" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
597
+ <Line x1="17" y1="15" x2="21" y2="15" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
598
+ </Svg>);
599
+ };
600
+ export const LayoutIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
601
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
602
+ <Rect x="3" y="3" width="18" height="18" rx="2" stroke={color} strokeWidth="1.8"/>
603
+ <Line x1="3" y1="9" x2="21" y2="9" stroke={color} strokeWidth="1.8"/>
604
+ <Line x1="9" y1="9" x2="9" y2="21" stroke={color} strokeWidth="1.8"/>
605
+ <Rect x="12" y="12" width="6" height="6" fill={color}/>
606
+ </Svg>);
607
+ };
608
+ export const StackTraceIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
609
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
610
+ <Path d="M4 6h16M4 10h11M4 14h16M4 18h9" stroke={color} strokeWidth="2" strokeLinecap="round"/>
611
+ <Path d="M7.5 12.5 4 14l3.5 1.5" stroke={color} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/>
612
+ </Svg>);
613
+ };
614
+ export const DiagnosticsIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
615
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
616
+ <Path d="M3 12h3l2-5 3 9 2-6 1.5 2H21" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
617
+ <Line x1="4" y1="19" x2="20" y2="19" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
618
+ </Svg>);
619
+ };
620
+ export const TrailIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
621
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
622
+ <Circle cx="5" cy="18" r="2" fill={color}/>
623
+ <Circle cx="12" cy="12" r="2" fill={color}/>
624
+ <Circle cx="19" cy="6" r="2" fill={color}/>
625
+ <Path d="M6.5 16.5 10.5 13.5M13.5 10.5 17.5 7.5" stroke={color} strokeWidth="1.6" strokeLinecap="round"/>
626
+ </Svg>);
627
+ };
628
+ export const RawJsonIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
629
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
630
+ <Path d="M8 3c-2 1-3 2.5-3 5 0 2-1 3.5-2 4 1 .5 2 2 2 4 0 2.5 1 4 3 5M16 3c2 1 3 2.5 3 5 0 2 1 3.5 2 4-1 .5-2 2-2 4 0 2.5-1 4-3 5" stroke={color} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
631
+ </Svg>);
632
+ };
633
+ export const AppFramesIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
634
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
635
+ <Path d="M4 6h16M4 10h11M4 14h16M4 18h9" stroke={color} strokeWidth="2" strokeLinecap="round"/>
636
+ <Path d="M18 12.5l2 2 3-3.5" stroke="#059669" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
637
+ </Svg>);
638
+ };
639
+ export const AllFramesIcon = ({ color = AppColors.grayTextWeak, size = 14, }) => {
640
+ return (<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
641
+ <Path d="M4 4h16M4 8h16M4 12h16M4 16h16M4 20h10" stroke={color} strokeWidth="1.8" strokeLinecap="round"/>
642
+ <Rect x="16" y="16" width="4" height="4" rx="1" fill={color}/>
643
+ </Svg>);
644
+ };
@@ -40,7 +40,8 @@ const SegmentedTabs = React.memo(({ tabs, activeKey, onChange, style }) => (<Vie
40
40
  },
41
41
  ]}>
42
42
  {tab.icon ? tab.icon(isActive) : null}
43
- <Text style={{
43
+ <Text numberOfLines={1} ellipsizeMode="tail" style={{
44
+ flexShrink: 1,
44
45
  fontFamily: AppFonts.interBold,
45
46
  fontSize: 10.5,
46
47
  color: isActive
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "1.1.25";
1
+ export declare const LIB_VERSION = "1.1.26";
@@ -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.25';
3
+ export const LIB_VERSION = '1.1.26';