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.
Files changed (67) hide show
  1. package/android/build.gradle +1 -0
  2. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.java +34 -0
  3. package/dist/commonjs/components/ErrorBoundary.d.ts +1 -1
  4. package/dist/commonjs/components/ErrorBoundary.js +530 -100
  5. package/dist/commonjs/components/Inspector/AnalyticsTab.js +176 -126
  6. package/dist/commonjs/components/Inspector/BundleTab.d.ts +1 -0
  7. package/dist/commonjs/components/Inspector/BundleTab.js +145 -21
  8. package/dist/commonjs/components/Inspector/CrashTab.js +0 -8
  9. package/dist/commonjs/components/Inspector/NetworkDetail.js +41 -0
  10. package/dist/commonjs/components/Inspector/PerformanceTab.d.ts +5 -0
  11. package/dist/commonjs/components/Inspector/PerformanceTab.js +588 -155
  12. package/dist/commonjs/components/Inspector/SettingsPanel.js +57 -22
  13. package/dist/commonjs/components/Inspector/TabBar.js +13 -1
  14. package/dist/commonjs/components/LogCard.js +75 -34
  15. package/dist/commonjs/components/NetworkIcons.d.ts +112 -102
  16. package/dist/commonjs/constants/version.d.ts +1 -1
  17. package/dist/commonjs/constants/version.js +1 -1
  18. package/dist/commonjs/customHooks/analyticsLogger.d.ts +1 -11
  19. package/dist/commonjs/customHooks/analyticsLogger.js +8 -1
  20. package/dist/commonjs/customHooks/bundleAnalyzer.js +121 -124
  21. package/dist/commonjs/customHooks/networkLogger.d.ts +1 -0
  22. package/dist/commonjs/customHooks/networkLogger.js +16 -0
  23. package/dist/commonjs/customHooks/performanceTracker.d.ts +74 -0
  24. package/dist/commonjs/customHooks/performanceTracker.js +546 -392
  25. package/dist/commonjs/customHooks/reduxLogger.d.ts +1 -0
  26. package/dist/commonjs/customHooks/reduxLogger.js +3 -1
  27. package/dist/commonjs/helpers/index.js +27 -3
  28. package/dist/commonjs/i18n/locales/en.json +225 -4
  29. package/dist/commonjs/index.d.ts +1 -1
  30. package/dist/commonjs/index.js +36 -2
  31. package/dist/commonjs/styles/index.d.ts +3 -1
  32. package/dist/commonjs/styles/index.js +8 -6
  33. package/dist/commonjs/types/interfaces.d.ts +3 -0
  34. package/dist/esm/components/ErrorBoundary.d.ts +1 -1
  35. package/dist/esm/components/ErrorBoundary.js +498 -101
  36. package/dist/esm/components/Inspector/AnalyticsTab.js +177 -127
  37. package/dist/esm/components/Inspector/BundleTab.d.ts +1 -0
  38. package/dist/esm/components/Inspector/BundleTab.js +145 -23
  39. package/dist/esm/components/Inspector/CrashTab.js +0 -8
  40. package/dist/esm/components/Inspector/NetworkDetail.js +41 -0
  41. package/dist/esm/components/Inspector/PerformanceTab.d.ts +5 -0
  42. package/dist/esm/components/Inspector/PerformanceTab.js +591 -158
  43. package/dist/esm/components/Inspector/SettingsPanel.js +57 -22
  44. package/dist/esm/components/Inspector/TabBar.js +13 -1
  45. package/dist/esm/components/LogCard.js +75 -34
  46. package/dist/esm/components/NetworkIcons.d.ts +112 -102
  47. package/dist/esm/constants/version.d.ts +1 -1
  48. package/dist/esm/constants/version.js +1 -1
  49. package/dist/esm/customHooks/analyticsLogger.d.ts +1 -11
  50. package/dist/esm/customHooks/analyticsLogger.js +6 -0
  51. package/dist/esm/customHooks/bundleAnalyzer.js +121 -124
  52. package/dist/esm/customHooks/networkLogger.d.ts +1 -0
  53. package/dist/esm/customHooks/networkLogger.js +16 -0
  54. package/dist/esm/customHooks/performanceTracker.d.ts +74 -0
  55. package/dist/esm/customHooks/performanceTracker.js +531 -391
  56. package/dist/esm/customHooks/reduxLogger.d.ts +1 -0
  57. package/dist/esm/customHooks/reduxLogger.js +1 -0
  58. package/dist/esm/helpers/index.js +27 -3
  59. package/dist/esm/i18n/locales/en.json +225 -4
  60. package/dist/esm/index.d.ts +1 -1
  61. package/dist/esm/index.js +24 -3
  62. package/dist/esm/styles/index.d.ts +3 -1
  63. package/dist/esm/styles/index.js +8 -6
  64. package/dist/esm/types/interfaces.d.ts +3 -0
  65. package/ios/NetworkInspectorModule.h +2 -0
  66. package/ios/NetworkInspectorModule.m +10 -0
  67. package/package.json +1 -1
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getCachedBundleAnalysis = exports.clearCachedBundleAnalysis = exports.analyzeHostAppBundle = exports.parseBundleSource = exports.trackRuntimeDefine = exports.trackRuntimeModuleExecution = exports.getHostScriptURL = void 0;
4
4
  const AppColors_1 = require("../styles/AppColors");
5
+ const i18n_1 = require("../i18n");
5
6
  // ─── Real Host App Bundle Analyzer ──────────────────────────────────────────
6
7
  //
7
8
  // Dynamically measures and analyzes the real JavaScript bundle and packages
@@ -254,25 +255,32 @@ const extractBundleModules = (bundleText) => {
254
255
  const modules = [];
255
256
  const seenIds = new Set();
256
257
  if (bundleText && bundleText.length > 0) {
257
- // Primary high-speed Metro tail regex: matches }, <id>, [<deps>], "<path>"
258
- const tailRegex = /\}\s*,\s*(\d+)\s*,\s*\[([\d,\s]*)\]\s*,\s*(?:"([^"\r\n]+)"|'([^'\r\n]+)')/g;
258
+ // 1. Primary Metro regex: matches }, <id>, [<deps>] or {<deps>}, "<path>"
259
+ const tailRegex = /\}\s*,\s*(\d+)\s*,\s*(?:\[[\s\S]*?\]|\{[\s\S]*?\})\s*,\s*(?:"([^"\r\n]+)"|'([^'\r\n]+)')/g;
259
260
  let match;
260
261
  while ((match = tailRegex.exec(bundleText)) !== null) {
261
262
  const id = parseInt(match[1], 10);
262
- const depsStr = match[2];
263
- const path = match[3] || match[4] || '';
264
- const deps = depsStr
265
- ? depsStr
266
- .split(',')
267
- .map(s => parseInt(s.trim(), 10))
268
- .filter(n => !isNaN(n))
269
- : [];
263
+ const path = match[2] || match[3] || '';
270
264
  if (!seenIds.has(id) && path.length > 0) {
271
265
  seenIds.add(id);
272
- modules.push({ id, deps, path });
266
+ modules.push({ id, deps: [], path });
273
267
  }
274
268
  }
275
- // Secondary fallback if tailRegex didn't find modules
269
+ // 2. SourceURL comment extraction (Metro dev server embeds //# sourceURL=... for every module)
270
+ const sourceUrlRegex = /\/\/[#@]\s*sourceURL=(?:https?:\/\/[^/\n\r]+\/|file:\/\/)?([^?\r\n#\s]+)/g;
271
+ let srcMatch;
272
+ let autoId = 900000;
273
+ while ((srcMatch = sourceUrlRegex.exec(bundleText)) !== null) {
274
+ const path = srcMatch[1];
275
+ if (path && path.length > 0 && !path.endsWith('.bundle')) {
276
+ const id = autoId++;
277
+ if (!seenIds.has(id)) {
278
+ seenIds.add(id);
279
+ modules.push({ id, deps: [], path });
280
+ }
281
+ }
282
+ }
283
+ // 3. Fallback scan for __d calls
276
284
  if (modules.length === 0) {
277
285
  const defineRe = /__d\s*\(/g;
278
286
  let m;
@@ -287,22 +295,13 @@ const extractBundleModules = (bundleText) => {
287
295
  const idNum = parseInt(idMatch[1], 10);
288
296
  if (seenIds.has(idNum))
289
297
  continue;
290
- const depsMatch = args[2].match(/\[([^\]]*)\]/);
291
- const deps = [];
292
- if (depsMatch) {
293
- const depRe = /\d+/g;
294
- let d;
295
- while ((d = depRe.exec(depsMatch[1])) !== null) {
296
- deps.push(parseInt(d[0], 10));
297
- }
298
- }
299
298
  const pathRaw = args[3].trim();
300
299
  const pathMatch = pathRaw.match(/^["']([^"']+)["']$/);
301
300
  const path = pathMatch ? pathMatch[1] : pathRaw;
302
301
  if (path.length === 0 || path.length > 500)
303
302
  continue;
304
303
  seenIds.add(idNum);
305
- modules.push({ id: idNum, deps, path });
304
+ modules.push({ id: idNum, deps: [], path });
306
305
  }
307
306
  }
308
307
  }
@@ -324,8 +323,28 @@ const getStaticStartupModuleIds = (bundleText) => {
324
323
  }
325
324
  return ids;
326
325
  };
327
- const findCommonDirectoryPrefix = (paths) => {
328
- const absPaths = paths.filter(p => p.startsWith('/'));
326
+ /**
327
+ * Dynamically computes the host app's project root directory without hardcoding any folder names.
328
+ * Uses node_modules boundary, root entry points (index/App/package.json), and common directory analysis.
329
+ */
330
+ const detectProjectRoot = (allRawPaths) => {
331
+ const normPaths = allRawPaths.map(p => p.replace(/\\/g, '/'));
332
+ // 1. Extract from node_modules path (most definitive in Metro dev bundles)
333
+ for (const norm of normPaths) {
334
+ const nmIdx = norm.indexOf('/node_modules/');
335
+ if (nmIdx !== -1) {
336
+ return norm.slice(0, nmIdx + 1); // e.g. "/Users/user/Projects/my-app/"
337
+ }
338
+ }
339
+ // 2. Extract from root entrypoint files (e.g. /path/to/project/index.js or App.tsx)
340
+ for (const norm of normPaths) {
341
+ const match = norm.match(/^(.*\/)(?:index\.[jt]sx?|app\.[jt]sx?|package\.json)(?:[?#].*)?$/i);
342
+ if (match && match[1]) {
343
+ return match[1];
344
+ }
345
+ }
346
+ // 3. Fallback: lowest common directory ancestor among all absolute project paths
347
+ const absPaths = normPaths.filter(p => p.startsWith('/') && !p.includes('/node_modules/'));
329
348
  if (absPaths.length === 0)
330
349
  return '';
331
350
  if (absPaths.length === 1) {
@@ -333,20 +352,42 @@ const findCommonDirectoryPrefix = (paths) => {
333
352
  return lastSlash > 0 ? absPaths[0].slice(0, lastSlash + 1) : '';
334
353
  }
335
354
  const splitPaths = absPaths.map(p => p.split('/'));
336
- let commonIndex = 0;
355
+ let commonLen = 0;
337
356
  const first = splitPaths[0];
338
- while (commonIndex < first.length - 1) {
339
- const segment = first[commonIndex];
340
- if (splitPaths.every(p => p[commonIndex] === segment)) {
341
- commonIndex++;
357
+ const minLen = Math.min(...splitPaths.map(sp => sp.length));
358
+ while (commonLen < minLen - 1) {
359
+ const seg = first[commonLen];
360
+ if (splitPaths.every(sp => sp[commonLen] === seg)) {
361
+ commonLen++;
342
362
  }
343
363
  else {
344
364
  break;
345
365
  }
346
366
  }
347
- if (commonIndex === 0)
348
- return '';
349
- return first.slice(0, commonIndex).join('/') + '/';
367
+ return commonLen > 0 ? first.slice(0, commonLen).join('/') + '/' : '';
368
+ };
369
+ /**
370
+ * Normalizes absolute or relative module paths so they retain their full
371
+ * folder hierarchy from the host project root dynamically.
372
+ */
373
+ const normalizeProjectRelativePath = (rawPath, projectRoot) => {
374
+ let clean = rawPath.replace(/\\/g, '/');
375
+ // Strip query parameters e.g. ?platform=ios or hashes
376
+ const qIdx = clean.search(/[?#]/);
377
+ if (qIdx !== -1) {
378
+ clean = clean.slice(0, qIdx);
379
+ }
380
+ // Strip file:// or http://.../ dev server URL prefixes
381
+ clean = clean.replace(/^(?:https?:\/\/[^/]+\/|file:\/\/)/, '');
382
+ // Strip dynamically detected project root prefix
383
+ if (projectRoot && clean.startsWith(projectRoot)) {
384
+ clean = clean.slice(projectRoot.length);
385
+ }
386
+ // Clean leading ../ sequences, ./, and leading /
387
+ clean = clean.replace(/^(\.\.\/)+/, '').replace(/^\.\//, '').replace(/^\/+/, '');
388
+ if (!clean)
389
+ clean = rawPath.split('/').pop() || rawPath;
390
+ return clean;
350
391
  };
351
392
  const isExternalPackage = (rawPath) => {
352
393
  // 1. Standard node_modules
@@ -457,19 +498,12 @@ const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = true) =>
457
498
  }
458
499
  rawProjectItems.push({ mod, rawPath });
459
500
  }
460
- // Calculate common prefix for absolute paths to cleanly extract host app project files
461
- const commonPrefix = findCommonDirectoryPrefix(rawProjectItems.map(item => item.rawPath));
501
+ // Dynamically calculate project root prefix to cleanly extract all host app folders & files
502
+ const projectRoot = detectProjectRoot(modules.map(item => item.path));
462
503
  const discoveredFiles = [];
463
504
  let fileIdx = 0;
464
505
  for (const { mod, rawPath } of rawProjectItems) {
465
- let cleanPath = rawPath;
466
- if (commonPrefix && cleanPath.startsWith(commonPrefix)) {
467
- cleanPath = cleanPath.slice(commonPrefix.length);
468
- }
469
- // Clean leading ../ sequences, ./, and leading /
470
- cleanPath = cleanPath.replace(/^(\.\.\/)+/, '').replace(/^\.\//, '').replace(/^\/+/, '');
471
- if (!cleanPath)
472
- cleanPath = rawPath.split('/').pop() || rawPath;
506
+ const cleanPath = normalizeProjectRelativePath(rawPath, projectRoot);
473
507
  const isLocalFile = cleanPath.endsWith('.tsx') ||
474
508
  cleanPath.endsWith('.ts') ||
475
509
  cleanPath.endsWith('.jsx') ||
@@ -543,43 +577,6 @@ const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = true) =>
543
577
  isConsumed,
544
578
  });
545
579
  }
546
- // If no modules could be parsed (e.g. Hermes bytecode / obfuscated bundle), synthesize from loaded modules
547
- if (discoveredFiles.length === 0) {
548
- discoveredFiles.push({
549
- id: 'hf-1',
550
- name: 'index.js (App Entry)',
551
- path: 'index.js',
552
- ext: 'JS',
553
- category: 'javascript',
554
- sizeKb: Math.round(totalDevKb * 0.08),
555
- meta: 'React Native Root Entrypoint',
556
- color: AppColors_1.AppColors.indigo500,
557
- status: 'optimal',
558
- isConsumed: true,
559
- }, {
560
- id: 'hf-2',
561
- name: 'App.tsx',
562
- path: 'src/App.tsx',
563
- ext: 'TSX',
564
- category: 'typescript',
565
- sizeKb: Math.round(totalDevKb * 0.12),
566
- meta: 'Root Navigation & Provider Container',
567
- color: AppColors_1.AppColors.sky500,
568
- status: 'optimal',
569
- isConsumed: true,
570
- }, {
571
- id: 'hf-3',
572
- name: 'HomeScreen.tsx',
573
- path: 'src/screens/HomeScreen.tsx',
574
- ext: 'TSX',
575
- category: 'typescript',
576
- sizeKb: Math.round(totalDevKb * 0.06),
577
- meta: 'Main Dashboard Screen View',
578
- color: AppColors_1.AppColors.sky500,
579
- status: 'optimal',
580
- isConsumed: true,
581
- });
582
- }
583
580
  // Dynamic color palette generator based on package name hash
584
581
  const getPackageColor = (name) => {
585
582
  const colors = [
@@ -732,105 +729,105 @@ const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = true) =>
732
729
  const iosComponents = [
733
730
  {
734
731
  id: 'ios-c1',
735
- name: 'Frameworks & Dynamic Pods',
732
+ name: (0, i18n_1.t)('bundle.iosComp1Name'),
736
733
  category: 'frameworks',
737
734
  sizeMb: nativeFrameworksMb,
738
735
  pct: Number(((nativeFrameworksMb / iosInstallMb) * 100).toFixed(1)),
739
736
  color: AppColors_1.AppColors.indigo500,
740
- description: `React, Hermes, and ${packagesList.length} native pod frameworks.`,
741
- advice: 'Ensure Dead Code Stripping (STRIP_INSTALLED_PRODUCT = YES) in Release mode.',
737
+ description: (0, i18n_1.t)('bundle.iosComp1Desc', { count: packagesList.length }),
738
+ advice: (0, i18n_1.t)('bundle.iosComp1Advice'),
742
739
  },
743
740
  {
744
741
  id: 'ios-c2',
745
- name: 'Mach-O Executable (ARM64)',
742
+ name: (0, i18n_1.t)('bundle.iosComp2Name'),
746
743
  category: 'native',
747
744
  sizeMb: nativeMachoMb,
748
745
  pct: Number(((nativeMachoMb / iosInstallMb) * 100).toFixed(1)),
749
746
  color: AppColors_1.AppColors.sky500,
750
- description: 'Host App compiled Swift/Objective-C and C++ native bridges.',
751
- advice: 'Enable Monolithic LTO (Link-Time Optimization) in Xcode Scheme.',
747
+ description: (0, i18n_1.t)('bundle.iosComp2Desc'),
748
+ advice: (0, i18n_1.t)('bundle.iosComp2Advice'),
752
749
  },
753
750
  {
754
751
  id: 'ios-c3',
755
- name: 'Asset Catalog (Assets.car)',
752
+ name: (0, i18n_1.t)('bundle.iosComp3Name'),
756
753
  category: 'assets',
757
754
  sizeMb: assetsCatalogMb,
758
755
  pct: Number(((assetsCatalogMb / iosInstallMb) * 100).toFixed(1)),
759
756
  color: AppColors_1.AppColors.pink500,
760
- description: 'AppIcons, splash screens, vector glyphs, and bundled fonts.',
761
- advice: 'Compile images into Xcode Asset Catalog for automatic App Thinning.',
757
+ description: (0, i18n_1.t)('bundle.iosComp3Desc'),
758
+ advice: (0, i18n_1.t)('bundle.iosComp3Advice'),
762
759
  },
763
760
  {
764
761
  id: 'ios-c4',
765
- name: 'Hermes Bytecode (main.jsbundle)',
762
+ name: (0, i18n_1.t)('bundle.iosComp4Name'),
766
763
  category: 'js',
767
764
  sizeMb: releaseJsMb,
768
765
  pct: Number(((releaseJsMb / iosInstallMb) * 100).toFixed(1)),
769
766
  color: AppColors_1.AppColors.emerald500,
770
- description: `Host app JavaScript compiled AOT into Hermes bytecode (${discoveredFiles.length} files).`,
771
- advice: 'AOT bytecode loads with 0ms compile latency on device launch.',
767
+ description: (0, i18n_1.t)('bundle.iosComp4Desc', { count: discoveredFiles.length }),
768
+ advice: (0, i18n_1.t)('bundle.iosComp4Advice'),
772
769
  },
773
770
  {
774
771
  id: 'ios-c5',
775
- name: 'Metadata & Code Signatures',
772
+ name: (0, i18n_1.t)('bundle.iosComp5Name'),
776
773
  category: 'meta',
777
774
  sizeMb: metadataMb,
778
775
  pct: Number(((metadataMb / iosInstallMb) * 100).toFixed(1)),
779
776
  color: AppColors_1.AppColors.amber500,
780
- description: '_CodeSignature, Info.plist, and entitlements block.',
781
- advice: 'Standard Apple Code Signing & provisioning signature.',
777
+ description: (0, i18n_1.t)('bundle.iosComp5Desc'),
778
+ advice: (0, i18n_1.t)('bundle.iosComp5Advice'),
782
779
  },
783
780
  ];
784
781
  const androidComponents = [
785
782
  {
786
783
  id: 'and-c1',
787
- name: 'Native C++ Libraries (.so)',
784
+ name: (0, i18n_1.t)('bundle.andComp1Name'),
788
785
  category: 'native',
789
786
  sizeMb: androidCppMb,
790
787
  pct: Number(((androidCppMb / androidInstallMb) * 100).toFixed(1)),
791
788
  color: AppColors_1.AppColors.sky500,
792
- description: `libhermes.so, libfbjni.so, and ${packagesList.length} C++ native adapters.`,
793
- advice: 'Deploy with Android App Bundle (.aab) to deliver per-ABI split APKs.',
789
+ description: (0, i18n_1.t)('bundle.andComp1Desc', { count: packagesList.length }),
790
+ advice: (0, i18n_1.t)('bundle.andComp1Advice'),
794
791
  },
795
792
  {
796
793
  id: 'and-c2',
797
- name: 'Compiled DEX (classes.dex)',
794
+ name: (0, i18n_1.t)('bundle.andComp2Name'),
798
795
  category: 'frameworks',
799
796
  sizeMb: androidDexMb,
800
797
  pct: Number(((androidDexMb / androidInstallMb) * 100).toFixed(1)),
801
798
  color: AppColors_1.AppColors.indigo500,
802
- description: 'Compiled Java & Kotlin runtime, AndroidX, and React Native bridges.',
803
- advice: 'Enable R8 / ProGuard shrinking (minifyEnabled true) in build.gradle.',
799
+ description: (0, i18n_1.t)('bundle.andComp2Desc'),
800
+ advice: (0, i18n_1.t)('bundle.andComp2Advice'),
804
801
  },
805
802
  {
806
803
  id: 'and-c3',
807
- name: 'Android Resources (res/)',
804
+ name: (0, i18n_1.t)('bundle.andComp3Name'),
808
805
  category: 'assets',
809
806
  sizeMb: androidResMb,
810
807
  pct: Number(((androidResMb / androidInstallMb) * 100).toFixed(1)),
811
808
  color: AppColors_1.AppColors.pink500,
812
- description: 'Drawables, vector XMLs, mipmap densities, resources.arsc, fonts.',
813
- advice: 'Use WebP and VectorDrawables to avoid multi-density asset duplication.',
809
+ description: (0, i18n_1.t)('bundle.andComp3Desc'),
810
+ advice: (0, i18n_1.t)('bundle.andComp3Advice'),
814
811
  },
815
812
  {
816
813
  id: 'and-c4',
817
- name: 'Hermes Bytecode (Android)',
814
+ name: (0, i18n_1.t)('bundle.andComp4Name'),
818
815
  category: 'js',
819
816
  sizeMb: releaseJsMb,
820
817
  pct: Number(((releaseJsMb / androidInstallMb) * 100).toFixed(1)),
821
818
  color: AppColors_1.AppColors.emerald500,
822
- description: `Host app JavaScript compiled into Hermes bytecode (${discoveredFiles.length} files).`,
823
- advice: 'Pre-compiled bytecode during assembleRelease gradle task.',
819
+ description: (0, i18n_1.t)('bundle.andComp4Desc', { count: discoveredFiles.length }),
820
+ advice: (0, i18n_1.t)('bundle.andComp4Advice'),
824
821
  },
825
822
  {
826
823
  id: 'and-c5',
827
- name: 'Manifest & Signatures (META-INF)',
824
+ name: (0, i18n_1.t)('bundle.andComp5Name'),
828
825
  category: 'meta',
829
826
  sizeMb: 2.6,
830
827
  pct: Number(((2.6 / androidInstallMb) * 100).toFixed(1)),
831
828
  color: AppColors_1.AppColors.amber500,
832
- description: 'AndroidManifest.xml, signing certs, v2/v3/v4 APK Signature Scheme blocks.',
833
- advice: 'Official Google Play signing & signature block.',
829
+ description: (0, i18n_1.t)('bundle.andComp5Desc'),
830
+ advice: (0, i18n_1.t)('bundle.andComp5Advice'),
834
831
  },
835
832
  ];
836
833
  // Universal Standalone APK metrics (Multi-ABI FAT APK: arm64 + v7a + x86_64)
@@ -840,53 +837,53 @@ const parseBundleSource = (bundleText, totalBytes, scriptURL, isLive = true) =>
840
837
  const androidApkComponents = [
841
838
  {
842
839
  id: 'apk-c1',
843
- name: 'Multi-ABI C++ Libraries (.so)',
840
+ name: (0, i18n_1.t)('bundle.apkComp1Name'),
844
841
  category: 'native',
845
842
  sizeMb: androidMultiAbiCppMb,
846
843
  pct: Number(((androidMultiAbiCppMb / androidApkInstallMb) * 100).toFixed(1)),
847
844
  color: AppColors_1.AppColors.sky500,
848
- description: 'Universal multi-architecture shared libraries (.so) bundled for direct sideloading.',
849
- advice: 'Use Android App Bundle (.aab) for Google Play to reduce install size by 60%.',
845
+ description: (0, i18n_1.t)('bundle.apkComp1Desc'),
846
+ advice: (0, i18n_1.t)('bundle.apkComp1Advice'),
850
847
  },
851
848
  {
852
849
  id: 'apk-c2',
853
- name: 'Compiled DEX Bytecode (classes.dex)',
850
+ name: (0, i18n_1.t)('bundle.apkComp2Name'),
854
851
  category: 'frameworks',
855
852
  sizeMb: androidDexMb,
856
853
  pct: Number(((androidDexMb / androidApkInstallMb) * 100).toFixed(1)),
857
854
  color: AppColors_1.AppColors.indigo500,
858
- description: 'Compiled Java & Kotlin runtime, AndroidX libraries, and native bridge modules.',
859
- advice: 'Enable R8 / ProGuard shrinking (minifyEnabled true) and shrinkResources true.',
855
+ description: (0, i18n_1.t)('bundle.apkComp2Desc'),
856
+ advice: (0, i18n_1.t)('bundle.apkComp2Advice'),
860
857
  },
861
858
  {
862
859
  id: 'apk-c3',
863
- name: 'Android Resources & Assets (res/)',
860
+ name: (0, i18n_1.t)('bundle.apkComp3Name'),
864
861
  category: 'assets',
865
862
  sizeMb: androidResMb,
866
863
  pct: Number(((androidResMb / androidApkInstallMb) * 100).toFixed(1)),
867
864
  color: AppColors_1.AppColors.pink500,
868
- description: 'Drawables, vector XMLs, mipmap densities, resources.arsc, fonts.',
869
- advice: 'Use WebP and VectorDrawables to avoid multi-density asset duplication.',
865
+ description: (0, i18n_1.t)('bundle.apkComp3Desc'),
866
+ advice: (0, i18n_1.t)('bundle.apkComp3Advice'),
870
867
  },
871
868
  {
872
869
  id: 'apk-c4',
873
- name: 'Hermes Bytecode Bundle (Android)',
870
+ name: (0, i18n_1.t)('bundle.apkComp4Name'),
874
871
  category: 'js',
875
872
  sizeMb: releaseJsMb,
876
873
  pct: Number(((releaseJsMb / androidApkInstallMb) * 100).toFixed(1)),
877
874
  color: AppColors_1.AppColors.emerald500,
878
- description: `Host app JavaScript compiled into Hermes bytecode (${discoveredFiles.length} files).`,
879
- advice: 'Pre-compiled bytecode during assembleRelease gradle task.',
875
+ description: (0, i18n_1.t)('bundle.apkComp4Desc', { count: discoveredFiles.length }),
876
+ advice: (0, i18n_1.t)('bundle.apkComp4Advice'),
880
877
  },
881
878
  {
882
879
  id: 'apk-c5',
883
- name: 'Manifest & Signatures (META-INF)',
880
+ name: (0, i18n_1.t)('bundle.apkComp5Name'),
884
881
  category: 'meta',
885
882
  sizeMb: 3.2,
886
883
  pct: Number(((3.2 / androidApkInstallMb) * 100).toFixed(1)),
887
884
  color: AppColors_1.AppColors.amber500,
888
- description: 'AndroidManifest.xml, signing certs, JAR & v2/v3/v4 APK Signature Scheme.',
889
- advice: 'Enterprise sideload & direct install signature block.',
885
+ description: (0, i18n_1.t)('bundle.apkComp5Desc'),
886
+ advice: (0, i18n_1.t)('bundle.apkComp5Advice'),
890
887
  },
891
888
  ];
892
889
  return {
@@ -8,6 +8,7 @@ type NetworkLog = {
8
8
  duration?: number;
9
9
  startTime: number;
10
10
  caller?: string;
11
+ client?: string;
11
12
  requestHeaders?: Record<string, string>;
12
13
  responseHeaders?: Record<string, string>;
13
14
  };
@@ -154,15 +154,26 @@ const setupNetworkLogger = () => {
154
154
  return originalFetch(url, options);
155
155
  let caller = "Unknown";
156
156
  let requestHeaders;
157
+ let client = 'fetch';
157
158
  try {
158
159
  requestHeaders = normaliseHeaders(options?.headers);
159
160
  caller = getCallerFromStack(); // ✅ Capture call line
161
+ if (requestHeaders?.['apollographql-client-name'] || finalUrl?.toLowerCase().includes('/graphql')) {
162
+ client = 'apollo';
163
+ }
164
+ else if (requestHeaders?.['x-requested-with']?.toLowerCase().includes('xmlhttprequest')) {
165
+ client = 'xhr';
166
+ }
167
+ else if (caller?.toLowerCase().includes('axios')) {
168
+ client = 'axios';
169
+ }
160
170
  addOrUpdateLog({
161
171
  id,
162
172
  url: finalUrl,
163
173
  method,
164
174
  startTime: start,
165
175
  caller,
176
+ client,
166
177
  request: method === "GET" ? undefined : parseRequestData(options?.body),
167
178
  requestHeaders,
168
179
  });
@@ -202,6 +213,7 @@ const setupNetworkLogger = () => {
202
213
  duration,
203
214
  startTime: start,
204
215
  caller,
216
+ client,
205
217
  responseHeaders,
206
218
  });
207
219
  }
@@ -218,6 +230,7 @@ const setupNetworkLogger = () => {
218
230
  startTime: start,
219
231
  response: error,
220
232
  caller,
233
+ client,
221
234
  duration: Date.now() - start,
222
235
  });
223
236
  }
@@ -274,6 +287,7 @@ const addAxiosInterceptors = (axiosInstance) => {
274
287
  method,
275
288
  startTime: start,
276
289
  caller,
290
+ client: 'axios',
277
291
  request: method === "GET" ? undefined : parseRequestData(config.data),
278
292
  requestHeaders: normaliseHeaders(config.headers),
279
293
  });
@@ -299,6 +313,7 @@ const addAxiosInterceptors = (axiosInstance) => {
299
313
  startTime: start || Date.now(),
300
314
  duration: start != null ? Date.now() - start : undefined,
301
315
  caller,
316
+ client: 'axios',
302
317
  responseHeaders: normaliseHeaders(response.headers),
303
318
  });
304
319
  return response;
@@ -321,6 +336,7 @@ const addAxiosInterceptors = (axiosInstance) => {
321
336
  startTime: start || Date.now(),
322
337
  duration: start != null ? Date.now() - start : undefined,
323
338
  caller,
339
+ client: 'axios',
324
340
  responseHeaders: normaliseHeaders(error.response?.headers),
325
341
  });
326
342
  }
@@ -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>>;