@openreplay/tracker 13.0.1 → 14.0.0
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 +14 -0
- package/bun.lockb +0 -0
- package/cjs/app/canvas.d.ts +2 -0
- package/cjs/app/canvas.js +6 -5
- package/cjs/app/index.d.ts +55 -16
- package/cjs/app/index.js +417 -236
- package/cjs/app/messages.gen.d.ts +6 -3
- package/cjs/app/messages.gen.js +44 -10
- package/cjs/app/nodes.d.ts +2 -0
- package/cjs/app/nodes.js +15 -1
- package/cjs/app/observer/iframe_observer.d.ts +1 -0
- package/cjs/app/observer/iframe_observer.js +9 -0
- package/cjs/app/observer/iframe_offsets.js +0 -1
- package/cjs/app/observer/top_observer.d.ts +1 -0
- package/cjs/app/observer/top_observer.js +14 -0
- package/cjs/common/messages.gen.d.ts +38 -10
- package/cjs/index.d.ts +1 -0
- package/cjs/index.js +17 -8
- package/cjs/modules/conditionsManager.js +2 -2
- package/cjs/modules/mouse.js +14 -1
- package/cjs/modules/scroll.d.ts +1 -1
- package/cjs/modules/scroll.js +9 -4
- package/cjs/modules/viewport.js +2 -2
- package/cjs/utils.d.ts +2 -1
- package/cjs/utils.js +33 -6
- package/lib/app/canvas.d.ts +2 -0
- package/lib/app/canvas.js +6 -5
- package/lib/app/index.d.ts +55 -16
- package/lib/app/index.js +399 -218
- package/lib/app/messages.gen.d.ts +6 -3
- package/lib/app/messages.gen.js +37 -6
- package/lib/app/nodes.d.ts +2 -0
- package/lib/app/nodes.js +15 -1
- package/lib/app/observer/iframe_observer.d.ts +1 -0
- package/lib/app/observer/iframe_observer.js +9 -0
- package/lib/app/observer/iframe_offsets.js +0 -1
- package/lib/app/observer/top_observer.d.ts +1 -0
- package/lib/app/observer/top_observer.js +14 -0
- package/lib/common/messages.gen.d.ts +38 -10
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +18 -9
- package/lib/modules/conditionsManager.js +2 -2
- package/lib/modules/mouse.js +14 -1
- package/lib/modules/scroll.d.ts +1 -1
- package/lib/modules/scroll.js +9 -4
- package/lib/modules/viewport.js +2 -2
- package/lib/utils.d.ts +2 -1
- package/lib/utils.js +31 -5
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import Network from './modules/network.js';
|
|
|
21
21
|
import ConstructedStyleSheets from './modules/constructedStyleSheets.js';
|
|
22
22
|
import Selection from './modules/selection.js';
|
|
23
23
|
import Tabs from './modules/tabs.js';
|
|
24
|
-
import { IN_BROWSER, deprecationWarn, DOCS_HOST } from './utils.js';
|
|
24
|
+
import { IN_BROWSER, deprecationWarn, DOCS_HOST, inIframe } from './utils.js';
|
|
25
25
|
const DOCS_SETUP = '/installation/javascript-sdk';
|
|
26
26
|
function processOptions(obj) {
|
|
27
27
|
if (obj == null) {
|
|
@@ -54,6 +54,7 @@ export default class API {
|
|
|
54
54
|
constructor(options) {
|
|
55
55
|
this.options = options;
|
|
56
56
|
this.app = null;
|
|
57
|
+
this.crossdomainMode = false;
|
|
57
58
|
this.checkDoNotTrack = () => {
|
|
58
59
|
return (this.options.respectDoNotTrack &&
|
|
59
60
|
(navigator.doNotTrack == '1' ||
|
|
@@ -66,7 +67,7 @@ export default class API {
|
|
|
66
67
|
const orig = this.options.ingestPoint || DEFAULT_INGEST_POINT;
|
|
67
68
|
req.open('POST', orig + '/v1/web/not-started');
|
|
68
69
|
req.send(JSON.stringify({
|
|
69
|
-
trackerVersion: '
|
|
70
|
+
trackerVersion: '14.0.0',
|
|
70
71
|
projectKey: this.options.projectKey,
|
|
71
72
|
doNotTrack,
|
|
72
73
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|
|
@@ -94,6 +95,7 @@ export default class API {
|
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
97
|
};
|
|
98
|
+
this.crossdomainMode = Boolean(inIframe() && options.crossdomain?.enabled);
|
|
97
99
|
if (!IN_BROWSER || !processOptions(options)) {
|
|
98
100
|
return;
|
|
99
101
|
}
|
|
@@ -148,25 +150,32 @@ export default class API {
|
|
|
148
150
|
this.signalStartIssue('missing_api', failReason);
|
|
149
151
|
return;
|
|
150
152
|
}
|
|
151
|
-
const app = new App(options.projectKey, options.sessionToken, options, this.signalStartIssue);
|
|
153
|
+
const app = new App(options.projectKey, options.sessionToken, options, this.signalStartIssue, this.crossdomainMode);
|
|
152
154
|
this.app = app;
|
|
153
|
-
|
|
155
|
+
if (!this.crossdomainMode) {
|
|
156
|
+
// no need to send iframe viewport data since its a node for us
|
|
157
|
+
Viewport(app);
|
|
158
|
+
// calculated in main window
|
|
159
|
+
Connection(app);
|
|
160
|
+
// while we can calculate it here, trying to compute it for all parts is hard
|
|
161
|
+
Performance(app, options);
|
|
162
|
+
// no tabs in iframes yet
|
|
163
|
+
Tabs(app);
|
|
164
|
+
}
|
|
165
|
+
Mouse(app, options.mouse);
|
|
166
|
+
// inside iframe, we ignore viewport scroll
|
|
167
|
+
Scroll(app, this.crossdomainMode);
|
|
154
168
|
CSSRules(app);
|
|
155
169
|
ConstructedStyleSheets(app);
|
|
156
|
-
Connection(app);
|
|
157
170
|
Console(app, options);
|
|
158
171
|
Exception(app, options);
|
|
159
172
|
Img(app);
|
|
160
173
|
Input(app, options);
|
|
161
|
-
Mouse(app, options.mouse);
|
|
162
174
|
Timing(app, options);
|
|
163
|
-
Performance(app, options);
|
|
164
|
-
Scroll(app);
|
|
165
175
|
Focus(app);
|
|
166
176
|
Fonts(app);
|
|
167
177
|
Network(app, options.network);
|
|
168
178
|
Selection(app);
|
|
169
|
-
Tabs(app);
|
|
170
179
|
window.__OPENREPLAY__ = this;
|
|
171
180
|
if (options.flags && options.flags.onFlagsLoad) {
|
|
172
181
|
this.onFlagsLoad(options.flags.onFlagsLoad);
|
|
@@ -84,10 +84,10 @@ export default class ConditionsManager {
|
|
|
84
84
|
case 27 /* Type.CustomEvent */:
|
|
85
85
|
this.customEvent(message);
|
|
86
86
|
break;
|
|
87
|
-
case
|
|
87
|
+
case 68 /* Type.MouseClick */:
|
|
88
88
|
this.clickEvent(message);
|
|
89
89
|
break;
|
|
90
|
-
case
|
|
90
|
+
case 122 /* Type.SetPageLocation */:
|
|
91
91
|
this.pageLocationEvent(message);
|
|
92
92
|
break;
|
|
93
93
|
case 83 /* Type.NetworkRequest */:
|
package/lib/modules/mouse.js
CHANGED
|
@@ -163,8 +163,14 @@ export default function (app, options) {
|
|
|
163
163
|
}
|
|
164
164
|
const id = app.nodes.getID(target);
|
|
165
165
|
if (id !== undefined) {
|
|
166
|
+
const clickX = e.pageX;
|
|
167
|
+
const clickY = e.pageY;
|
|
168
|
+
const contentWidth = document.documentElement.scrollWidth;
|
|
169
|
+
const contentHeight = document.documentElement.scrollHeight;
|
|
170
|
+
const normalizedX = roundNumber(clickX / contentWidth);
|
|
171
|
+
const normalizedY = roundNumber(clickY / contentHeight);
|
|
166
172
|
sendMouseMove();
|
|
167
|
-
app.send(MouseClick(id, mouseTarget === target ? Math.round(performance.now() - mouseTargetTime) : 0, getTargetLabel(target), isClickable(target) && !disableClickmaps ? getSelector(id, target, options) : ''), true);
|
|
173
|
+
app.send(MouseClick(id, mouseTarget === target ? Math.round(performance.now() - mouseTargetTime) : 0, getTargetLabel(target), isClickable(target) && !disableClickmaps ? getSelector(id, target, options) : '', normalizedX, normalizedY), true);
|
|
168
174
|
}
|
|
169
175
|
mouseTarget = null;
|
|
170
176
|
});
|
|
@@ -177,3 +183,10 @@ export default function (app, options) {
|
|
|
177
183
|
patchDocument(document, true);
|
|
178
184
|
app.ticker.attach(sendMouseMove, options?.trackingOffset || 7);
|
|
179
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* we get 0 to 1 decimal number, convert and round it, then turn to %
|
|
188
|
+
* 0.39643 => 396.43 => 396 => 39.6%
|
|
189
|
+
* */
|
|
190
|
+
function roundNumber(num) {
|
|
191
|
+
return Math.round(num * 1e3) / 1e1;
|
|
192
|
+
}
|
package/lib/modules/scroll.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type App from '../app/index.js';
|
|
2
|
-
export default function (app: App): void;
|
|
2
|
+
export default function (app: App, insideIframe: boolean | null): void;
|
package/lib/modules/scroll.js
CHANGED
|
@@ -3,17 +3,17 @@ import { isNode, isElementNode, isRootNode, isDocument } from '../app/guards.js'
|
|
|
3
3
|
function getDocumentScroll(doc) {
|
|
4
4
|
const win = doc.defaultView;
|
|
5
5
|
return [
|
|
6
|
-
(win && win.
|
|
6
|
+
(win && win.scrollX) ||
|
|
7
7
|
(doc.documentElement && doc.documentElement.scrollLeft) ||
|
|
8
8
|
(doc.body && doc.body.scrollLeft) ||
|
|
9
9
|
0,
|
|
10
|
-
(win && win.
|
|
10
|
+
(win && win.scrollY) ||
|
|
11
11
|
(doc.documentElement && doc.documentElement.scrollTop) ||
|
|
12
12
|
(doc.body && doc.body.scrollTop) ||
|
|
13
13
|
0,
|
|
14
14
|
];
|
|
15
15
|
}
|
|
16
|
-
export default function (app) {
|
|
16
|
+
export default function (app, insideIframe) {
|
|
17
17
|
let documentScroll = false;
|
|
18
18
|
const nodeScroll = new Map();
|
|
19
19
|
function setNodeScroll(target) {
|
|
@@ -27,7 +27,12 @@ export default function (app) {
|
|
|
27
27
|
nodeScroll.set(target, getDocumentScroll(target));
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
const sendSetViewportScroll = app.safe(() =>
|
|
30
|
+
const sendSetViewportScroll = app.safe(() => {
|
|
31
|
+
if (insideIframe) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
app.send(SetViewportScroll(...getDocumentScroll(document)));
|
|
35
|
+
});
|
|
31
36
|
const sendSetNodeScroll = app.safe((s, node) => {
|
|
32
37
|
const id = app.nodes.getID(node);
|
|
33
38
|
if (id !== undefined) {
|
package/lib/modules/viewport.js
CHANGED
|
@@ -8,7 +8,7 @@ export default function (app) {
|
|
|
8
8
|
const { URL } = document;
|
|
9
9
|
if (URL !== url) {
|
|
10
10
|
url = URL;
|
|
11
|
-
app.send(SetPageLocation(url, referrer, navigationStart));
|
|
11
|
+
app.send(SetPageLocation(url, referrer, navigationStart, document.title));
|
|
12
12
|
navigationStart = 0;
|
|
13
13
|
referrer = url;
|
|
14
14
|
}
|
|
@@ -25,7 +25,7 @@ export default function (app) {
|
|
|
25
25
|
? Function.prototype
|
|
26
26
|
: app.safe(() => app.send(SetPageVisibility(document.hidden)));
|
|
27
27
|
app.attachStartCallback(() => {
|
|
28
|
-
url =
|
|
28
|
+
url = null;
|
|
29
29
|
navigationStart = getTimeOrigin();
|
|
30
30
|
width = height = -1;
|
|
31
31
|
sendSetPageLocation();
|
package/lib/utils.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export declare function hasOpenreplayAttribute(e: Element, attr: string): boolea
|
|
|
16
16
|
**/
|
|
17
17
|
export declare function canAccessIframe(iframe: HTMLIFrameElement): boolean;
|
|
18
18
|
export declare function generateRandomId(len?: number): string;
|
|
19
|
-
export declare function inIframe(): boolean;
|
|
19
|
+
export declare function inIframe(): boolean | null;
|
|
20
20
|
/**
|
|
21
21
|
* Because angular devs decided that its a good idea to override a browser apis
|
|
22
22
|
* we need to use this to achieve safe behavior
|
|
@@ -26,3 +26,4 @@ export declare function createMutationObserver(cb: MutationCallback): MutationOb
|
|
|
26
26
|
export declare function createEventListener(target: EventTarget, event: string, cb: EventListenerOrEventListenerObject, capture?: boolean): void;
|
|
27
27
|
export declare function deleteEventListener(target: EventTarget, event: string, cb: EventListenerOrEventListenerObject, capture?: boolean): void;
|
|
28
28
|
export declare function requestIdleCb(callback: () => void): void;
|
|
29
|
+
export declare function simpleMerge<T>(defaultObj: T, givenObj: Partial<T>): T;
|
package/lib/utils.js
CHANGED
|
@@ -78,12 +78,17 @@ export function generateRandomId(len) {
|
|
|
78
78
|
// msCrypto = IE11
|
|
79
79
|
// @ts-ignore
|
|
80
80
|
const safeCrypto = window.crypto || window.msCrypto;
|
|
81
|
-
safeCrypto
|
|
82
|
-
|
|
81
|
+
if (safeCrypto) {
|
|
82
|
+
safeCrypto.getRandomValues(arr);
|
|
83
|
+
return Array.from(arr, dec2hex).join('');
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
return Array.from({ length: len || 40 }, () => dec2hex(Math.floor(Math.random() * 16))).join('');
|
|
87
|
+
}
|
|
83
88
|
}
|
|
84
89
|
export function inIframe() {
|
|
85
90
|
try {
|
|
86
|
-
return window.self !== window.top;
|
|
91
|
+
return window.self && window.top && window.self !== window.top;
|
|
87
92
|
}
|
|
88
93
|
catch (e) {
|
|
89
94
|
return true;
|
|
@@ -110,9 +115,10 @@ export function createEventListener(target, event, cb, capture) {
|
|
|
110
115
|
target[safeAddEventListener](event, cb, capture);
|
|
111
116
|
}
|
|
112
117
|
catch (e) {
|
|
118
|
+
const msg = e.message;
|
|
113
119
|
console.debug(
|
|
114
120
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
115
|
-
`Openreplay: ${
|
|
121
|
+
`Openreplay: ${msg}; if this error is caused by an IframeObserver, ignore it`);
|
|
116
122
|
}
|
|
117
123
|
}
|
|
118
124
|
export function deleteEventListener(target, event, cb, capture) {
|
|
@@ -121,9 +127,10 @@ export function deleteEventListener(target, event, cb, capture) {
|
|
|
121
127
|
target[safeRemoveEventListener](event, cb, capture);
|
|
122
128
|
}
|
|
123
129
|
catch (e) {
|
|
130
|
+
const msg = e.message;
|
|
124
131
|
console.debug(
|
|
125
132
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
126
|
-
`Openreplay: ${
|
|
133
|
+
`Openreplay: ${msg}; if this error is caused by an IframeObserver, ignore it`);
|
|
127
134
|
}
|
|
128
135
|
}
|
|
129
136
|
class FIFOTaskScheduler {
|
|
@@ -183,3 +190,22 @@ export function requestIdleCb(callback) {
|
|
|
183
190
|
// })
|
|
184
191
|
// }
|
|
185
192
|
}
|
|
193
|
+
export function simpleMerge(defaultObj, givenObj) {
|
|
194
|
+
const result = { ...defaultObj };
|
|
195
|
+
for (const key in givenObj) {
|
|
196
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
197
|
+
if (givenObj.hasOwnProperty(key)) {
|
|
198
|
+
const userOptionValue = givenObj[key];
|
|
199
|
+
const defaultOptionValue = defaultObj[key];
|
|
200
|
+
if (typeof userOptionValue === 'object' &&
|
|
201
|
+
!Array.isArray(userOptionValue) &&
|
|
202
|
+
userOptionValue !== null) {
|
|
203
|
+
result[key] = simpleMerge(defaultOptionValue || {}, userOptionValue);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
result[key] = userOptionValue;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return result;
|
|
211
|
+
}
|