react-native-in-app-debugger 1.0.5 → 1.0.8
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/Api.jsx +42 -27
- package/Variables.jsx +4 -4
- package/index.jsx +26 -17
- package/package.json +1 -1
- package/useApiInterceptor.js +31 -51
package/Api.jsx
CHANGED
|
@@ -13,15 +13,21 @@ let Clipboard;
|
|
|
13
13
|
try {
|
|
14
14
|
Clipboard = require("@react-native-clipboard/clipboard")?.default;
|
|
15
15
|
} catch (error) {
|
|
16
|
-
console.error("Error importing Clipboard:", error);
|
|
16
|
+
// console.error("Error importing Clipboard:", error);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const MAX_URL_LENGTH = 100;
|
|
20
20
|
|
|
21
21
|
const Row = ({ item }) => {
|
|
22
|
-
const
|
|
22
|
+
const tabs = [
|
|
23
|
+
{ value: "Response Body" },
|
|
24
|
+
{ value: "Request Body", hide: !item.request.data },
|
|
25
|
+
{ value: "Request Body" },
|
|
26
|
+
];
|
|
27
|
+
const [tab, setTab] = useState(tabs[0].value);
|
|
23
28
|
const hasResponse = item.response;
|
|
24
|
-
const Tab = ({ value,
|
|
29
|
+
const Tab = ({ value, hide }) => {
|
|
30
|
+
if (hide) return null;
|
|
25
31
|
const isSelected = value === tab;
|
|
26
32
|
return (
|
|
27
33
|
<TouchableOpacity
|
|
@@ -33,13 +39,17 @@ const Row = ({ item }) => {
|
|
|
33
39
|
]}
|
|
34
40
|
>
|
|
35
41
|
<Text
|
|
36
|
-
style={{
|
|
42
|
+
style={{
|
|
43
|
+
color: isSelected ? "#000" : "#ffffff88",
|
|
44
|
+
textAlign: "center",
|
|
45
|
+
}}
|
|
37
46
|
>
|
|
38
|
-
{
|
|
47
|
+
{value}
|
|
39
48
|
</Text>
|
|
40
49
|
</TouchableOpacity>
|
|
41
50
|
);
|
|
42
51
|
};
|
|
52
|
+
|
|
43
53
|
return (
|
|
44
54
|
<View style={styles.details}>
|
|
45
55
|
{item.request.url.length > MAX_URL_LENGTH && (
|
|
@@ -49,24 +59,22 @@ const Row = ({ item }) => {
|
|
|
49
59
|
)}
|
|
50
60
|
<View>
|
|
51
61
|
<View style={{ flexDirection: "row" }}>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
)}
|
|
56
|
-
<Tab value="request-header" label="Request Header" />
|
|
62
|
+
{tabs.map((t) => (
|
|
63
|
+
<Tab key={t.value} {...t} />
|
|
64
|
+
))}
|
|
57
65
|
</View>
|
|
58
66
|
|
|
59
|
-
{tab ===
|
|
67
|
+
{tab === tabs[0].value && hasResponse && (
|
|
60
68
|
<Text style={{ color: "white" }}>
|
|
61
69
|
{JSON.stringify(item.response.data, undefined, 4)}
|
|
62
70
|
</Text>
|
|
63
71
|
)}
|
|
64
|
-
{tab ===
|
|
72
|
+
{tab === tabs[1].value && (
|
|
65
73
|
<Text style={{ color: "white" }}>
|
|
66
74
|
{JSON.stringify(item.request.data, undefined, 4)}
|
|
67
75
|
</Text>
|
|
68
76
|
)}
|
|
69
|
-
{tab ===
|
|
77
|
+
{tab === tabs[2].value && (
|
|
70
78
|
<Text style={{ color: "white" }}>
|
|
71
79
|
{JSON.stringify(item.request.headers, undefined, 4)}
|
|
72
80
|
</Text>
|
|
@@ -148,6 +156,13 @@ export default (props) => {
|
|
|
148
156
|
</TouchableOpacity>
|
|
149
157
|
)}
|
|
150
158
|
</View>
|
|
159
|
+
{!filter &&
|
|
160
|
+
!!props.maxNumOfApiToStore &&
|
|
161
|
+
apis.length === props.maxNumOfApiToStore && (
|
|
162
|
+
<Text style={{ color: "#ffffff88", padding: 10 }}>
|
|
163
|
+
Capped to only latest {props.maxNumOfApiToStore} APIs
|
|
164
|
+
</Text>
|
|
165
|
+
)}
|
|
151
166
|
<SectionList
|
|
152
167
|
contentContainerStyle={{ padding: 5 }}
|
|
153
168
|
keyExtractor={(i) => i.id}
|
|
@@ -166,19 +181,19 @@ export default (props) => {
|
|
|
166
181
|
const item = data[0];
|
|
167
182
|
const hasResponse = !!item.response;
|
|
168
183
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
184
|
+
const duration = item.response?.timestamp
|
|
185
|
+
? ~~(item.response?.timestamp - item.request.timestamp) / 1000
|
|
186
|
+
: 0;
|
|
187
|
+
const date = new Date(item.request.datetime);
|
|
188
|
+
let hour = date.getHours();
|
|
189
|
+
const minute = date.getMinutes();
|
|
190
|
+
|
|
191
|
+
const amPm = hour >= 12 ? "PM" : "AM";
|
|
192
|
+
|
|
193
|
+
if (hour > 12) {
|
|
194
|
+
hour -= 12;
|
|
195
|
+
} else if (hour === 0) {
|
|
196
|
+
hour = 12;
|
|
182
197
|
}
|
|
183
198
|
const isExpand = expands[item.id];
|
|
184
199
|
return (
|
|
@@ -199,7 +214,7 @@ export default (props) => {
|
|
|
199
214
|
{item.request.method +
|
|
200
215
|
` (${item.response?.status ?? "no response"})` +
|
|
201
216
|
" - " +
|
|
202
|
-
item.request.
|
|
217
|
+
item.request.time +
|
|
203
218
|
(hasResponse ? " - " + duration + " second(s)" : "") +
|
|
204
219
|
"\n"}
|
|
205
220
|
</Text>
|
package/Variables.jsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { Text, FlatList, TextInput } from 'react-native';
|
|
3
3
|
|
|
4
|
-
export default ({
|
|
4
|
+
export default ({ variables }) => {
|
|
5
5
|
const [filter, setFilter] = useState('');
|
|
6
6
|
|
|
7
7
|
return (
|
|
@@ -15,13 +15,13 @@ export default ({ envs }) => {
|
|
|
15
15
|
/>
|
|
16
16
|
<FlatList
|
|
17
17
|
contentContainerStyle={{ padding: 5, paddingBottom: 20 }}
|
|
18
|
-
data={Object.keys(
|
|
19
|
-
(k) => !filter ||
|
|
18
|
+
data={Object.keys(variables).filter(
|
|
19
|
+
(k) => !filter || variables[k].toLowerCase().includes(filter) || k.toLowerCase().includes(filter),
|
|
20
20
|
)}
|
|
21
21
|
keyExtractor={(i) => i}
|
|
22
22
|
renderItem={({ item }) => (
|
|
23
23
|
<Text selectable style={{ color: 'white', marginVertical: 10 }}>
|
|
24
|
-
{item + ' : ' +
|
|
24
|
+
{item + ' : ' + variables[item]}
|
|
25
25
|
</Text>
|
|
26
26
|
)}
|
|
27
27
|
/>
|
package/index.jsx
CHANGED
|
@@ -19,7 +19,7 @@ let DeviceInfo;
|
|
|
19
19
|
try {
|
|
20
20
|
DeviceInfo = require("react-native-device-info");
|
|
21
21
|
} catch (error) {
|
|
22
|
-
console.error("Error importing DeviceInfo:", error);
|
|
22
|
+
// console.error("Error importing DeviceInfo:", error);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
import useAnimation from "./useAnimation";
|
|
@@ -29,7 +29,7 @@ import useApiInterceptor from "./useApiInterceptor";
|
|
|
29
29
|
|
|
30
30
|
const dimension = Dimensions.get("window");
|
|
31
31
|
|
|
32
|
-
const
|
|
32
|
+
const v = DeviceInfo?.getReadableVersion() || "";
|
|
33
33
|
|
|
34
34
|
const Label = (props) => (
|
|
35
35
|
<Text
|
|
@@ -40,8 +40,8 @@ const Label = (props) => (
|
|
|
40
40
|
/>
|
|
41
41
|
);
|
|
42
42
|
|
|
43
|
-
export default ({ variables, env }) => {
|
|
44
|
-
const { apis, clear } = useApiInterceptor();
|
|
43
|
+
export default ({ variables, env, version = v, maxNumOfApiToStore = 0 }) => {
|
|
44
|
+
const { apis, clear } = useApiInterceptor(maxNumOfApiToStore);
|
|
45
45
|
|
|
46
46
|
const [tab, setTab] = useState("api");
|
|
47
47
|
|
|
@@ -74,6 +74,7 @@ export default ({ variables, env }) => {
|
|
|
74
74
|
backgroundColor: "#000000" + (isOpen ? "dd" : "bb"),
|
|
75
75
|
height,
|
|
76
76
|
width,
|
|
77
|
+
borderTopRightRadius: numPendingApiCalls || errors ? 0 : undefined,
|
|
77
78
|
}}
|
|
78
79
|
{...(isOpen ? {} : panResponder.panHandlers)}
|
|
79
80
|
>
|
|
@@ -97,18 +98,14 @@ export default ({ variables, env }) => {
|
|
|
97
98
|
<Label>{(env || "") + (env ? " " : "") + version}</Label>
|
|
98
99
|
)}
|
|
99
100
|
{!!DeviceInfo && (
|
|
100
|
-
<Label
|
|
101
|
+
<Label>
|
|
101
102
|
{DeviceInfo.getDeviceId() + " " + DeviceInfo.getSystemVersion()}
|
|
102
103
|
</Label>
|
|
103
104
|
)}
|
|
104
|
-
<Label
|
|
105
|
-
|
|
106
|
-
</Label>
|
|
107
|
-
{variables?.GIT_BRANCH && (
|
|
108
|
-
<Label style={{ fontSize: 6 }}>{variables.GIT_BRANCH}</Label>
|
|
109
|
-
)}
|
|
105
|
+
<Label>{dimension.width + "x" + dimension.height}</Label>
|
|
106
|
+
{variables?.GIT_BRANCH && <Label>{variables.GIT_BRANCH}</Label>}
|
|
110
107
|
{variables?.BUILD_DATE_TIME && (
|
|
111
|
-
<Label
|
|
108
|
+
<Label>{variables.BUILD_DATE_TIME}</Label>
|
|
112
109
|
)}
|
|
113
110
|
</TouchableOpacity>
|
|
114
111
|
) : (
|
|
@@ -129,7 +126,13 @@ export default ({ variables, env }) => {
|
|
|
129
126
|
borderColor: "white",
|
|
130
127
|
}}
|
|
131
128
|
>
|
|
132
|
-
<Text
|
|
129
|
+
<Text
|
|
130
|
+
style={{
|
|
131
|
+
color: "white",
|
|
132
|
+
opacity: isSelected ? 1 : 0.5,
|
|
133
|
+
textAlign: "center",
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
133
136
|
{t.toUpperCase()}
|
|
134
137
|
</Text>
|
|
135
138
|
</TouchableOpacity>
|
|
@@ -143,7 +146,13 @@ export default ({ variables, env }) => {
|
|
|
143
146
|
{tab === "variables" && !!variables && (
|
|
144
147
|
<Variables variables={variables} />
|
|
145
148
|
)}
|
|
146
|
-
{tab === "api" &&
|
|
149
|
+
{tab === "api" && (
|
|
150
|
+
<Api
|
|
151
|
+
apis={apis}
|
|
152
|
+
clear={clear}
|
|
153
|
+
maxNumOfApiToStore={maxNumOfApiToStore}
|
|
154
|
+
/>
|
|
155
|
+
)}
|
|
147
156
|
</SafeAreaView>
|
|
148
157
|
)}
|
|
149
158
|
</Animated.View>
|
|
@@ -156,12 +165,12 @@ const styles = StyleSheet.create({
|
|
|
156
165
|
width: "100%",
|
|
157
166
|
height: "100%",
|
|
158
167
|
},
|
|
159
|
-
label: { color: "white", textAlign: "center", fontSize:
|
|
168
|
+
label: { color: "white", textAlign: "center", fontSize: 6 },
|
|
160
169
|
badgeContainer: {
|
|
161
170
|
gap: 3,
|
|
162
171
|
flexDirection: "row",
|
|
163
|
-
top: -
|
|
164
|
-
right: -
|
|
172
|
+
top: -12,
|
|
173
|
+
right: -6,
|
|
165
174
|
position: "absolute",
|
|
166
175
|
zIndex: 999,
|
|
167
176
|
},
|
package/package.json
CHANGED
package/useApiInterceptor.js
CHANGED
|
@@ -1,17 +1,7 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
import { useEffect, useState } from "react";
|
|
3
|
-
import { Platform } from "react-native";
|
|
4
2
|
import XHRInterceptor from "react-native/Libraries/Network/XHRInterceptor.js";
|
|
5
3
|
|
|
6
4
|
const filterNonBusinessRelatedAPI = true;
|
|
7
|
-
const MAX_NUM_OF_API = 50;
|
|
8
|
-
|
|
9
|
-
const now = () =>
|
|
10
|
-
new Date().toLocaleTimeString("en-US", {
|
|
11
|
-
hour: "numeric",
|
|
12
|
-
minute: "numeric",
|
|
13
|
-
second: "numeric",
|
|
14
|
-
});
|
|
15
5
|
|
|
16
6
|
const shouldExclude = (url, method) =>
|
|
17
7
|
["HEAD"].includes(method) ||
|
|
@@ -27,20 +17,34 @@ const parse = (data) => {
|
|
|
27
17
|
}
|
|
28
18
|
};
|
|
29
19
|
|
|
30
|
-
export default () => {
|
|
20
|
+
export default (maxNumOfApiToStore) => {
|
|
31
21
|
const [apis, setApis] = useState([]);
|
|
32
22
|
|
|
33
23
|
const makeRequest = (data) => {
|
|
24
|
+
const date = new Date();
|
|
25
|
+
let hour = date.getHours();
|
|
26
|
+
const minute = (date.getMinutes() + "").padStart(2, "0");
|
|
27
|
+
|
|
28
|
+
const amPm = hour >= 12 ? "PM" : "AM";
|
|
29
|
+
|
|
30
|
+
if (hour > 12) {
|
|
31
|
+
hour -= 12;
|
|
32
|
+
} else if (hour === 0) {
|
|
33
|
+
hour = 12;
|
|
34
|
+
}
|
|
34
35
|
const request = {
|
|
35
36
|
...data,
|
|
36
|
-
|
|
37
|
+
timestamp: performance.now(),
|
|
38
|
+
time: `${hour}:${minute} ${amPm}`,
|
|
37
39
|
};
|
|
38
|
-
setApis((v) =>
|
|
39
|
-
[
|
|
40
|
+
setApis((v) => {
|
|
41
|
+
const newData = [
|
|
40
42
|
{ request, id: Date.now().toString(36) + Math.random().toString(36) },
|
|
41
43
|
...v,
|
|
42
|
-
]
|
|
43
|
-
|
|
44
|
+
];
|
|
45
|
+
if (maxNumOfApiToStore) newData.slice(0, maxNumOfApiToStore);
|
|
46
|
+
return newData;
|
|
47
|
+
});
|
|
44
48
|
};
|
|
45
49
|
|
|
46
50
|
const receiveResponse = (data) => {
|
|
@@ -59,7 +63,7 @@ export default () => {
|
|
|
59
63
|
|
|
60
64
|
oldData[i].response = {
|
|
61
65
|
...data,
|
|
62
|
-
|
|
66
|
+
timestamp: performance.now(),
|
|
63
67
|
error,
|
|
64
68
|
};
|
|
65
69
|
break;
|
|
@@ -73,6 +77,7 @@ export default () => {
|
|
|
73
77
|
XHRInterceptor.enableInterception();
|
|
74
78
|
// console.log('API interceptor status', XHRInterceptor.isInterceptorEnabled());
|
|
75
79
|
XHRInterceptor.setSendCallback((...obj) => {
|
|
80
|
+
obj[1].responseType = "text";
|
|
76
81
|
const data = parse(obj[0]);
|
|
77
82
|
|
|
78
83
|
const { _method: method, _url: url, _headers: headers } = obj[1];
|
|
@@ -89,45 +94,20 @@ export default () => {
|
|
|
89
94
|
});
|
|
90
95
|
|
|
91
96
|
XHRInterceptor.setResponseCallback((...obj) => {
|
|
92
|
-
const
|
|
93
|
-
const { _method: method, _url: url, _response, status } = xhr;
|
|
97
|
+
const { _method: method, _url: url, _response, status } = obj[5];
|
|
94
98
|
if (filterNonBusinessRelatedAPI) {
|
|
95
99
|
if (shouldExclude(url, method)) return;
|
|
96
100
|
}
|
|
97
101
|
const data = parse(_response);
|
|
98
102
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
config: {
|
|
108
|
-
url,
|
|
109
|
-
method,
|
|
110
|
-
},
|
|
111
|
-
data: response,
|
|
112
|
-
status,
|
|
113
|
-
});
|
|
114
|
-
};
|
|
115
|
-
} catch (e) {
|
|
116
|
-
console.log(e);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (Platform.OS === "android" || !data.blobId) {
|
|
122
|
-
receiveResponse({
|
|
123
|
-
config: {
|
|
124
|
-
url,
|
|
125
|
-
method,
|
|
126
|
-
},
|
|
127
|
-
data,
|
|
128
|
-
status,
|
|
129
|
-
});
|
|
130
|
-
}
|
|
103
|
+
receiveResponse({
|
|
104
|
+
config: {
|
|
105
|
+
url,
|
|
106
|
+
method,
|
|
107
|
+
},
|
|
108
|
+
data,
|
|
109
|
+
status,
|
|
110
|
+
});
|
|
131
111
|
});
|
|
132
112
|
}, []);
|
|
133
113
|
|