react-native-inapp-inspector 1.1.34 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +123 -101
  2. package/android/build.gradle +13 -1
  3. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +904 -0
  4. package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.kt +17 -0
  5. package/dist/commonjs/components/ConsoleLogCard.js +57 -56
  6. package/dist/commonjs/components/CopyButton.js +10 -1
  7. package/dist/commonjs/components/ErrorBoundary.js +3 -0
  8. package/dist/commonjs/components/Inspector/AnalyticsTab.js +7 -3
  9. package/dist/commonjs/components/Inspector/BundleTab.js +20 -20
  10. package/dist/commonjs/components/Inspector/ConsoleTab.js +1 -1
  11. package/dist/commonjs/components/Inspector/CrashDetail.js +16 -12
  12. package/dist/commonjs/components/Inspector/CrashTab.js +97 -90
  13. package/dist/commonjs/components/Inspector/InspectorHeader.js +28 -24
  14. package/dist/commonjs/components/Inspector/MainScreen.js +20 -103
  15. package/dist/commonjs/components/Inspector/NetworkTab.js +143 -10
  16. package/dist/commonjs/components/Inspector/PerformanceTab.js +96 -3
  17. package/dist/commonjs/components/Inspector/ReduxDetail.js +24 -19
  18. package/dist/commonjs/components/Inspector/ReduxTab.js +30 -18
  19. package/dist/commonjs/components/Inspector/SettingsPanel.js +1578 -754
  20. package/dist/commonjs/components/Inspector/TabBar.js +6 -3
  21. package/dist/commonjs/components/LogCard.js +27 -9
  22. package/dist/commonjs/components/MetaAccordion.js +42 -0
  23. package/dist/commonjs/components/NetworkIcons.d.ts +10 -0
  24. package/dist/commonjs/components/NetworkIcons.js +53 -1
  25. package/dist/commonjs/components/Toast.js +3 -3
  26. package/dist/commonjs/components/TouchableScale.d.ts +5 -2
  27. package/dist/commonjs/components/TouchableScale.js +30 -32
  28. package/dist/commonjs/constants/index.d.ts +1 -2
  29. package/dist/commonjs/constants/index.js +4 -0
  30. package/dist/commonjs/constants/version.d.ts +1 -1
  31. package/dist/commonjs/constants/version.js +1 -1
  32. package/dist/commonjs/customHooks/analyticsLogger.d.ts +6 -0
  33. package/dist/commonjs/customHooks/analyticsLogger.js +16 -5
  34. package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +2 -0
  35. package/dist/commonjs/customHooks/bundleAnalyzer.js +26 -17
  36. package/dist/commonjs/customHooks/consoleLogger.d.ts +2 -0
  37. package/dist/commonjs/customHooks/consoleLogger.js +10 -1
  38. package/dist/commonjs/customHooks/crashHandler.d.ts +2 -0
  39. package/dist/commonjs/customHooks/crashHandler.js +17 -1
  40. package/dist/commonjs/customHooks/networkLogger.d.ts +2 -0
  41. package/dist/commonjs/customHooks/networkLogger.js +12 -1
  42. package/dist/commonjs/customHooks/performanceTracker.d.ts +3 -1
  43. package/dist/commonjs/customHooks/performanceTracker.js +18 -4
  44. package/dist/commonjs/customHooks/reduxLogger.d.ts +2 -0
  45. package/dist/commonjs/customHooks/reduxLogger.js +10 -1
  46. package/dist/commonjs/helpers/index.js +10 -1
  47. package/dist/commonjs/helpers/settingsStore.d.ts +9 -0
  48. package/dist/commonjs/helpers/settingsStore.js +59 -3
  49. package/dist/commonjs/i18n/locales/en.json +96 -28
  50. package/dist/commonjs/index.d.ts +1 -0
  51. package/dist/commonjs/index.js +307 -73
  52. package/dist/commonjs/native/NativeInspector.d.ts +125 -0
  53. package/dist/commonjs/native/NativeInspector.js +313 -0
  54. package/dist/commonjs/native/NativeNetworkInspector.d.ts +22 -0
  55. package/dist/commonjs/native/NativeNetworkInspector.js +4 -0
  56. package/dist/commonjs/styles/AppColors.d.ts +28 -0
  57. package/dist/commonjs/styles/AppColors.js +30 -0
  58. package/dist/commonjs/styles/index.js +6 -6
  59. package/dist/commonjs/types/enums.d.ts +1 -1
  60. package/dist/commonjs/types/interfaces.d.ts +9 -0
  61. package/dist/esm/components/ConsoleLogCard.js +58 -57
  62. package/dist/esm/components/CopyButton.js +10 -1
  63. package/dist/esm/components/ErrorBoundary.js +3 -0
  64. package/dist/esm/components/Inspector/AnalyticsTab.js +7 -3
  65. package/dist/esm/components/Inspector/BundleTab.js +20 -20
  66. package/dist/esm/components/Inspector/ConsoleTab.js +1 -1
  67. package/dist/esm/components/Inspector/CrashDetail.js +16 -12
  68. package/dist/esm/components/Inspector/CrashTab.js +97 -90
  69. package/dist/esm/components/Inspector/InspectorHeader.js +29 -25
  70. package/dist/esm/components/Inspector/MainScreen.js +21 -71
  71. package/dist/esm/components/Inspector/NetworkTab.js +145 -12
  72. package/dist/esm/components/Inspector/PerformanceTab.js +96 -3
  73. package/dist/esm/components/Inspector/ReduxDetail.js +24 -19
  74. package/dist/esm/components/Inspector/ReduxTab.js +30 -18
  75. package/dist/esm/components/Inspector/SettingsPanel.js +1582 -758
  76. package/dist/esm/components/Inspector/TabBar.js +7 -4
  77. package/dist/esm/components/LogCard.js +27 -9
  78. package/dist/esm/components/MetaAccordion.js +42 -0
  79. package/dist/esm/components/NetworkIcons.d.ts +10 -0
  80. package/dist/esm/components/NetworkIcons.js +42 -0
  81. package/dist/esm/components/Toast.js +3 -3
  82. package/dist/esm/components/TouchableScale.d.ts +5 -2
  83. package/dist/esm/components/TouchableScale.js +31 -33
  84. package/dist/esm/constants/index.d.ts +1 -2
  85. package/dist/esm/constants/index.js +4 -0
  86. package/dist/esm/constants/version.d.ts +1 -1
  87. package/dist/esm/constants/version.js +1 -1
  88. package/dist/esm/customHooks/analyticsLogger.d.ts +6 -0
  89. package/dist/esm/customHooks/analyticsLogger.js +12 -4
  90. package/dist/esm/customHooks/bundleAnalyzer.d.ts +2 -0
  91. package/dist/esm/customHooks/bundleAnalyzer.js +23 -16
  92. package/dist/esm/customHooks/consoleLogger.d.ts +2 -0
  93. package/dist/esm/customHooks/consoleLogger.js +7 -0
  94. package/dist/esm/customHooks/crashHandler.d.ts +2 -0
  95. package/dist/esm/customHooks/crashHandler.js +14 -0
  96. package/dist/esm/customHooks/networkLogger.d.ts +2 -0
  97. package/dist/esm/customHooks/networkLogger.js +9 -0
  98. package/dist/esm/customHooks/performanceTracker.d.ts +3 -1
  99. package/dist/esm/customHooks/performanceTracker.js +15 -3
  100. package/dist/esm/customHooks/reduxLogger.d.ts +2 -0
  101. package/dist/esm/customHooks/reduxLogger.js +7 -0
  102. package/dist/esm/helpers/index.js +10 -1
  103. package/dist/esm/helpers/settingsStore.d.ts +9 -0
  104. package/dist/esm/helpers/settingsStore.js +58 -3
  105. package/dist/esm/i18n/locales/en.json +96 -28
  106. package/dist/esm/index.d.ts +1 -0
  107. package/dist/esm/index.js +279 -59
  108. package/dist/esm/native/NativeInspector.d.ts +125 -0
  109. package/dist/esm/native/NativeInspector.js +289 -0
  110. package/dist/esm/native/NativeNetworkInspector.d.ts +22 -0
  111. package/dist/esm/native/NativeNetworkInspector.js +2 -0
  112. package/dist/esm/styles/AppColors.d.ts +28 -0
  113. package/dist/esm/styles/AppColors.js +30 -0
  114. package/dist/esm/styles/index.js +6 -6
  115. package/dist/esm/types/enums.d.ts +1 -1
  116. package/dist/esm/types/interfaces.d.ts +9 -0
  117. package/ios/NetworkInspectorModule.h +6 -0
  118. package/ios/NetworkInspectorModule.m +720 -5
  119. package/package.json +15 -3
  120. package/react-native-inapp-inspector.podspec +7 -2
  121. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +0 -97
  122. package/android/src/main/java/com/inappinspector/NetworkInspectorPackage.java +0 -28
package/dist/esm/index.js CHANGED
@@ -10,16 +10,20 @@ import { InspectorContext, animateNextLayout, } from './components/Inspector/Ins
10
10
  // Helpers
11
11
  import { formatDisplayUrl, getNavigationInfo, deduplicateLogs, getDomainColor, getEventCategory, } from './helpers';
12
12
  // #5 — settings persistence
13
- import { loadSettings, saveSettings, setCustomStorage, clearPersistedSettings, } from './helpers/settingsStore';
13
+ import { loadSettings, saveSettings, setCustomStorage, clearPersistedSettings, calculateRamBasedLimits, } from './helpers/settingsStore';
14
+ import { getNativeSystemMetrics, pushNativeLogRecord, fetchNativeCachedPage, } from './native/NativeInspector';
14
15
  // Network
15
- import { setupNetworkLogger, clearNetworkLogs, subscribeNetworkLogs, } from './customHooks/networkLogger';
16
+ import { setupNetworkLogger, clearNetworkLogs, subscribeNetworkLogs, setNetworkModuleEnabled, } from './customHooks/networkLogger';
16
17
  // Console
17
- import { setupConsoleLogger, clearConsoleLogs, subscribeConsoleLogs, } from './customHooks/consoleLogger';
18
+ import { setupConsoleLogger, clearConsoleLogs, subscribeConsoleLogs, setConsoleModuleEnabled, } from './customHooks/consoleLogger';
18
19
  import { IGNORED_LOG_PREFIXES } from './customHooks/logFilters';
19
20
  // Crash Protection
20
- import { setupGlobalCrashHandler, subscribeCrashEvents, getCrashRecords, clearCrashRecords, setMaxCrashLogsLimit, } from './customHooks/crashHandler';
21
- import { subscribeAnalyticsEvents, clearAnalyticsEvents, autoSetupAnalyticsLogger, isAnalyticsConnected, } from './customHooks/analyticsLogger';
22
- import { getReduxState, subscribeReduxState, setReduxAutoRefresh, getLastActionForReducer, clearActionHistory, isReduxConnected, } from './customHooks/reduxLogger';
21
+ import { setupGlobalCrashHandler, subscribeCrashEvents, getCrashRecords, clearCrashRecords, setMaxCrashLogsLimit, setCrashModuleEnabled, } from './customHooks/crashHandler';
22
+ import { subscribeAnalyticsEvents, clearAnalyticsEvents, autoSetupAnalyticsLogger, isAnalyticsConnected, setAnalyticsModuleEnabled, } from './customHooks/analyticsLogger';
23
+ import { getReduxState, subscribeReduxState, setReduxAutoRefresh, getLastActionForReducer, clearActionHistory, isReduxConnected, setReduxModuleEnabled, } from './customHooks/reduxLogger';
24
+ import { setPerformanceModuleEnabled } from './customHooks/performanceTracker';
25
+ import { setBundleModuleEnabled } from './customHooks/bundleAnalyzer';
26
+ import { showNativeFloatingButton, hideNativeFloatingButton, setNativeFloatingButtonBadge, subscribeNativeFloatingButtonPress, subscribeNativeDeviceShake, isNativeModuleAvailable, } from './native/NativeInspector';
23
27
  import { LIB_VERSION } from './constants';
24
28
  // Stylesheet
25
29
  import { toggleGlobalTheme } from './styles';
@@ -165,18 +169,50 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
165
169
  const [tabVisibility, setTabVisibility] = useState({
166
170
  apis: true,
167
171
  logs: true,
168
- analytics: true,
172
+ analytics: false,
169
173
  redux: false,
170
174
  bundle: false,
171
175
  performance: false,
172
- crash: true,
176
+ crash: false,
173
177
  });
174
178
  const [maxNetworkLogs, setMaxNetworkLogs] = useState(100);
179
+ const [maxAnalyticsEventsLimit, setMaxAnalyticsEventsLimit] = useState(250);
180
+ const [isAutoRamLimitEnabled, setIsAutoRamLimitEnabled] = useState(true);
181
+ const [deviceFreeRamMb, setDeviceFreeRamMb] = useState(1800);
175
182
  const [reduxAutoRefresh, setReduxAutoRefreshState] = useState(true);
176
183
  const [reduxExpandDepth, setReduxExpandDepth] = useState(1);
177
184
  // #6 — tab the inspector opens on. Shown with a DEFAULT badge in Settings.
178
185
  const [defaultTab, setDefaultTab] = useState('apis');
179
186
  const [showDuplicateLogs, setShowDuplicateLogs] = useState(false);
187
+ // Synchronize runtime background listeners with active settings
188
+ useEffect(() => {
189
+ setNetworkModuleEnabled(!!tabVisibility.apis);
190
+ setConsoleModuleEnabled(!!tabVisibility.logs);
191
+ setAnalyticsModuleEnabled(!!tabVisibility.analytics);
192
+ setReduxModuleEnabled(!!tabVisibility.redux);
193
+ setPerformanceModuleEnabled(!!tabVisibility.performance);
194
+ setCrashModuleEnabled(!!tabVisibility.crash);
195
+ setBundleModuleEnabled(!!tabVisibility.bundle);
196
+ }, [tabVisibility]);
197
+ // Query native hardware RAM and auto-tune limits if auto-RAM is active
198
+ useEffect(() => {
199
+ getNativeSystemMetrics()
200
+ .then(metrics => {
201
+ if (metrics) {
202
+ const freeRam = metrics.totalPhysicalRamMb - metrics.residentRamMb;
203
+ const freeMb = Math.max(200, Math.round(freeRam > 0 ? freeRam : 1500));
204
+ setDeviceFreeRamMb(freeMb);
205
+ if (isAutoRamLimitEnabled) {
206
+ const profile = calculateRamBasedLimits(freeMb);
207
+ setMaxNetworkLogs(profile.maxNetworkLogs);
208
+ setMaxConsoleLogs(profile.maxConsoleLogs);
209
+ setMaxAnalyticsEventsLimit(profile.maxAnalyticsEvents);
210
+ setMaxCrashLogs(profile.maxCrashRecords);
211
+ }
212
+ }
213
+ })
214
+ .catch(() => { });
215
+ }, [isAutoRamLimitEnabled]);
180
216
  const resetToDefaults = async () => {
181
217
  await clearPersistedSettings();
182
218
  setIsDark(false);
@@ -186,16 +222,19 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
186
222
  setTabVisibility({
187
223
  apis: true,
188
224
  logs: true,
189
- analytics: true,
225
+ analytics: false,
190
226
  redux: false,
191
227
  bundle: false,
192
228
  performance: false,
193
- crash: true,
229
+ crash: false,
194
230
  });
195
231
  setDefaultTab('apis');
196
- setMaxCrashLogs(100);
197
- setMaxNetworkLogs(100);
198
- setMaxConsoleLogs(200);
232
+ setIsAutoRamLimitEnabled(true);
233
+ const profile = calculateRamBasedLimits(deviceFreeRamMb);
234
+ setMaxCrashLogs(profile.maxCrashRecords);
235
+ setMaxNetworkLogs(profile.maxNetworkLogs);
236
+ setMaxConsoleLogs(profile.maxConsoleLogs);
237
+ setMaxAnalyticsEventsLimit(profile.maxAnalyticsEvents);
199
238
  setShowConsoleLevels({
200
239
  info: true,
201
240
  warn: true,
@@ -226,16 +265,19 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
226
265
  ...prev,
227
266
  ...saved.tabVisibility,
228
267
  apis: true, // APIs is always required
229
- crash: saved.tabVisibility.crash !== undefined
230
- ? saved.tabVisibility.crash
231
- : true,
232
268
  }));
233
269
  if (saved.defaultTab)
234
270
  setDefaultTab(saved.defaultTab);
271
+ if (saved.isAutoRamLimitEnabled != null)
272
+ setIsAutoRamLimitEnabled(saved.isAutoRamLimitEnabled);
235
273
  if (saved.maxNetworkLogs != null)
236
274
  setMaxNetworkLogs(saved.maxNetworkLogs);
237
275
  if (saved.maxConsoleLogs != null)
238
276
  setMaxConsoleLogs(saved.maxConsoleLogs);
277
+ if (saved.maxAnalyticsEventsLimit != null)
278
+ setMaxAnalyticsEventsLimit(saved.maxAnalyticsEventsLimit);
279
+ if (saved.maxCrashLogs != null)
280
+ setMaxCrashLogs(saved.maxCrashLogs);
239
281
  if (saved.showConsoleLevels)
240
282
  setShowConsoleLevels(saved.showConsoleLevels);
241
283
  if (saved.reduxAutoRefresh != null)
@@ -250,11 +292,11 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
250
292
  ...{
251
293
  apis: true,
252
294
  logs: true,
253
- analytics: true,
295
+ analytics: false,
254
296
  redux: false,
255
297
  bundle: false,
256
298
  performance: false,
257
- crash: true,
299
+ crash: false,
258
300
  },
259
301
  ...(saved.tabVisibility || {}),
260
302
  apis: true,
@@ -278,6 +320,9 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
278
320
  defaultTab,
279
321
  maxNetworkLogs,
280
322
  maxConsoleLogs,
323
+ maxAnalyticsEventsLimit,
324
+ maxCrashLogs,
325
+ isAutoRamLimitEnabled,
281
326
  showConsoleLevels,
282
327
  reduxAutoRefresh,
283
328
  reduxExpandDepth,
@@ -291,6 +336,9 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
291
336
  defaultTab,
292
337
  maxNetworkLogs,
293
338
  maxConsoleLogs,
339
+ maxAnalyticsEventsLimit,
340
+ maxCrashLogs,
341
+ isAutoRamLimitEnabled,
294
342
  showConsoleLevels,
295
343
  reduxAutoRefresh,
296
344
  reduxExpandDepth,
@@ -365,13 +413,43 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
365
413
  return newVisibility;
366
414
  });
367
415
  };
416
+ const loadNativePage = useCallback(async (tabKey, query = '') => {
417
+ if (tabKey === 'apis' || tabKey === 'logs' || tabKey === 'analytics' || tabKey === 'crash') {
418
+ const pageData = await fetchNativeCachedPage(tabKey, 0, 100, query);
419
+ if (pageData && pageData.items && pageData.items.length > 0) {
420
+ if (tabKey === 'apis')
421
+ setLogs(pageData.items);
422
+ else if (tabKey === 'logs')
423
+ setConsoleLogs(pageData.items);
424
+ else if (tabKey === 'analytics')
425
+ setAnalyticsEvents(pageData.items);
426
+ else if (tabKey === 'crash')
427
+ setCrashRecords(pageData.items);
428
+ }
429
+ }
430
+ }, []);
368
431
  const switchActiveTab = useCallback((key) => {
369
432
  if (key === 'redux' && !isReduxConnected())
370
433
  return;
371
434
  if (key === 'analytics' && !isAnalyticsConnected())
372
435
  return;
373
- setActiveTab(key);
374
- }, []);
436
+ setSelected(null);
437
+ setSelectedEvent(null);
438
+ setSelectedLog(null);
439
+ setSelectedReduxSlice(null);
440
+ setSelectedReduxAction(null);
441
+ setSelectedCrash(null);
442
+ if (typeof React.startTransition === 'function') {
443
+ React.startTransition(() => {
444
+ setActiveTab(key);
445
+ loadNativePage(key);
446
+ });
447
+ }
448
+ else {
449
+ setActiveTab(key);
450
+ loadNativePage(key);
451
+ }
452
+ }, [loadNativePage]);
375
453
  const [selectedEvent, setSelectedEvent] = useState(null);
376
454
  const [analyticsSearch, setAnalyticsSearch] = useState('');
377
455
  const [analyticsFilters, setAnalyticsFilters] = useState({
@@ -619,13 +697,84 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
619
697
  loop.start();
620
698
  return () => loop.stop();
621
699
  }, [unreadPulseAnim]);
622
- // #6 every time the inspector is opened, land on the chosen default tab.
700
+ const isNativeModule = useMemo(() => isNativeModuleAvailable(), []);
701
+ const useNativeFab = (Platform.OS === 'ios' || Platform.OS === 'android') && isNativeModule;
702
+ // 100% Native Main-Thread Floating Button Lifecycle
623
703
  useEffect(() => {
704
+ if (!useNativeFab || !isEnabled || !enabled) {
705
+ if (useNativeFab) {
706
+ hideNativeFloatingButton();
707
+ }
708
+ return;
709
+ }
710
+ if (visible) {
711
+ hideNativeFloatingButton();
712
+ }
713
+ else {
714
+ showNativeFloatingButton();
715
+ setNativeFloatingButtonBadge(logs.length > 0 || analyticsEvents.length > 0);
716
+ }
717
+ }, [
718
+ useNativeFab,
719
+ isEnabled,
720
+ enabled,
721
+ visible,
722
+ logs.length,
723
+ analyticsEvents.length,
724
+ ]);
725
+ // Subscribe to native UI-thread floating button tap events
726
+ useEffect(() => {
727
+ if (!useNativeFab)
728
+ return;
729
+ const unsubscribe = subscribeNativeFloatingButtonPress(() => {
730
+ setVisible(true);
731
+ });
732
+ return () => {
733
+ unsubscribe();
734
+ };
735
+ }, [useNativeFab]);
736
+ // Subscribe to physical hardware shake events (or Cmd+Ctrl+Z on iOS simulator)
737
+ useEffect(() => {
738
+ if (!useNativeFab)
739
+ return;
740
+ const unsubscribe = subscribeNativeDeviceShake(() => {
741
+ setVisible(prev => !prev);
742
+ });
743
+ return () => {
744
+ unsubscribe();
745
+ };
746
+ }, [useNativeFab]);
747
+ const isVisibleRefObj = useRef(visible);
748
+ // #6 — every time the inspector is opened, land on chosen default tab & sync latest logs
749
+ useEffect(() => {
750
+ isVisibleRefObj.current = visible;
624
751
  if (visible) {
625
752
  const target = defaultTab === 'apis' || tabVisibility?.[defaultTab]
626
753
  ? defaultTab
627
754
  : 'apis';
628
755
  setActiveTab(target);
756
+ // Instant synchronization of data collected while modal was closed
757
+ if (latestNetworkLogsRef.current.length > 0) {
758
+ const deduped = deduplicateLogs(latestNetworkLogsRef.current);
759
+ const incoming = new Set(deduped.map(l => l.id));
760
+ prevLogIdsRef.current = incoming;
761
+ setLogs(deduped);
762
+ }
763
+ if (latestConsoleLogsRef.current.length > 0) {
764
+ setConsoleLogs(latestConsoleLogsRef.current);
765
+ }
766
+ if (latestAnalyticsEventsRef.current.length > 0) {
767
+ setAnalyticsEvents(latestAnalyticsEventsRef.current);
768
+ }
769
+ const freshState = getReduxState();
770
+ if (freshState) {
771
+ setReduxState(typeof freshState === 'object' ? { ...freshState } : freshState);
772
+ setReduxLastActionMap({ ...getLastActionForReducer() });
773
+ }
774
+ const freshCrashes = getCrashRecords();
775
+ if (freshCrashes.length > 0) {
776
+ setCrashRecords(freshCrashes);
777
+ }
629
778
  }
630
779
  // eslint-disable-next-line react-hooks/exhaustive-deps
631
780
  }, [visible]);
@@ -653,6 +802,7 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
653
802
  setupConsoleLogger();
654
803
  autoSetupAnalyticsLogger();
655
804
  setupGlobalCrashHandler();
805
+ const isVisibleRef = isVisibleRefObj;
656
806
  const unsubscribeCrash = subscribeCrashEvents(crashInfo => {
657
807
  if (crashInfo.message === '__CLEARED__') {
658
808
  setCrashRecords([]);
@@ -660,20 +810,31 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
660
810
  return;
661
811
  }
662
812
  const updated = getCrashRecords();
663
- setCrashRecords(updated);
813
+ if (updated.length > 0) {
814
+ pushNativeLogRecord('crash', JSON.stringify(updated[0]));
815
+ }
816
+ if (isVisibleRef.current) {
817
+ setCrashRecords(updated);
818
+ }
664
819
  });
665
820
  // Sync crashes recorded before this subscription ran (e.g. a render crash
666
821
  // during the very first commit, which fires before effects are mounted).
667
822
  const pendingCrashes = getCrashRecords();
668
823
  if (pendingCrashes.length > 0) {
824
+ pendingCrashes.forEach(c => pushNativeLogRecord('crash', JSON.stringify(c)));
669
825
  setCrashRecords(pendingCrashes);
670
826
  }
671
827
  let timeoutId;
672
828
  let isFirstNetworkCall = true;
673
829
  const unsubscribe = subscribeNetworkLogs((raw) => {
674
830
  latestNetworkLogsRef.current = raw;
831
+ if (raw.length > 0) {
832
+ pushNativeLogRecord('apis', JSON.stringify(raw[0]));
833
+ }
675
834
  if (isNetworkPausedRef.current)
676
835
  return;
836
+ if (!isVisibleRef.current)
837
+ return; // ZERO-RENDER INACTIVE MODE
677
838
  clearTimeout(timeoutId);
678
839
  const updateNetworkState = () => {
679
840
  const deduped = deduplicateLogs(raw);
@@ -711,8 +872,13 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
711
872
  let isFirstAnalyticsCall = true;
712
873
  const unsubscribeAnalytics = subscribeAnalyticsEvents((raw) => {
713
874
  latestAnalyticsEventsRef.current = raw;
875
+ if (raw.length > 0) {
876
+ pushNativeLogRecord('analytics', JSON.stringify(raw[0]));
877
+ }
714
878
  if (isAnalyticsPausedRef.current)
715
879
  return;
880
+ if (!isVisibleRef.current)
881
+ return; // ZERO-RENDER INACTIVE MODE
716
882
  clearTimeout(analyticsTimeoutId);
717
883
  const updateAnalyticsState = () => {
718
884
  const incoming = new Set(raw.map(e => e.id));
@@ -748,8 +914,13 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
748
914
  let isFirstConsoleCall = true;
749
915
  const unsubscribeConsole = subscribeConsoleLogs((raw) => {
750
916
  latestConsoleLogsRef.current = raw;
917
+ if (raw.length > 0) {
918
+ pushNativeLogRecord('logs', JSON.stringify(raw[0]));
919
+ }
751
920
  if (isConsolePausedRef.current)
752
921
  return;
922
+ if (!isVisibleRef.current)
923
+ return; // ZERO-RENDER INACTIVE MODE
753
924
  clearTimeout(consoleTimeoutId);
754
925
  if (isFirstConsoleCall) {
755
926
  isFirstConsoleCall = false;
@@ -762,11 +933,13 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
762
933
  }
763
934
  });
764
935
  const initialReduxState = getReduxState();
765
- setReduxState(initialReduxState && typeof initialReduxState === 'object' ? { ...initialReduxState } : initialReduxState);
766
- setReduxLastActionMap({ ...getLastActionForReducer() });
936
+ if (initialReduxState) {
937
+ setReduxState(typeof initialReduxState === 'object' ? { ...initialReduxState } : initialReduxState);
938
+ setReduxLastActionMap({ ...getLastActionForReducer() });
939
+ }
767
940
  const unsubscribeRedux = subscribeReduxState(() => {
768
- // New references each time guarantee the Redux tab updates live, even when
769
- // the root state object reference is unchanged or auto-refresh is paused.
941
+ if (!isVisibleRef.current)
942
+ return; // ZERO-RENDER INACTIVE MODE
770
943
  const freshState = getReduxState();
771
944
  setReduxState(freshState && typeof freshState === 'object' ? { ...freshState } : freshState);
772
945
  setReduxLastActionMap({ ...getLastActionForReducer() });
@@ -814,6 +987,10 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
814
987
  return true;
815
988
  if (f === 'Failed')
816
989
  return log.status === 0 || log.status == null;
990
+ const codeNum = parseInt(f, 10);
991
+ if (!isNaN(codeNum)) {
992
+ return Number(log.status) === codeNum;
993
+ }
817
994
  return String(log.status)[0] === f[0];
818
995
  });
819
996
  if (!matched)
@@ -829,9 +1006,26 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
829
1006
  if (!matchedMethod)
830
1007
  return false;
831
1008
  }
832
- // Search Bar Check
833
- if (search && !log.url?.toLowerCase().includes(search.toLowerCase()))
834
- return false;
1009
+ // Comprehensive Search Bar Check
1010
+ if (search && search.trim().length > 0) {
1011
+ const queryTokens = search.trim().toLowerCase().split(/\s+/).filter(Boolean);
1012
+ const routePath = logRouteMapRef.current.get(log.id)?.path || '';
1013
+ const reqStr = typeof log.request === 'string' ? log.request : JSON.stringify(log.request || '');
1014
+ const resStr = typeof log.response === 'string' ? log.response : JSON.stringify(log.response || '');
1015
+ const searchTarget = [
1016
+ log.method || '',
1017
+ log.url || '',
1018
+ String(log.status ?? ''),
1019
+ routePath,
1020
+ reqStr,
1021
+ resStr,
1022
+ JSON.stringify(log.requestHeaders || ''),
1023
+ JSON.stringify(log.responseHeaders || ''),
1024
+ ].join(' ').toLowerCase();
1025
+ const isMatch = queryTokens.every(token => searchTarget.includes(token));
1026
+ if (!isMatch)
1027
+ return false;
1028
+ }
835
1029
  return true;
836
1030
  });
837
1031
  if (sortOrder === 'oldest') {
@@ -986,12 +1180,20 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
986
1180
  const filteredAnalyticsEvents = useMemo(() => {
987
1181
  let events = analyticsEvents;
988
1182
  // Search query filter
989
- if (analyticsSearch) {
990
- const s = analyticsSearch.toLowerCase();
991
- events = events.filter(e => e.name.toLowerCase().includes(s) ||
992
- JSON.stringify(e.params || {}).toLowerCase().includes(s) ||
993
- (e.screenName ?? '').toLowerCase().includes(s) ||
994
- (e.pageTitle ?? '').toLowerCase().includes(s));
1183
+ if (analyticsSearch && analyticsSearch.trim().length > 0) {
1184
+ const queryTokens = analyticsSearch.trim().toLowerCase().split(/\s+/).filter(Boolean);
1185
+ events = events.filter(e => {
1186
+ const searchTarget = [
1187
+ e.name || '',
1188
+ JSON.stringify(e.params || ''),
1189
+ JSON.stringify(e.userProperties || ''),
1190
+ e.screenName || '',
1191
+ e.pageTitle || '',
1192
+ e.userId || '',
1193
+ e.source || '',
1194
+ ].join(' ').toLowerCase();
1195
+ return queryTokens.every(token => searchTarget.includes(token));
1196
+ });
995
1197
  }
996
1198
  // Category filter
997
1199
  if (analyticsFilters.categories.size > 0 && !analyticsFilters.categories.has('all')) {
@@ -1029,16 +1231,15 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
1029
1231
  }
1030
1232
  // Payload complexity filter
1031
1233
  if (analyticsFilters.payloadComplexity !== 'all') {
1032
- events = events.filter(e => {
1033
- const count = e.params ? Object.keys(e.params).length : 0;
1034
- if (analyticsFilters.payloadComplexity === 'none')
1035
- return count === 0;
1036
- if (analyticsFilters.payloadComplexity === 'simple')
1037
- return count >= 1 && count <= 5;
1038
- if (analyticsFilters.payloadComplexity === 'heavy')
1039
- return count > 5;
1040
- return true;
1041
- });
1234
+ if (analyticsFilters.payloadComplexity === 'none') {
1235
+ events = events.filter(e => !e.params || Object.keys(e.params).length === 0);
1236
+ }
1237
+ else if (analyticsFilters.payloadComplexity === 'simple') {
1238
+ events = events.filter(e => e.params && Object.keys(e.params).length <= 3);
1239
+ }
1240
+ else if (analyticsFilters.payloadComplexity === 'heavy') {
1241
+ events = events.filter(e => e.params && Object.keys(e.params).length > 3);
1242
+ }
1042
1243
  }
1043
1244
  // Conversion / Goal events filter
1044
1245
  if (analyticsFilters.onlyConversions) {
@@ -1071,10 +1272,8 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
1071
1272
  }
1072
1273
  // Has Revenue filter
1073
1274
  if (analyticsFilters.hasRevenue) {
1074
- events = events.filter(e => {
1075
- const val = e.params?.value ?? e.params?.price;
1076
- return val !== undefined && val !== null && Number(val) > 0;
1077
- });
1275
+ events = events.filter(e => (e.params?.value != null && !isNaN(Number(e.params.value))) ||
1276
+ (e.params?.price != null && !isNaN(Number(e.params.price))));
1078
1277
  }
1079
1278
  // Has Items filter
1080
1279
  if (analyticsFilters.hasItems) {
@@ -1139,16 +1338,23 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
1139
1338
  if (logFilters.has('user-log') && log.sourceMethod === 'log')
1140
1339
  return true;
1141
1340
  if (logFilters.has('analytics') &&
1142
- log.message.toLowerCase().includes('[analytics error]'))
1341
+ log.message?.toLowerCase().includes('[analytics error]'))
1143
1342
  return true;
1144
1343
  return false;
1145
1344
  });
1146
1345
  }
1147
- // Search bar check
1148
- if (logSearch) {
1149
- const s = logSearch.toLowerCase();
1150
- result = result.filter(log => log.message.toLowerCase().includes(s) ||
1151
- (log.caller ?? '').toLowerCase().includes(s));
1346
+ // Comprehensive Search bar check
1347
+ if (logSearch && logSearch.trim().length > 0) {
1348
+ const queryTokens = logSearch.trim().toLowerCase().split(/\s+/).filter(Boolean);
1349
+ result = result.filter(log => {
1350
+ const searchTarget = [
1351
+ log.message || '',
1352
+ log.caller || '',
1353
+ log.type || '',
1354
+ log.sourceMethod || '',
1355
+ ].join(' ').toLowerCase();
1356
+ return queryTokens.every(token => searchTarget.includes(token));
1357
+ });
1152
1358
  }
1153
1359
  // #7 — apply sort order (newest/oldest first)
1154
1360
  result = [...result].sort((a, b) => logSortOrder === 'newest'
@@ -1185,10 +1391,17 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
1185
1391
  ]);
1186
1392
  const logCounts = useMemo(() => {
1187
1393
  let searchedLogs = visibleConsoleLogs;
1188
- if (logSearch) {
1189
- const s = logSearch.toLowerCase();
1190
- searchedLogs = visibleConsoleLogs.filter(log => log.message.toLowerCase().includes(s) ||
1191
- (log.caller ?? '').toLowerCase().includes(s));
1394
+ if (logSearch && logSearch.trim().length > 0) {
1395
+ const queryTokens = logSearch.trim().toLowerCase().split(/\s+/).filter(Boolean);
1396
+ searchedLogs = visibleConsoleLogs.filter(log => {
1397
+ const searchTarget = [
1398
+ log.message || '',
1399
+ log.caller || '',
1400
+ log.type || '',
1401
+ log.sourceMethod || '',
1402
+ ].join(' ').toLowerCase();
1403
+ return queryTokens.every(token => searchTarget.includes(token));
1404
+ });
1192
1405
  }
1193
1406
  const total = visibleConsoleLogs.length;
1194
1407
  return {
@@ -1382,6 +1595,7 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
1382
1595
  unreadPulseAnim,
1383
1596
  runClearAllWithAnimation,
1384
1597
  // ─── FAB / launcher ─────────────────────────────────────────────────
1598
+ useNativeFab,
1385
1599
  fabPan,
1386
1600
  fabPanResponder,
1387
1601
  fabDraggedRef,
@@ -1499,6 +1713,11 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
1499
1713
  setMaxNetworkLogs,
1500
1714
  maxConsoleLogs,
1501
1715
  setMaxConsoleLogs,
1716
+ maxAnalyticsEventsLimit,
1717
+ setMaxAnalyticsEventsLimit,
1718
+ isAutoRamLimitEnabled,
1719
+ setIsAutoRamLimitEnabled,
1720
+ deviceFreeRamMb,
1502
1721
  reduxAutoRefresh,
1503
1722
  setReduxAutoRefreshState,
1504
1723
  reduxExpandDepth,
@@ -1532,4 +1751,5 @@ export { connectReduxStore, inspectorReduxMiddleware, getReduxState, subscribeRe
1532
1751
  export { getEventCategory, registerGAPlugin, } from './helpers/gaAnalyticsRegistry';
1533
1752
  export { usePerformanceTracker, useComponentProfiler, useNavigationProfiler, trackComponentRender, trackNavigationTransition, trackHeavyTask, measureAsync, getHermesMemoryStats, registerComponentProfile, subscribeRenderProfiles, getRenderProfiles, logPerformanceEvent, clearPerformanceEvents, subscribePerformanceEvents, getPerformanceEvents, getInitialRenderProfiles, getInitialPerformanceEvents, generateFixSnippet, } from './customHooks/performanceTracker';
1534
1753
  export { InspectLog, InspectTrackTime, InspectCatch, } from './decorators';
1754
+ export { getNativeDeviceMetrics, enableNativeCrashProtection, subscribeNativeCrashes, showNativeFloatingButton, hideNativeFloatingButton, setNativeFloatingButtonBadge, subscribeNativeFloatingButtonPress, subscribeNativeDeviceShake, startNativeFpsMonitoring, stopNativeFpsMonitoring, getNativeFpsMetrics, getNativeStorageItem, setNativeStorageItem, isNativeModuleAvailable, } from './native/NativeInspector';
1535
1755
  export { ActiveTab, Method, StatusFilter, SortOrder, LocalFilter, ModalAnimationType, SettingsPage, SettingsSubTab, LogFilter, ConsoleLogType, AnalyticsEventSource, GAEventCategory, StackFrameType, DiffResultType, BundleSubTab, PerformanceSubTab, CrashType, CrashExportFormat, CrashDetailSubTab, CrashFilterType, BreadcrumbType, } from './types';