react-native-inapp-inspector 2.2.9 → 2.3.0
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/dist/commonjs/components/AppHeaderLogo.js +45 -12
- package/dist/commonjs/components/BrandSquareIcon.js +92 -49
- package/dist/commonjs/components/EmptyState.d.ts +7 -2
- package/dist/commonjs/components/EmptyState.js +11 -5
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +29 -18
- package/dist/commonjs/components/Inspector/ConsoleTab.js +6 -1
- package/dist/commonjs/components/Inspector/CrashDetail.js +43 -9
- package/dist/commonjs/components/Inspector/CrashTab.js +34 -3
- package/dist/commonjs/components/Inspector/DeviceInfoTab.js +80 -16
- package/dist/commonjs/components/Inspector/InspectorHeader.js +16 -3
- package/dist/commonjs/components/Inspector/NetworkDetail.js +3 -2
- package/dist/commonjs/components/Inspector/NetworkTab.js +103 -4
- package/dist/commonjs/components/Inspector/ReduxTab.js +19 -3
- package/dist/commonjs/components/Inspector/SettingsPanel.js +4 -4
- package/dist/commonjs/components/Inspector/StorageTab.js +19 -3
- package/dist/commonjs/components/JsonViewer.js +2 -0
- package/dist/commonjs/components/MetaAccordion.js +15 -3
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/networkLogger.d.ts +3 -0
- package/dist/commonjs/customHooks/networkLogger.js +10 -1
- package/dist/commonjs/helpers/index.d.ts +6 -0
- package/dist/commonjs/helpers/index.js +196 -6
- package/dist/commonjs/helpers/searchQueryParser.js +62 -20
- package/dist/commonjs/i18n/index.d.ts +13 -0
- package/dist/commonjs/i18n/index.js +35 -2
- package/dist/commonjs/index.d.ts +3 -0
- package/dist/commonjs/index.js +80 -11
- package/dist/commonjs/styles/AppColors.d.ts +4 -0
- package/dist/commonjs/styles/AppColors.js +11 -1
- package/dist/commonjs/styles/AppFonts.d.ts +11 -0
- package/dist/commonjs/styles/AppFonts.js +11 -1
- package/dist/commonjs/types/interfaces.d.ts +1 -0
- package/dist/esm/components/AppHeaderLogo.js +45 -12
- package/dist/esm/components/BrandSquareIcon.js +92 -49
- package/dist/esm/components/EmptyState.d.ts +7 -2
- package/dist/esm/components/EmptyState.js +11 -5
- package/dist/esm/components/Inspector/AnalyticsTab.js +30 -19
- package/dist/esm/components/Inspector/ConsoleTab.js +6 -1
- package/dist/esm/components/Inspector/CrashDetail.js +43 -9
- package/dist/esm/components/Inspector/CrashTab.js +34 -3
- package/dist/esm/components/Inspector/DeviceInfoTab.js +80 -16
- package/dist/esm/components/Inspector/InspectorHeader.js +17 -4
- package/dist/esm/components/Inspector/NetworkDetail.js +3 -2
- package/dist/esm/components/Inspector/NetworkTab.js +103 -4
- package/dist/esm/components/Inspector/ReduxTab.js +19 -3
- package/dist/esm/components/Inspector/SettingsPanel.js +4 -4
- package/dist/esm/components/Inspector/StorageTab.js +19 -3
- package/dist/esm/components/JsonViewer.js +2 -0
- package/dist/esm/components/MetaAccordion.js +15 -3
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/networkLogger.d.ts +3 -0
- package/dist/esm/customHooks/networkLogger.js +8 -0
- package/dist/esm/helpers/index.d.ts +6 -0
- package/dist/esm/helpers/index.js +193 -5
- package/dist/esm/helpers/searchQueryParser.js +62 -20
- package/dist/esm/i18n/index.d.ts +13 -0
- package/dist/esm/i18n/index.js +33 -3
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +68 -12
- package/dist/esm/styles/AppColors.d.ts +4 -0
- package/dist/esm/styles/AppColors.js +9 -0
- package/dist/esm/styles/AppFonts.d.ts +11 -0
- package/dist/esm/styles/AppFonts.js +9 -0
- package/dist/esm/types/interfaces.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/AppHeaderLogo.tsx +46 -12
- package/src/components/BrandSquareIcon.tsx +127 -78
- package/src/components/EmptyState.tsx +27 -5
- package/src/components/Inspector/AnalyticsTab.tsx +48 -27
- package/src/components/Inspector/ConsoleTab.tsx +10 -0
- package/src/components/Inspector/CrashDetail.tsx +65 -9
- package/src/components/Inspector/CrashTab.tsx +41 -3
- package/src/components/Inspector/DeviceInfoTab.tsx +87 -16
- package/src/components/Inspector/InspectorHeader.tsx +24 -4
- package/src/components/Inspector/NetworkDetail.tsx +4 -4
- package/src/components/Inspector/NetworkTab.tsx +129 -4
- package/src/components/Inspector/ReduxTab.tsx +26 -8
- package/src/components/Inspector/SettingsPanel.tsx +4 -4
- package/src/components/Inspector/StorageTab.tsx +21 -3
- package/src/components/JsonViewer.tsx +2 -0
- package/src/components/MetaAccordion.tsx +18 -3
- package/src/constants/version.ts +1 -1
- package/src/customHooks/networkLogger.ts +15 -0
- package/src/helpers/index.ts +213 -5
- package/src/helpers/searchQueryParser.ts +63 -20
- package/src/i18n/index.ts +38 -3
- package/src/index.tsx +89 -11
- package/src/styles/AppColors.ts +9 -0
- package/src/styles/AppFonts.ts +16 -0
- package/src/types/interfaces.ts +1 -0
|
@@ -665,7 +665,7 @@ const NetworkTab = React.memo(() => {
|
|
|
665
665
|
style={{
|
|
666
666
|
backgroundColor: `${AppColors.purple}20`,
|
|
667
667
|
borderRadius: 10,
|
|
668
|
-
paddingHorizontal:
|
|
668
|
+
paddingHorizontal: 6,
|
|
669
669
|
paddingVertical: 1.5,
|
|
670
670
|
}}>
|
|
671
671
|
<Text
|
|
@@ -759,19 +759,130 @@ const NetworkTab = React.memo(() => {
|
|
|
759
759
|
styles.toolbarBtnActive,
|
|
760
760
|
]}
|
|
761
761
|
onPress={filtersAccordion.toggleOpen}
|
|
762
|
-
hitSlop={
|
|
762
|
+
hitSlop={6}>
|
|
763
763
|
<FilterIcon
|
|
764
764
|
color={
|
|
765
765
|
filtersAccordion.isOpen
|
|
766
766
|
? AppColors.purple
|
|
767
767
|
: AppColors.grayTextStrong
|
|
768
768
|
}
|
|
769
|
-
size={
|
|
769
|
+
size={16}
|
|
770
770
|
/>
|
|
771
|
+
{(statusFilters.size > 0 ||
|
|
772
|
+
methodFilters.size > 0) && (
|
|
773
|
+
<View style={styles.activeFilterDot} />
|
|
774
|
+
)}
|
|
771
775
|
</TouchableScale>
|
|
772
776
|
</View>
|
|
773
777
|
</View>
|
|
774
778
|
|
|
779
|
+
{/* Quick Search Scope & Filter Tags Row */}
|
|
780
|
+
<View style={{paddingBottom: 4}}>
|
|
781
|
+
<ScrollView
|
|
782
|
+
horizontal
|
|
783
|
+
showsHorizontalScrollIndicator={false}
|
|
784
|
+
contentContainerStyle={{
|
|
785
|
+
paddingHorizontal: 12,
|
|
786
|
+
flexDirection: 'row',
|
|
787
|
+
alignItems: 'center',
|
|
788
|
+
gap: 5,
|
|
789
|
+
paddingVertical: 2,
|
|
790
|
+
}}>
|
|
791
|
+
{/* Search Scopes */}
|
|
792
|
+
{SEARCH_SCOPES.map(s => {
|
|
793
|
+
const isActive = searchScope === s.id;
|
|
794
|
+
return (
|
|
795
|
+
<TouchableScale
|
|
796
|
+
key={`scope_${s.id}`}
|
|
797
|
+
onPress={() => setSearchScope(s.id)}
|
|
798
|
+
hitSlop={6}
|
|
799
|
+
style={{
|
|
800
|
+
flexDirection: 'row',
|
|
801
|
+
alignItems: 'center',
|
|
802
|
+
gap: 3.5,
|
|
803
|
+
paddingHorizontal: 7.5,
|
|
804
|
+
paddingVertical: 3.5,
|
|
805
|
+
borderRadius: 6,
|
|
806
|
+
backgroundColor: isActive
|
|
807
|
+
? AppColors.purple
|
|
808
|
+
: AppColors.grayBackground,
|
|
809
|
+
borderWidth: 1,
|
|
810
|
+
borderColor: isActive
|
|
811
|
+
? AppColors.purple
|
|
812
|
+
: AppColors.grayBorderSecondary,
|
|
813
|
+
}}>
|
|
814
|
+
{s.icon(isActive ? AppColors.white : AppColors.grayTextWeak)}
|
|
815
|
+
<Text
|
|
816
|
+
style={{
|
|
817
|
+
fontFamily: AppFonts.interBold,
|
|
818
|
+
fontSize: 10,
|
|
819
|
+
color: isActive ? AppColors.white : AppColors.grayText,
|
|
820
|
+
}}>
|
|
821
|
+
{s.label}
|
|
822
|
+
</Text>
|
|
823
|
+
</TouchableScale>
|
|
824
|
+
);
|
|
825
|
+
})}
|
|
826
|
+
|
|
827
|
+
<View
|
|
828
|
+
style={{
|
|
829
|
+
width: 1,
|
|
830
|
+
height: 14,
|
|
831
|
+
backgroundColor: AppColors.dividerColor,
|
|
832
|
+
marginHorizontal: 3,
|
|
833
|
+
}}
|
|
834
|
+
/>
|
|
835
|
+
|
|
836
|
+
{/* Quick Query Suggestions */}
|
|
837
|
+
{QUICK_API_QUERY_TAGS.map(q => {
|
|
838
|
+
const isActive = search.includes(q.query);
|
|
839
|
+
return (
|
|
840
|
+
<TouchableScale
|
|
841
|
+
key={`quick_${q.query}`}
|
|
842
|
+
onPress={() => {
|
|
843
|
+
setSearch(prev => {
|
|
844
|
+
if (prev.includes(q.query)) {
|
|
845
|
+
return prev
|
|
846
|
+
.replace(q.query, '')
|
|
847
|
+
.replace(/\s+/g, ' ')
|
|
848
|
+
.trim();
|
|
849
|
+
}
|
|
850
|
+
return `${prev} ${q.query}`.trim();
|
|
851
|
+
});
|
|
852
|
+
}}
|
|
853
|
+
hitSlop={6}
|
|
854
|
+
style={{
|
|
855
|
+
flexDirection: 'row',
|
|
856
|
+
alignItems: 'center',
|
|
857
|
+
gap: 3.5,
|
|
858
|
+
paddingHorizontal: 7.5,
|
|
859
|
+
paddingVertical: 3.5,
|
|
860
|
+
borderRadius: 6,
|
|
861
|
+
backgroundColor: isActive
|
|
862
|
+
? `${AppColors.purple}20`
|
|
863
|
+
: AppColors.grayBackground,
|
|
864
|
+
borderWidth: 1,
|
|
865
|
+
borderColor: isActive
|
|
866
|
+
? AppColors.purple
|
|
867
|
+
: AppColors.grayBorderSecondary,
|
|
868
|
+
}}>
|
|
869
|
+
{q.icon(isActive ? AppColors.purple : AppColors.grayTextWeak)}
|
|
870
|
+
<Text
|
|
871
|
+
style={{
|
|
872
|
+
fontFamily: AppFonts.interMedium,
|
|
873
|
+
fontSize: 10,
|
|
874
|
+
color: isActive
|
|
875
|
+
? AppColors.purple
|
|
876
|
+
: AppColors.grayText,
|
|
877
|
+
}}>
|
|
878
|
+
{q.label}
|
|
879
|
+
</Text>
|
|
880
|
+
</TouchableScale>
|
|
881
|
+
);
|
|
882
|
+
})}
|
|
883
|
+
</ScrollView>
|
|
884
|
+
</View>
|
|
885
|
+
|
|
775
886
|
{/* Quick Filter Horizontal Chips Bar with Live Counts */}
|
|
776
887
|
<View style={{marginBottom: 8}}>
|
|
777
888
|
<ScrollView
|
|
@@ -1138,8 +1249,22 @@ const NetworkTab = React.memo(() => {
|
|
|
1138
1249
|
ListEmptyComponent={
|
|
1139
1250
|
<EmptyState
|
|
1140
1251
|
isSearch={
|
|
1141
|
-
search.length > 0 ||
|
|
1252
|
+
search.length > 0 ||
|
|
1253
|
+
statusFilters.size > 0 ||
|
|
1254
|
+
methodFilters.size > 0
|
|
1255
|
+
}
|
|
1256
|
+
searchQuery={search}
|
|
1257
|
+
customTitle={
|
|
1258
|
+
search.length > 0
|
|
1259
|
+
? 'No matching API requests'
|
|
1260
|
+
: 'No network activity'
|
|
1142
1261
|
}
|
|
1262
|
+
onClearSearch={() => {
|
|
1263
|
+
setSearch('');
|
|
1264
|
+
setStatusFilters(new Set());
|
|
1265
|
+
setMethodFilters(new Set());
|
|
1266
|
+
setSearchScope('all');
|
|
1267
|
+
}}
|
|
1143
1268
|
/>
|
|
1144
1269
|
}
|
|
1145
1270
|
ListFooterComponent={
|
|
@@ -548,14 +548,32 @@ const ReduxTab = React.memo(() => {
|
|
|
548
548
|
autoCapitalize="none"
|
|
549
549
|
/>
|
|
550
550
|
{reduxSearch.length > 0 && (
|
|
551
|
-
<
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
551
|
+
<View style={{flexDirection: 'row', alignItems: 'center', gap: 4}}>
|
|
552
|
+
<View
|
|
553
|
+
style={{
|
|
554
|
+
backgroundColor: `${AppColors.purple}20`,
|
|
555
|
+
borderRadius: 10,
|
|
556
|
+
paddingHorizontal: 6,
|
|
557
|
+
paddingVertical: 1.5,
|
|
558
|
+
}}>
|
|
559
|
+
<Text
|
|
560
|
+
style={{
|
|
561
|
+
color: AppColors.purple,
|
|
562
|
+
fontSize: 9.5,
|
|
563
|
+
fontFamily: AppFonts.interBold,
|
|
564
|
+
}}>
|
|
565
|
+
{filteredSlices.length}
|
|
566
|
+
</Text>
|
|
567
|
+
</View>
|
|
568
|
+
<Pressable
|
|
569
|
+
accessible={true}
|
|
570
|
+
accessibilityRole="button"
|
|
571
|
+
accessibilityLabel="Clear search input"
|
|
572
|
+
onPress={() => setReduxSearch('')}
|
|
573
|
+
hitSlop={10}>
|
|
574
|
+
<ClearIcon color={AppColors.grayTextWeak} size={14} />
|
|
575
|
+
</Pressable>
|
|
576
|
+
</View>
|
|
559
577
|
)}
|
|
560
578
|
</View>
|
|
561
579
|
|
|
@@ -207,8 +207,8 @@ const SettingsPanel = () => {
|
|
|
207
207
|
bundle: Boolean(tabVisibility?.bundle),
|
|
208
208
|
performance: Boolean(tabVisibility?.performance),
|
|
209
209
|
crash: Boolean(tabVisibility?.crash),
|
|
210
|
-
device: Boolean(tabVisibility?.device
|
|
211
|
-
storage: Boolean(tabVisibility?.storage
|
|
210
|
+
device: Boolean(tabVisibility?.device),
|
|
211
|
+
storage: Boolean(tabVisibility?.storage),
|
|
212
212
|
}));
|
|
213
213
|
|
|
214
214
|
// Synchronize staged state with tabVisibility when tabVisibility updates
|
|
@@ -221,8 +221,8 @@ const SettingsPanel = () => {
|
|
|
221
221
|
bundle: Boolean(tabVisibility?.bundle),
|
|
222
222
|
performance: Boolean(tabVisibility?.performance),
|
|
223
223
|
crash: Boolean(tabVisibility?.crash),
|
|
224
|
-
device: Boolean(tabVisibility?.device
|
|
225
|
-
storage: Boolean(tabVisibility?.storage
|
|
224
|
+
device: Boolean(tabVisibility?.device),
|
|
225
|
+
storage: Boolean(tabVisibility?.storage),
|
|
226
226
|
});
|
|
227
227
|
}, [tabVisibility]);
|
|
228
228
|
|
|
@@ -357,9 +357,27 @@ export const StorageTab = React.memo(() => {
|
|
|
357
357
|
clearButtonMode="while-editing"
|
|
358
358
|
/>
|
|
359
359
|
{search.length > 0 && (
|
|
360
|
-
<
|
|
361
|
-
<
|
|
362
|
-
|
|
360
|
+
<View style={{flexDirection: 'row', alignItems: 'center', gap: 4}}>
|
|
361
|
+
<View
|
|
362
|
+
style={{
|
|
363
|
+
backgroundColor: `${AppColors.purple}20`,
|
|
364
|
+
borderRadius: 10,
|
|
365
|
+
paddingHorizontal: 6,
|
|
366
|
+
paddingVertical: 1.5,
|
|
367
|
+
}}>
|
|
368
|
+
<Text
|
|
369
|
+
style={{
|
|
370
|
+
color: AppColors.purple,
|
|
371
|
+
fontSize: 9.5,
|
|
372
|
+
fontFamily: AppFonts.interBold,
|
|
373
|
+
}}>
|
|
374
|
+
{filteredEntries.length}
|
|
375
|
+
</Text>
|
|
376
|
+
</View>
|
|
377
|
+
<TouchableScale onPress={() => setSearch('')} hitSlop={8}>
|
|
378
|
+
<ClearIcon size={13} color={AppColors.grayTextWeak} />
|
|
379
|
+
</TouchableScale>
|
|
380
|
+
</View>
|
|
363
381
|
)}
|
|
364
382
|
</View>
|
|
365
383
|
|
|
@@ -6,6 +6,7 @@ import {useTranslation} from '../i18n';
|
|
|
6
6
|
import TreeNode from './TreeNode';
|
|
7
7
|
import SegmentedTabs from './SegmentedTabs';
|
|
8
8
|
import HighlightText from './HighlightText';
|
|
9
|
+
import CopyButton from './CopyButton';
|
|
9
10
|
import {PrettyIcon, RawIcon, TableIcon} from './NetworkIcons';
|
|
10
11
|
|
|
11
12
|
// Styles
|
|
@@ -260,6 +261,7 @@ const JsonViewer = React.memo(({
|
|
|
260
261
|
setMode(key as 'pretty' | 'raw' | 'table')
|
|
261
262
|
}
|
|
262
263
|
/>
|
|
264
|
+
<CopyButton value={data} label="JSON" />
|
|
263
265
|
</View>
|
|
264
266
|
)}
|
|
265
267
|
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
|
|
28
28
|
// Components
|
|
29
29
|
import TouchableScale from './TouchableScale';
|
|
30
|
+
import CopyButton from './CopyButton';
|
|
30
31
|
|
|
31
32
|
// Stylesheet
|
|
32
33
|
import {AppColors} from '../styles/AppColors';
|
|
@@ -97,9 +98,23 @@ const MetaAccordion = ({
|
|
|
97
98
|
<Pressable onPress={toggleOpen} hitSlop={12}>
|
|
98
99
|
<View style={styles.metaHeader}>
|
|
99
100
|
<Text style={styles.metaTitle}>Metadata</Text>
|
|
100
|
-
<
|
|
101
|
-
<
|
|
102
|
-
|
|
101
|
+
<View style={{flexDirection: 'row', alignItems: 'center', gap: 8}}>
|
|
102
|
+
<CopyButton
|
|
103
|
+
value={{
|
|
104
|
+
status: status ?? 0,
|
|
105
|
+
duration: duration != null ? `${duration} ms` : '—',
|
|
106
|
+
size: size || '—',
|
|
107
|
+
triggeredAt: triggeredAt || '',
|
|
108
|
+
method: method || 'GET',
|
|
109
|
+
contentType: contentType || 'application/json',
|
|
110
|
+
url: url || '',
|
|
111
|
+
}}
|
|
112
|
+
label="Metadata"
|
|
113
|
+
/>
|
|
114
|
+
<Animated.View style={chevronStyle}>
|
|
115
|
+
<ChevronIcon color={AppColors.grayTextWeak} size={14} />
|
|
116
|
+
</Animated.View>
|
|
117
|
+
</View>
|
|
103
118
|
</View>
|
|
104
119
|
</Pressable>
|
|
105
120
|
|
package/src/constants/version.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import {setupGlobalCrashHandler} from "./crashHandler";
|
|
3
|
+
import {RouteInfo} from "../types";
|
|
3
4
|
|
|
4
5
|
type NetworkLog = {
|
|
5
6
|
id: number;
|
|
@@ -14,12 +15,20 @@ type NetworkLog = {
|
|
|
14
15
|
client?: string; // ✅ Captures request client: axios, fetch, xhr, apollo, etc.
|
|
15
16
|
requestHeaders?: Record<string, string>;
|
|
16
17
|
responseHeaders?: Record<string, string>;
|
|
18
|
+
routeInfo?: RouteInfo;
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
let logs: NetworkLog[] = [];
|
|
20
22
|
let listeners: ((logs: NetworkLog[]) => void)[] = [];
|
|
21
23
|
let counter = 0;
|
|
22
24
|
let isNetworkModuleEnabled = true;
|
|
25
|
+
let currentRouteProvider: (() => RouteInfo | null) | null = null;
|
|
26
|
+
|
|
27
|
+
export const setRouteInfoProvider = (
|
|
28
|
+
provider: (() => RouteInfo | null) | null,
|
|
29
|
+
) => {
|
|
30
|
+
currentRouteProvider = provider;
|
|
31
|
+
};
|
|
23
32
|
|
|
24
33
|
export const setNetworkModuleEnabled = (enabled: boolean) => {
|
|
25
34
|
isNetworkModuleEnabled = enabled;
|
|
@@ -232,6 +241,8 @@ export const setupNetworkLogger = () => {
|
|
|
232
241
|
client = 'axios';
|
|
233
242
|
}
|
|
234
243
|
|
|
244
|
+
const currentRoute = currentRouteProvider ? currentRouteProvider() : null;
|
|
245
|
+
|
|
235
246
|
addOrUpdateLog({
|
|
236
247
|
id,
|
|
237
248
|
url: finalUrl,
|
|
@@ -239,6 +250,7 @@ export const setupNetworkLogger = () => {
|
|
|
239
250
|
startTime: start,
|
|
240
251
|
caller,
|
|
241
252
|
client,
|
|
253
|
+
routeInfo: currentRoute || undefined,
|
|
242
254
|
request: method === "GET" ? undefined : parseRequestData(options?.body),
|
|
243
255
|
requestHeaders,
|
|
244
256
|
});
|
|
@@ -347,6 +359,8 @@ export const addAxiosInterceptors = (axiosInstance: any) => {
|
|
|
347
359
|
config.__logStart = start;
|
|
348
360
|
config.__logCaller = caller;
|
|
349
361
|
|
|
362
|
+
const currentRoute = currentRouteProvider ? currentRouteProvider() : null;
|
|
363
|
+
|
|
350
364
|
addOrUpdateLog({
|
|
351
365
|
id,
|
|
352
366
|
url,
|
|
@@ -354,6 +368,7 @@ export const addAxiosInterceptors = (axiosInstance: any) => {
|
|
|
354
368
|
startTime: start,
|
|
355
369
|
caller,
|
|
356
370
|
client: 'axios',
|
|
371
|
+
routeInfo: currentRoute || undefined,
|
|
357
372
|
request: method === "GET" ? undefined : parseRequestData(config.data),
|
|
358
373
|
requestHeaders: normaliseHeaders(config.headers),
|
|
359
374
|
});
|
package/src/helpers/index.ts
CHANGED
|
@@ -198,16 +198,37 @@ export const getNavigationInfo = (
|
|
|
198
198
|
state: any,
|
|
199
199
|
path: string[] = [],
|
|
200
200
|
): RouteInfo => {
|
|
201
|
-
if (!state
|
|
201
|
+
if (!state) {
|
|
202
202
|
return {
|
|
203
|
-
path: path.length > 0 ? path.join(' ➔ ') : '
|
|
203
|
+
path: path.length > 0 ? path.join(' ➔ ') : '',
|
|
204
204
|
params: null,
|
|
205
205
|
};
|
|
206
206
|
}
|
|
207
|
-
|
|
207
|
+
if (state.name && !state.routes) {
|
|
208
|
+
const fullPath =
|
|
209
|
+
path.length > 0 ? [...path, state.name].join(' ➔ ') : state.name;
|
|
210
|
+
return {path: fullPath, params: state.params || null};
|
|
211
|
+
}
|
|
212
|
+
if (
|
|
213
|
+
!state.routes ||
|
|
214
|
+
!Array.isArray(state.routes) ||
|
|
215
|
+
state.routes.length === 0
|
|
216
|
+
) {
|
|
217
|
+
return {
|
|
218
|
+
path: path.length > 0 ? path.join(' ➔ ') : '',
|
|
219
|
+
params: null,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const index =
|
|
223
|
+
typeof state.index === 'number' &&
|
|
224
|
+
state.index >= 0 &&
|
|
225
|
+
state.index < state.routes.length
|
|
226
|
+
? state.index
|
|
227
|
+
: 0;
|
|
228
|
+
const route = state.routes[index];
|
|
208
229
|
if (!route) {
|
|
209
230
|
return {
|
|
210
|
-
path: path.length > 0 ? path.join(' ➔ ') : '
|
|
231
|
+
path: path.length > 0 ? path.join(' ➔ ') : '',
|
|
211
232
|
params: null,
|
|
212
233
|
};
|
|
213
234
|
}
|
|
@@ -217,10 +238,96 @@ export const getNavigationInfo = (
|
|
|
217
238
|
return getNavigationInfo(route.state, currentPath);
|
|
218
239
|
}
|
|
219
240
|
const resolved =
|
|
220
|
-
currentPath.length > 0 ? currentPath.join(' ➔ ') : '
|
|
241
|
+
currentPath.length > 0 ? currentPath.join(' ➔ ') : route.name || '';
|
|
221
242
|
return {path: resolved, params: route.params || null};
|
|
222
243
|
};
|
|
223
244
|
|
|
245
|
+
export const getLogPageName = (
|
|
246
|
+
log: NetworkLog,
|
|
247
|
+
routeInfo?: RouteInfo | null,
|
|
248
|
+
): string => {
|
|
249
|
+
// 1. If routeInfo has a valid path, resolve the leaf screen name
|
|
250
|
+
const effectiveRoute = routeInfo || (log as any)?.routeInfo;
|
|
251
|
+
if (
|
|
252
|
+
effectiveRoute &&
|
|
253
|
+
effectiveRoute.path &&
|
|
254
|
+
effectiveRoute.path !== 'Navigators'
|
|
255
|
+
) {
|
|
256
|
+
const parts = effectiveRoute.path
|
|
257
|
+
.split(' ➔ ')
|
|
258
|
+
.map((s: string) => s.trim())
|
|
259
|
+
.filter(Boolean);
|
|
260
|
+
if (parts.length > 0) {
|
|
261
|
+
return parts[parts.length - 1]; // Leaf screen name, e.g. "HomeScreen", "ProfileScreen"
|
|
262
|
+
}
|
|
263
|
+
return effectiveRoute.path;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// 2. Extract screen / component name from log.caller stack trace
|
|
267
|
+
if (log.caller && log.caller !== 'Unknown') {
|
|
268
|
+
try {
|
|
269
|
+
const match = log.caller.match(/([^/\\]+)\.(tsx|jsx|ts|js)/i);
|
|
270
|
+
if (match && match[1]) {
|
|
271
|
+
const file = match[1];
|
|
272
|
+
const ignored = [
|
|
273
|
+
'networklogger',
|
|
274
|
+
'fetch',
|
|
275
|
+
'axios',
|
|
276
|
+
'apiclient',
|
|
277
|
+
'request',
|
|
278
|
+
'http',
|
|
279
|
+
'index',
|
|
280
|
+
'nativeinspector',
|
|
281
|
+
'inappinspector',
|
|
282
|
+
'bundleanalyzer',
|
|
283
|
+
];
|
|
284
|
+
if (!ignored.includes(file.toLowerCase())) {
|
|
285
|
+
return file;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
} catch (e) {}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// 3. Fallback to API resource / endpoint category from URL
|
|
292
|
+
if (log.url) {
|
|
293
|
+
try {
|
|
294
|
+
const cleanUrl = log.url.split('?')[0].split('#')[0];
|
|
295
|
+
const withoutProto = cleanUrl.replace(/^https?:\/\//i, '');
|
|
296
|
+
const slashIdx = withoutProto.indexOf('/');
|
|
297
|
+
if (slashIdx !== -1) {
|
|
298
|
+
const pathSegments = withoutProto
|
|
299
|
+
.substring(slashIdx + 1)
|
|
300
|
+
.split('/')
|
|
301
|
+
.filter(Boolean);
|
|
302
|
+
const ignoredSegments = [
|
|
303
|
+
'api',
|
|
304
|
+
'v1',
|
|
305
|
+
'v2',
|
|
306
|
+
'v3',
|
|
307
|
+
'v4',
|
|
308
|
+
'rest',
|
|
309
|
+
'graphql',
|
|
310
|
+
'json',
|
|
311
|
+
'data',
|
|
312
|
+
'service',
|
|
313
|
+
'app',
|
|
314
|
+
];
|
|
315
|
+
const meaningful = pathSegments.filter(
|
|
316
|
+
s => !ignoredSegments.includes(s.toLowerCase()),
|
|
317
|
+
);
|
|
318
|
+
if (meaningful.length > 0) {
|
|
319
|
+
const seg = meaningful[0];
|
|
320
|
+
return seg.charAt(0).toUpperCase() + seg.slice(1);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const host = withoutProto.split('/')[0];
|
|
324
|
+
if (host) return host;
|
|
325
|
+
} catch (e) {}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return 'General';
|
|
329
|
+
};
|
|
330
|
+
|
|
224
331
|
export const flattenObject = (obj: any, prefix = ''): Record<string, any> => {
|
|
225
332
|
let result: Record<string, any> = {};
|
|
226
333
|
if (typeof obj === 'object' && obj !== null) {
|
|
@@ -409,6 +516,107 @@ export const getAppName = (): string => {
|
|
|
409
516
|
return 'App';
|
|
410
517
|
};
|
|
411
518
|
|
|
519
|
+
export const getAppVersionAndBuild = (): {
|
|
520
|
+
version: string;
|
|
521
|
+
build: string;
|
|
522
|
+
formatted: string;
|
|
523
|
+
} => {
|
|
524
|
+
let version = '';
|
|
525
|
+
let build = '';
|
|
526
|
+
|
|
527
|
+
// 1. Try ExpoApplication / ExponentConstants
|
|
528
|
+
const ExpoApplication = NativeModules.ExpoApplication;
|
|
529
|
+
if (ExpoApplication) {
|
|
530
|
+
if (typeof ExpoApplication.nativeAppVersion === 'string') {
|
|
531
|
+
version = ExpoApplication.nativeAppVersion;
|
|
532
|
+
}
|
|
533
|
+
if (typeof ExpoApplication.nativeBuildVersion === 'string') {
|
|
534
|
+
build = ExpoApplication.nativeBuildVersion;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const ExponentConstants = NativeModules.ExponentConstants;
|
|
539
|
+
if (ExponentConstants) {
|
|
540
|
+
const manifest = ExponentConstants.manifest || ExponentConstants.expoConfig;
|
|
541
|
+
if (manifest) {
|
|
542
|
+
if (!version && manifest.version) {
|
|
543
|
+
version = String(manifest.version);
|
|
544
|
+
}
|
|
545
|
+
if (!build) {
|
|
546
|
+
if (manifest.ios?.buildNumber) {
|
|
547
|
+
build = String(manifest.ios.buildNumber);
|
|
548
|
+
} else if (manifest.android?.versionCode) {
|
|
549
|
+
build = String(manifest.android.versionCode);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// 2. Try react-native-device-info
|
|
556
|
+
const RNDeviceInfo = NativeModules.RNDeviceInfo;
|
|
557
|
+
if (RNDeviceInfo) {
|
|
558
|
+
if (!version) {
|
|
559
|
+
if (typeof RNDeviceInfo.appVersion === 'string') {
|
|
560
|
+
version = RNDeviceInfo.appVersion;
|
|
561
|
+
} else if (typeof RNDeviceInfo.getVersion === 'function') {
|
|
562
|
+
try {
|
|
563
|
+
version = RNDeviceInfo.getVersion();
|
|
564
|
+
} catch (e) {}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (!build) {
|
|
568
|
+
if (typeof RNDeviceInfo.buildNumber === 'string') {
|
|
569
|
+
build = RNDeviceInfo.buildNumber;
|
|
570
|
+
} else if (typeof RNDeviceInfo.getBuildNumber === 'function') {
|
|
571
|
+
try {
|
|
572
|
+
build = RNDeviceInfo.getBuildNumber();
|
|
573
|
+
} catch (e) {}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// 3. Try PlatformConstants / Platform.constants
|
|
579
|
+
const constants =
|
|
580
|
+
(Platform.constants as any) || NativeModules.PlatformConstants;
|
|
581
|
+
if (constants) {
|
|
582
|
+
if (
|
|
583
|
+
!version &&
|
|
584
|
+
constants.Version &&
|
|
585
|
+
typeof constants.Version === 'string' &&
|
|
586
|
+
constants.Version.includes('.')
|
|
587
|
+
) {
|
|
588
|
+
version = constants.Version;
|
|
589
|
+
}
|
|
590
|
+
if (!version && constants.reactNativeVersion) {
|
|
591
|
+
const rnv = constants.reactNativeVersion;
|
|
592
|
+
if (rnv.major !== undefined) {
|
|
593
|
+
version = `${rnv.major}.${rnv.minor}.${rnv.patch}`;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// 4. Try Android AppInfo
|
|
599
|
+
const AppInfo = NativeModules.AppInfo;
|
|
600
|
+
if (AppInfo) {
|
|
601
|
+
if (!version && typeof AppInfo.versionName === 'string') {
|
|
602
|
+
version = AppInfo.versionName;
|
|
603
|
+
}
|
|
604
|
+
if (!build && typeof AppInfo.versionCode === 'string') {
|
|
605
|
+
build = AppInfo.versionCode;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Fallbacks
|
|
610
|
+
if (!version) version = '1.0.0';
|
|
611
|
+
if (!build) build = '1';
|
|
612
|
+
|
|
613
|
+
return {
|
|
614
|
+
version,
|
|
615
|
+
build,
|
|
616
|
+
formatted: `${version} (${build})`,
|
|
617
|
+
};
|
|
618
|
+
};
|
|
619
|
+
|
|
412
620
|
export const handleOpenExternalLink = (url: string): void => {
|
|
413
621
|
if (!url) return;
|
|
414
622
|
const openUrl = formatDisplayUrl(url);
|