react-native-inapp-inspector 2.3.8 → 2.3.9

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 (53) hide show
  1. package/dist/commonjs/components/Inspector/AnalyticsTab.js +27 -2
  2. package/dist/commonjs/components/Inspector/BundleTab.js +3 -0
  3. package/dist/commonjs/components/Inspector/ConsoleTab.js +24 -1
  4. package/dist/commonjs/components/Inspector/CrashTab.js +30 -1
  5. package/dist/commonjs/components/Inspector/FeatureUnderDevNotice.d.ts +7 -0
  6. package/dist/commonjs/components/Inspector/FeatureUnderDevNotice.js +111 -0
  7. package/dist/commonjs/components/Inspector/InspectorHeader.js +225 -108
  8. package/dist/commonjs/components/Inspector/NpmUpdateToast.js +1 -1
  9. package/dist/commonjs/components/Inspector/PerformanceTab.js +3 -0
  10. package/dist/commonjs/components/Inspector/ReduxTab.js +24 -1
  11. package/dist/commonjs/components/Inspector/SettingsPanel.js +73 -88
  12. package/dist/commonjs/components/Inspector/StorageTab.js +37 -11
  13. package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +2 -0
  14. package/dist/commonjs/components/LogCard.js +33 -3
  15. package/dist/commonjs/constants/version.d.ts +1 -1
  16. package/dist/commonjs/constants/version.js +1 -1
  17. package/dist/commonjs/helpers/telemetry.js +34 -0
  18. package/dist/commonjs/index.js +3 -0
  19. package/dist/esm/components/Inspector/AnalyticsTab.js +29 -4
  20. package/dist/esm/components/Inspector/BundleTab.js +3 -0
  21. package/dist/esm/components/Inspector/ConsoleTab.js +26 -3
  22. package/dist/esm/components/Inspector/CrashTab.js +32 -3
  23. package/dist/esm/components/Inspector/FeatureUnderDevNotice.d.ts +7 -0
  24. package/dist/esm/components/Inspector/FeatureUnderDevNotice.js +74 -0
  25. package/dist/esm/components/Inspector/InspectorHeader.js +226 -109
  26. package/dist/esm/components/Inspector/NpmUpdateToast.js +1 -1
  27. package/dist/esm/components/Inspector/PerformanceTab.js +3 -0
  28. package/dist/esm/components/Inspector/ReduxTab.js +26 -3
  29. package/dist/esm/components/Inspector/SettingsPanel.js +73 -88
  30. package/dist/esm/components/Inspector/StorageTab.js +39 -13
  31. package/dist/esm/components/Inspector/UpdateAvailableModal.js +2 -0
  32. package/dist/esm/components/LogCard.js +34 -4
  33. package/dist/esm/constants/version.d.ts +1 -1
  34. package/dist/esm/constants/version.js +1 -1
  35. package/dist/esm/helpers/telemetry.js +34 -0
  36. package/dist/esm/index.js +3 -0
  37. package/package.json +1 -1
  38. package/src/components/Inspector/AnalyticsTab.tsx +71 -43
  39. package/src/components/Inspector/BundleTab.tsx +3 -0
  40. package/src/components/Inspector/ConsoleTab.tsx +28 -1
  41. package/src/components/Inspector/CrashTab.tsx +45 -14
  42. package/src/components/Inspector/FeatureUnderDevNotice.tsx +94 -0
  43. package/src/components/Inspector/InspectorHeader.tsx +257 -115
  44. package/src/components/Inspector/NpmUpdateToast.tsx +1 -1
  45. package/src/components/Inspector/PerformanceTab.tsx +3 -0
  46. package/src/components/Inspector/ReduxTab.tsx +28 -1
  47. package/src/components/Inspector/SettingsPanel.tsx +93 -132
  48. package/src/components/Inspector/StorageTab.tsx +56 -27
  49. package/src/components/Inspector/UpdateAvailableModal.tsx +2 -0
  50. package/src/components/LogCard.tsx +41 -4
  51. package/src/constants/version.ts +1 -1
  52. package/src/helpers/telemetry.ts +36 -0
  53. package/src/index.tsx +5 -0
@@ -128,7 +128,7 @@ const NpmUpdateToast = () => {
128
128
  react_native_1.Linking.openURL('https://www.npmjs.com/package/react-native-inapp-inspector').catch(() => { });
129
129
  handleDismiss();
130
130
  };
131
- if (!showUpdateToast || !visible || !updateAvailable || !latestNpmVersion)
131
+ if (typeof __DEV__ === 'undefined' || !__DEV__ || !showUpdateToast || !visible || !updateAvailable || !latestNpmVersion)
132
132
  return null;
133
133
  const progressWidth = progressAnim.interpolate({
134
134
  inputRange: [0, 1],
@@ -43,6 +43,7 @@ const TouchableScale_1 = __importDefault(require("../TouchableScale"));
43
43
  const CopyButton_1 = __importDefault(require("../CopyButton"));
44
44
  const HighlightText_1 = __importDefault(require("../HighlightText"));
45
45
  const EndOfListFooter_1 = __importDefault(require("../EndOfListFooter"));
46
+ const FeatureUnderDevNotice_1 = __importDefault(require("./FeatureUnderDevNotice"));
46
47
  const AppColors_1 = require("../../styles/AppColors");
47
48
  const AppFonts_1 = require("../../styles/AppFonts");
48
49
  const i18n_1 = require("../../i18n");
@@ -394,6 +395,8 @@ const PerformanceTab = react_1.default.memo(() => {
394
395
  </TouchableScale_1.default>
395
396
  </react_native_1.View>
396
397
 
398
+ <FeatureUnderDevNotice_1.default featureName="Performance & FPS Profiler"/>
399
+
397
400
 
398
401
  <react_native_1.View style={perfStyles.categoryScrollWrapper}>
399
402
  <react_native_1.ScrollView horizontal showsHorizontalScrollIndicator={false} style={perfStyles.categoryScrollView} contentContainerStyle={perfStyles.categoryScroll}>
@@ -98,6 +98,7 @@ const getOriginBadge = (originType) => {
98
98
  const ReduxTab = react_1.default.memo(() => {
99
99
  const { t } = (0, i18n_1.useTranslation)();
100
100
  const { reduxState, reduxLastActionMap, reduxSearch, setReduxSearch, setSelectedReduxSlice, } = (0, InspectorContext_1.useInspector)();
101
+ const listRef = (0, react_1.useRef)(null);
101
102
  const [sortMode, setSortMode] = (0, react_1.useState)('latest');
102
103
  const [isReduxPaused, setIsReduxPaused] = (0, react_1.useState)(!(0, reduxLogger_1.getReduxAutoRefresh)());
103
104
  const handleTogglePause = (0, react_1.useCallback)(() => {
@@ -491,10 +492,32 @@ const ReduxTab = react_1.default.memo(() => {
491
492
  </react_native_1.View>
492
493
 
493
494
 
494
- <react_native_1.FlatList data={filteredSlices} keyExtractor={item => item.id} renderItem={renderSliceItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState_1.default isSearch={reduxSearch.length > 0}/>} ListFooterComponent={filteredSlices.length > 0 ? (<EndOfListFooter_1.default count={filteredSlices.length} label="slices"/>) : null} contentContainerStyle={[
495
+ <react_native_1.FlatList ref={listRef} data={filteredSlices} keyExtractor={item => item.id} renderItem={renderSliceItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState_1.default isSearch={reduxSearch.length > 0}/>} ListFooterComponent={filteredSlices.length > 0 ? (<EndOfListFooter_1.default count={filteredSlices.length} label="slices"/>) : null} contentContainerStyle={[
495
496
  reduxTabStyles.listContent,
496
497
  filteredSlices.length === 0 && { flexGrow: 1 },
497
498
  ]} keyboardShouldPersistTaps="handled"/>
499
+
500
+ <TouchableScale_1.default onPress={() => {
501
+ try {
502
+ listRef.current?.scrollToOffset({
503
+ offset: 0,
504
+ animated: true,
505
+ });
506
+ }
507
+ catch {
508
+ try {
509
+ listRef.current?.scrollToIndex({
510
+ index: 0,
511
+ animated: true,
512
+ });
513
+ }
514
+ catch { }
515
+ }
516
+ }} hitSlop={12} style={styles_1.default.scrollTopBtn}>
517
+ <react_native_1.View style={{ transform: [{ rotate: '180deg' }] }}>
518
+ <NetworkIcons_1.ChevronIcon color={AppColors_1.AppColors.white} size={18}/>
519
+ </react_native_1.View>
520
+ </TouchableScale_1.default>
498
521
  </react_native_1.View>);
499
522
  });
500
523
  const reduxTabStyles = react_native_1.StyleSheet.create({
@@ -313,11 +313,12 @@ const SettingsPanel = () => {
313
313
  }}>
314
314
  <react_native_1.ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, paddingBottom: 100, gap: 14 }} showsVerticalScrollIndicator={false}>
315
315
 
316
+
316
317
  <react_native_1.View style={{
317
- flexDirection: 'row',
318
318
  backgroundColor: AppColors_1.AppColors.primaryLight,
319
- borderRadius: 12,
320
- padding: 4,
319
+ borderRadius: 13,
320
+ paddingVertical: 4,
321
+ paddingHorizontal: 4,
321
322
  borderWidth: 1,
322
323
  borderColor: AppColors_1.AppColors.grayBorderSecondary,
323
324
  shadowColor: AppColors_1.AppColors.black,
@@ -325,95 +326,79 @@ const SettingsPanel = () => {
325
326
  shadowRadius: 4,
326
327
  shadowOffset: { width: 0, height: 2 },
327
328
  }}>
328
- <TouchableScale_1.default accessible={true} accessibilityRole="tab" accessibilityLabel={t('settings.modulesAndTools')} accessibilityState={{ selected: settingsActiveSubTab === 'module' }} onPress={() => {
329
- (0, InspectorContext_1.animateNextLayout)();
330
- setSettingsActiveSubTab('module');
331
- }} style={{
332
- flex: 1,
333
- paddingVertical: 9,
329
+ <react_native_1.ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{
334
330
  flexDirection: 'row',
335
331
  alignItems: 'center',
336
- justifyContent: 'center',
337
332
  gap: 6,
338
- borderRadius: 9,
339
- backgroundColor: settingsActiveSubTab === 'module'
340
- ? AppColors_1.AppColors.purple
341
- : 'transparent',
342
- }}>
343
- <NetworkIcons_1.LayersIcon color={settingsActiveSubTab === 'module'
344
- ? AppColors_1.AppColors.white
345
- : AppColors_1.AppColors.grayText} size={13}/>
346
- <react_native_1.Text style={{
347
- fontFamily: AppFonts_1.AppFonts.interBold,
348
- fontSize: 12.5,
349
- lineHeight: 16,
350
- color: settingsActiveSubTab === 'module'
351
- ? AppColors_1.AppColors.white
352
- : AppColors_1.AppColors.grayText,
353
- }}>
354
- {t('settings.modulesAndTools')}
355
- </react_native_1.Text>
356
- </TouchableScale_1.default>
357
-
358
- <TouchableScale_1.default accessible={true} accessibilityRole="tab" accessibilityLabel={t('settings.uiPreferences')} accessibilityState={{ selected: settingsActiveSubTab === 'ui' }} onPress={() => {
359
- (0, InspectorContext_1.animateNextLayout)();
360
- setSettingsActiveSubTab('ui');
361
- }} style={{
362
- flex: 1,
363
- paddingVertical: 9,
364
- flexDirection: 'row',
365
- alignItems: 'center',
366
- justifyContent: 'center',
367
- gap: 5,
368
- borderRadius: 9,
369
- backgroundColor: settingsActiveSubTab === 'ui'
370
- ? AppColors_1.AppColors.purple
371
- : 'transparent',
372
- }}>
373
- <NetworkIcons_1.ScreenIcon color={settingsActiveSubTab === 'ui'
374
- ? AppColors_1.AppColors.white
375
- : AppColors_1.AppColors.grayText} size={13}/>
376
- <react_native_1.Text numberOfLines={1} style={{
377
- fontFamily: AppFonts_1.AppFonts.interBold,
378
- fontSize: 12,
379
- lineHeight: 16,
380
- color: settingsActiveSubTab === 'ui'
381
- ? AppColors_1.AppColors.white
382
- : AppColors_1.AppColors.grayText,
383
- }}>
384
- {t('settings.uiPreferences')}
385
- </react_native_1.Text>
386
- </TouchableScale_1.default>
387
-
388
- <TouchableScale_1.default accessible={true} accessibilityRole="tab" accessibilityLabel={t('settings.ramLimits')} accessibilityState={{ selected: settingsActiveSubTab === 'limits' }} onPress={() => {
389
- (0, InspectorContext_1.animateNextLayout)();
390
- setSettingsActiveSubTab('limits');
391
- }} style={{
392
- flex: 1,
393
- paddingVertical: 9,
394
- flexDirection: 'row',
395
- alignItems: 'center',
396
- justifyContent: 'center',
397
- gap: 5,
398
- borderRadius: 9,
399
- backgroundColor: settingsActiveSubTab === 'limits'
400
- ? AppColors_1.AppColors.purple
401
- : 'transparent',
402
- }}>
403
- <NetworkIcons_1.BrainIcon color={settingsActiveSubTab === 'limits'
404
- ? AppColors_1.AppColors.white
405
- : AppColors_1.AppColors.grayText} size={13}/>
406
- <react_native_1.Text numberOfLines={1} style={{
407
- fontFamily: AppFonts_1.AppFonts.interBold,
408
- fontSize: 12,
409
- lineHeight: 16,
410
- color: settingsActiveSubTab === 'limits'
411
- ? AppColors_1.AppColors.white
412
- : AppColors_1.AppColors.grayText,
333
+ paddingHorizontal: 2,
413
334
  }}>
414
- {t('settings.ramLimits')}
415
- </react_native_1.Text>
416
- </TouchableScale_1.default>
335
+ {[
336
+ {
337
+ key: 'module',
338
+ label: t('settings.modulesAndTools', 'Modules & Tools'),
339
+ Icon: NetworkIcons_1.LayersIcon,
340
+ badge: `${allModules.filter(m => stagedTabVisibility?.[m.key] || m.key === 'apis').length}/${allModules.length}`,
341
+ },
342
+ {
343
+ key: 'ui',
344
+ label: t('settings.uiPreferences', 'UI Preferences'),
345
+ Icon: NetworkIcons_1.ScreenIcon,
346
+ },
347
+ {
348
+ key: 'limits',
349
+ label: t('settings.ramLimits', 'RAM & Limits'),
350
+ Icon: NetworkIcons_1.BrainIcon,
351
+ },
352
+ ].map(tab => {
353
+ const isActive = settingsActiveSubTab === tab.key;
354
+ const IconComp = tab.Icon;
355
+ return (<TouchableScale_1.default key={tab.key} accessible={true} accessibilityRole="tab" accessibilityLabel={tab.label} accessibilityState={{ selected: isActive }} onPress={() => {
356
+ (0, InspectorContext_1.animateNextLayout)();
357
+ setSettingsActiveSubTab(tab.key);
358
+ }} style={{
359
+ paddingVertical: 8,
360
+ paddingHorizontal: 14,
361
+ flexDirection: 'row',
362
+ alignItems: 'center',
363
+ justifyContent: 'center',
364
+ gap: 6,
365
+ borderRadius: 9,
366
+ backgroundColor: isActive
367
+ ? AppColors_1.AppColors.purple
368
+ : 'transparent',
369
+ }}>
370
+ <IconComp color={isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.grayText} size={13}/>
371
+ <react_native_1.Text style={{
372
+ fontFamily: AppFonts_1.AppFonts.interBold,
373
+ fontSize: 12.5,
374
+ lineHeight: 16,
375
+ color: isActive
376
+ ? AppColors_1.AppColors.white
377
+ : AppColors_1.AppColors.grayText,
378
+ }}>
379
+ {tab.label}
380
+ </react_native_1.Text>
381
+ {tab.badge && (<react_native_1.View style={{
382
+ backgroundColor: isActive
383
+ ? 'rgba(255,255,255,0.25)'
384
+ : `${AppColors_1.AppColors.purple}18`,
385
+ paddingHorizontal: 5.5,
386
+ paddingVertical: 1,
387
+ borderRadius: 10,
388
+ }}>
389
+ <react_native_1.Text style={{
390
+ fontFamily: AppFonts_1.AppFonts.interBold,
391
+ fontSize: 9.5,
392
+ color: isActive
393
+ ? AppColors_1.AppColors.white
394
+ : AppColors_1.AppColors.purple,
395
+ }}>
396
+ {tab.badge}
397
+ </react_native_1.Text>
398
+ </react_native_1.View>)}
399
+ </TouchableScale_1.default>);
400
+ })}
401
+ </react_native_1.ScrollView>
417
402
  </react_native_1.View>
418
403
 
419
404
  {settingsActiveSubTab === 'module' && (<react_native_1.View style={{ gap: 12 }}>
@@ -40,6 +40,7 @@ exports.StorageTab = void 0;
40
40
  const react_1 = __importStar(require("react"));
41
41
  const react_native_1 = require("react-native");
42
42
  const TouchableScale_1 = __importDefault(require("../TouchableScale"));
43
+ const styles_1 = __importDefault(require("../../styles"));
43
44
  const AppColors_1 = require("../../styles/AppColors");
44
45
  const AppFonts_1 = require("../../styles/AppFonts");
45
46
  const i18n_1 = require("../../i18n");
@@ -134,6 +135,7 @@ const StorageEntryCard = react_1.default.memo(function StorageEntryCard({ entry,
134
135
  });
135
136
  exports.StorageTab = react_1.default.memo(() => {
136
137
  const { t } = (0, i18n_1.useTranslation)();
138
+ const listRef = (0, react_1.useRef)(null);
137
139
  const [activeDriver, setActiveDriver] = (0, react_1.useState)('asyncStorage');
138
140
  const [activeMMKVId, setActiveMMKVId] = (0, react_1.useState)('default');
139
141
  const [entries, setEntries] = (0, react_1.useState)([]);
@@ -399,19 +401,43 @@ exports.StorageTab = react_1.default.memo(() => {
399
401
  {isLoading ? (<react_native_1.View style={styles.loadingContainer}>
400
402
  <react_native_1.ActivityIndicator size="small" color={AppColors_1.AppColors.purple}/>
401
403
  <react_native_1.Text style={styles.loadingText}>Loading storage entries...</react_native_1.Text>
402
- </react_native_1.View>) : (<react_native_1.FlatList data={filteredEntries} keyExtractor={item => item.key} renderItem={renderItem} initialNumToRender={10} maxToRenderPerBatch={10} windowSize={5} removeClippedSubviews={react_native_1.Platform.OS === 'android'} style={styles.scrollArea} contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false} ListEmptyComponent={<react_native_1.View style={styles.emptyContainer}>
403
- <react_native_1.View style={styles.emptyIconWrap}>
404
- <NetworkIcons_1.DatabaseIcon size={28} color={AppColors_1.AppColors.grayTextWeak}/>
405
- </react_native_1.View>
406
- <react_native_1.Text style={styles.emptyTitle}>
407
- {search ? 'No matching keys found' : `No ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} Keys`}
408
- </react_native_1.Text>
409
- <react_native_1.Text style={styles.emptySubtitle}>
410
- {search
404
+ </react_native_1.View>) : (<>
405
+ <react_native_1.FlatList ref={listRef} data={filteredEntries} keyExtractor={item => item.key} renderItem={renderItem} initialNumToRender={10} maxToRenderPerBatch={10} windowSize={5} removeClippedSubviews={react_native_1.Platform.OS === 'android'} style={styles.scrollArea} contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false} ListEmptyComponent={<react_native_1.View style={styles.emptyContainer}>
406
+ <react_native_1.View style={styles.emptyIconWrap}>
407
+ <NetworkIcons_1.DatabaseIcon size={28} color={AppColors_1.AppColors.grayTextWeak}/>
408
+ </react_native_1.View>
409
+ <react_native_1.Text style={styles.emptyTitle}>
410
+ {search ? 'No matching keys found' : `No ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} Keys`}
411
+ </react_native_1.Text>
412
+ <react_native_1.Text style={styles.emptySubtitle}>
413
+ {search
411
414
  ? 'Try modifying your search query'
412
415
  : `Storage is auto-detected. Tap "+ Add" above to create your first ${activeDriver === 'asyncStorage' ? 'AsyncStorage' : 'MMKV'} key!`}
413
- </react_native_1.Text>
414
- </react_native_1.View>} ListFooterComponent={<react_native_1.View style={{ height: 60 }}/>}/>)}
416
+ </react_native_1.Text>
417
+ </react_native_1.View>} ListFooterComponent={<react_native_1.View style={{ height: 60 }}/>}/>
418
+
419
+ <TouchableScale_1.default onPress={() => {
420
+ try {
421
+ listRef.current?.scrollToOffset({
422
+ offset: 0,
423
+ animated: true,
424
+ });
425
+ }
426
+ catch {
427
+ try {
428
+ listRef.current?.scrollToIndex({
429
+ index: 0,
430
+ animated: true,
431
+ });
432
+ }
433
+ catch { }
434
+ }
435
+ }} hitSlop={12} style={styles_1.default.scrollTopBtn}>
436
+ <react_native_1.View style={{ transform: [{ rotate: '180deg' }] }}>
437
+ <NetworkIcons_1.ChevronIcon color={AppColors_1.AppColors.white} size={18}/>
438
+ </react_native_1.View>
439
+ </TouchableScale_1.default>
440
+ </>)}
415
441
 
416
442
 
417
443
  <react_native_1.Modal visible={modalVisible} transparent animationType="fade" onRequestClose={() => setModalVisible(false)}>
@@ -68,6 +68,8 @@ const UpdateAvailableModal = ({ visible, latestVersion, onClose, }) => {
68
68
  const fadeAnim = (0, react_1.useState)(new react_native_1.Animated.Value(0))[0];
69
69
  const scaleAnim = (0, react_1.useState)(new react_native_1.Animated.Value(0.92))[0];
70
70
  const installCommand = `npm install react-native-inapp-inspector@latest`;
71
+ if (typeof __DEV__ === 'undefined' || !__DEV__)
72
+ return null;
71
73
  (0, react_1.useEffect)(() => {
72
74
  if (visible) {
73
75
  setCopied(false);
@@ -348,9 +348,39 @@ const LogCard = react_1.default.memo(function LogCard({ item, onPress, timelineM
348
348
 
349
349
 
350
350
  <react_native_1.View style={styles_1.default.cardFooterRow}>
351
- <react_native_1.View style={styles_1.default.cardDateRow}>
352
- <NetworkIcons_1.CalendarIcon color={AppColors_1.AppColors.grayTextWeak} size={10}/>
353
- <react_native_1.Text style={styles_1.default.cardDateText}>{triggeredAt}</react_native_1.Text>
351
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flexShrink: 1, minWidth: 0 }}>
352
+ <react_native_1.View style={styles_1.default.cardDateRow}>
353
+ <NetworkIcons_1.CalendarIcon color={AppColors_1.AppColors.grayTextWeak} size={10}/>
354
+ <react_native_1.Text style={styles_1.default.cardDateText}>{triggeredAt}</react_native_1.Text>
355
+ </react_native_1.View>
356
+
357
+ {item.caller && item.caller !== 'Unknown' && (<react_native_1.View style={[
358
+ styles_1.default.chip,
359
+ {
360
+ flexDirection: 'row',
361
+ alignItems: 'center',
362
+ gap: 3,
363
+ backgroundColor: `${AppColors_1.AppColors.skyBlue}14`,
364
+ borderColor: `${AppColors_1.AppColors.skyBlue}30`,
365
+ paddingHorizontal: 5,
366
+ paddingVertical: 1,
367
+ borderRadius: 4,
368
+ flexShrink: 1,
369
+ maxWidth: 160,
370
+ },
371
+ ]}>
372
+ <NetworkIcons_1.PinIcon color={AppColors_1.AppColors.skyBlue} size={8.5}/>
373
+ <react_native_1.Text style={[
374
+ styles_1.default.chipText,
375
+ {
376
+ color: AppColors_1.AppColors.skyBlue,
377
+ fontSize: 8.5,
378
+ fontFamily: AppFonts_1.AppFonts.interMedium,
379
+ },
380
+ ]} numberOfLines={1} ellipsizeMode="middle">
381
+ {item.caller}
382
+ </react_native_1.Text>
383
+ </react_native_1.View>)}
354
384
  </react_native_1.View>
355
385
 
356
386
  <react_native_1.View style={styles_1.default.cardFooterRight}>
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "2.3.8";
1
+ export declare const LIB_VERSION = "2.3.9";
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LIB_VERSION = void 0;
4
- exports.LIB_VERSION = '2.3.8';
4
+ exports.LIB_VERSION = '2.3.9';
@@ -83,6 +83,36 @@ async function getOrCreateClientId() {
83
83
  return `${Math.floor(100000000 + Math.random() * 900000000)}.${Math.floor(1000000000 + Math.random() * 9000000000)}`;
84
84
  }
85
85
  }
86
+ function isDeviceEmulator() {
87
+ try {
88
+ if (react_native_1.Platform.OS === 'android') {
89
+ const c = react_native_1.Platform.constants || {};
90
+ const model = String(c.Model || '').toLowerCase();
91
+ const brand = String(c.Brand || '').toLowerCase();
92
+ const fingerprint = String(c.Fingerprint || '').toLowerCase();
93
+ const hardware = String(c.Hardware || '').toLowerCase();
94
+ const manufacturer = String(c.Manufacturer || '').toLowerCase();
95
+ return (model.includes('emulator') ||
96
+ model.includes('sdk') ||
97
+ model.includes('google_sdk') ||
98
+ model.includes('vbox') ||
99
+ brand.includes('generic') ||
100
+ fingerprint.startsWith('generic') ||
101
+ hardware.includes('goldfish') ||
102
+ hardware.includes('ranchu') ||
103
+ manufacturer.includes('genymotion'));
104
+ }
105
+ if (react_native_1.Platform.OS === 'ios') {
106
+ const c = react_native_1.Platform.constants || {};
107
+ const model = String(c.Model || '').toLowerCase();
108
+ return model.includes('simulator') || Boolean(c.isSimulator);
109
+ }
110
+ }
111
+ catch {
112
+ return false;
113
+ }
114
+ return false;
115
+ }
86
116
  function getSystemMetadata(environment) {
87
117
  const rnConstants = react_native_1.Platform.constants;
88
118
  const rnVersion = rnConstants?.reactNativeVersion
@@ -91,6 +121,7 @@ function getSystemMetadata(environment) {
91
121
  const isHermes = Boolean(typeof global.HermesInternal === 'object' && global.HermesInternal !== null);
92
122
  const isFabric = Boolean(global?.nativeFabricUIManager !== undefined);
93
123
  const isDev = Boolean(typeof __DEV__ !== 'undefined' && __DEV__);
124
+ const isEmulator = isDeviceEmulator();
94
125
  return {
95
126
  lib_version: version_1.LIB_VERSION,
96
127
  platform: react_native_1.Platform.OS,
@@ -99,6 +130,9 @@ function getSystemMetadata(environment) {
99
130
  is_hermes: isHermes,
100
131
  is_fabric: isFabric,
101
132
  is_dev: isDev,
133
+ is_emulator: isEmulator,
134
+ device_type: isEmulator ? 'emulator' : 'real_device',
135
+ app_mode: isDev ? 'local_mode' : 'bundled_application',
102
136
  environment: environment || (isDev ? 'DEV' : 'PROD'),
103
137
  engagement_time_msec: 1000,
104
138
  };
@@ -403,6 +403,9 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
403
403
  return false;
404
404
  }, [latestNpmVersion]);
405
405
  (0, react_1.useEffect)(() => {
406
+ if (typeof __DEV__ === 'undefined' || !__DEV__) {
407
+ return;
408
+ }
406
409
  let cancelled = false;
407
410
  fetch('https://registry.npmjs.org/react-native-inapp-inspector/latest')
408
411
  .then(res => (res.ok ? res.json() : null))
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useState, useMemo, useEffect } from 'react';
1
+ import React, { useCallback, useState, useMemo, useEffect, useRef } from 'react';
2
2
  import { FlatList, Pressable, Text, TextInput, TouchableOpacity, View, } from 'react-native';
3
3
  import { animateNextLayout, useInspector } from './InspectorContext';
4
4
  import AnalyticsEventCard from '../AnalyticsEventCard';
@@ -13,7 +13,7 @@ import Svg, { Path, Rect, Line, Circle, G, Defs, LinearGradient as SvgLinearGrad
13
13
  import TouchableScale from '../TouchableScale';
14
14
  import { getCurrentUserId, getCurrentUserProperties, getDefaultEventParameters, getCollectionEnabled, } from '../../customHooks/analyticsLogger';
15
15
  import { getEventCategory, } from '../../helpers';
16
- import { LayersIcon, SearchIcon, ClearIcon, TrashIcon, HeaderPauseIcon, FilterIcon, CartIcon, GlobeIcon, BoltIcon, SparkleIcon, PinIcon, MoneyIcon, } from '../NetworkIcons';
16
+ import { LayersIcon, SearchIcon, ClearIcon, TrashIcon, HeaderPauseIcon, FilterIcon, CartIcon, GlobeIcon, BoltIcon, SparkleIcon, PinIcon, MoneyIcon, ChevronIcon, } from '../NetworkIcons';
17
17
  const AnalyticsHeader = React.memo(() => {
18
18
  const { t } = useTranslation();
19
19
  const { analyticsEvents, filteredAnalyticsEvents, analyticsFilters, setAnalyticsFilters, analyticsHeaderExpanded, setAnalyticsHeaderExpanded, } = useInspector();
@@ -795,6 +795,7 @@ const AnalyticsHeader = React.memo(() => {
795
795
  const AnalyticsTab = React.memo(() => {
796
796
  const { t } = useTranslation();
797
797
  const { filteredAnalyticsEvents, analyticsSearch, setAnalyticsSearch, handleDelete, selectedEvent, setSelectedEvent, newEventIds, logRouteMapRef, isAnalyticsLayoutReady, setIsAnalyticsLayoutReady, isAnalyticsPaused, setIsAnalyticsPaused, isAnalyticsFilterApplied, } = useInspector();
798
+ const listRef = useRef(null);
798
799
  const [isFilterModalOpen, setIsFilterModalOpen] = useState(false);
799
800
  const keyExtractor = useCallback((item, index) => item?.id?.toString() ?? index.toString(), []);
800
801
  const renderItem = useCallback(({ item, index }) => {
@@ -922,7 +923,8 @@ const AnalyticsTab = React.memo(() => {
922
923
  <AnalyticsFilterModal visible={isFilterModalOpen} onClose={() => setIsFilterModalOpen(false)}/>
923
924
 
924
925
  <View style={{ flex: 1 }} onLayout={() => setIsAnalyticsLayoutReady(true)}>
925
- {isAnalyticsLayoutReady ? (<FlatList data={filteredAnalyticsEvents} keyExtractor={keyExtractor} ListHeaderComponent={AnalyticsHeader} renderItem={renderItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState isSearch={analyticsSearch.length > 0} searchQuery={analyticsSearch} customTitle={analyticsSearch.length > 0
926
+ {isAnalyticsLayoutReady ? (<>
927
+ <FlatList ref={listRef} data={filteredAnalyticsEvents} keyExtractor={keyExtractor} ListHeaderComponent={AnalyticsHeader} renderItem={renderItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState isSearch={analyticsSearch.length > 0} searchQuery={analyticsSearch} customTitle={analyticsSearch.length > 0
926
928
  ? 'No matching analytics events'
927
929
  : 'No analytics events yet'} customSub={analyticsSearch.length > 0
928
930
  ? `No events matched "${analyticsSearch}"`
@@ -931,7 +933,30 @@ const AnalyticsTab = React.memo(() => {
931
933
  filteredAnalyticsEvents.length === 0 && {
932
934
  flexGrow: 1,
933
935
  },
934
- ]} keyboardShouldPersistTaps="handled"/>) : null}
936
+ ]} keyboardShouldPersistTaps="handled"/>
937
+
938
+ <TouchableScale onPress={() => {
939
+ try {
940
+ listRef.current?.scrollToOffset({
941
+ offset: 0,
942
+ animated: true,
943
+ });
944
+ }
945
+ catch {
946
+ try {
947
+ listRef.current?.scrollToIndex({
948
+ index: 0,
949
+ animated: true,
950
+ });
951
+ }
952
+ catch { }
953
+ }
954
+ }} hitSlop={12} style={styles.scrollTopBtn}>
955
+ <View style={{ transform: [{ rotate: '180deg' }] }}>
956
+ <ChevronIcon color={AppColors.white} size={18}/>
957
+ </View>
958
+ </TouchableScale>
959
+ </>) : null}
935
960
  </View>
936
961
  </>);
937
962
  });
@@ -4,6 +4,7 @@ import { useTranslation, t } from '../../i18n';
4
4
  import TouchableScale from '../TouchableScale';
5
5
  import CopyButton from '../CopyButton';
6
6
  import HighlightText from '../HighlightText';
7
+ import FeatureUnderDevNotice from './FeatureUnderDevNotice';
7
8
  import { AppColors } from '../../styles/AppColors';
8
9
  import { AppFonts } from '../../styles/AppFonts';
9
10
  import { copyToClipboard } from '../../helpers';
@@ -788,6 +789,8 @@ const BundleTab = React.memo(() => {
788
789
  </TouchableScale>
789
790
  </View>
790
791
 
792
+ <FeatureUnderDevNotice featureName="Metro Bundle Analyzer"/>
793
+
791
794
 
792
795
 
793
796
 
@@ -1,4 +1,4 @@
1
- import React, { useCallback, useMemo } from 'react';
1
+ import React, { useCallback, useMemo, useRef } from 'react';
2
2
  import { FlatList, Pressable, ScrollView, Text, TextInput, View, } from 'react-native';
3
3
  import { useInspector } from './InspectorContext';
4
4
  import { useTranslation } from '../../i18n';
@@ -10,10 +10,11 @@ import EndOfListFooter from '../EndOfListFooter';
10
10
  import styles from '../../styles';
11
11
  import { AppColors } from '../../styles/AppColors';
12
12
  import { AppFonts } from '../../styles/AppFonts';
13
- import { SearchIcon, ClearIcon, SortArrowIcon, TrashIcon, LayersIcon, UserIcon, InfoCircleIcon, WarningTriangleIcon, ErrorCircleIcon, AnalyticsIcon, HeaderPauseIcon, } from '../NetworkIcons';
13
+ import { SearchIcon, ClearIcon, SortArrowIcon, TrashIcon, LayersIcon, UserIcon, InfoCircleIcon, WarningTriangleIcon, ErrorCircleIcon, AnalyticsIcon, HeaderPauseIcon, ChevronIcon, } from '../NetworkIcons';
14
14
  const ConsoleTab = React.memo(() => {
15
15
  const { t } = useTranslation();
16
16
  const { logSearch, setLogSearch, logSortOrder, setLogSortOrder, handleDelete, logFilters, setLogFilters, logCounts, filteredConsoleLogs, visibleConsoleLogs, isConsolePaused, setIsConsolePaused, } = useInspector();
17
+ const listRef = useRef(null);
17
18
  const renderItem = useCallback(({ item, index }) => (<AnimatedEntrance index={index} distance={8}>
18
19
  <ConsoleLogCard item={item} searchStr={logSearch}/>
19
20
  </AnimatedEntrance>), [logSearch]);
@@ -480,7 +481,7 @@ const ConsoleTab = React.memo(() => {
480
481
  </ScrollView>
481
482
  </View>
482
483
 
483
- <FlatList data={filteredConsoleLogs} keyExtractor={keyExtractor} ListHeaderComponent={listHeader} renderItem={renderItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState isSearch={logSearch.length > 0 || logFilters.size > 0} searchQuery={logSearch} customTitle={logSearch.length > 0
484
+ <FlatList ref={listRef} data={filteredConsoleLogs} keyExtractor={keyExtractor} ListHeaderComponent={listHeader} renderItem={renderItem} initialNumToRender={12} maxToRenderPerBatch={8} windowSize={5} removeClippedSubviews={true} renderToHardwareTextureAndroid={true} ListEmptyComponent={<EmptyState isSearch={logSearch.length > 0 || logFilters.size > 0} searchQuery={logSearch} customTitle={logSearch.length > 0
484
485
  ? 'No matching console logs'
485
486
  : 'No console logs'} onClearSearch={() => {
486
487
  setLogSearch('');
@@ -489,6 +490,28 @@ const ConsoleTab = React.memo(() => {
489
490
  styles.listContent,
490
491
  filteredConsoleLogs.length === 0 && { flexGrow: 1 },
491
492
  ]} keyboardShouldPersistTaps="handled"/>
493
+
494
+ <TouchableScale onPress={() => {
495
+ try {
496
+ listRef.current?.scrollToOffset({
497
+ offset: 0,
498
+ animated: true,
499
+ });
500
+ }
501
+ catch {
502
+ try {
503
+ listRef.current?.scrollToIndex({
504
+ index: 0,
505
+ animated: true,
506
+ });
507
+ }
508
+ catch { }
509
+ }
510
+ }} hitSlop={12} style={styles.scrollTopBtn}>
511
+ <View style={{ transform: [{ rotate: '180deg' }] }}>
512
+ <ChevronIcon color={AppColors.white} size={18}/>
513
+ </View>
514
+ </TouchableScale>
492
515
  </View>);
493
516
  });
494
517
  export default ConsoleTab;