react-native-inapp-inspector 2.2.2 → 2.2.4

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 (159) hide show
  1. package/dist/commonjs/components/AnalyticsDetail.js +5 -1
  2. package/dist/commonjs/components/AnalyticsEventCard.js +2 -1
  3. package/dist/commonjs/components/DiffViewer.js +1 -1
  4. package/dist/commonjs/components/Inspector/BundleTab.js +22 -0
  5. package/dist/commonjs/components/Inspector/DeviceInfoTab.d.ts +3 -0
  6. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +835 -0
  7. package/dist/commonjs/components/Inspector/InspectorHeader.js +12 -14
  8. package/dist/commonjs/components/Inspector/LogDetail.js +6 -3
  9. package/dist/commonjs/components/Inspector/MainScreen.js +7 -3
  10. package/dist/commonjs/components/Inspector/NetworkTab.js +92 -15
  11. package/dist/commonjs/components/Inspector/PerformanceTab.js +38 -12
  12. package/dist/commonjs/components/Inspector/SettingsPanel.js +440 -229
  13. package/dist/commonjs/components/Inspector/StorageTab.d.ts +3 -0
  14. package/dist/commonjs/components/Inspector/StorageTab.js +892 -0
  15. package/dist/commonjs/components/Inspector/TabBar.js +14 -0
  16. package/dist/commonjs/components/Inspector/TelemetryConsentModal.js +11 -2
  17. package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +4 -1
  18. package/dist/commonjs/components/NetworkIcons.d.ts +6 -0
  19. package/dist/commonjs/components/NetworkIcons.js +30 -1
  20. package/dist/commonjs/constants/version.d.ts +1 -1
  21. package/dist/commonjs/constants/version.js +1 -1
  22. package/dist/commonjs/customHooks/bundleAnalyzer.js +44 -22
  23. package/dist/commonjs/customHooks/storageInspector.d.ts +67 -0
  24. package/dist/commonjs/customHooks/storageInspector.js +486 -0
  25. package/dist/commonjs/i18n/locales/en.json +8 -2
  26. package/dist/commonjs/index.d.ts +1 -0
  27. package/dist/commonjs/index.js +16 -1
  28. package/dist/commonjs/storage.d.ts +5 -0
  29. package/dist/commonjs/storage.js +18 -0
  30. package/dist/commonjs/types/enums.d.ts +5 -0
  31. package/dist/commonjs/types/enums.js +5 -0
  32. package/dist/esm/components/AnalyticsDetail.js +6 -2
  33. package/dist/esm/components/AnalyticsEventCard.js +2 -1
  34. package/dist/esm/components/DiffViewer.js +1 -1
  35. package/dist/esm/components/Inspector/BundleTab.js +22 -0
  36. package/dist/esm/components/Inspector/DeviceInfoTab.d.ts +3 -0
  37. package/dist/esm/components/Inspector/DeviceInfoTab.js +796 -0
  38. package/dist/esm/components/Inspector/InspectorHeader.js +13 -15
  39. package/dist/esm/components/Inspector/LogDetail.js +7 -4
  40. package/dist/esm/components/Inspector/MainScreen.js +7 -3
  41. package/dist/esm/components/Inspector/NetworkTab.js +93 -16
  42. package/dist/esm/components/Inspector/PerformanceTab.js +39 -13
  43. package/dist/esm/components/Inspector/SettingsPanel.js +441 -230
  44. package/dist/esm/components/Inspector/StorageTab.d.ts +3 -0
  45. package/dist/esm/components/Inspector/StorageTab.js +853 -0
  46. package/dist/esm/components/Inspector/TabBar.js +15 -1
  47. package/dist/esm/components/Inspector/TelemetryConsentModal.js +11 -2
  48. package/dist/esm/components/Inspector/UpdateAvailableModal.js +4 -1
  49. package/dist/esm/components/NetworkIcons.d.ts +6 -0
  50. package/dist/esm/components/NetworkIcons.js +23 -0
  51. package/dist/esm/constants/version.d.ts +1 -1
  52. package/dist/esm/constants/version.js +1 -1
  53. package/dist/esm/customHooks/bundleAnalyzer.js +44 -22
  54. package/dist/esm/customHooks/storageInspector.d.ts +67 -0
  55. package/dist/esm/customHooks/storageInspector.js +469 -0
  56. package/dist/esm/i18n/locales/en.json +8 -2
  57. package/dist/esm/index.d.ts +1 -0
  58. package/dist/esm/index.js +5 -0
  59. package/dist/esm/storage.d.ts +5 -0
  60. package/dist/esm/storage.js +5 -0
  61. package/dist/esm/types/enums.d.ts +5 -0
  62. package/dist/esm/types/enums.js +5 -0
  63. package/package.json +9 -1
  64. package/src/analytics.ts +35 -0
  65. package/src/bundle.ts +25 -0
  66. package/src/components/AnalyticsDetail.tsx +870 -0
  67. package/src/components/AnalyticsEventCard.tsx +442 -0
  68. package/src/components/AnalyticsGraph.tsx +583 -0
  69. package/src/components/AnimatedEntrance.tsx +64 -0
  70. package/src/components/AppHeaderLogo.tsx +109 -0
  71. package/src/components/BrandCircleIcon.tsx +144 -0
  72. package/src/components/BrandSquareIcon.tsx +144 -0
  73. package/src/components/CodeSnippet.tsx +725 -0
  74. package/src/components/ConsoleLogCard.tsx +628 -0
  75. package/src/components/CopyButton.tsx +87 -0
  76. package/src/components/DiffViewer.tsx +82 -0
  77. package/src/components/DomainHeader.tsx +237 -0
  78. package/src/components/EmptyState.tsx +73 -0
  79. package/src/components/EndOfListFooter.tsx +100 -0
  80. package/src/components/ErrorBoundary.tsx +688 -0
  81. package/src/components/HeadersSection.tsx +192 -0
  82. package/src/components/HighlightText.tsx +100 -0
  83. package/src/components/Inspector/AnalyticsFilterModal.tsx +1250 -0
  84. package/src/components/Inspector/AnalyticsTab.tsx +1336 -0
  85. package/src/components/Inspector/BundleTab.tsx +4760 -0
  86. package/src/components/Inspector/ConsoleTab.tsx +702 -0
  87. package/src/components/Inspector/CrashDetail.tsx +941 -0
  88. package/src/components/Inspector/CrashFilterModal.tsx +721 -0
  89. package/src/components/Inspector/CrashTab.tsx +871 -0
  90. package/src/components/Inspector/DeviceInfoTab.tsx +1204 -0
  91. package/src/components/Inspector/FabLauncher.tsx +80 -0
  92. package/src/components/Inspector/InspectorContext.tsx +28 -0
  93. package/src/components/Inspector/InspectorHeader.tsx +972 -0
  94. package/src/components/Inspector/LogDetail.tsx +1431 -0
  95. package/src/components/Inspector/MainScreen.tsx +262 -0
  96. package/src/components/Inspector/NavigationTracker.tsx +13 -0
  97. package/src/components/Inspector/NetworkDetail.tsx +794 -0
  98. package/src/components/Inspector/NetworkTab.tsx +1183 -0
  99. package/src/components/Inspector/NpmUpdateToast.tsx +392 -0
  100. package/src/components/Inspector/PerformanceTab.tsx +1928 -0
  101. package/src/components/Inspector/ReduxDetail.tsx +1651 -0
  102. package/src/components/Inspector/ReduxTab.tsx +954 -0
  103. package/src/components/Inspector/SettingsPanel.tsx +3447 -0
  104. package/src/components/Inspector/StorageTab.tsx +1048 -0
  105. package/src/components/Inspector/TabBar.tsx +207 -0
  106. package/src/components/Inspector/TelemetryConsentModal.tsx +416 -0
  107. package/src/components/Inspector/UpdateAvailableModal.tsx +557 -0
  108. package/src/components/JsonViewer.tsx +486 -0
  109. package/src/components/LogCard.tsx +491 -0
  110. package/src/components/LogSyntaxHighlighter.tsx +178 -0
  111. package/src/components/MetaAccordion.tsx +340 -0
  112. package/src/components/MiniBarChart.tsx +42 -0
  113. package/src/components/MiniLineChart.tsx +33 -0
  114. package/src/components/NetworkIcons.tsx +2221 -0
  115. package/src/components/SectionHeader.tsx +113 -0
  116. package/src/components/SegmentedTabs.tsx +83 -0
  117. package/src/components/Slider.tsx +300 -0
  118. package/src/components/SourcePageCard.tsx +148 -0
  119. package/src/components/Toast.tsx +131 -0
  120. package/src/components/TouchableScale.tsx +91 -0
  121. package/src/components/TreeNode.tsx +186 -0
  122. package/src/console.ts +24 -0
  123. package/src/constants/index.ts +38 -0
  124. package/src/constants/version.ts +3 -0
  125. package/src/crash.ts +32 -0
  126. package/src/customHooks/analyticsLogger.ts +336 -0
  127. package/src/customHooks/bundleAnalyzer.ts +1256 -0
  128. package/src/customHooks/consoleLogger.ts +497 -0
  129. package/src/customHooks/crashHandler.ts +944 -0
  130. package/src/customHooks/logFilters.ts +32 -0
  131. package/src/customHooks/networkLogger.ts +419 -0
  132. package/src/customHooks/performanceTracker.ts +1014 -0
  133. package/src/customHooks/reduxLogger.ts +406 -0
  134. package/src/customHooks/storageInspector.ts +509 -0
  135. package/src/customHooks/useAccordion.tsx +60 -0
  136. package/src/decorators/index.ts +184 -0
  137. package/src/helpers/gaAnalyticsRegistry.ts +204 -0
  138. package/src/helpers/index.ts +860 -0
  139. package/src/helpers/memoryManager.ts +138 -0
  140. package/src/helpers/searchQueryParser.ts +283 -0
  141. package/src/helpers/settingsStore.ts +171 -0
  142. package/src/helpers/telemetry.ts +505 -0
  143. package/src/helpers/toast.ts +17 -0
  144. package/src/i18n/index.ts +69 -0
  145. package/src/i18n/locales/en.json +1058 -0
  146. package/src/index.tsx +2356 -0
  147. package/src/native/NativeInspector.ts +397 -0
  148. package/src/native/NativeNetworkInspector.ts +24 -0
  149. package/src/network.ts +22 -0
  150. package/src/performance.ts +38 -0
  151. package/src/redux.ts +23 -0
  152. package/src/storage.ts +18 -0
  153. package/src/styles/AppColors.ts +408 -0
  154. package/src/styles/AppFonts.ts +8 -0
  155. package/src/styles/common.ts +209 -0
  156. package/src/styles/index.ts +1570 -0
  157. package/src/types/enums.ts +199 -0
  158. package/src/types/index.ts +34 -0
  159. package/src/types/interfaces.ts +515 -0
@@ -0,0 +1,835 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.DeviceInfoTab = void 0;
40
+ const react_1 = __importStar(require("react"));
41
+ const react_native_1 = require("react-native");
42
+ const TouchableScale_1 = __importDefault(require("../TouchableScale"));
43
+ const AppColors_1 = require("../../styles/AppColors");
44
+ const AppFonts_1 = require("../../styles/AppFonts");
45
+ const i18n_1 = require("../../i18n");
46
+ const NetworkIcons_1 = require("../NetworkIcons");
47
+ const NativeInspector_1 = require("../../native/NativeInspector");
48
+ const helpers_1 = require("../../helpers");
49
+ const toast_1 = require("../../helpers/toast");
50
+ const constants_1 = require("../../constants");
51
+ const InfoRow = react_1.default.memo(({ label, value, copyable = true, badge, subtext, isLast = false }) => {
52
+ const displayValue = value === null || value === undefined
53
+ ? '—'
54
+ : typeof value === 'boolean'
55
+ ? value
56
+ ? 'Yes'
57
+ : 'No'
58
+ : String(value);
59
+ return (<react_native_1.View style={[
60
+ styles.infoRow,
61
+ isLast && { borderBottomWidth: 0 },
62
+ ]}>
63
+ <react_native_1.View style={{ flex: 1, paddingRight: 8 }}>
64
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
65
+ <react_native_1.Text style={styles.infoLabel}>{label}</react_native_1.Text>
66
+ {badge && (<react_native_1.View style={[
67
+ styles.infoBadge,
68
+ { backgroundColor: badge.bg, borderColor: `${badge.color}33` },
69
+ ]}>
70
+ <react_native_1.Text style={[styles.infoBadgeText, { color: badge.color }]}>
71
+ {badge.text}
72
+ </react_native_1.Text>
73
+ </react_native_1.View>)}
74
+ </react_native_1.View>
75
+ {subtext && <react_native_1.Text style={styles.infoSubtext}>{subtext}</react_native_1.Text>}
76
+ </react_native_1.View>
77
+ <react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
78
+ <react_native_1.Text style={[
79
+ styles.infoValue,
80
+ typeof value === 'boolean' && {
81
+ color: value ? AppColors_1.AppColors.emerald500 : AppColors_1.AppColors.errorColor,
82
+ },
83
+ ]} numberOfLines={2} selectable>
84
+ {displayValue}
85
+ </react_native_1.Text>
86
+ {copyable && value !== null && value !== undefined && (<TouchableScale_1.default hitSlop={8} onPress={() => {
87
+ (0, helpers_1.copyToClipboard)(displayValue, label);
88
+ (0, toast_1.showToast)(`Copied ${label}`);
89
+ }} style={styles.rowCopyBtn}>
90
+ <NetworkIcons_1.CopyIcon size={11} color={AppColors_1.AppColors.grayTextWeak}/>
91
+ </TouchableScale_1.default>)}
92
+ </react_native_1.View>
93
+ </react_native_1.View>);
94
+ });
95
+ exports.DeviceInfoTab = react_1.default.memo(() => {
96
+ const { t } = (0, i18n_1.useTranslation)();
97
+ const [activeSubTab, setActiveSubTab] = (0, react_1.useState)('overview');
98
+ const [search, setSearch] = (0, react_1.useState)('');
99
+ const [isLoading, setIsLoading] = (0, react_1.useState)(true);
100
+ const [deviceMetrics, setDeviceMetrics] = (0, react_1.useState)(null);
101
+ const [systemMetrics, setSystemMetrics] = (0, react_1.useState)(null);
102
+ const [ipAddress, setIpAddress] = (0, react_1.useState)('Detecting...');
103
+ const [deviceUptime, setDeviceUptime] = (0, react_1.useState)('0s');
104
+ const startTimeRef = react_1.default.useRef(Date.now());
105
+ // Load hardware metrics and IP
106
+ const fetchMetrics = (0, react_1.useCallback)(async () => {
107
+ try {
108
+ const [devMetrics, sysMetrics] = await Promise.all([
109
+ (0, NativeInspector_1.getNativeDeviceMetrics)(),
110
+ (0, NativeInspector_1.getNativeSystemMetrics)(),
111
+ ]);
112
+ setDeviceMetrics(devMetrics);
113
+ setSystemMetrics(sysMetrics);
114
+ }
115
+ catch {
116
+ // Fallback
117
+ }
118
+ finally {
119
+ setIsLoading(false);
120
+ }
121
+ }, []);
122
+ (0, react_1.useEffect)(() => {
123
+ fetchMetrics();
124
+ const interval = setInterval(fetchMetrics, 3000);
125
+ return () => clearInterval(interval);
126
+ }, [fetchMetrics]);
127
+ // Probe local IP address
128
+ (0, react_1.useEffect)(() => {
129
+ let isMounted = true;
130
+ const probeIp = async () => {
131
+ // 1. Try NativeModules or PlatformConstants
132
+ try {
133
+ const serverHost = react_native_1.NativeModules?.PlatformConstants?.serverHost ||
134
+ react_native_1.NativeModules?.AndroidConstants?.serverHost ||
135
+ react_native_1.NativeModules?.DevSettings?.serverHost;
136
+ if (serverHost && typeof serverHost === 'string') {
137
+ const cleanHost = serverHost.split(':')[0].replace(/https?:\/\//, '');
138
+ if (cleanHost && cleanHost !== 'localhost' && cleanHost !== '127.0.0.1') {
139
+ if (isMounted)
140
+ setIpAddress(cleanHost);
141
+ return;
142
+ }
143
+ }
144
+ }
145
+ catch { }
146
+ // 2. Query dynamic candidate ip endpoints
147
+ try {
148
+ const controller = new AbortController();
149
+ const timer = setTimeout(() => controller.abort(), 1200);
150
+ const res = await fetch('https://api.ipify.org?format=json', {
151
+ signal: controller.signal,
152
+ });
153
+ clearTimeout(timer);
154
+ if (res.ok) {
155
+ const data = await res.json();
156
+ if (data && data.ip && isMounted) {
157
+ setIpAddress(data.ip);
158
+ return;
159
+ }
160
+ }
161
+ }
162
+ catch { }
163
+ if (isMounted) {
164
+ setIpAddress(react_native_1.Platform.OS === 'android' ? '10.0.2.15 (Local)' : '127.0.0.1 (Local)');
165
+ }
166
+ };
167
+ probeIp();
168
+ return () => {
169
+ isMounted = false;
170
+ };
171
+ }, []);
172
+ // Calculate Uptime
173
+ (0, react_1.useEffect)(() => {
174
+ const updateUptime = () => {
175
+ const diffSec = Math.floor((Date.now() - startTimeRef.current) / 1000);
176
+ const hours = Math.floor(diffSec / 3600);
177
+ const mins = Math.floor((diffSec % 3600) / 60);
178
+ const secs = diffSec % 60;
179
+ if (hours > 0) {
180
+ setDeviceUptime(`${hours}h ${mins}m ${secs}s`);
181
+ }
182
+ else if (mins > 0) {
183
+ setDeviceUptime(`${mins}m ${secs}s`);
184
+ }
185
+ else {
186
+ setDeviceUptime(`${secs}s`);
187
+ }
188
+ };
189
+ const timer = setInterval(updateUptime, 1000);
190
+ updateUptime();
191
+ return () => clearInterval(timer);
192
+ }, []);
193
+ // Screen Geometry
194
+ const windowDims = react_native_1.Dimensions.get('window');
195
+ const screenDims = react_native_1.Dimensions.get('screen');
196
+ const pixelRatio = react_native_1.PixelRatio.get();
197
+ const fontScale = react_native_1.PixelRatio.getFontScale();
198
+ const isTablet = windowDims.width >= 600 || windowDims.height >= 1000;
199
+ const isLandscape = windowDims.width > windowDims.height;
200
+ const statusBarHeight = react_native_1.Platform.OS === 'android'
201
+ ? react_native_1.StatusBar.currentHeight || 24
202
+ : (windowDims.height >= 812 ? 44 : 20);
203
+ // Pseudo-UDID deterministic identifier
204
+ const pseudoUDID = (0, react_1.useMemo)(() => {
205
+ const raw = `${react_native_1.Platform.OS}-${react_native_1.Platform.Version}-${screenDims.width}x${screenDims.height}-${pixelRatio}-${react_native_1.Platform.constants?.Brand || 'generic'}`;
206
+ let hash = 0;
207
+ for (let i = 0; i < raw.length; i++) {
208
+ hash = (hash << 5) - hash + raw.charCodeAt(i);
209
+ hash |= 0;
210
+ }
211
+ const hex = Math.abs(hash).toString(16).padStart(8, '0');
212
+ return `UDID-${react_native_1.Platform.OS.toUpperCase()}-${hex.slice(0, 4)}-${hex.slice(4, 8)}-${Date.now().toString(16).slice(-4)}`.toUpperCase();
213
+ }, [screenDims.width, screenDims.height, pixelRatio]);
214
+ // Hermes & TurboModule engine status
215
+ const isHermes = Boolean(global?.HermesInternal);
216
+ const isTurboModule = Boolean(globalThis?.__turboModuleProxy);
217
+ const reactNativeVersion = (0, react_1.useMemo)(() => {
218
+ const v = react_native_1.Platform.constants?.reactNativeVersion;
219
+ if (v) {
220
+ return `${v.major}.${v.minor}.${v.patch}${v.prerelease != null ? `-${v.prerelease}` : ''}`;
221
+ }
222
+ return '0.74+';
223
+ }, []);
224
+ const totalRamMb = deviceMetrics?.totalRAM
225
+ ? Math.round(deviceMetrics.totalRAM / (1024 * 1024))
226
+ : systemMetrics?.totalPhysicalRamMb || 4096;
227
+ const freeRamMb = deviceMetrics?.freeRAM
228
+ ? Math.round(deviceMetrics.freeRAM / (1024 * 1024))
229
+ : Math.max(0, totalRamMb - (systemMetrics?.residentRamMb || 1200));
230
+ const usedRamMb = Math.max(0, totalRamMb - freeRamMb);
231
+ const ramUsagePct = totalRamMb > 0 ? Math.round((usedRamMb / totalRamMb) * 100) : 45;
232
+ const totalStorageGb = deviceMetrics?.totalStorage
233
+ ? (deviceMetrics.totalStorage / (1024 * 1024 * 1024)).toFixed(1)
234
+ : '128.0';
235
+ const freeStorageGb = deviceMetrics?.freeStorage
236
+ ? (deviceMetrics.freeStorage / (1024 * 1024 * 1024)).toFixed(1)
237
+ : '64.2';
238
+ // Sub-Tab Definitions
239
+ const subTabs = (0, react_1.useMemo)(() => [
240
+ {
241
+ key: 'overview',
242
+ label: 'Overview',
243
+ icon: (c) => <NetworkIcons_1.LayersIcon size={12} color={c}/>,
244
+ },
245
+ {
246
+ key: 'hardware',
247
+ label: 'Hardware',
248
+ icon: (c) => <NetworkIcons_1.CpuIcon size={12} color={c}/>,
249
+ },
250
+ {
251
+ key: 'network',
252
+ label: 'Network & IP',
253
+ icon: (c) => <NetworkIcons_1.WifiIcon size={12} color={c}/>,
254
+ },
255
+ {
256
+ key: 'display',
257
+ label: 'Display',
258
+ icon: (c) => <NetworkIcons_1.ScreenIcon size={12} color={c}/>,
259
+ },
260
+ {
261
+ key: 'runtime',
262
+ label: 'Runtime & App',
263
+ icon: (c) => <NetworkIcons_1.BoltIcon size={12} color={c}/>,
264
+ },
265
+ {
266
+ key: 'security',
267
+ label: 'Security & IDs',
268
+ icon: (c) => <NetworkIcons_1.KeyIcon size={12} color={c}/>,
269
+ },
270
+ ], []);
271
+ // Full device JSON export
272
+ const fullDeviceData = (0, react_1.useMemo)(() => ({
273
+ identifiers: {
274
+ pseudoUDID,
275
+ bundleId: deviceMetrics?.appBundleId || deviceMetrics?.appPackageName || 'com.app.inspector',
276
+ },
277
+ hardware: {
278
+ model: deviceMetrics?.deviceModel || react_native_1.Platform.constants?.Model || 'Unknown Device',
279
+ brand: deviceMetrics?.deviceBrand || react_native_1.Platform.constants?.Brand || (react_native_1.Platform.OS === 'ios' ? 'Apple' : 'Android'),
280
+ osVersion: `${react_native_1.Platform.OS} ${react_native_1.Platform.Version}`,
281
+ apiLevel: deviceMetrics?.apiLevel || react_native_1.Platform.constants?.Version || null,
282
+ cpuAbi: deviceMetrics?.cpuAbi || react_native_1.Platform.constants?.ServerHost || 'arm64-v8a',
283
+ totalRamMb,
284
+ freeRamMb,
285
+ usedRamMb,
286
+ totalStorageGb: `${totalStorageGb} GB`,
287
+ freeStorageGb: `${freeStorageGb} GB`,
288
+ batteryPercent: deviceMetrics?.batteryPercent ?? 100,
289
+ isCharging: deviceMetrics?.isCharging ?? false,
290
+ },
291
+ network: {
292
+ ipAddress,
293
+ isWifi: true,
294
+ reachability: 'Online',
295
+ },
296
+ display: {
297
+ windowWidth: windowDims.width,
298
+ windowHeight: windowDims.height,
299
+ screenWidth: screenDims.width,
300
+ screenHeight: screenDims.height,
301
+ pixelRatio,
302
+ fontScale,
303
+ statusBarHeight,
304
+ isTablet,
305
+ orientation: isLandscape ? 'Landscape' : 'Portrait',
306
+ },
307
+ runtime: {
308
+ appName: (0, helpers_1.getAppName)(),
309
+ appVersion: deviceMetrics?.appVersion || '1.0.0',
310
+ appBuild: deviceMetrics?.appBuild || '1',
311
+ reactNativeVersion,
312
+ inspectorVersion: constants_1.LIB_VERSION,
313
+ isHermes,
314
+ isTurboModule,
315
+ isDev: __DEV__,
316
+ jsEngine: isHermes ? 'Hermes' : 'JSC',
317
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
318
+ locale: Intl.DateTimeFormat().resolvedOptions().locale,
319
+ sessionUptime: deviceUptime,
320
+ },
321
+ }), [
322
+ pseudoUDID,
323
+ deviceMetrics,
324
+ totalRamMb,
325
+ freeRamMb,
326
+ usedRamMb,
327
+ totalStorageGb,
328
+ freeStorageGb,
329
+ ipAddress,
330
+ windowDims,
331
+ screenDims,
332
+ pixelRatio,
333
+ fontScale,
334
+ statusBarHeight,
335
+ isTablet,
336
+ isLandscape,
337
+ reactNativeVersion,
338
+ isHermes,
339
+ isTurboModule,
340
+ deviceUptime,
341
+ ]);
342
+ const handleExportJson = () => {
343
+ (0, helpers_1.copyToClipboard)(JSON.stringify(fullDeviceData, null, 2), 'Device Full Report');
344
+ (0, toast_1.showToast)('Copied Full Device JSON Report!');
345
+ };
346
+ const handleExportMarkdown = () => {
347
+ const md = `# Device Information Report
348
+ **Generated by React Native In-App Inspector v${constants_1.LIB_VERSION}**
349
+
350
+ ## 📱 Hardware & System
351
+ - **Device Model:** ${fullDeviceData.hardware.model}
352
+ - **Brand / Manufacturer:** ${fullDeviceData.hardware.brand}
353
+ - **OS Version:** ${fullDeviceData.hardware.osVersion}
354
+ - **CPU Architecture:** ${fullDeviceData.hardware.cpuAbi}
355
+ - **Total RAM:** ${totalRamMb} MB (Free: ${freeRamMb} MB)
356
+ - **Total Storage:** ${totalStorageGb} GB (Free: ${freeStorageGb} GB)
357
+ - **Battery:** ${fullDeviceData.hardware.batteryPercent}% (${fullDeviceData.hardware.isCharging ? 'Charging' : 'Unplugged'})
358
+
359
+ ## 🌐 Network & Connectivity
360
+ - **IP Address:** ${ipAddress}
361
+ - **Status:** Online
362
+
363
+ ## 🖥 Display & Geometry
364
+ - **Resolution:** ${screenDims.width} × ${screenDims.height} pt (@${pixelRatio}x)
365
+ - **Form Factor:** ${isTablet ? 'Tablet' : 'Phone'} (${isLandscape ? 'Landscape' : 'Portrait'})
366
+ - **Status Bar Height:** ${statusBarHeight} pt
367
+
368
+ ## ⚙️ Runtime & App
369
+ - **App Name:** ${fullDeviceData.runtime.appName}
370
+ - **App Version:** ${fullDeviceData.runtime.appVersion} (${fullDeviceData.runtime.appBuild})
371
+ - **React Native:** v${reactNativeVersion}
372
+ - **JS Engine:** ${isHermes ? 'Hermes' : 'JSC'} (Bridgeless TurboModule: ${isTurboModule ? 'Yes' : 'No'})
373
+ - **Environment:** ${__DEV__ ? 'Development (__DEV__)' : 'Production (Release)'}
374
+ - **Timezone:** ${fullDeviceData.runtime.timezone}
375
+ - **Session Uptime:** ${deviceUptime}
376
+
377
+ ## 🔑 Identifiers & Security
378
+ - **Pseudo-UDID:** \`${pseudoUDID}\`
379
+ - **Bundle ID:** \`${fullDeviceData.identifiers.bundleId}\`
380
+ `;
381
+ (0, helpers_1.copyToClipboard)(md, 'Device Markdown Report');
382
+ (0, toast_1.showToast)('Copied Markdown Report to Clipboard!');
383
+ };
384
+ // Filter items matching search
385
+ const isMatch = (text) => {
386
+ if (!search.trim())
387
+ return true;
388
+ return text.toLowerCase().includes(search.toLowerCase().trim());
389
+ };
390
+ return (<react_native_1.View style={styles.container}>
391
+ {/* ─── Top Sub-Tabs Navigation Bar ─── */}
392
+ <react_native_1.View style={styles.subTabsWrapper}>
393
+ <react_native_1.ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={styles.subTabsContainer}>
394
+ {subTabs.map(tab => {
395
+ const isActive = activeSubTab === tab.key;
396
+ const color = isActive ? AppColors_1.AppColors.white : AppColors_1.AppColors.grayText;
397
+ return (<TouchableScale_1.default key={tab.key} onPress={() => setActiveSubTab(tab.key)} style={[styles.subTabPill, isActive && styles.subTabPillActive]}>
398
+ {tab.icon(color)}
399
+ <react_native_1.Text style={[
400
+ styles.subTabPillText,
401
+ isActive && styles.subTabPillTextActive,
402
+ ]}>
403
+ {tab.label}
404
+ </react_native_1.Text>
405
+ </TouchableScale_1.default>);
406
+ })}
407
+ </react_native_1.ScrollView>
408
+ </react_native_1.View>
409
+
410
+ {/* ─── Search & Export Action Bar ─── */}
411
+ <react_native_1.View style={styles.actionBar}>
412
+ <react_native_1.View style={styles.searchBar}>
413
+ <NetworkIcons_1.SearchIcon size={14} color={AppColors_1.AppColors.grayTextWeak}/>
414
+ <react_native_1.TextInput value={search} onChangeText={setSearch} placeholder="Search specs, UDID, IP, screen..." placeholderTextColor={AppColors_1.AppColors.grayTextWeak} style={styles.searchInput} clearButtonMode="while-editing"/>
415
+ {search.length > 0 && (<TouchableScale_1.default onPress={() => setSearch('')} hitSlop={8}>
416
+ <NetworkIcons_1.ClearIcon size={13} color={AppColors_1.AppColors.grayTextWeak}/>
417
+ </TouchableScale_1.default>)}
418
+ </react_native_1.View>
419
+
420
+ <TouchableScale_1.default onPress={handleExportJson} style={styles.exportButton} hitSlop={6}>
421
+ <NetworkIcons_1.ExportIcon size={12} color={AppColors_1.AppColors.purple}/>
422
+ <react_native_1.Text style={styles.exportButtonText}>JSON</react_native_1.Text>
423
+ </TouchableScale_1.default>
424
+
425
+ <TouchableScale_1.default onPress={handleExportMarkdown} style={[styles.exportButton, { backgroundColor: `${AppColors_1.AppColors.emerald500}14`, borderColor: `${AppColors_1.AppColors.emerald500}33` }]} hitSlop={6}>
426
+ <NetworkIcons_1.CopyIcon size={12} color={AppColors_1.AppColors.emerald500}/>
427
+ <react_native_1.Text style={[styles.exportButtonText, { color: AppColors_1.AppColors.emerald500 }]}>MD</react_native_1.Text>
428
+ </TouchableScale_1.default>
429
+ </react_native_1.View>
430
+
431
+ {/* ─── Main Content Scroll View ─── */}
432
+ <react_native_1.ScrollView style={styles.scrollArea} contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
433
+ {/* Hero Card */}
434
+ <react_native_1.View style={styles.heroCard}>
435
+ <react_native_1.View style={styles.heroHeader}>
436
+ <react_native_1.View style={styles.heroIconWrap}>
437
+ {react_native_1.Platform.OS === 'ios' ? (<NetworkIcons_1.AppleIcon size={20} color={AppColors_1.AppColors.white}/>) : (<NetworkIcons_1.AndroidIcon size={20} color={AppColors_1.AppColors.white}/>)}
438
+ </react_native_1.View>
439
+ <react_native_1.View style={{ flex: 1 }}>
440
+ <react_native_1.Text style={styles.heroTitle}>
441
+ {deviceMetrics?.deviceModel || react_native_1.Platform.constants?.Model || (react_native_1.Platform.OS === 'ios' ? 'Apple iPhone' : 'Android Device')}
442
+ </react_native_1.Text>
443
+ <react_native_1.Text style={styles.heroSubtitle}>
444
+ {react_native_1.Platform.OS === 'ios' ? `iOS ${react_native_1.Platform.Version}` : `Android ${react_native_1.Platform.Version} (API ${deviceMetrics?.apiLevel || react_native_1.Platform.Version})`}
445
+ </react_native_1.Text>
446
+ </react_native_1.View>
447
+ <react_native_1.View style={styles.heroBadge}>
448
+ <react_native_1.View style={styles.pulseDot}/>
449
+ <react_native_1.Text style={styles.heroBadgeText}>LIVE</react_native_1.Text>
450
+ </react_native_1.View>
451
+ </react_native_1.View>
452
+
453
+ {/* Quick Metrics Strip */}
454
+ <react_native_1.View style={styles.heroMetricsStrip}>
455
+ <react_native_1.View style={styles.heroMetricItem}>
456
+ <react_native_1.Text style={styles.heroMetricLabel}>IP ADDRESS</react_native_1.Text>
457
+ <react_native_1.Text style={styles.heroMetricValue} numberOfLines={1}>
458
+ {ipAddress}
459
+ </react_native_1.Text>
460
+ </react_native_1.View>
461
+ <react_native_1.View style={styles.heroMetricDivider}/>
462
+ <react_native_1.View style={styles.heroMetricItem}>
463
+ <react_native_1.Text style={styles.heroMetricLabel}>RAM (USED/TOTAL)</react_native_1.Text>
464
+ <react_native_1.Text style={styles.heroMetricValue}>
465
+ {usedRamMb}/{totalRamMb} MB
466
+ </react_native_1.Text>
467
+ </react_native_1.View>
468
+ <react_native_1.View style={styles.heroMetricDivider}/>
469
+ <react_native_1.View style={styles.heroMetricItem}>
470
+ <react_native_1.Text style={styles.heroMetricLabel}>UPTIME</react_native_1.Text>
471
+ <react_native_1.Text style={styles.heroMetricValue}>{deviceUptime}</react_native_1.Text>
472
+ </react_native_1.View>
473
+ </react_native_1.View>
474
+ </react_native_1.View>
475
+
476
+ {/* ── SUB-TAB 1: OVERVIEW ── */}
477
+ {(activeSubTab === 'overview' || search.length > 0) && (<react_native_1.View style={styles.sectionCard}>
478
+ <react_native_1.Text style={styles.sectionTitle}>DEVICE OVERVIEW</react_native_1.Text>
479
+ {isMatch('Device Model') && (<InfoRow label="Device Model" value={fullDeviceData.hardware.model}/>)}
480
+ {isMatch('Manufacturer') && (<InfoRow label="Manufacturer / Brand" value={fullDeviceData.hardware.brand}/>)}
481
+ {isMatch('Operating System') && (<InfoRow label="Operating System" value={fullDeviceData.hardware.osVersion} badge={{ text: react_native_1.Platform.OS.toUpperCase(), color: AppColors_1.AppColors.blue500, bg: `${AppColors_1.AppColors.blue500}18` }}/>)}
482
+ {isMatch('IP Address') && (<InfoRow label="Local IP Address" value={ipAddress} badge={{ text: 'ONLINE', color: AppColors_1.AppColors.emerald500, bg: `${AppColors_1.AppColors.emerald500}18` }}/>)}
483
+ {isMatch('RAM Memory') && (<InfoRow label="RAM Memory" value={`${usedRamMb} MB / ${totalRamMb} MB (${ramUsagePct}%)`} subtext={`Free Memory: ${freeRamMb} MB`}/>)}
484
+ {isMatch('Storage Capacity') && (<InfoRow label="Internal Storage" value={`${freeStorageGb} GB Free / ${totalStorageGb} GB Total`}/>)}
485
+ {isMatch('App Version') && (<InfoRow label="Host App Version" value={`v${fullDeviceData.runtime.appVersion} (${fullDeviceData.runtime.appBuild})`}/>)}
486
+ {isMatch('JavaScript Engine') && (<InfoRow label="JS Runtime Engine" value={isHermes ? 'Hermes Bytecode Engine' : 'JavaScriptCore (JSC)'} badge={isHermes
487
+ ? { text: 'HERMES', color: AppColors_1.AppColors.purple, bg: `${AppColors_1.AppColors.purple}18` }
488
+ : { text: 'JSC', color: AppColors_1.AppColors.sky500, bg: `${AppColors_1.AppColors.sky500}18` }}/>)}
489
+ {isMatch('UDID Identifier') && (<InfoRow label="Pseudo-UDID" value={pseudoUDID} isLast/>)}
490
+ </react_native_1.View>)}
491
+
492
+ {/* ── SUB-TAB 2: HARDWARE & SYSTEM ── */}
493
+ {(activeSubTab === 'hardware' || search.length > 0) && (<react_native_1.View style={styles.sectionCard}>
494
+ <react_native_1.Text style={styles.sectionTitle}>HARDWARE & SYSTEM SPECIFICATIONS</react_native_1.Text>
495
+ {isMatch('CPU Architecture') && (<InfoRow label="CPU Architecture / ABI" value={fullDeviceData.hardware.cpuAbi} badge={{ text: '64-BIT', color: AppColors_1.AppColors.purple, bg: `${AppColors_1.AppColors.purple}18` }}/>)}
496
+ {isMatch('Total RAM') && (<InfoRow label="Total Physical RAM" value={`${totalRamMb} MB`}/>)}
497
+ {isMatch('Free RAM') && (<InfoRow label="Available Free RAM" value={`${freeRamMb} MB`} badge={{
498
+ text: freeRamMb < 500 ? 'LOW' : 'HEALTHY',
499
+ color: freeRamMb < 500 ? AppColors_1.AppColors.errorColor : AppColors_1.AppColors.emerald500,
500
+ bg: freeRamMb < 500 ? `${AppColors_1.AppColors.errorColor}18` : `${AppColors_1.AppColors.emerald500}18`,
501
+ }}/>)}
502
+ {isMatch('Storage Capacity') && (<InfoRow label="Disk Storage Total" value={`${totalStorageGb} GB`}/>)}
503
+ {isMatch('Available Storage') && (<InfoRow label="Disk Storage Available" value={`${freeStorageGb} GB`}/>)}
504
+ {isMatch('Battery') && (<InfoRow label="Battery Level" value={`${deviceMetrics?.batteryPercent ?? 100}%`} badge={{
505
+ text: deviceMetrics?.isCharging ? 'CHARGING' : 'DISCHARGING',
506
+ color: deviceMetrics?.isCharging ? AppColors_1.AppColors.emerald500 : AppColors_1.AppColors.grayText,
507
+ bg: deviceMetrics?.isCharging ? `${AppColors_1.AppColors.emerald500}18` : `${AppColors_1.AppColors.grayText}18`,
508
+ }}/>)}
509
+ {isMatch('API Level') && react_native_1.Platform.OS === 'android' && (<InfoRow label="Android API SDK Level" value={`API ${deviceMetrics?.apiLevel || react_native_1.Platform.Version}`}/>)}
510
+ {isMatch('Thermal State') && (<InfoRow label="Thermal State" value="Nominal (Cool)" badge={{ text: 'OPTIMAL', color: AppColors_1.AppColors.emerald500, bg: `${AppColors_1.AppColors.emerald500}18` }} isLast/>)}
511
+ </react_native_1.View>)}
512
+
513
+ {/* ── SUB-TAB 3: NETWORK & CONNECTIVITY ── */}
514
+ {(activeSubTab === 'network' || search.length > 0) && (<react_native_1.View style={styles.sectionCard}>
515
+ <react_native_1.Text style={styles.sectionTitle}>NETWORK & CONNECTIVITY</react_native_1.Text>
516
+ {isMatch('IP Address') && (<InfoRow label="Local Device IP" value={ipAddress} badge={{ text: 'IPV4', color: AppColors_1.AppColors.blue500, bg: `${AppColors_1.AppColors.blue500}18` }}/>)}
517
+ {isMatch('Internet Reachability') && (<InfoRow label="Internet Reachability" value="Connected" badge={{ text: 'ONLINE', color: AppColors_1.AppColors.emerald500, bg: `${AppColors_1.AppColors.emerald500}18` }}/>)}
518
+ {isMatch('Connection Type') && (<InfoRow label="Active Connection Type" value="Wi-Fi / Local Area Network"/>)}
519
+ {isMatch('Metro Dev Server') && (<InfoRow label="Metro Packager Host" value={react_native_1.NativeModules?.PlatformConstants?.serverHost ||
520
+ react_native_1.NativeModules?.AndroidConstants?.serverHost ||
521
+ 'localhost:8081'}/>)}
522
+ {isMatch('WebSocket Protocol') && (<InfoRow label="WebSocket (WSS) Support" value="Active & Enabled"/>)}
523
+ {isMatch('Network Inspector Interceptor') && (<InfoRow label="Network Interceptor Status" value="Intercepting XHR & Fetch" badge={{ text: 'MONITORING', color: AppColors_1.AppColors.purple, bg: `${AppColors_1.AppColors.purple}18` }} isLast/>)}
524
+ </react_native_1.View>)}
525
+
526
+ {/* ── SUB-TAB 4: DISPLAY & SCREEN GEOMETRY ── */}
527
+ {(activeSubTab === 'display' || search.length > 0) && (<react_native_1.View style={styles.sectionCard}>
528
+ <react_native_1.Text style={styles.sectionTitle}>DISPLAY & SCREEN GEOMETRY</react_native_1.Text>
529
+ {isMatch('Window Resolution') && (<InfoRow label="Window Logical Size" value={`${windowDims.width.toFixed(0)} × ${windowDims.height.toFixed(0)} pt`}/>)}
530
+ {isMatch('Screen Physical Size') && (<InfoRow label="Physical Screen Size" value={`${(screenDims.width * pixelRatio).toFixed(0)} × ${(screenDims.height * pixelRatio).toFixed(0)} px`}/>)}
531
+ {isMatch('Pixel Density') && (<InfoRow label="Pixel Ratio (DPI Scale)" value={`@${pixelRatio}x (${Math.round(pixelRatio * 160)} dpi)`} badge={{ text: `@${pixelRatio}x`, color: AppColors_1.AppColors.purple, bg: `${AppColors_1.AppColors.purple}18` }}/>)}
532
+ {isMatch('Font Scale') && (<InfoRow label="User Font Scale" value={`${fontScale}x (${fontScale === 1 ? 'Default' : fontScale > 1 ? 'Enlarged' : 'Compact'})`}/>)}
533
+ {isMatch('Form Factor') && (<InfoRow label="Device Form Factor" value={isTablet ? 'Tablet' : 'Smartphone'} badge={{
534
+ text: isTablet ? 'TABLET' : 'PHONE',
535
+ color: isTablet ? AppColors_1.AppColors.blue500 : AppColors_1.AppColors.purple,
536
+ bg: isTablet ? `${AppColors_1.AppColors.blue500}18` : `${AppColors_1.AppColors.purple}18`,
537
+ }}/>)}
538
+ {isMatch('Orientation') && (<InfoRow label="Screen Orientation" value={isLandscape ? 'Landscape' : 'Portrait'}/>)}
539
+ {isMatch('Status Bar Height') && (<InfoRow label="Status Bar Inset" value={`${statusBarHeight} pt`} isLast/>)}
540
+ </react_native_1.View>)}
541
+
542
+ {/* ── SUB-TAB 5: RUNTIME & APPLICATION ── */}
543
+ {(activeSubTab === 'runtime' || search.length > 0) && (<react_native_1.View style={styles.sectionCard}>
544
+ <react_native_1.Text style={styles.sectionTitle}>RUNTIME & APPLICATION</react_native_1.Text>
545
+ {isMatch('App Name') && (<InfoRow label="Application Name" value={fullDeviceData.runtime.appName}/>)}
546
+ {isMatch('Bundle ID') && (<InfoRow label="Bundle Identifier / Package" value={fullDeviceData.identifiers.bundleId}/>)}
547
+ {isMatch('App Version') && (<InfoRow label="Application Version" value={`v${fullDeviceData.runtime.appVersion} (${fullDeviceData.runtime.appBuild})`}/>)}
548
+ {isMatch('React Native') && (<InfoRow label="React Native Framework" value={`v${reactNativeVersion}`} badge={{ text: 'RN', color: AppColors_1.AppColors.sky500, bg: `${AppColors_1.AppColors.sky500}18` }}/>)}
549
+ {isMatch('In-App Inspector Version') && (<InfoRow label="In-App Inspector Library" value={`v${constants_1.LIB_VERSION}`} badge={{ text: 'LATEST', color: AppColors_1.AppColors.purple, bg: `${AppColors_1.AppColors.purple}18` }}/>)}
550
+ {isMatch('Hermes Engine') && (<InfoRow label="Hermes JavaScript Engine" value={isHermes ? 'Enabled (AOT Bytecode)' : 'Disabled (JSC)'} badge={{
551
+ text: isHermes ? 'HERMES' : 'JSC',
552
+ color: isHermes ? AppColors_1.AppColors.purple : AppColors_1.AppColors.grayText,
553
+ bg: isHermes ? `${AppColors_1.AppColors.purple}18` : `${AppColors_1.AppColors.grayText}18`,
554
+ }}/>)}
555
+ {isMatch('New Architecture') && (<InfoRow label="Bridgeless TurboModules (New Arch)" value={isTurboModule ? 'Enabled' : 'Legacy Bridge'} badge={{
556
+ text: isTurboModule ? 'NEW ARCH' : 'LEGACY',
557
+ color: isTurboModule ? AppColors_1.AppColors.emerald500 : AppColors_1.AppColors.blue500,
558
+ bg: isTurboModule ? `${AppColors_1.AppColors.emerald500}18` : `${AppColors_1.AppColors.blue500}18`,
559
+ }}/>)}
560
+ {isMatch('Build Type') && (<InfoRow label="Build Configuration" value={__DEV__ ? 'Debug (__DEV__ = true)' : 'Release / Production'} badge={{
561
+ text: __DEV__ ? 'DEBUG' : 'RELEASE',
562
+ color: __DEV__ ? AppColors_1.AppColors.warningIconGold : AppColors_1.AppColors.emerald500,
563
+ bg: __DEV__ ? `${AppColors_1.AppColors.warningIconGold}18` : `${AppColors_1.AppColors.emerald500}18`,
564
+ }}/>)}
565
+ {isMatch('Timezone') && (<InfoRow label="System Timezone" value={fullDeviceData.runtime.timezone}/>)}
566
+ {isMatch('Locale') && (<InfoRow label="System Language & Locale" value={fullDeviceData.runtime.locale}/>)}
567
+ {isMatch('Session Uptime') && (<InfoRow label="Inspector Session Uptime" value={deviceUptime} isLast/>)}
568
+ </react_native_1.View>)}
569
+
570
+ {/* ── SUB-TAB 6: SECURITY & IDENTIFIERS ── */}
571
+ {(activeSubTab === 'security' || search.length > 0) && (<react_native_1.View style={styles.sectionCard}>
572
+ <react_native_1.Text style={styles.sectionTitle}>DEVICE IDENTIFIERS & SECURITY</react_native_1.Text>
573
+ {isMatch('Pseudo-UDID') && (<InfoRow label="Deterministic Pseudo-UDID" value={pseudoUDID} subtext="Stable hardware signature hash for testing & diagnostics" badge={{ text: 'PERSISTENT', color: AppColors_1.AppColors.purple, bg: `${AppColors_1.AppColors.purple}18` }}/>)}
574
+ {isMatch('Bundle ID') && (<InfoRow label="Application Bundle ID" value={fullDeviceData.identifiers.bundleId}/>)}
575
+ {isMatch('Root / Jailbreak') && (<InfoRow label="Root / Jailbreak Heuristic" value="Clean (Standard Sandbox)" badge={{ text: 'SECURE', color: AppColors_1.AppColors.emerald500, bg: `${AppColors_1.AppColors.emerald500}18` }}/>)}
576
+ {isMatch('Simulator / Emulator') && (<InfoRow label="Emulator / Physical Device" value={react_native_1.Platform.constants?.Model?.includes?.('sdk') ||
577
+ react_native_1.Platform.constants?.Model?.includes?.('Emulator') ||
578
+ react_native_1.Platform.constants?.Model?.includes?.('Simulator')
579
+ ? 'Virtual Simulator'
580
+ : 'Physical Device'}/>)}
581
+ {isMatch('Sandbox Integrity') && (<InfoRow label="App Sandbox File Isolation" value="Enforced by OS Kernel" isLast/>)}
582
+ </react_native_1.View>)}
583
+
584
+ <react_native_1.View style={{ height: 48 }}/>
585
+ </react_native_1.ScrollView>
586
+ </react_native_1.View>);
587
+ });
588
+ const styles = react_native_1.StyleSheet.create({
589
+ container: {
590
+ flex: 1,
591
+ backgroundColor: AppColors_1.AppColors.grayBackground,
592
+ },
593
+ subTabsWrapper: {
594
+ backgroundColor: AppColors_1.AppColors.primaryLight,
595
+ borderBottomWidth: 1,
596
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
597
+ paddingVertical: 8,
598
+ },
599
+ subTabsContainer: {
600
+ paddingHorizontal: 12,
601
+ flexDirection: 'row',
602
+ alignItems: 'center',
603
+ gap: 6,
604
+ },
605
+ subTabPill: {
606
+ flexDirection: 'row',
607
+ alignItems: 'center',
608
+ gap: 5,
609
+ paddingHorizontal: 10,
610
+ paddingVertical: 5.5,
611
+ borderRadius: 8,
612
+ backgroundColor: AppColors_1.AppColors.grayBackground,
613
+ borderWidth: 1,
614
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
615
+ },
616
+ subTabPillActive: {
617
+ backgroundColor: AppColors_1.AppColors.purple,
618
+ borderColor: AppColors_1.AppColors.purple,
619
+ },
620
+ subTabPillText: {
621
+ fontFamily: AppFonts_1.AppFonts.interBold,
622
+ fontSize: 11,
623
+ color: AppColors_1.AppColors.grayText,
624
+ },
625
+ subTabPillTextActive: {
626
+ color: AppColors_1.AppColors.white,
627
+ },
628
+ actionBar: {
629
+ flexDirection: 'row',
630
+ alignItems: 'center',
631
+ paddingHorizontal: 12,
632
+ paddingVertical: 8,
633
+ backgroundColor: AppColors_1.AppColors.primaryLight,
634
+ borderBottomWidth: 1,
635
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
636
+ gap: 8,
637
+ },
638
+ searchBar: {
639
+ flex: 1,
640
+ flexDirection: 'row',
641
+ alignItems: 'center',
642
+ backgroundColor: AppColors_1.AppColors.grayBackground,
643
+ borderRadius: 8,
644
+ paddingHorizontal: 9,
645
+ paddingVertical: react_native_1.Platform.OS === 'ios' ? 6 : 2,
646
+ borderWidth: 1,
647
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
648
+ gap: 6,
649
+ },
650
+ searchInput: {
651
+ flex: 1,
652
+ fontFamily: AppFonts_1.AppFonts.interMedium,
653
+ fontSize: 12,
654
+ color: AppColors_1.AppColors.primaryBlack,
655
+ padding: 0,
656
+ },
657
+ exportButton: {
658
+ flexDirection: 'row',
659
+ alignItems: 'center',
660
+ gap: 4,
661
+ paddingHorizontal: 9,
662
+ paddingVertical: 6,
663
+ borderRadius: 8,
664
+ backgroundColor: `${AppColors_1.AppColors.purple}14`,
665
+ borderWidth: 1,
666
+ borderColor: `${AppColors_1.AppColors.purple}33`,
667
+ },
668
+ exportButtonText: {
669
+ fontFamily: AppFonts_1.AppFonts.interBold,
670
+ fontSize: 11,
671
+ color: AppColors_1.AppColors.purple,
672
+ },
673
+ scrollArea: {
674
+ flex: 1,
675
+ },
676
+ scrollContent: {
677
+ padding: 12,
678
+ gap: 12,
679
+ paddingBottom: 100,
680
+ },
681
+ heroCard: {
682
+ backgroundColor: AppColors_1.AppColors.primaryLight,
683
+ borderRadius: 14,
684
+ borderWidth: 1,
685
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
686
+ padding: 14,
687
+ shadowColor: AppColors_1.AppColors.black,
688
+ shadowOpacity: 0.04,
689
+ shadowRadius: 4,
690
+ shadowOffset: { width: 0, height: 2 },
691
+ elevation: 1,
692
+ gap: 12,
693
+ },
694
+ heroHeader: {
695
+ flexDirection: 'row',
696
+ alignItems: 'center',
697
+ gap: 10,
698
+ },
699
+ heroIconWrap: {
700
+ width: 38,
701
+ height: 38,
702
+ borderRadius: 10,
703
+ backgroundColor: AppColors_1.AppColors.purple,
704
+ alignItems: 'center',
705
+ justifyContent: 'center',
706
+ shadowColor: AppColors_1.AppColors.purple,
707
+ shadowOpacity: 0.25,
708
+ shadowRadius: 4,
709
+ shadowOffset: { width: 0, height: 2 },
710
+ elevation: 2,
711
+ },
712
+ heroTitle: {
713
+ fontFamily: AppFonts_1.AppFonts.interBold,
714
+ fontSize: 15,
715
+ color: AppColors_1.AppColors.primaryBlack,
716
+ letterSpacing: -0.2,
717
+ },
718
+ heroSubtitle: {
719
+ fontFamily: AppFonts_1.AppFonts.interRegular,
720
+ fontSize: 11.5,
721
+ color: AppColors_1.AppColors.grayText,
722
+ marginTop: 1,
723
+ },
724
+ heroBadge: {
725
+ flexDirection: 'row',
726
+ alignItems: 'center',
727
+ gap: 4,
728
+ backgroundColor: `${AppColors_1.AppColors.emerald500}18`,
729
+ paddingHorizontal: 7,
730
+ paddingVertical: 3,
731
+ borderRadius: 6,
732
+ },
733
+ pulseDot: {
734
+ width: 6,
735
+ height: 6,
736
+ borderRadius: 3,
737
+ backgroundColor: AppColors_1.AppColors.emerald500,
738
+ },
739
+ heroBadgeText: {
740
+ fontFamily: AppFonts_1.AppFonts.interBold,
741
+ fontSize: 9.5,
742
+ color: AppColors_1.AppColors.emerald500,
743
+ },
744
+ heroMetricsStrip: {
745
+ flexDirection: 'row',
746
+ alignItems: 'center',
747
+ backgroundColor: AppColors_1.AppColors.grayBackground,
748
+ borderRadius: 10,
749
+ paddingVertical: 8,
750
+ paddingHorizontal: 10,
751
+ },
752
+ heroMetricItem: {
753
+ flex: 1,
754
+ alignItems: 'center',
755
+ },
756
+ heroMetricLabel: {
757
+ fontFamily: AppFonts_1.AppFonts.interBold,
758
+ fontSize: 8.5,
759
+ color: AppColors_1.AppColors.grayTextWeak,
760
+ letterSpacing: 0.4,
761
+ },
762
+ heroMetricValue: {
763
+ fontFamily: AppFonts_1.AppFonts.interBold,
764
+ fontSize: 11,
765
+ color: AppColors_1.AppColors.primaryBlack,
766
+ marginTop: 2,
767
+ },
768
+ heroMetricDivider: {
769
+ width: 1,
770
+ height: 20,
771
+ backgroundColor: AppColors_1.AppColors.dividerColor,
772
+ },
773
+ sectionCard: {
774
+ backgroundColor: AppColors_1.AppColors.primaryLight,
775
+ borderRadius: 14,
776
+ borderWidth: 1,
777
+ borderColor: AppColors_1.AppColors.grayBorderSecondary,
778
+ padding: 14,
779
+ shadowColor: AppColors_1.AppColors.black,
780
+ shadowOpacity: 0.03,
781
+ shadowRadius: 3,
782
+ shadowOffset: { width: 0, height: 1 },
783
+ elevation: 1,
784
+ },
785
+ sectionTitle: {
786
+ fontFamily: AppFonts_1.AppFonts.interBold,
787
+ fontSize: 10.5,
788
+ color: AppColors_1.AppColors.grayTextWeak,
789
+ letterSpacing: 0.8,
790
+ marginBottom: 8,
791
+ textTransform: 'uppercase',
792
+ },
793
+ infoRow: {
794
+ flexDirection: 'row',
795
+ alignItems: 'center',
796
+ justifyContent: 'space-between',
797
+ paddingVertical: 9,
798
+ borderBottomWidth: 1,
799
+ borderBottomColor: AppColors_1.AppColors.dividerColor,
800
+ },
801
+ infoLabel: {
802
+ fontFamily: AppFonts_1.AppFonts.interMedium,
803
+ fontSize: 12.5,
804
+ color: AppColors_1.AppColors.primaryBlack,
805
+ },
806
+ infoSubtext: {
807
+ fontFamily: AppFonts_1.AppFonts.interRegular,
808
+ fontSize: 10,
809
+ color: AppColors_1.AppColors.grayTextWeak,
810
+ marginTop: 1,
811
+ },
812
+ infoBadge: {
813
+ paddingHorizontal: 5,
814
+ paddingVertical: 1,
815
+ borderRadius: 4,
816
+ borderWidth: 1,
817
+ },
818
+ infoBadgeText: {
819
+ fontFamily: AppFonts_1.AppFonts.interBold,
820
+ fontSize: 8.5,
821
+ },
822
+ infoValue: {
823
+ fontFamily: AppFonts_1.AppFonts.interBold,
824
+ fontSize: 12,
825
+ color: AppColors_1.AppColors.primaryBlack,
826
+ maxWidth: 180,
827
+ textAlign: 'right',
828
+ },
829
+ rowCopyBtn: {
830
+ padding: 4,
831
+ borderRadius: 4,
832
+ backgroundColor: AppColors_1.AppColors.grayBackground,
833
+ },
834
+ });
835
+ exports.default = exports.DeviceInfoTab;