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.
Files changed (96) hide show
  1. package/README.md +1 -0
  2. package/dist/commonjs/components/Inspector/AnalyticsTab.js +0 -22
  3. package/dist/commonjs/components/Inspector/ConsoleTab.js +0 -22
  4. package/dist/commonjs/components/Inspector/CrashTab.js +0 -23
  5. package/dist/commonjs/components/Inspector/FeedbackModal.d.ts +7 -0
  6. package/dist/commonjs/components/Inspector/FeedbackModal.js +552 -0
  7. package/dist/commonjs/components/Inspector/InspectorHeader.js +56 -4
  8. package/dist/commonjs/components/Inspector/MainScreen.js +45 -3
  9. package/dist/commonjs/components/Inspector/NetworkTab.js +27 -38
  10. package/dist/commonjs/components/Inspector/NpmStarPrompt.d.ts +3 -0
  11. package/dist/commonjs/components/Inspector/NpmStarPrompt.js +494 -0
  12. package/dist/commonjs/components/Inspector/PerformanceTab.js +8 -1
  13. package/dist/commonjs/components/Inspector/ReduxTab.js +0 -22
  14. package/dist/commonjs/components/Inspector/SettingsPanel.js +1035 -173
  15. package/dist/commonjs/components/Inspector/StorageTab.js +0 -23
  16. package/dist/commonjs/components/Inspector/TabBar.js +50 -15
  17. package/dist/commonjs/components/NetworkIcons.d.ts +5 -0
  18. package/dist/commonjs/components/NetworkIcons.js +33 -2
  19. package/dist/commonjs/constants/version.d.ts +1 -1
  20. package/dist/commonjs/constants/version.js +1 -1
  21. package/dist/commonjs/helpers/index.d.ts +1 -0
  22. package/dist/commonjs/helpers/index.js +1 -0
  23. package/dist/commonjs/helpers/remoteConfig.d.ts +4 -0
  24. package/dist/commonjs/helpers/remoteConfig.js +165 -0
  25. package/dist/commonjs/helpers/searchQueryParser.js +2 -0
  26. package/dist/commonjs/helpers/telemetry.d.ts +5 -0
  27. package/dist/commonjs/helpers/telemetry.js +339 -8
  28. package/dist/commonjs/index.d.ts +1 -0
  29. package/dist/commonjs/index.js +32 -2
  30. package/dist/commonjs/styles/AppFonts.d.ts +2 -0
  31. package/dist/commonjs/styles/AppFonts.js +1 -0
  32. package/dist/commonjs/styles/index.d.ts +22 -0
  33. package/dist/commonjs/styles/index.js +19 -0
  34. package/dist/commonjs/types/enums.d.ts +1 -0
  35. package/dist/commonjs/types/enums.js +1 -0
  36. package/dist/commonjs/types/interfaces.d.ts +12 -0
  37. package/dist/esm/components/Inspector/AnalyticsTab.js +1 -23
  38. package/dist/esm/components/Inspector/ConsoleTab.js +1 -23
  39. package/dist/esm/components/Inspector/CrashTab.js +1 -24
  40. package/dist/esm/components/Inspector/FeedbackModal.d.ts +7 -0
  41. package/dist/esm/components/Inspector/FeedbackModal.js +515 -0
  42. package/dist/esm/components/Inspector/InspectorHeader.js +57 -5
  43. package/dist/esm/components/Inspector/MainScreen.js +46 -4
  44. package/dist/esm/components/Inspector/NetworkTab.js +28 -39
  45. package/dist/esm/components/Inspector/NpmStarPrompt.d.ts +3 -0
  46. package/dist/esm/components/Inspector/NpmStarPrompt.js +454 -0
  47. package/dist/esm/components/Inspector/PerformanceTab.js +8 -1
  48. package/dist/esm/components/Inspector/ReduxTab.js +1 -23
  49. package/dist/esm/components/Inspector/SettingsPanel.js +1038 -176
  50. package/dist/esm/components/Inspector/StorageTab.js +0 -23
  51. package/dist/esm/components/Inspector/TabBar.js +50 -15
  52. package/dist/esm/components/NetworkIcons.d.ts +5 -0
  53. package/dist/esm/components/NetworkIcons.js +26 -0
  54. package/dist/esm/constants/version.d.ts +1 -1
  55. package/dist/esm/constants/version.js +1 -1
  56. package/dist/esm/helpers/index.d.ts +1 -0
  57. package/dist/esm/helpers/index.js +1 -0
  58. package/dist/esm/helpers/remoteConfig.d.ts +4 -0
  59. package/dist/esm/helpers/remoteConfig.js +160 -0
  60. package/dist/esm/helpers/searchQueryParser.js +2 -0
  61. package/dist/esm/helpers/telemetry.d.ts +5 -0
  62. package/dist/esm/helpers/telemetry.js +332 -9
  63. package/dist/esm/index.d.ts +1 -0
  64. package/dist/esm/index.js +30 -2
  65. package/dist/esm/styles/AppFonts.d.ts +2 -0
  66. package/dist/esm/styles/AppFonts.js +1 -0
  67. package/dist/esm/styles/index.d.ts +22 -0
  68. package/dist/esm/styles/index.js +19 -0
  69. package/dist/esm/types/enums.d.ts +1 -0
  70. package/dist/esm/types/enums.js +1 -0
  71. package/dist/esm/types/interfaces.d.ts +12 -0
  72. package/package.json +1 -1
  73. package/src/components/Inspector/AnalyticsTab.tsx +0 -23
  74. package/src/components/Inspector/ConsoleTab.tsx +0 -23
  75. package/src/components/Inspector/CrashTab.tsx +0 -23
  76. package/src/components/Inspector/FeedbackModal.tsx +626 -0
  77. package/src/components/Inspector/InspectorHeader.tsx +78 -2
  78. package/src/components/Inspector/MainScreen.tsx +59 -3
  79. package/src/components/Inspector/NetworkTab.tsx +69 -78
  80. package/src/components/Inspector/NpmStarPrompt.tsx +532 -0
  81. package/src/components/Inspector/PerformanceTab.tsx +8 -1
  82. package/src/components/Inspector/ReduxTab.tsx +0 -23
  83. package/src/components/Inspector/SettingsPanel.tsx +1162 -197
  84. package/src/components/Inspector/StorageTab.tsx +0 -23
  85. package/src/components/Inspector/TabBar.tsx +57 -20
  86. package/src/components/NetworkIcons.tsx +92 -0
  87. package/src/constants/version.ts +1 -1
  88. package/src/helpers/index.ts +1 -0
  89. package/src/helpers/remoteConfig.ts +212 -0
  90. package/src/helpers/searchQueryParser.ts +3 -0
  91. package/src/helpers/telemetry.ts +381 -10
  92. package/src/index.tsx +42 -0
  93. package/src/styles/AppFonts.ts +2 -0
  94. package/src/styles/index.ts +20 -1
  95. package/src/types/enums.ts +1 -0
  96. package/src/types/interfaces.ts +12 -0
@@ -1,6 +1,13 @@
1
- import { Platform } from 'react-native';
1
+ import React from 'react';
2
+ import { Appearance, Dimensions, PixelRatio, Platform, NativeModules } from 'react-native';
2
3
  import { LIB_VERSION } from '../constants/version';
3
4
  import { loadSettings, saveSettings } 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 { getAppName, getBundleIdentifier, getAppVersionAndBuild, isLocalDebugEnvironment, } from './index';
4
11
  import { ENC_MID, ENC_SEC, TELEMETRY_SALT, } from '../constants/telemetryConfig';
5
12
  const PKG_NAME = 'react-native-inapp-inspector';
6
13
  const KEY_MATERIAL = `${PKG_NAME}::${TELEMETRY_SALT}`;
@@ -60,19 +67,33 @@ function getCollectUrl() {
60
67
  }
61
68
  const PING_INTERVAL_MS = 24 * 60 * 60 * 1000;
62
69
  let isTelemetryEnabled = true;
70
+ let _hasSearchFilterBeenUsed = false;
63
71
  export function setTelemetryEnabled(enabled) {
64
72
  isTelemetryEnabled = enabled;
65
73
  }
74
+ export function markSearchFilterUsed() {
75
+ _hasSearchFilterBeenUsed = true;
76
+ }
66
77
  async function getOrCreateClientId() {
67
78
  try {
68
79
  const settings = await loadSettings();
69
- if (settings.telemetryClientId) {
70
- return settings.telemetryClientId;
80
+ if (settings.telemetryClientId || settings.telemetryDeviceId) {
81
+ const id = settings.telemetryClientId || settings.telemetryDeviceId || '';
82
+ if (!settings.telemetryDeviceId) {
83
+ await saveSettings({ ...settings, telemetryDeviceId: id });
84
+ }
85
+ return id;
71
86
  }
72
87
  const part1 = Math.floor(100000000 + Math.random() * 900000000);
73
88
  const part2 = Math.floor(1000000000 + Math.random() * 9000000000);
74
89
  const newId = `${part1}.${part2}`;
75
- saveSettings({ ...settings, telemetryClientId: newId });
90
+ const now = Date.now();
91
+ await saveSettings({
92
+ ...settings,
93
+ telemetryClientId: newId,
94
+ telemetryDeviceId: newId,
95
+ deviceFirstSeen: settings.deviceFirstSeen || now,
96
+ });
76
97
  return newId;
77
98
  }
78
99
  catch {
@@ -109,26 +130,181 @@ function isDeviceEmulator() {
109
130
  }
110
131
  return false;
111
132
  }
112
- function getSystemMetadata(environment) {
133
+ function getDeviceLocaleInfo() {
134
+ try {
135
+ const opts = typeof Intl !== 'undefined' && Intl.DateTimeFormat ? Intl.DateTimeFormat().resolvedOptions() : {};
136
+ const timeZone = opts.timeZone || 'unknown';
137
+ const locale = opts.locale || 'unknown';
138
+ let countryCode = 'unknown';
139
+ if (locale && locale !== 'unknown') {
140
+ const parts = locale.split(/[-_]/);
141
+ if (parts.length > 1) {
142
+ countryCode = parts[parts.length - 1].toUpperCase();
143
+ }
144
+ }
145
+ return { countryCode, locale, timeZone };
146
+ }
147
+ catch {
148
+ return { countryCode: 'unknown', locale: 'unknown', timeZone: 'unknown' };
149
+ }
150
+ }
151
+ function getSystemMetadata(environment, currentSettings) {
113
152
  const rnConstants = Platform.constants;
114
153
  const rnVersion = rnConstants?.reactNativeVersion
115
154
  ? `${rnConstants.reactNativeVersion.major}.${rnConstants.reactNativeVersion.minor}.${rnConstants.reactNativeVersion.patch}`
116
155
  : 'unknown';
117
156
  const isHermes = Boolean(typeof global.HermesInternal === 'object' && global.HermesInternal !== null);
118
157
  const isFabric = Boolean(global?.nativeFabricUIManager !== undefined);
158
+ const isBridgeless = Boolean(global?._rn_bridgeless || global?.RN$Bridgeless);
119
159
  const isDev = Boolean(typeof __DEV__ !== 'undefined' && __DEV__);
120
160
  const isEmulator = isDeviceEmulator();
161
+ const { countryCode, locale, timeZone } = getDeviceLocaleInfo();
162
+ let screenRes = 'unknown';
163
+ let screenDensity = 1;
164
+ let fontScale = 1;
165
+ let deviceFormFactor = 'phone';
166
+ let screenOrientation = 'portrait';
167
+ try {
168
+ const dim = Dimensions.get('window');
169
+ screenRes = `${Math.round(dim.width)}x${Math.round(dim.height)}`;
170
+ screenDensity = PixelRatio.get();
171
+ fontScale = PixelRatio.getFontScale();
172
+ screenOrientation = dim.width > dim.height ? 'landscape' : 'portrait';
173
+ const isTablet = (Platform.OS === 'ios' && Boolean(Platform.isPad)) ||
174
+ (Math.min(dim.width, dim.height) >= 600);
175
+ deviceFormFactor = isTablet ? 'tablet' : 'phone';
176
+ }
177
+ catch { }
178
+ let appearanceMode = 'unknown';
179
+ try {
180
+ appearanceMode = Appearance?.getColorScheme?.() || 'unknown';
181
+ }
182
+ catch { }
183
+ const isExpo = Boolean(globalThis?.expo ||
184
+ globalThis?.__expo ||
185
+ globalThis?.__turboModuleProxy?.name === 'Expo' ||
186
+ Platform.constants?.ExpoVersion);
187
+ let hermesVersion = 'non_hermes';
188
+ let jsEngine = 'jsc';
189
+ if (isHermes) {
190
+ jsEngine = 'hermes';
191
+ try {
192
+ const props = global.HermesInternal?.getRuntimeProperties?.() || {};
193
+ hermesVersion = props['OSS Release Version'] || (props['Bytecode Version'] ? `bc_v${props['Bytecode Version']}` : 'hermes');
194
+ }
195
+ catch {
196
+ hermesVersion = 'hermes';
197
+ }
198
+ }
199
+ else if (globalThis?._v8) {
200
+ jsEngine = 'v8';
201
+ }
202
+ let reduxAttached = false;
203
+ try {
204
+ reduxAttached = isReduxConnected();
205
+ }
206
+ catch { }
207
+ let analyticsAttached = false;
208
+ try {
209
+ analyticsAttached = isFirebaseAnalyticsPatched();
210
+ }
211
+ catch { }
212
+ const hasNativeModule = isNativeModuleAvailable();
213
+ const hasMmkv = Boolean(NativeModules?.RNMMKV || globalThis?.MMKV);
214
+ let capturedCrashesCount = 0;
215
+ try {
216
+ capturedCrashesCount = getCrashRecords().length;
217
+ }
218
+ catch { }
219
+ let capturedApisBracket = '0';
220
+ try {
221
+ const apiCount = getNetworkLogs().length;
222
+ capturedApisBracket =
223
+ apiCount === 0
224
+ ? '0'
225
+ : apiCount <= 10
226
+ ? '1-10'
227
+ : apiCount <= 50
228
+ ? '11-50'
229
+ : apiCount <= 100
230
+ ? '51-100'
231
+ : '100+';
232
+ }
233
+ catch { }
234
+ let isMetroConnected = false;
235
+ try {
236
+ isMetroConnected = isLocalDebugEnvironment();
237
+ }
238
+ catch { }
239
+ const defaultLandingTab = currentSettings?.defaultTab || 'apis';
240
+ const fabMode = hasNativeModule && currentSettings?.useNativeFab !== false
241
+ ? 'native_ui_thread'
242
+ : 'js_floating_button';
243
+ const deviceBrand = String(rnConstants?.Brand ||
244
+ (Platform.OS === 'ios' ? 'Apple' : 'unknown'));
245
+ const deviceModel = String(rnConstants?.Model ||
246
+ rnConstants?.systemName ||
247
+ (Platform.OS === 'ios' ? 'iPhone/iPad' : 'unknown'));
248
+ const deviceManufacturer = String(rnConstants?.Manufacturer ||
249
+ (Platform.OS === 'ios' ? 'Apple' : 'unknown'));
250
+ let appName = 'App';
251
+ let bundleId = 'unknown';
252
+ let appVersion = 'unknown';
253
+ let appBuild = 'unknown';
254
+ try {
255
+ appName = getAppName() || 'App';
256
+ bundleId = getBundleIdentifier() || 'unknown';
257
+ const verInfo = getAppVersionAndBuild();
258
+ appVersion = verInfo.version || 'unknown';
259
+ appBuild = verInfo.build || 'unknown';
260
+ }
261
+ catch { }
262
+ const reactVer = typeof React !== 'undefined' && React.version ? React.version : 'unknown';
121
263
  return {
264
+ pkg_name: PKG_NAME,
265
+ pkg_version: LIB_VERSION,
122
266
  lib_version: LIB_VERSION,
267
+ install_type: isDev ? 'local_dev' : 'bundled_production',
268
+ app_name: appName,
269
+ bundle_id: bundleId,
270
+ app_version: appVersion,
271
+ app_build: appBuild,
272
+ react_version: reactVer,
123
273
  platform: Platform.OS,
124
274
  os_version: String(Platform.Version || 'unknown'),
125
275
  rn_version: rnVersion,
276
+ country_code: countryCode,
277
+ device_locale: locale,
278
+ time_zone: timeZone,
279
+ device_brand: deviceBrand,
280
+ device_model: deviceModel,
281
+ device_manufacturer: deviceManufacturer,
282
+ device_form_factor: deviceFormFactor,
283
+ screen_resolution: screenRes,
284
+ screen_density: screenDensity,
285
+ screen_orientation: screenOrientation,
286
+ font_scale: fontScale,
287
+ appearance_mode: appearanceMode,
288
+ is_expo: isExpo,
289
+ js_engine: jsEngine,
290
+ hermes_version: hermesVersion,
126
291
  is_hermes: isHermes,
127
292
  is_fabric: isFabric,
293
+ is_bridgeless: isBridgeless,
294
+ has_native_module: hasNativeModule,
295
+ has_mmkv: hasMmkv,
296
+ fab_mode: fabMode,
297
+ default_landing_tab: defaultLandingTab,
298
+ captured_crashes_count: capturedCrashesCount,
299
+ captured_apis_bracket: capturedApisBracket,
300
+ search_filter_used: _hasSearchFilterBeenUsed,
301
+ is_metro_connected: isMetroConnected,
128
302
  is_dev: isDev,
129
303
  is_emulator: isEmulator,
130
304
  device_type: isEmulator ? 'emulator' : 'real_device',
131
305
  app_mode: isDev ? 'local_mode' : 'bundled_application',
306
+ redux_attached: reduxAttached,
307
+ analytics_attached: analyticsAttached,
132
308
  environment: environment || (isDev ? 'DEV' : 'PROD'),
133
309
  engagement_time_msec: 1000,
134
310
  };
@@ -146,21 +322,168 @@ export async function trackActiveTelemetryHeartbeat(telemetryEnabled = true, env
146
322
  const settings = await loadSettings();
147
323
  const lastPing = settings.telemetryLastPing || 0;
148
324
  const now = Date.now();
149
- if (now - lastPing < PING_INTERVAL_MS)
325
+ const isNewDevice = !settings.deviceRegistered;
326
+ if (!isNewDevice && now - lastPing < PING_INTERVAL_MS)
150
327
  return;
151
328
  const clientId = await getOrCreateClientId();
152
- const params = getSystemMetadata(environment);
329
+ const params = getSystemMetadata(environment, settings);
330
+ const deviceParams = {
331
+ ...params,
332
+ device_id: clientId,
333
+ is_new_device: isNewDevice,
334
+ device_first_seen: settings.deviceFirstSeen || now,
335
+ };
336
+ const eventsToDispatch = isNewDevice
337
+ ? [
338
+ { name: 'active_device', params: deviceParams },
339
+ { name: 'first_device_install', params: deviceParams },
340
+ { name: 'inspector_active_heartbeat', params: deviceParams },
341
+ ]
342
+ : [
343
+ { name: 'active_device', params: deviceParams },
344
+ { name: 'inspector_active_heartbeat', params: deviceParams },
345
+ ];
153
346
  await fetch(url, {
154
347
  method: 'POST',
155
348
  headers: { 'Content-Type': 'application/json' },
156
349
  body: JSON.stringify({
157
350
  client_id: clientId,
351
+ user_id: clientId,
158
352
  non_personalized_ads: true,
159
- events: [{ name: 'inspector_active_heartbeat', params }],
353
+ user_properties: {
354
+ device_id: { value: clientId },
355
+ pkg_name: { value: params.pkg_name },
356
+ pkg_version: { value: params.pkg_version },
357
+ install_type: { value: params.install_type },
358
+ app_name: { value: params.app_name },
359
+ bundle_id: { value: params.bundle_id },
360
+ app_version: { value: params.app_version },
361
+ react_version: { value: params.react_version },
362
+ country: { value: params.country_code },
363
+ country_code: { value: params.country_code },
364
+ locale: { value: params.device_locale },
365
+ time_zone: { value: params.time_zone },
366
+ device_brand: { value: params.device_brand },
367
+ device_model: { value: params.device_model },
368
+ device_form_factor: { value: params.device_form_factor },
369
+ screen_resolution: { value: params.screen_resolution },
370
+ appearance_mode: { value: params.appearance_mode },
371
+ is_expo: { value: String(params.is_expo) },
372
+ js_engine: { value: params.js_engine },
373
+ is_fabric: { value: String(params.is_fabric) },
374
+ is_bridgeless: { value: String(params.is_bridgeless) },
375
+ has_native_module: { value: String(params.has_native_module) },
376
+ has_mmkv: { value: String(params.has_mmkv) },
377
+ fab_mode: { value: params.fab_mode },
378
+ default_landing_tab: { value: params.default_landing_tab },
379
+ captured_crashes_count: { value: String(params.captured_crashes_count) },
380
+ captured_apis_bracket: { value: params.captured_apis_bracket },
381
+ search_filter_used: { value: String(params.search_filter_used) },
382
+ is_metro_connected: { value: String(params.is_metro_connected) },
383
+ redux_attached: { value: String(params.redux_attached) },
384
+ analytics_attached: { value: String(params.analytics_attached) },
385
+ platform: { value: params.platform },
386
+ rn_version: { value: params.rn_version },
387
+ lib_version: { value: params.lib_version },
388
+ },
389
+ events: eventsToDispatch,
160
390
  }),
161
391
  });
162
- saveSettings({ ...settings, telemetryLastPing: now });
392
+ await saveSettings({
393
+ ...settings,
394
+ telemetryClientId: clientId,
395
+ telemetryDeviceId: clientId,
396
+ deviceRegistered: true,
397
+ deviceFirstSeen: settings.deviceFirstSeen || now,
398
+ telemetryLastPing: now,
399
+ telemetryLastActive: now,
400
+ });
163
401
  }
164
402
  catch {
165
403
  }
166
404
  }
405
+ export async function trackTelemetryEvent(eventName, eventParams) {
406
+ if (!isTelemetryEnabled)
407
+ return;
408
+ const url = getCollectUrl();
409
+ if (!url)
410
+ return;
411
+ try {
412
+ const clientId = await getOrCreateClientId();
413
+ const settings = await loadSettings().catch(() => ({}));
414
+ const metadata = getSystemMetadata(undefined, settings);
415
+ const params = {
416
+ ...metadata,
417
+ device_id: clientId,
418
+ ...eventParams,
419
+ engagement_time_msec: 100,
420
+ };
421
+ await fetch(url, {
422
+ method: 'POST',
423
+ headers: { 'Content-Type': 'application/json' },
424
+ body: JSON.stringify({
425
+ client_id: clientId,
426
+ user_id: clientId,
427
+ non_personalized_ads: true,
428
+ user_properties: {
429
+ device_id: { value: clientId },
430
+ pkg_name: { value: metadata.pkg_name },
431
+ pkg_version: { value: metadata.pkg_version },
432
+ install_type: { value: metadata.install_type },
433
+ app_name: { value: metadata.app_name },
434
+ bundle_id: { value: metadata.bundle_id },
435
+ app_version: { value: metadata.app_version },
436
+ react_version: { value: metadata.react_version },
437
+ country: { value: metadata.country_code },
438
+ country_code: { value: metadata.country_code },
439
+ locale: { value: metadata.device_locale },
440
+ time_zone: { value: metadata.time_zone },
441
+ device_brand: { value: metadata.device_brand },
442
+ device_model: { value: metadata.device_model },
443
+ device_form_factor: { value: metadata.device_form_factor },
444
+ screen_resolution: { value: metadata.screen_resolution },
445
+ appearance_mode: { value: metadata.appearance_mode },
446
+ is_expo: { value: String(metadata.is_expo) },
447
+ js_engine: { value: metadata.js_engine },
448
+ is_fabric: { value: String(metadata.is_fabric) },
449
+ is_bridgeless: { value: String(metadata.is_bridgeless) },
450
+ has_native_module: { value: String(metadata.has_native_module) },
451
+ has_mmkv: { value: String(metadata.has_mmkv) },
452
+ fab_mode: { value: metadata.fab_mode },
453
+ default_landing_tab: { value: metadata.default_landing_tab },
454
+ captured_crashes_count: { value: String(metadata.captured_crashes_count) },
455
+ captured_apis_bracket: { value: metadata.captured_apis_bracket },
456
+ search_filter_used: { value: String(metadata.search_filter_used) },
457
+ is_metro_connected: { value: String(metadata.is_metro_connected) },
458
+ redux_attached: { value: String(metadata.redux_attached) },
459
+ analytics_attached: { value: String(metadata.analytics_attached) },
460
+ platform: { value: metadata.platform },
461
+ rn_version: { value: metadata.rn_version },
462
+ lib_version: { value: metadata.lib_version },
463
+ },
464
+ events: [{ name: eventName, params }],
465
+ }),
466
+ });
467
+ }
468
+ catch {
469
+ }
470
+ }
471
+ export function trackInspectorTabView(tabName) {
472
+ trackTelemetryEvent('inspector_tab_view', {
473
+ tab_name: tabName,
474
+ screen_name: `tab_${tabName}`,
475
+ screen_class: 'NetworkInspector',
476
+ });
477
+ }
478
+ export function trackInspectorScreenView(screenName) {
479
+ trackTelemetryEvent('screen_view', {
480
+ screen_name: screenName,
481
+ screen_class: 'NetworkInspector',
482
+ });
483
+ }
484
+ export function trackInspectorScreenRecord(action, recordingType = 'screen') {
485
+ trackTelemetryEvent('inspector_screen_record', {
486
+ action,
487
+ recording_type: recordingType,
488
+ });
489
+ }
@@ -26,4 +26,5 @@ export { ActiveTab, Method, StatusFilter, SortOrder, LocalFilter, ModalAnimation
26
26
  export { AppFonts, setAppFonts, type AppFontConfig, } from './styles/AppFonts';
27
27
  export { AppColors, setAppColors, getThemeColors, updateAppColorsTheme, } from './styles/AppColors';
28
28
  export { t, i18n, useTranslation, setLanguage, addTranslations, setTranslations, I18nextProvider, } from './i18n';
29
+ export { fetchRemoteConfigModuleStatus, isFirebaseRemoteConfigAvailable, } from './helpers/remoteConfig';
29
30
  export { LIB_VERSION } from './constants/version';
package/dist/esm/index.js CHANGED
@@ -12,15 +12,16 @@ import { setupNetworkLogger, clearNetworkLogs, subscribeNetworkLogs, setNetworkM
12
12
  import { setupConsoleLogger, clearConsoleLogs, subscribeConsoleLogs, setConsoleModuleEnabled, } from './customHooks/consoleLogger';
13
13
  import { IGNORED_LOG_PREFIXES } from './customHooks/logFilters';
14
14
  import { setupGlobalCrashHandler, subscribeCrashEvents, getCrashRecords, clearCrashRecords, setMaxCrashLogsLimit, setCrashModuleEnabled, } from './customHooks/crashHandler';
15
- import { trackActiveTelemetryHeartbeat, setTelemetryEnabled, } from './helpers/telemetry';
15
+ import { trackActiveTelemetryHeartbeat, setTelemetryEnabled, trackInspectorTabView, trackInspectorScreenView, } from './helpers/telemetry';
16
16
  import { subscribeAnalyticsEvents, clearAnalyticsEvents, autoSetupAnalyticsLogger, isAnalyticsConnected, setAnalyticsModuleEnabled, } from './customHooks/analyticsLogger';
17
17
  import { getReduxState, subscribeReduxState, setReduxAutoRefresh, getLastActionForReducer, clearActionHistory, isReduxConnected, setReduxModuleEnabled, } from './customHooks/reduxLogger';
18
18
  import { setPerformanceModuleEnabled } from './customHooks/performanceTracker';
19
19
  import { setBundleModuleEnabled } from './customHooks/bundleAnalyzer';
20
20
  import { showNativeFloatingButton, hideNativeFloatingButton, setNativeFloatingButtonBadge, subscribeNativeFloatingButtonPress, subscribeNativeDeviceShake, isNativeModuleAvailable, } from './native/NativeInspector';
21
+ import { fetchRemoteConfigModuleStatus, } from './helpers/remoteConfig';
21
22
  import { LIB_VERSION } from './constants';
22
23
  import { toggleGlobalTheme } from './styles';
23
- const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, environment, initialVisible = false, visible: controlledVisible, }) => {
24
+ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, environment, initialVisible = false, visible: controlledVisible, remoteConfig, }) => {
24
25
  setCustomStorage(storage || null);
25
26
  const [isDark, setIsDark] = useState(false);
26
27
  const [reduxState, setReduxState] = useState(null);
@@ -157,6 +158,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
157
158
  const [logSearch, setLogSearch] = useState('');
158
159
  const [logFilters, setLogFilters] = useState(new Set(['all']));
159
160
  const [settingsPage, setSettingsPage] = useState(null);
161
+ const [isFeedbackOpen, setIsFeedbackOpen] = useState(false);
160
162
  const [settingsActiveSubTab, setSettingsActiveSubTab] = useState('module');
161
163
  const [tabVisibility, setTabVisibility] = useState({
162
164
  apis: true,
@@ -309,6 +311,25 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
309
311
  cancelled = true;
310
312
  };
311
313
  }, []);
314
+ useEffect(() => {
315
+ let isMounted = true;
316
+ if (remoteConfig === false)
317
+ return;
318
+ fetchRemoteConfigModuleStatus(typeof remoteConfig === 'object' ? remoteConfig : undefined)
319
+ .then(remoteModules => {
320
+ if (isMounted && remoteModules) {
321
+ setTabVisibility(prev => ({
322
+ ...prev,
323
+ ...remoteModules,
324
+ apis: remoteModules.apis ?? true,
325
+ }));
326
+ }
327
+ })
328
+ .catch(() => { });
329
+ return () => {
330
+ isMounted = false;
331
+ };
332
+ }, [remoteConfig]);
312
333
  useEffect(() => {
313
334
  if (!settingsHydratedRef.current)
314
335
  return;
@@ -448,6 +469,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
448
469
  setActiveTab(key);
449
470
  loadNativePage(key);
450
471
  }
472
+ trackInspectorTabView(key);
451
473
  }, [loadNativePage]);
452
474
  const [selectedEvent, setSelectedEvent] = useState(null);
453
475
  const [analyticsSearch, setAnalyticsSearch] = useState('');
@@ -758,10 +780,12 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
758
780
  useEffect(() => {
759
781
  isVisibleRefObj.current = visible;
760
782
  if (visible) {
783
+ trackInspectorScreenView('InspectorModal');
761
784
  const target = defaultTab === 'apis' || tabVisibility?.[defaultTab]
762
785
  ? defaultTab
763
786
  : 'apis';
764
787
  setActiveTab(target);
788
+ trackInspectorTabView(target);
765
789
  if (latestNetworkLogsRef.current.length > 0) {
766
790
  const deduped = deduplicateLogs(latestNetworkLogsRef.current);
767
791
  const incoming = new Set(deduped.map(l => l.id));
@@ -1622,6 +1646,8 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
1622
1646
  setShowHeaderInfo,
1623
1647
  settingsPage,
1624
1648
  setSettingsPage,
1649
+ isFeedbackOpen,
1650
+ setIsFeedbackOpen,
1625
1651
  updateAvailable,
1626
1652
  latestNpmVersion,
1627
1653
  clearAnim,
@@ -1780,6 +1806,7 @@ const NetworkInspector = ({ enabled = true, storage, navigationRef, appIcon, env
1780
1806
  selectedLog,
1781
1807
  showHeaderInfo,
1782
1808
  settingsPage,
1809
+ isFeedbackOpen,
1783
1810
  updateAvailable,
1784
1811
  latestNpmVersion,
1785
1812
  clearAnim,
@@ -1921,4 +1948,5 @@ export { ActiveTab, Method, StatusFilter, SortOrder, LocalFilter, ModalAnimation
1921
1948
  export { AppFonts, setAppFonts, } from './styles/AppFonts';
1922
1949
  export { AppColors, setAppColors, getThemeColors, updateAppColorsTheme, } from './styles/AppColors';
1923
1950
  export { t, i18n, useTranslation, setLanguage, addTranslations, setTranslations, I18nextProvider, } from './i18n';
1951
+ export { fetchRemoteConfigModuleStatus, isFirebaseRemoteConfigAvailable, } from './helpers/remoteConfig';
1924
1952
  export { LIB_VERSION } from './constants/version';
@@ -1,12 +1,14 @@
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
  }
7
8
  export declare const AppFonts: {
8
9
  interRegular: string;
9
10
  interMedium: string;
11
+ interSemiBold: string;
10
12
  interBold: string;
11
13
  Sfprotext: string;
12
14
  };
@@ -1,6 +1,7 @@
1
1
  export const AppFonts = {
2
2
  interRegular: 'Inter-Regular',
3
3
  interMedium: 'Inter-Medium',
4
+ interSemiBold: 'Inter-SemiBold',
4
5
  interBold: 'Inter-Bold',
5
6
  Sfprotext: 'Inter-Regular',
6
7
  };
@@ -149,6 +149,28 @@ export declare const getRawStyles: (colors: typeof AppColors) => {
149
149
  listContent: {
150
150
  paddingBottom: number;
151
151
  };
152
+ supportFab: {
153
+ position: string;
154
+ bottom: number;
155
+ right: number;
156
+ width: number;
157
+ height: number;
158
+ borderRadius: number;
159
+ backgroundColor: string;
160
+ alignItems: string;
161
+ justifyContent: string;
162
+ shadowColor: string;
163
+ shadowOffset: {
164
+ width: number;
165
+ height: number;
166
+ };
167
+ shadowOpacity: number;
168
+ shadowRadius: number;
169
+ elevation: number;
170
+ zIndex: number;
171
+ borderWidth: number;
172
+ borderColor: string;
173
+ };
152
174
  scrollTopBtn: {
153
175
  position: string;
154
176
  bottom: number;
@@ -137,6 +137,25 @@ export const getRawStyles = (colors) => ({
137
137
  letterSpacing: 0.2,
138
138
  },
139
139
  listContent: { paddingBottom: Platform.OS === 'ios' ? 44 : 32 },
140
+ supportFab: {
141
+ position: 'absolute',
142
+ bottom: 22,
143
+ right: 16,
144
+ width: 42,
145
+ height: 42,
146
+ borderRadius: 21,
147
+ backgroundColor: colors.purple,
148
+ alignItems: 'center',
149
+ justifyContent: 'center',
150
+ shadowColor: colors.purple,
151
+ shadowOffset: { width: 0, height: 4 },
152
+ shadowOpacity: 0.45,
153
+ shadowRadius: 8,
154
+ elevation: 14,
155
+ zIndex: 999,
156
+ borderWidth: 1.5,
157
+ borderColor: 'rgba(255, 255, 255, 0.25)',
158
+ },
140
159
  scrollTopBtn: {
141
160
  position: 'absolute',
142
161
  bottom: 22,
@@ -67,6 +67,7 @@ export declare const SettingsSubTab: {
67
67
  readonly Module: "module";
68
68
  readonly Ui: "ui";
69
69
  readonly Limits: "limits";
70
+ readonly About: "about";
70
71
  };
71
72
  export type SettingsSubTab = (typeof SettingsSubTab)[keyof typeof SettingsSubTab];
72
73
  export declare const LogFilter: {
@@ -60,6 +60,7 @@ export const SettingsSubTab = {
60
60
  Module: 'module',
61
61
  Ui: 'ui',
62
62
  Limits: 'limits',
63
+ About: 'about',
63
64
  };
64
65
  export const LogFilter = {
65
66
  All: 'all',
@@ -151,8 +151,17 @@ export interface PersistedSettings {
151
151
  reduxExpandDepth?: number;
152
152
  showDuplicateLogs?: boolean;
153
153
  showUpdateToast?: boolean;
154
+ useNativeFab?: boolean;
155
+ shakeToOpen?: boolean;
154
156
  telemetryClientId?: string;
157
+ telemetryDeviceId?: string;
158
+ deviceRegistered?: boolean;
159
+ deviceFirstSeen?: number;
155
160
  telemetryLastPing?: number;
161
+ telemetryLastActive?: number;
162
+ starPromptActioned?: boolean;
163
+ starPromptLastShown?: number;
164
+ starPromptFirstSeen?: number;
156
165
  }
157
166
  export interface NetworkInspectorProps {
158
167
  enabled?: boolean;
@@ -163,6 +172,7 @@ export interface NetworkInspectorProps {
163
172
  environment?: 'DEV' | 'UAT' | 'PrePROD' | 'PROD' | 'QA' | 'Staging' | string;
164
173
  initialVisible?: boolean;
165
174
  visible?: boolean;
175
+ remoteConfig?: boolean | any;
166
176
  }
167
177
  export interface NavigationTrackerProps {
168
178
  onStateChange: (state: any) => void;
@@ -198,6 +208,8 @@ export interface InspectorContextValue {
198
208
  setShowHeaderInfo: React.Dispatch<React.SetStateAction<boolean>>;
199
209
  settingsPage: SettingsPage;
200
210
  setSettingsPage: React.Dispatch<React.SetStateAction<SettingsPage>>;
211
+ isFeedbackOpen: boolean;
212
+ setIsFeedbackOpen: React.Dispatch<React.SetStateAction<boolean>>;
201
213
  updateAvailable: boolean;
202
214
  latestNpmVersion: string | null;
203
215
  clearAnim: Animated.Value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-inapp-inspector",
3
- "version": "2.3.15",
3
+ "version": "2.3.16",
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",