Skip to content

Commit 933442b

Browse files
cmcWebCode40claude
andcommitted
feat: enhance NetworkInterceptor with configuration and request filtering
Add runtime configuration support for maxLogs, ignored URLs/domains/methods, and slow request threshold. Requests exceeding the threshold are flagged with isSlow property for visual indication in the UI. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent cbfc2d6 commit 933442b

1 file changed

Lines changed: 70 additions & 14 deletions

File tree

src/NetworkInterceptor.ts

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import type { LogListener, NetworkLog, NetworkRequestHeaders } from './types';
1+
import type {
2+
LogListener,
3+
NetworkLog,
4+
NetworkLoggerConfig,
5+
NetworkRequestHeaders,
6+
} from './types';
7+
import { DEFAULT_CONFIG } from './constants/config';
8+
import { shouldIgnoreUrl, shouldIgnoreDomain } from './utils/filters';
29

310
interface CustomXMLHttpRequest extends XMLHttpRequest {
411
open: (method: string, url: string) => void;
@@ -10,17 +17,49 @@ class NetworkLogger {
1017
private logs: NetworkLog[] = [];
1118
private listeners: LogListener[] = [];
1219
private isEnabled: boolean = true;
20+
private config: NetworkLoggerConfig = { ...DEFAULT_CONFIG };
1321

14-
constructor() {
22+
constructor(config?: Partial<NetworkLoggerConfig>) {
1523
this.logs = [];
1624
this.listeners = [];
1725
this.isEnabled = true;
26+
if (config) {
27+
this.config = { ...DEFAULT_CONFIG, ...config };
28+
}
29+
}
30+
31+
public configure(config: Partial<NetworkLoggerConfig>): void {
32+
this.config = { ...this.config, ...config };
33+
}
34+
35+
public getConfig(): NetworkLoggerConfig {
36+
return { ...this.config };
37+
}
38+
39+
private shouldIgnoreRequest(url: string, method: string): boolean {
40+
if (shouldIgnoreUrl(url, this.config.ignoredUrls)) {
41+
return true;
42+
}
43+
if (shouldIgnoreDomain(url, this.config.ignoredDomains)) {
44+
return true;
45+
}
46+
if (
47+
this.config.ignoredMethods.length > 0 &&
48+
this.config.ignoredMethods
49+
.map((m) => m.toUpperCase())
50+
.includes(method.toUpperCase())
51+
) {
52+
return true;
53+
}
54+
return false;
1855
}
1956

2057
public setupInterceptor(): void {
2158
if (!this.isEnabled) return;
2259

2360
const originalFetch = global.fetch;
61+
// eslint-disable-next-line consistent-this
62+
const self = this;
2463

2564
global.fetch = async (
2665
input: RequestInfo | URL,
@@ -30,13 +69,18 @@ class NetworkLogger {
3069
const requestId: number = Date.now() + Math.random();
3170
const url: string = input.toString();
3271
const options: RequestInit = init || {};
72+
const method = options.method || 'GET';
73+
74+
if (self.shouldIgnoreRequest(url, method)) {
75+
return originalFetch(input, init);
76+
}
3377

3478
const requestLog: NetworkLog = {
3579
id: requestId,
36-
method: options.method || 'GET',
80+
method,
3781
url,
38-
headers: this.processRequestHeaders(options.headers),
39-
body: options.body ? this.stringifyBody(options.body) : null,
82+
headers: self.processRequestHeaders(options.headers),
83+
body: options.body ? self.stringifyBody(options.body) : null,
4084
timestamp: new Date().toISOString(),
4185
startTime,
4286
};
@@ -52,22 +96,24 @@ class NetworkLogger {
5296
responseBody = 'Unable to read response body';
5397
}
5498

99+
const duration = Date.now() - startTime;
55100
requestLog.response = {
56101
status: response.status,
57102
statusText: response.statusText,
58-
headers: this.headersToObject(response.headers),
103+
headers: self.headersToObject(response.headers),
59104
body: responseBody,
60-
duration: Date.now() - startTime,
105+
duration,
61106
};
107+
requestLog.isSlow = duration > self.config.slowRequestThreshold;
62108

63-
this.addLog(requestLog);
109+
self.addLog(requestLog);
64110
return response;
65111
} catch (error) {
66112
const errorMessage: string =
67113
error instanceof Error ? error.message : 'Unknown error';
68114
requestLog.error = errorMessage;
69115
requestLog.duration = Date.now() - startTime;
70-
this.addLog(requestLog);
116+
self.addLog(requestLog);
71117
throw error;
72118
}
73119
};
@@ -83,6 +129,7 @@ class NetworkLogger {
83129
global.XMLHttpRequest = function (): CustomXMLHttpRequest {
84130
const xhr = new originalXHR() as CustomXMLHttpRequest;
85131
const requestId: number = Date.now() + Math.random();
132+
let shouldIgnore = false;
86133
let requestLog: NetworkLog = {
87134
id: requestId,
88135
method: '',
@@ -100,22 +147,29 @@ class NetworkLogger {
100147
xhr.open = function (method: string, url: string): void {
101148
requestLog.method = method;
102149
requestLog.url = url;
150+
shouldIgnore = self.shouldIgnoreRequest(url, method);
103151
return originalOpen.call(this, method, url);
104152
};
105153

106154
xhr.setRequestHeader = function (header: string, value: string): void {
107-
requestLog.headers[header] = value;
155+
if (!shouldIgnore) {
156+
requestLog.headers[header] = value;
157+
}
108158
return originalSetRequestHeader.call(this, header, value);
109159
};
110160

111161
xhr.send = function (body?: Document | any | null): void {
162+
if (shouldIgnore) {
163+
return originalSend.call(this, body);
164+
}
165+
112166
requestLog.body = body ? self.stringifyBody(body) : null;
113167
requestLog.startTime = Date.now();
114168

115169
const originalOnReadyStateChange = xhr.onreadystatechange;
116170

117171
xhr.onreadystatechange = function (): void {
118-
if (xhr.readyState === 4) {
172+
if (xhr.readyState === 4 && !shouldIgnore) {
119173
let responseBody: string = '';
120174

121175
try {
@@ -146,13 +200,15 @@ class NetworkLogger {
146200
} catch (error) {
147201
responseBody = `[Error reading response: ${error instanceof Error ? error.message : 'Unknown error'}]`;
148202
}
203+
const duration = Date.now() - requestLog.startTime;
149204
requestLog.response = {
150205
status: xhr.status,
151206
statusText: xhr.statusText,
152207
headers: self.parseXHRHeaders(xhr.getAllResponseHeaders()),
153208
body: responseBody,
154-
duration: Date.now() - requestLog.startTime,
209+
duration,
155210
};
211+
requestLog.isSlow = duration > self.config.slowRequestThreshold;
156212
self.addLog(requestLog);
157213
}
158214

@@ -237,8 +293,8 @@ class NetworkLogger {
237293
private addLog(log: NetworkLog): void {
238294
this.logs.unshift(log);
239295

240-
if (this.logs.length > 100) {
241-
this.logs = this.logs.slice(0, 100);
296+
if (this.logs.length > this.config.maxLogs) {
297+
this.logs = this.logs.slice(0, this.config.maxLogs);
242298
}
243299

244300
this.listeners.forEach((listener: LogListener) => listener([...this.logs]));

0 commit comments

Comments
 (0)