react-native-debug-toolkit 0.1.5 → 0.1.7
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.
|
@@ -12,6 +12,7 @@ class NetworkFeature {
|
|
|
12
12
|
this.logs = []
|
|
13
13
|
this.pendingAxiosRequests = new Map()
|
|
14
14
|
this.originalFetch = null
|
|
15
|
+
this.blacklist = [] // URL patterns to exclude from logging
|
|
15
16
|
|
|
16
17
|
NetworkFeature.instance = this
|
|
17
18
|
}
|
|
@@ -39,6 +40,39 @@ class NetworkFeature {
|
|
|
39
40
|
this.pendingAxiosRequests.clear()
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
// Check if a URL matches any pattern in the blacklist
|
|
44
|
+
isUrlBlacklisted(url) {
|
|
45
|
+
if (!url) return false
|
|
46
|
+
|
|
47
|
+
return this.blacklist.some(pattern => {
|
|
48
|
+
if (pattern instanceof RegExp) {
|
|
49
|
+
return pattern.test(url)
|
|
50
|
+
}
|
|
51
|
+
return url.includes(pattern)
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Add a URL pattern to blacklist
|
|
56
|
+
addUrlToBlacklist(pattern) {
|
|
57
|
+
if (!this.blacklist.some(p =>
|
|
58
|
+
(p instanceof RegExp && pattern instanceof RegExp) ?
|
|
59
|
+
p.toString() === pattern.toString() : p === pattern)) {
|
|
60
|
+
this.blacklist.push(pattern)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Remove a URL pattern from blacklist
|
|
65
|
+
removeUrlFromBlacklist(pattern) {
|
|
66
|
+
this.blacklist = this.blacklist.filter(p =>
|
|
67
|
+
(p instanceof RegExp && pattern instanceof RegExp) ?
|
|
68
|
+
p.toString() !== pattern.toString() : p !== pattern)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Clear all patterns from blacklist
|
|
72
|
+
clearBlacklist() {
|
|
73
|
+
this.blacklist = []
|
|
74
|
+
}
|
|
75
|
+
|
|
42
76
|
setupAxiosInterceptors(axiosInstance) {
|
|
43
77
|
if (!__DEV__) {
|
|
44
78
|
return
|
|
@@ -94,6 +128,14 @@ class NetworkFeature {
|
|
|
94
128
|
return
|
|
95
129
|
}
|
|
96
130
|
|
|
131
|
+
const url = `${response.config.baseURL || ''}${response.config.url}`
|
|
132
|
+
|
|
133
|
+
// Skip logging if URL is blacklisted
|
|
134
|
+
if (this.isUrlBlacklisted(url)) {
|
|
135
|
+
this.pendingAxiosRequests.delete(trackId)
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
97
139
|
if (this.logs.length >= NetworkFeature.MAX_LOGS) {
|
|
98
140
|
this.logs.shift()
|
|
99
141
|
}
|
|
@@ -105,7 +147,7 @@ class NetworkFeature {
|
|
|
105
147
|
timestamp: pendingRequest.timestamp,
|
|
106
148
|
duration: Math.round(duration),
|
|
107
149
|
request: {
|
|
108
|
-
url:
|
|
150
|
+
url: url,
|
|
109
151
|
method: response.config.method?.toUpperCase() || 'GET',
|
|
110
152
|
headers: response.config.headers,
|
|
111
153
|
body: response.config.data || response.config.params,
|
|
@@ -148,6 +190,14 @@ class NetworkFeature {
|
|
|
148
190
|
const startTime = pendingRequest
|
|
149
191
|
? pendingRequest.startTime
|
|
150
192
|
: Date.now() - 100
|
|
193
|
+
|
|
194
|
+
const url = `${error.config.baseURL || ''}${error.config.url}`
|
|
195
|
+
|
|
196
|
+
// Skip logging if URL is blacklisted
|
|
197
|
+
if (this.isUrlBlacklisted(url)) {
|
|
198
|
+
this.pendingAxiosRequests.delete(trackId)
|
|
199
|
+
return
|
|
200
|
+
}
|
|
151
201
|
|
|
152
202
|
if (this.logs.length >= NetworkFeature.MAX_LOGS) {
|
|
153
203
|
this.logs.shift()
|
|
@@ -159,7 +209,7 @@ class NetworkFeature {
|
|
|
159
209
|
timestamp: pendingRequest ? pendingRequest.timestamp : new Date(),
|
|
160
210
|
duration: Math.round(duration),
|
|
161
211
|
request: {
|
|
162
|
-
url:
|
|
212
|
+
url: url,
|
|
163
213
|
method: error.config.method?.toUpperCase() || 'GET',
|
|
164
214
|
headers: error.config.headers,
|
|
165
215
|
body: error.config.data || error.config.params,
|
|
@@ -206,12 +256,18 @@ class NetworkFeature {
|
|
|
206
256
|
}
|
|
207
257
|
|
|
208
258
|
_logFetchResponse(request, options, response, startTime) {
|
|
259
|
+
const requestUrl = typeof request === 'string' ? request : request.url
|
|
260
|
+
|
|
261
|
+
// Skip logging if URL is blacklisted
|
|
262
|
+
if (this.isUrlBlacklisted(requestUrl)) {
|
|
263
|
+
return
|
|
264
|
+
}
|
|
265
|
+
|
|
209
266
|
if (this.logs.length >= NetworkFeature.MAX_LOGS) {
|
|
210
267
|
this.logs.shift()
|
|
211
268
|
}
|
|
212
269
|
|
|
213
270
|
const duration = Date.now() - startTime
|
|
214
|
-
const requestUrl = typeof request === 'string' ? request : request.url
|
|
215
271
|
|
|
216
272
|
const commonData = {
|
|
217
273
|
timestamp: new Date(),
|
|
@@ -276,6 +332,13 @@ class NetworkFeature {
|
|
|
276
332
|
}
|
|
277
333
|
|
|
278
334
|
_logFetchError(request, options, error, startTime) {
|
|
335
|
+
const requestUrl = typeof request === 'string' ? request : request.url
|
|
336
|
+
|
|
337
|
+
// Skip logging if URL is blacklisted
|
|
338
|
+
if (this.isUrlBlacklisted(requestUrl)) {
|
|
339
|
+
return
|
|
340
|
+
}
|
|
341
|
+
|
|
279
342
|
if (this.logs.length >= NetworkFeature.MAX_LOGS) {
|
|
280
343
|
this.logs.shift()
|
|
281
344
|
}
|
|
@@ -286,7 +349,7 @@ class NetworkFeature {
|
|
|
286
349
|
timestamp: new Date(),
|
|
287
350
|
duration: Math.round(duration),
|
|
288
351
|
request: {
|
|
289
|
-
url:
|
|
352
|
+
url: requestUrl,
|
|
290
353
|
method: options.method || 'GET',
|
|
291
354
|
headers: options.headers || {},
|
|
292
355
|
body: options.body,
|
|
@@ -326,5 +389,10 @@ export const createNetworkFeature = () => {
|
|
|
326
389
|
cleanup: () => feature.cleanup(),
|
|
327
390
|
setupAxiosInterceptors: (axiosInstance) =>
|
|
328
391
|
feature.setupAxiosInterceptors(axiosInstance),
|
|
392
|
+
// Expose blacklist management methods
|
|
393
|
+
addUrlToBlacklist: (pattern) => feature.addUrlToBlacklist(pattern),
|
|
394
|
+
removeUrlFromBlacklist: (pattern) => feature.removeUrlFromBlacklist(pattern),
|
|
395
|
+
clearBlacklist: () => feature.clearBlacklist(),
|
|
396
|
+
getBlacklist: () => feature.blacklist,
|
|
329
397
|
}
|
|
330
398
|
}
|
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
import React, { useState, useCallback } from 'react'
|
|
2
2
|
import { View, Text, StyleSheet, Clipboard, Dimensions } from 'react-native'
|
|
3
3
|
import { ScrollView, Pressable } from 'react-native'
|
|
4
|
-
|
|
4
|
+
import JSONTree from 'react-native-json-tree'
|
|
5
5
|
const { width: SCREEN_WIDTH } = Dimensions.get('window')
|
|
6
|
+
const theme = {
|
|
7
|
+
scheme: 'monokai',
|
|
8
|
+
author: 'wimer hazenberg (http://www.monokai.nl)',
|
|
9
|
+
base00: '#272822',
|
|
10
|
+
base01: '#383830',
|
|
11
|
+
base02: '#49483e',
|
|
12
|
+
base03: '#75715e',
|
|
13
|
+
base04: '#a59f85',
|
|
14
|
+
base05: '#f8f8f2',
|
|
15
|
+
base06: '#f5f4f1',
|
|
16
|
+
base07: '#f9f8f5',
|
|
17
|
+
base08: '#f92672',
|
|
18
|
+
base09: '#fd971f',
|
|
19
|
+
base0A: '#f4bf75',
|
|
20
|
+
base0B: '#a6e22e',
|
|
21
|
+
base0C: '#a1efe4',
|
|
22
|
+
base0D: '#66d9ef',
|
|
23
|
+
base0E: '#ae81ff',
|
|
24
|
+
base0F: '#cc6633'
|
|
25
|
+
};
|
|
6
26
|
|
|
7
27
|
const CopyButton = ({ text, style }) => {
|
|
8
28
|
const [copied, setCopied] = useState(false)
|
|
@@ -54,8 +74,6 @@ const LongTextContent = ({ text }) => {
|
|
|
54
74
|
}
|
|
55
75
|
|
|
56
76
|
const JSONValue = ({ value, path = '', level = 0, maxExpandLevel = 2 }) => {
|
|
57
|
-
const [expanded, setExpanded] = useState(level < maxExpandLevel)
|
|
58
|
-
|
|
59
77
|
if (value === null) {
|
|
60
78
|
return <Text style={styles.jsonNull}>null</Text>
|
|
61
79
|
}
|
|
@@ -75,9 +93,7 @@ const JSONValue = ({ value, path = '', level = 0, maxExpandLevel = 2 }) => {
|
|
|
75
93
|
if (typeof value === 'string') {
|
|
76
94
|
if (value.length > 150) {
|
|
77
95
|
return (
|
|
78
|
-
<CollapsibleSection
|
|
79
|
-
title={`String (${value.length} chars)`}
|
|
80
|
-
initiallyExpanded={false}>
|
|
96
|
+
<CollapsibleSection title={`String (${value.length} chars)`} initiallyExpanded={false}>
|
|
81
97
|
<LongTextContent text={value} />
|
|
82
98
|
</CollapsibleSection>
|
|
83
99
|
)
|
|
@@ -90,88 +106,16 @@ const JSONValue = ({ value, path = '', level = 0, maxExpandLevel = 2 }) => {
|
|
|
90
106
|
)
|
|
91
107
|
}
|
|
92
108
|
|
|
93
|
-
|
|
94
|
-
if (value.length === 0) {
|
|
95
|
-
return <Text style={styles.jsonArray}>[]</Text>
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
<View style={styles.jsonContainer}>
|
|
100
|
-
<Pressable
|
|
101
|
-
onPress={() => setExpanded(!expanded)}
|
|
102
|
-
style={styles.jsonToggle}>
|
|
103
|
-
<Text style={styles.jsonBrackets}>
|
|
104
|
-
[{!expanded && '...'}
|
|
105
|
-
{expanded && value.length > 0 && ''}
|
|
106
|
-
</Text>
|
|
107
|
-
{!expanded && (
|
|
108
|
-
<Text style={styles.jsonCollapsed}> Array({value.length}) </Text>
|
|
109
|
-
)}
|
|
110
|
-
</Pressable>
|
|
111
|
-
|
|
112
|
-
{expanded && (
|
|
113
|
-
<View style={styles.jsonChildren}>
|
|
114
|
-
{value.map((item, index) => (
|
|
115
|
-
<View key={`${path}-${index}`} style={styles.jsonArrayItem}>
|
|
116
|
-
<Text style={styles.jsonKey}>{index}: </Text>
|
|
117
|
-
<View style={styles.jsonValue}>
|
|
118
|
-
<JSONValue
|
|
119
|
-
value={item}
|
|
120
|
-
path={`${path}[${index}]`}
|
|
121
|
-
level={level + 1}
|
|
122
|
-
/>
|
|
123
|
-
</View>
|
|
124
|
-
</View>
|
|
125
|
-
))}
|
|
126
|
-
</View>
|
|
127
|
-
)}
|
|
128
|
-
|
|
129
|
-
{expanded && <Text style={styles.jsonBrackets}>]</Text>}
|
|
130
|
-
</View>
|
|
131
|
-
)
|
|
132
|
-
}
|
|
133
|
-
|
|
109
|
+
// For objects and arrays, use JSONTree for improved large data handling
|
|
134
110
|
if (typeof value === 'object') {
|
|
135
|
-
const keys = Object.keys(value)
|
|
136
|
-
|
|
137
|
-
if (keys.length === 0) {
|
|
138
|
-
return <Text style={styles.jsonObject}>{'{}'}</Text>
|
|
139
|
-
}
|
|
140
|
-
|
|
141
111
|
return (
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
{expanded && keys.length > 0 && ''}
|
|
150
|
-
</Text>
|
|
151
|
-
{!expanded && (
|
|
152
|
-
<Text style={styles.jsonCollapsed}> Object({keys.length}) </Text>
|
|
153
|
-
)}
|
|
154
|
-
</Pressable>
|
|
155
|
-
|
|
156
|
-
{expanded && (
|
|
157
|
-
<View style={styles.jsonChildren}>
|
|
158
|
-
{keys.map((key) => (
|
|
159
|
-
<View key={`${path}-${key}`} style={styles.jsonProperty}>
|
|
160
|
-
<Text style={styles.jsonKey}>{key}: </Text>
|
|
161
|
-
<View style={styles.jsonValue}>
|
|
162
|
-
<JSONValue
|
|
163
|
-
value={value[key]}
|
|
164
|
-
path={`${path}.${key}`}
|
|
165
|
-
level={level + 1}
|
|
166
|
-
/>
|
|
167
|
-
</View>
|
|
168
|
-
</View>
|
|
169
|
-
))}
|
|
170
|
-
</View>
|
|
171
|
-
)}
|
|
172
|
-
|
|
173
|
-
{expanded && <Text style={styles.jsonBrackets}>{'}'}</Text>}
|
|
174
|
-
</View>
|
|
112
|
+
<JSONTree
|
|
113
|
+
data={value}
|
|
114
|
+
theme={theme}
|
|
115
|
+
invertTheme={true}
|
|
116
|
+
hideRoot={true}
|
|
117
|
+
shouldExpandNode={(keyPath, nodeData, currentLevel) => currentLevel < maxExpandLevel}
|
|
118
|
+
/>
|
|
175
119
|
)
|
|
176
120
|
}
|
|
177
121
|
|
|
@@ -387,7 +331,7 @@ const HttpLogDetails = ({ log }) => {
|
|
|
387
331
|
nestedScrollEnabled={true}
|
|
388
332
|
bounces={false}
|
|
389
333
|
showsVerticalScrollIndicator={true}>
|
|
390
|
-
<JSONValue value={responseData} maxExpandLevel={
|
|
334
|
+
<JSONValue value={responseData} maxExpandLevel={2} />
|
|
391
335
|
</ScrollView>
|
|
392
336
|
</View>
|
|
393
337
|
</View>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-debug-toolkit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "A simple yet powerful debugging toolkit for React Native with a convenient floating UI for development",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"author": "zcj",
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"react-native-root-siblings": "^4.0.0"
|
|
26
|
+
"react-native-root-siblings": "^4.0.0",
|
|
27
|
+
"react-native-json-tree": "^1.5.0"
|
|
27
28
|
},
|
|
28
29
|
"peerDependencies": {
|
|
29
30
|
"react": "*",
|