@openreplay/tracker 5.0.2 → 6.0.1-beta.1
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 +25 -1
- package/cjs/app/index.d.ts +3 -0
- package/cjs/app/index.js +4 -3
- package/cjs/app/messages.gen.d.ts +6 -1
- package/cjs/app/messages.gen.js +56 -5
- package/cjs/app/nodes.d.ts +1 -0
- package/cjs/app/nodes.js +3 -0
- package/cjs/app/observer/observer.js +7 -1
- package/cjs/app/observer/top_observer.js +4 -0
- package/cjs/app/ticker.d.ts +6 -0
- package/cjs/app/ticker.js +6 -0
- package/cjs/common/messages.gen.d.ts +46 -5
- package/cjs/index.d.ts +2 -0
- package/cjs/index.js +4 -2
- package/cjs/modules/img.js +1 -1
- package/cjs/modules/input.d.ts +2 -2
- package/cjs/modules/input.js +61 -39
- package/cjs/modules/mouse.d.ts +23 -1
- package/cjs/modules/mouse.js +43 -9
- package/cjs/modules/network.d.ts +1 -1
- package/cjs/modules/network.js +81 -10
- package/cjs/modules/selection.d.ts +7 -0
- package/cjs/modules/selection.js +37 -0
- package/cjs/modules/timing.js +3 -1
- package/cjs/utils.d.ts +2 -0
- package/cjs/utils.js +20 -1
- package/lib/app/index.d.ts +3 -0
- package/lib/app/index.js +4 -3
- package/lib/app/messages.gen.d.ts +6 -1
- package/lib/app/messages.gen.js +48 -2
- package/lib/app/nodes.d.ts +1 -0
- package/lib/app/nodes.js +3 -0
- package/lib/app/observer/observer.js +8 -2
- package/lib/app/observer/top_observer.js +5 -1
- package/lib/app/ticker.d.ts +6 -0
- package/lib/app/ticker.js +6 -0
- package/lib/common/messages.gen.d.ts +46 -5
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +4 -2
- package/lib/modules/img.js +1 -1
- package/lib/modules/input.d.ts +2 -2
- package/lib/modules/input.js +63 -41
- package/lib/modules/mouse.d.ts +23 -1
- package/lib/modules/mouse.js +45 -11
- package/lib/modules/network.d.ts +1 -1
- package/lib/modules/network.js +81 -10
- package/lib/modules/selection.d.ts +7 -0
- package/lib/modules/selection.js +35 -0
- package/lib/modules/timing.js +3 -1
- package/lib/utils.d.ts +2 -0
- package/lib/utils.js +17 -0
- package/package.json +1 -1
package/cjs/modules/mouse.d.ts
CHANGED
|
@@ -1,2 +1,24 @@
|
|
|
1
1
|
import type App from '../app/index.js';
|
|
2
|
-
export
|
|
2
|
+
export interface MouseHandlerOptions {
|
|
3
|
+
disableClickmaps?: boolean;
|
|
4
|
+
/** minimum length of an optimised selector.
|
|
5
|
+
*
|
|
6
|
+
* body > div > div > p => body > p for example
|
|
7
|
+
*
|
|
8
|
+
* default 2
|
|
9
|
+
* */
|
|
10
|
+
minSelectorDepth?: number;
|
|
11
|
+
/** how many selectors to try before falling back to nth-child selectors
|
|
12
|
+
* performance expensive operation
|
|
13
|
+
*
|
|
14
|
+
* default 1000
|
|
15
|
+
* */
|
|
16
|
+
nthThreshold?: number;
|
|
17
|
+
/**
|
|
18
|
+
* how many tries to optimise and shorten the selector
|
|
19
|
+
*
|
|
20
|
+
* default 10_000
|
|
21
|
+
* */
|
|
22
|
+
maxOptimiseTries?: number;
|
|
23
|
+
}
|
|
24
|
+
export default function (app: App, options?: MouseHandlerOptions): void;
|
package/cjs/modules/mouse.js
CHANGED
|
@@ -5,13 +5,13 @@ const utils_js_1 = require("../utils.js");
|
|
|
5
5
|
const messages_gen_js_1 = require("../app/messages.gen.js");
|
|
6
6
|
const input_js_1 = require("./input.js");
|
|
7
7
|
const finder_1 = require("@medv/finder");
|
|
8
|
-
function _getSelector(target, document) {
|
|
8
|
+
function _getSelector(target, document, options) {
|
|
9
9
|
const selector = (0, finder_1.finder)(target, {
|
|
10
10
|
root: document.body,
|
|
11
11
|
seedMinLength: 3,
|
|
12
|
-
optimizedMinLength: 2,
|
|
13
|
-
threshold: 1000,
|
|
14
|
-
maxNumberOfTries: 10000,
|
|
12
|
+
optimizedMinLength: (options === null || options === void 0 ? void 0 : options.minSelectorDepth) || 2,
|
|
13
|
+
threshold: (options === null || options === void 0 ? void 0 : options.nthThreshold) || 1000,
|
|
14
|
+
maxNumberOfTries: (options === null || options === void 0 ? void 0 : options.maxOptimiseTries) || 10000,
|
|
15
15
|
});
|
|
16
16
|
return selector;
|
|
17
17
|
}
|
|
@@ -26,7 +26,7 @@ function isClickable(element) {
|
|
|
26
26
|
element.onclick != null ||
|
|
27
27
|
element.getAttribute('role') === 'button');
|
|
28
28
|
//|| element.className.includes("btn")
|
|
29
|
-
// MBTODO:
|
|
29
|
+
// MBTODO: intercept addEventListener
|
|
30
30
|
}
|
|
31
31
|
//TODO: fix (typescript is not sure about target variable after assignation of svg)
|
|
32
32
|
function getTarget(target, document) {
|
|
@@ -66,7 +66,8 @@ function _getTarget(target, document) {
|
|
|
66
66
|
}
|
|
67
67
|
return target === document.documentElement ? null : target;
|
|
68
68
|
}
|
|
69
|
-
function default_1(app) {
|
|
69
|
+
function default_1(app, options) {
|
|
70
|
+
const { disableClickmaps = false } = options || {};
|
|
70
71
|
function getTargetLabel(target) {
|
|
71
72
|
const dl = (0, utils_js_1.getLabelAttribute)(target);
|
|
72
73
|
if (dl !== null) {
|
|
@@ -91,12 +92,39 @@ function default_1(app) {
|
|
|
91
92
|
let mouseTarget = null;
|
|
92
93
|
let mouseTargetTime = 0;
|
|
93
94
|
let selectorMap = {};
|
|
95
|
+
let velocity = 0;
|
|
96
|
+
let direction = 0;
|
|
97
|
+
let directionChangeCount = 0;
|
|
98
|
+
let distance = 0;
|
|
99
|
+
let checkIntervalId;
|
|
100
|
+
const shakeThreshold = 0.008;
|
|
101
|
+
const shakeCheckInterval = 225;
|
|
102
|
+
function checkMouseShaking() {
|
|
103
|
+
const nextVelocity = distance / shakeCheckInterval;
|
|
104
|
+
if (!velocity) {
|
|
105
|
+
velocity = nextVelocity;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const acceleration = (nextVelocity - velocity) / shakeCheckInterval;
|
|
109
|
+
if (directionChangeCount > 4 && acceleration > shakeThreshold) {
|
|
110
|
+
app.send((0, messages_gen_js_1.MouseThrashing)((0, utils_js_1.now)()));
|
|
111
|
+
}
|
|
112
|
+
distance = 0;
|
|
113
|
+
directionChangeCount = 0;
|
|
114
|
+
velocity = nextVelocity;
|
|
115
|
+
}
|
|
116
|
+
app.attachStartCallback(() => {
|
|
117
|
+
checkIntervalId = setInterval(() => checkMouseShaking(), shakeCheckInterval);
|
|
118
|
+
});
|
|
94
119
|
app.attachStopCallback(() => {
|
|
95
120
|
mousePositionX = -1;
|
|
96
121
|
mousePositionY = -1;
|
|
97
122
|
mousePositionChanged = false;
|
|
98
123
|
mouseTarget = null;
|
|
99
124
|
selectorMap = {};
|
|
125
|
+
if (checkIntervalId) {
|
|
126
|
+
clearInterval(checkIntervalId);
|
|
127
|
+
}
|
|
100
128
|
});
|
|
101
129
|
const sendMouseMove = () => {
|
|
102
130
|
if (mousePositionChanged) {
|
|
@@ -105,8 +133,8 @@ function default_1(app) {
|
|
|
105
133
|
}
|
|
106
134
|
};
|
|
107
135
|
const patchDocument = (document, topframe = false) => {
|
|
108
|
-
function getSelector(id, target) {
|
|
109
|
-
return (selectorMap[id] = selectorMap[id] || _getSelector(target, document));
|
|
136
|
+
function getSelector(id, target, options) {
|
|
137
|
+
return (selectorMap[id] = selectorMap[id] || _getSelector(target, document, options));
|
|
110
138
|
}
|
|
111
139
|
const attachListener = topframe
|
|
112
140
|
? app.attachEventListener.bind(app) // attached/removed on start/stop
|
|
@@ -123,6 +151,12 @@ function default_1(app) {
|
|
|
123
151
|
mousePositionX = e.clientX + left;
|
|
124
152
|
mousePositionY = e.clientY + top;
|
|
125
153
|
mousePositionChanged = true;
|
|
154
|
+
const nextDirection = Math.sign(e.movementX);
|
|
155
|
+
distance += Math.abs(e.movementX) + Math.abs(e.movementY);
|
|
156
|
+
if (nextDirection !== direction) {
|
|
157
|
+
direction = nextDirection;
|
|
158
|
+
directionChangeCount++;
|
|
159
|
+
}
|
|
126
160
|
}, false);
|
|
127
161
|
attachListener(document, 'click', (e) => {
|
|
128
162
|
const target = getTarget(e.target, document);
|
|
@@ -132,7 +166,7 @@ function default_1(app) {
|
|
|
132
166
|
const id = app.nodes.getID(target);
|
|
133
167
|
if (id !== undefined) {
|
|
134
168
|
sendMouseMove();
|
|
135
|
-
app.send((0, messages_gen_js_1.MouseClick)(id, mouseTarget === target ? Math.round(performance.now() - mouseTargetTime) : 0, getTargetLabel(target), isClickable(target) ? getSelector(id, target) : ''), true);
|
|
169
|
+
app.send((0, messages_gen_js_1.MouseClick)(id, mouseTarget === target ? Math.round(performance.now() - mouseTargetTime) : 0, getTargetLabel(target), isClickable(target) && !disableClickmaps ? getSelector(id, target, options) : ''), true);
|
|
136
170
|
}
|
|
137
171
|
mouseTarget = null;
|
|
138
172
|
});
|
package/cjs/modules/network.d.ts
CHANGED
|
@@ -24,5 +24,5 @@ export interface Options {
|
|
|
24
24
|
capturePayload: boolean;
|
|
25
25
|
sanitizer?: Sanitizer;
|
|
26
26
|
}
|
|
27
|
-
export default function (app: App, opts?: Partial<Options>): void;
|
|
27
|
+
export default function (app: App, opts?: Partial<Options>, customEnv?: Record<string, any>): void;
|
|
28
28
|
export {};
|
package/cjs/modules/network.js
CHANGED
|
@@ -2,6 +2,43 @@
|
|
|
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
|
+
// Request:
|
|
6
|
+
// declare const enum BodyType {
|
|
7
|
+
// Blob = "Blob",
|
|
8
|
+
// ArrayBuffer = "ArrayBuffer",
|
|
9
|
+
// TypedArray = "TypedArray",
|
|
10
|
+
// DataView = "DataView",
|
|
11
|
+
// FormData = "FormData",
|
|
12
|
+
// URLSearchParams = "URLSearchParams",
|
|
13
|
+
// Document = "Document", // XHR only
|
|
14
|
+
// ReadableStream = "ReadableStream", // Fetch only
|
|
15
|
+
// Literal = "literal",
|
|
16
|
+
// Unknown = "unk",
|
|
17
|
+
// }
|
|
18
|
+
// XHRResponse body: ArrayBuffer, a Blob, a Document, a JavaScript Object, or a string
|
|
19
|
+
// TODO: extract maximum of useful information from any type of Request/Responce bodies
|
|
20
|
+
// function objectifyBody(body: any): RequestBody {
|
|
21
|
+
// if (body instanceof Blob) {
|
|
22
|
+
// return {
|
|
23
|
+
// body: `<Blob type: ${body.type}>; size: ${body.size}`,
|
|
24
|
+
// bodyType: BodyType.Blob,
|
|
25
|
+
// }
|
|
26
|
+
// }
|
|
27
|
+
// return {
|
|
28
|
+
// body,
|
|
29
|
+
// bodyType: BodyType.Literal,
|
|
30
|
+
// }
|
|
31
|
+
// }
|
|
32
|
+
function checkCacheByPerformanceTimings(requestUrl) {
|
|
33
|
+
if (performance) {
|
|
34
|
+
const timings = performance.getEntriesByName(requestUrl)[0];
|
|
35
|
+
if (timings) {
|
|
36
|
+
// @ts-ignore - weird ts typings, please refer to https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming
|
|
37
|
+
return timings.transferSize === 0 || timings.responseStart - timings.requestStart < 10;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
5
42
|
function getXHRRequestDataObject(xhr) {
|
|
6
43
|
// @ts-ignore this is 3x faster than using Map<XHR, XHRRequestData>
|
|
7
44
|
if (!xhr.__or_req_data__) {
|
|
@@ -14,7 +51,7 @@ function getXHRRequestDataObject(xhr) {
|
|
|
14
51
|
function strMethod(method) {
|
|
15
52
|
return typeof method === 'string' ? method.toUpperCase() : 'GET';
|
|
16
53
|
}
|
|
17
|
-
function default_1(app, opts = {}) {
|
|
54
|
+
function default_1(app, opts = {}, customEnv) {
|
|
18
55
|
const options = Object.assign({
|
|
19
56
|
failuresOnly: false,
|
|
20
57
|
ignoreHeaders: ['Cookie', 'Set-Cookie', 'Authorization'],
|
|
@@ -65,8 +102,10 @@ function default_1(app, opts = {}) {
|
|
|
65
102
|
return JSON.stringify(r);
|
|
66
103
|
}
|
|
67
104
|
/* ====== Fetch ====== */
|
|
68
|
-
const origFetch =
|
|
69
|
-
|
|
105
|
+
const origFetch = customEnv
|
|
106
|
+
? customEnv.fetch.bind(customEnv)
|
|
107
|
+
: window.fetch.bind(window);
|
|
108
|
+
const trackFetch = (input, init = {}) => {
|
|
70
109
|
if (!(typeof input === 'string' || input instanceof URL) || app.isServiceURL(String(input))) {
|
|
71
110
|
return origFetch(input, init);
|
|
72
111
|
}
|
|
@@ -140,10 +179,19 @@ function default_1(app, opts = {}) {
|
|
|
140
179
|
return response;
|
|
141
180
|
});
|
|
142
181
|
};
|
|
182
|
+
if (customEnv) {
|
|
183
|
+
customEnv.fetch = trackFetch;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
window.fetch = trackFetch;
|
|
187
|
+
}
|
|
143
188
|
/* ====== <> ====== */
|
|
144
189
|
/* ====== XHR ====== */
|
|
145
|
-
const nativeOpen =
|
|
146
|
-
|
|
190
|
+
const nativeOpen = customEnv
|
|
191
|
+
? customEnv.XMLHttpRequest.prototype.open
|
|
192
|
+
: XMLHttpRequest.prototype.open;
|
|
193
|
+
function trackXMLHttpReqOpen(initMethod, url) {
|
|
194
|
+
// @ts-ignore ??? this -> XMLHttpRequest
|
|
147
195
|
const xhr = this;
|
|
148
196
|
setSessionTokenHeader((name, value) => xhr.setRequestHeader(name, value));
|
|
149
197
|
let startTime = 0;
|
|
@@ -182,22 +230,45 @@ function default_1(app, opts = {}) {
|
|
|
182
230
|
}));
|
|
183
231
|
//TODO: handle error (though it has no Error API nor any useful information)
|
|
184
232
|
//xhr.addEventListener('error', (e) => {})
|
|
233
|
+
// @ts-ignore ??? this -> XMLHttpRequest
|
|
185
234
|
return nativeOpen.apply(this, arguments);
|
|
186
|
-
}
|
|
235
|
+
}
|
|
236
|
+
if (customEnv) {
|
|
237
|
+
customEnv.XMLHttpRequest.prototype.open = trackXMLHttpReqOpen.bind(customEnv);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
XMLHttpRequest.prototype.open = trackXMLHttpReqOpen;
|
|
241
|
+
}
|
|
187
242
|
const nativeSend = XMLHttpRequest.prototype.send;
|
|
188
|
-
|
|
243
|
+
function trackXHRSend(body) {
|
|
244
|
+
// @ts-ignore ??? this -> XMLHttpRequest
|
|
189
245
|
const rdo = getXHRRequestDataObject(this);
|
|
190
246
|
rdo.body = body;
|
|
247
|
+
// @ts-ignore ??? this -> XMLHttpRequest
|
|
191
248
|
return nativeSend.apply(this, arguments);
|
|
192
|
-
}
|
|
249
|
+
}
|
|
250
|
+
if (customEnv) {
|
|
251
|
+
customEnv.XMLHttpRequest.prototype.send = trackXHRSend.bind(customEnv);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
XMLHttpRequest.prototype.send = trackXHRSend;
|
|
255
|
+
}
|
|
193
256
|
const nativeSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
194
|
-
|
|
257
|
+
function trackSetReqHeader(name, value) {
|
|
195
258
|
if (!isHIgnored(name)) {
|
|
259
|
+
// @ts-ignore ??? this -> XMLHttpRequest
|
|
196
260
|
const rdo = getXHRRequestDataObject(this);
|
|
197
261
|
rdo.headers[name] = value;
|
|
198
262
|
}
|
|
263
|
+
// @ts-ignore ??? this -> XMLHttpRequest
|
|
199
264
|
return nativeSetRequestHeader.apply(this, arguments);
|
|
200
|
-
}
|
|
265
|
+
}
|
|
266
|
+
if (customEnv) {
|
|
267
|
+
customEnv.XMLHttpRequest.prototype.setRequestHeader = trackSetReqHeader.bind(customEnv);
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
XMLHttpRequest.prototype.setRequestHeader = trackSetReqHeader;
|
|
271
|
+
}
|
|
201
272
|
/* ====== <> ====== */
|
|
202
273
|
}
|
|
203
274
|
exports.default = default_1;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type App from '../app/index.js';
|
|
2
|
+
declare function selection(app: App): void;
|
|
3
|
+
export default selection;
|
|
4
|
+
/** TODO: research how to get all in-between nodes inside selection range
|
|
5
|
+
* including nodes between anchor and focus nodes and their children
|
|
6
|
+
* without recursively searching the dom tree
|
|
7
|
+
*/
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const messages_gen_js_1 = require("../app/messages.gen.js");
|
|
4
|
+
function selection(app) {
|
|
5
|
+
app.attachEventListener(document, 'selectionchange', () => {
|
|
6
|
+
const selection = document.getSelection();
|
|
7
|
+
if (selection !== null && !selection.isCollapsed) {
|
|
8
|
+
const selectionStart = app.nodes.getID(selection.anchorNode);
|
|
9
|
+
const selectionEnd = app.nodes.getID(selection.focusNode);
|
|
10
|
+
const selectedText = selection.toString().replace(/\s+/g, ' ');
|
|
11
|
+
if (selectionStart && selectionEnd) {
|
|
12
|
+
app.send((0, messages_gen_js_1.SelectionChange)(selectionStart, selectionEnd, selectedText));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
app.send((0, messages_gen_js_1.SelectionChange)(-1, -1, ''));
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
exports.default = selection;
|
|
21
|
+
/** TODO: research how to get all in-between nodes inside selection range
|
|
22
|
+
* including nodes between anchor and focus nodes and their children
|
|
23
|
+
* without recursively searching the dom tree
|
|
24
|
+
*/
|
|
25
|
+
// if (selection.rangeCount) {
|
|
26
|
+
// const nodes = [];
|
|
27
|
+
// for (let i = 0; i < selection.rangeCount; i++) {
|
|
28
|
+
// const range = selection.getRangeAt(i);
|
|
29
|
+
// let node: Node | null = range.startContainer;
|
|
30
|
+
// while (node) {
|
|
31
|
+
// nodes.push(node);
|
|
32
|
+
// if (node === range.endContainer) break;
|
|
33
|
+
// node = node.nextSibling;
|
|
34
|
+
// }
|
|
35
|
+
// }
|
|
36
|
+
// // send selected nodes
|
|
37
|
+
// }
|
package/cjs/modules/timing.js
CHANGED
|
@@ -75,7 +75,9 @@ function default_1(app, opts) {
|
|
|
75
75
|
if (resources !== null) {
|
|
76
76
|
resources[entry.name] = entry.startTime + entry.duration;
|
|
77
77
|
}
|
|
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
|
|
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, entry.transferSize,
|
|
79
|
+
// @ts-ignore
|
|
80
|
+
(entry.responseStatus && entry.responseStatus === 304) || entry.transferSize === 0));
|
|
79
81
|
}
|
|
80
82
|
const observer = new PerformanceObserver((list) => list.getEntries().forEach(resourceTiming));
|
|
81
83
|
let prevSessionID;
|
package/cjs/utils.d.ts
CHANGED
|
@@ -11,3 +11,5 @@ export declare const DOCS_HOST = "https://docs.openreplay.com";
|
|
|
11
11
|
export declare function deprecationWarn(nameOfFeature: string, useInstead: string, docsPath?: string): void;
|
|
12
12
|
export declare function getLabelAttribute(e: Element): string | null;
|
|
13
13
|
export declare function hasOpenreplayAttribute(e: Element, attr: string): boolean;
|
|
14
|
+
export declare function isIframeCrossdomain(e: HTMLIFrameElement): boolean;
|
|
15
|
+
export declare function canAccessIframe(iframe: HTMLIFrameElement): boolean;
|
package/cjs/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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.getTimeOrigin = exports.adjustTimeOrigin = exports.MAX_STR_LEN = exports.IS_FIREFOX = exports.IN_BROWSER = void 0;
|
|
3
|
+
exports.canAccessIframe = exports.isIframeCrossdomain = 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);
|
|
@@ -69,3 +69,22 @@ function hasOpenreplayAttribute(e, attr) {
|
|
|
69
69
|
return false;
|
|
70
70
|
}
|
|
71
71
|
exports.hasOpenreplayAttribute = hasOpenreplayAttribute;
|
|
72
|
+
function isIframeCrossdomain(e) {
|
|
73
|
+
var _a;
|
|
74
|
+
try {
|
|
75
|
+
return ((_a = e.contentWindow) === null || _a === void 0 ? void 0 : _a.location.href) !== window.location.href;
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.isIframeCrossdomain = isIframeCrossdomain;
|
|
82
|
+
function canAccessIframe(iframe) {
|
|
83
|
+
try {
|
|
84
|
+
return Boolean(iframe.contentDocument);
|
|
85
|
+
}
|
|
86
|
+
catch (e) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.canAccessIframe = canAccessIframe;
|
package/lib/app/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { Options as ObserverOptions } from './observer/top_observer.js';
|
|
|
9
9
|
import type { Options as SanitizerOptions } from './sanitizer.js';
|
|
10
10
|
import type { Options as LoggerOptions } from './logger.js';
|
|
11
11
|
import type { Options as SessOptions } from './session.js';
|
|
12
|
+
import type { Options as NetworkOptions } from '../modules/network.js';
|
|
12
13
|
import type { Options as WebworkerOptions } from '../common/interaction.js';
|
|
13
14
|
export interface StartOptions {
|
|
14
15
|
userID?: string;
|
|
@@ -50,6 +51,7 @@ type AppOptions = {
|
|
|
50
51
|
localStorage: Storage | null;
|
|
51
52
|
sessionStorage: Storage | null;
|
|
52
53
|
onStart?: StartCallback;
|
|
54
|
+
network?: NetworkOptions;
|
|
53
55
|
} & WebworkerOptions & SessOptions;
|
|
54
56
|
export type Options = AppOptions & ObserverOptions & SanitizerOptions;
|
|
55
57
|
export declare const DEFAULT_INGEST_POINT = "https://api.openreplay.com/ingest";
|
|
@@ -69,6 +71,7 @@ export default class App {
|
|
|
69
71
|
private readonly stopCallbacks;
|
|
70
72
|
private readonly commitCallbacks;
|
|
71
73
|
private readonly options;
|
|
74
|
+
readonly networkOptions?: NetworkOptions;
|
|
72
75
|
private readonly revID;
|
|
73
76
|
private activityState;
|
|
74
77
|
private readonly version;
|
package/lib/app/index.js
CHANGED
|
@@ -30,10 +30,11 @@ export default class App {
|
|
|
30
30
|
this.stopCallbacks = [];
|
|
31
31
|
this.commitCallbacks = [];
|
|
32
32
|
this.activityState = ActivityState.NotActive;
|
|
33
|
-
this.version = '
|
|
33
|
+
this.version = '6.0.1-beta.1'; // TODO: version compatability check inside each plugin.
|
|
34
34
|
this._usingOldFetchPlugin = false;
|
|
35
35
|
this.delay = 0;
|
|
36
36
|
this.projectKey = projectKey;
|
|
37
|
+
this.networkOptions = options.network;
|
|
37
38
|
this.options = Object.assign({
|
|
38
39
|
revID: '',
|
|
39
40
|
node_id: '__openreplay_id',
|
|
@@ -69,12 +70,12 @@ export default class App {
|
|
|
69
70
|
Object.entries(metadata).forEach(([key, value]) => this.send(Metadata(key, value)));
|
|
70
71
|
}
|
|
71
72
|
});
|
|
72
|
-
// @
|
|
73
|
+
// @deprecated (use sessionHash on start instead)
|
|
73
74
|
if (sessionToken != null) {
|
|
74
75
|
this.session.applySessionHash(sessionToken);
|
|
75
76
|
}
|
|
76
77
|
try {
|
|
77
|
-
this.worker = new Worker(URL.createObjectURL(new Blob(['"use strict";class t{constructor(t,i,s,e=10,n=1e3){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.ingestURL=t+"/v1/web/i"}authorise(t){this.token=t,this.busy||this.sendNext()}push(t){this.busy||!this.token?this.queue.push(t):this.sendBatch(t)}sendNext(){const t=this.queue.shift();t?this.sendBatch(t):this.busy=!1}retry(t){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout(()=>this.sendBatch(t),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t){this.busy=!0,fetch(this.ingestURL,{body:t,method:"POST",headers:{Authorization:"Bearer "+this.token},keepalive:t.length<65536}).then(i=>{if(401===i.status)return this.busy=!1,void this.onUnauthorised();i.status>=400?this.retry(t):(this.attemptsCount=0,this.sendNext())}).catch(i=>{console.warn("OpenReplay:",i),this.retry(t)})}clean(){this.queue.length=0,this.token=null}}const i="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(let n=0,
|
|
78
|
+
this.worker = new Worker(URL.createObjectURL(new Blob(['"use strict";class t{constructor(t,i,s,e=10,n=1e3){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.ingestURL=t+"/v1/web/i"}authorise(t){this.token=t,this.busy||this.sendNext()}push(t){this.busy||!this.token?this.queue.push(t):this.sendBatch(t)}sendNext(){const t=this.queue.shift();t?this.sendBatch(t):this.busy=!1}retry(t){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`):(this.attemptsCount++,setTimeout(()=>this.sendBatch(t),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t){this.busy=!0,fetch(this.ingestURL,{body:t,method:"POST",headers:{Authorization:"Bearer "+this.token},keepalive:t.length<65536}).then(i=>{if(401===i.status)return this.busy=!1,void this.onUnauthorised();i.status>=400?this.retry(t):(this.attemptsCount=0,this.sendNext())}).catch(i=>{console.warn("OpenReplay:",i),this.retry(t)})}clean(){this.queue.length=0,this.token=null}}const i="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(let n=0,h=0,r=0;r!==i;){if(n=t.charCodeAt(r),r+=1,n>=55296&&n<=56319){if(r===i){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;break}if(h=t.charCodeAt(r),!(h>=56320&&h<=57343)){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;continue}if(n=1024*(n-55296)+h-56320+65536,r+=1,n>65535){s[e+=1]=240|n>>>18,s[e+=1]=128|n>>>12&63,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n;continue}}n<=127?s[e+=1]=0|n:n<=2047?(s[e+=1]=192|n>>>6,s[e+=1]=128|63&n):(s[e+=1]=224|n>>>12,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n)}return s.subarray(0,e+1)}};class s extends class{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}getCurrentOffset(){return this.offset}checkpoint(){this.checkpointOffset=this.offset}get isEmpty(){return 0===this.offset}skip(t){return this.offset+=t,this.offset<=this.size}set(t,i){this.data.set(t,i)}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(t){const s=i.encode(t),e=s.byteLength;return!(!this.uint(e)||this.offset+e>this.size)&&(this.data.set(s,this.offset),this.offset+=e,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}{encode(t){switch(t[0]){case 0:return this.uint(t[1]);case 4:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 5:return this.uint(t[1])&&this.uint(t[2]);case 6:return this.int(t[1])&&this.int(t[2]);case 7:return!0;case 8:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.string(t[4])&&this.boolean(t[5]);case 9:case 10:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 11:return this.uint(t[1]);case 12:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 13:case 14:return this.uint(t[1])&&this.string(t[2]);case 16:return this.uint(t[1])&&this.int(t[2])&&this.int(t[3]);case 17:return this.uint(t[1])&&this.string(t[2]);case 18:return this.uint(t[1])&&this.string(t[2])&&this.int(t[3]);case 19:return this.uint(t[1])&&this.boolean(t[2]);case 20:return this.uint(t[1])&&this.uint(t[2]);case 21:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.string(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8]);case 22:return this.string(t[1])&&this.string(t[2]);case 23:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7])&&this.uint(t[8])&&this.uint(t[9]);case 24:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 27:return this.string(t[1])&&this.string(t[2]);case 28:case 29:return this.string(t[1]);case 30:return this.string(t[1])&&this.string(t[2]);case 37:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3]);case 38:return this.uint(t[1])&&this.uint(t[2]);case 39:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.uint(t[7]);case 40:return this.string(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 41:return this.string(t[1])&&this.string(t[2]);case 42:return this.string(t[1]);case 44:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 45:case 46:return this.string(t[1])&&this.string(t[2]);case 47:return this.string(t[1])&&this.string(t[2])&&this.uint(t[3]);case 48:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 49:return this.int(t[1])&&this.int(t[2])&&this.uint(t[3])&&this.uint(t[4]);case 50:return this.uint(t[1])&&this.string(t[2]);case 51:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3]);case 53:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8]);case 54:return this.uint(t[1])&&this.string(t[2]);case 55:return this.boolean(t[1]);case 57:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 58:return this.int(t[1]);case 59:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.string(t[5])&&this.string(t[6])&&this.string(t[7]);case 60:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 61:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 63:case 64:return this.string(t[1])&&this.string(t[2]);case 67:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 69:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3])&&this.string(t[4]);case 70:return this.uint(t[1])&&this.uint(t[2]);case 71:return this.uint(t[1])&&this.string(t[2])&&this.string(t[3]);case 73:return this.uint(t[1])&&this.string(t[2])&&this.uint(t[3])&&this.string(t[4]);case 75:case 76:case 77:return this.uint(t[1])&&this.uint(t[2]);case 78:return this.string(t[1])&&this.string(t[2])&&this.string(t[3])&&this.string(t[4]);case 79:return this.string(t[1])&&this.string(t[2]);case 81:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.int(t[4])&&this.string(t[5]);case 82:return this.uint(t[1])&&this.uint(t[2]);case 112:return this.uint(t[1])&&this.string(t[2])&&this.boolean(t[3])&&this.string(t[4])&&this.int(t[5])&&this.int(t[6]);case 113:return this.uint(t[1])&&this.uint(t[2])&&this.string(t[3]);case 114:case 115:return this.uint(t[1]);case 116:return this.uint(t[1])&&this.uint(t[2])&&this.uint(t[3])&&this.uint(t[4])&&this.uint(t[5])&&this.uint(t[6])&&this.string(t[7])&&this.string(t[8])&&this.uint(t[9])&&this.boolean(t[10])}}}class e{constructor(){this.idx=1,this.backDict={}}getKey(t){let i=!1;return this.backDict[t]||(i=!0,this.backDict[t]=this.idx++),[this.backDict[t],i]}}class n{constructor(t,i,n,h){this.pageNo=t,this.timestamp=i,this.url=n,this.onBatch=h,this.nextIndex=0,this.beaconSize=2e5,this.encoder=new s(this.beaconSize),this.strDict=new e,this.sizeBuffer=new Uint8Array(3),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepare()}writeType(t){return this.encoder.uint(t[0])}writeFields(t){return this.encoder.encode(t)}writeSizeAt(t,i){for(let i=0;i<3;i++)this.sizeBuffer[i]=t>>8*i;this.encoder.set(this.sizeBuffer,i)}prepare(){if(!this.encoder.isEmpty)return;const t=[81,1,this.pageNo,this.nextIndex,this.timestamp,this.url];this.writeType(t),this.writeFields(t),this.isEmpty=!0}writeWithSize(t){const i=this.encoder;if(!this.writeType(t)||!i.skip(3))return!1;const s=i.getCurrentOffset(),e=this.writeFields(t);if(e){const e=i.getCurrentOffset()-s;if(e>16777215)return console.warn("OpenReplay: max message size overflow."),!1;this.writeSizeAt(e,s-3),i.checkpoint(),this.isEmpty=this.isEmpty&&0===t[0],this.nextIndex++}return e}setBeaconSizeLimit(t){this.beaconSizeLimit=t}applyDict(t){const[i,s]=this.strDict.getKey(t);return s&&this.writeMessage([50,i,t]),i}writeMessage(t){0===t[0]&&(this.timestamp=t[1]),4===t[0]&&(this.url=t[1]),12===t[0]&&(t=[51,t[1],this.applyDict(t[2]),this.applyDict(t[3])]),this.writeWithSize(t)||(this.finaliseBatch(),this.writeWithSize(t)||(this.encoder=new s(this.beaconSizeLimit),this.prepare(),this.writeWithSize(t)?this.finaliseBatch():console.warn("OpenReplay: beacon size overflow. Skipping large message.",t,this),this.encoder=new s(this.beaconSize),this.prepare()))}finaliseBatch(){this.isEmpty||(this.onBatch(this.encoder.flush()),this.prepare())}clean(){this.encoder.reset()}}var h;!function(t){t[t.NotActive=0]="NotActive",t[t.Starting=1]="Starting",t[t.Stopping=2]="Stopping",t[t.Active=3]="Active"}(h||(h={}));let r=null,u=null;function a(){u&&u.finaliseBatch()}function c(){h.Stopping,null!==l&&(clearInterval(l),l=null),u&&(u.clean(),u=null),r&&(r.clean(),r=null),h.NotActive}function o(){postMessage("restart"),c()}h.NotActive;let g,l=null;self.onmessage=({data:i})=>{if(null!=i){if("stop"===i)return a(),void c();if(!Array.isArray(i))return"start"===i.type?(h.Starting,r=new t(i.ingestPoint,()=>{o()},t=>{!function(t){postMessage({type:"failure",reason:t}),c()}(t)},i.connAttemptCount,i.connAttemptGap),u=new n(i.pageNo,i.timestamp,i.url,t=>r&&r.push(t)),null===l&&(l=setInterval(a,1e4)),h.Active):"auth"===i.type?r?u?(r.authorise(i.token),void(i.beaconSizeLimit&&u.setBeaconSizeLimit(i.beaconSizeLimit))):(console.debug("WebWorker: writer not initialised. Received auth."),void o()):(console.debug("WebWorker: sender not initialised. Received auth."),void o()):void 0;if(null!==u){const t=u;i.forEach(i=>{55===i[0]&&(i[1]?g=setTimeout(()=>o(),18e5):clearTimeout(g)),t.writeMessage(i)})}u||(postMessage("not_init"),o())}else a()};'], { type: 'text/javascript' })));
|
|
78
79
|
this.worker.onerror = (e) => {
|
|
79
80
|
this._debug('webworker_error', e);
|
|
80
81
|
};
|
|
@@ -39,7 +39,7 @@ export declare function GraphQL(operationKind: string, operationName: string, va
|
|
|
39
39
|
export declare function PerformanceTrack(frames: number, ticks: number, totalJSHeapSize: number, usedJSHeapSize: number): Messages.PerformanceTrack;
|
|
40
40
|
export declare function StringDict(key: number, value: string): Messages.StringDict;
|
|
41
41
|
export declare function SetNodeAttributeDict(id: number, nameKey: number, valueKey: number): Messages.SetNodeAttributeDict;
|
|
42
|
-
export declare function
|
|
42
|
+
export declare function ResourceTimingDeprecated(timestamp: number, duration: number, ttfb: number, headerSize: number, encodedBodySize: number, decodedBodySize: number, url: string, initiator: string): Messages.ResourceTimingDeprecated;
|
|
43
43
|
export declare function ConnectionInformation(downlink: number, type: string): Messages.ConnectionInformation;
|
|
44
44
|
export declare function SetPageVisibility(hidden: boolean): Messages.SetPageVisibility;
|
|
45
45
|
export declare function LoadFontFace(parentID: number, family: string, source: string, descriptors: string): Messages.LoadFontFace;
|
|
@@ -61,3 +61,8 @@ export declare function JSException(name: string, message: string, payload: stri
|
|
|
61
61
|
export declare function Zustand(mutation: string, state: string): Messages.Zustand;
|
|
62
62
|
export declare function BatchMetadata(version: number, pageNo: number, firstIndex: number, timestamp: number, location: string): Messages.BatchMetadata;
|
|
63
63
|
export declare function PartitionedMessage(partNo: number, partTotal: number): Messages.PartitionedMessage;
|
|
64
|
+
export declare function InputChange(id: number, value: string, valueMasked: boolean, label: string, hesitationTime: number, inputDuration: number): Messages.InputChange;
|
|
65
|
+
export declare function SelectionChange(selectionStart: number, selectionEnd: number, selection: string): Messages.SelectionChange;
|
|
66
|
+
export declare function MouseThrashing(timestamp: number): Messages.MouseThrashing;
|
|
67
|
+
export declare function UnbindNodes(totalRemovedPercent: number): Messages.UnbindNodes;
|
|
68
|
+
export declare function ResourceTiming(timestamp: number, duration: number, ttfb: number, headerSize: number, encodedBodySize: number, decodedBodySize: number, url: string, initiator: string, transferredSize: number, cached: boolean): Messages.ResourceTiming;
|
package/lib/app/messages.gen.js
CHANGED
|
@@ -304,9 +304,9 @@ export function SetNodeAttributeDict(id, nameKey, valueKey) {
|
|
|
304
304
|
valueKey,
|
|
305
305
|
];
|
|
306
306
|
}
|
|
307
|
-
export function
|
|
307
|
+
export function ResourceTimingDeprecated(timestamp, duration, ttfb, headerSize, encodedBodySize, decodedBodySize, url, initiator) {
|
|
308
308
|
return [
|
|
309
|
-
53 /* Messages.Type.
|
|
309
|
+
53 /* Messages.Type.ResourceTimingDeprecated */,
|
|
310
310
|
timestamp,
|
|
311
311
|
duration,
|
|
312
312
|
ttfb,
|
|
@@ -484,3 +484,49 @@ export function PartitionedMessage(partNo, partTotal) {
|
|
|
484
484
|
partTotal,
|
|
485
485
|
];
|
|
486
486
|
}
|
|
487
|
+
export function InputChange(id, value, valueMasked, label, hesitationTime, inputDuration) {
|
|
488
|
+
return [
|
|
489
|
+
112 /* Messages.Type.InputChange */,
|
|
490
|
+
id,
|
|
491
|
+
value,
|
|
492
|
+
valueMasked,
|
|
493
|
+
label,
|
|
494
|
+
hesitationTime,
|
|
495
|
+
inputDuration,
|
|
496
|
+
];
|
|
497
|
+
}
|
|
498
|
+
export function SelectionChange(selectionStart, selectionEnd, selection) {
|
|
499
|
+
return [
|
|
500
|
+
113 /* Messages.Type.SelectionChange */,
|
|
501
|
+
selectionStart,
|
|
502
|
+
selectionEnd,
|
|
503
|
+
selection,
|
|
504
|
+
];
|
|
505
|
+
}
|
|
506
|
+
export function MouseThrashing(timestamp) {
|
|
507
|
+
return [
|
|
508
|
+
114 /* Messages.Type.MouseThrashing */,
|
|
509
|
+
timestamp,
|
|
510
|
+
];
|
|
511
|
+
}
|
|
512
|
+
export function UnbindNodes(totalRemovedPercent) {
|
|
513
|
+
return [
|
|
514
|
+
115 /* Messages.Type.UnbindNodes */,
|
|
515
|
+
totalRemovedPercent,
|
|
516
|
+
];
|
|
517
|
+
}
|
|
518
|
+
export function ResourceTiming(timestamp, duration, ttfb, headerSize, encodedBodySize, decodedBodySize, url, initiator, transferredSize, cached) {
|
|
519
|
+
return [
|
|
520
|
+
116 /* Messages.Type.ResourceTiming */,
|
|
521
|
+
timestamp,
|
|
522
|
+
duration,
|
|
523
|
+
ttfb,
|
|
524
|
+
headerSize,
|
|
525
|
+
encodedBodySize,
|
|
526
|
+
decodedBodySize,
|
|
527
|
+
url,
|
|
528
|
+
initiator,
|
|
529
|
+
transferredSize,
|
|
530
|
+
cached,
|
|
531
|
+
];
|
|
532
|
+
}
|
package/lib/app/nodes.d.ts
CHANGED
package/lib/app/nodes.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RemoveNodeAttribute, SetNodeAttribute, SetNodeAttributeURLBased, SetCSSDataURLBased, SetNodeData, CreateTextNode, CreateElementNode, MoveNode, RemoveNode, } from '../messages.gen.js';
|
|
1
|
+
import { RemoveNodeAttribute, SetNodeAttribute, SetNodeAttributeURLBased, SetCSSDataURLBased, SetNodeData, CreateTextNode, CreateElementNode, MoveNode, RemoveNode, UnbindNodes, } from '../messages.gen.js';
|
|
2
2
|
import { isRootNode, isTextNode, isElementNode, isSVGElement, hasTag, isCommentNode, } from '../guards.js';
|
|
3
3
|
function isIgnored(node) {
|
|
4
4
|
if (isCommentNode(node)) {
|
|
@@ -191,10 +191,16 @@ export default class Observer {
|
|
|
191
191
|
},
|
|
192
192
|
// @ts-ignore
|
|
193
193
|
false);
|
|
194
|
+
let removed = 0;
|
|
195
|
+
const totalBeforeRemove = this.app.nodes.getNodeCount();
|
|
194
196
|
while (walker.nextNode()) {
|
|
197
|
+
removed += 1;
|
|
195
198
|
this.app.nodes.unregisterNode(walker.currentNode);
|
|
196
199
|
}
|
|
197
|
-
|
|
200
|
+
const removedPercent = Math.floor((removed / totalBeforeRemove) * 100);
|
|
201
|
+
if (removedPercent > 30) {
|
|
202
|
+
this.app.send(UnbindNodes(removedPercent));
|
|
203
|
+
}
|
|
198
204
|
}
|
|
199
205
|
}
|
|
200
206
|
// A top-consumption function on the infinite lists test. (~1% of performance resources)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import Observer from './observer.js';
|
|
2
2
|
import { isElementNode, hasTag } from '../guards.js';
|
|
3
|
+
import Network from '../../modules/network.js';
|
|
3
4
|
import IFrameObserver from './iframe_observer.js';
|
|
4
5
|
import ShadowRootObserver from './shadow_root_observer.js';
|
|
5
6
|
import IFrameOffsets from './iframe_offsets.js';
|
|
6
7
|
import { CreateDocument } from '../messages.gen.js';
|
|
7
|
-
import { IN_BROWSER, hasOpenreplayAttribute } from '../../utils.js';
|
|
8
|
+
import { IN_BROWSER, hasOpenreplayAttribute, canAccessIframe } from '../../utils.js';
|
|
8
9
|
const attachShadowNativeFn = IN_BROWSER ? Element.prototype.attachShadow : () => new ShadowRoot();
|
|
9
10
|
export default class TopObserver extends Observer {
|
|
10
11
|
constructor(app, options) {
|
|
@@ -49,6 +50,8 @@ export default class TopObserver extends Observer {
|
|
|
49
50
|
//log
|
|
50
51
|
return;
|
|
51
52
|
}
|
|
53
|
+
if (!canAccessIframe(iframe))
|
|
54
|
+
return;
|
|
52
55
|
const currentWin = iframe.contentWindow;
|
|
53
56
|
const currentDoc = iframe.contentDocument;
|
|
54
57
|
if (currentDoc && currentDoc !== doc) {
|
|
@@ -65,6 +68,7 @@ export default class TopObserver extends Observer {
|
|
|
65
68
|
//TODO: more explicit logic
|
|
66
69
|
) {
|
|
67
70
|
this.contextsSet.add(currentWin);
|
|
71
|
+
Network(this.app, this.app.networkOptions, currentWin);
|
|
68
72
|
//@ts-ignore https://github.com/microsoft/TypeScript/issues/41684
|
|
69
73
|
this.contextCallbacks.forEach((cb) => cb(currentWin));
|
|
70
74
|
}
|
package/lib/app/ticker.d.ts
CHANGED
|
@@ -5,6 +5,12 @@ export default class Ticker {
|
|
|
5
5
|
private timer;
|
|
6
6
|
private readonly callbacks;
|
|
7
7
|
constructor(app: App);
|
|
8
|
+
/**
|
|
9
|
+
* @param {Callback} callback - repeated cb
|
|
10
|
+
* @param {number} n - number of turn skips; ticker have a 30 ms cycle
|
|
11
|
+
* @param {boolean} useSafe - using safe wrapper to check if app is active
|
|
12
|
+
* @param {object} thisArg - link to <this>
|
|
13
|
+
* */
|
|
8
14
|
attach(callback: Callback, n?: number, useSafe?: boolean, thisArg?: any): void;
|
|
9
15
|
start(): void;
|
|
10
16
|
stop(): void;
|