logbubble 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LogBubble Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,244 @@
1
+ # LogBubble 🫧
2
+
3
+ [![npm version](https://badge.fury.io/js/logbubble.svg)](https://badge.fury.io/js/logbubble)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![GitHub](https://img.shields.io/badge/GitHub-LogBubble-blue)](https://github.com/dktiwary007/LogBubble)
6
+
7
+ A lightweight, floating log viewer for monitoring network requests and console logs in web applications. Perfect for debugging web apps, Capacitor apps, and Progressive Web Apps (PWAs) directly on mobile devices or in production-like environments.
8
+
9
+ [View on npm](https://www.npmjs.com/package/logbubble)
10
+
11
+ ## Features
12
+
13
+ ✨ **Floating UI**: Non-intrusive bubble interface that stays accessible without blocking your app
14
+ 🌐 **Network Monitoring**: Automatically logs `fetch`, `XMLHttpRequest`, and dynamic script/link loading
15
+ 📝 **Console Logging**: Captures `console.log`, `console.warn`, `console.error`, `console.info`, and `console.debug`
16
+ 🔔 **Unread Badge**: Shows count of new logs since last view
17
+ 📋 **Copy to Clipboard**: Export all logs with timestamps
18
+ 🔄 **Auto-initialization**: Works out of the box with zero configuration
19
+ 🎨 **Clean UI**: Modern, minimalist design with color-coded log types
20
+
21
+ ## Installation
22
+
23
+ Install LogBubble from npm:
24
+
25
+ ```bash
26
+ npm install logbubble
27
+ ```
28
+
29
+ Or with yarn:
30
+
31
+ ```bash
32
+ yarn add logbubble
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ### Auto-initialization (Recommended)
38
+
39
+ Simply import LogBubble and it will automatically initialize:
40
+
41
+ ```javascript
42
+ import "logbubble";
43
+ ```
44
+
45
+ The floating bubble will appear in the top-right corner of your app.
46
+
47
+ ### Manual initialization
48
+
49
+ If you want more control over when LogBubble initializes:
50
+
51
+ ```javascript
52
+ import { initNetworkLogger } from "logbubble";
53
+
54
+ // Initialize when ready
55
+ initNetworkLogger();
56
+ ```
57
+
58
+ **Note:** LogBubble has a built-in guard against duplicate initialization, so calling `initNetworkLogger()` multiple times is safe.
59
+
60
+ ## Examples
61
+
62
+ ### React (Vite/CRA)
63
+
64
+ ```javascript
65
+ // main.jsx or index.js
66
+ import React from "react";
67
+ import ReactDOM from "react-dom/client";
68
+ import App from "./App";
69
+ import "logbubble"; // Add this line
70
+
71
+ ReactDOM.createRoot(document.getElementById("root")).render(
72
+ <React.StrictMode>
73
+ <App />
74
+ </React.StrictMode>,
75
+ );
76
+ ```
77
+
78
+ ### Capacitor Apps
79
+
80
+ ```javascript
81
+ // main.jsx
82
+ import React from "react";
83
+ import ReactDOM from "react-dom/client";
84
+ import App from "./App";
85
+ import { initNetworkLogger } from "logbubble";
86
+
87
+ // Initialize LogBubble for mobile debugging
88
+ initNetworkLogger();
89
+
90
+ ReactDOM.createRoot(document.getElementById("root")).render(
91
+ <React.StrictMode>
92
+ <App />
93
+ </React.StrictMode>,
94
+ );
95
+ ```
96
+
97
+ ### Vanilla JavaScript
98
+
99
+ ```html
100
+ <!DOCTYPE html>
101
+ <html>
102
+ <head>
103
+ <title>My App</title>
104
+ </head>
105
+ <body>
106
+ <script type="module">
107
+ import "logbubble";
108
+
109
+ // Your app code
110
+ fetch("https://api.example.com/data")
111
+ .then((res) => res.json())
112
+ .then((data) => console.log("Data:", data));
113
+ </script>
114
+ </body>
115
+ </html>
116
+ ```
117
+
118
+ ## What Gets Logged?
119
+
120
+ LogBubble automatically intercepts and logs:
121
+
122
+ - **Fetch requests**: `[NET] GET https://api.example.com/users 200 145ms`
123
+ - **XHR requests**: `[NET] POST https://api.example.com/login 201 312ms`
124
+ - **Dynamic scripts/links**: `[NET] SCRIPT https://cdn.example.com/lib.js LOADED`
125
+ - **Console messages**: `[LOG] User logged in`, `[WARN] Connection slow`, `[ERROR] Failed to load`
126
+
127
+ ## UI Controls
128
+
129
+ - **Bubble**: Click to toggle the log window
130
+ - **Badge**: Shows unread log count (disappears when window is opened)
131
+ - **Clear**: Remove all logs
132
+ - **Copy**: Copy all logs to clipboard with timestamps
133
+
134
+ ## Development
135
+
136
+ ### Build
137
+
138
+ ```bash
139
+ npm run build
140
+ ```
141
+
142
+ ### Watch mode
143
+
144
+ ```bash
145
+ npm run dev
146
+ ```
147
+
148
+ ### Project Structure
149
+
150
+ ```
151
+ LogBubble/
152
+ ├── core/ # Patching logic for fetch, XHR, DOM, console
153
+ ├── ui/ # Floating UI and log store
154
+ ├── init.ts # Main entry point with auto-init
155
+ ├── auto.ts # Side-effect entry point
156
+ ├── dist/ # Compiled output
157
+ └── package.json
158
+ ```
159
+
160
+ ## API
161
+
162
+ ### `initNetworkLogger()`
163
+
164
+ Initializes LogBubble and starts intercepting network requests and console logs. Safe to call multiple times (duplicate calls are ignored).
165
+
166
+ ```javascript
167
+ import { initNetworkLogger } from "logbubble";
168
+ initNetworkLogger();
169
+ ```
170
+
171
+ ### Global Access
172
+
173
+ When in a browser environment, LogBubble exposes itself globally:
174
+
175
+ ```javascript
176
+ // Available on window object
177
+ window.initNetworkLogger();
178
+ ```
179
+
180
+ ## Browser Support
181
+
182
+ LogBubble works in all modern browsers and WebView environments:
183
+
184
+ - ✅ Chrome/Edge (Chromium)
185
+ - ✅ Firefox
186
+ - ✅ Safari
187
+ - ✅ Mobile browsers (iOS Safari, Chrome Mobile)
188
+ - ✅ Capacitor WebView
189
+ - ✅ Cordova WebView
190
+
191
+ ## Use Cases
192
+
193
+ - 🐛 **Mobile Debugging**: Debug network issues on real devices without DevTools
194
+ - 🚀 **Production Testing**: Monitor requests in production-like environments
195
+ - 📱 **Capacitor/PWA Development**: Essential for debugging hybrid mobile apps
196
+ - 🧪 **QA Testing**: Allow testers to capture and share logs easily
197
+ - 📊 **Performance Monitoring**: Track request timing and errors
198
+
199
+ ## Known Limitations
200
+
201
+ - Browser-only (requires `window` and DOM APIs)
202
+ - Logs are stored in memory only (cleared on page refresh)
203
+ - Maximum 500 logs retained (older logs are automatically removed)
204
+
205
+ ## Troubleshooting
206
+
207
+ ### UI not appearing
208
+
209
+ Ensure LogBubble is imported at the entry point of your application (before React renders or before any other scripts run).
210
+
211
+ ### Duplicate logs
212
+
213
+ If you see duplicate logs, check that `initNetworkLogger()` is not being called multiple times. LogBubble has a guard against this, but if you call it manually AND import the auto-init module, it may appear twice.
214
+
215
+ ### Not capturing network requests
216
+
217
+ Make sure your app is using native `fetch` or `XMLHttpRequest` APIs. Some custom HTTP clients may not be automatically patched.
218
+
219
+ ## Support
220
+
221
+ For issues, feature requests, or questions, please open an issue on [GitHub](https://github.com/dktiwary007/LogBubble/issues).
222
+
223
+ ## License
224
+
225
+ MIT
226
+
227
+ ## Contributing
228
+
229
+ Contributions are welcome! Please feel free to submit issues or pull requests on [GitHub](https://github.com/dktiwary007/LogBubble).
230
+
231
+ ### Getting Started with Development
232
+
233
+ If you want to contribute to LogBubble:
234
+
235
+ 1. Clone the repository
236
+ 2. Install dependencies: `npm install`
237
+ 3. Build the project: `npm run build`
238
+ 4. Watch for changes: `npm run dev`
239
+
240
+ ---
241
+
242
+ Built with ❤️ for developers who need better mobile debugging tools.
243
+
244
+ **Made by [Deepak Kumar](https://github.com/dktiwary007)**
package/auto.ts ADDED
@@ -0,0 +1,4 @@
1
+ // auto.ts
2
+ // Side-effect import for auto-initialization
3
+ import { initNetworkLogger } from "./init";
4
+ initNetworkLogger();
@@ -0,0 +1,79 @@
1
+ // console.ts
2
+ // Patches console methods to log to the network logger UI
3
+
4
+ import { logStore } from "../ui/logStore";
5
+
6
+ let isPatching = false;
7
+
8
+ export function patchConsole() {
9
+ if (typeof window === "undefined" || typeof console === "undefined") return;
10
+
11
+ const originalLog = console.log;
12
+ const originalWarn = console.warn;
13
+ const originalError = console.error;
14
+ const originalInfo = console.info;
15
+ const originalDebug = console.debug;
16
+
17
+ console.log = function (...args: any[]) {
18
+ originalLog.apply(console, args);
19
+ if (!isPatching) {
20
+ isPatching = true;
21
+ const message = args.map((arg) => formatArg(arg)).join(" ");
22
+ logStore.addLog(`[LOG] ${message}`, "plugin");
23
+ isPatching = false;
24
+ }
25
+ };
26
+
27
+ console.warn = function (...args: any[]) {
28
+ originalWarn.apply(console, args);
29
+ if (!isPatching) {
30
+ isPatching = true;
31
+ const message = args.map((arg) => formatArg(arg)).join(" ");
32
+ logStore.addLog(`[WARN] ${message}`, "plugin");
33
+ isPatching = false;
34
+ }
35
+ };
36
+
37
+ console.error = function (...args: any[]) {
38
+ originalError.apply(console, args);
39
+ if (!isPatching) {
40
+ isPatching = true;
41
+ const message = args.map((arg) => formatArg(arg)).join(" ");
42
+ logStore.addLog(`[ERROR] ${message}`, "plugin");
43
+ isPatching = false;
44
+ }
45
+ };
46
+
47
+ console.info = function (...args: any[]) {
48
+ originalInfo.apply(console, args);
49
+ if (!isPatching) {
50
+ isPatching = true;
51
+ const message = args.map((arg) => formatArg(arg)).join(" ");
52
+ logStore.addLog(`[INFO] ${message}`, "plugin");
53
+ isPatching = false;
54
+ }
55
+ };
56
+
57
+ console.debug = function (...args: any[]) {
58
+ originalDebug.apply(console, args);
59
+ if (!isPatching) {
60
+ isPatching = true;
61
+ const message = args.map((arg) => formatArg(arg)).join(" ");
62
+ logStore.addLog(`[DEBUG] ${message}`, "plugin");
63
+ isPatching = false;
64
+ }
65
+ };
66
+ }
67
+
68
+ function formatArg(arg: any): string {
69
+ if (arg === null) return "null";
70
+ if (arg === undefined) return "undefined";
71
+ if (typeof arg === "string") return arg;
72
+ if (typeof arg === "number" || typeof arg === "boolean") return String(arg);
73
+ if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
74
+ try {
75
+ return JSON.stringify(arg);
76
+ } catch {
77
+ return String(arg);
78
+ }
79
+ }
package/core/dom.ts ADDED
@@ -0,0 +1,33 @@
1
+ // dom.ts
2
+ // (Optional) Patch dynamic <script> and <link> loading for network logging
3
+
4
+ import { logStore } from "../ui/logStore";
5
+
6
+ export function patchDOM(logFn: (msg: string) => void) {
7
+ if (typeof window === "undefined") return;
8
+ const origCreateElement = document.createElement;
9
+ document.createElement = function (
10
+ this: Document,
11
+ tag: string,
12
+ options?: ElementCreationOptions,
13
+ ) {
14
+ const el = origCreateElement.call(this, tag, options);
15
+ if (tag === "script" || tag === "link") {
16
+ el.addEventListener("load", function () {
17
+ const src =
18
+ (el as HTMLScriptElement).src || (el as HTMLLinkElement).href;
19
+ const message = `[NET] ${tag.toUpperCase()} ${src} LOADED`;
20
+ logFn(message);
21
+ logStore.addLog(message, "dom");
22
+ });
23
+ el.addEventListener("error", function () {
24
+ const src =
25
+ (el as HTMLScriptElement).src || (el as HTMLLinkElement).href;
26
+ const message = `[NET] ${tag.toUpperCase()} ${src} ERROR`;
27
+ logFn(message);
28
+ logStore.addLog(message, "dom");
29
+ });
30
+ }
31
+ return el;
32
+ } as typeof document.createElement;
33
+ }
package/core/fetch.ts ADDED
@@ -0,0 +1,41 @@
1
+ // fetch.ts
2
+ // Patches window.fetch to log network requests in dev mode (browser/WebView only)
3
+
4
+ import { logStore } from "../ui/logStore";
5
+
6
+ export function patchFetch(logFn: (msg: string) => void) {
7
+ if (typeof window === "undefined" || typeof window.fetch !== "function")
8
+ return;
9
+ const originalFetch = window.fetch;
10
+ window.fetch = async function (
11
+ this: typeof globalThis,
12
+ input: RequestInfo | URL,
13
+ init?: RequestInit,
14
+ ) {
15
+ const method =
16
+ (init && init.method) ||
17
+ (typeof input === "object" && "method" in input && input.method) ||
18
+ "GET";
19
+ const url =
20
+ typeof input === "string"
21
+ ? input
22
+ : input instanceof URL
23
+ ? input.href
24
+ : input.url;
25
+ const start = Date.now();
26
+ try {
27
+ const response = await originalFetch.call(this, input, init);
28
+ const ms = Date.now() - start;
29
+ const message = `[NET] ${method} ${url} ${response.status} ${ms}ms`;
30
+ logFn(message);
31
+ logStore.addLog(message, "fetch");
32
+ return response;
33
+ } catch (err) {
34
+ const ms = Date.now() - start;
35
+ const message = `[NET] ${method} ${url} ERROR ${ms}ms`;
36
+ logFn(message);
37
+ logStore.addLog(message, "fetch");
38
+ throw err;
39
+ }
40
+ } as typeof window.fetch;
41
+ }
package/core/xhr.ts ADDED
@@ -0,0 +1,38 @@
1
+ // xhr.ts
2
+ // Patches XMLHttpRequest to log network requests in dev mode (browser/WebView only)
3
+
4
+ import { logStore } from "../ui/logStore";
5
+
6
+ export function patchXHR(logFn: (msg: string) => void) {
7
+ if (
8
+ typeof window === "undefined" ||
9
+ typeof window.XMLHttpRequest !== "function"
10
+ )
11
+ return;
12
+ const OriginalXHR = window.XMLHttpRequest;
13
+ function PatchedXHR(this: XMLHttpRequest) {
14
+ const xhr = new OriginalXHR();
15
+ let url = "";
16
+ let method = "";
17
+ let start = 0;
18
+ xhr.open = new Proxy(xhr.open, {
19
+ apply(target, thisArg, args: [string, string | URL, ...any[]]) {
20
+ method = args[0];
21
+ url = typeof args[1] === "string" ? args[1] : args[1].href;
22
+ return Reflect.apply(target, thisArg, args);
23
+ },
24
+ });
25
+ xhr.addEventListener("loadstart", () => {
26
+ start = Date.now();
27
+ });
28
+ xhr.addEventListener("loadend", () => {
29
+ const ms = Date.now() - start;
30
+ const message = `[NET] ${method} ${url} ${xhr.status} ${ms}ms`;
31
+ logFn(message);
32
+ logStore.addLog(message, "xhr");
33
+ });
34
+ return xhr;
35
+ }
36
+ PatchedXHR.prototype = OriginalXHR.prototype;
37
+ window.XMLHttpRequest = PatchedXHR as any;
38
+ }
package/dist/auto.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/auto.js ADDED
@@ -0,0 +1,4 @@
1
+ // auto.ts
2
+ // Side-effect import for auto-initialization
3
+ import { initNetworkLogger } from "./init";
4
+ initNetworkLogger();
@@ -0,0 +1 @@
1
+ export declare function patchConsole(): void;
@@ -0,0 +1,76 @@
1
+ // console.ts
2
+ // Patches console methods to log to the network logger UI
3
+ import { logStore } from "../ui/logStore";
4
+ let isPatching = false;
5
+ export function patchConsole() {
6
+ if (typeof window === "undefined" || typeof console === "undefined")
7
+ return;
8
+ const originalLog = console.log;
9
+ const originalWarn = console.warn;
10
+ const originalError = console.error;
11
+ const originalInfo = console.info;
12
+ const originalDebug = console.debug;
13
+ console.log = function (...args) {
14
+ originalLog.apply(console, args);
15
+ if (!isPatching) {
16
+ isPatching = true;
17
+ const message = args.map((arg) => formatArg(arg)).join(" ");
18
+ logStore.addLog(`[LOG] ${message}`, "plugin");
19
+ isPatching = false;
20
+ }
21
+ };
22
+ console.warn = function (...args) {
23
+ originalWarn.apply(console, args);
24
+ if (!isPatching) {
25
+ isPatching = true;
26
+ const message = args.map((arg) => formatArg(arg)).join(" ");
27
+ logStore.addLog(`[WARN] ${message}`, "plugin");
28
+ isPatching = false;
29
+ }
30
+ };
31
+ console.error = function (...args) {
32
+ originalError.apply(console, args);
33
+ if (!isPatching) {
34
+ isPatching = true;
35
+ const message = args.map((arg) => formatArg(arg)).join(" ");
36
+ logStore.addLog(`[ERROR] ${message}`, "plugin");
37
+ isPatching = false;
38
+ }
39
+ };
40
+ console.info = function (...args) {
41
+ originalInfo.apply(console, args);
42
+ if (!isPatching) {
43
+ isPatching = true;
44
+ const message = args.map((arg) => formatArg(arg)).join(" ");
45
+ logStore.addLog(`[INFO] ${message}`, "plugin");
46
+ isPatching = false;
47
+ }
48
+ };
49
+ console.debug = function (...args) {
50
+ originalDebug.apply(console, args);
51
+ if (!isPatching) {
52
+ isPatching = true;
53
+ const message = args.map((arg) => formatArg(arg)).join(" ");
54
+ logStore.addLog(`[DEBUG] ${message}`, "plugin");
55
+ isPatching = false;
56
+ }
57
+ };
58
+ }
59
+ function formatArg(arg) {
60
+ if (arg === null)
61
+ return "null";
62
+ if (arg === undefined)
63
+ return "undefined";
64
+ if (typeof arg === "string")
65
+ return arg;
66
+ if (typeof arg === "number" || typeof arg === "boolean")
67
+ return String(arg);
68
+ if (arg instanceof Error)
69
+ return `${arg.name}: ${arg.message}`;
70
+ try {
71
+ return JSON.stringify(arg);
72
+ }
73
+ catch {
74
+ return String(arg);
75
+ }
76
+ }
@@ -0,0 +1 @@
1
+ export declare function patchDOM(logFn: (msg: string) => void): void;
@@ -0,0 +1,26 @@
1
+ // dom.ts
2
+ // (Optional) Patch dynamic <script> and <link> loading for network logging
3
+ import { logStore } from "../ui/logStore";
4
+ export function patchDOM(logFn) {
5
+ if (typeof window === "undefined")
6
+ return;
7
+ const origCreateElement = document.createElement;
8
+ document.createElement = function (tag, options) {
9
+ const el = origCreateElement.call(this, tag, options);
10
+ if (tag === "script" || tag === "link") {
11
+ el.addEventListener("load", function () {
12
+ const src = el.src || el.href;
13
+ const message = `[NET] ${tag.toUpperCase()} ${src} LOADED`;
14
+ logFn(message);
15
+ logStore.addLog(message, "dom");
16
+ });
17
+ el.addEventListener("error", function () {
18
+ const src = el.src || el.href;
19
+ const message = `[NET] ${tag.toUpperCase()} ${src} ERROR`;
20
+ logFn(message);
21
+ logStore.addLog(message, "dom");
22
+ });
23
+ }
24
+ return el;
25
+ };
26
+ }
@@ -0,0 +1 @@
1
+ export declare function patchFetch(logFn: (msg: string) => void): void;
@@ -0,0 +1,34 @@
1
+ // fetch.ts
2
+ // Patches window.fetch to log network requests in dev mode (browser/WebView only)
3
+ import { logStore } from "../ui/logStore";
4
+ export function patchFetch(logFn) {
5
+ if (typeof window === "undefined" || typeof window.fetch !== "function")
6
+ return;
7
+ const originalFetch = window.fetch;
8
+ window.fetch = async function (input, init) {
9
+ const method = (init && init.method) ||
10
+ (typeof input === "object" && "method" in input && input.method) ||
11
+ "GET";
12
+ const url = typeof input === "string"
13
+ ? input
14
+ : input instanceof URL
15
+ ? input.href
16
+ : input.url;
17
+ const start = Date.now();
18
+ try {
19
+ const response = await originalFetch.call(this, input, init);
20
+ const ms = Date.now() - start;
21
+ const message = `[NET] ${method} ${url} ${response.status} ${ms}ms`;
22
+ logFn(message);
23
+ logStore.addLog(message, "fetch");
24
+ return response;
25
+ }
26
+ catch (err) {
27
+ const ms = Date.now() - start;
28
+ const message = `[NET] ${method} ${url} ERROR ${ms}ms`;
29
+ logFn(message);
30
+ logStore.addLog(message, "fetch");
31
+ throw err;
32
+ }
33
+ };
34
+ }
@@ -0,0 +1 @@
1
+ export declare function patchXHR(logFn: (msg: string) => void): void;
@@ -0,0 +1,34 @@
1
+ // xhr.ts
2
+ // Patches XMLHttpRequest to log network requests in dev mode (browser/WebView only)
3
+ import { logStore } from "../ui/logStore";
4
+ export function patchXHR(logFn) {
5
+ if (typeof window === "undefined" ||
6
+ typeof window.XMLHttpRequest !== "function")
7
+ return;
8
+ const OriginalXHR = window.XMLHttpRequest;
9
+ function PatchedXHR() {
10
+ const xhr = new OriginalXHR();
11
+ let url = "";
12
+ let method = "";
13
+ let start = 0;
14
+ xhr.open = new Proxy(xhr.open, {
15
+ apply(target, thisArg, args) {
16
+ method = args[0];
17
+ url = typeof args[1] === "string" ? args[1] : args[1].href;
18
+ return Reflect.apply(target, thisArg, args);
19
+ },
20
+ });
21
+ xhr.addEventListener("loadstart", () => {
22
+ start = Date.now();
23
+ });
24
+ xhr.addEventListener("loadend", () => {
25
+ const ms = Date.now() - start;
26
+ const message = `[NET] ${method} ${url} ${xhr.status} ${ms}ms`;
27
+ logFn(message);
28
+ logStore.addLog(message, "xhr");
29
+ });
30
+ return xhr;
31
+ }
32
+ PatchedXHR.prototype = OriginalXHR.prototype;
33
+ window.XMLHttpRequest = PatchedXHR;
34
+ }
package/dist/init.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function initNetworkLogger(): void;