@kush_hemant/react-api-monitor 1.0.2 → 1.0.3
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/dist/index.js +125 -0
- package/package.json +13 -3
- package/src/core/init.js +0 -7
- package/src/core/sender.js +0 -20
- package/src/index.js +0 -1
- package/src/network/auto.js +0 -7
- package/src/network/fetchMonitor.js +0 -54
- package/src/network/xhrMonitor.js +0 -50
- package/src/utils/metadata.js +0 -7
package/dist/index.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// src/core/sender.js
|
|
2
|
+
var endpoint = "";
|
|
3
|
+
function configureSender(url) {
|
|
4
|
+
endpoint = url;
|
|
5
|
+
}
|
|
6
|
+
function sendLog(data) {
|
|
7
|
+
var _a;
|
|
8
|
+
if (!endpoint) return;
|
|
9
|
+
((_a = navigator.sendBeacon) == null ? void 0 : _a.call(
|
|
10
|
+
navigator,
|
|
11
|
+
endpoint,
|
|
12
|
+
JSON.stringify(data)
|
|
13
|
+
)) || fetch(endpoint, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: { "Content-Type": "application/json" },
|
|
16
|
+
body: JSON.stringify(data),
|
|
17
|
+
keepalive: true
|
|
18
|
+
}).catch(() => {
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/utils/metadata.js
|
|
23
|
+
function getMetadata() {
|
|
24
|
+
return {
|
|
25
|
+
pageUrl: window.location.href,
|
|
26
|
+
userAgent: navigator.userAgent,
|
|
27
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/network/fetchMonitor.js
|
|
32
|
+
function monitorFetch() {
|
|
33
|
+
const originalFetch = window.fetch;
|
|
34
|
+
window.fetch = async (input, init = {}) => {
|
|
35
|
+
const start = Date.now();
|
|
36
|
+
let requestBody = init.body || null;
|
|
37
|
+
let method = init.method || "GET";
|
|
38
|
+
try {
|
|
39
|
+
const response = await originalFetch(input, init);
|
|
40
|
+
const clone = response.clone();
|
|
41
|
+
let responseBody = null;
|
|
42
|
+
try {
|
|
43
|
+
responseBody = await clone.text();
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
sendLog({
|
|
47
|
+
type: "api_call",
|
|
48
|
+
transport: "fetch",
|
|
49
|
+
url: typeof input === "string" ? input : input.url,
|
|
50
|
+
method,
|
|
51
|
+
statusCode: response.status,
|
|
52
|
+
requestHeaders: init.headers,
|
|
53
|
+
requestBody,
|
|
54
|
+
responseHeaders: Object.fromEntries(
|
|
55
|
+
response.headers.entries()
|
|
56
|
+
),
|
|
57
|
+
responseBody,
|
|
58
|
+
duration: Date.now() - start,
|
|
59
|
+
...getMetadata()
|
|
60
|
+
});
|
|
61
|
+
return response;
|
|
62
|
+
} catch (err) {
|
|
63
|
+
sendLog({
|
|
64
|
+
type: "api_error",
|
|
65
|
+
transport: "fetch",
|
|
66
|
+
url: input,
|
|
67
|
+
method,
|
|
68
|
+
error: err.message,
|
|
69
|
+
...getMetadata()
|
|
70
|
+
});
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/network/xhrMonitor.js
|
|
77
|
+
function monitorXHR() {
|
|
78
|
+
const originalOpen = XMLHttpRequest.prototype.open;
|
|
79
|
+
const originalSend = XMLHttpRequest.prototype.send;
|
|
80
|
+
const originalSetHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
81
|
+
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
|
|
82
|
+
this._method = method;
|
|
83
|
+
this._url = url;
|
|
84
|
+
this._headers = {};
|
|
85
|
+
return originalOpen.call(this, method, url, ...rest);
|
|
86
|
+
};
|
|
87
|
+
XMLHttpRequest.prototype.setRequestHeader = function(key, value) {
|
|
88
|
+
this._headers[key] = value;
|
|
89
|
+
return originalSetHeader.call(this, key, value);
|
|
90
|
+
};
|
|
91
|
+
XMLHttpRequest.prototype.send = function(body) {
|
|
92
|
+
const start = Date.now();
|
|
93
|
+
this.addEventListener("loadend", () => {
|
|
94
|
+
sendLog({
|
|
95
|
+
type: "api_call",
|
|
96
|
+
transport: "xhr",
|
|
97
|
+
url: this._url,
|
|
98
|
+
method: this._method,
|
|
99
|
+
statusCode: this.status,
|
|
100
|
+
requestHeaders: this._headers,
|
|
101
|
+
requestBody: body,
|
|
102
|
+
responseHeaders: this.getAllResponseHeaders(),
|
|
103
|
+
responseBody: this.responseText,
|
|
104
|
+
duration: Date.now() - start,
|
|
105
|
+
...getMetadata()
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
return originalSend.call(this, body);
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/network/auto.js
|
|
113
|
+
function startNetworkMonitoring() {
|
|
114
|
+
monitorFetch();
|
|
115
|
+
monitorXHR();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/core/init.js
|
|
119
|
+
function initMonitoring(options) {
|
|
120
|
+
configureSender(options.endpoint);
|
|
121
|
+
startNetworkMonitoring();
|
|
122
|
+
}
|
|
123
|
+
export {
|
|
124
|
+
initMonitoring
|
|
125
|
+
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kush_hemant/react-api-monitor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Automatic API monitoring SDK for React apps",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
7
10
|
"keywords": [
|
|
8
11
|
"react",
|
|
9
12
|
"monitoring",
|
|
@@ -12,5 +15,12 @@
|
|
|
12
15
|
"observability"
|
|
13
16
|
],
|
|
14
17
|
"author": "Hemant Kushwah",
|
|
15
|
-
"license": "MIT"
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"tsup": "^8.5.1",
|
|
21
|
+
"typescript": "^5.9.3"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup src/index.js --format esm --dts false"
|
|
25
|
+
}
|
|
16
26
|
}
|
package/src/core/init.js
DELETED
package/src/core/sender.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
let endpoint = "";
|
|
2
|
-
|
|
3
|
-
export function configureSender(url) {
|
|
4
|
-
endpoint = url;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function sendLog(data) {
|
|
8
|
-
if (!endpoint) return;
|
|
9
|
-
|
|
10
|
-
navigator.sendBeacon?.(
|
|
11
|
-
endpoint,
|
|
12
|
-
JSON.stringify(data)
|
|
13
|
-
) ||
|
|
14
|
-
fetch(endpoint, {
|
|
15
|
-
method: "POST",
|
|
16
|
-
headers: { "Content-Type": "application/json" },
|
|
17
|
-
body: JSON.stringify(data),
|
|
18
|
-
keepalive: true,
|
|
19
|
-
}).catch(() => {});
|
|
20
|
-
}
|
package/src/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { initMonitoring } from "./core/init.js";
|
package/src/network/auto.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { sendLog } from "../core/sender.js";
|
|
2
|
-
import { getMetadata } from "../utils/metadata.js";
|
|
3
|
-
|
|
4
|
-
export function monitorFetch() {
|
|
5
|
-
const originalFetch = window.fetch;
|
|
6
|
-
|
|
7
|
-
window.fetch = async (input, init = {}) => {
|
|
8
|
-
const start = Date.now();
|
|
9
|
-
|
|
10
|
-
let requestBody = init.body || null;
|
|
11
|
-
let method = init.method || "GET";
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
const response = await originalFetch(input, init);
|
|
15
|
-
|
|
16
|
-
// Clone response to read body safely
|
|
17
|
-
const clone = response.clone();
|
|
18
|
-
let responseBody = null;
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
responseBody = await clone.text();
|
|
22
|
-
} catch {}
|
|
23
|
-
|
|
24
|
-
sendLog({
|
|
25
|
-
type: "api_call",
|
|
26
|
-
transport: "fetch",
|
|
27
|
-
url: typeof input === "string" ? input : input.url,
|
|
28
|
-
method,
|
|
29
|
-
statusCode: response.status,
|
|
30
|
-
requestHeaders: init.headers,
|
|
31
|
-
requestBody,
|
|
32
|
-
responseHeaders: Object.fromEntries(
|
|
33
|
-
response.headers.entries()
|
|
34
|
-
),
|
|
35
|
-
responseBody,
|
|
36
|
-
duration: Date.now() - start,
|
|
37
|
-
...getMetadata(),
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return response;
|
|
41
|
-
} catch (err) {
|
|
42
|
-
sendLog({
|
|
43
|
-
type: "api_error",
|
|
44
|
-
transport: "fetch",
|
|
45
|
-
url: input,
|
|
46
|
-
method,
|
|
47
|
-
error: err.message,
|
|
48
|
-
...getMetadata(),
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
throw err;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { sendLog } from "../core/sender.js";
|
|
2
|
-
import { getMetadata } from "../utils/metadata.js";
|
|
3
|
-
|
|
4
|
-
export function monitorXHR() {
|
|
5
|
-
const originalOpen = XMLHttpRequest.prototype.open;
|
|
6
|
-
const originalSend = XMLHttpRequest.prototype.send;
|
|
7
|
-
const originalSetHeader =
|
|
8
|
-
XMLHttpRequest.prototype.setRequestHeader;
|
|
9
|
-
|
|
10
|
-
XMLHttpRequest.prototype.open = function (
|
|
11
|
-
method,
|
|
12
|
-
url,
|
|
13
|
-
...rest
|
|
14
|
-
) {
|
|
15
|
-
this._method = method;
|
|
16
|
-
this._url = url;
|
|
17
|
-
this._headers = {};
|
|
18
|
-
return originalOpen.call(this, method, url, ...rest);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
XMLHttpRequest.prototype.setRequestHeader = function (
|
|
22
|
-
key,
|
|
23
|
-
value
|
|
24
|
-
) {
|
|
25
|
-
this._headers[key] = value;
|
|
26
|
-
return originalSetHeader.call(this, key, value);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
XMLHttpRequest.prototype.send = function (body) {
|
|
30
|
-
const start = Date.now();
|
|
31
|
-
|
|
32
|
-
this.addEventListener("loadend", () => {
|
|
33
|
-
sendLog({
|
|
34
|
-
type: "api_call",
|
|
35
|
-
transport: "xhr",
|
|
36
|
-
url: this._url,
|
|
37
|
-
method: this._method,
|
|
38
|
-
statusCode: this.status,
|
|
39
|
-
requestHeaders: this._headers,
|
|
40
|
-
requestBody: body,
|
|
41
|
-
responseHeaders: this.getAllResponseHeaders(),
|
|
42
|
-
responseBody: this.responseText,
|
|
43
|
-
duration: Date.now() - start,
|
|
44
|
-
...getMetadata(),
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
return originalSend.call(this, body);
|
|
49
|
-
};
|
|
50
|
-
}
|