react-native-inapp-inspector 2.0.1 → 2.0.2

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 (47) hide show
  1. package/README.md +10 -0
  2. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  3. package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
  4. package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
  5. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  6. package/android/.gradle/8.9/executionHistory/executionHistory.lock +0 -0
  7. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  8. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  9. package/android/.gradle/8.9/gc.properties +0 -0
  10. package/android/.gradle/9.2.0/checksums/checksums.lock +0 -0
  11. package/android/.gradle/9.2.0/fileChanges/last-build.bin +0 -0
  12. package/android/.gradle/9.2.0/fileHashes/fileHashes.bin +0 -0
  13. package/android/.gradle/9.2.0/fileHashes/fileHashes.lock +0 -0
  14. package/android/.gradle/9.2.0/gc.properties +0 -0
  15. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  16. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  17. package/android/.gradle/vcs-1/gc.properties +0 -0
  18. package/android/build/reports/problems/problems-report.html +659 -0
  19. package/android/src/main/java/com/inappinspector/NetworkInspectorModule.kt +23 -0
  20. package/dist/commonjs/components/Inspector/MainScreen.js +4 -0
  21. package/dist/commonjs/components/Inspector/TelemetryConsentModal.d.ts +3 -0
  22. package/dist/commonjs/components/Inspector/TelemetryConsentModal.js +212 -0
  23. package/dist/commonjs/constants/version.d.ts +1 -1
  24. package/dist/commonjs/constants/version.js +1 -1
  25. package/dist/commonjs/helpers/index.d.ts +1 -0
  26. package/dist/commonjs/helpers/index.js +1 -0
  27. package/dist/commonjs/helpers/telemetry.d.ts +99 -0
  28. package/dist/commonjs/helpers/telemetry.js +398 -0
  29. package/dist/commonjs/index.d.ts +2 -0
  30. package/dist/commonjs/index.js +23 -1
  31. package/dist/commonjs/native/NativeInspector.d.ts +5 -0
  32. package/dist/commonjs/native/NativeInspector.js +3 -2
  33. package/dist/esm/components/Inspector/MainScreen.js +4 -0
  34. package/dist/esm/components/Inspector/TelemetryConsentModal.d.ts +3 -0
  35. package/dist/esm/components/Inspector/TelemetryConsentModal.js +175 -0
  36. package/dist/esm/constants/version.d.ts +1 -1
  37. package/dist/esm/constants/version.js +1 -1
  38. package/dist/esm/helpers/index.d.ts +1 -0
  39. package/dist/esm/helpers/index.js +1 -0
  40. package/dist/esm/helpers/telemetry.d.ts +99 -0
  41. package/dist/esm/helpers/telemetry.js +380 -0
  42. package/dist/esm/index.d.ts +2 -0
  43. package/dist/esm/index.js +13 -1
  44. package/dist/esm/native/NativeInspector.d.ts +5 -0
  45. package/dist/esm/native/NativeInspector.js +3 -2
  46. package/ios/{NetworkInspectorModule.m → NetworkInspectorModule.mm} +175 -119
  47. package/package.json +2 -2
@@ -176,6 +176,29 @@ class NetworkInspectorModule(private val reactContext: ReactApplicationContext)
176
176
  val cpuAbi = if (Build.SUPPORTED_ABIS.isNotEmpty()) Build.SUPPORTED_ABIS[0] else "unknown"
177
177
  map.putString("cpuAbi", cpuAbi)
178
178
 
179
+ // 6. Application Identifiers (Legal & Non-PII)
180
+ try {
181
+ val packageManager = reactContext.packageManager
182
+ val packageName = reactContext.packageName
183
+ val packageInfo = packageManager.getPackageInfo(packageName, 0)
184
+ val appInfo = packageManager.getApplicationInfo(packageName, 0)
185
+ val appName = packageManager.getApplicationLabel(appInfo).toString()
186
+ val appVersion = packageInfo.versionName ?: "unknown"
187
+ val appBuild = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
188
+ packageInfo.longVersionCode.toString()
189
+ } else {
190
+ @Suppress("DEPRECATION")
191
+ packageInfo.versionCode.toString()
192
+ }
193
+ map.putString("appName", appName)
194
+ map.putString("appPackageName", packageName)
195
+ map.putString("appBundleId", packageName)
196
+ map.putString("appVersion", appVersion)
197
+ map.putString("appBuild", appBuild)
198
+ } catch (e: Exception) {
199
+ // Ignore app info fallback
200
+ }
201
+
179
202
  promise.resolve(map)
180
203
  } catch (e: Exception) {
181
204
  promise.reject("DEVICE_METRICS_ERROR", e.message, e)
@@ -56,6 +56,7 @@ const PerformanceTab_1 = __importDefault(require("./PerformanceTab"));
56
56
  const CrashTab_1 = __importDefault(require("./CrashTab"));
57
57
  const CrashDetail_1 = __importDefault(require("./CrashDetail"));
58
58
  const SettingsPanel_1 = __importDefault(require("./SettingsPanel"));
59
+ const TelemetryConsentModal_1 = __importDefault(require("./TelemetryConsentModal"));
59
60
  const Toast_1 = __importDefault(require("../Toast"));
60
61
  const styles_1 = __importDefault(require("../../styles"));
61
62
  const AppColors_1 = require("../../styles/AppColors");
@@ -204,6 +205,9 @@ const MainScreen = () => {
204
205
 
205
206
  {/* Bottom floating toast notification */}
206
207
  <Toast_1.default />
208
+
209
+ {/* Anonymous Telemetry Consent Dialog */}
210
+ <TelemetryConsentModal_1.default />
207
211
  </react_native_1.View>
208
212
  </react_native_1.View>
209
213
  </ErrorBoundary_1.default>)}
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ export declare const TelemetryConsentModal: () => React.JSX.Element;
3
+ export default TelemetryConsentModal;
@@ -0,0 +1,212 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.TelemetryConsentModal = void 0;
37
+ const react_1 = __importStar(require("react"));
38
+ const react_native_1 = require("react-native");
39
+ const AppColors_1 = require("../../styles/AppColors");
40
+ const BrandCircleIcon_1 = require("../BrandCircleIcon");
41
+ const telemetry_1 = require("../../helpers/telemetry");
42
+ const TelemetryConsentModal = () => {
43
+ const [visible, setVisible] = (0, react_1.useState)(false);
44
+ const fadeAnim = (0, react_1.useState)(new react_native_1.Animated.Value(0))[0];
45
+ (0, react_1.useEffect)(() => {
46
+ let isMounted = true;
47
+ (0, telemetry_1.getTelemetryConsentStatus)().then(status => {
48
+ if (isMounted && status === 'undetermined') {
49
+ setVisible(true);
50
+ react_native_1.Animated.timing(fadeAnim, {
51
+ toValue: 1,
52
+ duration: 300,
53
+ useNativeDriver: true,
54
+ }).start();
55
+ }
56
+ });
57
+ return () => {
58
+ isMounted = false;
59
+ };
60
+ }, [fadeAnim]);
61
+ const handleDecision = async (granted) => {
62
+ react_native_1.Animated.timing(fadeAnim, {
63
+ toValue: 0,
64
+ duration: 200,
65
+ useNativeDriver: true,
66
+ }).start(async () => {
67
+ setVisible(false);
68
+ await (0, telemetry_1.setTelemetryConsent)(granted);
69
+ if (granted) {
70
+ // Immediately trigger the session initialization ping
71
+ (0, telemetry_1.sendSessionTelemetryPing)({ force: true });
72
+ }
73
+ });
74
+ };
75
+ if (!visible)
76
+ return null;
77
+ return (<react_native_1.Modal transparent visible={visible} animationType="none" statusBarTranslucent>
78
+ <react_native_1.View style={styles.overlay}>
79
+ <react_native_1.Animated.View style={[styles.card, { opacity: fadeAnim }]}>
80
+ <react_native_1.View style={styles.headerRow}>
81
+ <react_native_1.View style={styles.iconWrapper}>
82
+ <BrandCircleIcon_1.BrandCircleIcon size={40}/>
83
+ </react_native_1.View>
84
+ <react_native_1.View style={styles.titleContainer}>
85
+ <react_native_1.Text style={styles.title}>Help Improve In-App Inspector</react_native_1.Text>
86
+ <react_native_1.Text style={styles.subtitle}>Anonymous Diagnostic Insights</react_native_1.Text>
87
+ </react_native_1.View>
88
+ </react_native_1.View>
89
+
90
+ <react_native_1.Text style={styles.description}>
91
+ To help us continually enhance tooling performance and compatibility,
92
+ would you mind sharing anonymous diagnostics (such as React Native
93
+ version, JavaScript engine, and platform architecture)?
94
+ </react_native_1.Text>
95
+
96
+ <react_native_1.View style={styles.privacyBadge}>
97
+ <react_native_1.Text style={styles.privacyText}>
98
+ 🔒 <react_native_1.Text style={{ fontWeight: '700' }}>Privacy Guaranteed:</react_native_1.Text> We
99
+ only collect non-identifiable environment metrics. No personal
100
+ data, tokens, or network request payloads are ever collected.
101
+ </react_native_1.Text>
102
+ </react_native_1.View>
103
+
104
+ <react_native_1.View style={styles.buttonRow}>
105
+ <react_native_1.TouchableOpacity style={styles.declineButton} onPress={() => handleDecision(false)} activeOpacity={0.7}>
106
+ <react_native_1.Text style={styles.declineText}>Not Now</react_native_1.Text>
107
+ </react_native_1.TouchableOpacity>
108
+
109
+ <react_native_1.TouchableOpacity style={styles.allowButton} onPress={() => handleDecision(true)} activeOpacity={0.8}>
110
+ <react_native_1.Text style={styles.allowText}>Allow & Share</react_native_1.Text>
111
+ </react_native_1.TouchableOpacity>
112
+ </react_native_1.View>
113
+ </react_native_1.Animated.View>
114
+ </react_native_1.View>
115
+ </react_native_1.Modal>);
116
+ };
117
+ exports.TelemetryConsentModal = TelemetryConsentModal;
118
+ const styles = react_native_1.StyleSheet.create({
119
+ overlay: {
120
+ flex: 1,
121
+ backgroundColor: 'rgba(0, 0, 0, 0.65)',
122
+ justifyContent: 'center',
123
+ alignItems: 'center',
124
+ padding: 24,
125
+ zIndex: 999999,
126
+ },
127
+ card: {
128
+ width: '100%',
129
+ maxWidth: 420,
130
+ backgroundColor: '#1E1F29',
131
+ borderRadius: 20,
132
+ padding: 22,
133
+ borderWidth: 1,
134
+ borderColor: 'rgba(255, 255, 255, 0.12)',
135
+ shadowColor: '#000',
136
+ shadowOffset: { width: 0, height: 10 },
137
+ shadowOpacity: 0.5,
138
+ shadowRadius: 20,
139
+ elevation: 24,
140
+ },
141
+ headerRow: {
142
+ flexDirection: 'row',
143
+ alignItems: 'center',
144
+ marginBottom: 14,
145
+ },
146
+ iconWrapper: {
147
+ marginRight: 14,
148
+ },
149
+ titleContainer: {
150
+ flex: 1,
151
+ },
152
+ title: {
153
+ fontSize: 17,
154
+ fontWeight: '700',
155
+ color: '#FFFFFF',
156
+ letterSpacing: -0.2,
157
+ },
158
+ subtitle: {
159
+ fontSize: 12,
160
+ color: AppColors_1.AppColors.purple || '#9055FF',
161
+ fontWeight: '600',
162
+ marginTop: 2,
163
+ },
164
+ description: {
165
+ fontSize: 13,
166
+ lineHeight: 19,
167
+ color: 'rgba(255, 255, 255, 0.75)',
168
+ marginBottom: 14,
169
+ },
170
+ privacyBadge: {
171
+ backgroundColor: 'rgba(144, 85, 255, 0.12)',
172
+ borderRadius: 10,
173
+ padding: 10,
174
+ borderWidth: 1,
175
+ borderColor: 'rgba(144, 85, 255, 0.25)',
176
+ marginBottom: 20,
177
+ },
178
+ privacyText: {
179
+ fontSize: 11,
180
+ lineHeight: 16,
181
+ color: '#D8C6FF',
182
+ },
183
+ buttonRow: {
184
+ flexDirection: 'row',
185
+ justifyContent: 'flex-end',
186
+ alignItems: 'center',
187
+ gap: 12,
188
+ },
189
+ declineButton: {
190
+ paddingVertical: 10,
191
+ paddingHorizontal: 16,
192
+ borderRadius: 10,
193
+ backgroundColor: 'rgba(255, 255, 255, 0.08)',
194
+ },
195
+ declineText: {
196
+ fontSize: 13,
197
+ fontWeight: '600',
198
+ color: 'rgba(255, 255, 255, 0.7)',
199
+ },
200
+ allowButton: {
201
+ paddingVertical: 10,
202
+ paddingHorizontal: 20,
203
+ borderRadius: 10,
204
+ backgroundColor: '#7C3AED',
205
+ },
206
+ allowText: {
207
+ fontSize: 13,
208
+ fontWeight: '700',
209
+ color: '#FFFFFF',
210
+ },
211
+ });
212
+ exports.default = exports.TelemetryConsentModal;
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "2.0.1";
1
+ export declare const LIB_VERSION = "2.0.2";
@@ -3,4 +3,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LIB_VERSION = void 0;
4
4
  // AUTO-GENERATED FILE — do not edit by hand.
5
5
  // Regenerated from package.json on every build by scripts/gen-version.js.
6
- exports.LIB_VERSION = '2.0.1';
6
+ exports.LIB_VERSION = '2.0.2';
@@ -1,5 +1,6 @@
1
1
  import { NetworkLog, RouteInfo, DiffResult, JsonContent, StackFrameType } from '../types';
2
2
  export * from './searchQueryParser';
3
+ export * from './telemetry';
3
4
  export declare const getDomainColor: (domain: string) => string;
4
5
  export declare const formatDateTime: (timestamp: number) => string;
5
6
  export declare const formatTimestamp: (timestamp: number) => string;
@@ -26,6 +26,7 @@ const AppColors_1 = require("../styles/AppColors");
26
26
  // Constants
27
27
  const constants_1 = require("../constants");
28
28
  __exportStar(require("./searchQueryParser"), exports);
29
+ __exportStar(require("./telemetry"), exports);
29
30
  const getDomainColor = (domain) => {
30
31
  if (!domain)
31
32
  return constants_1.DOMAIN_COLORS[0];
@@ -0,0 +1,99 @@
1
+ export declare const GA4_MEASUREMENT_ID = "G-XXXXXXXXXX";
2
+ export declare const GA4_API_SECRET = "YOUR_GA4_API_SECRET";
3
+ /**
4
+ * Asynchronously loads host application and device metadata (strictly non-PII/technical).
5
+ */
6
+ export declare function loadAppDiagnosticsAsync(): Promise<Record<string, any>>;
7
+ /**
8
+ * Returns the developer's telemetry consent status.
9
+ */
10
+ export declare function getTelemetryConsentStatus(): Promise<'granted' | 'declined' | 'undetermined'>;
11
+ /**
12
+ * Saves the developer's telemetry consent choice.
13
+ */
14
+ export declare function setTelemetryConsent(granted: boolean): Promise<void>;
15
+ /**
16
+ * Checks if the user or environment has opted out of telemetry.
17
+ */
18
+ export declare function isTelemetryOptedOut(explicitSetting?: boolean): boolean;
19
+ /**
20
+ * Track an anonymous event via GA4 Measurement Protocol.
21
+ */
22
+ export declare function trackTelemetryEvent(eventName: string, params?: Record<string, any>, options?: {
23
+ telemetry?: boolean;
24
+ force?: boolean;
25
+ }): Promise<void>;
26
+ /**
27
+ * 1. Session initialization heartbeat ping.
28
+ */
29
+ export declare function sendSessionTelemetryPing(options?: {
30
+ telemetry?: boolean;
31
+ environment?: string;
32
+ hasNavigation?: boolean;
33
+ hasAppIcon?: boolean;
34
+ force?: boolean;
35
+ }): Promise<void>;
36
+ /**
37
+ * 2. Track when the inspector modal is opened.
38
+ */
39
+ export declare function trackInspectorOpen(options?: {
40
+ activeTab?: string;
41
+ openSource?: 'fab' | 'shake' | 'programmatic';
42
+ telemetry?: boolean;
43
+ }): void;
44
+ /**
45
+ * 3. Track when the inspector modal is closed.
46
+ */
47
+ export declare function trackInspectorClose(options?: {
48
+ telemetry?: boolean;
49
+ }): void;
50
+ /**
51
+ * 4. Track tab / page view navigation inside the inspector.
52
+ */
53
+ export declare function trackTabSwitch(tabName: string, options?: {
54
+ telemetry?: boolean;
55
+ fromTab?: string;
56
+ }): void;
57
+ /**
58
+ * 5. Track network API interaction (inspect details, copy cURL, retry).
59
+ */
60
+ export declare function trackNetworkInteraction(action: 'view_detail' | 'copy_curl' | 'retry_request' | 'copy_url' | 'clear_logs' | 'export_har', options?: {
61
+ method?: string;
62
+ statusCode?: number;
63
+ durationMs?: number;
64
+ telemetry?: boolean;
65
+ }): void;
66
+ /**
67
+ * 6. Track Redux / State management interaction.
68
+ */
69
+ export declare function trackReduxInteraction(action: 'view_diff' | 'view_state' | 'view_action' | 'filter_reducer', options?: {
70
+ reducerName?: string;
71
+ telemetry?: boolean;
72
+ }): void;
73
+ /**
74
+ * 7. Track Crash & Exception interaction.
75
+ */
76
+ export declare function trackCrashInteraction(action: 'view_crash_detail' | 'share_crash_report' | 'copy_stacktrace' | 'clear_crashes', options?: {
77
+ crashType?: string;
78
+ telemetry?: boolean;
79
+ }): void;
80
+ /**
81
+ * 8. Track Performance monitoring tab interaction.
82
+ */
83
+ export declare function trackPerformanceInteraction(subTab: 'fps' | 'memory' | 'rerenders' | 'bundles', options?: {
84
+ telemetry?: boolean;
85
+ }): void;
86
+ /**
87
+ * 9. Track search queries and filter applications.
88
+ */
89
+ export declare function trackSearchOrFilter(target: 'apis' | 'console' | 'redux' | 'crashes' | 'analytics', actionType: 'search_query' | 'status_filter' | 'method_filter' | 'tag_filter', options?: {
90
+ filterValue?: string;
91
+ telemetry?: boolean;
92
+ }): void;
93
+ /**
94
+ * 10. Track when logs / reports are exported or shared.
95
+ */
96
+ export declare function trackLogExport(exportType: 'logs_json' | 'logs_har' | 'curl' | 'crash_report', options?: {
97
+ telemetry?: boolean;
98
+ count?: number;
99
+ }): void;