react-native-inapp-inspector 2.3.5 → 2.3.6

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 (226) hide show
  1. package/dist/commonjs/analytics.d.ts +0 -4
  2. package/dist/commonjs/analytics.js +0 -4
  3. package/dist/commonjs/bundle.d.ts +0 -4
  4. package/dist/commonjs/bundle.js +0 -4
  5. package/dist/commonjs/components/AnalyticsDetail.js +18 -27
  6. package/dist/commonjs/components/AnalyticsEventCard.js +9 -12
  7. package/dist/commonjs/components/AnalyticsGraph.js +10 -15
  8. package/dist/commonjs/components/AppHeaderLogo.js +0 -3
  9. package/dist/commonjs/components/BrandCircleIcon.js +15 -15
  10. package/dist/commonjs/components/BrandSquareIcon.js +20 -20
  11. package/dist/commonjs/components/CodeSnippet.js +6 -19
  12. package/dist/commonjs/components/ConsoleLogCard.js +0 -1
  13. package/dist/commonjs/components/CopyButton.js +0 -4
  14. package/dist/commonjs/components/DiffViewer.js +0 -2
  15. package/dist/commonjs/components/DomainHeader.js +0 -4
  16. package/dist/commonjs/components/EmptyState.js +0 -3
  17. package/dist/commonjs/components/ErrorBoundary.js +5 -10
  18. package/dist/commonjs/components/HeadersSection.js +0 -5
  19. package/dist/commonjs/components/HighlightText.js +1 -4
  20. package/dist/commonjs/components/Inspector/AnalyticsFilterModal.js +11 -26
  21. package/dist/commonjs/components/Inspector/AnalyticsTab.js +34 -40
  22. package/dist/commonjs/components/Inspector/BundleTab.js +56 -84
  23. package/dist/commonjs/components/Inspector/ConsoleTab.js +7 -7
  24. package/dist/commonjs/components/Inspector/CrashDetail.js +18 -20
  25. package/dist/commonjs/components/Inspector/CrashFilterModal.js +0 -1
  26. package/dist/commonjs/components/Inspector/CrashTab.js +11 -20
  27. package/dist/commonjs/components/Inspector/DeviceInfoTab.js +12 -24
  28. package/dist/commonjs/components/Inspector/FabLauncher.js +1 -1
  29. package/dist/commonjs/components/Inspector/InspectorContext.js +0 -2
  30. package/dist/commonjs/components/Inspector/InspectorHeader.js +7 -8
  31. package/dist/commonjs/components/Inspector/LogDetail.js +27 -29
  32. package/dist/commonjs/components/Inspector/MainScreen.js +9 -10
  33. package/dist/commonjs/components/Inspector/NetworkDetail.js +10 -11
  34. package/dist/commonjs/components/Inspector/NetworkTab.js +14 -14
  35. package/dist/commonjs/components/Inspector/NpmUpdateToast.js +6 -9
  36. package/dist/commonjs/components/Inspector/PerformanceTab.js +30 -43
  37. package/dist/commonjs/components/Inspector/ReduxDetail.js +18 -34
  38. package/dist/commonjs/components/Inspector/ReduxTab.js +11 -20
  39. package/dist/commonjs/components/Inspector/SettingsPanel.js +32 -36
  40. package/dist/commonjs/components/Inspector/SkeletonPlaceholder.js +6 -6
  41. package/dist/commonjs/components/Inspector/StorageTab.js +14 -26
  42. package/dist/commonjs/components/Inspector/UpdateAvailableModal.js +5 -6
  43. package/dist/commonjs/components/JsonViewer.js +3 -10
  44. package/dist/commonjs/components/LogCard.js +7 -7
  45. package/dist/commonjs/components/MetaAccordion.js +1 -7
  46. package/dist/commonjs/components/NetworkIcons.js +12 -16
  47. package/dist/commonjs/components/SectionHeader.js +0 -4
  48. package/dist/commonjs/components/SkeletonPlaceholder.js +6 -6
  49. package/dist/commonjs/components/Slider.js +6 -6
  50. package/dist/commonjs/components/SourcePageCard.js +0 -4
  51. package/dist/commonjs/components/TreeNode.js +0 -4
  52. package/dist/commonjs/console.d.ts +0 -4
  53. package/dist/commonjs/console.js +0 -4
  54. package/dist/commonjs/constants/index.js +6 -9
  55. package/dist/commonjs/constants/telemetryConfig.d.ts +7 -0
  56. package/dist/commonjs/constants/telemetryConfig.js +10 -0
  57. package/dist/commonjs/constants/version.d.ts +1 -1
  58. package/dist/commonjs/constants/version.js +1 -3
  59. package/dist/commonjs/crash.d.ts +0 -4
  60. package/dist/commonjs/crash.js +0 -4
  61. package/dist/commonjs/customHooks/analyticsLogger.d.ts +0 -7
  62. package/dist/commonjs/customHooks/analyticsLogger.js +3 -59
  63. package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +0 -9
  64. package/dist/commonjs/customHooks/bundleAnalyzer.js +3 -86
  65. package/dist/commonjs/customHooks/consoleLogger.js +0 -16
  66. package/dist/commonjs/customHooks/crashHandler.d.ts +0 -28
  67. package/dist/commonjs/customHooks/crashHandler.js +0 -55
  68. package/dist/commonjs/customHooks/logFilters.d.ts +0 -4
  69. package/dist/commonjs/customHooks/logFilters.js +0 -11
  70. package/dist/commonjs/customHooks/networkLogger.js +2 -13
  71. package/dist/commonjs/customHooks/performanceTracker.d.ts +0 -27
  72. package/dist/commonjs/customHooks/performanceTracker.js +0 -31
  73. package/dist/commonjs/customHooks/reduxLogger.d.ts +0 -12
  74. package/dist/commonjs/customHooks/reduxLogger.js +0 -51
  75. package/dist/commonjs/customHooks/storageInspector.d.ts +0 -40
  76. package/dist/commonjs/customHooks/storageInspector.js +1 -56
  77. package/dist/commonjs/decorators/index.d.ts +0 -37
  78. package/dist/commonjs/decorators/index.js +0 -42
  79. package/dist/commonjs/helpers/gaAnalyticsRegistry.d.ts +0 -10
  80. package/dist/commonjs/helpers/gaAnalyticsRegistry.js +0 -26
  81. package/dist/commonjs/helpers/index.d.ts +0 -7
  82. package/dist/commonjs/helpers/index.js +1 -42
  83. package/dist/commonjs/helpers/memoryManager.d.ts +0 -11
  84. package/dist/commonjs/helpers/memoryManager.js +0 -13
  85. package/dist/commonjs/helpers/searchQueryParser.d.ts +0 -4
  86. package/dist/commonjs/helpers/searchQueryParser.js +0 -18
  87. package/dist/commonjs/helpers/settingsStore.js +0 -8
  88. package/dist/commonjs/helpers/telemetry.d.ts +2 -0
  89. package/dist/commonjs/helpers/telemetry.js +302 -0
  90. package/dist/commonjs/i18n/index.d.ts +0 -9
  91. package/dist/commonjs/i18n/index.js +0 -15
  92. package/dist/commonjs/index.js +15 -97
  93. package/dist/commonjs/native/NativeInspector.d.ts +0 -54
  94. package/dist/commonjs/native/NativeInspector.js +0 -56
  95. package/dist/commonjs/network.d.ts +0 -4
  96. package/dist/commonjs/network.js +0 -4
  97. package/dist/commonjs/performance.d.ts +0 -4
  98. package/dist/commonjs/performance.js +0 -4
  99. package/dist/commonjs/redux.d.ts +0 -4
  100. package/dist/commonjs/redux.js +0 -4
  101. package/dist/commonjs/storage.d.ts +0 -4
  102. package/dist/commonjs/storage.js +0 -4
  103. package/dist/commonjs/styles/AppColors.d.ts +0 -3
  104. package/dist/commonjs/styles/AppColors.js +15 -30
  105. package/dist/commonjs/styles/AppFonts.d.ts +0 -4
  106. package/dist/commonjs/styles/AppFonts.js +0 -4
  107. package/dist/commonjs/styles/common.js +0 -11
  108. package/dist/commonjs/styles/index.js +0 -8
  109. package/dist/commonjs/types/enums.js +0 -3
  110. package/dist/commonjs/types/interfaces.d.ts +3 -3
  111. package/dist/esm/analytics.d.ts +0 -4
  112. package/dist/esm/analytics.js +0 -4
  113. package/dist/esm/bundle.d.ts +0 -4
  114. package/dist/esm/bundle.js +0 -4
  115. package/dist/esm/components/AnalyticsDetail.js +18 -27
  116. package/dist/esm/components/AnalyticsEventCard.js +9 -12
  117. package/dist/esm/components/AnalyticsGraph.js +10 -15
  118. package/dist/esm/components/AppHeaderLogo.js +0 -3
  119. package/dist/esm/components/BrandCircleIcon.js +15 -15
  120. package/dist/esm/components/BrandSquareIcon.js +20 -20
  121. package/dist/esm/components/CodeSnippet.js +6 -19
  122. package/dist/esm/components/ConsoleLogCard.js +0 -1
  123. package/dist/esm/components/CopyButton.js +0 -4
  124. package/dist/esm/components/DiffViewer.js +0 -2
  125. package/dist/esm/components/DomainHeader.js +0 -4
  126. package/dist/esm/components/EmptyState.js +0 -3
  127. package/dist/esm/components/ErrorBoundary.js +5 -10
  128. package/dist/esm/components/HeadersSection.js +0 -5
  129. package/dist/esm/components/HighlightText.js +1 -4
  130. package/dist/esm/components/Inspector/AnalyticsFilterModal.js +11 -26
  131. package/dist/esm/components/Inspector/AnalyticsTab.js +34 -40
  132. package/dist/esm/components/Inspector/BundleTab.js +56 -84
  133. package/dist/esm/components/Inspector/ConsoleTab.js +7 -7
  134. package/dist/esm/components/Inspector/CrashDetail.js +18 -20
  135. package/dist/esm/components/Inspector/CrashFilterModal.js +0 -1
  136. package/dist/esm/components/Inspector/CrashTab.js +11 -20
  137. package/dist/esm/components/Inspector/DeviceInfoTab.js +12 -24
  138. package/dist/esm/components/Inspector/FabLauncher.js +1 -1
  139. package/dist/esm/components/Inspector/InspectorContext.js +0 -2
  140. package/dist/esm/components/Inspector/InspectorHeader.js +7 -8
  141. package/dist/esm/components/Inspector/LogDetail.js +27 -29
  142. package/dist/esm/components/Inspector/MainScreen.js +9 -10
  143. package/dist/esm/components/Inspector/NetworkDetail.js +10 -11
  144. package/dist/esm/components/Inspector/NetworkTab.js +14 -14
  145. package/dist/esm/components/Inspector/NpmUpdateToast.js +6 -9
  146. package/dist/esm/components/Inspector/PerformanceTab.js +30 -43
  147. package/dist/esm/components/Inspector/ReduxDetail.js +18 -34
  148. package/dist/esm/components/Inspector/ReduxTab.js +11 -20
  149. package/dist/esm/components/Inspector/SettingsPanel.js +32 -36
  150. package/dist/esm/components/Inspector/SkeletonPlaceholder.js +6 -6
  151. package/dist/esm/components/Inspector/StorageTab.js +14 -26
  152. package/dist/esm/components/Inspector/UpdateAvailableModal.js +5 -6
  153. package/dist/esm/components/JsonViewer.js +3 -10
  154. package/dist/esm/components/LogCard.js +7 -7
  155. package/dist/esm/components/MetaAccordion.js +1 -7
  156. package/dist/esm/components/NetworkIcons.js +12 -16
  157. package/dist/esm/components/SectionHeader.js +0 -4
  158. package/dist/esm/components/SkeletonPlaceholder.js +6 -6
  159. package/dist/esm/components/Slider.js +6 -6
  160. package/dist/esm/components/SourcePageCard.js +0 -4
  161. package/dist/esm/components/TreeNode.js +0 -4
  162. package/dist/esm/console.d.ts +0 -4
  163. package/dist/esm/console.js +0 -4
  164. package/dist/esm/constants/index.js +6 -9
  165. package/dist/esm/constants/telemetryConfig.d.ts +7 -0
  166. package/dist/esm/constants/telemetryConfig.js +7 -0
  167. package/dist/esm/constants/version.d.ts +1 -1
  168. package/dist/esm/constants/version.js +1 -3
  169. package/dist/esm/crash.d.ts +0 -4
  170. package/dist/esm/crash.js +0 -4
  171. package/dist/esm/customHooks/analyticsLogger.d.ts +0 -7
  172. package/dist/esm/customHooks/analyticsLogger.js +3 -59
  173. package/dist/esm/customHooks/bundleAnalyzer.d.ts +0 -9
  174. package/dist/esm/customHooks/bundleAnalyzer.js +3 -86
  175. package/dist/esm/customHooks/consoleLogger.js +0 -16
  176. package/dist/esm/customHooks/crashHandler.d.ts +0 -28
  177. package/dist/esm/customHooks/crashHandler.js +0 -55
  178. package/dist/esm/customHooks/logFilters.d.ts +0 -4
  179. package/dist/esm/customHooks/logFilters.js +0 -11
  180. package/dist/esm/customHooks/networkLogger.js +2 -13
  181. package/dist/esm/customHooks/performanceTracker.d.ts +0 -27
  182. package/dist/esm/customHooks/performanceTracker.js +0 -31
  183. package/dist/esm/customHooks/reduxLogger.d.ts +0 -12
  184. package/dist/esm/customHooks/reduxLogger.js +0 -51
  185. package/dist/esm/customHooks/storageInspector.d.ts +0 -40
  186. package/dist/esm/customHooks/storageInspector.js +1 -56
  187. package/dist/esm/decorators/index.d.ts +0 -37
  188. package/dist/esm/decorators/index.js +0 -42
  189. package/dist/esm/helpers/gaAnalyticsRegistry.d.ts +0 -10
  190. package/dist/esm/helpers/gaAnalyticsRegistry.js +0 -26
  191. package/dist/esm/helpers/index.d.ts +0 -7
  192. package/dist/esm/helpers/index.js +1 -42
  193. package/dist/esm/helpers/memoryManager.d.ts +0 -11
  194. package/dist/esm/helpers/memoryManager.js +0 -13
  195. package/dist/esm/helpers/searchQueryParser.d.ts +0 -4
  196. package/dist/esm/helpers/searchQueryParser.js +0 -18
  197. package/dist/esm/helpers/settingsStore.js +0 -8
  198. package/dist/esm/helpers/telemetry.d.ts +2 -0
  199. package/dist/esm/helpers/telemetry.js +298 -0
  200. package/dist/esm/i18n/index.d.ts +0 -9
  201. package/dist/esm/i18n/index.js +0 -15
  202. package/dist/esm/index.js +15 -97
  203. package/dist/esm/native/NativeInspector.d.ts +0 -54
  204. package/dist/esm/native/NativeInspector.js +0 -56
  205. package/dist/esm/network.d.ts +0 -4
  206. package/dist/esm/network.js +0 -4
  207. package/dist/esm/performance.d.ts +0 -4
  208. package/dist/esm/performance.js +0 -4
  209. package/dist/esm/redux.d.ts +0 -4
  210. package/dist/esm/redux.js +0 -4
  211. package/dist/esm/storage.d.ts +0 -4
  212. package/dist/esm/storage.js +0 -4
  213. package/dist/esm/styles/AppColors.d.ts +0 -3
  214. package/dist/esm/styles/AppColors.js +15 -30
  215. package/dist/esm/styles/AppFonts.d.ts +0 -4
  216. package/dist/esm/styles/AppFonts.js +0 -4
  217. package/dist/esm/styles/common.js +0 -11
  218. package/dist/esm/styles/index.js +0 -8
  219. package/dist/esm/types/enums.js +0 -3
  220. package/dist/esm/types/interfaces.d.ts +3 -3
  221. package/package.json +2 -2
  222. package/src/constants/telemetryConfig.ts +16 -0
  223. package/src/constants/version.ts +1 -1
  224. package/src/helpers/telemetry.ts +341 -0
  225. package/src/index.tsx +15 -1
  226. package/src/types/interfaces.ts +3 -0
@@ -55,7 +55,6 @@ export interface ConsoleLog {
55
55
  errorStack?: string;
56
56
  rawArgs?: any[];
57
57
  sourceMethod?: 'log' | 'info' | 'warn' | 'error';
58
- /** #9 — number of consecutive identical logs collapsed into this entry. */
59
58
  duplicateCount?: number;
60
59
  }
61
60
  export interface AnalyticsEvent {
@@ -101,9 +100,7 @@ export interface NetworkLog {
101
100
  response?: unknown;
102
101
  requestHeaders?: Record<string, string>;
103
102
  responseHeaders?: Record<string, string>;
104
- /** #9 — number of consecutive identical requests collapsed into this entry. */
105
103
  duplicateCount?: number;
106
- /** Client identifier: axios, fetch, xhr, apollo, etc. */
107
104
  client?: 'axios' | 'fetch' | 'xhr' | 'apollo' | 'graphql' | string;
108
105
  caller?: string;
109
106
  routeInfo?: RouteInfo;
@@ -154,9 +151,12 @@ export interface PersistedSettings {
154
151
  reduxExpandDepth?: number;
155
152
  showDuplicateLogs?: boolean;
156
153
  showUpdateToast?: boolean;
154
+ telemetryClientId?: string;
155
+ telemetryLastPing?: number;
157
156
  }
158
157
  export interface NetworkInspectorProps {
159
158
  enabled?: boolean;
159
+ telemetry?: boolean;
160
160
  storage?: InspectorStorage;
161
161
  navigationRef?: any;
162
162
  appIcon?: any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-inapp-inspector",
3
- "version": "2.3.5",
3
+ "version": "2.3.6",
4
4
  "description": "The zero-config, all-in-one in-app debugger for React Native & Expo. Inspect Network (fetch/axios), Console logs, Stack Traces, Redux State, Firebase Analytics, and JS Bundle size directly on device.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -100,7 +100,7 @@
100
100
  },
101
101
  "scripts": {
102
102
  "clean": "rm -rf dist",
103
- "prebuild": "node scripts/gen-version.js",
103
+ "prebuild": "node scripts/gen-version.js && node scripts/gen-telemetry.js",
104
104
  "build": "npm run clean && tsc && tsc -p tsconfig.esm.json",
105
105
  "prepare": "npm run build",
106
106
  "watch": "tsc -w",
@@ -0,0 +1,16 @@
1
+ // AUTO-GENERATED FILE — do not edit by hand.
2
+ // Generated by scripts/gen-telemetry.js from .env at build time.
3
+ // The .env file is gitignored; this file contains only encrypted payloads.
4
+
5
+ /** AES-256-GCM encrypted GA4 Measurement ID */
6
+ export const ENC_MID = '029e338afbbf509e97b2ea5b';
7
+ export const ENC_MID_IV = '9a6d6b4d732f07bedbe40229';
8
+ export const ENC_MID_TAG = 'e545372ce1ad53c593394a2c0281c75d';
9
+
10
+ /** AES-256-GCM encrypted GA4 API Secret */
11
+ export const ENC_SEC = '7e95ab688f1b37f9b72d3ab70c9d92105e5bd7046e84';
12
+ export const ENC_SEC_IV = '64a3aa1ee24005449e885c08';
13
+ export const ENC_SEC_TAG = '007ce86e096dfb0ed902678902754f71';
14
+
15
+ /** Key derivation salt (public, used to reconstruct the key at runtime) */
16
+ export const TELEMETRY_SALT = 'rn-inapp-inspector-telemetry-v1';
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED FILE — do not edit by hand.
2
2
  // Regenerated from package.json on every build by scripts/gen-version.js.
3
- export const LIB_VERSION = '2.3.5';
3
+ export const LIB_VERSION = '2.3.6';
@@ -0,0 +1,341 @@
1
+ import {Platform} from 'react-native';
2
+ import {LIB_VERSION} from '../constants/version';
3
+ import {loadSettings, saveSettings} from './settingsStore';
4
+ import {
5
+ ENC_MID,
6
+ ENC_MID_IV,
7
+ ENC_MID_TAG,
8
+ ENC_SEC,
9
+ ENC_SEC_IV,
10
+ ENC_SEC_TAG,
11
+ TELEMETRY_SALT,
12
+ } from '../constants/telemetryConfig';
13
+
14
+ // ─── Runtime AES-256-GCM Decryption ────────────────────────────────────────
15
+ // Credentials are encrypted at build time by scripts/gen-telemetry.js.
16
+ // The key is derived from public package metadata + salt using SHA-256.
17
+ // This prevents plain-text secrets from appearing in source code or npm tarball.
18
+
19
+ const PKG_NAME = 'react-native-inapp-inspector';
20
+ const PKG_REPO = 'git+https://github.com/vengatmacuser/react-native-inapp-inspector.git';
21
+
22
+ /**
23
+ * SHA-256 hash (returns hex string). Works in React Native / Hermes
24
+ * via a lightweight iterative implementation (no native crypto needed).
25
+ */
26
+ function sha256Hex(input: string): string {
27
+ // Lightweight SHA-256 for runtime key derivation.
28
+ // Adapted from a minimal pure-JS implementation.
29
+ const K = [
30
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
31
+ 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
32
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
33
+ 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
34
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
35
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
36
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
37
+ 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
38
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
39
+ 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
40
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
41
+ ];
42
+
43
+ function rr(n: number, x: number) {
44
+ return ((n >>> x) | (n << (32 - x))) >>> 0;
45
+ }
46
+
47
+ // Convert string to UTF-8 bytes
48
+ const bytes: number[] = [];
49
+ for (let i = 0; i < input.length; i++) {
50
+ const c = input.charCodeAt(i);
51
+ if (c < 0x80) bytes.push(c);
52
+ else if (c < 0x800) {
53
+ bytes.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f));
54
+ } else {
55
+ bytes.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f));
56
+ }
57
+ }
58
+
59
+ // Pre-processing: padding
60
+ const bitLen = bytes.length * 8;
61
+ bytes.push(0x80);
62
+ while (bytes.length % 64 !== 56) bytes.push(0);
63
+ // Append original length in bits as 64-bit big-endian
64
+ for (let i = 56; i >= 0; i -= 8) {
65
+ bytes.push((bitLen >>> i) & 0xff);
66
+ }
67
+
68
+ let h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a;
69
+ let h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19;
70
+
71
+ for (let offset = 0; offset < bytes.length; offset += 64) {
72
+ const w = new Array(64);
73
+ for (let i = 0; i < 16; i++) {
74
+ w[i] = ((bytes[offset + i * 4] << 24) | (bytes[offset + i * 4 + 1] << 16) |
75
+ (bytes[offset + i * 4 + 2] << 8) | bytes[offset + i * 4 + 3]) >>> 0;
76
+ }
77
+ for (let i = 16; i < 64; i++) {
78
+ const s0 = rr(w[i - 15], 7) ^ rr(w[i - 15], 18) ^ (w[i - 15] >>> 3);
79
+ const s1 = rr(w[i - 2], 17) ^ rr(w[i - 2], 19) ^ (w[i - 2] >>> 10);
80
+ w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
81
+ }
82
+ let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
83
+ for (let i = 0; i < 64; i++) {
84
+ const S1 = rr(e, 6) ^ rr(e, 11) ^ rr(e, 25);
85
+ const ch = (e & f) ^ (~e & g);
86
+ const temp1 = (h + S1 + ch + K[i] + w[i]) >>> 0;
87
+ const S0 = rr(a, 2) ^ rr(a, 13) ^ rr(a, 22);
88
+ const maj = (a & b) ^ (a & c) ^ (b & c);
89
+ const temp2 = (S0 + maj) >>> 0;
90
+ h = g; g = f; f = e; e = (d + temp1) >>> 0;
91
+ d = c; c = b; b = a; a = (temp1 + temp2) >>> 0;
92
+ }
93
+ h0 = (h0 + a) >>> 0; h1 = (h1 + b) >>> 0; h2 = (h2 + c) >>> 0; h3 = (h3 + d) >>> 0;
94
+ h4 = (h4 + e) >>> 0; h5 = (h5 + f) >>> 0; h6 = (h6 + g) >>> 0; h7 = (h7 + h) >>> 0;
95
+ }
96
+
97
+ function toHex(n: number) {
98
+ return ('00000000' + n.toString(16)).slice(-8);
99
+ }
100
+ return toHex(h0) + toHex(h1) + toHex(h2) + toHex(h3) + toHex(h4) + toHex(h5) + toHex(h6) + toHex(h7);
101
+ }
102
+
103
+ function hexToBytes(hex: string): number[] {
104
+ const bytes: number[] = [];
105
+ for (let i = 0; i < hex.length; i += 2) {
106
+ bytes.push(parseInt(hex.substring(i, i + 2), 16));
107
+ }
108
+ return bytes;
109
+ }
110
+
111
+ /**
112
+ * AES-256-GCM decryption (pure JS for React Native / Hermes compatibility).
113
+ * Uses a lightweight AES + GCM implementation that runs without native crypto.
114
+ */
115
+ function aesGcmDecrypt(ctHex: string, ivHex: string, _tagHex: string, keyHex: string): string {
116
+ // For React Native runtime where SubtleCrypto is unavailable,
117
+ // we use AES-CTR mode (GCM's encryption layer) for decryption.
118
+ // The auth tag was verified at build time; runtime skips tag verification
119
+ // since we control both the encryption and decryption.
120
+ const keyBytes = hexToBytes(keyHex);
121
+ const ivBytes = hexToBytes(ivHex);
122
+ const ctBytes = hexToBytes(ctHex);
123
+
124
+ // ─── AES key expansion ───
125
+ const Sbox = [
126
+ 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
127
+ 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
128
+ 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
129
+ 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
130
+ 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
131
+ 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
132
+ 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
133
+ 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
134
+ 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
135
+ 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
136
+ 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
137
+ 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
138
+ 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
139
+ 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
140
+ 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
141
+ 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
142
+ ];
143
+
144
+ const Rcon = [0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36];
145
+
146
+ // Key schedule for AES-256
147
+ const Nk = 8, Nr = 14;
148
+ const expandedKey = new Uint8Array(4 * 4 * (Nr + 1));
149
+ for (let i = 0; i < 32; i++) expandedKey[i] = keyBytes[i];
150
+
151
+ for (let i = Nk; i < 4 * (Nr + 1); i++) {
152
+ const t = expandedKey.slice((i - 1) * 4, i * 4);
153
+ if (i % Nk === 0) {
154
+ const tmp = t[0];
155
+ t[0] = Sbox[t[1]] ^ Rcon[i / Nk - 1];
156
+ t[1] = Sbox[t[2]];
157
+ t[2] = Sbox[t[3]];
158
+ t[3] = Sbox[tmp];
159
+ } else if (Nk > 6 && i % Nk === 4) {
160
+ t[0] = Sbox[t[0]]; t[1] = Sbox[t[1]]; t[2] = Sbox[t[2]]; t[3] = Sbox[t[3]];
161
+ }
162
+ for (let j = 0; j < 4; j++) {
163
+ expandedKey[i * 4 + j] = expandedKey[(i - Nk) * 4 + j] ^ t[j];
164
+ }
165
+ }
166
+
167
+ // AES single-block encryption (for CTR mode counter blocks)
168
+ function aesEncryptBlock(block: Uint8Array): Uint8Array {
169
+ const state = new Uint8Array(16);
170
+ for (let i = 0; i < 16; i++) state[i] = block[i] ^ expandedKey[i];
171
+
172
+ for (let round = 1; round <= Nr; round++) {
173
+ // SubBytes
174
+ for (let i = 0; i < 16; i++) state[i] = Sbox[state[i]];
175
+ // ShiftRows
176
+ let t = state[1]; state[1] = state[5]; state[5] = state[9]; state[9] = state[13]; state[13] = t;
177
+ t = state[2]; state[2] = state[10]; state[10] = t; t = state[6]; state[6] = state[14]; state[14] = t;
178
+ t = state[15]; state[15] = state[11]; state[11] = state[7]; state[7] = state[3]; state[3] = t;
179
+ // MixColumns (skip on last round)
180
+ if (round < Nr) {
181
+ for (let c = 0; c < 4; c++) {
182
+ const s0 = state[c*4], s1 = state[c*4+1], s2 = state[c*4+2], s3 = state[c*4+3];
183
+ const xtime = (v: number) => ((v << 1) ^ ((v & 0x80) ? 0x1b : 0)) & 0xff;
184
+ state[c*4] = xtime(s0) ^ xtime(s1) ^ s1 ^ s2 ^ s3;
185
+ state[c*4+1] = s0 ^ xtime(s1) ^ xtime(s2) ^ s2 ^ s3;
186
+ state[c*4+2] = s0 ^ s1 ^ xtime(s2) ^ xtime(s3) ^ s3;
187
+ state[c*4+3] = xtime(s0) ^ s0 ^ s1 ^ s2 ^ xtime(s3);
188
+ }
189
+ }
190
+ // AddRoundKey
191
+ const rkOffset = round * 16;
192
+ for (let i = 0; i < 16; i++) state[i] ^= expandedKey[rkOffset + i];
193
+ }
194
+ return state;
195
+ }
196
+
197
+ // ─── AES-CTR decryption (GCM uses CTR internally) ───
198
+ // Build initial counter block: IV (12 bytes) + counter (4 bytes, starts at 2 for GCM)
199
+ const result: number[] = [];
200
+ let counter = 2; // GCM starts CTR at 2 for ciphertext (1 is used for tag)
201
+
202
+ for (let i = 0; i < ctBytes.length; i += 16) {
203
+ const counterBlock = new Uint8Array(16);
204
+ for (let j = 0; j < 12; j++) counterBlock[j] = ivBytes[j];
205
+ counterBlock[12] = (counter >>> 24) & 0xff;
206
+ counterBlock[13] = (counter >>> 16) & 0xff;
207
+ counterBlock[14] = (counter >>> 8) & 0xff;
208
+ counterBlock[15] = counter & 0xff;
209
+ counter++;
210
+
211
+ const keystream = aesEncryptBlock(counterBlock);
212
+ const blockLen = Math.min(16, ctBytes.length - i);
213
+ for (let j = 0; j < blockLen; j++) {
214
+ result.push(ctBytes[i + j] ^ keystream[j]);
215
+ }
216
+ }
217
+
218
+ return String.fromCharCode(...result);
219
+ }
220
+
221
+ // ─── Lazy-initialized credentials ──────────────────────────────────────────
222
+ let _cachedMid: string | null = null;
223
+ let _cachedSec: string | null = null;
224
+
225
+ function getCredentials(): {measurementId: string; apiSecret: string} {
226
+ if (_cachedMid !== null && _cachedSec !== null) {
227
+ return {measurementId: _cachedMid, apiSecret: _cachedSec};
228
+ }
229
+
230
+ if (!ENC_MID || !ENC_SEC || !TELEMETRY_SALT) {
231
+ _cachedMid = '';
232
+ _cachedSec = '';
233
+ return {measurementId: '', apiSecret: ''};
234
+ }
235
+
236
+ try {
237
+ const keyMaterial = `${PKG_NAME}::${TELEMETRY_SALT}::${PKG_REPO}`;
238
+ const keyHex = sha256Hex(keyMaterial);
239
+ _cachedMid = aesGcmDecrypt(ENC_MID, ENC_MID_IV, ENC_MID_TAG, keyHex);
240
+ _cachedSec = aesGcmDecrypt(ENC_SEC, ENC_SEC_IV, ENC_SEC_TAG, keyHex);
241
+ } catch {
242
+ _cachedMid = '';
243
+ _cachedSec = '';
244
+ }
245
+
246
+ return {measurementId: _cachedMid, apiSecret: _cachedSec};
247
+ }
248
+
249
+ function getCollectUrl(): string {
250
+ const {measurementId, apiSecret} = getCredentials();
251
+ if (!measurementId || !apiSecret) return '';
252
+ return `https://www.google-analytics.com/mp/collect?measurement_id=${measurementId}&api_secret=${apiSecret}`;
253
+ }
254
+
255
+ // ─── Telemetry State ────────────────────────────────────────────────────────
256
+
257
+ const PING_INTERVAL_MS = 24 * 60 * 60 * 1000;
258
+
259
+ let isTelemetryEnabled = true;
260
+
261
+ export function setTelemetryEnabled(enabled: boolean): void {
262
+ isTelemetryEnabled = enabled;
263
+ }
264
+
265
+ async function getOrCreateClientId(): Promise<string> {
266
+ try {
267
+ const settings = await loadSettings();
268
+ if (settings.telemetryClientId) {
269
+ return settings.telemetryClientId;
270
+ }
271
+ const part1 = Math.floor(100000000 + Math.random() * 900000000);
272
+ const part2 = Math.floor(1000000000 + Math.random() * 9000000000);
273
+ const newId = `${part1}.${part2}`;
274
+ saveSettings({...settings, telemetryClientId: newId});
275
+ return newId;
276
+ } catch {
277
+ return `${Math.floor(100000000 + Math.random() * 900000000)}.${Math.floor(1000000000 + Math.random() * 9000000000)}`;
278
+ }
279
+ }
280
+
281
+ function getSystemMetadata(environment?: string) {
282
+ const rnConstants = Platform.constants as any;
283
+ const rnVersion = rnConstants?.reactNativeVersion
284
+ ? `${rnConstants.reactNativeVersion.major}.${rnConstants.reactNativeVersion.minor}.${rnConstants.reactNativeVersion.patch}`
285
+ : 'unknown';
286
+
287
+ const isHermes = Boolean(typeof (global as any).HermesInternal === 'object' && (global as any).HermesInternal !== null);
288
+ const isFabric = Boolean((global as any)?.nativeFabricUIManager !== undefined);
289
+ const isDev = Boolean(typeof __DEV__ !== 'undefined' && __DEV__);
290
+
291
+ return {
292
+ lib_version: LIB_VERSION,
293
+ platform: Platform.OS,
294
+ os_version: String(Platform.Version || 'unknown'),
295
+ rn_version: rnVersion,
296
+ is_hermes: isHermes,
297
+ is_fabric: isFabric,
298
+ is_dev: isDev,
299
+ environment: environment || (isDev ? 'DEV' : 'PROD'),
300
+ engagement_time_msec: 1000,
301
+ };
302
+ }
303
+
304
+ export async function trackActiveTelemetryHeartbeat(
305
+ telemetryEnabled = true,
306
+ environment?: string,
307
+ ): Promise<void> {
308
+ if (telemetryEnabled === false) {
309
+ isTelemetryEnabled = false;
310
+ return;
311
+ }
312
+ isTelemetryEnabled = true;
313
+
314
+ const url = getCollectUrl();
315
+ if (!url) return;
316
+
317
+ try {
318
+ const settings = await loadSettings();
319
+ const lastPing = settings.telemetryLastPing || 0;
320
+ const now = Date.now();
321
+
322
+ if (now - lastPing < PING_INTERVAL_MS) return;
323
+
324
+ const clientId = await getOrCreateClientId();
325
+ const params = getSystemMetadata(environment);
326
+
327
+ await fetch(url, {
328
+ method: 'POST',
329
+ headers: {'Content-Type': 'application/json'},
330
+ body: JSON.stringify({
331
+ client_id: clientId,
332
+ non_personalized_ads: true,
333
+ events: [{name: 'inspector_active_heartbeat', params}],
334
+ }),
335
+ });
336
+
337
+ saveSettings({...settings, telemetryLastPing: now});
338
+ } catch {
339
+ // silent
340
+ }
341
+ }
package/src/index.tsx CHANGED
@@ -84,6 +84,11 @@ import {
84
84
  setCrashModuleEnabled,
85
85
  } from './customHooks/crashHandler';
86
86
 
87
+ import {
88
+ trackActiveTelemetryHeartbeat,
89
+ setTelemetryEnabled,
90
+ } from './helpers/telemetry';
91
+
87
92
  import {
88
93
  subscribeAnalyticsEvents,
89
94
  clearAnalyticsEvents,
@@ -2170,15 +2175,24 @@ const NetworkInspector = ({
2170
2175
 
2171
2176
  const NetworkInspectorWrapper = (props: NetworkInspectorProps) => {
2172
2177
  const enabled = props?.enabled ?? true;
2178
+ const telemetry = props?.telemetry ?? true;
2173
2179
 
2174
2180
  useEffect(() => {
2175
2181
  if (!enabled) {
2182
+ // When inspector is disabled: hide FAB and kill all telemetry
2176
2183
  hideNativeFloatingButton().catch(() => {});
2184
+ setTelemetryEnabled(false);
2185
+ } else if (telemetry) {
2186
+ // Inspector is enabled and telemetry is on — fire heartbeat
2187
+ trackActiveTelemetryHeartbeat(true, props?.environment);
2188
+ } else {
2189
+ // Inspector is enabled but telemetry is explicitly off
2190
+ setTelemetryEnabled(false);
2177
2191
  }
2178
2192
  return () => {
2179
2193
  hideNativeFloatingButton().catch(() => {});
2180
2194
  };
2181
- }, [enabled]);
2195
+ }, [enabled, telemetry, props?.environment]);
2182
2196
 
2183
2197
  // If enabled is false, return null immediately with 0 overhead
2184
2198
  if (!enabled) {
@@ -180,12 +180,15 @@ export interface PersistedSettings {
180
180
  reduxExpandDepth?: number;
181
181
  showDuplicateLogs?: boolean;
182
182
  showUpdateToast?: boolean;
183
+ telemetryClientId?: string;
184
+ telemetryLastPing?: number;
183
185
  }
184
186
 
185
187
  // ─── Inspector component props / context ──────────────────────────────────────
186
188
 
187
189
  export interface NetworkInspectorProps {
188
190
  enabled?: boolean;
191
+ telemetry?: boolean;
189
192
  storage?: InspectorStorage;
190
193
  navigationRef?: any;
191
194
  appIcon?: any;