Skip to content

Commit ee94329

Browse files
committed
feat: update debugger UI
1 parent 8ddc120 commit ee94329

22 files changed

+457
-327
lines changed

example/src/App.tsx

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable no-console */
2-
import axios from 'axios';
3-
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
2+
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
3+
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
44
import Xenon from 'react-native-xenon';
55

66
function Button({ title, onPress }: { title: string; onPress: () => void }) {
@@ -13,28 +13,19 @@ function Button({ title, onPress }: { title: string; onPress: () => void }) {
1313

1414
export default function App() {
1515
return (
16-
<>
17-
<View style={styles.container}>
16+
<SafeAreaProvider>
17+
<SafeAreaView style={styles.container}>
1818
<Button
19-
title="Fetch: Get pokemon"
19+
title="Fetch users"
2020
onPress={() => {
21-
fetch('https://pokeapi.co/api/v2/pokemon/ditto')
22-
.then(res => res.json())
23-
.then(console.log);
21+
fetch('https://jsonplaceholder.typicode.com/users?_start=5&_limit=5&_embed=posts')
22+
.then(response => response.json())
23+
.then(json => console.log(json));
2424
}}
2525
/>
2626

2727
<Button
28-
title="Fetch: Get posts"
29-
onPress={() => {
30-
fetch('https://jsonplaceholder.typicode.com/posts?userId=1')
31-
.then(res => res.json())
32-
.then(console.log);
33-
}}
34-
/>
35-
36-
<Button
37-
title="Fetch: Create post"
28+
title="Create a post"
3829
onPress={() => {
3930
fetch('https://jsonplaceholder.typicode.com/posts', {
4031
method: 'POST',
@@ -47,35 +38,56 @@ export default function App() {
4738
'Content-type': 'application/json; charset=UTF-8',
4839
},
4940
})
50-
.then(res => res.json())
51-
.then(console.log);
41+
.then(response => response.json())
42+
.then(json => console.info(json));
5243
}}
5344
/>
5445

5546
<Button
56-
title="Axios: Get pokemon"
47+
title="Update a post"
5748
onPress={() => {
58-
axios('https://pokeapi.co/api/v2/pokemon/ditto').then(console.log);
49+
fetch('https://jsonplaceholder.typicode.com/posts/1', {
50+
method: 'PUT',
51+
body: JSON.stringify({
52+
id: 1,
53+
title: 'foo',
54+
body: 'bar',
55+
userId: 1,
56+
}),
57+
headers: {
58+
'Content-type': 'application/json; charset=UTF-8',
59+
},
60+
})
61+
.then(response => response.json())
62+
.then(json => console.warn(json));
5963
}}
6064
/>
6165

6266
<Button
63-
title="Axios: Get posts"
67+
title="Patch a post"
6468
onPress={() => {
65-
axios('https://jsonplaceholder.typicode.com/posts?userId=1').then(console.log);
69+
fetch('https://jsonplaceholder.typicode.com/posts/1', {
70+
method: 'PATCH',
71+
body: JSON.stringify({
72+
title: 'foo',
73+
}),
74+
headers: {
75+
'Content-type': 'application/json; charset=UTF-8',
76+
},
77+
})
78+
.then(response => response.json())
79+
.then(json => console.warn(json));
6680
}}
6781
/>
6882

6983
<Button
70-
title="Axios: Create post"
84+
title="Delete a post"
7185
onPress={() => {
72-
axios
73-
.post('https://jsonplaceholder.typicode.com/posts', {
74-
title: 'foo',
75-
body: 'bar',
76-
userId: 1,
77-
})
78-
.then(console.log);
86+
fetch('https://jsonplaceholder.typicode.com/posts/1', {
87+
method: 'DELETE',
88+
})
89+
.then(response => response.json())
90+
.then(json => console.error(json));
7991
}}
8092
/>
8193

@@ -106,19 +118,20 @@ export default function App() {
106118
Xenon.isVisible() ? Xenon.hide() : Xenon.show();
107119
}}
108120
/>
109-
</View>
121+
</SafeAreaView>
110122
<Xenon.Component />
111-
</>
123+
</SafeAreaProvider>
112124
);
113125
}
114126

115127
const styles = StyleSheet.create({
116128
container: {
117129
flex: 1,
118-
justifyContent: 'center',
119-
alignItems: 'center',
130+
flexWrap: 'wrap',
131+
flexDirection: 'row',
120132
backgroundColor: 'white',
121-
rowGap: 8,
133+
gap: 8,
134+
padding: 8,
122135
},
123136
button: {
124137
paddingHorizontal: 16,

src/core/utils.ts

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import { URL } from 'react-native-url-polyfill';
2-
import { NetworkType, type HttpRequest, type WebSocketRequest } from '../types';
2+
import { NetworkType, type HttpRequest, type LogMessage, type WebSocketRequest } from '../types';
3+
import colors from '../theme/colors';
34

45
export const getNetworkUtils = (data: HttpRequest | WebSocketRequest) => {
56
const isHttp = data?.type !== NetworkType.WS;
67
const requestUrl = new URL(data.url);
78

89
const overviewShown = !!data.url;
9-
const headersShown = isHttp && (!!data.requestHeaders || !!data.responseHeaders);
10+
const httpHeadersShown = isHttp && (!!data.requestHeaders?.size || !!data.responseHeaders?.size);
11+
const websocketHeadersShown = !isHttp && !!Object.keys(data.options?.headers ?? {}).length;
12+
const headersShown = httpHeadersShown || websocketHeadersShown;
1013
const requestShown = isHttp && (!!requestUrl.search || !!data.body);
1114
const responseShown = isHttp && !!data.response;
1215
const messagesShown = !isHttp && !!data.messages;
@@ -22,6 +25,33 @@ export const getNetworkUtils = (data: HttpRequest | WebSocketRequest) => {
2225
};
2326
};
2427

28+
const hexToHexAlpha = (hex: string, opacity: number) =>
29+
`${hex}${`${(Math.min(Math.max(opacity, 0), 1) * 255).toString(16)}0`.slice(0, 2)}`;
30+
31+
export const getConsoleTypeColor = (type: LogMessage['type']) => {
32+
let color: string;
33+
switch (type) {
34+
case 'log':
35+
color = colors.white;
36+
break;
37+
case 'info':
38+
color = colors.blue;
39+
break;
40+
case 'warn':
41+
case 'debug':
42+
case 'trace':
43+
color = colors.yellow;
44+
break;
45+
case 'error':
46+
color = colors.red;
47+
break;
48+
default:
49+
color = colors.white;
50+
}
51+
52+
return hexToHexAlpha(color, 0.25);
53+
};
54+
2555
//#region metrics
2656
export const getVerticalSafeMargin = (screenHeight: number) => screenHeight / 8;
2757

@@ -36,7 +66,7 @@ export const getHttpInterceptorId = () => {
3666
//#endregion
3767

3868
//#region formatters
39-
export const limitChar = (value: any, limit = 5000) => {
69+
const limitChar = (value: any, limit = 5000) => {
4070
const stringValue = typeof value === 'string' ? value : JSON.stringify(value ?? '');
4171

4272
return stringValue.length > limit
@@ -53,24 +83,23 @@ export const keyValueToString = (
5383

5484
export const formatRequestMethod = (method?: string) => method ?? 'GET';
5585

56-
export const formatRequestDuration = (duration?: number) =>
57-
duration ? `${duration}ms` : 'pending';
86+
export const formatRequestDuration = (startTime?: number, endTime?: number) => {
87+
if (typeof startTime !== 'number' || typeof endTime !== 'number') return 'pending';
88+
return `${endTime - startTime}ms`;
89+
};
5890

5991
export const formatRequestStatusCode = (statusCode?: number) => `${statusCode ?? 'pending'}`;
6092

61-
export const formatLogMessage = (type: string, values: any[]) => {
62-
const message: string = values.reduce(
63-
(pre, cur, index) => pre + (!index ? '' : ', ') + limitChar(cur),
64-
'',
65-
);
66-
67-
return `${type.toUpperCase()}: ${message}`;
93+
export const formatLogMessage = (values: any[]) => {
94+
return values.reduce((pre, cur, index) => pre + (!index ? '' : ', ') + limitChar(cur), '');
6895
};
6996

7097
export const beautify = (data: any, beautified: boolean) => {
98+
if (!data) return '';
99+
71100
try {
72101
const res = typeof data === 'string' ? JSON.parse(data) : data;
73-
return beautified ? JSON.stringify(res, null, 2) : limitChar(res);
102+
return beautified ? JSON.stringify(res, null, 4) : limitChar(res);
74103
} catch (error) {
75104
return limitChar(data);
76105
}

src/hooks/useNetworkInterceptor.ts

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,10 @@ export default function useNetworkInterceptor({ autoEnabled }: NetworkIntercepto
5353
setNetworkRequests((draft: NetworkRequests<HttpRequest>) => {
5454
if (!draft.get(id)) return draft;
5555

56-
const requestHeaderNewLine: Parameters<typeof keyValueToString>[2] = draft.get(id)!
57-
.requestHeadersString?.length
58-
? 'leading'
59-
: null;
60-
61-
const currentHeaderLine = keyValueToString(header, value, requestHeaderNewLine);
56+
const currentHeaderLine = keyValueToString(header, value);
6257

6358
const fetchRequestHeaderLineRegex = RegExp(
64-
keyValueToString(NETWORK_REQUEST_HEADER, NetworkType.Fetch, requestHeaderNewLine),
59+
keyValueToString(NETWORK_REQUEST_HEADER, NetworkType.Fetch),
6560
'gi',
6661
);
6762

@@ -72,20 +67,19 @@ export default function useNetworkInterceptor({ autoEnabled }: NetworkIntercepto
7267
if (isFetchInXHR) {
7368
draft.delete(id);
7469
} else {
75-
draft.get(id)!.requestHeadersString ??= '';
76-
draft.get(id)!.requestHeadersString += currentHeaderLine;
77-
draft.get(id)!.requestHeaders ??= {};
78-
draft.get(id)!.requestHeaders![header] = value;
70+
draft.get(id)!.requestHeaders ??= new Map();
71+
draft.get(id)!.requestHeaders!.set(header, value);
7972
}
8073
});
8174
};
8275

83-
const sendCallback: HttpHandlers['send'] = (id, data) => {
76+
const sendCallback: HttpHandlers['send'] = (id, startTime, data) => {
8477
if (!id) return;
8578

8679
setNetworkRequests((draft: NetworkRequests<HttpRequest>) => {
8780
if (!draft.get(id)) return draft;
8881

82+
draft.get(id)!.startTime = startTime;
8983
draft.get(id)!.body = data;
9084
});
9185
};
@@ -111,7 +105,7 @@ export default function useNetworkInterceptor({ autoEnabled }: NetworkIntercepto
111105
id,
112106
status,
113107
timeout,
114-
duration,
108+
endTime,
115109
response,
116110
responseURL,
117111
responseType,
@@ -123,7 +117,7 @@ export default function useNetworkInterceptor({ autoEnabled }: NetworkIntercepto
123117

124118
draft.get(id)!.status = status;
125119
draft.get(id)!.timeout = timeout;
126-
draft.get(id)!.duration = duration;
120+
draft.get(id)!.endTime = endTime;
127121
draft.get(id)!.response = response;
128122
if (responseURL) draft.get(id)!.url = responseURL;
129123
draft.get(id)!.responseType = responseType;
@@ -148,11 +142,18 @@ export default function useNetworkInterceptor({ autoEnabled }: NetworkIntercepto
148142
}, [setNetworkRequests]);
149143

150144
const enableWebSocketInterception = useCallback(() => {
151-
const connectCallback: WebSocketHandlers['connect'] = (url, protocols, options, socketId) => {
145+
const connectCallback: WebSocketHandlers['connect'] = (
146+
startTime,
147+
url,
148+
protocols,
149+
options,
150+
socketId,
151+
) => {
152152
if (typeof socketId !== 'number') return;
153153

154154
setNetworkRequests((draft: NetworkRequests<WebSocketRequest>) => {
155155
draft.set(`${socketId}`, {
156+
startTime,
156157
url,
157158
type: NetworkType.WS,
158159
protocols,
@@ -168,11 +169,7 @@ export default function useNetworkInterceptor({ autoEnabled }: NetworkIntercepto
168169
if (!draft.get(`${socketId}`)) return draft;
169170

170171
draft.get(`${socketId}`)!.messages ??= '';
171-
draft.get(`${socketId}`)!.messages += keyValueToString(
172-
'SENT',
173-
data,
174-
draft.get(`${socketId}`)!.messages?.length ? 'leading' : null,
175-
);
172+
draft.get(`${socketId}`)!.messages += keyValueToString('SENT', data);
176173
});
177174
};
178175

@@ -187,13 +184,13 @@ export default function useNetworkInterceptor({ autoEnabled }: NetworkIntercepto
187184
});
188185
};
189186

190-
const onOpenCallback: WebSocketHandlers['onOpen'] = (socketId, duration) => {
187+
const onOpenCallback: WebSocketHandlers['onOpen'] = (socketId, endTime) => {
191188
if (typeof socketId !== 'number') return;
192189

193190
setNetworkRequests((draft: NetworkRequests<WebSocketRequest>) => {
194191
if (!draft.get(`${socketId}`)) return draft;
195192

196-
draft.get(`${socketId}`)!.duration = duration;
193+
draft.get(`${socketId}`)!.endTime = endTime;
197194
});
198195
};
199196

@@ -204,11 +201,7 @@ export default function useNetworkInterceptor({ autoEnabled }: NetworkIntercepto
204201
if (!draft.get(`${socketId}`)) return draft;
205202

206203
draft.get(`${socketId}`)!.messages ??= '';
207-
draft.get(`${socketId}`)!.messages += keyValueToString(
208-
'RECEIVED',
209-
message,
210-
draft.get(`${socketId}`)!.messages?.length ? 'leading' : null,
211-
);
204+
draft.get(`${socketId}`)!.messages += keyValueToString('RECEIVED', message);
212205
});
213206
};
214207

0 commit comments

Comments
 (0)