@openreplay/tracker 7.0.1-beta.2 → 7.0.2-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 +6 -0
- package/cjs/app/index.js +17 -22
- package/cjs/app/observer/iframe_offsets.js +4 -2
- package/cjs/app/observer/observer.js +1 -1
- package/cjs/index.js +1 -1
- package/cjs/modules/axiosSpy.d.ts +53 -0
- package/cjs/modules/axiosSpy.js +102 -0
- package/cjs/modules/constructedStyleSheets.js +2 -5
- package/cjs/modules/input.js +11 -1
- package/cjs/modules/mouse.js +12 -21
- package/cjs/modules/network.d.ts +4 -1
- package/cjs/modules/network.js +21 -9
- package/cjs/utils.js +2 -1
- package/cjs/vendors/finder/finder.js +2 -2
- package/lib/app/index.js +17 -22
- package/lib/app/observer/iframe_offsets.js +4 -2
- package/lib/app/observer/observer.js +1 -1
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.js +1 -1
- package/lib/modules/axiosSpy.d.ts +53 -0
- package/lib/modules/axiosSpy.js +99 -0
- package/lib/modules/constructedStyleSheets.js +2 -5
- package/lib/modules/input.js +11 -1
- package/lib/modules/mouse.js +12 -21
- package/lib/modules/network.d.ts +4 -1
- package/lib/modules/network.js +21 -9
- package/lib/utils.js +2 -1
- package/lib/vendors/finder/finder.js +2 -2
- package/package.json +2 -2
- package/tsconfig-base.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# 7.0.1
|
|
2
|
+
|
|
3
|
+
- fix time inputs capturing
|
|
4
|
+
- add option `{ network: { captureInIframes: boolean } }` to disable network tracking inside iframes (default true)
|
|
5
|
+
- added option `{ network: { axiosInstances: AxiosInstance[] } }` to include custom axios instances for better tracking
|
|
6
|
+
|
|
1
7
|
# 7.0.0
|
|
2
8
|
|
|
3
9
|
- **[breaking]** added gzip compression to large messages
|
package/cjs/app/index.js
CHANGED
|
@@ -14,7 +14,7 @@ const performance_js_1 = require("../modules/performance.js");
|
|
|
14
14
|
const CANCELED = 'canceled';
|
|
15
15
|
const START_ERROR = ':(';
|
|
16
16
|
const UnsuccessfulStart = (reason) => ({ reason, success: false });
|
|
17
|
-
const SuccessfulStart = (body) => ({
|
|
17
|
+
const SuccessfulStart = (body) => (Object.assign(Object.assign({}, body), { success: true }));
|
|
18
18
|
var ActivityState;
|
|
19
19
|
(function (ActivityState) {
|
|
20
20
|
ActivityState[ActivityState["NotActive"] = 0] = "NotActive";
|
|
@@ -28,12 +28,13 @@ class App {
|
|
|
28
28
|
// if (options.onStart !== undefined) {
|
|
29
29
|
// deprecationWarn("'onStart' option", "tracker.start().then(/* handle session info */)")
|
|
30
30
|
// } ?? maybe onStart is good
|
|
31
|
+
var _a, _b;
|
|
31
32
|
this.messages = [];
|
|
32
33
|
this.startCallbacks = [];
|
|
33
34
|
this.stopCallbacks = [];
|
|
34
35
|
this.commitCallbacks = [];
|
|
35
36
|
this.activityState = ActivityState.NotActive;
|
|
36
|
-
this.version = '7.0.
|
|
37
|
+
this.version = '7.0.2-beta.1'; // TODO: version compatability check inside each plugin.
|
|
37
38
|
this.compressionThreshold = 24 * 1000;
|
|
38
39
|
this.restartAttempts = 0;
|
|
39
40
|
this._usingOldFetchPlugin = false;
|
|
@@ -56,8 +57,8 @@ class App {
|
|
|
56
57
|
sessionStorage: null,
|
|
57
58
|
}, options);
|
|
58
59
|
this.revID = this.options.revID;
|
|
59
|
-
this.localStorage = this.options.localStorage
|
|
60
|
-
this.sessionStorage = this.options.sessionStorage
|
|
60
|
+
this.localStorage = (_a = this.options.localStorage) !== null && _a !== void 0 ? _a : window.localStorage;
|
|
61
|
+
this.sessionStorage = (_b = this.options.sessionStorage) !== null && _b !== void 0 ? _b : window.sessionStorage;
|
|
61
62
|
this.sanitizer = new sanitizer_js_1.default(this, options);
|
|
62
63
|
this.nodes = new nodes_js_1.default(this.options.node_id);
|
|
63
64
|
this.observer = new top_observer_js_1.default(this, options);
|
|
@@ -85,6 +86,7 @@ class App {
|
|
|
85
86
|
this._debug('webworker_error', e);
|
|
86
87
|
};
|
|
87
88
|
this.worker.onmessage = ({ data }) => {
|
|
89
|
+
var _a;
|
|
88
90
|
if (data === 'restart') {
|
|
89
91
|
this.stop(false);
|
|
90
92
|
void this.start({}, true);
|
|
@@ -101,6 +103,7 @@ class App {
|
|
|
101
103
|
const batchSize = batch.byteLength;
|
|
102
104
|
if (batchSize > this.compressionThreshold) {
|
|
103
105
|
(0, fflate_1.gzip)(data.batch, { mtime: 0 }, (err, result) => {
|
|
106
|
+
var _a;
|
|
104
107
|
if (err) {
|
|
105
108
|
console.error('Openreplay compression error:', err);
|
|
106
109
|
this.stop(false);
|
|
@@ -110,11 +113,11 @@ class App {
|
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
115
|
// @ts-ignore
|
|
113
|
-
this.worker
|
|
116
|
+
(_a = this.worker) === null || _a === void 0 ? void 0 : _a.postMessage({ type: 'compressed', batch: result });
|
|
114
117
|
});
|
|
115
118
|
}
|
|
116
119
|
else {
|
|
117
|
-
this.worker
|
|
120
|
+
(_a = this.worker) === null || _a === void 0 ? void 0 : _a.postMessage({ type: 'uncompressed', batch: batch });
|
|
118
121
|
}
|
|
119
122
|
}
|
|
120
123
|
};
|
|
@@ -217,8 +220,8 @@ class App {
|
|
|
217
220
|
if (useSafe) {
|
|
218
221
|
listener = this.safe(listener);
|
|
219
222
|
}
|
|
220
|
-
this.attachStartCallback(() => target
|
|
221
|
-
this.attachStopCallback(() => target
|
|
223
|
+
this.attachStartCallback(() => target === null || target === void 0 ? void 0 : target.addEventListener(type, listener, useCapture), useSafe);
|
|
224
|
+
this.attachStopCallback(() => target === null || target === void 0 ? void 0 : target.removeEventListener(type, listener, useCapture), useSafe);
|
|
222
225
|
}
|
|
223
226
|
// TODO: full correct semantic
|
|
224
227
|
checkRequiredVersion(version) {
|
|
@@ -247,10 +250,7 @@ class App {
|
|
|
247
250
|
};
|
|
248
251
|
}
|
|
249
252
|
getSessionInfo() {
|
|
250
|
-
return {
|
|
251
|
-
...this.session.getInfo(),
|
|
252
|
-
...this.getTrackerInfo(),
|
|
253
|
-
};
|
|
253
|
+
return Object.assign(Object.assign({}, this.session.getInfo()), this.getTrackerInfo());
|
|
254
254
|
}
|
|
255
255
|
getSessionToken() {
|
|
256
256
|
return this.session.getSessionToken();
|
|
@@ -268,7 +268,7 @@ class App {
|
|
|
268
268
|
const isSaas = /api\.openreplay\.com/.test(ingest);
|
|
269
269
|
const projectPath = isSaas ? 'https://openreplay.com/ingest' : ingest;
|
|
270
270
|
const url = projectPath.replace(/ingest$/, `${projectID}/session/${sessionID}`);
|
|
271
|
-
if (options
|
|
271
|
+
if (options === null || options === void 0 ? void 0 : options.withCurrentTime) {
|
|
272
272
|
const jumpTo = (0, utils_js_1.now)() - timestamp;
|
|
273
273
|
return `${url}?jumpto=${jumpTo}`;
|
|
274
274
|
}
|
|
@@ -281,6 +281,7 @@ class App {
|
|
|
281
281
|
return this.projectKey;
|
|
282
282
|
}
|
|
283
283
|
getBaseHref() {
|
|
284
|
+
var _a, _b;
|
|
284
285
|
if (typeof this.options.resourceBaseHref === 'string') {
|
|
285
286
|
return this.options.resourceBaseHref;
|
|
286
287
|
}
|
|
@@ -291,7 +292,7 @@ class App {
|
|
|
291
292
|
return document.baseURI;
|
|
292
293
|
}
|
|
293
294
|
// IE only
|
|
294
|
-
return (document.head
|
|
295
|
+
return (((_b = (_a = document.head) === null || _a === void 0 ? void 0 : _a.getElementsByTagName('base')[0]) === null || _b === void 0 ? void 0 : _b.getAttribute('href')) ||
|
|
295
296
|
location.origin + location.pathname);
|
|
296
297
|
}
|
|
297
298
|
resolveResourceURL(resourceURL) {
|
|
@@ -354,14 +355,8 @@ class App {
|
|
|
354
355
|
headers: {
|
|
355
356
|
'Content-Type': 'application/json',
|
|
356
357
|
},
|
|
357
|
-
body: JSON.stringify({
|
|
358
|
-
|
|
359
|
-
timestamp,
|
|
360
|
-
userID: this.session.getInfo().userID,
|
|
361
|
-
token: needNewSessionID ? undefined : this.session.getSessionToken(),
|
|
362
|
-
deviceMemory: performance_js_1.deviceMemory,
|
|
363
|
-
jsHeapSizeLimit: performance_js_1.jsHeapSizeLimit,
|
|
364
|
-
}),
|
|
358
|
+
body: JSON.stringify(Object.assign(Object.assign({}, this.getTrackerInfo()), { timestamp, userID: this.session.getInfo().userID, token: needNewSessionID ? undefined : this.session.getSessionToken(), deviceMemory: performance_js_1.deviceMemory,
|
|
359
|
+
jsHeapSizeLimit: performance_js_1.jsHeapSizeLimit })),
|
|
365
360
|
})
|
|
366
361
|
.then((r) => {
|
|
367
362
|
if (r.status === 200) {
|
|
@@ -26,6 +26,7 @@ class IFrameOffsets {
|
|
|
26
26
|
return this.calcOffset(state);
|
|
27
27
|
}
|
|
28
28
|
observe(iFrame) {
|
|
29
|
+
var _a;
|
|
29
30
|
const doc = iFrame.contentDocument;
|
|
30
31
|
if (!doc) {
|
|
31
32
|
return;
|
|
@@ -37,8 +38,9 @@ class IFrameOffsets {
|
|
|
37
38
|
iFrame,
|
|
38
39
|
parent: parentState || null,
|
|
39
40
|
clear: () => {
|
|
41
|
+
var _a;
|
|
40
42
|
parentDoc.removeEventListener('scroll', invalidateOffset);
|
|
41
|
-
parentDoc.defaultView
|
|
43
|
+
(_a = parentDoc.defaultView) === null || _a === void 0 ? void 0 : _a.removeEventListener('resize', invalidateOffset);
|
|
42
44
|
},
|
|
43
45
|
};
|
|
44
46
|
const invalidateOffset = () => {
|
|
@@ -46,7 +48,7 @@ class IFrameOffsets {
|
|
|
46
48
|
};
|
|
47
49
|
// anything more reliable? This does not cover all cases (layout changes are ignored, for ex.)
|
|
48
50
|
parentDoc.addEventListener('scroll', invalidateOffset);
|
|
49
|
-
parentDoc.defaultView
|
|
51
|
+
(_a = parentDoc.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener('resize', invalidateOffset);
|
|
50
52
|
this.states.set(doc, state);
|
|
51
53
|
}
|
|
52
54
|
clear() {
|
|
@@ -16,7 +16,7 @@ function isIgnored(node) {
|
|
|
16
16
|
if (tag === 'LINK') {
|
|
17
17
|
const rel = node.getAttribute('rel');
|
|
18
18
|
const as = node.getAttribute('as');
|
|
19
|
-
return !(rel
|
|
19
|
+
return !((rel === null || rel === void 0 ? void 0 : rel.includes('stylesheet')) || as === 'style' || as === 'font');
|
|
20
20
|
}
|
|
21
21
|
return (tag === 'SCRIPT' || tag === 'NOSCRIPT' || tag === 'META' || tag === 'TITLE' || tag === 'BASE');
|
|
22
22
|
}
|
package/cjs/index.js
CHANGED
|
@@ -142,7 +142,7 @@ class API {
|
|
|
142
142
|
// no-cors issue only with text/plain or not-set Content-Type
|
|
143
143
|
// req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
144
144
|
req.send(JSON.stringify({
|
|
145
|
-
trackerVersion: '7.0.
|
|
145
|
+
trackerVersion: '7.0.2-beta.1',
|
|
146
146
|
projectKey: options.projectKey,
|
|
147
147
|
doNotTrack,
|
|
148
148
|
// TODO: add precise reason (an exact API missing)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type App from '../app/index.js';
|
|
2
|
+
import type { RequestResponseData, Options } from './network.js';
|
|
3
|
+
interface RawAxiosHeaders {
|
|
4
|
+
[key: string]: string;
|
|
5
|
+
}
|
|
6
|
+
interface AxiosRequestConfig {
|
|
7
|
+
url: string;
|
|
8
|
+
method?: string;
|
|
9
|
+
baseURL?: string;
|
|
10
|
+
status?: number;
|
|
11
|
+
headers: {
|
|
12
|
+
toJSON(): RawAxiosHeaders;
|
|
13
|
+
};
|
|
14
|
+
params?: any;
|
|
15
|
+
data?: any;
|
|
16
|
+
}
|
|
17
|
+
interface InternalAxiosRequestConfig extends AxiosRequestConfig {
|
|
18
|
+
__openreplay_timing: number;
|
|
19
|
+
headers: {
|
|
20
|
+
toJSON(): RawAxiosHeaders;
|
|
21
|
+
set(name: string, value: string): void;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface AxiosResponse<T = any> {
|
|
25
|
+
data: T;
|
|
26
|
+
status: number;
|
|
27
|
+
statusText: string;
|
|
28
|
+
headers: {
|
|
29
|
+
toJSON(): RawAxiosHeaders;
|
|
30
|
+
};
|
|
31
|
+
config: InternalAxiosRequestConfig;
|
|
32
|
+
request?: any;
|
|
33
|
+
response?: AxiosRequestConfig;
|
|
34
|
+
}
|
|
35
|
+
export interface AxiosInstance extends Record<string, any> {
|
|
36
|
+
interceptors: {
|
|
37
|
+
request: AxiosInterceptorManager<InternalAxiosRequestConfig>;
|
|
38
|
+
response: AxiosInterceptorManager<AxiosResponse>;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export interface AxiosInterceptorOptions {
|
|
42
|
+
synchronous?: boolean;
|
|
43
|
+
}
|
|
44
|
+
export interface AxiosInterceptorManager<V> {
|
|
45
|
+
use(onFulfilled?: ((value: V) => V | Promise<V>) | null, onRejected?: ((error: any) => any) | null, options?: AxiosInterceptorOptions): number;
|
|
46
|
+
eject?: (id: number) => void;
|
|
47
|
+
clear?: () => void;
|
|
48
|
+
}
|
|
49
|
+
export default function (app: App, instance: AxiosInstance, opts: Options, sanitize: (data: RequestResponseData) => RequestResponseData | null, stringify: (data: {
|
|
50
|
+
headers: Record<string, string>;
|
|
51
|
+
body: any;
|
|
52
|
+
}) => string): void;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
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 default_1(app, instance, opts, sanitize, stringify) {
|
|
6
|
+
function captureResponseData(axiosResponseObj) {
|
|
7
|
+
const { headers: reqHs, data: reqData, method, url } = axiosResponseObj.config;
|
|
8
|
+
const { data: rData, headers: rHs, status: globStatus, response } = axiosResponseObj;
|
|
9
|
+
const { data: resData, headers: resHs, status: resStatus } = response || {};
|
|
10
|
+
const ihOpt = opts.ignoreHeaders;
|
|
11
|
+
const isHIgnoring = Array.isArray(ihOpt)
|
|
12
|
+
? (name) => ihOpt.includes(name)
|
|
13
|
+
: () => ihOpt;
|
|
14
|
+
function writeHeader(hsObj, header) {
|
|
15
|
+
if (!isHIgnoring(header[0])) {
|
|
16
|
+
hsObj[header[0]] = header[1];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
let requestHs = {};
|
|
20
|
+
let responseHs = {};
|
|
21
|
+
if (reqHs.toJSON) {
|
|
22
|
+
requestHs = reqHs.toJSON();
|
|
23
|
+
}
|
|
24
|
+
else if (reqHs instanceof Headers) {
|
|
25
|
+
reqHs.forEach((v, n) => writeHeader(requestHs, [n, v]));
|
|
26
|
+
}
|
|
27
|
+
else if (Array.isArray(reqHs)) {
|
|
28
|
+
reqHs.forEach((h) => writeHeader(requestHs, h));
|
|
29
|
+
}
|
|
30
|
+
else if (typeof reqHs === 'object') {
|
|
31
|
+
Object.entries(reqHs).forEach((h) => writeHeader(requestHs, h));
|
|
32
|
+
}
|
|
33
|
+
const usedResHeader = resHs ? resHs : rHs;
|
|
34
|
+
if (usedResHeader.toJSON) {
|
|
35
|
+
responseHs = usedResHeader.toJSON();
|
|
36
|
+
}
|
|
37
|
+
else if (usedResHeader instanceof Headers) {
|
|
38
|
+
usedResHeader.forEach((v, n) => writeHeader(responseHs, [n, v]));
|
|
39
|
+
}
|
|
40
|
+
else if (Array.isArray(usedResHeader)) {
|
|
41
|
+
usedResHeader.forEach((h) => writeHeader(responseHs, h));
|
|
42
|
+
}
|
|
43
|
+
else if (typeof usedResHeader === 'object') {
|
|
44
|
+
Object.entries(usedResHeader).forEach(([n, v]) => {
|
|
45
|
+
if (!isHIgnoring(n))
|
|
46
|
+
responseHs[n] = v;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const reqResInfo = sanitize({
|
|
50
|
+
url,
|
|
51
|
+
method: method || '',
|
|
52
|
+
status: globStatus || resStatus || 0,
|
|
53
|
+
request: {
|
|
54
|
+
headers: requestHs,
|
|
55
|
+
body: reqData,
|
|
56
|
+
},
|
|
57
|
+
response: {
|
|
58
|
+
headers: responseHs,
|
|
59
|
+
body: resData || rData,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
if (!reqResInfo) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const requestStart = axiosResponseObj.config.__openreplay_timing;
|
|
66
|
+
const duration = performance.now() - requestStart;
|
|
67
|
+
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
|
+
}
|
|
69
|
+
function getStartTime(config) {
|
|
70
|
+
config.__openreplay_timing = performance.now();
|
|
71
|
+
if (opts.sessionTokenHeader) {
|
|
72
|
+
const header = typeof opts.sessionTokenHeader === 'string'
|
|
73
|
+
? opts.sessionTokenHeader
|
|
74
|
+
: 'X-OpenReplay-Session-Token';
|
|
75
|
+
const headerValue = app.getSessionToken();
|
|
76
|
+
if (headerValue) {
|
|
77
|
+
config.headers.set(header, headerValue);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return config;
|
|
81
|
+
}
|
|
82
|
+
function captureNetworkRequest(response) {
|
|
83
|
+
if (opts.failuresOnly)
|
|
84
|
+
return response;
|
|
85
|
+
captureResponseData(response);
|
|
86
|
+
return response;
|
|
87
|
+
}
|
|
88
|
+
function captureNetworkError(error) {
|
|
89
|
+
captureResponseData(error);
|
|
90
|
+
return Promise.reject(error);
|
|
91
|
+
}
|
|
92
|
+
const reqInt = instance.interceptors.request.use(getStartTime, null, { synchronous: true });
|
|
93
|
+
const resInt = instance.interceptors.response.use(captureNetworkRequest, captureNetworkError, {
|
|
94
|
+
synchronous: true,
|
|
95
|
+
});
|
|
96
|
+
app.attachStopCallback(() => {
|
|
97
|
+
var _a, _b, _c, _d;
|
|
98
|
+
(_b = (_a = instance.interceptors.request).eject) === null || _b === void 0 ? void 0 : _b.call(_a, reqInt);
|
|
99
|
+
(_d = (_c = instance.interceptors.response).eject) === null || _d === void 0 ? void 0 : _d.call(_c, resInt);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
exports.default = default_1;
|
|
@@ -72,15 +72,12 @@ function default_1(app) {
|
|
|
72
72
|
function patchAdoptedStyleSheets(prototype) {
|
|
73
73
|
const nativeAdoptedStyleSheetsDescriptor = Object.getOwnPropertyDescriptor(prototype, 'adoptedStyleSheets');
|
|
74
74
|
if (nativeAdoptedStyleSheetsDescriptor) {
|
|
75
|
-
Object.defineProperty(prototype, 'adoptedStyleSheets', {
|
|
76
|
-
...nativeAdoptedStyleSheetsDescriptor,
|
|
77
|
-
set: function (value) {
|
|
75
|
+
Object.defineProperty(prototype, 'adoptedStyleSheets', Object.assign(Object.assign({}, nativeAdoptedStyleSheetsDescriptor), { set: function (value) {
|
|
78
76
|
// @ts-ignore
|
|
79
77
|
const retVal = nativeAdoptedStyleSheetsDescriptor.set.call(this, value);
|
|
80
78
|
sendAdoptedStyleSheetsUpdate(this);
|
|
81
79
|
return retVal;
|
|
82
|
-
}
|
|
83
|
-
});
|
|
80
|
+
} }));
|
|
84
81
|
}
|
|
85
82
|
}
|
|
86
83
|
const patchContext = (context) => {
|
package/cjs/modules/input.js
CHANGED
|
@@ -4,7 +4,17 @@ 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 = [
|
|
7
|
+
const INPUT_TYPES = [
|
|
8
|
+
'text',
|
|
9
|
+
'password',
|
|
10
|
+
'email',
|
|
11
|
+
'search',
|
|
12
|
+
'number',
|
|
13
|
+
'range',
|
|
14
|
+
'date',
|
|
15
|
+
'tel',
|
|
16
|
+
'time',
|
|
17
|
+
];
|
|
8
18
|
function isTextFieldElement(node) {
|
|
9
19
|
if ((0, guards_js_1.hasTag)(node, 'textarea')) {
|
|
10
20
|
return true;
|
package/cjs/modules/mouse.js
CHANGED
|
@@ -4,21 +4,16 @@ const guards_js_1 = require("../app/guards.js");
|
|
|
4
4
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
async function _getSelector(target, document, options) {
|
|
11
|
-
if (!finderLib) {
|
|
12
|
-
const { finder } = await import('@medv/finder');
|
|
13
|
-
finderLib = finder;
|
|
14
|
-
}
|
|
15
|
-
return finderLib(target, {
|
|
7
|
+
const finder_1 = require("@medv/finder");
|
|
8
|
+
function _getSelector(target, document, options) {
|
|
9
|
+
const selector = (0, finder_1.finder)(target, {
|
|
16
10
|
root: document.body,
|
|
17
11
|
seedMinLength: 3,
|
|
18
|
-
optimizedMinLength: options
|
|
19
|
-
threshold: options
|
|
20
|
-
maxNumberOfTries: options
|
|
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,
|
|
21
15
|
});
|
|
16
|
+
return selector;
|
|
22
17
|
}
|
|
23
18
|
function isClickable(element) {
|
|
24
19
|
const tag = element.tagName.toUpperCase();
|
|
@@ -138,12 +133,8 @@ function default_1(app, options) {
|
|
|
138
133
|
}
|
|
139
134
|
};
|
|
140
135
|
const patchDocument = (document, topframe = false) => {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return selectorMap[id];
|
|
144
|
-
}
|
|
145
|
-
const selector = await _getSelector(target, document, options);
|
|
146
|
-
return selector;
|
|
136
|
+
function getSelector(id, target, options) {
|
|
137
|
+
return (selectorMap[id] = selectorMap[id] || _getSelector(target, document, options));
|
|
147
138
|
}
|
|
148
139
|
const attachListener = topframe
|
|
149
140
|
? app.attachEventListener.bind(app) // attached/removed on start/stop
|
|
@@ -167,7 +158,7 @@ function default_1(app, options) {
|
|
|
167
158
|
directionChangeCount++;
|
|
168
159
|
}
|
|
169
160
|
}, false);
|
|
170
|
-
attachListener(document, 'click',
|
|
161
|
+
attachListener(document, 'click', (e) => {
|
|
171
162
|
const target = getTarget(e.target, document);
|
|
172
163
|
if ((!e.clientX && !e.clientY) || target === null) {
|
|
173
164
|
return;
|
|
@@ -175,7 +166,7 @@ function default_1(app, options) {
|
|
|
175
166
|
const id = app.nodes.getID(target);
|
|
176
167
|
if (id !== undefined) {
|
|
177
168
|
sendMouseMove();
|
|
178
|
-
app.send((0, messages_gen_js_1.MouseClick)(id, mouseTarget === target ? Math.round(performance.now() - mouseTargetTime) : 0, getTargetLabel(target), isClickable(target) && !disableClickmaps ?
|
|
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);
|
|
179
170
|
}
|
|
180
171
|
mouseTarget = null;
|
|
181
172
|
});
|
|
@@ -186,6 +177,6 @@ function default_1(app, options) {
|
|
|
186
177
|
}
|
|
187
178
|
});
|
|
188
179
|
patchDocument(document, true);
|
|
189
|
-
app.ticker.attach(sendMouseMove, options
|
|
180
|
+
app.ticker.attach(sendMouseMove, (options === null || options === void 0 ? void 0 : options.trackingOffset) || 7);
|
|
190
181
|
}
|
|
191
182
|
exports.default = default_1;
|
package/cjs/modules/network.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type App from '../app/index.js';
|
|
2
|
+
import type { AxiosInstance } from './axiosSpy.js';
|
|
2
3
|
type XHRRequestBody = Parameters<XMLHttpRequest['send']>[0];
|
|
3
4
|
type FetchRequestBody = RequestInit['body'];
|
|
4
5
|
interface RequestData {
|
|
@@ -9,7 +10,7 @@ interface ResponseData {
|
|
|
9
10
|
body: any;
|
|
10
11
|
headers: Record<string, string>;
|
|
11
12
|
}
|
|
12
|
-
interface RequestResponseData {
|
|
13
|
+
export interface RequestResponseData {
|
|
13
14
|
readonly status: number;
|
|
14
15
|
readonly method: string;
|
|
15
16
|
url: string;
|
|
@@ -22,7 +23,9 @@ export interface Options {
|
|
|
22
23
|
failuresOnly: boolean;
|
|
23
24
|
ignoreHeaders: Array<string> | boolean;
|
|
24
25
|
capturePayload: boolean;
|
|
26
|
+
captureInIframes: boolean;
|
|
25
27
|
sanitizer?: Sanitizer;
|
|
28
|
+
axiosInstances?: Array<AxiosInstance>;
|
|
26
29
|
}
|
|
27
30
|
export default function (app: App, opts?: Partial<Options>): void;
|
|
28
31
|
export {};
|
package/cjs/modules/network.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
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 axiosSpy_js_1 = require("./axiosSpy.js");
|
|
5
6
|
function getXHRRequestDataObject(xhr) {
|
|
6
7
|
// @ts-ignore this is 3x faster than using Map<XHR, XHRRequestData>
|
|
7
8
|
if (!xhr.__or_req_data__) {
|
|
@@ -20,6 +21,8 @@ function default_1(app, opts = {}) {
|
|
|
20
21
|
ignoreHeaders: ['Cookie', 'Set-Cookie', 'Authorization'],
|
|
21
22
|
capturePayload: false,
|
|
22
23
|
sessionTokenHeader: false,
|
|
24
|
+
captureInIframes: true,
|
|
25
|
+
axiosInstances: undefined,
|
|
23
26
|
}, opts);
|
|
24
27
|
const ignoreHeaders = options.ignoreHeaders;
|
|
25
28
|
const isHIgnored = Array.isArray(ignoreHeaders)
|
|
@@ -46,7 +49,7 @@ function default_1(app, opts = {}) {
|
|
|
46
49
|
try {
|
|
47
50
|
reqResInfo.response.body = JSON.parse(resBody);
|
|
48
51
|
}
|
|
49
|
-
catch { }
|
|
52
|
+
catch (_a) { }
|
|
50
53
|
}
|
|
51
54
|
return options.sanitizer(reqResInfo);
|
|
52
55
|
}
|
|
@@ -57,7 +60,7 @@ function default_1(app, opts = {}) {
|
|
|
57
60
|
try {
|
|
58
61
|
r.body = JSON.stringify(r.body);
|
|
59
62
|
}
|
|
60
|
-
catch {
|
|
63
|
+
catch (_a) {
|
|
61
64
|
r.body = '<unable to stringify>';
|
|
62
65
|
app.notify.warn("Openreplay fetch couldn't stringify body:", r.body);
|
|
63
66
|
}
|
|
@@ -145,6 +148,8 @@ function default_1(app, opts = {}) {
|
|
|
145
148
|
/* ====== <> ====== */
|
|
146
149
|
/* ====== XHR ====== */
|
|
147
150
|
const nativeOpen = context.XMLHttpRequest.prototype.open;
|
|
151
|
+
const nativeSetRequestHeader = context.XMLHttpRequest.prototype.setRequestHeader;
|
|
152
|
+
const nativeSend = context.XMLHttpRequest.prototype.send;
|
|
148
153
|
function trackXMLHttpReqOpen(initMethod, url) {
|
|
149
154
|
const xhr = this;
|
|
150
155
|
setSessionTokenHeader((name, value) => xhr.setRequestHeader(name, value));
|
|
@@ -161,7 +166,7 @@ function default_1(app, opts = {}) {
|
|
|
161
166
|
.split('\r\n')
|
|
162
167
|
.map((h) => h.split(':'))
|
|
163
168
|
.filter((entry) => !isHIgnored(entry[0]))
|
|
164
|
-
.reduce((hds, [name, value]) => ({
|
|
169
|
+
.reduce((hds, [name, value]) => (Object.assign(Object.assign({}, hds), { [name]: value })), {})
|
|
165
170
|
: {};
|
|
166
171
|
const method = strMethod(initMethod);
|
|
167
172
|
const reqResInfo = sanitize({
|
|
@@ -186,16 +191,12 @@ function default_1(app, opts = {}) {
|
|
|
186
191
|
//xhr.addEventListener('error', (e) => {})
|
|
187
192
|
return nativeOpen.apply(this, arguments);
|
|
188
193
|
}
|
|
189
|
-
context.XMLHttpRequest.prototype.open = trackXMLHttpReqOpen;
|
|
190
|
-
const nativeSend = context.XMLHttpRequest.prototype.send;
|
|
191
194
|
function trackXHRSend(body) {
|
|
192
195
|
const rdo = getXHRRequestDataObject(this);
|
|
193
196
|
rdo.body = body;
|
|
194
197
|
// @ts-ignore ??? this -> XMLHttpRequest
|
|
195
198
|
return nativeSend.apply(this, arguments);
|
|
196
199
|
}
|
|
197
|
-
context.XMLHttpRequest.prototype.send = trackXHRSend;
|
|
198
|
-
const nativeSetRequestHeader = context.XMLHttpRequest.prototype.setRequestHeader;
|
|
199
200
|
function trackSetReqHeader(name, value) {
|
|
200
201
|
if (!isHIgnored(name)) {
|
|
201
202
|
const rdo = getXHRRequestDataObject(this);
|
|
@@ -203,10 +204,21 @@ function default_1(app, opts = {}) {
|
|
|
203
204
|
}
|
|
204
205
|
return nativeSetRequestHeader.apply(this, arguments);
|
|
205
206
|
}
|
|
206
|
-
|
|
207
|
+
if (!options.axiosInstances) {
|
|
208
|
+
context.XMLHttpRequest.prototype.open = trackXMLHttpReqOpen;
|
|
209
|
+
context.XMLHttpRequest.prototype.send = trackXHRSend;
|
|
210
|
+
context.XMLHttpRequest.prototype.setRequestHeader = trackSetReqHeader;
|
|
211
|
+
}
|
|
207
212
|
/* ====== <> ====== */
|
|
208
213
|
};
|
|
209
214
|
patchWindow(window);
|
|
210
|
-
|
|
215
|
+
if (options.axiosInstances) {
|
|
216
|
+
options.axiosInstances.forEach((axiosInstance) => {
|
|
217
|
+
(0, axiosSpy_js_1.default)(app, axiosInstance, options, sanitize, stringify);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
if (options.captureInIframes) {
|
|
221
|
+
app.observer.attachContextCallback(app.safe(patchWindow));
|
|
222
|
+
}
|
|
211
223
|
}
|
|
212
224
|
exports.default = default_1;
|
package/cjs/utils.js
CHANGED
|
@@ -70,8 +70,9 @@ function hasOpenreplayAttribute(e, attr) {
|
|
|
70
70
|
}
|
|
71
71
|
exports.hasOpenreplayAttribute = hasOpenreplayAttribute;
|
|
72
72
|
function isIframeCrossdomain(e) {
|
|
73
|
+
var _a;
|
|
73
74
|
try {
|
|
74
|
-
return e.contentWindow
|
|
75
|
+
return ((_a = e.contentWindow) === null || _a === void 0 ? void 0 : _a.location.href) !== window.location.href;
|
|
75
76
|
}
|
|
76
77
|
catch (e) {
|
|
77
78
|
return true;
|
|
@@ -27,7 +27,7 @@ function finder(input, options) {
|
|
|
27
27
|
threshold: 1000,
|
|
28
28
|
maxNumberOfTries: 10000,
|
|
29
29
|
};
|
|
30
|
-
config = {
|
|
30
|
+
config = Object.assign(Object.assign({}, defaults), options);
|
|
31
31
|
rootDocument = findRootDocument(config.root, defaults);
|
|
32
32
|
let path = bottomUpSearch(input, Limit.All, () => bottomUpSearch(input, Limit.Two, () => bottomUpSearch(input, Limit.One)));
|
|
33
33
|
if (path) {
|
|
@@ -271,7 +271,7 @@ const defaultOptions = {
|
|
|
271
271
|
wrap: false,
|
|
272
272
|
};
|
|
273
273
|
function cssesc(string, opt = {}) {
|
|
274
|
-
const options = {
|
|
274
|
+
const options = Object.assign(Object.assign({}, defaultOptions), opt);
|
|
275
275
|
if (options.quotes != 'single' && options.quotes != 'double') {
|
|
276
276
|
options.quotes = 'single';
|
|
277
277
|
}
|