react-native-inapp-inspector 2.2.8 → 2.3.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.
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +22 -7
- 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/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 +19 -3
- package/dist/commonjs/components/JsonViewer.js +2 -0
- package/dist/commonjs/components/MetaAccordion.js +15 -3
- 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/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 +80 -11
- package/dist/commonjs/native/NativeInspector.js +13 -0
- package/dist/commonjs/native/NativeNetworkInspector.d.ts +1 -1
- 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 +1 -0
- 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/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 +19 -3
- package/dist/esm/components/JsonViewer.js +2 -0
- package/dist/esm/components/MetaAccordion.js +15 -3
- 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/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 +68 -12
- package/dist/esm/native/NativeInspector.js +13 -0
- package/dist/esm/native/NativeNetworkInspector.d.ts +1 -1
- 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 +1 -0
- package/ios/NetworkInspectorModule.mm +11 -1
- 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/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 +21 -3
- package/src/components/JsonViewer.tsx +2 -0
- package/src/components/MetaAccordion.tsx +18 -3
- package/src/constants/version.ts +1 -1
- package/src/customHooks/networkLogger.ts +15 -0
- 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 +89 -11
- package/src/native/NativeInspector.ts +13 -0
- package/src/native/NativeNetworkInspector.ts +1 -1
- package/src/styles/AppColors.ts +9 -0
- package/src/styles/AppFonts.ts +16 -0
- package/src/types/interfaces.ts +1 -0
package/src/helpers/index.ts
CHANGED
|
@@ -198,16 +198,37 @@ export const getNavigationInfo = (
|
|
|
198
198
|
state: any,
|
|
199
199
|
path: string[] = [],
|
|
200
200
|
): RouteInfo => {
|
|
201
|
-
if (!state
|
|
201
|
+
if (!state) {
|
|
202
202
|
return {
|
|
203
|
-
path: path.length > 0 ? path.join(' ➔ ') : '
|
|
203
|
+
path: path.length > 0 ? path.join(' ➔ ') : '',
|
|
204
204
|
params: null,
|
|
205
205
|
};
|
|
206
206
|
}
|
|
207
|
-
|
|
207
|
+
if (state.name && !state.routes) {
|
|
208
|
+
const fullPath =
|
|
209
|
+
path.length > 0 ? [...path, state.name].join(' ➔ ') : state.name;
|
|
210
|
+
return {path: fullPath, params: state.params || null};
|
|
211
|
+
}
|
|
212
|
+
if (
|
|
213
|
+
!state.routes ||
|
|
214
|
+
!Array.isArray(state.routes) ||
|
|
215
|
+
state.routes.length === 0
|
|
216
|
+
) {
|
|
217
|
+
return {
|
|
218
|
+
path: path.length > 0 ? path.join(' ➔ ') : '',
|
|
219
|
+
params: null,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const index =
|
|
223
|
+
typeof state.index === 'number' &&
|
|
224
|
+
state.index >= 0 &&
|
|
225
|
+
state.index < state.routes.length
|
|
226
|
+
? state.index
|
|
227
|
+
: 0;
|
|
228
|
+
const route = state.routes[index];
|
|
208
229
|
if (!route) {
|
|
209
230
|
return {
|
|
210
|
-
path: path.length > 0 ? path.join(' ➔ ') : '
|
|
231
|
+
path: path.length > 0 ? path.join(' ➔ ') : '',
|
|
211
232
|
params: null,
|
|
212
233
|
};
|
|
213
234
|
}
|
|
@@ -217,10 +238,96 @@ export const getNavigationInfo = (
|
|
|
217
238
|
return getNavigationInfo(route.state, currentPath);
|
|
218
239
|
}
|
|
219
240
|
const resolved =
|
|
220
|
-
currentPath.length > 0 ? currentPath.join(' ➔ ') : '
|
|
241
|
+
currentPath.length > 0 ? currentPath.join(' ➔ ') : route.name || '';
|
|
221
242
|
return {path: resolved, params: route.params || null};
|
|
222
243
|
};
|
|
223
244
|
|
|
245
|
+
export const getLogPageName = (
|
|
246
|
+
log: NetworkLog,
|
|
247
|
+
routeInfo?: RouteInfo | null,
|
|
248
|
+
): string => {
|
|
249
|
+
// 1. If routeInfo has a valid path, resolve the leaf screen name
|
|
250
|
+
const effectiveRoute = routeInfo || (log as any)?.routeInfo;
|
|
251
|
+
if (
|
|
252
|
+
effectiveRoute &&
|
|
253
|
+
effectiveRoute.path &&
|
|
254
|
+
effectiveRoute.path !== 'Navigators'
|
|
255
|
+
) {
|
|
256
|
+
const parts = effectiveRoute.path
|
|
257
|
+
.split(' ➔ ')
|
|
258
|
+
.map((s: string) => s.trim())
|
|
259
|
+
.filter(Boolean);
|
|
260
|
+
if (parts.length > 0) {
|
|
261
|
+
return parts[parts.length - 1]; // Leaf screen name, e.g. "HomeScreen", "ProfileScreen"
|
|
262
|
+
}
|
|
263
|
+
return effectiveRoute.path;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// 2. Extract screen / component name from log.caller stack trace
|
|
267
|
+
if (log.caller && log.caller !== 'Unknown') {
|
|
268
|
+
try {
|
|
269
|
+
const match = log.caller.match(/([^/\\]+)\.(tsx|jsx|ts|js)/i);
|
|
270
|
+
if (match && match[1]) {
|
|
271
|
+
const file = match[1];
|
|
272
|
+
const ignored = [
|
|
273
|
+
'networklogger',
|
|
274
|
+
'fetch',
|
|
275
|
+
'axios',
|
|
276
|
+
'apiclient',
|
|
277
|
+
'request',
|
|
278
|
+
'http',
|
|
279
|
+
'index',
|
|
280
|
+
'nativeinspector',
|
|
281
|
+
'inappinspector',
|
|
282
|
+
'bundleanalyzer',
|
|
283
|
+
];
|
|
284
|
+
if (!ignored.includes(file.toLowerCase())) {
|
|
285
|
+
return file;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
} catch (e) {}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// 3. Fallback to API resource / endpoint category from URL
|
|
292
|
+
if (log.url) {
|
|
293
|
+
try {
|
|
294
|
+
const cleanUrl = log.url.split('?')[0].split('#')[0];
|
|
295
|
+
const withoutProto = cleanUrl.replace(/^https?:\/\//i, '');
|
|
296
|
+
const slashIdx = withoutProto.indexOf('/');
|
|
297
|
+
if (slashIdx !== -1) {
|
|
298
|
+
const pathSegments = withoutProto
|
|
299
|
+
.substring(slashIdx + 1)
|
|
300
|
+
.split('/')
|
|
301
|
+
.filter(Boolean);
|
|
302
|
+
const ignoredSegments = [
|
|
303
|
+
'api',
|
|
304
|
+
'v1',
|
|
305
|
+
'v2',
|
|
306
|
+
'v3',
|
|
307
|
+
'v4',
|
|
308
|
+
'rest',
|
|
309
|
+
'graphql',
|
|
310
|
+
'json',
|
|
311
|
+
'data',
|
|
312
|
+
'service',
|
|
313
|
+
'app',
|
|
314
|
+
];
|
|
315
|
+
const meaningful = pathSegments.filter(
|
|
316
|
+
s => !ignoredSegments.includes(s.toLowerCase()),
|
|
317
|
+
);
|
|
318
|
+
if (meaningful.length > 0) {
|
|
319
|
+
const seg = meaningful[0];
|
|
320
|
+
return seg.charAt(0).toUpperCase() + seg.slice(1);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const host = withoutProto.split('/')[0];
|
|
324
|
+
if (host) return host;
|
|
325
|
+
} catch (e) {}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return 'General';
|
|
329
|
+
};
|
|
330
|
+
|
|
224
331
|
export const flattenObject = (obj: any, prefix = ''): Record<string, any> => {
|
|
225
332
|
let result: Record<string, any> = {};
|
|
226
333
|
if (typeof obj === 'object' && obj !== null) {
|
|
@@ -409,6 +516,107 @@ export const getAppName = (): string => {
|
|
|
409
516
|
return 'App';
|
|
410
517
|
};
|
|
411
518
|
|
|
519
|
+
export const getAppVersionAndBuild = (): {
|
|
520
|
+
version: string;
|
|
521
|
+
build: string;
|
|
522
|
+
formatted: string;
|
|
523
|
+
} => {
|
|
524
|
+
let version = '';
|
|
525
|
+
let build = '';
|
|
526
|
+
|
|
527
|
+
// 1. Try ExpoApplication / ExponentConstants
|
|
528
|
+
const ExpoApplication = NativeModules.ExpoApplication;
|
|
529
|
+
if (ExpoApplication) {
|
|
530
|
+
if (typeof ExpoApplication.nativeAppVersion === 'string') {
|
|
531
|
+
version = ExpoApplication.nativeAppVersion;
|
|
532
|
+
}
|
|
533
|
+
if (typeof ExpoApplication.nativeBuildVersion === 'string') {
|
|
534
|
+
build = ExpoApplication.nativeBuildVersion;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const ExponentConstants = NativeModules.ExponentConstants;
|
|
539
|
+
if (ExponentConstants) {
|
|
540
|
+
const manifest = ExponentConstants.manifest || ExponentConstants.expoConfig;
|
|
541
|
+
if (manifest) {
|
|
542
|
+
if (!version && manifest.version) {
|
|
543
|
+
version = String(manifest.version);
|
|
544
|
+
}
|
|
545
|
+
if (!build) {
|
|
546
|
+
if (manifest.ios?.buildNumber) {
|
|
547
|
+
build = String(manifest.ios.buildNumber);
|
|
548
|
+
} else if (manifest.android?.versionCode) {
|
|
549
|
+
build = String(manifest.android.versionCode);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// 2. Try react-native-device-info
|
|
556
|
+
const RNDeviceInfo = NativeModules.RNDeviceInfo;
|
|
557
|
+
if (RNDeviceInfo) {
|
|
558
|
+
if (!version) {
|
|
559
|
+
if (typeof RNDeviceInfo.appVersion === 'string') {
|
|
560
|
+
version = RNDeviceInfo.appVersion;
|
|
561
|
+
} else if (typeof RNDeviceInfo.getVersion === 'function') {
|
|
562
|
+
try {
|
|
563
|
+
version = RNDeviceInfo.getVersion();
|
|
564
|
+
} catch (e) {}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (!build) {
|
|
568
|
+
if (typeof RNDeviceInfo.buildNumber === 'string') {
|
|
569
|
+
build = RNDeviceInfo.buildNumber;
|
|
570
|
+
} else if (typeof RNDeviceInfo.getBuildNumber === 'function') {
|
|
571
|
+
try {
|
|
572
|
+
build = RNDeviceInfo.getBuildNumber();
|
|
573
|
+
} catch (e) {}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// 3. Try PlatformConstants / Platform.constants
|
|
579
|
+
const constants =
|
|
580
|
+
(Platform.constants as any) || NativeModules.PlatformConstants;
|
|
581
|
+
if (constants) {
|
|
582
|
+
if (
|
|
583
|
+
!version &&
|
|
584
|
+
constants.Version &&
|
|
585
|
+
typeof constants.Version === 'string' &&
|
|
586
|
+
constants.Version.includes('.')
|
|
587
|
+
) {
|
|
588
|
+
version = constants.Version;
|
|
589
|
+
}
|
|
590
|
+
if (!version && constants.reactNativeVersion) {
|
|
591
|
+
const rnv = constants.reactNativeVersion;
|
|
592
|
+
if (rnv.major !== undefined) {
|
|
593
|
+
version = `${rnv.major}.${rnv.minor}.${rnv.patch}`;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// 4. Try Android AppInfo
|
|
599
|
+
const AppInfo = NativeModules.AppInfo;
|
|
600
|
+
if (AppInfo) {
|
|
601
|
+
if (!version && typeof AppInfo.versionName === 'string') {
|
|
602
|
+
version = AppInfo.versionName;
|
|
603
|
+
}
|
|
604
|
+
if (!build && typeof AppInfo.versionCode === 'string') {
|
|
605
|
+
build = AppInfo.versionCode;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Fallbacks
|
|
610
|
+
if (!version) version = '1.0.0';
|
|
611
|
+
if (!build) build = '1';
|
|
612
|
+
|
|
613
|
+
return {
|
|
614
|
+
version,
|
|
615
|
+
build,
|
|
616
|
+
formatted: `${version} (${build})`,
|
|
617
|
+
};
|
|
618
|
+
};
|
|
619
|
+
|
|
412
620
|
export const handleOpenExternalLink = (url: string): void => {
|
|
413
621
|
if (!url) return;
|
|
414
622
|
const openUrl = formatDisplayUrl(url);
|
|
@@ -18,8 +18,9 @@ export function matchNetworkLogQuery(
|
|
|
18
18
|
): boolean {
|
|
19
19
|
if (!searchQuery || searchQuery.trim().length === 0) return true;
|
|
20
20
|
|
|
21
|
+
// Split tokens by spaces or commas while respecting quotes
|
|
21
22
|
const rawTokens =
|
|
22
|
-
searchQuery.trim().match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) || [];
|
|
23
|
+
searchQuery.trim().match(/(?:[^\s,"']+|"[^"]*"|'[^']*')+/g) || [];
|
|
23
24
|
|
|
24
25
|
if (rawTokens.length === 0) return true;
|
|
25
26
|
|
|
@@ -32,27 +33,38 @@ export function matchNetworkLogQuery(
|
|
|
32
33
|
const statusNum =
|
|
33
34
|
typeof log.status === 'number'
|
|
34
35
|
? log.status
|
|
35
|
-
:
|
|
36
|
-
|
|
36
|
+
: log.status != null
|
|
37
|
+
? parseInt(String(log.status), 10)
|
|
38
|
+
: null;
|
|
39
|
+
const statusStr = log.status != null ? String(log.status) : 'pending';
|
|
37
40
|
const durationNum = log.duration || 0;
|
|
38
41
|
const clientRaw = log.client || '';
|
|
42
|
+
const callerRaw = log.caller || '';
|
|
39
43
|
const reqRaw =
|
|
40
44
|
typeof log.request === 'string'
|
|
41
45
|
? log.request
|
|
42
|
-
:
|
|
46
|
+
: log.request != null
|
|
47
|
+
? JSON.stringify(log.request)
|
|
48
|
+
: '';
|
|
43
49
|
const resRaw =
|
|
44
50
|
typeof log.response === 'string'
|
|
45
51
|
? log.response
|
|
46
|
-
:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
52
|
+
: log.response != null
|
|
53
|
+
? JSON.stringify(log.response)
|
|
54
|
+
: '';
|
|
55
|
+
const reqHeadersRaw = log.requestHeaders
|
|
56
|
+
? JSON.stringify(log.requestHeaders)
|
|
57
|
+
: '';
|
|
58
|
+
const resHeadersRaw = log.responseHeaders
|
|
59
|
+
? JSON.stringify(log.responseHeaders)
|
|
60
|
+
: '';
|
|
61
|
+
const pathRaw = routePath || (log as any)?.routeInfo?.path || '';
|
|
50
62
|
|
|
51
63
|
// Construct search corpus based on active scope
|
|
52
64
|
const getScopedCorpus = (caseSens: boolean): string => {
|
|
53
65
|
let parts: string[] = [];
|
|
54
66
|
if (scope === 'url') {
|
|
55
|
-
parts = [methodRaw, urlRaw, pathRaw];
|
|
67
|
+
parts = [methodRaw, urlRaw, pathRaw, callerRaw];
|
|
56
68
|
} else if (scope === 'reqBody') {
|
|
57
69
|
parts = [reqRaw];
|
|
58
70
|
} else if (scope === 'resBody') {
|
|
@@ -65,6 +77,7 @@ export function matchNetworkLogQuery(
|
|
|
65
77
|
urlRaw,
|
|
66
78
|
statusStr,
|
|
67
79
|
pathRaw,
|
|
80
|
+
callerRaw,
|
|
68
81
|
clientRaw,
|
|
69
82
|
reqRaw,
|
|
70
83
|
resRaw,
|
|
@@ -81,6 +94,7 @@ export function matchNetworkLogQuery(
|
|
|
81
94
|
const methodStr = methodRaw.toLowerCase();
|
|
82
95
|
const urlStr = urlRaw.toLowerCase();
|
|
83
96
|
const clientStr = clientRaw.toLowerCase();
|
|
97
|
+
const callerStr = callerRaw.toLowerCase();
|
|
84
98
|
const reqStr = reqRaw.toLowerCase();
|
|
85
99
|
const resStr = resRaw.toLowerCase();
|
|
86
100
|
const reqHeadersStr = reqHeadersRaw.toLowerCase();
|
|
@@ -107,18 +121,20 @@ export function matchNetworkLogQuery(
|
|
|
107
121
|
// 2. status:<VAL> or s:<VAL>
|
|
108
122
|
if (lowerToken.startsWith('status:') || lowerToken.startsWith('s:')) {
|
|
109
123
|
const val = lowerToken.replace(/^(status:|s:)/, '').trim();
|
|
110
|
-
if (val
|
|
124
|
+
if (val === 'pending' || val === 'loading') {
|
|
125
|
+
if (log.status != null) return false;
|
|
126
|
+
} else if (val.startsWith('>=')) {
|
|
111
127
|
const threshold = parseInt(val.slice(2), 10);
|
|
112
|
-
if (isNaN(threshold) || statusNum < threshold) return false;
|
|
128
|
+
if (isNaN(threshold) || statusNum === null || statusNum < threshold) return false;
|
|
113
129
|
} else if (val.startsWith('>')) {
|
|
114
130
|
const threshold = parseInt(val.slice(1), 10);
|
|
115
|
-
if (isNaN(threshold) || statusNum <= threshold) return false;
|
|
131
|
+
if (isNaN(threshold) || statusNum === null || statusNum <= threshold) return false;
|
|
116
132
|
} else if (val.startsWith('<=')) {
|
|
117
133
|
const threshold = parseInt(val.slice(2), 10);
|
|
118
|
-
if (isNaN(threshold) || statusNum > threshold) return false;
|
|
134
|
+
if (isNaN(threshold) || statusNum === null || statusNum > threshold) return false;
|
|
119
135
|
} else if (val.startsWith('<')) {
|
|
120
136
|
const threshold = parseInt(val.slice(1), 10);
|
|
121
|
-
if (isNaN(threshold) || statusNum >= threshold) return false;
|
|
137
|
+
if (isNaN(threshold) || statusNum === null || statusNum >= threshold) return false;
|
|
122
138
|
} else if (val.endsWith('xx') || val.endsWith('x')) {
|
|
123
139
|
const prefix = val.replace(/x/g, '');
|
|
124
140
|
if (!statusStr.startsWith(prefix)) return false;
|
|
@@ -143,11 +159,13 @@ export function matchNetworkLogQuery(
|
|
|
143
159
|
flag === 'fail'
|
|
144
160
|
) {
|
|
145
161
|
const isErr =
|
|
146
|
-
log.status === 0 ||
|
|
162
|
+
log.status === 0 || (statusNum !== null && statusNum >= 400);
|
|
147
163
|
if (!isErr) return false;
|
|
148
164
|
} else if (flag === 'success' || flag === 'ok' || flag === '2xx') {
|
|
149
|
-
const isSuccess = statusNum >= 200 && statusNum < 300;
|
|
165
|
+
const isSuccess = statusNum !== null && statusNum >= 200 && statusNum < 300;
|
|
150
166
|
if (!isSuccess) return false;
|
|
167
|
+
} else if (flag === 'pending' || flag === 'loading') {
|
|
168
|
+
if (log.status != null) return false;
|
|
151
169
|
} else if (flag === 'slow') {
|
|
152
170
|
if (durationNum < 1000) return false;
|
|
153
171
|
} else if (flag === 'fast') {
|
|
@@ -169,6 +187,11 @@ export function matchNetworkLogQuery(
|
|
|
169
187
|
resHeadersStr.includes('application/json') ||
|
|
170
188
|
urlStr.includes('.json');
|
|
171
189
|
if (!isJson) return false;
|
|
190
|
+
} else if (flag === 'image') {
|
|
191
|
+
const isImg =
|
|
192
|
+
resHeadersStr.includes('image/') ||
|
|
193
|
+
/\.(png|jpe?g|gif|webp|svg)/i.test(urlStr);
|
|
194
|
+
if (!isImg) return false;
|
|
172
195
|
}
|
|
173
196
|
continue;
|
|
174
197
|
}
|
|
@@ -230,10 +253,20 @@ export function matchNetworkLogQuery(
|
|
|
230
253
|
continue;
|
|
231
254
|
}
|
|
232
255
|
|
|
233
|
-
// 7. path:<PATH> or p:<PATH>
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
|
|
256
|
+
// 7. path:<PATH> or p:<PATH> or page:<PAGE>
|
|
257
|
+
if (
|
|
258
|
+
lowerToken.startsWith('path:') ||
|
|
259
|
+
lowerToken.startsWith('p:') ||
|
|
260
|
+
lowerToken.startsWith('page:')
|
|
261
|
+
) {
|
|
262
|
+
const targetPath = lowerToken
|
|
263
|
+
.replace(/^(path:|p:|page:)/, '')
|
|
264
|
+
.trim();
|
|
265
|
+
if (
|
|
266
|
+
!urlStr.includes(targetPath) &&
|
|
267
|
+
!pathStr.includes(targetPath) &&
|
|
268
|
+
!callerStr.includes(targetPath)
|
|
269
|
+
) {
|
|
237
270
|
return false;
|
|
238
271
|
}
|
|
239
272
|
continue;
|
|
@@ -274,6 +307,16 @@ export function matchNetworkLogQuery(
|
|
|
274
307
|
} else {
|
|
275
308
|
const queryTerm = isCaseSensitive ? token : lowerToken;
|
|
276
309
|
if (!targetCorpus.includes(queryTerm)) {
|
|
310
|
+
// Special case: if user typed "error" / "failed", check error status
|
|
311
|
+
if (
|
|
312
|
+
queryTerm === 'error' ||
|
|
313
|
+
queryTerm === 'failed' ||
|
|
314
|
+
queryTerm === 'fail'
|
|
315
|
+
) {
|
|
316
|
+
const isErr =
|
|
317
|
+
log.status === 0 || (statusNum !== null && statusNum >= 400);
|
|
318
|
+
if (isErr) continue;
|
|
319
|
+
}
|
|
277
320
|
return false;
|
|
278
321
|
}
|
|
279
322
|
}
|
package/src/i18n/index.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
2
|
+
import enLocale from './locales/en.json';
|
|
3
3
|
|
|
4
4
|
type TranslationParams = Record<string, any>;
|
|
5
5
|
|
|
6
|
+
const localeRegistry: Record<string, Record<string, any>> = {
|
|
7
|
+
en: enLocale,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
let currentLanguage = 'en';
|
|
11
|
+
|
|
6
12
|
/**
|
|
7
13
|
* Lightweight nested lookup for translation keys (e.g. "network.headers")
|
|
8
14
|
*/
|
|
@@ -31,7 +37,12 @@ function interpolate(template: string, params?: TranslationParams): string {
|
|
|
31
37
|
* Standalone zero-dependency translation function
|
|
32
38
|
*/
|
|
33
39
|
export function t(key: string, optionsOrFallback?: TranslationParams | string): string {
|
|
34
|
-
const
|
|
40
|
+
const activeBundle = localeRegistry[currentLanguage] || localeRegistry.en;
|
|
41
|
+
let raw = lookupKey(activeBundle, key);
|
|
42
|
+
if (raw === undefined && currentLanguage !== 'en') {
|
|
43
|
+
raw = lookupKey(localeRegistry.en, key);
|
|
44
|
+
}
|
|
45
|
+
|
|
35
46
|
if (typeof raw === 'string') {
|
|
36
47
|
if (typeof optionsOrFallback === 'object' && optionsOrFallback !== null) {
|
|
37
48
|
return interpolate(raw, optionsOrFallback);
|
|
@@ -44,9 +55,33 @@ export function t(key: string, optionsOrFallback?: TranslationParams | string):
|
|
|
44
55
|
return key;
|
|
45
56
|
}
|
|
46
57
|
|
|
58
|
+
export function setLanguage(lang: string): void {
|
|
59
|
+
if (typeof lang === 'string' && lang.trim()) {
|
|
60
|
+
currentLanguage = lang.trim();
|
|
61
|
+
i18n.language = currentLanguage;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function addTranslations(lang: string, translations: Record<string, any>): void {
|
|
66
|
+
if (!lang || !translations || typeof translations !== 'object') return;
|
|
67
|
+
localeRegistry[lang] = {
|
|
68
|
+
...(localeRegistry[lang] || {}),
|
|
69
|
+
...translations,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function setTranslations(translations: Record<string, any>, lang: string = 'en'): void {
|
|
74
|
+
addTranslations(lang, translations);
|
|
75
|
+
}
|
|
76
|
+
|
|
47
77
|
export const i18n = {
|
|
48
78
|
t,
|
|
49
|
-
language:
|
|
79
|
+
language: currentLanguage,
|
|
80
|
+
changeLanguage: setLanguage,
|
|
81
|
+
addResourceBundle: (lng: string, _ns: string, resources: any) => addTranslations(lng, resources),
|
|
82
|
+
setLanguage,
|
|
83
|
+
addTranslations,
|
|
84
|
+
setTranslations,
|
|
50
85
|
};
|
|
51
86
|
|
|
52
87
|
/**
|
package/src/index.tsx
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
import {
|
|
27
27
|
formatDisplayUrl,
|
|
28
28
|
getNavigationInfo,
|
|
29
|
+
getLogPageName,
|
|
29
30
|
deduplicateLogs,
|
|
30
31
|
getDomainColor,
|
|
31
32
|
getEventCategory,
|
|
@@ -55,6 +56,7 @@ import {
|
|
|
55
56
|
subscribeNetworkLogs,
|
|
56
57
|
setNetworkModuleEnabled,
|
|
57
58
|
setMaxNetworkLogsLimit,
|
|
59
|
+
setRouteInfoProvider,
|
|
58
60
|
} from './customHooks/networkLogger';
|
|
59
61
|
|
|
60
62
|
// Console
|
|
@@ -357,8 +359,8 @@ const NetworkInspector = ({
|
|
|
357
359
|
bundle: false,
|
|
358
360
|
performance: false,
|
|
359
361
|
crash: false,
|
|
360
|
-
device:
|
|
361
|
-
storage:
|
|
362
|
+
device: false,
|
|
363
|
+
storage: false,
|
|
362
364
|
});
|
|
363
365
|
|
|
364
366
|
const [maxNetworkLogs, setMaxNetworkLogs] = useState<number>(100);
|
|
@@ -419,8 +421,8 @@ const NetworkInspector = ({
|
|
|
419
421
|
bundle: false,
|
|
420
422
|
performance: false,
|
|
421
423
|
crash: false,
|
|
422
|
-
device:
|
|
423
|
-
storage:
|
|
424
|
+
device: false,
|
|
425
|
+
storage: false,
|
|
424
426
|
});
|
|
425
427
|
setDefaultTab('apis');
|
|
426
428
|
setIsAutoRamLimitEnabled(true);
|
|
@@ -490,6 +492,8 @@ const NetworkInspector = ({
|
|
|
490
492
|
bundle: false,
|
|
491
493
|
performance: false,
|
|
492
494
|
crash: false,
|
|
495
|
+
device: false,
|
|
496
|
+
storage: false,
|
|
493
497
|
},
|
|
494
498
|
...(saved.tabVisibility || {}),
|
|
495
499
|
apis: true,
|
|
@@ -708,12 +712,23 @@ const NetworkInspector = ({
|
|
|
708
712
|
const hasNavigationContext = navigationContext !== undefined;
|
|
709
713
|
|
|
710
714
|
const currentRouteRef = useRef<RouteInfo>({
|
|
711
|
-
path: '
|
|
715
|
+
path: '',
|
|
712
716
|
params: null,
|
|
713
717
|
});
|
|
718
|
+
|
|
719
|
+
useEffect(() => {
|
|
720
|
+
setRouteInfoProvider(() => currentRouteRef.current);
|
|
721
|
+
return () => {
|
|
722
|
+
setRouteInfoProvider(null);
|
|
723
|
+
};
|
|
724
|
+
}, []);
|
|
725
|
+
|
|
714
726
|
useEffect(() => {
|
|
715
727
|
if (navState) {
|
|
716
|
-
|
|
728
|
+
const info = getNavigationInfo(navState);
|
|
729
|
+
if (info?.path) {
|
|
730
|
+
currentRouteRef.current = info;
|
|
731
|
+
}
|
|
717
732
|
}
|
|
718
733
|
}, [navState]);
|
|
719
734
|
|
|
@@ -723,9 +738,22 @@ const NetworkInspector = ({
|
|
|
723
738
|
const updateState = () => {
|
|
724
739
|
try {
|
|
725
740
|
if (typeof navigationRef.isReady === 'function' && navigationRef.isReady()) {
|
|
741
|
+
const currentRoute = typeof navigationRef.getCurrentRoute === 'function'
|
|
742
|
+
? navigationRef.getCurrentRoute()
|
|
743
|
+
: null;
|
|
744
|
+
if (currentRoute?.name) {
|
|
745
|
+
currentRouteRef.current = {
|
|
746
|
+
path: currentRoute.name,
|
|
747
|
+
params: currentRoute.params || null,
|
|
748
|
+
};
|
|
749
|
+
}
|
|
726
750
|
const state = navigationRef.getRootState();
|
|
727
751
|
if (state) {
|
|
728
752
|
setNavState(state);
|
|
753
|
+
const routeInfo = getNavigationInfo(state);
|
|
754
|
+
if (routeInfo?.path) {
|
|
755
|
+
currentRouteRef.current = routeInfo;
|
|
756
|
+
}
|
|
729
757
|
}
|
|
730
758
|
}
|
|
731
759
|
} catch (err) {
|
|
@@ -1077,7 +1105,10 @@ const NetworkInspector = ({
|
|
|
1077
1105
|
if (freshIds.size > 0) {
|
|
1078
1106
|
freshIds.forEach(id => {
|
|
1079
1107
|
if (!logRouteMapRef.current.has(id)) {
|
|
1080
|
-
|
|
1108
|
+
const matchedLog = deduped.find(l => l.id === id);
|
|
1109
|
+
const resolvedRoute =
|
|
1110
|
+
(matchedLog as any)?.routeInfo || currentRouteRef.current;
|
|
1111
|
+
logRouteMapRef.current.set(id, resolvedRoute);
|
|
1081
1112
|
}
|
|
1082
1113
|
});
|
|
1083
1114
|
setNewLogIds(freshIds);
|
|
@@ -1091,6 +1122,13 @@ const NetworkInspector = ({
|
|
|
1091
1122
|
const deduped = deduplicateLogs(raw);
|
|
1092
1123
|
const incoming = new Set(deduped.map(l => l.id));
|
|
1093
1124
|
prevLogIdsRef.current = incoming;
|
|
1125
|
+
deduped.forEach(l => {
|
|
1126
|
+
if (!logRouteMapRef.current.has(l.id)) {
|
|
1127
|
+
const resolvedRoute =
|
|
1128
|
+
(l as any)?.routeInfo || currentRouteRef.current;
|
|
1129
|
+
logRouteMapRef.current.set(l.id, resolvedRoute);
|
|
1130
|
+
}
|
|
1131
|
+
});
|
|
1094
1132
|
setLogs(deduped);
|
|
1095
1133
|
} else {
|
|
1096
1134
|
timeoutId = setTimeout(updateNetworkState, 250);
|
|
@@ -1378,8 +1416,9 @@ const NetworkInspector = ({
|
|
|
1378
1416
|
|
|
1379
1417
|
for (let i = 0; i < filteredLogs.length; i++) {
|
|
1380
1418
|
const log = filteredLogs[i];
|
|
1381
|
-
const routeInfo =
|
|
1382
|
-
|
|
1419
|
+
const routeInfo =
|
|
1420
|
+
logRouteMapRef.current.get(log.id) || (log as any)?.routeInfo;
|
|
1421
|
+
const pageName = getLogPageName(log, routeInfo);
|
|
1383
1422
|
|
|
1384
1423
|
if (
|
|
1385
1424
|
groups.length === 0 ||
|
|
@@ -1680,7 +1719,23 @@ const NetworkInspector = ({
|
|
|
1680
1719
|
log.sourceMethod || '',
|
|
1681
1720
|
].join(' ').toLowerCase();
|
|
1682
1721
|
|
|
1683
|
-
return queryTokens.every(token =>
|
|
1722
|
+
return queryTokens.every(token => {
|
|
1723
|
+
if (token.startsWith('level:') || token.startsWith('is:') || token.startsWith('type:')) {
|
|
1724
|
+
const flag = token.replace(/^(level:|is:|type:)/, '').trim();
|
|
1725
|
+
if (flag === 'error' || flag === 'err') return log.type === 'error';
|
|
1726
|
+
if (flag === 'warn' || flag === 'warning') return log.type === 'warn';
|
|
1727
|
+
if (flag === 'info') return log.type === 'info';
|
|
1728
|
+
if (flag === 'log') return log.sourceMethod === 'log';
|
|
1729
|
+
if (flag === 'analytics') return (log.message || '').toLowerCase().includes('[analytics');
|
|
1730
|
+
}
|
|
1731
|
+
if (token === 'error' || token === 'err') {
|
|
1732
|
+
return log.type === 'error' || searchTarget.includes(token);
|
|
1733
|
+
}
|
|
1734
|
+
if (token === 'warn' || token === 'warning') {
|
|
1735
|
+
return log.type === 'warn' || searchTarget.includes(token);
|
|
1736
|
+
}
|
|
1737
|
+
return searchTarget.includes(token);
|
|
1738
|
+
});
|
|
1684
1739
|
});
|
|
1685
1740
|
}
|
|
1686
1741
|
|
|
@@ -2331,4 +2386,27 @@ export {
|
|
|
2331
2386
|
CrashDetailSubTab,
|
|
2332
2387
|
CrashFilterType,
|
|
2333
2388
|
BreadcrumbType,
|
|
2334
|
-
} from './types';
|
|
2389
|
+
} from './types';
|
|
2390
|
+
|
|
2391
|
+
export {
|
|
2392
|
+
AppFonts,
|
|
2393
|
+
setAppFonts,
|
|
2394
|
+
type AppFontConfig,
|
|
2395
|
+
} from './styles/AppFonts';
|
|
2396
|
+
|
|
2397
|
+
export {
|
|
2398
|
+
AppColors,
|
|
2399
|
+
setAppColors,
|
|
2400
|
+
getThemeColors,
|
|
2401
|
+
updateAppColorsTheme,
|
|
2402
|
+
} from './styles/AppColors';
|
|
2403
|
+
|
|
2404
|
+
export {
|
|
2405
|
+
t,
|
|
2406
|
+
i18n,
|
|
2407
|
+
useTranslation,
|
|
2408
|
+
setLanguage,
|
|
2409
|
+
addTranslations,
|
|
2410
|
+
setTranslations,
|
|
2411
|
+
I18nextProvider,
|
|
2412
|
+
} from './i18n';
|
|
@@ -207,6 +207,19 @@ export const subscribeNativeFloatingButtonPress = (
|
|
|
207
207
|
} catch (e) {}
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
// Active Bridgeless / TurboModule tap detection
|
|
211
|
+
const interval = setInterval(async () => {
|
|
212
|
+
if (NativeModule && NativeModule.checkFloatingButtonPress) {
|
|
213
|
+
try {
|
|
214
|
+
const pressed = await NativeModule.checkFloatingButtonPress();
|
|
215
|
+
if (pressed) {
|
|
216
|
+
callback();
|
|
217
|
+
}
|
|
218
|
+
} catch (e) {}
|
|
219
|
+
}
|
|
220
|
+
}, 180);
|
|
221
|
+
cleanups.push(() => clearInterval(interval));
|
|
222
|
+
|
|
210
223
|
return () => {
|
|
211
224
|
cleanups.forEach(fn => {
|
|
212
225
|
try {
|
|
@@ -16,7 +16,7 @@ export interface Spec extends TurboModule {
|
|
|
16
16
|
triggerHaptic(style: string): Promise<boolean>;
|
|
17
17
|
getNativeSystemMetrics(): Promise<Object>;
|
|
18
18
|
pushNativeLogRecord(pageKey: string, jsonPayload: string): Promise<boolean>;
|
|
19
|
-
|
|
19
|
+
checkFloatingButtonPress(): Promise<boolean>;
|
|
20
20
|
addListener(eventName: string): void;
|
|
21
21
|
removeListeners(count: number): void;
|
|
22
22
|
}
|