@openreplay/tracker 7.0.2-beta.1 → 7.0.2
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/CHANGELOG.md +4 -0
- package/cjs/modules/axiosSpy.d.ts +1 -0
- package/cjs/modules/axiosSpy.js +27 -6
- package/cjs/modules/network.js +11 -9
- package/lib/modules/axiosSpy.d.ts +1 -0
- package/lib/modules/axiosSpy.js +27 -6
- package/lib/modules/network.js +11 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -33,6 +33,7 @@ interface AxiosResponse<T = any> {
|
|
|
33
33
|
response?: AxiosRequestConfig;
|
|
34
34
|
}
|
|
35
35
|
export interface AxiosInstance extends Record<string, any> {
|
|
36
|
+
getUri: (config?: AxiosRequestConfig) => string;
|
|
36
37
|
interceptors: {
|
|
37
38
|
request: AxiosInterceptorManager<InternalAxiosRequestConfig>;
|
|
38
39
|
response: AxiosInterceptorManager<AxiosResponse>;
|
package/cjs/modules/axiosSpy.js
CHANGED
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const messages_gen_js_1 = require("../app/messages.gen.js");
|
|
4
4
|
const utils_js_1 = require("../utils.js");
|
|
5
|
+
const exception_js_1 = require("./exception.js");
|
|
5
6
|
function default_1(app, instance, opts, sanitize, stringify) {
|
|
7
|
+
app.debug.log('Openreplay: attaching axios spy to instance', instance);
|
|
6
8
|
function captureResponseData(axiosResponseObj) {
|
|
7
|
-
|
|
9
|
+
app.debug.log('Openreplay: capturing axios response data', axiosResponseObj);
|
|
10
|
+
const { headers: reqHs, data: reqData, method, url, baseURL } = axiosResponseObj.config;
|
|
8
11
|
const { data: rData, headers: rHs, status: globStatus, response } = axiosResponseObj;
|
|
9
12
|
const { data: resData, headers: resHs, status: resStatus } = response || {};
|
|
10
13
|
const ihOpt = opts.ignoreHeaders;
|
|
11
|
-
const isHIgnoring = Array.isArray(ihOpt)
|
|
12
|
-
? (name) => ihOpt.includes(name)
|
|
13
|
-
: () => ihOpt;
|
|
14
|
+
const isHIgnoring = Array.isArray(ihOpt) ? (name) => ihOpt.includes(name) : () => ihOpt;
|
|
14
15
|
function writeHeader(hsObj, header) {
|
|
15
16
|
if (!isHIgnoring(header[0])) {
|
|
16
17
|
hsObj[header[0]] = header[1];
|
|
@@ -60,13 +61,16 @@ function default_1(app, instance, opts, sanitize, stringify) {
|
|
|
60
61
|
},
|
|
61
62
|
});
|
|
62
63
|
if (!reqResInfo) {
|
|
64
|
+
app.debug.log('Openreplay: empty request/response info, skipping');
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
65
67
|
const requestStart = axiosResponseObj.config.__openreplay_timing;
|
|
66
68
|
const duration = performance.now() - requestStart;
|
|
69
|
+
app.debug.log('Openreplay: final req object', reqResInfo);
|
|
67
70
|
app.send((0, messages_gen_js_1.NetworkRequest)('xhr', String(method), String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), reqResInfo.status, requestStart + (0, utils_js_1.getTimeOrigin)(), duration));
|
|
68
71
|
}
|
|
69
72
|
function getStartTime(config) {
|
|
73
|
+
app.debug.log('Openreplay: capturing API request', config);
|
|
70
74
|
config.__openreplay_timing = performance.now();
|
|
71
75
|
if (opts.sessionTokenHeader) {
|
|
72
76
|
const header = typeof opts.sessionTokenHeader === 'string'
|
|
@@ -86,10 +90,21 @@ function default_1(app, instance, opts, sanitize, stringify) {
|
|
|
86
90
|
return response;
|
|
87
91
|
}
|
|
88
92
|
function captureNetworkError(error) {
|
|
89
|
-
|
|
93
|
+
app.debug.log('Openreplay: capturing API request error', error);
|
|
94
|
+
if (isAxiosError(error)) {
|
|
95
|
+
captureResponseData(error.response);
|
|
96
|
+
}
|
|
97
|
+
else if (error instanceof Error) {
|
|
98
|
+
app.send((0, exception_js_1.getExceptionMessage)(error, []));
|
|
99
|
+
}
|
|
90
100
|
return Promise.reject(error);
|
|
91
101
|
}
|
|
92
|
-
|
|
102
|
+
function logRequestError(ev) {
|
|
103
|
+
app.debug.log('Openreplay: failed API request, skipping', ev);
|
|
104
|
+
}
|
|
105
|
+
const reqInt = instance.interceptors.request.use(getStartTime, logRequestError, {
|
|
106
|
+
synchronous: true,
|
|
107
|
+
});
|
|
93
108
|
const resInt = instance.interceptors.response.use(captureNetworkRequest, captureNetworkError, {
|
|
94
109
|
synchronous: true,
|
|
95
110
|
});
|
|
@@ -100,3 +115,9 @@ function default_1(app, instance, opts, sanitize, stringify) {
|
|
|
100
115
|
});
|
|
101
116
|
}
|
|
102
117
|
exports.default = default_1;
|
|
118
|
+
function isAxiosError(payload) {
|
|
119
|
+
return isObject(payload) && payload.isAxiosError === true;
|
|
120
|
+
}
|
|
121
|
+
function isObject(thing) {
|
|
122
|
+
return thing !== null && typeof thing === 'object';
|
|
123
|
+
}
|
package/cjs/modules/network.js
CHANGED
|
@@ -160,14 +160,16 @@ function default_1(app, opts = {}) {
|
|
|
160
160
|
xhr.addEventListener('load', app.safe((e) => {
|
|
161
161
|
const { headers: reqHs, body: reqBody } = getXHRRequestDataObject(xhr);
|
|
162
162
|
const duration = startTime > 0 ? e.timeStamp - startTime : 0;
|
|
163
|
-
const hString =
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
163
|
+
const hString = xhr.getAllResponseHeaders() || ''; // might be null (though only if no response received though)
|
|
164
|
+
const headersArr = hString.trim().split(/[\r\n]+/);
|
|
165
|
+
const headerMap = {};
|
|
166
|
+
headersArr.forEach(function (line) {
|
|
167
|
+
const parts = line.split(': ');
|
|
168
|
+
const header = parts.shift();
|
|
169
|
+
if (!isHIgnored(header)) {
|
|
170
|
+
headerMap[header] = parts.join(': ');
|
|
171
|
+
}
|
|
172
|
+
});
|
|
171
173
|
const method = strMethod(initMethod);
|
|
172
174
|
const reqResInfo = sanitize({
|
|
173
175
|
url: String(url),
|
|
@@ -178,7 +180,7 @@ function default_1(app, opts = {}) {
|
|
|
178
180
|
body: reqBody,
|
|
179
181
|
},
|
|
180
182
|
response: {
|
|
181
|
-
headers:
|
|
183
|
+
headers: headerMap,
|
|
182
184
|
body: xhr.response,
|
|
183
185
|
},
|
|
184
186
|
});
|
|
@@ -33,6 +33,7 @@ interface AxiosResponse<T = any> {
|
|
|
33
33
|
response?: AxiosRequestConfig;
|
|
34
34
|
}
|
|
35
35
|
export interface AxiosInstance extends Record<string, any> {
|
|
36
|
+
getUri: (config?: AxiosRequestConfig) => string;
|
|
36
37
|
interceptors: {
|
|
37
38
|
request: AxiosInterceptorManager<InternalAxiosRequestConfig>;
|
|
38
39
|
response: AxiosInterceptorManager<AxiosResponse>;
|
package/lib/modules/axiosSpy.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { NetworkRequest } from '../app/messages.gen.js';
|
|
2
2
|
import { getTimeOrigin } from '../utils.js';
|
|
3
|
+
import { getExceptionMessage } from './exception.js';
|
|
3
4
|
export default function (app, instance, opts, sanitize, stringify) {
|
|
5
|
+
app.debug.log('Openreplay: attaching axios spy to instance', instance);
|
|
4
6
|
function captureResponseData(axiosResponseObj) {
|
|
5
|
-
|
|
7
|
+
app.debug.log('Openreplay: capturing axios response data', axiosResponseObj);
|
|
8
|
+
const { headers: reqHs, data: reqData, method, url, baseURL } = axiosResponseObj.config;
|
|
6
9
|
const { data: rData, headers: rHs, status: globStatus, response } = axiosResponseObj;
|
|
7
10
|
const { data: resData, headers: resHs, status: resStatus } = response || {};
|
|
8
11
|
const ihOpt = opts.ignoreHeaders;
|
|
9
|
-
const isHIgnoring = Array.isArray(ihOpt)
|
|
10
|
-
? (name) => ihOpt.includes(name)
|
|
11
|
-
: () => ihOpt;
|
|
12
|
+
const isHIgnoring = Array.isArray(ihOpt) ? (name) => ihOpt.includes(name) : () => ihOpt;
|
|
12
13
|
function writeHeader(hsObj, header) {
|
|
13
14
|
if (!isHIgnoring(header[0])) {
|
|
14
15
|
hsObj[header[0]] = header[1];
|
|
@@ -58,13 +59,16 @@ export default function (app, instance, opts, sanitize, stringify) {
|
|
|
58
59
|
},
|
|
59
60
|
});
|
|
60
61
|
if (!reqResInfo) {
|
|
62
|
+
app.debug.log('Openreplay: empty request/response info, skipping');
|
|
61
63
|
return;
|
|
62
64
|
}
|
|
63
65
|
const requestStart = axiosResponseObj.config.__openreplay_timing;
|
|
64
66
|
const duration = performance.now() - requestStart;
|
|
67
|
+
app.debug.log('Openreplay: final req object', reqResInfo);
|
|
65
68
|
app.send(NetworkRequest('xhr', String(method), String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), reqResInfo.status, requestStart + getTimeOrigin(), duration));
|
|
66
69
|
}
|
|
67
70
|
function getStartTime(config) {
|
|
71
|
+
app.debug.log('Openreplay: capturing API request', config);
|
|
68
72
|
config.__openreplay_timing = performance.now();
|
|
69
73
|
if (opts.sessionTokenHeader) {
|
|
70
74
|
const header = typeof opts.sessionTokenHeader === 'string'
|
|
@@ -84,10 +88,21 @@ export default function (app, instance, opts, sanitize, stringify) {
|
|
|
84
88
|
return response;
|
|
85
89
|
}
|
|
86
90
|
function captureNetworkError(error) {
|
|
87
|
-
|
|
91
|
+
app.debug.log('Openreplay: capturing API request error', error);
|
|
92
|
+
if (isAxiosError(error)) {
|
|
93
|
+
captureResponseData(error.response);
|
|
94
|
+
}
|
|
95
|
+
else if (error instanceof Error) {
|
|
96
|
+
app.send(getExceptionMessage(error, []));
|
|
97
|
+
}
|
|
88
98
|
return Promise.reject(error);
|
|
89
99
|
}
|
|
90
|
-
|
|
100
|
+
function logRequestError(ev) {
|
|
101
|
+
app.debug.log('Openreplay: failed API request, skipping', ev);
|
|
102
|
+
}
|
|
103
|
+
const reqInt = instance.interceptors.request.use(getStartTime, logRequestError, {
|
|
104
|
+
synchronous: true,
|
|
105
|
+
});
|
|
91
106
|
const resInt = instance.interceptors.response.use(captureNetworkRequest, captureNetworkError, {
|
|
92
107
|
synchronous: true,
|
|
93
108
|
});
|
|
@@ -97,3 +112,9 @@ export default function (app, instance, opts, sanitize, stringify) {
|
|
|
97
112
|
(_d = (_c = instance.interceptors.response).eject) === null || _d === void 0 ? void 0 : _d.call(_c, resInt);
|
|
98
113
|
});
|
|
99
114
|
}
|
|
115
|
+
function isAxiosError(payload) {
|
|
116
|
+
return isObject(payload) && payload.isAxiosError === true;
|
|
117
|
+
}
|
|
118
|
+
function isObject(thing) {
|
|
119
|
+
return thing !== null && typeof thing === 'object';
|
|
120
|
+
}
|
package/lib/modules/network.js
CHANGED
|
@@ -158,14 +158,16 @@ export default function (app, opts = {}) {
|
|
|
158
158
|
xhr.addEventListener('load', app.safe((e) => {
|
|
159
159
|
const { headers: reqHs, body: reqBody } = getXHRRequestDataObject(xhr);
|
|
160
160
|
const duration = startTime > 0 ? e.timeStamp - startTime : 0;
|
|
161
|
-
const hString =
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
161
|
+
const hString = xhr.getAllResponseHeaders() || ''; // might be null (though only if no response received though)
|
|
162
|
+
const headersArr = hString.trim().split(/[\r\n]+/);
|
|
163
|
+
const headerMap = {};
|
|
164
|
+
headersArr.forEach(function (line) {
|
|
165
|
+
const parts = line.split(': ');
|
|
166
|
+
const header = parts.shift();
|
|
167
|
+
if (!isHIgnored(header)) {
|
|
168
|
+
headerMap[header] = parts.join(': ');
|
|
169
|
+
}
|
|
170
|
+
});
|
|
169
171
|
const method = strMethod(initMethod);
|
|
170
172
|
const reqResInfo = sanitize({
|
|
171
173
|
url: String(url),
|
|
@@ -176,7 +178,7 @@ export default function (app, opts = {}) {
|
|
|
176
178
|
body: reqBody,
|
|
177
179
|
},
|
|
178
180
|
response: {
|
|
179
|
-
headers:
|
|
181
|
+
headers: headerMap,
|
|
180
182
|
body: xhr.response,
|
|
181
183
|
},
|
|
182
184
|
});
|