react-native-inapp-inspector 2.2.9 → 2.3.1

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 (105) hide show
  1. package/dist/commonjs/components/AppHeaderLogo.js +45 -12
  2. package/dist/commonjs/components/BrandSquareIcon.js +92 -49
  3. package/dist/commonjs/components/EmptyState.d.ts +7 -2
  4. package/dist/commonjs/components/EmptyState.js +11 -5
  5. package/dist/commonjs/components/Inspector/AnalyticsTab.js +29 -18
  6. package/dist/commonjs/components/Inspector/ConsoleTab.js +6 -1
  7. package/dist/commonjs/components/Inspector/CrashDetail.js +43 -9
  8. package/dist/commonjs/components/Inspector/CrashTab.js +34 -3
  9. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +80 -16
  10. package/dist/commonjs/components/Inspector/InspectorHeader.js +16 -3
  11. package/dist/commonjs/components/Inspector/MainScreen.js +7 -11
  12. package/dist/commonjs/components/Inspector/NetworkDetail.js +3 -2
  13. package/dist/commonjs/components/Inspector/NetworkTab.js +103 -4
  14. package/dist/commonjs/components/Inspector/ReduxTab.js +19 -3
  15. package/dist/commonjs/components/Inspector/SettingsPanel.js +4 -4
  16. package/dist/commonjs/components/Inspector/StorageTab.js +123 -92
  17. package/dist/commonjs/components/JsonViewer.js +2 -0
  18. package/dist/commonjs/components/MetaAccordion.js +15 -3
  19. package/dist/commonjs/components/SkeletonPlaceholder.d.ts +6 -0
  20. package/dist/commonjs/components/SkeletonPlaceholder.js +208 -0
  21. package/dist/commonjs/constants/version.d.ts +1 -1
  22. package/dist/commonjs/constants/version.js +1 -1
  23. package/dist/commonjs/customHooks/networkLogger.d.ts +3 -0
  24. package/dist/commonjs/customHooks/networkLogger.js +10 -1
  25. package/dist/commonjs/customHooks/storageInspector.d.ts +2 -2
  26. package/dist/commonjs/customHooks/storageInspector.js +17 -13
  27. package/dist/commonjs/helpers/index.d.ts +6 -0
  28. package/dist/commonjs/helpers/index.js +196 -6
  29. package/dist/commonjs/helpers/searchQueryParser.js +62 -20
  30. package/dist/commonjs/i18n/index.d.ts +13 -0
  31. package/dist/commonjs/i18n/index.js +35 -2
  32. package/dist/commonjs/index.d.ts +3 -0
  33. package/dist/commonjs/index.js +108 -35
  34. package/dist/commonjs/styles/AppColors.d.ts +4 -0
  35. package/dist/commonjs/styles/AppColors.js +11 -1
  36. package/dist/commonjs/styles/AppFonts.d.ts +11 -0
  37. package/dist/commonjs/styles/AppFonts.js +11 -1
  38. package/dist/commonjs/types/interfaces.d.ts +2 -2
  39. package/dist/esm/components/AppHeaderLogo.js +45 -12
  40. package/dist/esm/components/BrandSquareIcon.js +92 -49
  41. package/dist/esm/components/EmptyState.d.ts +7 -2
  42. package/dist/esm/components/EmptyState.js +11 -5
  43. package/dist/esm/components/Inspector/AnalyticsTab.js +30 -19
  44. package/dist/esm/components/Inspector/ConsoleTab.js +6 -1
  45. package/dist/esm/components/Inspector/CrashDetail.js +43 -9
  46. package/dist/esm/components/Inspector/CrashTab.js +34 -3
  47. package/dist/esm/components/Inspector/DeviceInfoTab.js +80 -16
  48. package/dist/esm/components/Inspector/InspectorHeader.js +17 -4
  49. package/dist/esm/components/Inspector/MainScreen.js +8 -12
  50. package/dist/esm/components/Inspector/NetworkDetail.js +3 -2
  51. package/dist/esm/components/Inspector/NetworkTab.js +103 -4
  52. package/dist/esm/components/Inspector/ReduxTab.js +19 -3
  53. package/dist/esm/components/Inspector/SettingsPanel.js +4 -4
  54. package/dist/esm/components/Inspector/StorageTab.js +124 -93
  55. package/dist/esm/components/JsonViewer.js +2 -0
  56. package/dist/esm/components/MetaAccordion.js +15 -3
  57. package/dist/esm/components/SkeletonPlaceholder.d.ts +6 -0
  58. package/dist/esm/components/SkeletonPlaceholder.js +173 -0
  59. package/dist/esm/constants/version.d.ts +1 -1
  60. package/dist/esm/constants/version.js +1 -1
  61. package/dist/esm/customHooks/networkLogger.d.ts +3 -0
  62. package/dist/esm/customHooks/networkLogger.js +8 -0
  63. package/dist/esm/customHooks/storageInspector.d.ts +2 -2
  64. package/dist/esm/customHooks/storageInspector.js +17 -13
  65. package/dist/esm/helpers/index.d.ts +6 -0
  66. package/dist/esm/helpers/index.js +193 -5
  67. package/dist/esm/helpers/searchQueryParser.js +62 -20
  68. package/dist/esm/i18n/index.d.ts +13 -0
  69. package/dist/esm/i18n/index.js +33 -3
  70. package/dist/esm/index.d.ts +3 -0
  71. package/dist/esm/index.js +97 -37
  72. package/dist/esm/styles/AppColors.d.ts +4 -0
  73. package/dist/esm/styles/AppColors.js +9 -0
  74. package/dist/esm/styles/AppFonts.d.ts +11 -0
  75. package/dist/esm/styles/AppFonts.js +9 -0
  76. package/dist/esm/types/interfaces.d.ts +2 -2
  77. package/package.json +1 -1
  78. package/src/components/AppHeaderLogo.tsx +46 -12
  79. package/src/components/BrandSquareIcon.tsx +127 -78
  80. package/src/components/EmptyState.tsx +27 -5
  81. package/src/components/Inspector/AnalyticsTab.tsx +48 -27
  82. package/src/components/Inspector/ConsoleTab.tsx +10 -0
  83. package/src/components/Inspector/CrashDetail.tsx +65 -9
  84. package/src/components/Inspector/CrashTab.tsx +41 -3
  85. package/src/components/Inspector/DeviceInfoTab.tsx +87 -16
  86. package/src/components/Inspector/InspectorHeader.tsx +24 -4
  87. package/src/components/Inspector/MainScreen.tsx +7 -11
  88. package/src/components/Inspector/NetworkDetail.tsx +4 -4
  89. package/src/components/Inspector/NetworkTab.tsx +129 -4
  90. package/src/components/Inspector/ReduxTab.tsx +26 -8
  91. package/src/components/Inspector/SettingsPanel.tsx +4 -4
  92. package/src/components/Inspector/StorageTab.tsx +191 -117
  93. package/src/components/JsonViewer.tsx +2 -0
  94. package/src/components/MetaAccordion.tsx +18 -3
  95. package/src/components/SkeletonPlaceholder.tsx +206 -0
  96. package/src/constants/version.ts +1 -1
  97. package/src/customHooks/networkLogger.ts +15 -0
  98. package/src/customHooks/storageInspector.ts +18 -14
  99. package/src/helpers/index.ts +213 -5
  100. package/src/helpers/searchQueryParser.ts +63 -20
  101. package/src/i18n/index.ts +38 -3
  102. package/src/index.tsx +124 -37
  103. package/src/styles/AppColors.ts +9 -0
  104. package/src/styles/AppFonts.ts +16 -0
  105. package/src/types/interfaces.ts +2 -2
@@ -5,7 +5,8 @@
5
5
  export function matchNetworkLogQuery(log, searchQuery, routePath, options) {
6
6
  if (!searchQuery || searchQuery.trim().length === 0)
7
7
  return true;
8
- const rawTokens = searchQuery.trim().match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) || [];
8
+ // Split tokens by spaces or commas while respecting quotes
9
+ const rawTokens = searchQuery.trim().match(/(?:[^\s,"']+|"[^"]*"|'[^']*')+/g) || [];
9
10
  if (rawTokens.length === 0)
10
11
  return true;
11
12
  const isCaseSensitive = Boolean(options?.isCaseSensitive);
@@ -15,24 +16,35 @@ export function matchNetworkLogQuery(log, searchQuery, routePath, options) {
15
16
  const urlRaw = log.url || '';
16
17
  const statusNum = typeof log.status === 'number'
17
18
  ? log.status
18
- : parseInt(String(log.status || 0), 10);
19
- const statusStr = String(log.status ?? '');
19
+ : log.status != null
20
+ ? parseInt(String(log.status), 10)
21
+ : null;
22
+ const statusStr = log.status != null ? String(log.status) : 'pending';
20
23
  const durationNum = log.duration || 0;
21
24
  const clientRaw = log.client || '';
25
+ const callerRaw = log.caller || '';
22
26
  const reqRaw = typeof log.request === 'string'
23
27
  ? log.request
24
- : JSON.stringify(log.request || '');
28
+ : log.request != null
29
+ ? JSON.stringify(log.request)
30
+ : '';
25
31
  const resRaw = typeof log.response === 'string'
26
32
  ? log.response
27
- : JSON.stringify(log.response || '');
28
- const reqHeadersRaw = JSON.stringify(log.requestHeaders || '');
29
- const resHeadersRaw = JSON.stringify(log.responseHeaders || '');
30
- const pathRaw = routePath || '';
33
+ : log.response != null
34
+ ? JSON.stringify(log.response)
35
+ : '';
36
+ const reqHeadersRaw = log.requestHeaders
37
+ ? JSON.stringify(log.requestHeaders)
38
+ : '';
39
+ const resHeadersRaw = log.responseHeaders
40
+ ? JSON.stringify(log.responseHeaders)
41
+ : '';
42
+ const pathRaw = routePath || log?.routeInfo?.path || '';
31
43
  // Construct search corpus based on active scope
32
44
  const getScopedCorpus = (caseSens) => {
33
45
  let parts = [];
34
46
  if (scope === 'url') {
35
- parts = [methodRaw, urlRaw, pathRaw];
47
+ parts = [methodRaw, urlRaw, pathRaw, callerRaw];
36
48
  }
37
49
  else if (scope === 'reqBody') {
38
50
  parts = [reqRaw];
@@ -49,6 +61,7 @@ export function matchNetworkLogQuery(log, searchQuery, routePath, options) {
49
61
  urlRaw,
50
62
  statusStr,
51
63
  pathRaw,
64
+ callerRaw,
52
65
  clientRaw,
53
66
  reqRaw,
54
67
  resRaw,
@@ -63,6 +76,7 @@ export function matchNetworkLogQuery(log, searchQuery, routePath, options) {
63
76
  const methodStr = methodRaw.toLowerCase();
64
77
  const urlStr = urlRaw.toLowerCase();
65
78
  const clientStr = clientRaw.toLowerCase();
79
+ const callerStr = callerRaw.toLowerCase();
66
80
  const reqStr = reqRaw.toLowerCase();
67
81
  const resStr = resRaw.toLowerCase();
68
82
  const reqHeadersStr = reqHeadersRaw.toLowerCase();
@@ -89,24 +103,28 @@ export function matchNetworkLogQuery(log, searchQuery, routePath, options) {
89
103
  // 2. status:<VAL> or s:<VAL>
90
104
  if (lowerToken.startsWith('status:') || lowerToken.startsWith('s:')) {
91
105
  const val = lowerToken.replace(/^(status:|s:)/, '').trim();
92
- if (val.startsWith('>=')) {
106
+ if (val === 'pending' || val === 'loading') {
107
+ if (log.status != null)
108
+ return false;
109
+ }
110
+ else if (val.startsWith('>=')) {
93
111
  const threshold = parseInt(val.slice(2), 10);
94
- if (isNaN(threshold) || statusNum < threshold)
112
+ if (isNaN(threshold) || statusNum === null || statusNum < threshold)
95
113
  return false;
96
114
  }
97
115
  else if (val.startsWith('>')) {
98
116
  const threshold = parseInt(val.slice(1), 10);
99
- if (isNaN(threshold) || statusNum <= threshold)
117
+ if (isNaN(threshold) || statusNum === null || statusNum <= threshold)
100
118
  return false;
101
119
  }
102
120
  else if (val.startsWith('<=')) {
103
121
  const threshold = parseInt(val.slice(2), 10);
104
- if (isNaN(threshold) || statusNum > threshold)
122
+ if (isNaN(threshold) || statusNum === null || statusNum > threshold)
105
123
  return false;
106
124
  }
107
125
  else if (val.startsWith('<')) {
108
126
  const threshold = parseInt(val.slice(1), 10);
109
- if (isNaN(threshold) || statusNum >= threshold)
127
+ if (isNaN(threshold) || statusNum === null || statusNum >= threshold)
110
128
  return false;
111
129
  }
112
130
  else if (val.endsWith('xx') || val.endsWith('x')) {
@@ -133,15 +151,19 @@ export function matchNetworkLogQuery(log, searchQuery, routePath, options) {
133
151
  flag === 'failed' ||
134
152
  flag === 'err' ||
135
153
  flag === 'fail') {
136
- const isErr = log.status === 0 || log.status == null || statusNum >= 400;
154
+ const isErr = log.status === 0 || (statusNum !== null && statusNum >= 400);
137
155
  if (!isErr)
138
156
  return false;
139
157
  }
140
158
  else if (flag === 'success' || flag === 'ok' || flag === '2xx') {
141
- const isSuccess = statusNum >= 200 && statusNum < 300;
159
+ const isSuccess = statusNum !== null && statusNum >= 200 && statusNum < 300;
142
160
  if (!isSuccess)
143
161
  return false;
144
162
  }
163
+ else if (flag === 'pending' || flag === 'loading') {
164
+ if (log.status != null)
165
+ return false;
166
+ }
145
167
  else if (flag === 'slow') {
146
168
  if (durationNum < 1000)
147
169
  return false;
@@ -172,6 +194,12 @@ export function matchNetworkLogQuery(log, searchQuery, routePath, options) {
172
194
  if (!isJson)
173
195
  return false;
174
196
  }
197
+ else if (flag === 'image') {
198
+ const isImg = resHeadersStr.includes('image/') ||
199
+ /\.(png|jpe?g|gif|webp|svg)/i.test(urlStr);
200
+ if (!isImg)
201
+ return false;
202
+ }
175
203
  continue;
176
204
  }
177
205
  // 4. slow:<DURATION> or dur:<DURATION> or duration:<DURATION>
@@ -233,10 +261,16 @@ export function matchNetworkLogQuery(log, searchQuery, routePath, options) {
233
261
  return false;
234
262
  continue;
235
263
  }
236
- // 7. path:<PATH> or p:<PATH>
237
- if (lowerToken.startsWith('path:') || lowerToken.startsWith('p:')) {
238
- const targetPath = lowerToken.replace(/^(path:|p:)/, '').trim();
239
- if (!urlStr.includes(targetPath) && !pathStr.includes(targetPath)) {
264
+ // 7. path:<PATH> or p:<PATH> or page:<PAGE>
265
+ if (lowerToken.startsWith('path:') ||
266
+ lowerToken.startsWith('p:') ||
267
+ lowerToken.startsWith('page:')) {
268
+ const targetPath = lowerToken
269
+ .replace(/^(path:|p:|page:)/, '')
270
+ .trim();
271
+ if (!urlStr.includes(targetPath) &&
272
+ !pathStr.includes(targetPath) &&
273
+ !callerStr.includes(targetPath)) {
240
274
  return false;
241
275
  }
242
276
  continue;
@@ -279,6 +313,14 @@ export function matchNetworkLogQuery(log, searchQuery, routePath, options) {
279
313
  else {
280
314
  const queryTerm = isCaseSensitive ? token : lowerToken;
281
315
  if (!targetCorpus.includes(queryTerm)) {
316
+ // Special case: if user typed "error" / "failed", check error status
317
+ if (queryTerm === 'error' ||
318
+ queryTerm === 'failed' ||
319
+ queryTerm === 'fail') {
320
+ const isErr = log.status === 0 || (statusNum !== null && statusNum >= 400);
321
+ if (isErr)
322
+ continue;
323
+ }
282
324
  return false;
283
325
  }
284
326
  }
@@ -4,9 +4,17 @@ type TranslationParams = Record<string, any>;
4
4
  * Standalone zero-dependency translation function
5
5
  */
6
6
  export declare function t(key: string, optionsOrFallback?: TranslationParams | string): string;
7
+ export declare function setLanguage(lang: string): void;
8
+ export declare function addTranslations(lang: string, translations: Record<string, any>): void;
9
+ export declare function setTranslations(translations: Record<string, any>, lang?: string): void;
7
10
  export declare const i18n: {
8
11
  t: typeof t;
9
12
  language: string;
13
+ changeLanguage: typeof setLanguage;
14
+ addResourceBundle: (lng: string, _ns: string, resources: any) => void;
15
+ setLanguage: typeof setLanguage;
16
+ addTranslations: typeof addTranslations;
17
+ setTranslations: typeof setTranslations;
10
18
  };
11
19
  /**
12
20
  * React hook compatible with react-i18next useTranslation()
@@ -16,6 +24,11 @@ export declare function useTranslation(): {
16
24
  i18n: {
17
25
  t: typeof t;
18
26
  language: string;
27
+ changeLanguage: typeof setLanguage;
28
+ addResourceBundle: (lng: string, _ns: string, resources: any) => void;
29
+ setLanguage: typeof setLanguage;
30
+ addTranslations: typeof addTranslations;
31
+ setTranslations: typeof setTranslations;
19
32
  };
20
33
  };
21
34
  /**
@@ -1,5 +1,9 @@
1
1
  import React from 'react';
2
- import en from './locales/en.json';
2
+ import enLocale from './locales/en.json';
3
+ const localeRegistry = {
4
+ en: enLocale,
5
+ };
6
+ let currentLanguage = 'en';
3
7
  /**
4
8
  * Lightweight nested lookup for translation keys (e.g. "network.headers")
5
9
  */
@@ -29,7 +33,11 @@ function interpolate(template, params) {
29
33
  * Standalone zero-dependency translation function
30
34
  */
31
35
  export function t(key, optionsOrFallback) {
32
- const raw = lookupKey(en, key);
36
+ const activeBundle = localeRegistry[currentLanguage] || localeRegistry.en;
37
+ let raw = lookupKey(activeBundle, key);
38
+ if (raw === undefined && currentLanguage !== 'en') {
39
+ raw = lookupKey(localeRegistry.en, key);
40
+ }
33
41
  if (typeof raw === 'string') {
34
42
  if (typeof optionsOrFallback === 'object' && optionsOrFallback !== null) {
35
43
  return interpolate(raw, optionsOrFallback);
@@ -41,9 +49,31 @@ export function t(key, optionsOrFallback) {
41
49
  }
42
50
  return key;
43
51
  }
52
+ export function setLanguage(lang) {
53
+ if (typeof lang === 'string' && lang.trim()) {
54
+ currentLanguage = lang.trim();
55
+ i18n.language = currentLanguage;
56
+ }
57
+ }
58
+ export function addTranslations(lang, translations) {
59
+ if (!lang || !translations || typeof translations !== 'object')
60
+ return;
61
+ localeRegistry[lang] = {
62
+ ...(localeRegistry[lang] || {}),
63
+ ...translations,
64
+ };
65
+ }
66
+ export function setTranslations(translations, lang = 'en') {
67
+ addTranslations(lang, translations);
68
+ }
44
69
  export const i18n = {
45
70
  t,
46
- language: 'en',
71
+ language: currentLanguage,
72
+ changeLanguage: setLanguage,
73
+ addResourceBundle: (lng, _ns, resources) => addTranslations(lng, resources),
74
+ setLanguage,
75
+ addTranslations,
76
+ setTranslations,
47
77
  };
48
78
  /**
49
79
  * React hook compatible with react-i18next useTranslation()
@@ -23,3 +23,6 @@ export { setMaxPerformanceEventsLimit, getMaxPerformanceEventsLimit, prunePerfor
23
23
  export { BrandSquareIcon, BrandCircleIcon, } from './components/NetworkIcons';
24
24
  export { connectAsyncStorage, connectMMKV, isAsyncStorageConnected, isMMKVConnected, getRegisteredMMKVInstanceIds, fetchStorageEntries, setStorageEntry, removeStorageEntry, clearStorageDriver, subscribeToStorageChanges, type StorageEntry, type StorageDriver, } from './customHooks/storageInspector';
25
25
  export { ActiveTab, Method, StatusFilter, SortOrder, LocalFilter, ModalAnimationType, SettingsPage, SettingsSubTab, LogFilter, ConsoleLogType, AnalyticsEventSource, GAEventCategory, StackFrameType, DiffResultType, BundleSubTab, PerformanceSubTab, CrashType, CrashExportFormat, CrashDetailSubTab, CrashFilterType, BreadcrumbType, } from './types';
26
+ export { AppFonts, setAppFonts, type AppFontConfig, } from './styles/AppFonts';
27
+ export { AppColors, setAppColors, getThemeColors, updateAppColorsTheme, } from './styles/AppColors';
28
+ export { t, i18n, useTranslation, setLanguage, addTranslations, setTranslations, I18nextProvider, } from './i18n';
package/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
2
- import { Alert, Animated, PanResponder, Platform, UIManager, LogBox, InteractionManager, } from 'react-native';
2
+ import { Alert, Animated, PanResponder, Platform, UIManager, LogBox, } from 'react-native';
3
3
  import { NavigationContext } from '@react-navigation/native';
4
4
  // i18n
5
5
  import { I18nextProvider, i18n } from './i18n';
@@ -8,12 +8,12 @@ import ErrorBoundary from './components/ErrorBoundary';
8
8
  import MainScreen from './components/Inspector/MainScreen';
9
9
  import { InspectorContext, animateNextLayout, } from './components/Inspector/InspectorContext';
10
10
  // Helpers
11
- import { formatDisplayUrl, getNavigationInfo, deduplicateLogs, getDomainColor, getEventCategory, matchNetworkLogQuery, setupMemoryWarningHandler, } from './helpers';
11
+ import { formatDisplayUrl, getNavigationInfo, getLogPageName, deduplicateLogs, getDomainColor, getEventCategory, matchNetworkLogQuery, setupMemoryWarningHandler, } from './helpers';
12
12
  // #5 — settings persistence
13
13
  import { loadSettings, saveSettings, setCustomStorage, clearPersistedSettings, calculateRamBasedLimits, } from './helpers/settingsStore';
14
14
  import { getNativeSystemMetrics, pushNativeLogRecord, fetchNativeCachedPage, } from './native/NativeInspector';
15
15
  // Network
16
- import { setupNetworkLogger, clearNetworkLogs, subscribeNetworkLogs, setNetworkModuleEnabled, setMaxNetworkLogsLimit, } from './customHooks/networkLogger';
16
+ import { setupNetworkLogger, clearNetworkLogs, subscribeNetworkLogs, setNetworkModuleEnabled, setMaxNetworkLogsLimit, setRouteInfoProvider, } from './customHooks/networkLogger';
17
17
  // Console
18
18
  import { setupConsoleLogger, clearConsoleLogs, subscribeConsoleLogs, setConsoleModuleEnabled, } from './customHooks/consoleLogger';
19
19
  import { IGNORED_LOG_PREFIXES } from './customHooks/logFilters';
@@ -27,7 +27,7 @@ import { showNativeFloatingButton, hideNativeFloatingButton, setNativeFloatingBu
27
27
  import { LIB_VERSION } from './constants';
28
28
  // Stylesheet
29
29
  import { toggleGlobalTheme } from './styles';
30
- const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigationRef, appIcon, environment, initialVisible, visible: controlledVisible, }) => {
30
+ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, environment, initialVisible = false, visible: controlledVisible, }) => {
31
31
  // Set custom storage synchronously during render phase
32
32
  setCustomStorage(storage || null);
33
33
  const [isDark, setIsDark] = useState(false);
@@ -39,7 +39,7 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
39
39
  const [modalHeightPercent, setModalHeightPercent] = useState(90);
40
40
  const [modalAnimationType, setModalAnimationType] = useState('slide');
41
41
  const [logs, setLogs] = useState([]);
42
- const [visible, setVisible] = useState(initialVisible ?? controlledVisible ?? false);
42
+ const [visible, setVisible] = useState(controlledVisible ?? initialVisible ?? false);
43
43
  useEffect(() => {
44
44
  if (controlledVisible !== undefined) {
45
45
  setVisible(controlledVisible);
@@ -183,8 +183,8 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
183
183
  bundle: false,
184
184
  performance: false,
185
185
  crash: false,
186
- device: true,
187
- storage: true,
186
+ device: false,
187
+ storage: false,
188
188
  });
189
189
  const [maxNetworkLogs, setMaxNetworkLogs] = useState(100);
190
190
  const [maxAnalyticsEventsLimit, setMaxAnalyticsEventsLimit] = useState(75);
@@ -239,8 +239,8 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
239
239
  bundle: false,
240
240
  performance: false,
241
241
  crash: false,
242
- device: true,
243
- storage: true,
242
+ device: false,
243
+ storage: false,
244
244
  });
245
245
  setDefaultTab('apis');
246
246
  setIsAutoRamLimitEnabled(true);
@@ -314,6 +314,8 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
314
314
  bundle: false,
315
315
  performance: false,
316
316
  crash: false,
317
+ device: false,
318
+ storage: false,
317
319
  },
318
320
  ...(saved.tabVisibility || {}),
319
321
  apis: true,
@@ -539,12 +541,21 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
539
541
  const navigationContext = React.useContext(NavigationContext);
540
542
  const hasNavigationContext = navigationContext !== undefined;
541
543
  const currentRouteRef = useRef({
542
- path: 'Navigators',
544
+ path: '',
543
545
  params: null,
544
546
  });
547
+ useEffect(() => {
548
+ setRouteInfoProvider(() => currentRouteRef.current);
549
+ return () => {
550
+ setRouteInfoProvider(null);
551
+ };
552
+ }, []);
545
553
  useEffect(() => {
546
554
  if (navState) {
547
- currentRouteRef.current = getNavigationInfo(navState);
555
+ const info = getNavigationInfo(navState);
556
+ if (info?.path) {
557
+ currentRouteRef.current = info;
558
+ }
548
559
  }
549
560
  }, [navState]);
550
561
  useEffect(() => {
@@ -553,9 +564,22 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
553
564
  const updateState = () => {
554
565
  try {
555
566
  if (typeof navigationRef.isReady === 'function' && navigationRef.isReady()) {
567
+ const currentRoute = typeof navigationRef.getCurrentRoute === 'function'
568
+ ? navigationRef.getCurrentRoute()
569
+ : null;
570
+ if (currentRoute?.name) {
571
+ currentRouteRef.current = {
572
+ path: currentRoute.name,
573
+ params: currentRoute.params || null,
574
+ };
575
+ }
556
576
  const state = navigationRef.getRootState();
557
577
  if (state) {
558
578
  setNavState(state);
579
+ const routeInfo = getNavigationInfo(state);
580
+ if (routeInfo?.path) {
581
+ currentRouteRef.current = routeInfo;
582
+ }
559
583
  }
560
584
  }
561
585
  }
@@ -719,22 +743,26 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
719
743
  const useNativeFab = (Platform.OS === 'ios' || Platform.OS === 'android') && isNativeModule;
720
744
  // 100% Native Main-Thread Floating Button Lifecycle
721
745
  useEffect(() => {
722
- if (!useNativeFab || !isEnabled || !enabled) {
746
+ if (!useNativeFab || !enabled) {
723
747
  if (useNativeFab) {
724
- hideNativeFloatingButton();
748
+ hideNativeFloatingButton().catch(() => { });
725
749
  }
726
750
  return;
727
751
  }
728
752
  if (visible) {
729
- hideNativeFloatingButton();
753
+ hideNativeFloatingButton().catch(() => { });
730
754
  }
731
755
  else {
732
- showNativeFloatingButton();
733
- setNativeFloatingButtonBadge(logs.length > 0 || analyticsEvents.length > 0);
756
+ showNativeFloatingButton().catch(() => { });
757
+ setNativeFloatingButtonBadge(logs.length > 0 || analyticsEvents.length > 0).catch(() => { });
734
758
  }
759
+ return () => {
760
+ if (useNativeFab) {
761
+ hideNativeFloatingButton().catch(() => { });
762
+ }
763
+ };
735
764
  }, [
736
765
  useNativeFab,
737
- isEnabled,
738
766
  enabled,
739
767
  visible,
740
768
  logs.length,
@@ -793,20 +821,11 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
793
821
  if (freshCrashes.length > 0) {
794
822
  setCrashRecords(freshCrashes);
795
823
  }
796
- }
797
- // eslint-disable-next-line react-hooks/exhaustive-deps
798
- }, [visible]);
799
- useEffect(() => {
800
- if (visible) {
801
- const task = InteractionManager.runAfterInteractions(() => {
824
+ const frame = requestAnimationFrame(() => {
802
825
  setIsReady(true);
803
826
  });
804
- const fallbackTimer = setTimeout(() => {
805
- setIsReady(true);
806
- }, 350);
807
827
  return () => {
808
- task.cancel();
809
- clearTimeout(fallbackTimer);
828
+ cancelAnimationFrame(frame);
810
829
  };
811
830
  }
812
831
  else {
@@ -867,7 +886,9 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
867
886
  if (freshIds.size > 0) {
868
887
  freshIds.forEach(id => {
869
888
  if (!logRouteMapRef.current.has(id)) {
870
- logRouteMapRef.current.set(id, currentRouteRef.current);
889
+ const matchedLog = deduped.find(l => l.id === id);
890
+ const resolvedRoute = matchedLog?.routeInfo || currentRouteRef.current;
891
+ logRouteMapRef.current.set(id, resolvedRoute);
871
892
  }
872
893
  });
873
894
  setNewLogIds(freshIds);
@@ -880,6 +901,12 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
880
901
  const deduped = deduplicateLogs(raw);
881
902
  const incoming = new Set(deduped.map(l => l.id));
882
903
  prevLogIdsRef.current = incoming;
904
+ deduped.forEach(l => {
905
+ if (!logRouteMapRef.current.has(l.id)) {
906
+ const resolvedRoute = l?.routeInfo || currentRouteRef.current;
907
+ logRouteMapRef.current.set(l.id, resolvedRoute);
908
+ }
909
+ });
883
910
  setLogs(deduped);
884
911
  }
885
912
  else {
@@ -1151,8 +1178,8 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
1151
1178
  const groups = [];
1152
1179
  for (let i = 0; i < filteredLogs.length; i++) {
1153
1180
  const log = filteredLogs[i];
1154
- const routeInfo = logRouteMapRef.current.get(log.id);
1155
- const pageName = routeInfo?.path || 'Navigators';
1181
+ const routeInfo = logRouteMapRef.current.get(log.id) || log?.routeInfo;
1182
+ const pageName = getLogPageName(log, routeInfo);
1156
1183
  if (groups.length === 0 ||
1157
1184
  groups[groups.length - 1].pageName !== pageName) {
1158
1185
  groups.push({ pageName, color: getDomainColor(pageName), logs: [] });
@@ -1405,7 +1432,28 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
1405
1432
  log.type || '',
1406
1433
  log.sourceMethod || '',
1407
1434
  ].join(' ').toLowerCase();
1408
- return queryTokens.every(token => searchTarget.includes(token));
1435
+ return queryTokens.every(token => {
1436
+ if (token.startsWith('level:') || token.startsWith('is:') || token.startsWith('type:')) {
1437
+ const flag = token.replace(/^(level:|is:|type:)/, '').trim();
1438
+ if (flag === 'error' || flag === 'err')
1439
+ return log.type === 'error';
1440
+ if (flag === 'warn' || flag === 'warning')
1441
+ return log.type === 'warn';
1442
+ if (flag === 'info')
1443
+ return log.type === 'info';
1444
+ if (flag === 'log')
1445
+ return log.sourceMethod === 'log';
1446
+ if (flag === 'analytics')
1447
+ return (log.message || '').toLowerCase().includes('[analytics');
1448
+ }
1449
+ if (token === 'error' || token === 'err') {
1450
+ return log.type === 'error' || searchTarget.includes(token);
1451
+ }
1452
+ if (token === 'warn' || token === 'warning') {
1453
+ return log.type === 'warn' || searchTarget.includes(token);
1454
+ }
1455
+ return searchTarget.includes(token);
1456
+ });
1409
1457
  });
1410
1458
  }
1411
1459
  // #7 — apply sort order (newest/oldest first)
@@ -1613,7 +1661,8 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
1613
1661
  setVisible,
1614
1662
  closeModal,
1615
1663
  isReady,
1616
- isEnabled,
1664
+ enabled,
1665
+ isEnabled: enabled,
1617
1666
  appIcon,
1618
1667
  environment,
1619
1668
  modalHeightPercent,
@@ -1790,14 +1839,22 @@ const NetworkInspector = ({ enabled = true, isEnabled = true, storage, navigatio
1790
1839
  </InspectorContext.Provider>);
1791
1840
  };
1792
1841
  const NetworkInspectorWrapper = (props) => {
1793
- // If running in production release build and not explicitly force-enabled (e.g. for QA builds),
1794
- // return null immediately for 0-overhead production stubbing.
1795
- if (typeof __DEV__ !== 'undefined' && !__DEV__ && !props?.forceEnable) {
1842
+ const enabled = props?.enabled ?? true;
1843
+ useEffect(() => {
1844
+ if (!enabled) {
1845
+ hideNativeFloatingButton().catch(() => { });
1846
+ }
1847
+ return () => {
1848
+ hideNativeFloatingButton().catch(() => { });
1849
+ };
1850
+ }, [enabled]);
1851
+ // If enabled is false, return null immediately with 0 overhead
1852
+ if (!enabled) {
1796
1853
  return null;
1797
1854
  }
1798
1855
  return (<I18nextProvider i18n={i18n}>
1799
1856
  <ErrorBoundary fallbackType="inline">
1800
- <NetworkInspector {...props}/>
1857
+ <NetworkInspector {...props} enabled={enabled}/>
1801
1858
  </ErrorBoundary>
1802
1859
  </I18nextProvider>);
1803
1860
  };
@@ -1824,3 +1881,6 @@ export { setMaxPerformanceEventsLimit, getMaxPerformanceEventsLimit, prunePerfor
1824
1881
  export { BrandSquareIcon, BrandCircleIcon, } from './components/NetworkIcons';
1825
1882
  export { connectAsyncStorage, connectMMKV, isAsyncStorageConnected, isMMKVConnected, getRegisteredMMKVInstanceIds, fetchStorageEntries, setStorageEntry, removeStorageEntry, clearStorageDriver, subscribeToStorageChanges, } from './customHooks/storageInspector';
1826
1883
  export { ActiveTab, Method, StatusFilter, SortOrder, LocalFilter, ModalAnimationType, SettingsPage, SettingsSubTab, LogFilter, ConsoleLogType, AnalyticsEventSource, GAEventCategory, StackFrameType, DiffResultType, BundleSubTab, PerformanceSubTab, CrashType, CrashExportFormat, CrashDetailSubTab, CrashFilterType, BreadcrumbType, } from './types';
1884
+ export { AppFonts, setAppFonts, } from './styles/AppFonts';
1885
+ export { AppColors, setAppColors, getThemeColors, updateAppColorsTheme, } from './styles/AppColors';
1886
+ export { t, i18n, useTranslation, setLanguage, addTranslations, setTranslations, I18nextProvider, } from './i18n';
@@ -344,4 +344,8 @@ export declare const getThemeColors: (isDark: boolean) => {
344
344
  };
345
345
  export declare const AppColors: typeof LightColors;
346
346
  export declare const updateAppColorsTheme: (isDark: boolean) => void;
347
+ /**
348
+ * Configure or override specific color tokens used throughout the inspector.
349
+ */
350
+ export declare const setAppColors: (customColors: Partial<typeof LightColors>) => void;
347
351
  export default AppColors;
@@ -384,4 +384,13 @@ Object.assign(AppColors, LightColors);
384
384
  export const updateAppColorsTheme = (isDark) => {
385
385
  Object.assign(AppColors, getThemeColors(isDark));
386
386
  };
387
+ /**
388
+ * Configure or override specific color tokens used throughout the inspector.
389
+ */
390
+ export const setAppColors = (customColors) => {
391
+ if (!customColors || typeof customColors !== 'object')
392
+ return;
393
+ Object.assign(AppColors, customColors);
394
+ Object.assign(LightColors, customColors);
395
+ };
387
396
  export default AppColors;
@@ -1,7 +1,18 @@
1
+ export interface AppFontConfig {
2
+ interRegular?: string;
3
+ interMedium?: string;
4
+ interBold?: string;
5
+ Sfprotext?: string;
6
+ }
1
7
  export declare const AppFonts: {
2
8
  interRegular: string;
3
9
  interMedium: string;
4
10
  interBold: string;
5
11
  Sfprotext: string;
6
12
  };
13
+ /**
14
+ * Configure or override font families used across all inspector screens.
15
+ * Useful when integrating into apps with custom font setups or system fonts.
16
+ */
17
+ export declare const setAppFonts: (customFonts: Partial<typeof AppFonts>) => void;
7
18
  export default AppFonts;
@@ -4,4 +4,13 @@ export const AppFonts = {
4
4
  interBold: 'Inter-Bold',
5
5
  Sfprotext: 'Inter-Regular',
6
6
  };
7
+ /**
8
+ * Configure or override font families used across all inspector screens.
9
+ * Useful when integrating into apps with custom font setups or system fonts.
10
+ */
11
+ export const setAppFonts = (customFonts) => {
12
+ if (!customFonts || typeof customFonts !== 'object')
13
+ return;
14
+ Object.assign(AppFonts, customFonts);
15
+ };
7
16
  export default AppFonts;
@@ -106,6 +106,7 @@ export interface NetworkLog {
106
106
  /** Client identifier: axios, fetch, xhr, apollo, etc. */
107
107
  client?: 'axios' | 'fetch' | 'xhr' | 'apollo' | 'graphql' | string;
108
108
  caller?: string;
109
+ routeInfo?: RouteInfo;
109
110
  }
110
111
  export interface RouteInfo {
111
112
  path: string;
@@ -156,8 +157,6 @@ export interface PersistedSettings {
156
157
  }
157
158
  export interface NetworkInspectorProps {
158
159
  enabled?: boolean;
159
- isEnabled?: boolean;
160
- forceEnable?: boolean;
161
160
  storage?: InspectorStorage;
162
161
  navigationRef?: any;
163
162
  appIcon?: any;
@@ -173,6 +172,7 @@ export interface InspectorContextValue {
173
172
  setVisible: React.Dispatch<React.SetStateAction<boolean>>;
174
173
  closeModal: () => void;
175
174
  isReady: boolean;
175
+ enabled: boolean;
176
176
  isEnabled: boolean;
177
177
  appIcon?: any;
178
178
  environment?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-inapp-inspector",
3
- "version": "2.2.9",
3
+ "version": "2.3.1",
4
4
  "description": "The zero-config, all-in-one in-app debugger for React Native & Expo. Inspect Network (fetch/axios), Console logs, Stack Traces, Redux State, Firebase Analytics, and JS Bundle size directly on device.",
5
5
  "repository": {
6
6
  "type": "git",