react-native-in-app-debugger 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Api.jsx +131 -62
- package/README.md +21 -0
- package/index.jsx +116 -50
- package/package.json +8 -4
- package/useApiInterceptor.js +43 -32
package/Api.jsx
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
import React, { useState } from
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Text,
|
|
4
|
+
SectionList,
|
|
5
|
+
TextInput,
|
|
6
|
+
View,
|
|
7
|
+
Alert,
|
|
8
|
+
StyleSheet,
|
|
9
|
+
TouchableOpacity,
|
|
10
|
+
} from "react-native";
|
|
11
|
+
// import Clipboard from '@react-native-clipboard/clipboard';
|
|
12
|
+
let Clipboard;
|
|
13
|
+
try {
|
|
14
|
+
Clipboard = require("@react-native-clipboard/clipboard");
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error("Error importing Clipboard:", error);
|
|
17
|
+
}
|
|
4
18
|
|
|
5
19
|
const MAX_URL_LENGTH = 100;
|
|
6
20
|
|
|
7
21
|
const Row = ({ item }) => {
|
|
8
|
-
const [tab, setTab] = useState(
|
|
22
|
+
const [tab, setTab] = useState("response-body");
|
|
9
23
|
const hasResponse = item.response;
|
|
10
24
|
const Tab = ({ value, label }) => {
|
|
11
25
|
const isSelected = value === tab;
|
|
@@ -13,32 +27,49 @@ const Row = ({ item }) => {
|
|
|
13
27
|
<TouchableOpacity
|
|
14
28
|
activeOpacity={isSelected ? 1 : 0.7}
|
|
15
29
|
onPress={() => setTab(value)}
|
|
16
|
-
style={[
|
|
30
|
+
style={[
|
|
31
|
+
styles.selectionTab,
|
|
32
|
+
{ backgroundColor: isSelected ? "white" : undefined },
|
|
33
|
+
]}
|
|
17
34
|
>
|
|
18
|
-
<Text
|
|
35
|
+
<Text
|
|
36
|
+
style={{ color: isSelected ? "#000" : "#fff", textAlign: "center" }}
|
|
37
|
+
>
|
|
38
|
+
{label}
|
|
39
|
+
</Text>
|
|
19
40
|
</TouchableOpacity>
|
|
20
41
|
);
|
|
21
42
|
};
|
|
22
43
|
return (
|
|
23
44
|
<View style={styles.details}>
|
|
24
45
|
{item.request.url.length > MAX_URL_LENGTH && (
|
|
25
|
-
<Text style={{ color:
|
|
46
|
+
<Text style={{ color: "#ffffff99", paddingVertical: 20 }}>
|
|
47
|
+
{item.request.url}
|
|
48
|
+
</Text>
|
|
26
49
|
)}
|
|
27
50
|
<View>
|
|
28
|
-
<View style={{ flexDirection:
|
|
29
|
-
<Tab value=
|
|
30
|
-
{!!item.request.data &&
|
|
31
|
-
|
|
51
|
+
<View style={{ flexDirection: "row" }}>
|
|
52
|
+
<Tab value="response-body" label="Response Body" />
|
|
53
|
+
{!!item.request.data && (
|
|
54
|
+
<Tab value="request-body" label="Request Body" />
|
|
55
|
+
)}
|
|
56
|
+
<Tab value="request-header" label="Request Header" />
|
|
32
57
|
</View>
|
|
33
58
|
|
|
34
|
-
{tab ===
|
|
35
|
-
<Text style={{ color:
|
|
59
|
+
{tab === "response-body" && hasResponse && (
|
|
60
|
+
<Text style={{ color: "white" }}>
|
|
61
|
+
{JSON.stringify(item.response.data, undefined, 4)}
|
|
62
|
+
</Text>
|
|
36
63
|
)}
|
|
37
|
-
{tab ===
|
|
38
|
-
<Text style={{ color:
|
|
64
|
+
{tab === "request-body" && (
|
|
65
|
+
<Text style={{ color: "white" }}>
|
|
66
|
+
{JSON.stringify(item.request.data, undefined, 4)}
|
|
67
|
+
</Text>
|
|
39
68
|
)}
|
|
40
|
-
{tab ===
|
|
41
|
-
<Text style={{ color:
|
|
69
|
+
{tab === "request-header" && (
|
|
70
|
+
<Text style={{ color: "white" }}>
|
|
71
|
+
{JSON.stringify(item.request.headers, undefined, 4)}
|
|
72
|
+
</Text>
|
|
42
73
|
)}
|
|
43
74
|
</View>
|
|
44
75
|
</View>
|
|
@@ -46,48 +77,74 @@ const Row = ({ item }) => {
|
|
|
46
77
|
};
|
|
47
78
|
|
|
48
79
|
export default (props) => {
|
|
49
|
-
const [filter, setFilter] = useState(
|
|
80
|
+
const [filter, setFilter] = useState("");
|
|
50
81
|
const [errorOnly, setErrorOnly] = useState(false);
|
|
51
82
|
const [filterUrlOnly, setFilterUrlOnly] = useState(true);
|
|
52
83
|
const [expands, setExpands] = useState({});
|
|
53
|
-
const apis = props.apis.filter(
|
|
84
|
+
const apis = props.apis.filter(
|
|
85
|
+
(a) => !errorOnly || a.response?.status < 200 || a.response?.status >= 400
|
|
86
|
+
);
|
|
54
87
|
|
|
55
|
-
const hasError = apis.some(
|
|
88
|
+
const hasError = apis.some(
|
|
89
|
+
(a) => a.response?.status < 200 || a.response?.status >= 400
|
|
90
|
+
);
|
|
56
91
|
|
|
57
92
|
return (
|
|
58
93
|
<>
|
|
59
|
-
<View
|
|
94
|
+
<View
|
|
95
|
+
style={{
|
|
96
|
+
flexDirection: "row",
|
|
97
|
+
paddingLeft: 5,
|
|
98
|
+
alignItems: "center",
|
|
99
|
+
gap: 5,
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
60
102
|
{!!apis.length && !filter && (
|
|
61
103
|
<TouchableOpacity
|
|
62
|
-
style={{ padding: 5, backgroundColor:
|
|
104
|
+
style={{ padding: 5, backgroundColor: "white", borderRadius: 5 }}
|
|
63
105
|
onPress={() =>
|
|
64
|
-
Alert.alert(
|
|
65
|
-
{ text:
|
|
66
|
-
{ text:
|
|
106
|
+
Alert.alert("Are you sure", "You want to clear all logs", [
|
|
107
|
+
{ text: "Delete", onPress: props.clear, style: "cancel" },
|
|
108
|
+
{ text: "Cancel" },
|
|
67
109
|
])
|
|
68
110
|
}
|
|
69
111
|
>
|
|
70
|
-
<Text style={{ color:
|
|
112
|
+
<Text style={{ color: "black" }}>Clear {apis.length} APIs</Text>
|
|
71
113
|
</TouchableOpacity>
|
|
72
114
|
)}
|
|
73
115
|
{hasError && !filter && (
|
|
74
|
-
<TouchableOpacity
|
|
75
|
-
|
|
116
|
+
<TouchableOpacity
|
|
117
|
+
style={{ padding: 5 }}
|
|
118
|
+
onPress={() => setErrorOnly((v) => !v)}
|
|
119
|
+
>
|
|
120
|
+
<Text
|
|
121
|
+
style={{
|
|
122
|
+
color: "red",
|
|
123
|
+
textDecorationLine: errorOnly ? "line-through" : undefined,
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
Error Only
|
|
127
|
+
</Text>
|
|
76
128
|
</TouchableOpacity>
|
|
77
129
|
)}
|
|
78
|
-
<View style={{ flexDirection:
|
|
130
|
+
<View style={{ flexDirection: "row", flex: 1 }}>
|
|
79
131
|
<TextInput
|
|
80
132
|
value={filter}
|
|
81
|
-
placeholder=
|
|
82
|
-
clearButtonMode=
|
|
83
|
-
placeholderTextColor=
|
|
84
|
-
style={{ paddingHorizontal: 5, color:
|
|
133
|
+
placeholder="Filter..."
|
|
134
|
+
clearButtonMode="always"
|
|
135
|
+
placeholderTextColor="grey"
|
|
136
|
+
style={{ paddingHorizontal: 5, color: "white", flex: 1 }}
|
|
85
137
|
onChangeText={(t) => setFilter(t.toLowerCase())}
|
|
86
138
|
/>
|
|
87
139
|
</View>
|
|
88
140
|
{!!filter && (
|
|
89
|
-
<TouchableOpacity
|
|
90
|
-
|
|
141
|
+
<TouchableOpacity
|
|
142
|
+
style={{ padding: 5 }}
|
|
143
|
+
onPress={() => setFilterUrlOnly((v) => !v)}
|
|
144
|
+
>
|
|
145
|
+
<Text style={{ color: "#ffffff88" }}>
|
|
146
|
+
{filterUrlOnly ? "by URL" : "by URL & body"}
|
|
147
|
+
</Text>
|
|
91
148
|
</TouchableOpacity>
|
|
92
149
|
)}
|
|
93
150
|
</View>
|
|
@@ -99,22 +156,24 @@ export default (props) => {
|
|
|
99
156
|
.filter((a) =>
|
|
100
157
|
!filter || filterUrlOnly
|
|
101
158
|
? a.request.url.includes(filter)
|
|
102
|
-
: JSON.stringify(a).toLowerCase().includes(filter)
|
|
159
|
+
: JSON.stringify(a).toLowerCase().includes(filter)
|
|
103
160
|
)
|
|
104
161
|
.map((data) => ({ data: [data], id: data.id }))}
|
|
105
|
-
renderItem={(i) =>
|
|
162
|
+
renderItem={(i) =>
|
|
163
|
+
expands[i.item.id] ? <Row {...i} /> : <View style={{ height: 20 }} />
|
|
164
|
+
}
|
|
106
165
|
renderSectionHeader={({ section: { data } }) => {
|
|
107
166
|
const item = data[0];
|
|
108
167
|
const hasResponse = !!item.response;
|
|
109
168
|
|
|
110
169
|
let duration = 0;
|
|
111
170
|
if (item.response?.datetime) {
|
|
112
|
-
let [hr, min, sec] = item.request.datetime.split(
|
|
171
|
+
let [hr, min, sec] = item.request.datetime.split(" ")[0].split(":");
|
|
113
172
|
const start = new Date();
|
|
114
173
|
start.setHours(hr);
|
|
115
174
|
start.setMinutes(min);
|
|
116
175
|
start.setSeconds(sec);
|
|
117
|
-
[hr, min, sec] = item.response.datetime.split(
|
|
176
|
+
[hr, min, sec] = item.response.datetime.split(" ")[0].split(":");
|
|
118
177
|
const end = new Date();
|
|
119
178
|
end.setHours(hr);
|
|
120
179
|
end.setMinutes(min);
|
|
@@ -128,20 +187,24 @@ export default (props) => {
|
|
|
128
187
|
selectable
|
|
129
188
|
style={{
|
|
130
189
|
flex: 1,
|
|
131
|
-
color: hasResponse
|
|
190
|
+
color: hasResponse
|
|
191
|
+
? item.response.error
|
|
192
|
+
? "red"
|
|
193
|
+
: "white"
|
|
194
|
+
: "yellow",
|
|
132
195
|
marginVertical: 10,
|
|
133
196
|
}}
|
|
134
197
|
>
|
|
135
198
|
<Text style={{ opacity: 0.7 }}>
|
|
136
199
|
{item.request.method +
|
|
137
|
-
` (${item.response?.status ??
|
|
138
|
-
|
|
200
|
+
` (${item.response?.status ?? "no response"})` +
|
|
201
|
+
" - " +
|
|
139
202
|
item.request.datetime +
|
|
140
|
-
(hasResponse ?
|
|
141
|
-
|
|
203
|
+
(hasResponse ? " - " + duration + " second(s)" : "") +
|
|
204
|
+
"\n"}
|
|
142
205
|
</Text>
|
|
143
206
|
{item.request.url.slice(0, MAX_URL_LENGTH)}
|
|
144
|
-
{item.request.url.length > MAX_URL_LENGTH &&
|
|
207
|
+
{item.request.url.length > MAX_URL_LENGTH && "......."}
|
|
145
208
|
</Text>
|
|
146
209
|
<View style={{ gap: 4 }}>
|
|
147
210
|
<TouchableOpacity
|
|
@@ -155,18 +218,24 @@ export default (props) => {
|
|
|
155
218
|
}
|
|
156
219
|
style={styles.actionButton}
|
|
157
220
|
>
|
|
158
|
-
<Text style={{ color:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
onPress={() => {
|
|
162
|
-
const content = { ...item };
|
|
163
|
-
delete content.id;
|
|
164
|
-
Clipboard.setString(JSON.stringify(content, undefined, 4));
|
|
165
|
-
}}
|
|
166
|
-
style={styles.actionButton}
|
|
167
|
-
>
|
|
168
|
-
<Text style={{ color: 'black' }}>Copy</Text>
|
|
221
|
+
<Text style={{ color: "black" }}>
|
|
222
|
+
{isExpand ? "Hide" : "Show"}
|
|
223
|
+
</Text>
|
|
169
224
|
</TouchableOpacity>
|
|
225
|
+
{!!Clipboard && (
|
|
226
|
+
<TouchableOpacity
|
|
227
|
+
onPress={() => {
|
|
228
|
+
const content = { ...item };
|
|
229
|
+
delete content.id;
|
|
230
|
+
Clipboard.setString(
|
|
231
|
+
JSON.stringify(content, undefined, 4)
|
|
232
|
+
);
|
|
233
|
+
}}
|
|
234
|
+
style={styles.actionButton}
|
|
235
|
+
>
|
|
236
|
+
<Text style={{ color: "black" }}>Copy</Text>
|
|
237
|
+
</TouchableOpacity>
|
|
238
|
+
)}
|
|
170
239
|
</View>
|
|
171
240
|
</View>
|
|
172
241
|
);
|
|
@@ -179,18 +248,18 @@ export default (props) => {
|
|
|
179
248
|
const styles = StyleSheet.create({
|
|
180
249
|
details: {
|
|
181
250
|
padding: 5,
|
|
182
|
-
backgroundColor:
|
|
251
|
+
backgroundColor: "#171717",
|
|
183
252
|
paddingTop: 10,
|
|
184
253
|
paddingBottom: 40,
|
|
185
254
|
},
|
|
186
|
-
actionButton: { backgroundColor:
|
|
255
|
+
actionButton: { backgroundColor: "white", borderRadius: 5, padding: 4 },
|
|
187
256
|
rowHeader: {
|
|
188
|
-
flexDirection:
|
|
257
|
+
flexDirection: "row",
|
|
189
258
|
gap: 5,
|
|
190
|
-
backgroundColor:
|
|
259
|
+
backgroundColor: "black",
|
|
191
260
|
padding: 5,
|
|
192
261
|
paddingTop: 20,
|
|
193
|
-
shadowColor:
|
|
262
|
+
shadowColor: "black",
|
|
194
263
|
shadowOffset: {
|
|
195
264
|
width: 0,
|
|
196
265
|
height: 2,
|
|
@@ -202,7 +271,7 @@ const styles = StyleSheet.create({
|
|
|
202
271
|
zIndex: 99,
|
|
203
272
|
},
|
|
204
273
|
selectionTab: {
|
|
205
|
-
borderBottomColor:
|
|
274
|
+
borderBottomColor: "white",
|
|
206
275
|
borderBottomWidth: 2,
|
|
207
276
|
flex: 1,
|
|
208
277
|
borderTopEndRadius: 10,
|
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# react-native-in-app-debugger
|
|
2
|
+
|
|
3
|
+
summary
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Usage :
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
import React from 'react';
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Properties
|
|
15
|
+
|
|
16
|
+
All FlatList props should work plus props mentioned below
|
|
17
|
+
|
|
18
|
+
| Prop | Type | Description | Default | Required |
|
|
19
|
+
| ----------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
|
20
|
+
| `env` | string | Any text | | Optional |
|
|
21
|
+
|
package/index.jsx
CHANGED
|
@@ -1,38 +1,76 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
2
|
// hooks are prevented to be called conditionally, but in this case, bundle id / package name will never changed in run time, so it is safe to call the hooks under that condition
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
import React, { useState } from "react";
|
|
5
|
+
import {
|
|
6
|
+
Animated,
|
|
7
|
+
Text,
|
|
8
|
+
StyleSheet,
|
|
9
|
+
TouchableOpacity,
|
|
10
|
+
View,
|
|
11
|
+
SafeAreaView,
|
|
12
|
+
Dimensions,
|
|
13
|
+
} from "react-native";
|
|
14
|
+
// const DeviceInfo = React.lazy(() =>
|
|
15
|
+
// import("react-native-device-info").catch(() => ({ default: null }))
|
|
16
|
+
// );
|
|
11
17
|
|
|
12
|
-
|
|
18
|
+
let DeviceInfo;
|
|
19
|
+
try {
|
|
20
|
+
DeviceInfo = require("react-native-device-info");
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error("Error importing DeviceInfo:", error);
|
|
23
|
+
}
|
|
13
24
|
|
|
14
|
-
|
|
25
|
+
import useAnimation from "./useAnimation";
|
|
26
|
+
import Variables from "./Variables";
|
|
27
|
+
import Api from "./Api";
|
|
28
|
+
import useApiInterceptor from "./useApiInterceptor";
|
|
29
|
+
|
|
30
|
+
const dimension = Dimensions.get("window");
|
|
31
|
+
|
|
32
|
+
const version = DeviceInfo?.getReadableVersion() || "";
|
|
33
|
+
|
|
34
|
+
const Label = (props) => (
|
|
35
|
+
<Text
|
|
36
|
+
{...props}
|
|
37
|
+
numberOfLines={1}
|
|
38
|
+
ellipsizeMode="tail"
|
|
39
|
+
style={[styles.label, props.style]}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
15
42
|
|
|
16
43
|
export default ({ variables, env }) => {
|
|
17
44
|
const { apis, clear } = useApiInterceptor();
|
|
18
45
|
|
|
19
|
-
const [tab, setTab] = useState(
|
|
46
|
+
const [tab, setTab] = useState("api");
|
|
20
47
|
|
|
21
48
|
const errors = apis.filter((a) => a.response?.error).length;
|
|
22
49
|
const numPendingApiCalls = apis.filter((a) => !a.response).length;
|
|
23
|
-
let badgeHeight =
|
|
24
|
-
if (variables
|
|
25
|
-
if (variables
|
|
50
|
+
let badgeHeight = 20;
|
|
51
|
+
if (variables?.GIT_BRANCH) badgeHeight += 10;
|
|
52
|
+
if (variables?.BUILD_DATE_TIME) badgeHeight += 10;
|
|
53
|
+
const hasEnvOrVersion = !!env || !!version;
|
|
54
|
+
if (hasEnvOrVersion) badgeHeight += 10;
|
|
55
|
+
if (DeviceInfo) badgeHeight += 10;
|
|
26
56
|
|
|
27
|
-
const {
|
|
28
|
-
|
|
57
|
+
const {
|
|
58
|
+
translateX,
|
|
59
|
+
translateY,
|
|
60
|
+
borderRadius,
|
|
61
|
+
width,
|
|
62
|
+
height,
|
|
63
|
+
isOpen,
|
|
64
|
+
panResponder,
|
|
65
|
+
setIsOpen,
|
|
66
|
+
} = useAnimation(badgeHeight);
|
|
29
67
|
return (
|
|
30
68
|
<Animated.View
|
|
31
69
|
style={{
|
|
32
70
|
transform: [{ translateX }, { translateY }],
|
|
33
|
-
position:
|
|
71
|
+
position: "absolute",
|
|
34
72
|
borderRadius,
|
|
35
|
-
backgroundColor:
|
|
73
|
+
backgroundColor: "#000000" + (isOpen ? "dd" : "bb"),
|
|
36
74
|
height,
|
|
37
75
|
width,
|
|
38
76
|
}}
|
|
@@ -42,46 +80,69 @@ export default ({ variables, env }) => {
|
|
|
42
80
|
<TouchableOpacity onPress={() => setIsOpen(true)} style={styles.box}>
|
|
43
81
|
<View style={styles.badgeContainer}>
|
|
44
82
|
{!!numPendingApiCalls && (
|
|
45
|
-
<View style={[styles.badge, { backgroundColor:
|
|
46
|
-
<Text style={{ fontSize: 8, color:
|
|
83
|
+
<View style={[styles.badge, { backgroundColor: "orange" }]}>
|
|
84
|
+
<Text style={{ fontSize: 8, color: "white" }}>
|
|
85
|
+
{numPendingApiCalls}
|
|
86
|
+
</Text>
|
|
47
87
|
</View>
|
|
48
88
|
)}
|
|
49
89
|
{!!errors && (
|
|
50
|
-
<View style={[styles.badge, { backgroundColor:
|
|
51
|
-
<Text style={{ fontSize: 8, color:
|
|
90
|
+
<View style={[styles.badge, { backgroundColor: "red" }]}>
|
|
91
|
+
<Text style={{ fontSize: 8, color: "white" }}>{errors}</Text>
|
|
52
92
|
</View>
|
|
53
93
|
)}
|
|
54
94
|
</View>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
|
|
95
|
+
{(!!env || !!version) && (
|
|
96
|
+
<Label>{(env || "") + (env ? " " : "") + version}</Label>
|
|
97
|
+
)}
|
|
98
|
+
{!!DeviceInfo && (
|
|
99
|
+
<Label style={{ fontSize: 6 }}>
|
|
100
|
+
{DeviceInfo.getDeviceId() + " " + DeviceInfo.getSystemVersion()}
|
|
101
|
+
</Label>
|
|
102
|
+
)}
|
|
103
|
+
<Label style={{ fontSize: 6 }}>
|
|
104
|
+
{dimension.width + "x" + dimension.height}
|
|
105
|
+
</Label>
|
|
106
|
+
{variables?.GIT_BRANCH && (
|
|
107
|
+
<Label style={{ fontSize: 6 }}>{variables.GIT_BRANCH}</Label>
|
|
108
|
+
)}
|
|
109
|
+
{variables?.BUILD_DATE_TIME && (
|
|
110
|
+
<Label style={{ fontSize: 6 }}>{variables.BUILD_DATE_TIME}</Label>
|
|
111
|
+
)}
|
|
60
112
|
</TouchableOpacity>
|
|
61
113
|
) : (
|
|
62
114
|
<SafeAreaView style={{ flex: 1 }}>
|
|
63
|
-
<View style={{ flexDirection:
|
|
64
|
-
<View style={{ flex: 1, flexDirection:
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
115
|
+
<View style={{ flexDirection: "row", padding: 5 }}>
|
|
116
|
+
<View style={{ flex: 1, flexDirection: "row" }}>
|
|
117
|
+
{!!variables &&
|
|
118
|
+
["api", "variables"].map((t) => {
|
|
119
|
+
const isSelected = t === tab;
|
|
120
|
+
return (
|
|
121
|
+
<TouchableOpacity
|
|
122
|
+
onPress={() => setTab(t)}
|
|
123
|
+
activeOpacity={isSelected ? 1 : 0.7}
|
|
124
|
+
key={t}
|
|
125
|
+
style={{
|
|
126
|
+
flex: 1,
|
|
127
|
+
borderBottomWidth: +isSelected,
|
|
128
|
+
borderColor: "white",
|
|
129
|
+
}}
|
|
130
|
+
>
|
|
131
|
+
<Text style={{ color: "white", textAlign: "center" }}>
|
|
132
|
+
{t.toUpperCase()}
|
|
133
|
+
</Text>
|
|
134
|
+
</TouchableOpacity>
|
|
135
|
+
);
|
|
136
|
+
})}
|
|
78
137
|
</View>
|
|
79
138
|
<TouchableOpacity onPress={() => setIsOpen(false)}>
|
|
80
139
|
<Text style={styles.close}>X</Text>
|
|
81
140
|
</TouchableOpacity>
|
|
82
141
|
</View>
|
|
83
|
-
{tab ===
|
|
84
|
-
|
|
142
|
+
{tab === "variables" && !!variables && (
|
|
143
|
+
<Variables variables={variables} />
|
|
144
|
+
)}
|
|
145
|
+
{tab === "api" && <Api apis={apis} clear={clear} />}
|
|
85
146
|
</SafeAreaView>
|
|
86
147
|
)}
|
|
87
148
|
</Animated.View>
|
|
@@ -90,22 +151,27 @@ export default ({ variables, env }) => {
|
|
|
90
151
|
|
|
91
152
|
const styles = StyleSheet.create({
|
|
92
153
|
box: {
|
|
93
|
-
justifyContent:
|
|
94
|
-
width:
|
|
95
|
-
height:
|
|
154
|
+
justifyContent: "center",
|
|
155
|
+
width: "100%",
|
|
156
|
+
height: "100%",
|
|
96
157
|
},
|
|
97
|
-
label: { color:
|
|
158
|
+
label: { color: "white", textAlign: "center", fontSize: 8 },
|
|
98
159
|
badgeContainer: {
|
|
99
160
|
gap: 3,
|
|
100
|
-
flexDirection:
|
|
161
|
+
flexDirection: "row",
|
|
101
162
|
top: -8,
|
|
102
163
|
right: -3,
|
|
103
|
-
position:
|
|
164
|
+
position: "absolute",
|
|
104
165
|
zIndex: 999,
|
|
105
166
|
},
|
|
106
167
|
badge: {
|
|
107
168
|
padding: 4,
|
|
108
169
|
borderRadius: 999,
|
|
109
170
|
},
|
|
110
|
-
close: {
|
|
171
|
+
close: {
|
|
172
|
+
color: "white",
|
|
173
|
+
fontWeight: "bold",
|
|
174
|
+
fontSize: 16,
|
|
175
|
+
paddingHorizontal: 10,
|
|
176
|
+
},
|
|
111
177
|
});
|
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-in-app-debugger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.jsx",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"deploy": "npm publish --access=public"
|
|
8
9
|
},
|
|
9
|
-
"
|
|
10
|
-
"
|
|
10
|
+
"devDependencies": {},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"debugger"
|
|
13
|
+
],
|
|
14
|
+
"author": "Fattah Muhyiddeen <fattahmuhyiddeen@gmail.com>",
|
|
11
15
|
"license": "MIT"
|
|
12
16
|
}
|
package/useApiInterceptor.js
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
import { useEffect, useState } from
|
|
3
|
-
import
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Platform } from "react-native";
|
|
4
|
+
import XHRInterceptor from "react-native/Libraries/Network/XHRInterceptor.js";
|
|
4
5
|
|
|
5
6
|
const filterNonBusinessRelatedAPI = true;
|
|
6
7
|
const MAX_NUM_OF_API = 50;
|
|
7
8
|
|
|
8
9
|
const now = () =>
|
|
9
|
-
new Date().toLocaleTimeString(
|
|
10
|
-
hour:
|
|
11
|
-
minute:
|
|
12
|
-
second:
|
|
10
|
+
new Date().toLocaleTimeString("en-US", {
|
|
11
|
+
hour: "numeric",
|
|
12
|
+
minute: "numeric",
|
|
13
|
+
second: "numeric",
|
|
13
14
|
});
|
|
14
15
|
|
|
15
16
|
const shouldExclude = (url, method) =>
|
|
16
|
-
[
|
|
17
|
-
url.includes(
|
|
18
|
-
url.includes(
|
|
19
|
-
url.includes(
|
|
17
|
+
["HEAD"].includes(method) ||
|
|
18
|
+
url.includes("codepush") ||
|
|
19
|
+
url.includes("localhost") ||
|
|
20
|
+
url.includes("applicationinsights.azure.com");
|
|
20
21
|
|
|
21
22
|
const parse = (data) => {
|
|
22
23
|
try {
|
|
@@ -35,7 +36,10 @@ export default () => {
|
|
|
35
36
|
datetime: now(),
|
|
36
37
|
};
|
|
37
38
|
setApis((v) =>
|
|
38
|
-
[
|
|
39
|
+
[
|
|
40
|
+
{ request, id: Date.now().toString(36) + Math.random().toString(36) },
|
|
41
|
+
...v,
|
|
42
|
+
].slice(0, MAX_NUM_OF_API)
|
|
39
43
|
);
|
|
40
44
|
};
|
|
41
45
|
|
|
@@ -46,7 +50,12 @@ export default () => {
|
|
|
46
50
|
const oldData = [...v];
|
|
47
51
|
for (let i = 0; i < oldData.length; i++) {
|
|
48
52
|
const old = oldData[i];
|
|
49
|
-
if (
|
|
53
|
+
if (
|
|
54
|
+
old.response ||
|
|
55
|
+
old.request.url !== data.config.url ||
|
|
56
|
+
old.request.method !== data.config.method
|
|
57
|
+
)
|
|
58
|
+
continue;
|
|
50
59
|
|
|
51
60
|
oldData[i].response = {
|
|
52
61
|
...data,
|
|
@@ -87,27 +96,29 @@ export default () => {
|
|
|
87
96
|
}
|
|
88
97
|
const data = parse(_response);
|
|
89
98
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
99
|
+
if (Platform.OS === "ios") {
|
|
100
|
+
xhr.addEventListener("load", function () {
|
|
101
|
+
try {
|
|
102
|
+
const reader = new FileReader();
|
|
103
|
+
reader.readAsText(xhr.response);
|
|
104
|
+
reader.onload = function () {
|
|
105
|
+
const response = JSON.parse(reader.result);
|
|
106
|
+
receiveResponse({
|
|
107
|
+
config: {
|
|
108
|
+
url,
|
|
109
|
+
method,
|
|
110
|
+
},
|
|
111
|
+
data: response,
|
|
112
|
+
status,
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
} catch (e) {
|
|
116
|
+
console.log(e);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
109
120
|
|
|
110
|
-
if (!data.blobId) {
|
|
121
|
+
if (Platform.OS === "ios" && !data.blobId) {
|
|
111
122
|
receiveResponse({
|
|
112
123
|
config: {
|
|
113
124
|
url,
|