react-native-inapp-inspector 2.3.15 → 2.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +0 -22
- package/dist/commonjs/components/Inspector/ConsoleTab.js +0 -22
- package/dist/commonjs/components/Inspector/CrashTab.js +0 -23
- package/dist/commonjs/components/Inspector/FeedbackModal.d.ts +7 -0
- package/dist/commonjs/components/Inspector/FeedbackModal.js +552 -0
- package/dist/commonjs/components/Inspector/InspectorHeader.js +56 -4
- package/dist/commonjs/components/Inspector/MainScreen.js +45 -3
- package/dist/commonjs/components/Inspector/NetworkTab.js +27 -38
- package/dist/commonjs/components/Inspector/NpmStarPrompt.d.ts +3 -0
- package/dist/commonjs/components/Inspector/NpmStarPrompt.js +494 -0
- package/dist/commonjs/components/Inspector/PerformanceTab.js +8 -1
- package/dist/commonjs/components/Inspector/ReduxTab.js +0 -22
- package/dist/commonjs/components/Inspector/SettingsPanel.js +1035 -173
- package/dist/commonjs/components/Inspector/StorageTab.js +0 -23
- package/dist/commonjs/components/Inspector/TabBar.js +50 -15
- package/dist/commonjs/components/NetworkIcons.d.ts +5 -0
- package/dist/commonjs/components/NetworkIcons.js +33 -2
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/helpers/index.d.ts +1 -0
- package/dist/commonjs/helpers/index.js +1 -0
- package/dist/commonjs/helpers/remoteConfig.d.ts +4 -0
- package/dist/commonjs/helpers/remoteConfig.js +165 -0
- package/dist/commonjs/helpers/searchQueryParser.js +2 -0
- package/dist/commonjs/helpers/telemetry.d.ts +5 -0
- package/dist/commonjs/helpers/telemetry.js +339 -8
- package/dist/commonjs/index.d.ts +1 -0
- package/dist/commonjs/index.js +32 -2
- package/dist/commonjs/styles/AppFonts.d.ts +2 -0
- package/dist/commonjs/styles/AppFonts.js +1 -0
- package/dist/commonjs/styles/index.d.ts +22 -0
- package/dist/commonjs/styles/index.js +19 -0
- package/dist/commonjs/types/enums.d.ts +1 -0
- package/dist/commonjs/types/enums.js +1 -0
- package/dist/commonjs/types/interfaces.d.ts +12 -0
- package/dist/esm/components/Inspector/AnalyticsTab.js +1 -23
- package/dist/esm/components/Inspector/ConsoleTab.js +1 -23
- package/dist/esm/components/Inspector/CrashTab.js +1 -24
- package/dist/esm/components/Inspector/FeedbackModal.d.ts +7 -0
- package/dist/esm/components/Inspector/FeedbackModal.js +515 -0
- package/dist/esm/components/Inspector/InspectorHeader.js +57 -5
- package/dist/esm/components/Inspector/MainScreen.js +46 -4
- package/dist/esm/components/Inspector/NetworkTab.js +28 -39
- package/dist/esm/components/Inspector/NpmStarPrompt.d.ts +3 -0
- package/dist/esm/components/Inspector/NpmStarPrompt.js +454 -0
- package/dist/esm/components/Inspector/PerformanceTab.js +8 -1
- package/dist/esm/components/Inspector/ReduxTab.js +1 -23
- package/dist/esm/components/Inspector/SettingsPanel.js +1038 -176
- package/dist/esm/components/Inspector/StorageTab.js +0 -23
- package/dist/esm/components/Inspector/TabBar.js +50 -15
- package/dist/esm/components/NetworkIcons.d.ts +5 -0
- package/dist/esm/components/NetworkIcons.js +26 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/helpers/index.d.ts +1 -0
- package/dist/esm/helpers/index.js +1 -0
- package/dist/esm/helpers/remoteConfig.d.ts +4 -0
- package/dist/esm/helpers/remoteConfig.js +160 -0
- package/dist/esm/helpers/searchQueryParser.js +2 -0
- package/dist/esm/helpers/telemetry.d.ts +5 -0
- package/dist/esm/helpers/telemetry.js +332 -9
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +30 -2
- package/dist/esm/styles/AppFonts.d.ts +2 -0
- package/dist/esm/styles/AppFonts.js +1 -0
- package/dist/esm/styles/index.d.ts +22 -0
- package/dist/esm/styles/index.js +19 -0
- package/dist/esm/types/enums.d.ts +1 -0
- package/dist/esm/types/enums.js +1 -0
- package/dist/esm/types/interfaces.d.ts +12 -0
- package/package.json +1 -1
- package/src/components/Inspector/AnalyticsTab.tsx +0 -23
- package/src/components/Inspector/ConsoleTab.tsx +0 -23
- package/src/components/Inspector/CrashTab.tsx +0 -23
- package/src/components/Inspector/FeedbackModal.tsx +626 -0
- package/src/components/Inspector/InspectorHeader.tsx +78 -2
- package/src/components/Inspector/MainScreen.tsx +59 -3
- package/src/components/Inspector/NetworkTab.tsx +69 -78
- package/src/components/Inspector/NpmStarPrompt.tsx +532 -0
- package/src/components/Inspector/PerformanceTab.tsx +8 -1
- package/src/components/Inspector/ReduxTab.tsx +0 -23
- package/src/components/Inspector/SettingsPanel.tsx +1162 -197
- package/src/components/Inspector/StorageTab.tsx +0 -23
- package/src/components/Inspector/TabBar.tsx +57 -20
- package/src/components/NetworkIcons.tsx +92 -0
- package/src/constants/version.ts +1 -1
- package/src/helpers/index.ts +1 -0
- package/src/helpers/remoteConfig.ts +212 -0
- package/src/helpers/searchQueryParser.ts +3 -0
- package/src/helpers/telemetry.ts +381 -10
- package/src/index.tsx +42 -0
- package/src/styles/AppFonts.ts +2 -0
- package/src/styles/index.ts +20 -1
- package/src/types/enums.ts +1 -0
- package/src/types/interfaces.ts +12 -0
package/src/helpers/telemetry.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {Appearance, Dimensions, PixelRatio, Platform, NativeModules} from 'react-native';
|
|
2
3
|
import {LIB_VERSION} from '../constants/version';
|
|
3
|
-
import {loadSettings, saveSettings} from './settingsStore';
|
|
4
|
+
import {loadSettings, saveSettings, PersistedSettings} from './settingsStore';
|
|
5
|
+
import {isReduxConnected} from '../customHooks/reduxLogger';
|
|
6
|
+
import {isFirebaseAnalyticsPatched} from '../customHooks/analyticsLogger';
|
|
7
|
+
import {getCrashRecords} from '../customHooks/crashHandler';
|
|
8
|
+
import {getNetworkLogs} from '../customHooks/networkLogger';
|
|
9
|
+
import {isNativeModuleAvailable} from '../native/NativeInspector';
|
|
10
|
+
import {
|
|
11
|
+
getAppName,
|
|
12
|
+
getBundleIdentifier,
|
|
13
|
+
getAppVersionAndBuild,
|
|
14
|
+
isLocalDebugEnvironment,
|
|
15
|
+
} from './index';
|
|
4
16
|
import {
|
|
5
17
|
ENC_MID,
|
|
6
18
|
ENC_SEC,
|
|
@@ -77,21 +89,36 @@ function getCollectUrl(): string {
|
|
|
77
89
|
const PING_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
78
90
|
|
|
79
91
|
let isTelemetryEnabled = true;
|
|
92
|
+
let _hasSearchFilterBeenUsed = false;
|
|
80
93
|
|
|
81
94
|
export function setTelemetryEnabled(enabled: boolean): void {
|
|
82
95
|
isTelemetryEnabled = enabled;
|
|
83
96
|
}
|
|
84
97
|
|
|
98
|
+
export function markSearchFilterUsed(): void {
|
|
99
|
+
_hasSearchFilterBeenUsed = true;
|
|
100
|
+
}
|
|
101
|
+
|
|
85
102
|
async function getOrCreateClientId(): Promise<string> {
|
|
86
103
|
try {
|
|
87
104
|
const settings = await loadSettings();
|
|
88
|
-
if (settings.telemetryClientId) {
|
|
89
|
-
|
|
105
|
+
if (settings.telemetryClientId || settings.telemetryDeviceId) {
|
|
106
|
+
const id = settings.telemetryClientId || settings.telemetryDeviceId || '';
|
|
107
|
+
if (!settings.telemetryDeviceId) {
|
|
108
|
+
await saveSettings({...settings, telemetryDeviceId: id});
|
|
109
|
+
}
|
|
110
|
+
return id;
|
|
90
111
|
}
|
|
91
112
|
const part1 = Math.floor(100000000 + Math.random() * 900000000);
|
|
92
113
|
const part2 = Math.floor(1000000000 + Math.random() * 9000000000);
|
|
93
114
|
const newId = `${part1}.${part2}`;
|
|
94
|
-
|
|
115
|
+
const now = Date.now();
|
|
116
|
+
await saveSettings({
|
|
117
|
+
...settings,
|
|
118
|
+
telemetryClientId: newId,
|
|
119
|
+
telemetryDeviceId: newId,
|
|
120
|
+
deviceFirstSeen: settings.deviceFirstSeen || now,
|
|
121
|
+
});
|
|
95
122
|
return newId;
|
|
96
123
|
} catch {
|
|
97
124
|
return `${Math.floor(100000000 + Math.random() * 900000000)}.${Math.floor(1000000000 + Math.random() * 9000000000)}`;
|
|
@@ -130,7 +157,27 @@ function isDeviceEmulator(): boolean {
|
|
|
130
157
|
return false;
|
|
131
158
|
}
|
|
132
159
|
|
|
133
|
-
function
|
|
160
|
+
function getDeviceLocaleInfo(): {countryCode: string; locale: string; timeZone: string} {
|
|
161
|
+
try {
|
|
162
|
+
const opts = typeof Intl !== 'undefined' && Intl.DateTimeFormat ? Intl.DateTimeFormat().resolvedOptions() : {} as any;
|
|
163
|
+
const timeZone = opts.timeZone || 'unknown';
|
|
164
|
+
const locale = opts.locale || 'unknown';
|
|
165
|
+
let countryCode = 'unknown';
|
|
166
|
+
|
|
167
|
+
if (locale && locale !== 'unknown') {
|
|
168
|
+
const parts = locale.split(/[-_]/);
|
|
169
|
+
if (parts.length > 1) {
|
|
170
|
+
countryCode = parts[parts.length - 1].toUpperCase();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return { countryCode, locale, timeZone };
|
|
175
|
+
} catch {
|
|
176
|
+
return { countryCode: 'unknown', locale: 'unknown', timeZone: 'unknown' };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function getSystemMetadata(environment?: string, currentSettings?: PersistedSettings) {
|
|
134
181
|
const rnConstants = Platform.constants as any;
|
|
135
182
|
const rnVersion = rnConstants?.reactNativeVersion
|
|
136
183
|
? `${rnConstants.reactNativeVersion.major}.${rnConstants.reactNativeVersion.minor}.${rnConstants.reactNativeVersion.patch}`
|
|
@@ -138,20 +185,172 @@ function getSystemMetadata(environment?: string) {
|
|
|
138
185
|
|
|
139
186
|
const isHermes = Boolean(typeof (global as any).HermesInternal === 'object' && (global as any).HermesInternal !== null);
|
|
140
187
|
const isFabric = Boolean((global as any)?.nativeFabricUIManager !== undefined);
|
|
188
|
+
const isBridgeless = Boolean((global as any)?._rn_bridgeless || (global as any)?.RN$Bridgeless);
|
|
141
189
|
const isDev = Boolean(typeof __DEV__ !== 'undefined' && __DEV__);
|
|
142
190
|
const isEmulator = isDeviceEmulator();
|
|
191
|
+
const { countryCode, locale, timeZone } = getDeviceLocaleInfo();
|
|
192
|
+
|
|
193
|
+
let screenRes = 'unknown';
|
|
194
|
+
let screenDensity = 1;
|
|
195
|
+
let fontScale = 1;
|
|
196
|
+
let deviceFormFactor = 'phone';
|
|
197
|
+
let screenOrientation = 'portrait';
|
|
198
|
+
try {
|
|
199
|
+
const dim = Dimensions.get('window');
|
|
200
|
+
screenRes = `${Math.round(dim.width)}x${Math.round(dim.height)}`;
|
|
201
|
+
screenDensity = PixelRatio.get();
|
|
202
|
+
fontScale = PixelRatio.getFontScale();
|
|
203
|
+
screenOrientation = dim.width > dim.height ? 'landscape' : 'portrait';
|
|
204
|
+
const isTablet = (Platform.OS === 'ios' && Boolean((Platform as any).isPad)) ||
|
|
205
|
+
(Math.min(dim.width, dim.height) >= 600);
|
|
206
|
+
deviceFormFactor = isTablet ? 'tablet' : 'phone';
|
|
207
|
+
} catch {}
|
|
208
|
+
|
|
209
|
+
let appearanceMode = 'unknown';
|
|
210
|
+
try {
|
|
211
|
+
appearanceMode = Appearance?.getColorScheme?.() || 'unknown';
|
|
212
|
+
} catch {}
|
|
213
|
+
|
|
214
|
+
const isExpo = Boolean(
|
|
215
|
+
(globalThis as any)?.expo ||
|
|
216
|
+
(globalThis as any)?.__expo ||
|
|
217
|
+
(globalThis as any)?.__turboModuleProxy?.name === 'Expo' ||
|
|
218
|
+
(Platform.constants as any)?.ExpoVersion
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
let hermesVersion = 'non_hermes';
|
|
222
|
+
let jsEngine = 'jsc';
|
|
223
|
+
if (isHermes) {
|
|
224
|
+
jsEngine = 'hermes';
|
|
225
|
+
try {
|
|
226
|
+
const props = (global as any).HermesInternal?.getRuntimeProperties?.() || {};
|
|
227
|
+
hermesVersion = props['OSS Release Version'] || (props['Bytecode Version'] ? `bc_v${props['Bytecode Version']}` : 'hermes');
|
|
228
|
+
} catch {
|
|
229
|
+
hermesVersion = 'hermes';
|
|
230
|
+
}
|
|
231
|
+
} else if ((globalThis as any)?._v8) {
|
|
232
|
+
jsEngine = 'v8';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
let reduxAttached = false;
|
|
236
|
+
try {
|
|
237
|
+
reduxAttached = isReduxConnected();
|
|
238
|
+
} catch {}
|
|
239
|
+
|
|
240
|
+
let analyticsAttached = false;
|
|
241
|
+
try {
|
|
242
|
+
analyticsAttached = isFirebaseAnalyticsPatched();
|
|
243
|
+
} catch {}
|
|
244
|
+
|
|
245
|
+
const hasNativeModule = isNativeModuleAvailable();
|
|
246
|
+
const hasMmkv = Boolean(NativeModules?.RNMMKV || (globalThis as any)?.MMKV);
|
|
247
|
+
|
|
248
|
+
let capturedCrashesCount = 0;
|
|
249
|
+
try {
|
|
250
|
+
capturedCrashesCount = getCrashRecords().length;
|
|
251
|
+
} catch {}
|
|
252
|
+
|
|
253
|
+
let capturedApisBracket = '0';
|
|
254
|
+
try {
|
|
255
|
+
const apiCount = getNetworkLogs().length;
|
|
256
|
+
capturedApisBracket =
|
|
257
|
+
apiCount === 0
|
|
258
|
+
? '0'
|
|
259
|
+
: apiCount <= 10
|
|
260
|
+
? '1-10'
|
|
261
|
+
: apiCount <= 50
|
|
262
|
+
? '11-50'
|
|
263
|
+
: apiCount <= 100
|
|
264
|
+
? '51-100'
|
|
265
|
+
: '100+';
|
|
266
|
+
} catch {}
|
|
267
|
+
|
|
268
|
+
let isMetroConnected = false;
|
|
269
|
+
try {
|
|
270
|
+
isMetroConnected = isLocalDebugEnvironment();
|
|
271
|
+
} catch {}
|
|
272
|
+
|
|
273
|
+
const defaultLandingTab = currentSettings?.defaultTab || 'apis';
|
|
274
|
+
const fabMode =
|
|
275
|
+
hasNativeModule && currentSettings?.useNativeFab !== false
|
|
276
|
+
? 'native_ui_thread'
|
|
277
|
+
: 'js_floating_button';
|
|
278
|
+
|
|
279
|
+
const deviceBrand = String(
|
|
280
|
+
rnConstants?.Brand ||
|
|
281
|
+
(Platform.OS === 'ios' ? 'Apple' : 'unknown'),
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
const deviceModel = String(
|
|
285
|
+
rnConstants?.Model ||
|
|
286
|
+
rnConstants?.systemName ||
|
|
287
|
+
(Platform.OS === 'ios' ? 'iPhone/iPad' : 'unknown'),
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
const deviceManufacturer = String(
|
|
291
|
+
rnConstants?.Manufacturer ||
|
|
292
|
+
(Platform.OS === 'ios' ? 'Apple' : 'unknown'),
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
let appName = 'App';
|
|
296
|
+
let bundleId = 'unknown';
|
|
297
|
+
let appVersion = 'unknown';
|
|
298
|
+
let appBuild = 'unknown';
|
|
299
|
+
try {
|
|
300
|
+
appName = getAppName() || 'App';
|
|
301
|
+
bundleId = getBundleIdentifier() || 'unknown';
|
|
302
|
+
const verInfo = getAppVersionAndBuild();
|
|
303
|
+
appVersion = verInfo.version || 'unknown';
|
|
304
|
+
appBuild = verInfo.build || 'unknown';
|
|
305
|
+
} catch {}
|
|
306
|
+
|
|
307
|
+
const reactVer = typeof React !== 'undefined' && React.version ? React.version : 'unknown';
|
|
143
308
|
|
|
144
309
|
return {
|
|
310
|
+
pkg_name: PKG_NAME,
|
|
311
|
+
pkg_version: LIB_VERSION,
|
|
145
312
|
lib_version: LIB_VERSION,
|
|
313
|
+
install_type: isDev ? 'local_dev' : 'bundled_production',
|
|
314
|
+
app_name: appName,
|
|
315
|
+
bundle_id: bundleId,
|
|
316
|
+
app_version: appVersion,
|
|
317
|
+
app_build: appBuild,
|
|
318
|
+
react_version: reactVer,
|
|
146
319
|
platform: Platform.OS,
|
|
147
320
|
os_version: String(Platform.Version || 'unknown'),
|
|
148
321
|
rn_version: rnVersion,
|
|
322
|
+
country_code: countryCode,
|
|
323
|
+
device_locale: locale,
|
|
324
|
+
time_zone: timeZone,
|
|
325
|
+
device_brand: deviceBrand,
|
|
326
|
+
device_model: deviceModel,
|
|
327
|
+
device_manufacturer: deviceManufacturer,
|
|
328
|
+
device_form_factor: deviceFormFactor,
|
|
329
|
+
screen_resolution: screenRes,
|
|
330
|
+
screen_density: screenDensity,
|
|
331
|
+
screen_orientation: screenOrientation,
|
|
332
|
+
font_scale: fontScale,
|
|
333
|
+
appearance_mode: appearanceMode,
|
|
334
|
+
is_expo: isExpo,
|
|
335
|
+
js_engine: jsEngine,
|
|
336
|
+
hermes_version: hermesVersion,
|
|
149
337
|
is_hermes: isHermes,
|
|
150
338
|
is_fabric: isFabric,
|
|
339
|
+
is_bridgeless: isBridgeless,
|
|
340
|
+
has_native_module: hasNativeModule,
|
|
341
|
+
has_mmkv: hasMmkv,
|
|
342
|
+
fab_mode: fabMode,
|
|
343
|
+
default_landing_tab: defaultLandingTab,
|
|
344
|
+
captured_crashes_count: capturedCrashesCount,
|
|
345
|
+
captured_apis_bracket: capturedApisBracket,
|
|
346
|
+
search_filter_used: _hasSearchFilterBeenUsed,
|
|
347
|
+
is_metro_connected: isMetroConnected,
|
|
151
348
|
is_dev: isDev,
|
|
152
349
|
is_emulator: isEmulator,
|
|
153
350
|
device_type: isEmulator ? 'emulator' : 'real_device',
|
|
154
351
|
app_mode: isDev ? 'local_mode' : 'bundled_application',
|
|
352
|
+
redux_attached: reduxAttached,
|
|
353
|
+
analytics_attached: analyticsAttached,
|
|
155
354
|
environment: environment || (isDev ? 'DEV' : 'PROD'),
|
|
156
355
|
engagement_time_msec: 1000,
|
|
157
356
|
};
|
|
@@ -174,24 +373,196 @@ export async function trackActiveTelemetryHeartbeat(
|
|
|
174
373
|
const settings = await loadSettings();
|
|
175
374
|
const lastPing = settings.telemetryLastPing || 0;
|
|
176
375
|
const now = Date.now();
|
|
376
|
+
const isNewDevice = !settings.deviceRegistered;
|
|
177
377
|
|
|
178
|
-
if
|
|
378
|
+
// Send on first launch or if 24h passed since last ping
|
|
379
|
+
if (!isNewDevice && now - lastPing < PING_INTERVAL_MS) return;
|
|
179
380
|
|
|
180
381
|
const clientId = await getOrCreateClientId();
|
|
181
|
-
const params = getSystemMetadata(environment);
|
|
382
|
+
const params = getSystemMetadata(environment, settings);
|
|
383
|
+
|
|
384
|
+
const deviceParams = {
|
|
385
|
+
...params,
|
|
386
|
+
device_id: clientId,
|
|
387
|
+
is_new_device: isNewDevice,
|
|
388
|
+
device_first_seen: settings.deviceFirstSeen || now,
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
const eventsToDispatch = isNewDevice
|
|
392
|
+
? [
|
|
393
|
+
{name: 'active_device', params: deviceParams},
|
|
394
|
+
{name: 'first_device_install', params: deviceParams},
|
|
395
|
+
{name: 'inspector_active_heartbeat', params: deviceParams},
|
|
396
|
+
]
|
|
397
|
+
: [
|
|
398
|
+
{name: 'active_device', params: deviceParams},
|
|
399
|
+
{name: 'inspector_active_heartbeat', params: deviceParams},
|
|
400
|
+
];
|
|
182
401
|
|
|
183
402
|
await fetch(url, {
|
|
184
403
|
method: 'POST',
|
|
185
404
|
headers: {'Content-Type': 'application/json'},
|
|
186
405
|
body: JSON.stringify({
|
|
187
406
|
client_id: clientId,
|
|
407
|
+
user_id: clientId,
|
|
188
408
|
non_personalized_ads: true,
|
|
189
|
-
|
|
409
|
+
user_properties: {
|
|
410
|
+
device_id: { value: clientId },
|
|
411
|
+
pkg_name: { value: params.pkg_name },
|
|
412
|
+
pkg_version: { value: params.pkg_version },
|
|
413
|
+
install_type: { value: params.install_type },
|
|
414
|
+
app_name: { value: params.app_name },
|
|
415
|
+
bundle_id: { value: params.bundle_id },
|
|
416
|
+
app_version: { value: params.app_version },
|
|
417
|
+
react_version: { value: params.react_version },
|
|
418
|
+
country: { value: params.country_code },
|
|
419
|
+
country_code: { value: params.country_code },
|
|
420
|
+
locale: { value: params.device_locale },
|
|
421
|
+
time_zone: { value: params.time_zone },
|
|
422
|
+
device_brand: { value: params.device_brand },
|
|
423
|
+
device_model: { value: params.device_model },
|
|
424
|
+
device_form_factor: { value: params.device_form_factor },
|
|
425
|
+
screen_resolution: { value: params.screen_resolution },
|
|
426
|
+
appearance_mode: { value: params.appearance_mode },
|
|
427
|
+
is_expo: { value: String(params.is_expo) },
|
|
428
|
+
js_engine: { value: params.js_engine },
|
|
429
|
+
is_fabric: { value: String(params.is_fabric) },
|
|
430
|
+
is_bridgeless: { value: String(params.is_bridgeless) },
|
|
431
|
+
has_native_module: { value: String(params.has_native_module) },
|
|
432
|
+
has_mmkv: { value: String(params.has_mmkv) },
|
|
433
|
+
fab_mode: { value: params.fab_mode },
|
|
434
|
+
default_landing_tab: { value: params.default_landing_tab },
|
|
435
|
+
captured_crashes_count: { value: String(params.captured_crashes_count) },
|
|
436
|
+
captured_apis_bracket: { value: params.captured_apis_bracket },
|
|
437
|
+
search_filter_used: { value: String(params.search_filter_used) },
|
|
438
|
+
is_metro_connected: { value: String(params.is_metro_connected) },
|
|
439
|
+
redux_attached: { value: String(params.redux_attached) },
|
|
440
|
+
analytics_attached: { value: String(params.analytics_attached) },
|
|
441
|
+
platform: { value: params.platform },
|
|
442
|
+
rn_version: { value: params.rn_version },
|
|
443
|
+
lib_version: { value: params.lib_version },
|
|
444
|
+
},
|
|
445
|
+
events: eventsToDispatch,
|
|
190
446
|
}),
|
|
191
447
|
});
|
|
192
448
|
|
|
193
|
-
saveSettings({
|
|
449
|
+
await saveSettings({
|
|
450
|
+
...settings,
|
|
451
|
+
telemetryClientId: clientId,
|
|
452
|
+
telemetryDeviceId: clientId,
|
|
453
|
+
deviceRegistered: true,
|
|
454
|
+
deviceFirstSeen: settings.deviceFirstSeen || now,
|
|
455
|
+
telemetryLastPing: now,
|
|
456
|
+
telemetryLastActive: now,
|
|
457
|
+
});
|
|
194
458
|
} catch {
|
|
195
459
|
// silent
|
|
196
460
|
}
|
|
197
461
|
}
|
|
462
|
+
|
|
463
|
+
export async function trackTelemetryEvent(
|
|
464
|
+
eventName: string,
|
|
465
|
+
eventParams?: Record<string, any>,
|
|
466
|
+
): Promise<void> {
|
|
467
|
+
if (!isTelemetryEnabled) return;
|
|
468
|
+
const url = getCollectUrl();
|
|
469
|
+
if (!url) return;
|
|
470
|
+
|
|
471
|
+
try {
|
|
472
|
+
const clientId = await getOrCreateClientId();
|
|
473
|
+
const settings = await loadSettings().catch(() => ({} as PersistedSettings));
|
|
474
|
+
const metadata = getSystemMetadata(undefined, settings);
|
|
475
|
+
|
|
476
|
+
const params = {
|
|
477
|
+
...metadata,
|
|
478
|
+
device_id: clientId,
|
|
479
|
+
...eventParams,
|
|
480
|
+
engagement_time_msec: 100,
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
await fetch(url, {
|
|
484
|
+
method: 'POST',
|
|
485
|
+
headers: {'Content-Type': 'application/json'},
|
|
486
|
+
body: JSON.stringify({
|
|
487
|
+
client_id: clientId,
|
|
488
|
+
user_id: clientId,
|
|
489
|
+
non_personalized_ads: true,
|
|
490
|
+
user_properties: {
|
|
491
|
+
device_id: { value: clientId },
|
|
492
|
+
pkg_name: { value: metadata.pkg_name },
|
|
493
|
+
pkg_version: { value: metadata.pkg_version },
|
|
494
|
+
install_type: { value: metadata.install_type },
|
|
495
|
+
app_name: { value: metadata.app_name },
|
|
496
|
+
bundle_id: { value: metadata.bundle_id },
|
|
497
|
+
app_version: { value: metadata.app_version },
|
|
498
|
+
react_version: { value: metadata.react_version },
|
|
499
|
+
country: { value: metadata.country_code },
|
|
500
|
+
country_code: { value: metadata.country_code },
|
|
501
|
+
locale: { value: metadata.device_locale },
|
|
502
|
+
time_zone: { value: metadata.time_zone },
|
|
503
|
+
device_brand: { value: metadata.device_brand },
|
|
504
|
+
device_model: { value: metadata.device_model },
|
|
505
|
+
device_form_factor: { value: metadata.device_form_factor },
|
|
506
|
+
screen_resolution: { value: metadata.screen_resolution },
|
|
507
|
+
appearance_mode: { value: metadata.appearance_mode },
|
|
508
|
+
is_expo: { value: String(metadata.is_expo) },
|
|
509
|
+
js_engine: { value: metadata.js_engine },
|
|
510
|
+
is_fabric: { value: String(metadata.is_fabric) },
|
|
511
|
+
is_bridgeless: { value: String(metadata.is_bridgeless) },
|
|
512
|
+
has_native_module: { value: String(metadata.has_native_module) },
|
|
513
|
+
has_mmkv: { value: String(metadata.has_mmkv) },
|
|
514
|
+
fab_mode: { value: metadata.fab_mode },
|
|
515
|
+
default_landing_tab: { value: metadata.default_landing_tab },
|
|
516
|
+
captured_crashes_count: { value: String(metadata.captured_crashes_count) },
|
|
517
|
+
captured_apis_bracket: { value: metadata.captured_apis_bracket },
|
|
518
|
+
search_filter_used: { value: String(metadata.search_filter_used) },
|
|
519
|
+
is_metro_connected: { value: String(metadata.is_metro_connected) },
|
|
520
|
+
redux_attached: { value: String(metadata.redux_attached) },
|
|
521
|
+
analytics_attached: { value: String(metadata.analytics_attached) },
|
|
522
|
+
platform: { value: metadata.platform },
|
|
523
|
+
rn_version: { value: metadata.rn_version },
|
|
524
|
+
lib_version: { value: metadata.lib_version },
|
|
525
|
+
},
|
|
526
|
+
events: [{ name: eventName, params }],
|
|
527
|
+
}),
|
|
528
|
+
});
|
|
529
|
+
} catch {
|
|
530
|
+
// silent
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Tracks when a developer opens/switches tabs in the In-App Inspector (e.g. APIs, Logs, Redux, Performance, Storage, etc.)
|
|
536
|
+
*/
|
|
537
|
+
export function trackInspectorTabView(tabName: string): void {
|
|
538
|
+
trackTelemetryEvent('inspector_tab_view', {
|
|
539
|
+
tab_name: tabName,
|
|
540
|
+
screen_name: `tab_${tabName}`,
|
|
541
|
+
screen_class: 'NetworkInspector',
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Tracks screen views within the In-App Inspector
|
|
547
|
+
*/
|
|
548
|
+
export function trackInspectorScreenView(screenName: string): void {
|
|
549
|
+
trackTelemetryEvent('screen_view', {
|
|
550
|
+
screen_name: screenName,
|
|
551
|
+
screen_class: 'NetworkInspector',
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Tracks screen / performance recording events
|
|
557
|
+
*/
|
|
558
|
+
export function trackInspectorScreenRecord(
|
|
559
|
+
action: 'start' | 'stop' | 'toggle',
|
|
560
|
+
recordingType = 'screen',
|
|
561
|
+
): void {
|
|
562
|
+
trackTelemetryEvent('inspector_screen_record', {
|
|
563
|
+
action,
|
|
564
|
+
recording_type: recordingType,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
|
package/src/index.tsx
CHANGED
|
@@ -87,6 +87,8 @@ import {
|
|
|
87
87
|
import {
|
|
88
88
|
trackActiveTelemetryHeartbeat,
|
|
89
89
|
setTelemetryEnabled,
|
|
90
|
+
trackInspectorTabView,
|
|
91
|
+
trackInspectorScreenView,
|
|
90
92
|
} from './helpers/telemetry';
|
|
91
93
|
|
|
92
94
|
import {
|
|
@@ -124,6 +126,11 @@ import {
|
|
|
124
126
|
isNativeModuleAvailable,
|
|
125
127
|
} from './native/NativeInspector';
|
|
126
128
|
|
|
129
|
+
import {
|
|
130
|
+
fetchRemoteConfigModuleStatus,
|
|
131
|
+
isFirebaseRemoteConfigAvailable,
|
|
132
|
+
} from './helpers/remoteConfig';
|
|
133
|
+
|
|
127
134
|
// Constants
|
|
128
135
|
import {
|
|
129
136
|
StatusFilter,
|
|
@@ -157,6 +164,7 @@ const NetworkInspector = ({
|
|
|
157
164
|
environment,
|
|
158
165
|
initialVisible = false,
|
|
159
166
|
visible: controlledVisible,
|
|
167
|
+
remoteConfig,
|
|
160
168
|
}: NetworkInspectorProps): React.JSX.Element | null => {
|
|
161
169
|
// Set custom storage synchronously during render phase
|
|
162
170
|
setCustomStorage(storage || null);
|
|
@@ -352,6 +360,7 @@ const NetworkInspector = ({
|
|
|
352
360
|
| 'redux'
|
|
353
361
|
| null
|
|
354
362
|
>(null);
|
|
363
|
+
const [isFeedbackOpen, setIsFeedbackOpen] = useState<boolean>(false);
|
|
355
364
|
const [settingsActiveSubTab, setSettingsActiveSubTab] = useState<SettingsSubTab>('module');
|
|
356
365
|
const [tabVisibility, setTabVisibility] = useState<
|
|
357
366
|
Record<ActiveTab, boolean>
|
|
@@ -513,6 +522,28 @@ const NetworkInspector = ({
|
|
|
513
522
|
};
|
|
514
523
|
}, []);
|
|
515
524
|
|
|
525
|
+
// Fetch and apply module enable/disable statuses from Firebase Remote Config if configured or available
|
|
526
|
+
useEffect(() => {
|
|
527
|
+
let isMounted = true;
|
|
528
|
+
if (remoteConfig === false) return;
|
|
529
|
+
|
|
530
|
+
fetchRemoteConfigModuleStatus(typeof remoteConfig === 'object' ? remoteConfig : undefined)
|
|
531
|
+
.then(remoteModules => {
|
|
532
|
+
if (isMounted && remoteModules) {
|
|
533
|
+
setTabVisibility(prev => ({
|
|
534
|
+
...prev,
|
|
535
|
+
...remoteModules,
|
|
536
|
+
apis: remoteModules.apis ?? true,
|
|
537
|
+
}));
|
|
538
|
+
}
|
|
539
|
+
})
|
|
540
|
+
.catch(() => {});
|
|
541
|
+
|
|
542
|
+
return () => {
|
|
543
|
+
isMounted = false;
|
|
544
|
+
};
|
|
545
|
+
}, [remoteConfig]);
|
|
546
|
+
|
|
516
547
|
useEffect(() => {
|
|
517
548
|
if (!settingsHydratedRef.current) return;
|
|
518
549
|
saveSettings({
|
|
@@ -655,6 +686,7 @@ const NetworkInspector = ({
|
|
|
655
686
|
setActiveTab(key);
|
|
656
687
|
loadNativePage(key);
|
|
657
688
|
}
|
|
689
|
+
trackInspectorTabView(key);
|
|
658
690
|
}, [loadNativePage]);
|
|
659
691
|
|
|
660
692
|
const [selectedEvent, setSelectedEvent] = useState<AnalyticsEvent | null>(
|
|
@@ -1013,11 +1045,13 @@ const NetworkInspector = ({
|
|
|
1013
1045
|
useEffect(() => {
|
|
1014
1046
|
isVisibleRefObj.current = visible;
|
|
1015
1047
|
if (visible) {
|
|
1048
|
+
trackInspectorScreenView('InspectorModal');
|
|
1016
1049
|
const target =
|
|
1017
1050
|
defaultTab === 'apis' || tabVisibility?.[defaultTab]
|
|
1018
1051
|
? defaultTab
|
|
1019
1052
|
: 'apis';
|
|
1020
1053
|
setActiveTab(target);
|
|
1054
|
+
trackInspectorTabView(target);
|
|
1021
1055
|
|
|
1022
1056
|
|
|
1023
1057
|
|
|
@@ -2032,6 +2066,8 @@ const NetworkInspector = ({
|
|
|
2032
2066
|
setShowHeaderInfo,
|
|
2033
2067
|
settingsPage,
|
|
2034
2068
|
setSettingsPage,
|
|
2069
|
+
isFeedbackOpen,
|
|
2070
|
+
setIsFeedbackOpen,
|
|
2035
2071
|
updateAvailable,
|
|
2036
2072
|
latestNpmVersion,
|
|
2037
2073
|
clearAnim,
|
|
@@ -2207,6 +2243,7 @@ const NetworkInspector = ({
|
|
|
2207
2243
|
selectedLog,
|
|
2208
2244
|
showHeaderInfo,
|
|
2209
2245
|
settingsPage,
|
|
2246
|
+
isFeedbackOpen,
|
|
2210
2247
|
updateAvailable,
|
|
2211
2248
|
latestNpmVersion,
|
|
2212
2249
|
clearAnim,
|
|
@@ -2562,4 +2599,9 @@ export {
|
|
|
2562
2599
|
I18nextProvider,
|
|
2563
2600
|
} from './i18n';
|
|
2564
2601
|
|
|
2602
|
+
export {
|
|
2603
|
+
fetchRemoteConfigModuleStatus,
|
|
2604
|
+
isFirebaseRemoteConfigAvailable,
|
|
2605
|
+
} from './helpers/remoteConfig';
|
|
2606
|
+
|
|
2565
2607
|
export { LIB_VERSION } from './constants/version';
|
package/src/styles/AppFonts.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export interface AppFontConfig {
|
|
2
2
|
interRegular?: string;
|
|
3
3
|
interMedium?: string;
|
|
4
|
+
interSemiBold?: string;
|
|
4
5
|
interBold?: string;
|
|
5
6
|
Sfprotext?: string;
|
|
6
7
|
}
|
|
@@ -8,6 +9,7 @@ export interface AppFontConfig {
|
|
|
8
9
|
export const AppFonts = {
|
|
9
10
|
interRegular: 'Inter-Regular',
|
|
10
11
|
interMedium: 'Inter-Medium',
|
|
12
|
+
interSemiBold: 'Inter-SemiBold',
|
|
11
13
|
interBold: 'Inter-Bold',
|
|
12
14
|
Sfprotext: 'Inter-Regular',
|
|
13
15
|
};
|
package/src/styles/index.ts
CHANGED
|
@@ -140,7 +140,26 @@ export const getRawStyles = (colors: typeof AppColors) => ({
|
|
|
140
140
|
},
|
|
141
141
|
|
|
142
142
|
listContent: {paddingBottom: Platform.OS === 'ios' ? 44 : 32},
|
|
143
|
-
//
|
|
143
|
+
// Floating Support & Feedback FAB, in place of scroll-to-top button
|
|
144
|
+
supportFab: {
|
|
145
|
+
position: 'absolute',
|
|
146
|
+
bottom: 22,
|
|
147
|
+
right: 16,
|
|
148
|
+
width: 42,
|
|
149
|
+
height: 42,
|
|
150
|
+
borderRadius: 21,
|
|
151
|
+
backgroundColor: colors.purple,
|
|
152
|
+
alignItems: 'center',
|
|
153
|
+
justifyContent: 'center',
|
|
154
|
+
shadowColor: colors.purple,
|
|
155
|
+
shadowOffset: {width: 0, height: 4},
|
|
156
|
+
shadowOpacity: 0.45,
|
|
157
|
+
shadowRadius: 8,
|
|
158
|
+
elevation: 14,
|
|
159
|
+
zIndex: 999,
|
|
160
|
+
borderWidth: 1.5,
|
|
161
|
+
borderColor: 'rgba(255, 255, 255, 0.25)',
|
|
162
|
+
},
|
|
144
163
|
scrollTopBtn: {
|
|
145
164
|
position: 'absolute',
|
|
146
165
|
bottom: 22,
|
package/src/types/enums.ts
CHANGED
package/src/types/interfaces.ts
CHANGED
|
@@ -180,8 +180,17 @@ export interface PersistedSettings {
|
|
|
180
180
|
reduxExpandDepth?: number;
|
|
181
181
|
showDuplicateLogs?: boolean;
|
|
182
182
|
showUpdateToast?: boolean;
|
|
183
|
+
useNativeFab?: boolean;
|
|
184
|
+
shakeToOpen?: boolean;
|
|
183
185
|
telemetryClientId?: string;
|
|
186
|
+
telemetryDeviceId?: string;
|
|
187
|
+
deviceRegistered?: boolean;
|
|
188
|
+
deviceFirstSeen?: number;
|
|
184
189
|
telemetryLastPing?: number;
|
|
190
|
+
telemetryLastActive?: number;
|
|
191
|
+
starPromptActioned?: boolean;
|
|
192
|
+
starPromptLastShown?: number;
|
|
193
|
+
starPromptFirstSeen?: number;
|
|
185
194
|
}
|
|
186
195
|
|
|
187
196
|
// ─── Inspector component props / context ──────────────────────────────────────
|
|
@@ -195,6 +204,7 @@ export interface NetworkInspectorProps {
|
|
|
195
204
|
environment?: 'DEV' | 'UAT' | 'PrePROD' | 'PROD' | 'QA' | 'Staging' | string;
|
|
196
205
|
initialVisible?: boolean;
|
|
197
206
|
visible?: boolean;
|
|
207
|
+
remoteConfig?: boolean | any;
|
|
198
208
|
}
|
|
199
209
|
|
|
200
210
|
export interface NavigationTrackerProps {
|
|
@@ -239,6 +249,8 @@ export interface InspectorContextValue {
|
|
|
239
249
|
setShowHeaderInfo: React.Dispatch<React.SetStateAction<boolean>>;
|
|
240
250
|
settingsPage: SettingsPage;
|
|
241
251
|
setSettingsPage: React.Dispatch<React.SetStateAction<SettingsPage>>;
|
|
252
|
+
isFeedbackOpen: boolean;
|
|
253
|
+
setIsFeedbackOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
|
242
254
|
updateAvailable: boolean;
|
|
243
255
|
latestNpmVersion: string | null;
|
|
244
256
|
clearAnim: Animated.Value;
|