@openreplay/tracker 4.1.8 → 4.1.9-beta.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 +18 -0
- package/README.md +22 -18
- package/cjs/app/guards.d.ts +10 -11
- package/cjs/app/guards.js +2 -1
- package/cjs/app/index.d.ts +5 -3
- package/cjs/app/index.js +53 -36
- package/cjs/app/messages.gen.d.ts +3 -2
- package/cjs/app/messages.gen.js +19 -5
- package/cjs/app/observer/observer.js +4 -4
- package/cjs/app/observer/top_observer.js +1 -1
- package/cjs/app/session.d.ts +1 -1
- package/cjs/app/session.js +1 -1
- package/cjs/common/messages.gen.d.ts +16 -4
- package/cjs/index.d.ts +5 -1
- package/cjs/index.js +6 -4
- package/cjs/modules/cssrules.js +1 -1
- package/cjs/modules/focus.js +2 -2
- package/cjs/modules/img.js +1 -1
- package/cjs/modules/input.js +9 -17
- package/cjs/modules/mouse.js +1 -1
- package/cjs/modules/network.d.ts +28 -0
- package/cjs/modules/network.js +203 -0
- package/cjs/modules/timing.js +9 -6
- package/cjs/modules/viewport.js +3 -1
- package/cjs/utils.d.ts +1 -0
- package/cjs/utils.js +7 -4
- package/jest.config.js +11 -0
- package/lib/app/guards.d.ts +10 -11
- package/lib/app/guards.js +2 -1
- package/lib/app/index.d.ts +5 -3
- package/lib/app/index.js +54 -37
- package/lib/app/messages.gen.d.ts +3 -2
- package/lib/app/messages.gen.js +15 -2
- package/lib/app/observer/observer.js +4 -4
- package/lib/app/observer/top_observer.js +1 -1
- package/lib/app/session.d.ts +1 -1
- package/lib/app/session.js +1 -1
- package/lib/common/messages.gen.d.ts +16 -4
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.d.ts +5 -1
- package/lib/index.js +7 -5
- package/lib/modules/cssrules.js +1 -1
- package/lib/modules/focus.js +2 -2
- package/lib/modules/img.js +1 -1
- package/lib/modules/input.js +9 -17
- package/lib/modules/mouse.js +1 -1
- package/lib/modules/network.d.ts +28 -0
- package/lib/modules/network.js +200 -0
- package/lib/modules/timing.js +10 -7
- package/lib/modules/viewport.js +3 -1
- package/lib/utils.d.ts +1 -0
- package/lib/utils.js +5 -3
- package/package.json +8 -3
- package/cjs/app/messages.d.ts +0 -52
- package/cjs/app/messages.js +0 -234
- package/lib/app/messages.d.ts +0 -52
- package/lib/app/messages.js +0 -181
package/cjs/index.js
CHANGED
|
@@ -22,6 +22,7 @@ const viewport_js_1 = require("./modules/viewport.js");
|
|
|
22
22
|
const cssrules_js_1 = require("./modules/cssrules.js");
|
|
23
23
|
const focus_js_1 = require("./modules/focus.js");
|
|
24
24
|
const fonts_js_1 = require("./modules/fonts.js");
|
|
25
|
+
const network_js_1 = require("./modules/network.js");
|
|
25
26
|
const constructedStyleSheets_js_1 = require("./modules/constructedStyleSheets.js");
|
|
26
27
|
const utils_js_1 = require("./utils.js");
|
|
27
28
|
const DOCS_SETUP = '/installation/setup-or';
|
|
@@ -114,6 +115,7 @@ class API {
|
|
|
114
115
|
(0, scroll_js_1.default)(app);
|
|
115
116
|
(0, focus_js_1.default)(app);
|
|
116
117
|
(0, fonts_js_1.default)(app);
|
|
118
|
+
(0, network_js_1.default)(app, options.network);
|
|
117
119
|
window.__OPENREPLAY__ = this;
|
|
118
120
|
if (options.autoResetOnWindowOpen) {
|
|
119
121
|
const wOpen = window.open;
|
|
@@ -138,7 +140,7 @@ class API {
|
|
|
138
140
|
// no-cors issue only with text/plain or not-set Content-Type
|
|
139
141
|
// req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
140
142
|
req.send(JSON.stringify({
|
|
141
|
-
trackerVersion: '4.1.
|
|
143
|
+
trackerVersion: '4.1.9-beta.2',
|
|
142
144
|
projectKey: options.projectKey,
|
|
143
145
|
doNotTrack,
|
|
144
146
|
// TODO: add precise reason (an exact API missing)
|
|
@@ -188,11 +190,11 @@ class API {
|
|
|
188
190
|
(0, utils_js_1.deprecationWarn)("'sessionID' method", "'getSessionID' method", '/');
|
|
189
191
|
return this.getSessionID();
|
|
190
192
|
}
|
|
191
|
-
getSessionURL() {
|
|
193
|
+
getSessionURL(options) {
|
|
192
194
|
if (this.app === null) {
|
|
193
195
|
return undefined;
|
|
194
196
|
}
|
|
195
|
-
return this.app.getSessionURL();
|
|
197
|
+
return this.app.getSessionURL(options);
|
|
196
198
|
}
|
|
197
199
|
setUserID(id) {
|
|
198
200
|
if (typeof id === 'string' && this.app !== null) {
|
|
@@ -233,7 +235,7 @@ class API {
|
|
|
233
235
|
catch (e) {
|
|
234
236
|
return;
|
|
235
237
|
}
|
|
236
|
-
this.app.send((0, messages_gen_js_1.
|
|
238
|
+
this.app.send((0, messages_gen_js_1.CustomEvent)(key, payload));
|
|
237
239
|
}
|
|
238
240
|
}
|
|
239
241
|
}
|
package/cjs/modules/cssrules.js
CHANGED
|
@@ -76,7 +76,7 @@ function default_1(app) {
|
|
|
76
76
|
patchContext(window);
|
|
77
77
|
app.observer.attachContextCallback(patchContext);
|
|
78
78
|
app.nodes.attachNodeCallback((node) => {
|
|
79
|
-
if (!((0, guards_js_1.hasTag)(node, '
|
|
79
|
+
if (!((0, guards_js_1.hasTag)(node, 'style')) || !node.sheet) {
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
82
|
if (node.textContent !== null && node.textContent.trim().length > 0) {
|
package/cjs/modules/focus.js
CHANGED
|
@@ -11,7 +11,7 @@ function default_1(app) {
|
|
|
11
11
|
}
|
|
12
12
|
let blurred = false;
|
|
13
13
|
app.nodes.attachNodeCallback((node) => {
|
|
14
|
-
if (!(0, guards_js_1.hasTag)(node, '
|
|
14
|
+
if (!(0, guards_js_1.hasTag)(node, 'body')) {
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
app.nodes.attachNodeListener(node, 'focus', (e) => {
|
|
@@ -34,7 +34,7 @@ function default_1(app) {
|
|
|
34
34
|
});
|
|
35
35
|
app.attachStartCallback(() => {
|
|
36
36
|
let elem = document.activeElement;
|
|
37
|
-
while (elem && (0, guards_js_1.hasTag)(elem, '
|
|
37
|
+
while (elem && (0, guards_js_1.hasTag)(elem, 'iframe') && elem.contentDocument) {
|
|
38
38
|
elem = elem.contentDocument.activeElement;
|
|
39
39
|
}
|
|
40
40
|
if (elem && elem !== elem.ownerDocument.body) {
|
package/cjs/modules/img.js
CHANGED
|
@@ -97,7 +97,7 @@ function default_1(app) {
|
|
|
97
97
|
observer.disconnect();
|
|
98
98
|
});
|
|
99
99
|
app.nodes.attachNodeCallback((node) => {
|
|
100
|
-
if (!(0, guards_js_1.hasTag)(node, '
|
|
100
|
+
if (!(0, guards_js_1.hasTag)(node, 'img')) {
|
|
101
101
|
return;
|
|
102
102
|
}
|
|
103
103
|
app.nodes.attachNodeListener(node, 'error', () => sendImgError(node));
|
package/cjs/modules/input.js
CHANGED
|
@@ -4,18 +4,18 @@ exports.getInputLabel = void 0;
|
|
|
4
4
|
const utils_js_1 = require("../utils.js");
|
|
5
5
|
const guards_js_1 = require("../app/guards.js");
|
|
6
6
|
const messages_gen_js_1 = require("../app/messages.gen.js");
|
|
7
|
-
const INPUT_TYPES = ['text', 'password', 'email', 'search', 'number', 'range', 'date'];
|
|
7
|
+
const INPUT_TYPES = ['text', 'password', 'email', 'search', 'number', 'range', 'date', 'tel'];
|
|
8
8
|
function isTextEditable(node) {
|
|
9
|
-
if ((0, guards_js_1.hasTag)(node, '
|
|
9
|
+
if ((0, guards_js_1.hasTag)(node, 'textarea')) {
|
|
10
10
|
return true;
|
|
11
11
|
}
|
|
12
|
-
if (!(0, guards_js_1.hasTag)(node, '
|
|
12
|
+
if (!(0, guards_js_1.hasTag)(node, 'input')) {
|
|
13
13
|
return false;
|
|
14
14
|
}
|
|
15
15
|
return INPUT_TYPES.includes(node.type);
|
|
16
16
|
}
|
|
17
17
|
function isCheckable(node) {
|
|
18
|
-
if (!(0, guards_js_1.hasTag)(node, '
|
|
18
|
+
if (!(0, guards_js_1.hasTag)(node, 'input')) {
|
|
19
19
|
return false;
|
|
20
20
|
}
|
|
21
21
|
const type = node.type;
|
|
@@ -25,7 +25,7 @@ const labelElementFor = utils_js_1.IN_BROWSER && 'labels' in HTMLInputElement.pr
|
|
|
25
25
|
? (node) => {
|
|
26
26
|
let p = node;
|
|
27
27
|
while ((p = p.parentNode) !== null) {
|
|
28
|
-
if ((0, guards_js_1.hasTag)(p, '
|
|
28
|
+
if ((0, guards_js_1.hasTag)(p, 'label')) {
|
|
29
29
|
return p;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -37,7 +37,7 @@ const labelElementFor = utils_js_1.IN_BROWSER && 'labels' in HTMLInputElement.pr
|
|
|
37
37
|
: (node) => {
|
|
38
38
|
let p = node;
|
|
39
39
|
while ((p = p.parentNode) !== null) {
|
|
40
|
-
if ((0, guards_js_1.hasTag)(p, '
|
|
40
|
+
if ((0, guards_js_1.hasTag)(p, 'label')) {
|
|
41
41
|
return p;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -115,11 +115,7 @@ function default_1(app, opts) {
|
|
|
115
115
|
inputValues.forEach((value, id) => {
|
|
116
116
|
const node = app.nodes.getNode(id);
|
|
117
117
|
if (!node)
|
|
118
|
-
return;
|
|
119
|
-
if (!isTextEditable(node)) {
|
|
120
|
-
inputValues.delete(id);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
118
|
+
return inputValues.delete(id);
|
|
123
119
|
if (value !== node.value) {
|
|
124
120
|
inputValues.set(id, node.value);
|
|
125
121
|
if (!registeredTargets.has(id)) {
|
|
@@ -132,11 +128,7 @@ function default_1(app, opts) {
|
|
|
132
128
|
checkableValues.forEach((checked, id) => {
|
|
133
129
|
const node = app.nodes.getNode(id);
|
|
134
130
|
if (!node)
|
|
135
|
-
return;
|
|
136
|
-
if (!isCheckable(node)) {
|
|
137
|
-
checkableValues.delete(id);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
131
|
+
return checkableValues.delete(id);
|
|
140
132
|
if (checked !== node.checked) {
|
|
141
133
|
checkableValues.set(id, node.checked);
|
|
142
134
|
app.send((0, messages_gen_js_1.SetInputChecked)(id, node.checked));
|
|
@@ -150,7 +142,7 @@ function default_1(app, opts) {
|
|
|
150
142
|
return;
|
|
151
143
|
}
|
|
152
144
|
// TODO: support multiple select (?): use selectedOptions; Need send target?
|
|
153
|
-
if ((0, guards_js_1.hasTag)(node, '
|
|
145
|
+
if ((0, guards_js_1.hasTag)(node, 'select')) {
|
|
154
146
|
sendInputValue(id, node);
|
|
155
147
|
app.attachEventListener(node, 'change', () => {
|
|
156
148
|
sendInputValue(id, node);
|
package/cjs/modules/mouse.js
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type App from '../app/index.js';
|
|
2
|
+
declare type XHRRequestBody = Parameters<XMLHttpRequest['send']>[0];
|
|
3
|
+
declare type FetchRequestBody = RequestInit['body'];
|
|
4
|
+
interface RequestData {
|
|
5
|
+
body: XHRRequestBody | FetchRequestBody;
|
|
6
|
+
headers: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
interface ResponseData {
|
|
9
|
+
body: any;
|
|
10
|
+
headers: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
interface RequestResponseData {
|
|
13
|
+
readonly status: number;
|
|
14
|
+
readonly method: string;
|
|
15
|
+
url: string;
|
|
16
|
+
request: RequestData;
|
|
17
|
+
response: ResponseData;
|
|
18
|
+
}
|
|
19
|
+
declare type Sanitizer = (data: RequestResponseData) => RequestResponseData | null;
|
|
20
|
+
export interface Options {
|
|
21
|
+
sessionTokenHeader: string | boolean;
|
|
22
|
+
failuresOnly: boolean;
|
|
23
|
+
ignoreHeaders: Array<string> | boolean;
|
|
24
|
+
capturePayload: boolean;
|
|
25
|
+
sanitizer?: Sanitizer;
|
|
26
|
+
}
|
|
27
|
+
export default function (app: App, opts?: Partial<Options>): void;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const messages_gen_js_1 = require("../app/messages.gen.js");
|
|
4
|
+
const utils_js_1 = require("../utils.js");
|
|
5
|
+
function getXHRRequestDataObject(xhr) {
|
|
6
|
+
// @ts-ignore this is 3x faster than using Map<XHR, XHRRequestData>
|
|
7
|
+
if (!xhr.__or_req_data__) {
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
xhr.__or_req_data__ = { body: undefined, headers: {} };
|
|
10
|
+
}
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
return xhr.__or_req_data__;
|
|
13
|
+
}
|
|
14
|
+
function strMethod(method) {
|
|
15
|
+
return typeof method === 'string' ? method.toUpperCase() : 'GET';
|
|
16
|
+
}
|
|
17
|
+
function default_1(app, opts = {}) {
|
|
18
|
+
const options = Object.assign({
|
|
19
|
+
failuresOnly: false,
|
|
20
|
+
ignoreHeaders: ['Cookie', 'Set-Cookie', 'Authorization'],
|
|
21
|
+
capturePayload: false,
|
|
22
|
+
sessionTokenHeader: false,
|
|
23
|
+
}, opts);
|
|
24
|
+
const ignoreHeaders = options.ignoreHeaders;
|
|
25
|
+
const isHIgnored = Array.isArray(ignoreHeaders)
|
|
26
|
+
? (name) => ignoreHeaders.includes(name)
|
|
27
|
+
: () => ignoreHeaders;
|
|
28
|
+
const stHeader = options.sessionTokenHeader === true ? 'X-OpenReplay-SessionToken' : options.sessionTokenHeader;
|
|
29
|
+
function setSessionTokenHeader(setRequestHeader) {
|
|
30
|
+
if (stHeader) {
|
|
31
|
+
const sessionToken = app.getSessionToken();
|
|
32
|
+
if (sessionToken) {
|
|
33
|
+
app.safe(setRequestHeader)(stHeader, sessionToken);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function sanitize(reqResInfo) {
|
|
38
|
+
if (!options.capturePayload) {
|
|
39
|
+
delete reqResInfo.request.body;
|
|
40
|
+
delete reqResInfo.response.body;
|
|
41
|
+
}
|
|
42
|
+
if (options.sanitizer) {
|
|
43
|
+
const resBody = reqResInfo.response.body;
|
|
44
|
+
if (typeof resBody === 'string') {
|
|
45
|
+
// Parse response in order to have handy view in sanitisation function
|
|
46
|
+
try {
|
|
47
|
+
reqResInfo.response.body = JSON.parse(resBody);
|
|
48
|
+
}
|
|
49
|
+
catch (_a) { }
|
|
50
|
+
}
|
|
51
|
+
return options.sanitizer(reqResInfo);
|
|
52
|
+
}
|
|
53
|
+
return reqResInfo;
|
|
54
|
+
}
|
|
55
|
+
function stringify(r) {
|
|
56
|
+
if (r && typeof r.body !== 'string') {
|
|
57
|
+
try {
|
|
58
|
+
r.body = JSON.stringify(r.body);
|
|
59
|
+
}
|
|
60
|
+
catch (_a) {
|
|
61
|
+
r.body = '<unable to stringify>';
|
|
62
|
+
app.notify.warn("Openreplay fetch couldn't stringify body:", r.body);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return JSON.stringify(r);
|
|
66
|
+
}
|
|
67
|
+
/* ====== Fetch ====== */
|
|
68
|
+
const origFetch = window.fetch.bind(window);
|
|
69
|
+
window.fetch = (input, init = {}) => {
|
|
70
|
+
if (!(typeof input === 'string' || input instanceof URL) || app.isServiceURL(String(input))) {
|
|
71
|
+
return origFetch(input, init);
|
|
72
|
+
}
|
|
73
|
+
setSessionTokenHeader(function (name, value) {
|
|
74
|
+
if (init.headers === undefined) {
|
|
75
|
+
init.headers = {};
|
|
76
|
+
}
|
|
77
|
+
if (init.headers instanceof Headers) {
|
|
78
|
+
init.headers.append(name, value);
|
|
79
|
+
}
|
|
80
|
+
else if (Array.isArray(init.headers)) {
|
|
81
|
+
init.headers.push([name, value]);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
init.headers[name] = value;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const startTime = performance.now();
|
|
88
|
+
return origFetch(input, init).then((response) => {
|
|
89
|
+
const duration = performance.now() - startTime;
|
|
90
|
+
if (options.failuresOnly && response.status < 400) {
|
|
91
|
+
return response;
|
|
92
|
+
}
|
|
93
|
+
const r = response.clone();
|
|
94
|
+
r.text()
|
|
95
|
+
.then((text) => {
|
|
96
|
+
const reqHs = {};
|
|
97
|
+
const resHs = {};
|
|
98
|
+
if (ignoreHeaders !== true) {
|
|
99
|
+
// request headers
|
|
100
|
+
const writeReqHeader = ([n, v]) => {
|
|
101
|
+
if (!isHIgnored(n)) {
|
|
102
|
+
reqHs[n] = v;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
if (init.headers instanceof Headers) {
|
|
106
|
+
init.headers.forEach((v, n) => writeReqHeader([n, v]));
|
|
107
|
+
}
|
|
108
|
+
else if (Array.isArray(init.headers)) {
|
|
109
|
+
init.headers.forEach(writeReqHeader);
|
|
110
|
+
}
|
|
111
|
+
else if (typeof init.headers === 'object') {
|
|
112
|
+
Object.entries(init.headers).forEach(writeReqHeader);
|
|
113
|
+
}
|
|
114
|
+
// response headers
|
|
115
|
+
r.headers.forEach((v, n) => {
|
|
116
|
+
if (!isHIgnored(n))
|
|
117
|
+
resHs[n] = v;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
const method = strMethod(init.method);
|
|
121
|
+
const reqResInfo = sanitize({
|
|
122
|
+
url: String(input),
|
|
123
|
+
method,
|
|
124
|
+
status: r.status,
|
|
125
|
+
request: {
|
|
126
|
+
headers: reqHs,
|
|
127
|
+
body: init.body,
|
|
128
|
+
},
|
|
129
|
+
response: {
|
|
130
|
+
headers: resHs,
|
|
131
|
+
body: text,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
if (!reqResInfo) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
app.send((0, messages_gen_js_1.NetworkRequest)('fetch', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), r.status, startTime + (0, utils_js_1.getTimeOrigin)(), duration));
|
|
138
|
+
})
|
|
139
|
+
.catch((e) => app.debug.error('Could not process Fetch response:', e));
|
|
140
|
+
return response;
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
/* ====== <> ====== */
|
|
144
|
+
/* ====== XHR ====== */
|
|
145
|
+
const nativeOpen = XMLHttpRequest.prototype.open;
|
|
146
|
+
XMLHttpRequest.prototype.open = function (initMethod, url) {
|
|
147
|
+
const xhr = this;
|
|
148
|
+
setSessionTokenHeader((name, value) => xhr.setRequestHeader(name, value));
|
|
149
|
+
let startTime = 0;
|
|
150
|
+
xhr.addEventListener('loadstart', (e) => {
|
|
151
|
+
startTime = e.timeStamp;
|
|
152
|
+
});
|
|
153
|
+
xhr.addEventListener('load', app.safe((e) => {
|
|
154
|
+
const { headers: reqHs, body: reqBody } = getXHRRequestDataObject(xhr);
|
|
155
|
+
const duration = startTime > 0 ? e.timeStamp - startTime : 0;
|
|
156
|
+
const hString = ignoreHeaders ? '' : xhr.getAllResponseHeaders(); // might be null (though only if no response received though)
|
|
157
|
+
const resHs = hString
|
|
158
|
+
? hString
|
|
159
|
+
.split('\r\n')
|
|
160
|
+
.map((h) => h.split(':'))
|
|
161
|
+
.filter((entry) => !isHIgnored(entry[0]))
|
|
162
|
+
.reduce((hds, [name, value]) => (Object.assign(Object.assign({}, hds), { [name]: value })), {})
|
|
163
|
+
: {};
|
|
164
|
+
const method = strMethod(initMethod);
|
|
165
|
+
const reqResInfo = sanitize({
|
|
166
|
+
url: String(url),
|
|
167
|
+
method,
|
|
168
|
+
status: xhr.status,
|
|
169
|
+
request: {
|
|
170
|
+
headers: reqHs,
|
|
171
|
+
body: reqBody,
|
|
172
|
+
},
|
|
173
|
+
response: {
|
|
174
|
+
headers: resHs,
|
|
175
|
+
body: xhr.response,
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
if (!reqResInfo) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
app.send((0, messages_gen_js_1.NetworkRequest)('xhr', method, String(reqResInfo.url), stringify(reqResInfo.request), stringify(reqResInfo.response), xhr.status, startTime + (0, utils_js_1.getTimeOrigin)(), duration));
|
|
182
|
+
}));
|
|
183
|
+
//TODO: handle error (though it has no Error API nor any useful information)
|
|
184
|
+
//xhr.addEventListener('error', (e) => {})
|
|
185
|
+
return nativeOpen.apply(this, arguments);
|
|
186
|
+
};
|
|
187
|
+
const nativeSend = XMLHttpRequest.prototype.send;
|
|
188
|
+
XMLHttpRequest.prototype.send = function (body) {
|
|
189
|
+
const rdo = getXHRRequestDataObject(this);
|
|
190
|
+
rdo.body = body;
|
|
191
|
+
return nativeSend.apply(this, arguments);
|
|
192
|
+
};
|
|
193
|
+
const nativeSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
194
|
+
XMLHttpRequest.prototype.setRequestHeader = function (name, value) {
|
|
195
|
+
if (!isHIgnored(name)) {
|
|
196
|
+
const rdo = getXHRRequestDataObject(this);
|
|
197
|
+
rdo.headers[name] = value;
|
|
198
|
+
}
|
|
199
|
+
return nativeSetRequestHeader.apply(this, arguments);
|
|
200
|
+
};
|
|
201
|
+
/* ====== <> ====== */
|
|
202
|
+
}
|
|
203
|
+
exports.default = default_1;
|
package/cjs/modules/timing.js
CHANGED
|
@@ -10,7 +10,7 @@ function getPaintBlocks(resources) {
|
|
|
10
10
|
for (let i = 0; i < elements.length; i++) {
|
|
11
11
|
const element = elements[i];
|
|
12
12
|
let src = '';
|
|
13
|
-
if ((0, guards_js_1.hasTag)(element, '
|
|
13
|
+
if ((0, guards_js_1.hasTag)(element, 'img')) {
|
|
14
14
|
src = element.currentSrc || element.src;
|
|
15
15
|
}
|
|
16
16
|
if (!src) {
|
|
@@ -70,13 +70,12 @@ function default_1(app, opts) {
|
|
|
70
70
|
} // Resources are necessary for all timings
|
|
71
71
|
let resources = {};
|
|
72
72
|
function resourceTiming(entry) {
|
|
73
|
-
var _a;
|
|
74
73
|
if (entry.duration < 0 || !(0, utils_js_1.isURL)(entry.name) || app.isServiceURL(entry.name))
|
|
75
74
|
return;
|
|
76
75
|
if (resources !== null) {
|
|
77
76
|
resources[entry.name] = entry.startTime + entry.duration;
|
|
78
77
|
}
|
|
79
|
-
app.send((0, messages_gen_js_1.ResourceTiming)(entry.startTime + (
|
|
78
|
+
app.send((0, messages_gen_js_1.ResourceTiming)(entry.startTime + (0, utils_js_1.getTimeOrigin)(), entry.duration, entry.responseStart && entry.startTime ? entry.responseStart - entry.startTime : 0, entry.transferSize > entry.encodedBodySize ? entry.transferSize - entry.encodedBodySize : 0, entry.encodedBodySize || 0, entry.decodedBodySize || 0, entry.name, entry.initiatorType));
|
|
80
79
|
}
|
|
81
80
|
const observer = new PerformanceObserver((list) => list.getEntries().forEach(resourceTiming));
|
|
82
81
|
let prevSessionID;
|
|
@@ -113,7 +112,11 @@ function default_1(app, opts) {
|
|
|
113
112
|
}
|
|
114
113
|
if (performance.timing.loadEventEnd || performance.now() > 30000) {
|
|
115
114
|
pageLoadTimingSent = true;
|
|
116
|
-
const {
|
|
115
|
+
const {
|
|
116
|
+
// should be ok to use here, (https://github.com/mdn/content/issues/4713)
|
|
117
|
+
// since it is compared with the values obtained on the page load (before any possible sleep state)
|
|
118
|
+
// deprecated though
|
|
119
|
+
navigationStart, requestStart, responseStart, responseEnd, domContentLoadedEventStart, domContentLoadedEventEnd, loadEventStart, loadEventEnd, } = performance.timing;
|
|
117
120
|
app.send((0, messages_gen_js_1.PageLoadTiming)(requestStart - navigationStart || 0, responseStart - navigationStart || 0, responseEnd - navigationStart || 0, domContentLoadedEventStart - navigationStart || 0, domContentLoadedEventEnd - navigationStart || 0, loadEventStart - navigationStart || 0, loadEventEnd - navigationStart || 0, firstPaint, firstContentfulPaint));
|
|
118
121
|
}
|
|
119
122
|
}, 30);
|
|
@@ -145,9 +148,9 @@ function default_1(app, opts) {
|
|
|
145
148
|
const speedIndex = paintBlocks === null
|
|
146
149
|
? 0
|
|
147
150
|
: calculateSpeedIndex(firstContentfulPaint || firstPaint, paintBlocks);
|
|
151
|
+
const { domContentLoadedEventEnd, navigationStart } = performance.timing;
|
|
148
152
|
const timeToInteractive = interactiveWindowTickTime === null
|
|
149
|
-
? Math.max(interactiveWindowStartTime, firstContentfulPaint,
|
|
150
|
-
0)
|
|
153
|
+
? Math.max(interactiveWindowStartTime, firstContentfulPaint, domContentLoadedEventEnd - navigationStart || 0)
|
|
151
154
|
: 0;
|
|
152
155
|
app.send((0, messages_gen_js_1.PageRenderTiming)(speedIndex, firstContentfulPaint > visuallyComplete ? firstContentfulPaint : visuallyComplete, timeToInteractive));
|
|
153
156
|
}
|
package/cjs/modules/viewport.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_js_1 = require("../utils.js");
|
|
3
4
|
const messages_gen_js_1 = require("../app/messages.gen.js");
|
|
4
5
|
function default_1(app) {
|
|
5
6
|
let url, width, height;
|
|
6
|
-
let navigationStart
|
|
7
|
+
let navigationStart;
|
|
7
8
|
const sendSetPageLocation = app.safe(() => {
|
|
8
9
|
const { URL } = document;
|
|
9
10
|
if (URL !== url) {
|
|
@@ -25,6 +26,7 @@ function default_1(app) {
|
|
|
25
26
|
: app.safe(() => app.send((0, messages_gen_js_1.SetPageVisibility)(document.hidden)));
|
|
26
27
|
app.attachStartCallback(() => {
|
|
27
28
|
url = '';
|
|
29
|
+
navigationStart = (0, utils_js_1.getTimeOrigin)();
|
|
28
30
|
width = height = -1;
|
|
29
31
|
sendSetPageLocation();
|
|
30
32
|
sendSetViewportSize();
|
package/cjs/utils.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export declare const IN_BROWSER: boolean;
|
|
|
2
2
|
export declare const IS_FIREFOX: false | RegExpMatchArray | null;
|
|
3
3
|
export declare const MAX_STR_LEN = 100000;
|
|
4
4
|
export declare function adjustTimeOrigin(): void;
|
|
5
|
+
export declare function getTimeOrigin(): number;
|
|
5
6
|
export declare const now: () => number;
|
|
6
7
|
export declare const stars: (str: string) => string;
|
|
7
8
|
export declare function normSpaces(str: string): string;
|
package/cjs/utils.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hasOpenreplayAttribute = exports.getLabelAttribute = exports.deprecationWarn = exports.DOCS_HOST = exports.isURL = exports.normSpaces = exports.stars = exports.now = exports.adjustTimeOrigin = exports.MAX_STR_LEN = exports.IS_FIREFOX = exports.IN_BROWSER = void 0;
|
|
3
|
+
exports.hasOpenreplayAttribute = exports.getLabelAttribute = exports.deprecationWarn = exports.DOCS_HOST = exports.isURL = exports.normSpaces = exports.stars = exports.now = exports.getTimeOrigin = exports.adjustTimeOrigin = exports.MAX_STR_LEN = exports.IS_FIREFOX = exports.IN_BROWSER = void 0;
|
|
4
4
|
const DEPRECATED_ATTRS = { htmlmasked: 'hidden', masked: 'obscured' };
|
|
5
5
|
exports.IN_BROWSER = !(typeof window === 'undefined');
|
|
6
6
|
exports.IS_FIREFOX = exports.IN_BROWSER && navigator.userAgent.match(/firefox|fxios/i);
|
|
7
7
|
exports.MAX_STR_LEN = 1e5;
|
|
8
8
|
// Buggy to use `performance.timeOrigin || performance.timing.navigationStart`
|
|
9
9
|
// https://github.com/mdn/content/issues/4713
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
: 0;
|
|
10
|
+
// Maybe move to timer/ticker
|
|
11
|
+
let timeOrigin = exports.IN_BROWSER ? Date.now() - performance.now() : 0;
|
|
13
12
|
function adjustTimeOrigin() {
|
|
14
13
|
timeOrigin = Date.now() - performance.now();
|
|
15
14
|
}
|
|
16
15
|
exports.adjustTimeOrigin = adjustTimeOrigin;
|
|
16
|
+
function getTimeOrigin() {
|
|
17
|
+
return timeOrigin;
|
|
18
|
+
}
|
|
19
|
+
exports.getTimeOrigin = getTimeOrigin;
|
|
17
20
|
exports.now = exports.IN_BROWSER && !!performance.now
|
|
18
21
|
? () => Math.round(performance.now() + timeOrigin)
|
|
19
22
|
: () => Date.now();
|
package/jest.config.js
ADDED
package/lib/app/guards.d.ts
CHANGED
|
@@ -5,17 +5,16 @@ export declare function isTextNode(node: Node): node is Text;
|
|
|
5
5
|
export declare function isDocument(node: Node): node is Document;
|
|
6
6
|
export declare function isRootNode(node: Node): node is Document | DocumentFragment;
|
|
7
7
|
declare type TagTypeMap = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
LINK: HTMLLinkElement;
|
|
8
|
+
html: HTMLHtmlElement;
|
|
9
|
+
body: HTMLBodyElement;
|
|
10
|
+
img: HTMLImageElement;
|
|
11
|
+
input: HTMLInputElement;
|
|
12
|
+
textarea: HTMLTextAreaElement;
|
|
13
|
+
select: HTMLSelectElement;
|
|
14
|
+
label: HTMLLabelElement;
|
|
15
|
+
iframe: HTMLIFrameElement;
|
|
16
|
+
style: HTMLStyleElement | SVGStyleElement;
|
|
17
|
+
link: HTMLLinkElement;
|
|
19
18
|
};
|
|
20
19
|
export declare function hasTag<T extends keyof TagTypeMap>(el: Node, tagName: T): el is TagTypeMap[typeof tagName];
|
|
21
20
|
export {};
|
package/lib/app/guards.js
CHANGED
|
@@ -18,5 +18,6 @@ export function isRootNode(node) {
|
|
|
18
18
|
return node.nodeType === Node.DOCUMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
|
|
19
19
|
}
|
|
20
20
|
export function hasTag(el, tagName) {
|
|
21
|
-
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
return el.localName === tagName;
|
|
22
23
|
}
|
package/lib/app/index.d.ts
CHANGED
|
@@ -75,6 +75,7 @@ export default class App {
|
|
|
75
75
|
private readonly worker?;
|
|
76
76
|
constructor(projectKey: string, sessionToken: string | undefined, options: Partial<Options>);
|
|
77
77
|
private _debug;
|
|
78
|
+
private _usingOldFetchPlugin;
|
|
78
79
|
send(message: Message, urgent?: boolean): void;
|
|
79
80
|
private commit;
|
|
80
81
|
private delay;
|
|
@@ -100,7 +101,9 @@ export default class App {
|
|
|
100
101
|
};
|
|
101
102
|
getSessionToken(): string | undefined;
|
|
102
103
|
getSessionID(): string | undefined;
|
|
103
|
-
getSessionURL(
|
|
104
|
+
getSessionURL(options?: {
|
|
105
|
+
withCurrentTime?: boolean;
|
|
106
|
+
}): string | undefined;
|
|
104
107
|
getHost(): string;
|
|
105
108
|
getProjectKey(): string;
|
|
106
109
|
getBaseHref(): string;
|
|
@@ -109,8 +112,7 @@ export default class App {
|
|
|
109
112
|
active(): boolean;
|
|
110
113
|
resetNextPageSession(flag: boolean): void;
|
|
111
114
|
private _start;
|
|
112
|
-
start(
|
|
115
|
+
start(...args: Parameters<App['_start']>): Promise<StartPromiseReturn>;
|
|
113
116
|
stop(stopWorker?: boolean): void;
|
|
114
|
-
restart(): void;
|
|
115
117
|
}
|
|
116
118
|
export {};
|