@openreplay/tracker 3.5.17-beta.0 → 3.6.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/.eslintignore +1 -1
- package/.prettierignore +1 -0
- package/LICENSE +1 -1
- package/cjs/app/guards.d.ts +2 -1
- package/cjs/app/guards.js +5 -1
- package/cjs/app/index.d.ts +17 -12
- package/cjs/app/index.js +63 -49
- package/cjs/app/messages.d.ts +52 -0
- package/cjs/app/messages.gen.d.ts +57 -0
- package/cjs/app/messages.gen.js +493 -0
- package/cjs/app/messages.js +234 -0
- package/cjs/app/nodes.d.ts +1 -1
- package/cjs/app/nodes.js +2 -0
- package/cjs/app/observer/iframe_observer.js +2 -2
- package/cjs/app/observer/observer.d.ts +1 -2
- package/cjs/app/observer/observer.js +40 -39
- package/cjs/app/observer/shadow_root_observer.js +2 -2
- package/cjs/app/observer/top_observer.d.ts +11 -0
- package/cjs/app/observer/top_observer.js +46 -12
- package/cjs/app/session.d.ts +19 -1
- package/cjs/app/session.js +61 -3
- package/cjs/common/{webworker.d.ts → interaction.d.ts} +3 -3
- package/cjs/common/{types.js → interaction.js} +0 -0
- package/cjs/common/messages.gen.d.ts +382 -0
- package/cjs/common/{webworker.js → messages.gen.js} +1 -0
- package/cjs/index.d.ts +3 -2
- package/cjs/index.js +20 -9
- package/cjs/modules/adoptedStyleSheets.d.ts +2 -0
- package/cjs/modules/adoptedStyleSheets.js +127 -0
- package/cjs/modules/connection.js +2 -2
- package/cjs/modules/console.js +6 -20
- package/cjs/modules/cssrules.js +16 -12
- package/cjs/modules/exception.d.ts +2 -2
- package/cjs/modules/exception.js +16 -12
- package/cjs/modules/img.js +31 -21
- package/cjs/modules/input.js +6 -6
- package/cjs/modules/mouse.js +42 -33
- package/cjs/modules/performance.js +2 -2
- package/cjs/modules/scroll.js +16 -7
- package/cjs/modules/timing.js +4 -4
- package/cjs/modules/viewport.js +4 -4
- package/lib/app/guards.d.ts +2 -1
- package/lib/app/guards.js +3 -0
- package/lib/app/index.d.ts +17 -12
- package/lib/app/index.js +64 -50
- package/lib/app/messages.d.ts +52 -0
- package/lib/app/messages.gen.d.ts +57 -0
- package/lib/app/messages.gen.js +434 -0
- package/lib/app/messages.js +181 -0
- package/lib/app/nodes.d.ts +1 -1
- package/lib/app/nodes.js +2 -0
- package/lib/app/observer/iframe_observer.js +1 -1
- package/lib/app/observer/observer.d.ts +1 -2
- package/lib/app/observer/observer.js +40 -39
- package/lib/app/observer/shadow_root_observer.js +1 -1
- package/lib/app/observer/top_observer.d.ts +11 -0
- package/lib/app/observer/top_observer.js +46 -12
- package/lib/app/session.d.ts +19 -1
- package/lib/app/session.js +61 -3
- package/lib/common/{webworker.d.ts → interaction.d.ts} +3 -3
- package/lib/common/{types.js → interaction.js} +0 -0
- package/lib/common/messages.gen.d.ts +382 -0
- package/lib/common/messages.gen.js +2 -0
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.d.ts +3 -2
- package/lib/index.js +20 -9
- package/lib/modules/adoptedStyleSheets.d.ts +2 -0
- package/lib/modules/adoptedStyleSheets.js +124 -0
- package/lib/modules/connection.js +2 -2
- package/lib/modules/console.js +6 -20
- package/lib/modules/cssrules.js +16 -12
- package/lib/modules/exception.d.ts +2 -2
- package/lib/modules/exception.js +16 -12
- package/lib/modules/img.js +31 -21
- package/lib/modules/input.js +6 -6
- package/lib/modules/mouse.js +43 -34
- package/lib/modules/performance.js +2 -2
- package/lib/modules/scroll.js +17 -8
- package/lib/modules/timing.js +4 -4
- package/lib/modules/viewport.js +4 -4
- package/package.json +1 -1
- package/cjs/common/messages.d.ts +0 -444
- package/cjs/common/messages.js +0 -794
- package/cjs/common/types.d.ts +0 -9
- package/cjs/modules/longtasks.d.ts +0 -2
- package/cjs/modules/longtasks.js +0 -34
- package/lib/common/messages.d.ts +0 -444
- package/lib/common/messages.js +0 -790
- package/lib/common/types.d.ts +0 -9
- package/lib/common/webworker.js +0 -1
- package/lib/modules/longtasks.d.ts +0 -2
- package/lib/modules/longtasks.js +0 -31
package/cjs/app/nodes.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export default class Nodes {
|
|
|
7
7
|
constructor(node_id: string);
|
|
8
8
|
attachNodeCallback(nodeCallback: NodeCallback): void;
|
|
9
9
|
attachElementListener(type: string, node: Element, elementListener: EventListener): void;
|
|
10
|
-
registerNode(node: Node): [id
|
|
10
|
+
registerNode(node: Node): [/*id:*/ number, /*isNew:*/ boolean];
|
|
11
11
|
unregisterNode(node: Node): number | undefined;
|
|
12
12
|
cleanTree(): void;
|
|
13
13
|
callNodeCallbacks(node: Node, isStart: boolean): void;
|
package/cjs/app/nodes.js
CHANGED
|
@@ -7,9 +7,11 @@ class Nodes {
|
|
|
7
7
|
this.nodeCallbacks = [];
|
|
8
8
|
this.elementListeners = new Map();
|
|
9
9
|
}
|
|
10
|
+
// Attached once per Tracker instance
|
|
10
11
|
attachNodeCallback(nodeCallback) {
|
|
11
12
|
this.nodeCallbacks.push(nodeCallback);
|
|
12
13
|
}
|
|
14
|
+
// TODO: what is the difference with app.attachEventListener. can we use only one of those?
|
|
13
15
|
attachElementListener(type, node, elementListener) {
|
|
14
16
|
const id = this.getID(node);
|
|
15
17
|
if (id === undefined) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const observer_js_1 = require("./observer.js");
|
|
4
|
-
const
|
|
4
|
+
const messages_gen_js_1 = require("../messages.gen.js");
|
|
5
5
|
class IFrameObserver extends observer_js_1.default {
|
|
6
6
|
observe(iframe) {
|
|
7
7
|
const doc = iframe.contentDocument;
|
|
@@ -15,7 +15,7 @@ class IFrameObserver extends observer_js_1.default {
|
|
|
15
15
|
console.log('OpenReplay: Iframe document not bound');
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
|
-
this.app.send((0,
|
|
18
|
+
this.app.send((0, messages_gen_js_1.CreateIFrameDocument)(hostID, docID));
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -13,9 +13,8 @@ export default abstract class Observer {
|
|
|
13
13
|
private sendNodeAttribute;
|
|
14
14
|
private sendNodeData;
|
|
15
15
|
private bindNode;
|
|
16
|
-
private unbindChildNode;
|
|
17
16
|
private bindTree;
|
|
18
|
-
private
|
|
17
|
+
private unbindTree;
|
|
19
18
|
private _commitNode;
|
|
20
19
|
private commitNode;
|
|
21
20
|
private commitNodes;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
3
|
+
const messages_gen_js_1 = require("../messages.gen.js");
|
|
4
4
|
const guards_js_1 = require("../guards.js");
|
|
5
5
|
function isIgnored(node) {
|
|
6
6
|
if ((0, guards_js_1.isTextNode)(node)) {
|
|
@@ -28,17 +28,11 @@ function isObservable(node) {
|
|
|
28
28
|
- fix unbinding logic + send all removals first (ensure sequence is correct)
|
|
29
29
|
- use document as a 0-node in the upper context (should be updated in player at first)
|
|
30
30
|
*/
|
|
31
|
-
/*
|
|
32
|
-
Nikita:
|
|
33
|
-
- rn we only send unbind event for parent (all child nodes will be cut in the live replay anyways)
|
|
34
|
-
to prevent sending 1k+ unbinds for child nodes and making replay file bigger than it should be
|
|
35
|
-
*/
|
|
36
31
|
var RecentsType;
|
|
37
32
|
(function (RecentsType) {
|
|
38
33
|
RecentsType[RecentsType["New"] = 0] = "New";
|
|
39
34
|
RecentsType[RecentsType["Removed"] = 1] = "Removed";
|
|
40
35
|
RecentsType[RecentsType["Changed"] = 2] = "Changed";
|
|
41
|
-
RecentsType[RecentsType["RemovedChild"] = 3] = "RemovedChild";
|
|
42
36
|
})(RecentsType || (RecentsType = {}));
|
|
43
37
|
class Observer {
|
|
44
38
|
constructor(app, isTopContext = false) {
|
|
@@ -59,7 +53,10 @@ class Observer {
|
|
|
59
53
|
}
|
|
60
54
|
if (type === 'childList') {
|
|
61
55
|
for (let i = 0; i < mutation.removedNodes.length; i++) {
|
|
62
|
-
|
|
56
|
+
// Should be the same as bindTree(mutation.removedNodes[i]), but logic needs to be be untied
|
|
57
|
+
if (isObservable(mutation.removedNodes[i])) {
|
|
58
|
+
this.bindNode(mutation.removedNodes[i]);
|
|
59
|
+
}
|
|
63
60
|
}
|
|
64
61
|
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
|
65
62
|
this.bindTree(mutation.addedNodes[i]);
|
|
@@ -106,16 +103,16 @@ class Observer {
|
|
|
106
103
|
name = name.substr(6);
|
|
107
104
|
}
|
|
108
105
|
if (value === null) {
|
|
109
|
-
this.app.send(
|
|
106
|
+
this.app.send((0, messages_gen_js_1.RemoveNodeAttribute)(id, name));
|
|
110
107
|
}
|
|
111
108
|
else if (name === 'href') {
|
|
112
109
|
if (value.length > 1e5) {
|
|
113
110
|
value = '';
|
|
114
111
|
}
|
|
115
|
-
this.app.send(
|
|
112
|
+
this.app.send((0, messages_gen_js_1.SetNodeAttributeURLBased)(id, name, value, this.app.getBaseHref()));
|
|
116
113
|
}
|
|
117
114
|
else {
|
|
118
|
-
this.app.send(
|
|
115
|
+
this.app.send((0, messages_gen_js_1.SetNodeAttribute)(id, name, value));
|
|
119
116
|
}
|
|
120
117
|
return;
|
|
121
118
|
}
|
|
@@ -135,25 +132,25 @@ class Observer {
|
|
|
135
132
|
return;
|
|
136
133
|
}
|
|
137
134
|
if (value === null) {
|
|
138
|
-
this.app.send(
|
|
135
|
+
this.app.send((0, messages_gen_js_1.RemoveNodeAttribute)(id, name));
|
|
139
136
|
return;
|
|
140
137
|
}
|
|
141
138
|
if (name === 'style' || (name === 'href' && (0, guards_js_1.hasTag)(node, 'LINK'))) {
|
|
142
|
-
this.app.send(
|
|
139
|
+
this.app.send((0, messages_gen_js_1.SetNodeAttributeURLBased)(id, name, value, this.app.getBaseHref()));
|
|
143
140
|
return;
|
|
144
141
|
}
|
|
145
142
|
if (name === 'href' || value.length > 1e5) {
|
|
146
143
|
value = '';
|
|
147
144
|
}
|
|
148
|
-
this.app.send(
|
|
145
|
+
this.app.send((0, messages_gen_js_1.SetNodeAttribute)(id, name, value));
|
|
149
146
|
}
|
|
150
147
|
sendNodeData(id, parentElement, data) {
|
|
151
148
|
if ((0, guards_js_1.hasTag)(parentElement, 'STYLE') || (0, guards_js_1.hasTag)(parentElement, 'style')) {
|
|
152
|
-
this.app.send(
|
|
149
|
+
this.app.send((0, messages_gen_js_1.SetCSSDataURLBased)(id, data, this.app.getBaseHref()));
|
|
153
150
|
return;
|
|
154
151
|
}
|
|
155
152
|
data = this.app.sanitizer.sanitize(id, data);
|
|
156
|
-
this.app.send(
|
|
153
|
+
this.app.send((0, messages_gen_js_1.SetNodeData)(id, data));
|
|
157
154
|
}
|
|
158
155
|
bindNode(node) {
|
|
159
156
|
const [id, isNew] = this.app.nodes.registerNode(node);
|
|
@@ -161,39 +158,42 @@ class Observer {
|
|
|
161
158
|
this.recents.set(id, RecentsType.New);
|
|
162
159
|
}
|
|
163
160
|
else if (this.recents.get(id) !== RecentsType.New) {
|
|
164
|
-
// can we do just `else` here?
|
|
165
161
|
this.recents.set(id, RecentsType.Removed);
|
|
166
162
|
}
|
|
167
163
|
}
|
|
168
|
-
|
|
169
|
-
const [id] = this.app.nodes.registerNode(node);
|
|
170
|
-
this.recents.set(id, RecentsType.RemovedChild);
|
|
171
|
-
}
|
|
172
|
-
bindTree(node, isChildUnbinding = false) {
|
|
164
|
+
bindTree(node) {
|
|
173
165
|
if (!isObservable(node)) {
|
|
174
166
|
return;
|
|
175
167
|
}
|
|
176
168
|
this.bindNode(node);
|
|
177
169
|
const walker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, {
|
|
178
|
-
acceptNode: (node) => isIgnored(node) ||
|
|
170
|
+
acceptNode: (node) => isIgnored(node) || this.app.nodes.getID(node) !== undefined
|
|
179
171
|
? NodeFilter.FILTER_REJECT
|
|
180
172
|
: NodeFilter.FILTER_ACCEPT,
|
|
181
173
|
},
|
|
182
174
|
// @ts-ignore
|
|
183
175
|
false);
|
|
184
176
|
while (walker.nextNode()) {
|
|
185
|
-
|
|
186
|
-
this.unbindChildNode(walker.currentNode);
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
this.bindNode(walker.currentNode);
|
|
190
|
-
}
|
|
177
|
+
this.bindNode(walker.currentNode);
|
|
191
178
|
}
|
|
192
179
|
}
|
|
193
|
-
|
|
180
|
+
unbindTree(node) {
|
|
194
181
|
const id = this.app.nodes.unregisterNode(node);
|
|
195
182
|
if (id !== undefined && this.recents.get(id) === RecentsType.Removed) {
|
|
196
|
-
|
|
183
|
+
// Sending RemoveNode only for parent to maintain
|
|
184
|
+
this.app.send((0, messages_gen_js_1.RemoveNode)(id));
|
|
185
|
+
// Unregistering all the children in order to clear the memory
|
|
186
|
+
const walker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, {
|
|
187
|
+
acceptNode: (node) => isIgnored(node) || this.app.nodes.getID(node) === undefined
|
|
188
|
+
? NodeFilter.FILTER_REJECT
|
|
189
|
+
: NodeFilter.FILTER_ACCEPT,
|
|
190
|
+
},
|
|
191
|
+
// @ts-ignore
|
|
192
|
+
false);
|
|
193
|
+
while (walker.nextNode()) {
|
|
194
|
+
this.app.nodes.unregisterNode(walker.currentNode);
|
|
195
|
+
}
|
|
196
|
+
// MBTODO: count and send RemovedNodesCount (for the page crash detection in heuristics)
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
// A top-consumption function on the infinite lists test. (~1% of performance resources)
|
|
@@ -209,17 +209,17 @@ class Observer {
|
|
|
209
209
|
if (!(0, guards_js_1.hasTag)(node, 'HTML') || !this.isTopContext) {
|
|
210
210
|
if (parent === null) {
|
|
211
211
|
// Sometimes one observation contains attribute mutations for the removimg node, which gets ignored here.
|
|
212
|
-
// That shouldn't affect the visual rendering ( should it? )
|
|
213
|
-
this.
|
|
212
|
+
// That shouldn't affect the visual rendering ( should it? maybe when transition applied? )
|
|
213
|
+
this.unbindTree(node);
|
|
214
214
|
return false;
|
|
215
215
|
}
|
|
216
216
|
parentID = this.app.nodes.getID(parent);
|
|
217
217
|
if (parentID === undefined) {
|
|
218
|
-
this.
|
|
218
|
+
this.unbindTree(node);
|
|
219
219
|
return false;
|
|
220
220
|
}
|
|
221
221
|
if (!this.commitNode(parentID)) {
|
|
222
|
-
this.
|
|
222
|
+
this.unbindTree(node);
|
|
223
223
|
return false;
|
|
224
224
|
}
|
|
225
225
|
this.app.sanitizer.handleNode(id, parentID, node);
|
|
@@ -258,7 +258,7 @@ class Observer {
|
|
|
258
258
|
el.style.width = width + 'px';
|
|
259
259
|
el.style.height = height + 'px';
|
|
260
260
|
}
|
|
261
|
-
this.app.send(
|
|
261
|
+
this.app.send((0, messages_gen_js_1.CreateElementNode)(id, parentID, index, el.tagName, (0, guards_js_1.isSVGElement)(node)));
|
|
262
262
|
}
|
|
263
263
|
for (let i = 0; i < el.attributes.length; i++) {
|
|
264
264
|
const attr = el.attributes[i];
|
|
@@ -267,13 +267,13 @@ class Observer {
|
|
|
267
267
|
}
|
|
268
268
|
else if ((0, guards_js_1.isTextNode)(node)) {
|
|
269
269
|
// for text node id != 0, hence parentID !== undefined and parent is Element
|
|
270
|
-
this.app.send(
|
|
270
|
+
this.app.send((0, messages_gen_js_1.CreateTextNode)(id, parentID, index));
|
|
271
271
|
this.sendNodeData(id, parent, node.data);
|
|
272
272
|
}
|
|
273
273
|
return true;
|
|
274
274
|
}
|
|
275
275
|
if (recentsType === RecentsType.Removed && parentID !== undefined) {
|
|
276
|
-
this.app.send(
|
|
276
|
+
this.app.send((0, messages_gen_js_1.MoveNode)(id, parentID, index));
|
|
277
277
|
}
|
|
278
278
|
const attr = this.attributesMap.get(id);
|
|
279
279
|
if (attr !== undefined) {
|
|
@@ -314,7 +314,8 @@ class Observer {
|
|
|
314
314
|
});
|
|
315
315
|
this.clear();
|
|
316
316
|
}
|
|
317
|
-
// ISSSUE
|
|
317
|
+
// ISSSUE (nodeToBinde should be the same as node. Look at the comment about 0-node at the beginning of the file.)
|
|
318
|
+
// TODO: use one observer instance for all iframes/shadowRoots (composition instiad of inheritance)
|
|
318
319
|
observeRoot(node, beforeCommit, nodeToBind = node) {
|
|
319
320
|
this.observer.observe(node, {
|
|
320
321
|
childList: true,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const observer_js_1 = require("./observer.js");
|
|
4
|
-
const
|
|
4
|
+
const messages_gen_js_1 = require("../messages.gen.js");
|
|
5
5
|
class ShadowRootObserver extends observer_js_1.default {
|
|
6
6
|
observe(el) {
|
|
7
7
|
const shRoot = el.shadowRoot;
|
|
@@ -14,7 +14,7 @@ class ShadowRootObserver extends observer_js_1.default {
|
|
|
14
14
|
console.log('OpenReplay: Shadow Root was not bound');
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
|
-
this.app.send((0,
|
|
17
|
+
this.app.send((0, messages_gen_js_1.CreateIFrameDocument)(hostID, rootID));
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
}
|
|
@@ -3,9 +3,19 @@ import App from '../index.js';
|
|
|
3
3
|
export interface Options {
|
|
4
4
|
captureIFrames: boolean;
|
|
5
5
|
}
|
|
6
|
+
declare type Context = Window & typeof globalThis;
|
|
7
|
+
declare type ContextCallback = (context: Context) => void;
|
|
8
|
+
declare type Offset = {
|
|
9
|
+
top: number;
|
|
10
|
+
left: number;
|
|
11
|
+
};
|
|
6
12
|
export default class TopObserver extends Observer {
|
|
7
13
|
private readonly options;
|
|
8
14
|
constructor(app: App, options: Partial<Options>);
|
|
15
|
+
private readonly contextCallbacks;
|
|
16
|
+
private readonly contextsSet;
|
|
17
|
+
attachContextCallback(cb: ContextCallback): void;
|
|
18
|
+
getDocumentOffset(doc: Document): Offset;
|
|
9
19
|
private iframeObservers;
|
|
10
20
|
private handleIframe;
|
|
11
21
|
private shadowRootObservers;
|
|
@@ -13,3 +23,4 @@ export default class TopObserver extends Observer {
|
|
|
13
23
|
observe(): void;
|
|
14
24
|
disconnect(): void;
|
|
15
25
|
}
|
|
26
|
+
export {};
|
|
@@ -4,12 +4,19 @@ const observer_js_1 = require("./observer.js");
|
|
|
4
4
|
const guards_js_1 = require("../guards.js");
|
|
5
5
|
const iframe_observer_js_1 = require("./iframe_observer.js");
|
|
6
6
|
const shadow_root_observer_js_1 = require("./shadow_root_observer.js");
|
|
7
|
-
const
|
|
7
|
+
const messages_gen_js_1 = require("../messages.gen.js");
|
|
8
8
|
const utils_js_1 = require("../../utils.js");
|
|
9
|
+
function isPatchedDocument(doc) {
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
return typeof doc.__openreplay__getOffset === 'function';
|
|
12
|
+
}
|
|
9
13
|
const attachShadowNativeFn = utils_js_1.IN_BROWSER ? Element.prototype.attachShadow : () => new ShadowRoot();
|
|
10
14
|
class TopObserver extends observer_js_1.default {
|
|
11
15
|
constructor(app, options) {
|
|
12
16
|
super(app, true);
|
|
17
|
+
this.contextCallbacks = [];
|
|
18
|
+
// Attached once per Tracker instance
|
|
19
|
+
this.contextsSet = new Set();
|
|
13
20
|
this.iframeObservers = [];
|
|
14
21
|
this.shadowRootObservers = [];
|
|
15
22
|
this.options = Object.assign({
|
|
@@ -30,23 +37,50 @@ class TopObserver extends observer_js_1.default {
|
|
|
30
37
|
}
|
|
31
38
|
});
|
|
32
39
|
}
|
|
40
|
+
attachContextCallback(cb) {
|
|
41
|
+
this.contextCallbacks.push(cb);
|
|
42
|
+
}
|
|
43
|
+
// Le truc
|
|
44
|
+
getDocumentOffset(doc) {
|
|
45
|
+
if (isPatchedDocument(doc)) {
|
|
46
|
+
return doc.__openreplay__getOffset();
|
|
47
|
+
}
|
|
48
|
+
return { top: 0, left: 0 };
|
|
49
|
+
}
|
|
33
50
|
handleIframe(iframe) {
|
|
34
51
|
let doc = null;
|
|
52
|
+
let win = null;
|
|
35
53
|
const handle = this.app.safe(() => {
|
|
36
54
|
const id = this.app.nodes.getID(iframe);
|
|
37
55
|
if (id === undefined) {
|
|
56
|
+
//log
|
|
38
57
|
return;
|
|
39
|
-
} //log
|
|
40
|
-
if (iframe.contentDocument === doc) {
|
|
41
|
-
return;
|
|
42
|
-
} // How frequently can it happen?
|
|
43
|
-
doc = iframe.contentDocument;
|
|
44
|
-
if (!doc || !iframe.contentWindow) {
|
|
45
|
-
return;
|
|
46
58
|
}
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
59
|
+
const currentWin = iframe.contentWindow;
|
|
60
|
+
const currentDoc = iframe.contentDocument;
|
|
61
|
+
if (currentDoc && currentDoc !== doc) {
|
|
62
|
+
const observer = new iframe_observer_js_1.default(this.app);
|
|
63
|
+
this.iframeObservers.push(observer);
|
|
64
|
+
observer.observe(iframe);
|
|
65
|
+
doc = currentDoc;
|
|
66
|
+
doc.__openreplay__getOffset = () => {
|
|
67
|
+
const { top, left } = this.getDocumentOffset(iframe.ownerDocument);
|
|
68
|
+
return {
|
|
69
|
+
top: iframe.offsetTop + top,
|
|
70
|
+
left: iframe.offsetLeft + left,
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (currentWin &&
|
|
75
|
+
// Sometimes currentWin.window is null (not in specification). Such window object is not functional
|
|
76
|
+
currentWin === currentWin.window &&
|
|
77
|
+
!this.contextsSet.has(currentWin) // for each context callbacks called once per Tracker (TopObserver) instance
|
|
78
|
+
) {
|
|
79
|
+
this.contextsSet.add(currentWin);
|
|
80
|
+
//@ts-ignore https://github.com/microsoft/TypeScript/issues/41684
|
|
81
|
+
this.contextCallbacks.forEach((cb) => cb(currentWin));
|
|
82
|
+
win = currentWin;
|
|
83
|
+
}
|
|
50
84
|
});
|
|
51
85
|
iframe.addEventListener('load', handle); // why app.attachEventListener not working?
|
|
52
86
|
handle();
|
|
@@ -72,7 +106,7 @@ class TopObserver extends observer_js_1.default {
|
|
|
72
106
|
// the 0-node ("fRoot") will become #document rather than documentElement as it is now.
|
|
73
107
|
// Alternatively - observe(#document) then bindNode(documentElement)
|
|
74
108
|
this.observeRoot(window.document, () => {
|
|
75
|
-
this.app.send(
|
|
109
|
+
this.app.send((0, messages_gen_js_1.CreateDocument)());
|
|
76
110
|
}, window.document.documentElement);
|
|
77
111
|
}
|
|
78
112
|
disconnect() {
|
package/cjs/app/session.d.ts
CHANGED
|
@@ -1,19 +1,37 @@
|
|
|
1
|
+
import type App from './index.js';
|
|
1
2
|
interface SessionInfo {
|
|
2
|
-
sessionID: string |
|
|
3
|
+
sessionID: string | undefined;
|
|
3
4
|
metadata: Record<string, string>;
|
|
4
5
|
userID: string | null;
|
|
6
|
+
timestamp: number;
|
|
7
|
+
projectID?: string;
|
|
5
8
|
}
|
|
6
9
|
declare type OnUpdateCallback = (i: Partial<SessionInfo>) => void;
|
|
10
|
+
export declare type Options = {
|
|
11
|
+
session_token_key: string;
|
|
12
|
+
session_pageno_key: string;
|
|
13
|
+
};
|
|
7
14
|
export default class Session {
|
|
15
|
+
private readonly app;
|
|
16
|
+
private readonly options;
|
|
8
17
|
private metadata;
|
|
9
18
|
private userID;
|
|
10
19
|
private sessionID;
|
|
11
20
|
private readonly callbacks;
|
|
21
|
+
private timestamp;
|
|
22
|
+
private projectID;
|
|
23
|
+
constructor(app: App, options: Options);
|
|
12
24
|
attachUpdateCallback(cb: OnUpdateCallback): void;
|
|
13
25
|
private handleUpdate;
|
|
14
26
|
update(newInfo: Partial<SessionInfo>): void;
|
|
15
27
|
setMetadata(key: string, value: string): void;
|
|
16
28
|
setUserID(userID: string): void;
|
|
29
|
+
private getPageNumber;
|
|
30
|
+
incPageNo(): number;
|
|
31
|
+
getSessionToken(): string | undefined;
|
|
32
|
+
setSessionToken(token: string): void;
|
|
33
|
+
applySessionHash(hash: string): void;
|
|
34
|
+
getSessionHash(): string | undefined;
|
|
17
35
|
getInfo(): SessionInfo;
|
|
18
36
|
reset(): void;
|
|
19
37
|
}
|
package/cjs/app/session.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
class Session {
|
|
4
|
-
constructor() {
|
|
4
|
+
constructor(app, options) {
|
|
5
|
+
this.app = app;
|
|
6
|
+
this.options = options;
|
|
5
7
|
this.metadata = {};
|
|
6
8
|
this.userID = null;
|
|
7
|
-
this.sessionID = null;
|
|
8
9
|
this.callbacks = [];
|
|
10
|
+
this.timestamp = 0;
|
|
9
11
|
}
|
|
10
12
|
attachUpdateCallback(cb) {
|
|
11
13
|
this.callbacks.push(cb);
|
|
@@ -30,6 +32,12 @@ class Session {
|
|
|
30
32
|
if (newInfo.sessionID !== undefined) {
|
|
31
33
|
this.sessionID = newInfo.sessionID;
|
|
32
34
|
}
|
|
35
|
+
if (newInfo.timestamp !== undefined) {
|
|
36
|
+
this.timestamp = newInfo.timestamp;
|
|
37
|
+
}
|
|
38
|
+
if (newInfo.projectID !== undefined) {
|
|
39
|
+
this.projectID = newInfo.projectID;
|
|
40
|
+
}
|
|
33
41
|
this.handleUpdate(newInfo);
|
|
34
42
|
}
|
|
35
43
|
setMetadata(key, value) {
|
|
@@ -40,17 +48,67 @@ class Session {
|
|
|
40
48
|
this.userID = userID;
|
|
41
49
|
this.handleUpdate({ userID });
|
|
42
50
|
}
|
|
51
|
+
getPageNumber() {
|
|
52
|
+
const pageNoStr = this.app.sessionStorage.getItem(this.options.session_pageno_key);
|
|
53
|
+
if (pageNoStr == null) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
return parseInt(pageNoStr);
|
|
57
|
+
}
|
|
58
|
+
incPageNo() {
|
|
59
|
+
let pageNo = this.getPageNumber();
|
|
60
|
+
if (pageNo === undefined) {
|
|
61
|
+
pageNo = 0;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
pageNo++;
|
|
65
|
+
}
|
|
66
|
+
this.app.sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
|
|
67
|
+
return pageNo;
|
|
68
|
+
}
|
|
69
|
+
getSessionToken() {
|
|
70
|
+
return this.app.sessionStorage.getItem(this.options.session_token_key) || undefined;
|
|
71
|
+
}
|
|
72
|
+
setSessionToken(token) {
|
|
73
|
+
this.app.sessionStorage.setItem(this.options.session_token_key, token);
|
|
74
|
+
}
|
|
75
|
+
applySessionHash(hash) {
|
|
76
|
+
const hashParts = decodeURI(hash).split('&');
|
|
77
|
+
let token = hash;
|
|
78
|
+
let pageNoStr = '100500'; // back-compat for sessionToken
|
|
79
|
+
if (hashParts.length == 2) {
|
|
80
|
+
;
|
|
81
|
+
[token, pageNoStr] = hashParts;
|
|
82
|
+
}
|
|
83
|
+
if (!pageNoStr || !token) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.app.sessionStorage.setItem(this.options.session_token_key, token);
|
|
87
|
+
this.app.sessionStorage.setItem(this.options.session_pageno_key, pageNoStr);
|
|
88
|
+
}
|
|
89
|
+
getSessionHash() {
|
|
90
|
+
const pageNo = this.getPageNumber();
|
|
91
|
+
const token = this.getSessionToken();
|
|
92
|
+
if (pageNo === undefined || token === undefined) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
return encodeURI(String(pageNo) + '&' + token);
|
|
96
|
+
}
|
|
43
97
|
getInfo() {
|
|
44
98
|
return {
|
|
45
99
|
sessionID: this.sessionID,
|
|
46
100
|
metadata: this.metadata,
|
|
47
101
|
userID: this.userID,
|
|
102
|
+
timestamp: this.timestamp,
|
|
103
|
+
projectID: this.projectID,
|
|
48
104
|
};
|
|
49
105
|
}
|
|
50
106
|
reset() {
|
|
107
|
+
this.app.sessionStorage.removeItem(this.options.session_token_key);
|
|
51
108
|
this.metadata = {};
|
|
52
109
|
this.userID = null;
|
|
53
|
-
this.sessionID =
|
|
110
|
+
this.sessionID = undefined;
|
|
111
|
+
this.timestamp = 0;
|
|
54
112
|
}
|
|
55
113
|
}
|
|
56
114
|
exports.default = Session;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Message from './messages.gen.js';
|
|
1
2
|
export interface Options {
|
|
2
3
|
connAttemptCount?: number;
|
|
3
4
|
connAttemptGap?: number;
|
|
@@ -7,13 +8,12 @@ declare type Start = {
|
|
|
7
8
|
ingestPoint: string;
|
|
8
9
|
pageNo: number;
|
|
9
10
|
timestamp: number;
|
|
11
|
+
url: string;
|
|
10
12
|
} & Options;
|
|
11
13
|
declare type Auth = {
|
|
12
14
|
type: 'auth';
|
|
13
15
|
token: string;
|
|
14
16
|
beaconSizeLimit?: number;
|
|
15
17
|
};
|
|
16
|
-
export declare type WorkerMessageData = null | 'stop' | Start | Auth | Array<
|
|
17
|
-
_id: number;
|
|
18
|
-
}>;
|
|
18
|
+
export declare type WorkerMessageData = null | 'stop' | Start | Auth | Array<Message>;
|
|
19
19
|
export {};
|
|
File without changes
|