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.
- package/dist/commonjs/components/AppHeaderLogo.js +45 -12
- package/dist/commonjs/components/BrandSquareIcon.js +92 -49
- package/dist/commonjs/components/EmptyState.d.ts +7 -2
- package/dist/commonjs/components/EmptyState.js +11 -5
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +29 -18
- package/dist/commonjs/components/Inspector/ConsoleTab.js +6 -1
- package/dist/commonjs/components/Inspector/CrashDetail.js +43 -9
- package/dist/commonjs/components/Inspector/CrashTab.js +34 -3
- package/dist/commonjs/components/Inspector/DeviceInfoTab.js +80 -16
- package/dist/commonjs/components/Inspector/InspectorHeader.js +16 -3
- package/dist/commonjs/components/Inspector/MainScreen.js +7 -11
- package/dist/commonjs/components/Inspector/NetworkDetail.js +3 -2
- package/dist/commonjs/components/Inspector/NetworkTab.js +103 -4
- package/dist/commonjs/components/Inspector/ReduxTab.js +19 -3
- package/dist/commonjs/components/Inspector/SettingsPanel.js +4 -4
- package/dist/commonjs/components/Inspector/StorageTab.js +123 -92
- package/dist/commonjs/components/JsonViewer.js +2 -0
- package/dist/commonjs/components/MetaAccordion.js +15 -3
- package/dist/commonjs/components/SkeletonPlaceholder.d.ts +6 -0
- package/dist/commonjs/components/SkeletonPlaceholder.js +208 -0
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/networkLogger.d.ts +3 -0
- package/dist/commonjs/customHooks/networkLogger.js +10 -1
- package/dist/commonjs/customHooks/storageInspector.d.ts +2 -2
- package/dist/commonjs/customHooks/storageInspector.js +17 -13
- package/dist/commonjs/helpers/index.d.ts +6 -0
- package/dist/commonjs/helpers/index.js +196 -6
- package/dist/commonjs/helpers/searchQueryParser.js +62 -20
- package/dist/commonjs/i18n/index.d.ts +13 -0
- package/dist/commonjs/i18n/index.js +35 -2
- package/dist/commonjs/index.d.ts +3 -0
- package/dist/commonjs/index.js +108 -35
- package/dist/commonjs/styles/AppColors.d.ts +4 -0
- package/dist/commonjs/styles/AppColors.js +11 -1
- package/dist/commonjs/styles/AppFonts.d.ts +11 -0
- package/dist/commonjs/styles/AppFonts.js +11 -1
- package/dist/commonjs/types/interfaces.d.ts +2 -2
- package/dist/esm/components/AppHeaderLogo.js +45 -12
- package/dist/esm/components/BrandSquareIcon.js +92 -49
- package/dist/esm/components/EmptyState.d.ts +7 -2
- package/dist/esm/components/EmptyState.js +11 -5
- package/dist/esm/components/Inspector/AnalyticsTab.js +30 -19
- package/dist/esm/components/Inspector/ConsoleTab.js +6 -1
- package/dist/esm/components/Inspector/CrashDetail.js +43 -9
- package/dist/esm/components/Inspector/CrashTab.js +34 -3
- package/dist/esm/components/Inspector/DeviceInfoTab.js +80 -16
- package/dist/esm/components/Inspector/InspectorHeader.js +17 -4
- package/dist/esm/components/Inspector/MainScreen.js +8 -12
- package/dist/esm/components/Inspector/NetworkDetail.js +3 -2
- package/dist/esm/components/Inspector/NetworkTab.js +103 -4
- package/dist/esm/components/Inspector/ReduxTab.js +19 -3
- package/dist/esm/components/Inspector/SettingsPanel.js +4 -4
- package/dist/esm/components/Inspector/StorageTab.js +124 -93
- package/dist/esm/components/JsonViewer.js +2 -0
- package/dist/esm/components/MetaAccordion.js +15 -3
- package/dist/esm/components/SkeletonPlaceholder.d.ts +6 -0
- package/dist/esm/components/SkeletonPlaceholder.js +173 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/networkLogger.d.ts +3 -0
- package/dist/esm/customHooks/networkLogger.js +8 -0
- package/dist/esm/customHooks/storageInspector.d.ts +2 -2
- package/dist/esm/customHooks/storageInspector.js +17 -13
- package/dist/esm/helpers/index.d.ts +6 -0
- package/dist/esm/helpers/index.js +193 -5
- package/dist/esm/helpers/searchQueryParser.js +62 -20
- package/dist/esm/i18n/index.d.ts +13 -0
- package/dist/esm/i18n/index.js +33 -3
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +97 -37
- package/dist/esm/styles/AppColors.d.ts +4 -0
- package/dist/esm/styles/AppColors.js +9 -0
- package/dist/esm/styles/AppFonts.d.ts +11 -0
- package/dist/esm/styles/AppFonts.js +9 -0
- package/dist/esm/types/interfaces.d.ts +2 -2
- package/package.json +1 -1
- package/src/components/AppHeaderLogo.tsx +46 -12
- package/src/components/BrandSquareIcon.tsx +127 -78
- package/src/components/EmptyState.tsx +27 -5
- package/src/components/Inspector/AnalyticsTab.tsx +48 -27
- package/src/components/Inspector/ConsoleTab.tsx +10 -0
- package/src/components/Inspector/CrashDetail.tsx +65 -9
- package/src/components/Inspector/CrashTab.tsx +41 -3
- package/src/components/Inspector/DeviceInfoTab.tsx +87 -16
- package/src/components/Inspector/InspectorHeader.tsx +24 -4
- package/src/components/Inspector/MainScreen.tsx +7 -11
- package/src/components/Inspector/NetworkDetail.tsx +4 -4
- package/src/components/Inspector/NetworkTab.tsx +129 -4
- package/src/components/Inspector/ReduxTab.tsx +26 -8
- package/src/components/Inspector/SettingsPanel.tsx +4 -4
- package/src/components/Inspector/StorageTab.tsx +191 -117
- package/src/components/JsonViewer.tsx +2 -0
- package/src/components/MetaAccordion.tsx +18 -3
- package/src/components/SkeletonPlaceholder.tsx +206 -0
- package/src/constants/version.ts +1 -1
- package/src/customHooks/networkLogger.ts +15 -0
- package/src/customHooks/storageInspector.ts +18 -14
- package/src/helpers/index.ts +213 -5
- package/src/helpers/searchQueryParser.ts +63 -20
- package/src/i18n/index.ts +38 -3
- package/src/index.tsx +124 -37
- package/src/styles/AppColors.ts +9 -0
- package/src/styles/AppFonts.ts +16 -0
- 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
|
-
|
|
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
|
-
:
|
|
19
|
-
|
|
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
|
-
:
|
|
28
|
+
: log.request != null
|
|
29
|
+
? JSON.stringify(log.request)
|
|
30
|
+
: '';
|
|
25
31
|
const resRaw = typeof log.response === 'string'
|
|
26
32
|
? log.response
|
|
27
|
-
:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
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
|
|
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 ||
|
|
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:') ||
|
|
238
|
-
|
|
239
|
-
|
|
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
|
}
|
package/dist/esm/i18n/index.d.ts
CHANGED
|
@@ -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
|
/**
|
package/dist/esm/i18n/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
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
|
|
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:
|
|
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()
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -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,
|
|
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,
|
|
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(
|
|
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:
|
|
187
|
-
storage:
|
|
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:
|
|
243
|
-
storage:
|
|
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: '
|
|
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
|
-
|
|
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 || !
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =>
|
|
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
|
-
|
|
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
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
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.
|
|
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",
|