react-native-inapp-inspector 1.1.26 → 1.1.28
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/build.gradle +1 -0
- package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +34 -0
- package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
- package/dist/commonjs/components/ErrorBoundary.js +530 -100
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +176 -126
- package/dist/commonjs/components/Inspector/BundleTab.d.ts +1 -0
- package/dist/commonjs/components/Inspector/BundleTab.js +145 -21
- package/dist/commonjs/components/Inspector/CrashTab.js +0 -8
- package/dist/commonjs/components/Inspector/NetworkDetail.js +41 -0
- package/dist/commonjs/components/Inspector/PerformanceTab.d.ts +5 -0
- package/dist/commonjs/components/Inspector/PerformanceTab.js +588 -155
- package/dist/commonjs/components/Inspector/SettingsPanel.js +57 -22
- package/dist/commonjs/components/Inspector/TabBar.js +13 -1
- package/dist/commonjs/components/LogCard.js +75 -34
- package/dist/commonjs/components/NetworkIcons.d.ts +112 -102
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/analyticsLogger.d.ts +1 -11
- package/dist/commonjs/customHooks/analyticsLogger.js +8 -1
- package/dist/commonjs/customHooks/bundleAnalyzer.js +121 -124
- package/dist/commonjs/customHooks/networkLogger.d.ts +1 -0
- package/dist/commonjs/customHooks/networkLogger.js +16 -0
- package/dist/commonjs/customHooks/performanceTracker.d.ts +74 -0
- package/dist/commonjs/customHooks/performanceTracker.js +546 -392
- package/dist/commonjs/customHooks/reduxLogger.d.ts +1 -0
- package/dist/commonjs/customHooks/reduxLogger.js +3 -1
- package/dist/commonjs/helpers/index.js +27 -3
- package/dist/commonjs/i18n/locales/en.json +225 -4
- package/dist/commonjs/index.d.ts +1 -1
- package/dist/commonjs/index.js +36 -2
- package/dist/commonjs/styles/index.d.ts +3 -1
- package/dist/commonjs/styles/index.js +8 -6
- package/dist/commonjs/types/interfaces.d.ts +3 -0
- package/dist/esm/components/ErrorBoundary.d.ts +1 -1
- package/dist/esm/components/ErrorBoundary.js +498 -101
- package/dist/esm/components/Inspector/AnalyticsTab.js +177 -127
- package/dist/esm/components/Inspector/BundleTab.d.ts +1 -0
- package/dist/esm/components/Inspector/BundleTab.js +145 -23
- package/dist/esm/components/Inspector/CrashTab.js +0 -8
- package/dist/esm/components/Inspector/NetworkDetail.js +41 -0
- package/dist/esm/components/Inspector/PerformanceTab.d.ts +5 -0
- package/dist/esm/components/Inspector/PerformanceTab.js +591 -158
- package/dist/esm/components/Inspector/SettingsPanel.js +57 -22
- package/dist/esm/components/Inspector/TabBar.js +13 -1
- package/dist/esm/components/LogCard.js +75 -34
- package/dist/esm/components/NetworkIcons.d.ts +112 -102
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/analyticsLogger.d.ts +1 -11
- package/dist/esm/customHooks/analyticsLogger.js +6 -0
- package/dist/esm/customHooks/bundleAnalyzer.js +121 -124
- package/dist/esm/customHooks/networkLogger.d.ts +1 -0
- package/dist/esm/customHooks/networkLogger.js +16 -0
- package/dist/esm/customHooks/performanceTracker.d.ts +74 -0
- package/dist/esm/customHooks/performanceTracker.js +531 -391
- package/dist/esm/customHooks/reduxLogger.d.ts +1 -0
- package/dist/esm/customHooks/reduxLogger.js +1 -0
- package/dist/esm/helpers/index.js +27 -3
- package/dist/esm/i18n/locales/en.json +225 -4
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +24 -3
- package/dist/esm/styles/index.d.ts +3 -1
- package/dist/esm/styles/index.js +8 -6
- package/dist/esm/types/interfaces.d.ts +3 -0
- package/ios/NetworkInspectorModule.h +2 -0
- package/ios/NetworkInspectorModule.m +10 -0
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AppColors } from '../styles/AppColors';
|
|
2
|
+
import { t } from '../i18n';
|
|
2
3
|
// ─── Real Host App Bundle Analyzer ──────────────────────────────────────────
|
|
3
4
|
//
|
|
4
5
|
// Dynamically measures and analyzes the real JavaScript bundle and packages
|
|
@@ -248,25 +249,32 @@ const extractBundleModules = (bundleText) => {
|
|
|
248
249
|
const modules = [];
|
|
249
250
|
const seenIds = new Set();
|
|
250
251
|
if (bundleText && bundleText.length > 0) {
|
|
251
|
-
// Primary
|
|
252
|
-
const tailRegex = /\}\s*,\s*(\d+)\s*,\s
|
|
252
|
+
// 1. Primary Metro regex: matches }, <id>, [<deps>] or {<deps>}, "<path>"
|
|
253
|
+
const tailRegex = /\}\s*,\s*(\d+)\s*,\s*(?:\[[\s\S]*?\]|\{[\s\S]*?\})\s*,\s*(?:"([^"\r\n]+)"|'([^'\r\n]+)')/g;
|
|
253
254
|
let match;
|
|
254
255
|
while ((match = tailRegex.exec(bundleText)) !== null) {
|
|
255
256
|
const id = parseInt(match[1], 10);
|
|
256
|
-
const
|
|
257
|
-
const path = match[3] || match[4] || '';
|
|
258
|
-
const deps = depsStr
|
|
259
|
-
? depsStr
|
|
260
|
-
.split(',')
|
|
261
|
-
.map(s => parseInt(s.trim(), 10))
|
|
262
|
-
.filter(n => !isNaN(n))
|
|
263
|
-
: [];
|
|
257
|
+
const path = match[2] || match[3] || '';
|
|
264
258
|
if (!seenIds.has(id) && path.length > 0) {
|
|
265
259
|
seenIds.add(id);
|
|
266
|
-
modules.push({ id, deps, path });
|
|
260
|
+
modules.push({ id, deps: [], path });
|
|
267
261
|
}
|
|
268
262
|
}
|
|
269
|
-
//
|
|
263
|
+
// 2. SourceURL comment extraction (Metro dev server embeds //# sourceURL=... for every module)
|
|
264
|
+
const sourceUrlRegex = /\/\/[#@]\s*sourceURL=(?:https?:\/\/[^/\n\r]+\/|file:\/\/)?([^?\r\n#\s]+)/g;
|
|
265
|
+
let srcMatch;
|
|
266
|
+
let autoId = 900000;
|
|
267
|
+
while ((srcMatch = sourceUrlRegex.exec(bundleText)) !== null) {
|
|
268
|
+
const path = srcMatch[1];
|
|
269
|
+
if (path && path.length > 0 && !path.endsWith('.bundle')) {
|
|
270
|
+
const id = autoId++;
|
|
271
|
+
if (!seenIds.has(id)) {
|
|
272
|
+
seenIds.add(id);
|
|
273
|
+
modules.push({ id, deps: [], path });
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// 3. Fallback scan for __d calls
|
|
270
278
|
if (modules.length === 0) {
|
|
271
279
|
const defineRe = /__d\s*\(/g;
|
|
272
280
|
let m;
|
|
@@ -281,22 +289,13 @@ const extractBundleModules = (bundleText) => {
|
|
|
281
289
|
const idNum = parseInt(idMatch[1], 10);
|
|
282
290
|
if (seenIds.has(idNum))
|
|
283
291
|
continue;
|
|
284
|
-
const depsMatch = args[2].match(/\[([^\]]*)\]/);
|
|
285
|
-
const deps = [];
|
|
286
|
-
if (depsMatch) {
|
|
287
|
-
const depRe = /\d+/g;
|
|
288
|
-
let d;
|
|
289
|
-
while ((d = depRe.exec(depsMatch[1])) !== null) {
|
|
290
|
-
deps.push(parseInt(d[0], 10));
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
292
|
const pathRaw = args[3].trim();
|
|
294
293
|
const pathMatch = pathRaw.match(/^["']([^"']+)["']$/);
|
|
295
294
|
const path = pathMatch ? pathMatch[1] : pathRaw;
|
|
296
295
|
if (path.length === 0 || path.length > 500)
|
|
297
296
|
continue;
|
|
298
297
|
seenIds.add(idNum);
|
|
299
|
-
modules.push({ id: idNum, deps, path });
|
|
298
|
+
modules.push({ id: idNum, deps: [], path });
|
|
300
299
|
}
|
|
301
300
|
}
|
|
302
301
|
}
|
|
@@ -318,8 +317,28 @@ const getStaticStartupModuleIds = (bundleText) => {
|
|
|
318
317
|
}
|
|
319
318
|
return ids;
|
|
320
319
|
};
|
|
321
|
-
|
|
322
|
-
|
|
320
|
+
/**
|
|
321
|
+
* Dynamically computes the host app's project root directory without hardcoding any folder names.
|
|
322
|
+
* Uses node_modules boundary, root entry points (index/App/package.json), and common directory analysis.
|
|
323
|
+
*/
|
|
324
|
+
const detectProjectRoot = (allRawPaths) => {
|
|
325
|
+
const normPaths = allRawPaths.map(p => p.replace(/\\/g, '/'));
|
|
326
|
+
// 1. Extract from node_modules path (most definitive in Metro dev bundles)
|
|
327
|
+
for (const norm of normPaths) {
|
|
328
|
+
const nmIdx = norm.indexOf('/node_modules/');
|
|
329
|
+
if (nmIdx !== -1) {
|
|
330
|
+
return norm.slice(0, nmIdx + 1); // e.g. "/Users/user/Projects/my-app/"
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
// 2. Extract from root entrypoint files (e.g. /path/to/project/index.js or App.tsx)
|
|
334
|
+
for (const norm of normPaths) {
|
|
335
|
+
const match = norm.match(/^(.*\/)(?:index\.[jt]sx?|app\.[jt]sx?|package\.json)(?:[?#].*)?$/i);
|
|
336
|
+
if (match && match[1]) {
|
|
337
|
+
return match[1];
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// 3. Fallback: lowest common directory ancestor among all absolute project paths
|
|
341
|
+
const absPaths = normPaths.filter(p => p.startsWith('/') && !p.includes('/node_modules/'));
|
|
323
342
|
if (absPaths.length === 0)
|
|
324
343
|
return '';
|
|
325
344
|
if (absPaths.length === 1) {
|
|
@@ -327,20 +346,42 @@ const findCommonDirectoryPrefix = (paths) => {
|
|
|
327
346
|
return lastSlash > 0 ? absPaths[0].slice(0, lastSlash + 1) : '';
|
|
328
347
|
}
|
|
329
348
|
const splitPaths = absPaths.map(p => p.split('/'));
|
|
330
|
-
let
|
|
349
|
+
let commonLen = 0;
|
|
331
350
|
const first = splitPaths[0];
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
351
|
+
const minLen = Math.min(...splitPaths.map(sp => sp.length));
|
|
352
|
+
while (commonLen < minLen - 1) {
|
|
353
|
+
const seg = first[commonLen];
|
|
354
|
+
if (splitPaths.every(sp => sp[commonLen] === seg)) {
|
|
355
|
+
commonLen++;
|
|
336
356
|
}
|
|
337
357
|
else {
|
|
338
358
|
break;
|
|
339
359
|
}
|
|
340
360
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
361
|
+
return commonLen > 0 ? first.slice(0, commonLen).join('/') + '/' : '';
|
|
362
|
+
};
|
|
363
|
+
/**
|
|
364
|
+
* Normalizes absolute or relative module paths so they retain their full
|
|
365
|
+
* folder hierarchy from the host project root dynamically.
|
|
366
|
+
*/
|
|
367
|
+
const normalizeProjectRelativePath = (rawPath, projectRoot) => {
|
|
368
|
+
let clean = rawPath.replace(/\\/g, '/');
|
|
369
|
+
// Strip query parameters e.g. ?platform=ios or hashes
|
|
370
|
+
const qIdx = clean.search(/[?#]/);
|
|
371
|
+
if (qIdx !== -1) {
|
|
372
|
+
clean = clean.slice(0, qIdx);
|
|
373
|
+
}
|
|
374
|
+
// Strip file:// or http://.../ dev server URL prefixes
|
|
375
|
+
clean = clean.replace(/^(?:https?:\/\/[^/]+\/|file:\/\/)/, '');
|
|
376
|
+
// Strip dynamically detected project root prefix
|
|
377
|
+
if (projectRoot && clean.startsWith(projectRoot)) {
|
|
378
|
+
clean = clean.slice(projectRoot.length);
|
|
379
|
+
}
|
|
380
|
+
// Clean leading ../ sequences, ./, and leading /
|
|
381
|
+
clean = clean.replace(/^(\.\.\/)+/, '').replace(/^\.\//, '').replace(/^\/+/, '');
|
|
382
|
+
if (!clean)
|
|
383
|
+
clean = rawPath.split('/').pop() || rawPath;
|
|
384
|
+
return clean;
|
|
344
385
|
};
|
|
345
386
|
const isExternalPackage = (rawPath) => {
|
|
346
387
|
// 1. Standard node_modules
|
|
@@ -451,19 +492,12 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
|
|
|
451
492
|
}
|
|
452
493
|
rawProjectItems.push({ mod, rawPath });
|
|
453
494
|
}
|
|
454
|
-
//
|
|
455
|
-
const
|
|
495
|
+
// Dynamically calculate project root prefix to cleanly extract all host app folders & files
|
|
496
|
+
const projectRoot = detectProjectRoot(modules.map(item => item.path));
|
|
456
497
|
const discoveredFiles = [];
|
|
457
498
|
let fileIdx = 0;
|
|
458
499
|
for (const { mod, rawPath } of rawProjectItems) {
|
|
459
|
-
|
|
460
|
-
if (commonPrefix && cleanPath.startsWith(commonPrefix)) {
|
|
461
|
-
cleanPath = cleanPath.slice(commonPrefix.length);
|
|
462
|
-
}
|
|
463
|
-
// Clean leading ../ sequences, ./, and leading /
|
|
464
|
-
cleanPath = cleanPath.replace(/^(\.\.\/)+/, '').replace(/^\.\//, '').replace(/^\/+/, '');
|
|
465
|
-
if (!cleanPath)
|
|
466
|
-
cleanPath = rawPath.split('/').pop() || rawPath;
|
|
500
|
+
const cleanPath = normalizeProjectRelativePath(rawPath, projectRoot);
|
|
467
501
|
const isLocalFile = cleanPath.endsWith('.tsx') ||
|
|
468
502
|
cleanPath.endsWith('.ts') ||
|
|
469
503
|
cleanPath.endsWith('.jsx') ||
|
|
@@ -537,43 +571,6 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
|
|
|
537
571
|
isConsumed,
|
|
538
572
|
});
|
|
539
573
|
}
|
|
540
|
-
// If no modules could be parsed (e.g. Hermes bytecode / obfuscated bundle), synthesize from loaded modules
|
|
541
|
-
if (discoveredFiles.length === 0) {
|
|
542
|
-
discoveredFiles.push({
|
|
543
|
-
id: 'hf-1',
|
|
544
|
-
name: 'index.js (App Entry)',
|
|
545
|
-
path: 'index.js',
|
|
546
|
-
ext: 'JS',
|
|
547
|
-
category: 'javascript',
|
|
548
|
-
sizeKb: Math.round(totalDevKb * 0.08),
|
|
549
|
-
meta: 'React Native Root Entrypoint',
|
|
550
|
-
color: AppColors.indigo500,
|
|
551
|
-
status: 'optimal',
|
|
552
|
-
isConsumed: true,
|
|
553
|
-
}, {
|
|
554
|
-
id: 'hf-2',
|
|
555
|
-
name: 'App.tsx',
|
|
556
|
-
path: 'src/App.tsx',
|
|
557
|
-
ext: 'TSX',
|
|
558
|
-
category: 'typescript',
|
|
559
|
-
sizeKb: Math.round(totalDevKb * 0.12),
|
|
560
|
-
meta: 'Root Navigation & Provider Container',
|
|
561
|
-
color: AppColors.sky500,
|
|
562
|
-
status: 'optimal',
|
|
563
|
-
isConsumed: true,
|
|
564
|
-
}, {
|
|
565
|
-
id: 'hf-3',
|
|
566
|
-
name: 'HomeScreen.tsx',
|
|
567
|
-
path: 'src/screens/HomeScreen.tsx',
|
|
568
|
-
ext: 'TSX',
|
|
569
|
-
category: 'typescript',
|
|
570
|
-
sizeKb: Math.round(totalDevKb * 0.06),
|
|
571
|
-
meta: 'Main Dashboard Screen View',
|
|
572
|
-
color: AppColors.sky500,
|
|
573
|
-
status: 'optimal',
|
|
574
|
-
isConsumed: true,
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
574
|
// Dynamic color palette generator based on package name hash
|
|
578
575
|
const getPackageColor = (name) => {
|
|
579
576
|
const colors = [
|
|
@@ -726,105 +723,105 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
|
|
|
726
723
|
const iosComponents = [
|
|
727
724
|
{
|
|
728
725
|
id: 'ios-c1',
|
|
729
|
-
name: '
|
|
726
|
+
name: t('bundle.iosComp1Name'),
|
|
730
727
|
category: 'frameworks',
|
|
731
728
|
sizeMb: nativeFrameworksMb,
|
|
732
729
|
pct: Number(((nativeFrameworksMb / iosInstallMb) * 100).toFixed(1)),
|
|
733
730
|
color: AppColors.indigo500,
|
|
734
|
-
description:
|
|
735
|
-
advice: '
|
|
731
|
+
description: t('bundle.iosComp1Desc', { count: packagesList.length }),
|
|
732
|
+
advice: t('bundle.iosComp1Advice'),
|
|
736
733
|
},
|
|
737
734
|
{
|
|
738
735
|
id: 'ios-c2',
|
|
739
|
-
name: '
|
|
736
|
+
name: t('bundle.iosComp2Name'),
|
|
740
737
|
category: 'native',
|
|
741
738
|
sizeMb: nativeMachoMb,
|
|
742
739
|
pct: Number(((nativeMachoMb / iosInstallMb) * 100).toFixed(1)),
|
|
743
740
|
color: AppColors.sky500,
|
|
744
|
-
description: '
|
|
745
|
-
advice: '
|
|
741
|
+
description: t('bundle.iosComp2Desc'),
|
|
742
|
+
advice: t('bundle.iosComp2Advice'),
|
|
746
743
|
},
|
|
747
744
|
{
|
|
748
745
|
id: 'ios-c3',
|
|
749
|
-
name: '
|
|
746
|
+
name: t('bundle.iosComp3Name'),
|
|
750
747
|
category: 'assets',
|
|
751
748
|
sizeMb: assetsCatalogMb,
|
|
752
749
|
pct: Number(((assetsCatalogMb / iosInstallMb) * 100).toFixed(1)),
|
|
753
750
|
color: AppColors.pink500,
|
|
754
|
-
description: '
|
|
755
|
-
advice: '
|
|
751
|
+
description: t('bundle.iosComp3Desc'),
|
|
752
|
+
advice: t('bundle.iosComp3Advice'),
|
|
756
753
|
},
|
|
757
754
|
{
|
|
758
755
|
id: 'ios-c4',
|
|
759
|
-
name: '
|
|
756
|
+
name: t('bundle.iosComp4Name'),
|
|
760
757
|
category: 'js',
|
|
761
758
|
sizeMb: releaseJsMb,
|
|
762
759
|
pct: Number(((releaseJsMb / iosInstallMb) * 100).toFixed(1)),
|
|
763
760
|
color: AppColors.emerald500,
|
|
764
|
-
description:
|
|
765
|
-
advice: '
|
|
761
|
+
description: t('bundle.iosComp4Desc', { count: discoveredFiles.length }),
|
|
762
|
+
advice: t('bundle.iosComp4Advice'),
|
|
766
763
|
},
|
|
767
764
|
{
|
|
768
765
|
id: 'ios-c5',
|
|
769
|
-
name: '
|
|
766
|
+
name: t('bundle.iosComp5Name'),
|
|
770
767
|
category: 'meta',
|
|
771
768
|
sizeMb: metadataMb,
|
|
772
769
|
pct: Number(((metadataMb / iosInstallMb) * 100).toFixed(1)),
|
|
773
770
|
color: AppColors.amber500,
|
|
774
|
-
description: '
|
|
775
|
-
advice: '
|
|
771
|
+
description: t('bundle.iosComp5Desc'),
|
|
772
|
+
advice: t('bundle.iosComp5Advice'),
|
|
776
773
|
},
|
|
777
774
|
];
|
|
778
775
|
const androidComponents = [
|
|
779
776
|
{
|
|
780
777
|
id: 'and-c1',
|
|
781
|
-
name: '
|
|
778
|
+
name: t('bundle.andComp1Name'),
|
|
782
779
|
category: 'native',
|
|
783
780
|
sizeMb: androidCppMb,
|
|
784
781
|
pct: Number(((androidCppMb / androidInstallMb) * 100).toFixed(1)),
|
|
785
782
|
color: AppColors.sky500,
|
|
786
|
-
description:
|
|
787
|
-
advice: '
|
|
783
|
+
description: t('bundle.andComp1Desc', { count: packagesList.length }),
|
|
784
|
+
advice: t('bundle.andComp1Advice'),
|
|
788
785
|
},
|
|
789
786
|
{
|
|
790
787
|
id: 'and-c2',
|
|
791
|
-
name: '
|
|
788
|
+
name: t('bundle.andComp2Name'),
|
|
792
789
|
category: 'frameworks',
|
|
793
790
|
sizeMb: androidDexMb,
|
|
794
791
|
pct: Number(((androidDexMb / androidInstallMb) * 100).toFixed(1)),
|
|
795
792
|
color: AppColors.indigo500,
|
|
796
|
-
description: '
|
|
797
|
-
advice: '
|
|
793
|
+
description: t('bundle.andComp2Desc'),
|
|
794
|
+
advice: t('bundle.andComp2Advice'),
|
|
798
795
|
},
|
|
799
796
|
{
|
|
800
797
|
id: 'and-c3',
|
|
801
|
-
name: '
|
|
798
|
+
name: t('bundle.andComp3Name'),
|
|
802
799
|
category: 'assets',
|
|
803
800
|
sizeMb: androidResMb,
|
|
804
801
|
pct: Number(((androidResMb / androidInstallMb) * 100).toFixed(1)),
|
|
805
802
|
color: AppColors.pink500,
|
|
806
|
-
description: '
|
|
807
|
-
advice: '
|
|
803
|
+
description: t('bundle.andComp3Desc'),
|
|
804
|
+
advice: t('bundle.andComp3Advice'),
|
|
808
805
|
},
|
|
809
806
|
{
|
|
810
807
|
id: 'and-c4',
|
|
811
|
-
name: '
|
|
808
|
+
name: t('bundle.andComp4Name'),
|
|
812
809
|
category: 'js',
|
|
813
810
|
sizeMb: releaseJsMb,
|
|
814
811
|
pct: Number(((releaseJsMb / androidInstallMb) * 100).toFixed(1)),
|
|
815
812
|
color: AppColors.emerald500,
|
|
816
|
-
description:
|
|
817
|
-
advice: '
|
|
813
|
+
description: t('bundle.andComp4Desc', { count: discoveredFiles.length }),
|
|
814
|
+
advice: t('bundle.andComp4Advice'),
|
|
818
815
|
},
|
|
819
816
|
{
|
|
820
817
|
id: 'and-c5',
|
|
821
|
-
name: '
|
|
818
|
+
name: t('bundle.andComp5Name'),
|
|
822
819
|
category: 'meta',
|
|
823
820
|
sizeMb: 2.6,
|
|
824
821
|
pct: Number(((2.6 / androidInstallMb) * 100).toFixed(1)),
|
|
825
822
|
color: AppColors.amber500,
|
|
826
|
-
description: '
|
|
827
|
-
advice: '
|
|
823
|
+
description: t('bundle.andComp5Desc'),
|
|
824
|
+
advice: t('bundle.andComp5Advice'),
|
|
828
825
|
},
|
|
829
826
|
];
|
|
830
827
|
// Universal Standalone APK metrics (Multi-ABI FAT APK: arm64 + v7a + x86_64)
|
|
@@ -834,53 +831,53 @@ export const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = tr
|
|
|
834
831
|
const androidApkComponents = [
|
|
835
832
|
{
|
|
836
833
|
id: 'apk-c1',
|
|
837
|
-
name: '
|
|
834
|
+
name: t('bundle.apkComp1Name'),
|
|
838
835
|
category: 'native',
|
|
839
836
|
sizeMb: androidMultiAbiCppMb,
|
|
840
837
|
pct: Number(((androidMultiAbiCppMb / androidApkInstallMb) * 100).toFixed(1)),
|
|
841
838
|
color: AppColors.sky500,
|
|
842
|
-
description: '
|
|
843
|
-
advice: '
|
|
839
|
+
description: t('bundle.apkComp1Desc'),
|
|
840
|
+
advice: t('bundle.apkComp1Advice'),
|
|
844
841
|
},
|
|
845
842
|
{
|
|
846
843
|
id: 'apk-c2',
|
|
847
|
-
name: '
|
|
844
|
+
name: t('bundle.apkComp2Name'),
|
|
848
845
|
category: 'frameworks',
|
|
849
846
|
sizeMb: androidDexMb,
|
|
850
847
|
pct: Number(((androidDexMb / androidApkInstallMb) * 100).toFixed(1)),
|
|
851
848
|
color: AppColors.indigo500,
|
|
852
|
-
description: '
|
|
853
|
-
advice: '
|
|
849
|
+
description: t('bundle.apkComp2Desc'),
|
|
850
|
+
advice: t('bundle.apkComp2Advice'),
|
|
854
851
|
},
|
|
855
852
|
{
|
|
856
853
|
id: 'apk-c3',
|
|
857
|
-
name: '
|
|
854
|
+
name: t('bundle.apkComp3Name'),
|
|
858
855
|
category: 'assets',
|
|
859
856
|
sizeMb: androidResMb,
|
|
860
857
|
pct: Number(((androidResMb / androidApkInstallMb) * 100).toFixed(1)),
|
|
861
858
|
color: AppColors.pink500,
|
|
862
|
-
description: '
|
|
863
|
-
advice: '
|
|
859
|
+
description: t('bundle.apkComp3Desc'),
|
|
860
|
+
advice: t('bundle.apkComp3Advice'),
|
|
864
861
|
},
|
|
865
862
|
{
|
|
866
863
|
id: 'apk-c4',
|
|
867
|
-
name: '
|
|
864
|
+
name: t('bundle.apkComp4Name'),
|
|
868
865
|
category: 'js',
|
|
869
866
|
sizeMb: releaseJsMb,
|
|
870
867
|
pct: Number(((releaseJsMb / androidApkInstallMb) * 100).toFixed(1)),
|
|
871
868
|
color: AppColors.emerald500,
|
|
872
|
-
description:
|
|
873
|
-
advice: '
|
|
869
|
+
description: t('bundle.apkComp4Desc', { count: discoveredFiles.length }),
|
|
870
|
+
advice: t('bundle.apkComp4Advice'),
|
|
874
871
|
},
|
|
875
872
|
{
|
|
876
873
|
id: 'apk-c5',
|
|
877
|
-
name: '
|
|
874
|
+
name: t('bundle.apkComp5Name'),
|
|
878
875
|
category: 'meta',
|
|
879
876
|
sizeMb: 3.2,
|
|
880
877
|
pct: Number(((3.2 / androidApkInstallMb) * 100).toFixed(1)),
|
|
881
878
|
color: AppColors.amber500,
|
|
882
|
-
description: '
|
|
883
|
-
advice: '
|
|
879
|
+
description: t('bundle.apkComp5Desc'),
|
|
880
|
+
advice: t('bundle.apkComp5Advice'),
|
|
884
881
|
},
|
|
885
882
|
];
|
|
886
883
|
return {
|
|
@@ -145,15 +145,26 @@ export const setupNetworkLogger = () => {
|
|
|
145
145
|
return originalFetch(url, options);
|
|
146
146
|
let caller = "Unknown";
|
|
147
147
|
let requestHeaders;
|
|
148
|
+
let client = 'fetch';
|
|
148
149
|
try {
|
|
149
150
|
requestHeaders = normaliseHeaders(options?.headers);
|
|
150
151
|
caller = getCallerFromStack(); // ✅ Capture call line
|
|
152
|
+
if (requestHeaders?.['apollographql-client-name'] || finalUrl?.toLowerCase().includes('/graphql')) {
|
|
153
|
+
client = 'apollo';
|
|
154
|
+
}
|
|
155
|
+
else if (requestHeaders?.['x-requested-with']?.toLowerCase().includes('xmlhttprequest')) {
|
|
156
|
+
client = 'xhr';
|
|
157
|
+
}
|
|
158
|
+
else if (caller?.toLowerCase().includes('axios')) {
|
|
159
|
+
client = 'axios';
|
|
160
|
+
}
|
|
151
161
|
addOrUpdateLog({
|
|
152
162
|
id,
|
|
153
163
|
url: finalUrl,
|
|
154
164
|
method,
|
|
155
165
|
startTime: start,
|
|
156
166
|
caller,
|
|
167
|
+
client,
|
|
157
168
|
request: method === "GET" ? undefined : parseRequestData(options?.body),
|
|
158
169
|
requestHeaders,
|
|
159
170
|
});
|
|
@@ -193,6 +204,7 @@ export const setupNetworkLogger = () => {
|
|
|
193
204
|
duration,
|
|
194
205
|
startTime: start,
|
|
195
206
|
caller,
|
|
207
|
+
client,
|
|
196
208
|
responseHeaders,
|
|
197
209
|
});
|
|
198
210
|
}
|
|
@@ -209,6 +221,7 @@ export const setupNetworkLogger = () => {
|
|
|
209
221
|
startTime: start,
|
|
210
222
|
response: error,
|
|
211
223
|
caller,
|
|
224
|
+
client,
|
|
212
225
|
duration: Date.now() - start,
|
|
213
226
|
});
|
|
214
227
|
}
|
|
@@ -264,6 +277,7 @@ export const addAxiosInterceptors = (axiosInstance) => {
|
|
|
264
277
|
method,
|
|
265
278
|
startTime: start,
|
|
266
279
|
caller,
|
|
280
|
+
client: 'axios',
|
|
267
281
|
request: method === "GET" ? undefined : parseRequestData(config.data),
|
|
268
282
|
requestHeaders: normaliseHeaders(config.headers),
|
|
269
283
|
});
|
|
@@ -289,6 +303,7 @@ export const addAxiosInterceptors = (axiosInstance) => {
|
|
|
289
303
|
startTime: start || Date.now(),
|
|
290
304
|
duration: start != null ? Date.now() - start : undefined,
|
|
291
305
|
caller,
|
|
306
|
+
client: 'axios',
|
|
292
307
|
responseHeaders: normaliseHeaders(response.headers),
|
|
293
308
|
});
|
|
294
309
|
return response;
|
|
@@ -311,6 +326,7 @@ export const addAxiosInterceptors = (axiosInstance) => {
|
|
|
311
326
|
startTime: start || Date.now(),
|
|
312
327
|
duration: start != null ? Date.now() - start : undefined,
|
|
313
328
|
caller,
|
|
329
|
+
client: 'axios',
|
|
314
330
|
responseHeaders: normaliseHeaders(error.response?.headers),
|
|
315
331
|
});
|
|
316
332
|
}
|
|
@@ -5,6 +5,11 @@ export interface PerformanceEvent {
|
|
|
5
5
|
category: 'render' | 'navigation' | 'memory' | 'io' | 'bridge';
|
|
6
6
|
fps: number;
|
|
7
7
|
durationMs: number;
|
|
8
|
+
droppedFrames?: number;
|
|
9
|
+
frameTimeMs?: number;
|
|
10
|
+
frameBudgetPct?: number;
|
|
11
|
+
bottleneckThread?: 'JS Thread' | 'UI Thread' | 'Bridge' | 'Balanced';
|
|
12
|
+
screenName?: string;
|
|
8
13
|
label: string;
|
|
9
14
|
detail: string;
|
|
10
15
|
source?: string;
|
|
@@ -54,7 +59,76 @@ export interface ComponentRenderProfile {
|
|
|
54
59
|
fixKeys: PerformanceFixKey[];
|
|
55
60
|
severity: 'optimal' | 'warning' | 'critical';
|
|
56
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Dynamically generates tailored Before/After performance optimization code snippets
|
|
64
|
+
* based on the target component's real identifier, props, and detected anti-pattern.
|
|
65
|
+
*/
|
|
66
|
+
export declare const generateFixSnippet: (fixKey: string, componentName?: string, context?: {
|
|
67
|
+
propName?: string;
|
|
68
|
+
actionName?: string;
|
|
69
|
+
itemHeight?: number;
|
|
70
|
+
}) => PerformanceFixKey;
|
|
71
|
+
/**
|
|
72
|
+
* Dynamically resolves caller file path or runtime source from the active JavaScript stack trace.
|
|
73
|
+
* Does not assume fixed directory hierarchies (such as src/ or components/) and extracts
|
|
74
|
+
* whatever relative path or symbol the host project structure uses.
|
|
75
|
+
*/
|
|
76
|
+
export declare function getCallerSourceFile(fallbackName?: string): string;
|
|
77
|
+
export declare const getInitialRenderProfiles: () => ComponentRenderProfile[];
|
|
78
|
+
export declare const getInitialPerformanceEvents: () => PerformanceEvent[];
|
|
57
79
|
export declare const INITIAL_EVENTS: PerformanceEvent[];
|
|
80
|
+
export declare const subscribeRenderProfiles: (listener: (profiles: ComponentRenderProfile[]) => void) => () => void;
|
|
81
|
+
export declare const getRenderProfiles: () => ComponentRenderProfile[];
|
|
82
|
+
export declare const registerComponentProfile: (profile: ComponentRenderProfile) => void;
|
|
83
|
+
export declare const trackComponentRender: (params: {
|
|
84
|
+
name: string;
|
|
85
|
+
type?: ComponentRenderProfile["type"];
|
|
86
|
+
sourceFile?: string;
|
|
87
|
+
renderTimeMs?: number;
|
|
88
|
+
isWasteful?: boolean;
|
|
89
|
+
reason?: string;
|
|
90
|
+
fixKeys?: PerformanceFixKey[];
|
|
91
|
+
}) => void;
|
|
92
|
+
/**
|
|
93
|
+
* Dynamically queries Hermes or JavaScript runtime memory statistics.
|
|
94
|
+
*/
|
|
95
|
+
export declare const getHermesMemoryStats: () => LiveMemoryStats;
|
|
96
|
+
/**
|
|
97
|
+
* Dynamically records and evaluates screen navigation transition performance.
|
|
98
|
+
*/
|
|
99
|
+
export declare const trackNavigationTransition: (screenName: string, durationMs: number, options?: {
|
|
100
|
+
ttiMs?: number;
|
|
101
|
+
droppedFrames?: number;
|
|
102
|
+
source?: string;
|
|
103
|
+
}) => PerformanceEvent;
|
|
104
|
+
/**
|
|
105
|
+
* React Hook that automatically profiles screen mounts and navigation transitions.
|
|
106
|
+
*/
|
|
107
|
+
export declare const useNavigationProfiler: (screenName: string, options?: {
|
|
108
|
+
onTransitionEnd?: (durationMs: number) => void;
|
|
109
|
+
}) => void;
|
|
110
|
+
/**
|
|
111
|
+
* Measures synchronous execution duration and alerts on frame budget spikes (>16ms).
|
|
112
|
+
*/
|
|
113
|
+
export declare const trackHeavyTask: <T>(taskName: string, syncFn: () => T, options?: {
|
|
114
|
+
thresholdMs?: number;
|
|
115
|
+
source?: string;
|
|
116
|
+
}) => T;
|
|
117
|
+
/**
|
|
118
|
+
* Measures async operation / Promise latency and records slow network or disk tasks.
|
|
119
|
+
*/
|
|
120
|
+
export declare const measureAsync: <T>(taskName: string, asyncFn: () => Promise<T>, options?: {
|
|
121
|
+
thresholdMs?: number;
|
|
122
|
+
source?: string;
|
|
123
|
+
}) => Promise<T>;
|
|
124
|
+
/**
|
|
125
|
+
* Custom React Hook to profile any component or screen renders dynamically in runtime.
|
|
126
|
+
*/
|
|
127
|
+
export declare const useComponentProfiler: (componentName: string, options?: {
|
|
128
|
+
type?: ComponentRenderProfile["type"];
|
|
129
|
+
sourceFile?: string;
|
|
130
|
+
propsToCompare?: Record<string, any>;
|
|
131
|
+
}) => void;
|
|
58
132
|
export declare const usePerformanceTracker: () => {
|
|
59
133
|
isRecording: boolean;
|
|
60
134
|
setIsRecording: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|