@openreplay/tracker 3.6.1 → 3.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/LICENSE +1 -1
  2. package/cjs/app/guards.d.ts +1 -2
  3. package/cjs/app/guards.js +3 -6
  4. package/cjs/app/index.d.ts +23 -28
  5. package/cjs/app/index.js +86 -107
  6. package/cjs/app/logger.js +3 -6
  7. package/cjs/app/nodes.d.ts +1 -1
  8. package/cjs/app/nodes.js +0 -2
  9. package/cjs/app/observer/iframe_observer.d.ts +1 -1
  10. package/cjs/app/observer/iframe_observer.js +3 -3
  11. package/cjs/app/observer/observer.d.ts +3 -2
  12. package/cjs/app/observer/observer.js +52 -50
  13. package/cjs/app/observer/shadow_root_observer.d.ts +1 -1
  14. package/cjs/app/observer/shadow_root_observer.js +3 -3
  15. package/cjs/app/observer/top_observer.d.ts +2 -13
  16. package/cjs/app/observer/top_observer.js +23 -58
  17. package/cjs/app/sanitizer.d.ts +1 -1
  18. package/cjs/app/sanitizer.js +5 -5
  19. package/cjs/app/session.d.ts +2 -20
  20. package/cjs/app/session.js +6 -65
  21. package/cjs/app/ticker.d.ts +1 -1
  22. package/cjs/common/messages.d.ts +444 -0
  23. package/cjs/common/messages.js +794 -0
  24. package/cjs/common/types.d.ts +9 -0
  25. package/cjs/common/{interaction.js → types.js} +0 -0
  26. package/cjs/common/{interaction.d.ts → webworker.d.ts} +5 -5
  27. package/cjs/common/{messages.gen.js → webworker.js} +0 -1
  28. package/cjs/index.d.ts +9 -10
  29. package/cjs/index.js +36 -47
  30. package/cjs/modules/connection.d.ts +1 -1
  31. package/cjs/modules/connection.js +2 -2
  32. package/cjs/modules/console.d.ts +1 -1
  33. package/cjs/modules/console.js +21 -7
  34. package/cjs/modules/cssrules.d.ts +1 -1
  35. package/cjs/modules/cssrules.js +14 -18
  36. package/cjs/modules/exception.d.ts +3 -3
  37. package/cjs/modules/exception.js +18 -23
  38. package/cjs/modules/img.d.ts +1 -1
  39. package/cjs/modules/img.js +26 -39
  40. package/cjs/modules/input.d.ts +1 -1
  41. package/cjs/modules/input.js +21 -21
  42. package/cjs/modules/longtasks.d.ts +2 -0
  43. package/cjs/modules/longtasks.js +26 -0
  44. package/cjs/modules/mouse.d.ts +1 -1
  45. package/cjs/modules/mouse.js +43 -50
  46. package/cjs/modules/performance.d.ts +1 -1
  47. package/cjs/modules/performance.js +2 -2
  48. package/cjs/modules/scroll.d.ts +1 -1
  49. package/cjs/modules/scroll.js +7 -16
  50. package/cjs/modules/timing.d.ts +1 -1
  51. package/cjs/modules/timing.js +26 -14
  52. package/cjs/modules/viewport.d.ts +1 -1
  53. package/cjs/modules/viewport.js +4 -4
  54. package/cjs/utils.js +7 -7
  55. package/cjs/vendors/finder/finder.js +48 -53
  56. package/lib/app/guards.d.ts +1 -2
  57. package/lib/app/guards.js +2 -4
  58. package/lib/app/index.d.ts +23 -28
  59. package/lib/app/index.js +94 -115
  60. package/lib/app/logger.js +3 -6
  61. package/lib/app/nodes.d.ts +1 -1
  62. package/lib/app/nodes.js +0 -2
  63. package/lib/app/observer/iframe_observer.d.ts +1 -1
  64. package/lib/app/observer/iframe_observer.js +3 -3
  65. package/lib/app/observer/observer.d.ts +3 -2
  66. package/lib/app/observer/observer.js +53 -51
  67. package/lib/app/observer/shadow_root_observer.d.ts +1 -1
  68. package/lib/app/observer/shadow_root_observer.js +3 -3
  69. package/lib/app/observer/top_observer.d.ts +2 -13
  70. package/lib/app/observer/top_observer.js +27 -62
  71. package/lib/app/sanitizer.d.ts +1 -1
  72. package/lib/app/sanitizer.js +7 -7
  73. package/lib/app/session.d.ts +2 -20
  74. package/lib/app/session.js +6 -65
  75. package/lib/app/ticker.d.ts +1 -1
  76. package/lib/common/messages.d.ts +444 -0
  77. package/lib/common/messages.js +790 -0
  78. package/lib/common/tsconfig.tsbuildinfo +1 -1
  79. package/lib/common/types.d.ts +9 -0
  80. package/lib/common/{interaction.js → types.js} +0 -0
  81. package/lib/common/{interaction.d.ts → webworker.d.ts} +5 -5
  82. package/lib/common/webworker.js +1 -0
  83. package/lib/index.d.ts +9 -10
  84. package/lib/index.js +49 -60
  85. package/lib/modules/connection.d.ts +1 -1
  86. package/lib/modules/connection.js +2 -2
  87. package/lib/modules/console.d.ts +1 -1
  88. package/lib/modules/console.js +22 -8
  89. package/lib/modules/cssrules.d.ts +1 -1
  90. package/lib/modules/cssrules.js +15 -19
  91. package/lib/modules/exception.d.ts +3 -3
  92. package/lib/modules/exception.js +18 -23
  93. package/lib/modules/img.d.ts +1 -1
  94. package/lib/modules/img.js +28 -41
  95. package/lib/modules/input.d.ts +1 -1
  96. package/lib/modules/input.js +23 -23
  97. package/lib/modules/longtasks.d.ts +2 -0
  98. package/lib/modules/longtasks.js +23 -0
  99. package/lib/modules/mouse.d.ts +1 -1
  100. package/lib/modules/mouse.js +46 -53
  101. package/lib/modules/performance.d.ts +1 -1
  102. package/lib/modules/performance.js +3 -3
  103. package/lib/modules/scroll.d.ts +1 -1
  104. package/lib/modules/scroll.js +8 -17
  105. package/lib/modules/timing.d.ts +1 -1
  106. package/lib/modules/timing.js +28 -16
  107. package/lib/modules/viewport.d.ts +1 -1
  108. package/lib/modules/viewport.js +4 -4
  109. package/lib/utils.js +7 -7
  110. package/lib/vendors/finder/finder.js +48 -53
  111. package/package.json +10 -27
  112. package/.eslintignore +0 -8
  113. package/.prettierignore +0 -1
  114. package/cjs/app/messages.d.ts +0 -52
  115. package/cjs/app/messages.gen.d.ts +0 -57
  116. package/cjs/app/messages.gen.js +0 -493
  117. package/cjs/app/messages.js +0 -234
  118. package/cjs/common/messages.gen.d.ts +0 -382
  119. package/cjs/modules/adoptedStyleSheets.d.ts +0 -2
  120. package/cjs/modules/adoptedStyleSheets.js +0 -127
  121. package/lib/app/messages.d.ts +0 -52
  122. package/lib/app/messages.gen.d.ts +0 -57
  123. package/lib/app/messages.gen.js +0 -434
  124. package/lib/app/messages.js +0 -181
  125. package/lib/common/messages.gen.d.ts +0 -382
  126. package/lib/common/messages.gen.js +0 -2
  127. package/lib/modules/adoptedStyleSheets.d.ts +0 -2
  128. package/lib/modules/adoptedStyleSheets.js +0 -124
package/cjs/app/logger.js CHANGED
@@ -13,12 +13,9 @@ function IsCustomLevel(l) {
13
13
  }
14
14
  class Logger {
15
15
  constructor(options = exports.LogLevel.Silent) {
16
- this.options =
17
- options === true
18
- ? { level: exports.LogLevel.Verbose }
19
- : typeof options === 'number'
20
- ? { level: options }
21
- : options;
16
+ this.options = options === true
17
+ ? { level: exports.LogLevel.Verbose }
18
+ : typeof options === "number" ? { level: options } : options;
22
19
  }
23
20
  log(...args) {
24
21
  if (IsCustomLevel(this.options.level)
@@ -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:*/ number, /*isNew:*/ boolean];
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,11 +7,9 @@ class Nodes {
7
7
  this.nodeCallbacks = [];
8
8
  this.elementListeners = new Map();
9
9
  }
10
- // Attached once per Tracker instance
11
10
  attachNodeCallback(nodeCallback) {
12
11
  this.nodeCallbacks.push(nodeCallback);
13
12
  }
14
- // TODO: what is the difference with app.attachEventListener. can we use only one of those?
15
13
  attachElementListener(type, node, elementListener) {
16
14
  const id = this.getID(node);
17
15
  if (id === undefined) {
@@ -1,4 +1,4 @@
1
- import Observer from './observer.js';
1
+ import Observer from "./observer.js";
2
2
  export default class IFrameObserver extends Observer {
3
3
  observe(iframe: HTMLIFrameElement): void;
4
4
  }
@@ -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 messages_gen_js_1 = require("../messages.gen.js");
4
+ const messages_js_1 = require("../../common/messages.js");
5
5
  class IFrameObserver extends observer_js_1.default {
6
6
  observe(iframe) {
7
7
  const doc = iframe.contentDocument;
@@ -12,10 +12,10 @@ class IFrameObserver extends observer_js_1.default {
12
12
  // Have to observe document, because the inner <html> might be changed
13
13
  this.observeRoot(doc, (docID) => {
14
14
  if (docID === undefined) {
15
- console.log('OpenReplay: Iframe document not bound');
15
+ console.log("OpenReplay: Iframe document not bound");
16
16
  return;
17
17
  }
18
- this.app.send((0, messages_gen_js_1.CreateIFrameDocument)(hostID, docID));
18
+ this.app.send((0, messages_js_1.CreateIFrameDocument)(hostID, docID));
19
19
  });
20
20
  }
21
21
  }
@@ -1,4 +1,4 @@
1
- import App from '../index.js';
1
+ import App from "../index.js";
2
2
  export default abstract class Observer {
3
3
  protected readonly app: App;
4
4
  protected readonly isTopContext: boolean;
@@ -13,8 +13,9 @@ export default abstract class Observer {
13
13
  private sendNodeAttribute;
14
14
  private sendNodeData;
15
15
  private bindNode;
16
+ private unbindChildNode;
16
17
  private bindTree;
17
- private unbindTree;
18
+ private unbindNode;
18
19
  private _commitNode;
19
20
  private commitNode;
20
21
  private commitNodes;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const messages_gen_js_1 = require("../messages.gen.js");
3
+ const messages_js_1 = require("../../common/messages.js");
4
4
  const guards_js_1 = require("../guards.js");
5
5
  function isIgnored(node) {
6
6
  if ((0, guards_js_1.isTextNode)(node)) {
@@ -13,9 +13,13 @@ function isIgnored(node) {
13
13
  if (tag === 'LINK') {
14
14
  const rel = node.getAttribute('rel');
15
15
  const as = node.getAttribute('as');
16
- return !((rel === null || rel === void 0 ? void 0 : rel.includes('stylesheet')) || as === 'style' || as === 'font');
16
+ return !((rel === null || rel === void 0 ? void 0 : rel.includes('stylesheet')) || as === "style" || as === "font");
17
17
  }
18
- return (tag === 'SCRIPT' || tag === 'NOSCRIPT' || tag === 'META' || tag === 'TITLE' || tag === 'BASE');
18
+ return (tag === 'SCRIPT' ||
19
+ tag === 'NOSCRIPT' ||
20
+ tag === 'META' ||
21
+ tag === 'TITLE' ||
22
+ tag === 'BASE');
19
23
  }
20
24
  function isObservable(node) {
21
25
  if ((0, guards_js_1.isRootNode)(node)) {
@@ -28,11 +32,17 @@ function isObservable(node) {
28
32
  - fix unbinding logic + send all removals first (ensure sequence is correct)
29
33
  - use document as a 0-node in the upper context (should be updated in player at first)
30
34
  */
35
+ /*
36
+ Nikita:
37
+ - rn we only send unbind event for parent (all child nodes will be cut in the live replay anyways)
38
+ to prevent sending 1k+ unbinds for child nodes and making replay file bigger than it should be
39
+ */
31
40
  var RecentsType;
32
41
  (function (RecentsType) {
33
42
  RecentsType[RecentsType["New"] = 0] = "New";
34
43
  RecentsType[RecentsType["Removed"] = 1] = "Removed";
35
44
  RecentsType[RecentsType["Changed"] = 2] = "Changed";
45
+ RecentsType[RecentsType["RemovedChild"] = 3] = "RemovedChild";
36
46
  })(RecentsType || (RecentsType = {}));
37
47
  class Observer {
38
48
  constructor(app, isTopContext = false) {
@@ -44,8 +54,7 @@ class Observer {
44
54
  this.attributesMap = new Map();
45
55
  this.textSet = new Set();
46
56
  this.observer = new MutationObserver(this.app.safe((mutations) => {
47
- for (const mutation of mutations) {
48
- // mutations order is sequential
57
+ for (const mutation of mutations) { // mutations order is sequential
49
58
  const target = mutation.target;
50
59
  const type = mutation.type;
51
60
  if (!isObservable(target)) {
@@ -53,10 +62,7 @@ class Observer {
53
62
  }
54
63
  if (type === 'childList') {
55
64
  for (let i = 0; i < mutation.removedNodes.length; i++) {
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
- }
65
+ this.bindTree(mutation.removedNodes[i], true);
60
66
  }
61
67
  for (let i = 0; i < mutation.addedNodes.length; i++) {
62
68
  this.bindTree(mutation.addedNodes[i]);
@@ -77,7 +83,7 @@ class Observer {
77
83
  }
78
84
  let attr = this.attributesMap.get(id);
79
85
  if (attr === undefined) {
80
- this.attributesMap.set(id, (attr = new Set()));
86
+ this.attributesMap.set(id, attr = new Set());
81
87
  }
82
88
  attr.add(name);
83
89
  continue;
@@ -103,16 +109,16 @@ class Observer {
103
109
  name = name.substr(6);
104
110
  }
105
111
  if (value === null) {
106
- this.app.send((0, messages_gen_js_1.RemoveNodeAttribute)(id, name));
112
+ this.app.send(new messages_js_1.RemoveNodeAttribute(id, name));
107
113
  }
108
114
  else if (name === 'href') {
109
115
  if (value.length > 1e5) {
110
116
  value = '';
111
117
  }
112
- this.app.send((0, messages_gen_js_1.SetNodeAttributeURLBased)(id, name, value, this.app.getBaseHref()));
118
+ this.app.send(new messages_js_1.SetNodeAttributeURLBased(id, name, value, this.app.getBaseHref()));
113
119
  }
114
120
  else {
115
- this.app.send((0, messages_gen_js_1.SetNodeAttribute)(id, name, value));
121
+ this.app.send(new messages_js_1.SetNodeAttribute(id, name, value));
116
122
  }
117
123
  return;
118
124
  }
@@ -125,75 +131,72 @@ class Observer {
125
131
  return;
126
132
  }
127
133
  if (name === 'value' &&
128
- (0, guards_js_1.hasTag)(node, 'INPUT') &&
134
+ (0, guards_js_1.hasTag)(node, "INPUT") &&
129
135
  node.type !== 'button' &&
130
136
  node.type !== 'reset' &&
131
137
  node.type !== 'submit') {
132
138
  return;
133
139
  }
134
140
  if (value === null) {
135
- this.app.send((0, messages_gen_js_1.RemoveNodeAttribute)(id, name));
141
+ this.app.send(new messages_js_1.RemoveNodeAttribute(id, name));
136
142
  return;
137
143
  }
138
- if (name === 'style' || (name === 'href' && (0, guards_js_1.hasTag)(node, 'LINK'))) {
139
- this.app.send((0, messages_gen_js_1.SetNodeAttributeURLBased)(id, name, value, this.app.getBaseHref()));
144
+ if (name === 'style' || name === 'href' && (0, guards_js_1.hasTag)(node, "LINK")) {
145
+ this.app.send(new messages_js_1.SetNodeAttributeURLBased(id, name, value, this.app.getBaseHref()));
140
146
  return;
141
147
  }
142
148
  if (name === 'href' || value.length > 1e5) {
143
149
  value = '';
144
150
  }
145
- this.app.send((0, messages_gen_js_1.SetNodeAttribute)(id, name, value));
151
+ this.app.send(new messages_js_1.SetNodeAttribute(id, name, value));
146
152
  }
147
153
  sendNodeData(id, parentElement, data) {
148
- if ((0, guards_js_1.hasTag)(parentElement, 'STYLE') || (0, guards_js_1.hasTag)(parentElement, 'style')) {
149
- this.app.send((0, messages_gen_js_1.SetCSSDataURLBased)(id, data, this.app.getBaseHref()));
154
+ if ((0, guards_js_1.hasTag)(parentElement, "STYLE") || (0, guards_js_1.hasTag)(parentElement, "style")) {
155
+ this.app.send(new messages_js_1.SetCSSDataURLBased(id, data, this.app.getBaseHref()));
150
156
  return;
151
157
  }
152
158
  data = this.app.sanitizer.sanitize(id, data);
153
- this.app.send((0, messages_gen_js_1.SetNodeData)(id, data));
159
+ this.app.send(new messages_js_1.SetNodeData(id, data));
154
160
  }
155
161
  bindNode(node) {
156
162
  const [id, isNew] = this.app.nodes.registerNode(node);
157
163
  if (isNew) {
158
164
  this.recents.set(id, RecentsType.New);
159
165
  }
160
- else if (this.recents.get(id) !== RecentsType.New) {
166
+ else if (this.recents.get(id) !== RecentsType.New) { // can we do just `else` here?
161
167
  this.recents.set(id, RecentsType.Removed);
162
168
  }
163
169
  }
164
- bindTree(node) {
170
+ unbindChildNode(node) {
171
+ const [id] = this.app.nodes.registerNode(node);
172
+ this.recents.set(id, RecentsType.RemovedChild);
173
+ }
174
+ bindTree(node, isChildUnbinding = false) {
165
175
  if (!isObservable(node)) {
166
176
  return;
167
177
  }
168
178
  this.bindNode(node);
169
179
  const walker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, {
170
- acceptNode: (node) => isIgnored(node) || this.app.nodes.getID(node) !== undefined
180
+ acceptNode: (node) => isIgnored(node)
181
+ || (this.app.nodes.getID(node) !== undefined && !isChildUnbinding)
171
182
  ? NodeFilter.FILTER_REJECT
172
183
  : NodeFilter.FILTER_ACCEPT,
173
184
  },
174
185
  // @ts-ignore
175
186
  false);
176
187
  while (walker.nextNode()) {
177
- this.bindNode(walker.currentNode);
188
+ if (isChildUnbinding) {
189
+ this.unbindChildNode(walker.currentNode);
190
+ }
191
+ else {
192
+ this.bindNode(walker.currentNode);
193
+ }
178
194
  }
179
195
  }
180
- unbindTree(node) {
196
+ unbindNode(node) {
181
197
  const id = this.app.nodes.unregisterNode(node);
182
198
  if (id !== undefined && this.recents.get(id) === RecentsType.Removed) {
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)
199
+ this.app.send(new messages_js_1.RemoveNode(id));
197
200
  }
198
201
  }
199
202
  // A top-consumption function on the infinite lists test. (~1% of performance resources)
@@ -206,20 +209,20 @@ class Observer {
206
209
  // Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
207
210
  // TODO: get rid of "special" cases (there is an issue with CreateDocument altered behaviour though)
208
211
  // TODO: Clean the logic (though now it workd fine)
209
- if (!(0, guards_js_1.hasTag)(node, 'HTML') || !this.isTopContext) {
212
+ if (!(0, guards_js_1.hasTag)(node, "HTML") || !this.isTopContext) {
210
213
  if (parent === null) {
211
214
  // Sometimes one observation contains attribute mutations for the removimg node, which gets ignored here.
212
- // That shouldn't affect the visual rendering ( should it? maybe when transition applied? )
213
- this.unbindTree(node);
215
+ // That shouldn't affect the visual rendering ( should it? )
216
+ this.unbindNode(node);
214
217
  return false;
215
218
  }
216
219
  parentID = this.app.nodes.getID(parent);
217
220
  if (parentID === undefined) {
218
- this.unbindTree(node);
221
+ this.unbindNode(node);
219
222
  return false;
220
223
  }
221
224
  if (!this.commitNode(parentID)) {
222
- this.unbindTree(node);
225
+ this.unbindNode(node);
223
226
  return false;
224
227
  }
225
228
  this.app.sanitizer.handleNode(id, parentID, node);
@@ -258,7 +261,7 @@ class Observer {
258
261
  el.style.width = width + 'px';
259
262
  el.style.height = height + 'px';
260
263
  }
261
- this.app.send((0, messages_gen_js_1.CreateElementNode)(id, parentID, index, el.tagName, (0, guards_js_1.isSVGElement)(node)));
264
+ this.app.send(new messages_js_1.CreateElementNode(id, parentID, index, el.tagName, (0, guards_js_1.isSVGElement)(node)));
262
265
  }
263
266
  for (let i = 0; i < el.attributes.length; i++) {
264
267
  const attr = el.attributes[i];
@@ -267,13 +270,13 @@ class Observer {
267
270
  }
268
271
  else if ((0, guards_js_1.isTextNode)(node)) {
269
272
  // for text node id != 0, hence parentID !== undefined and parent is Element
270
- this.app.send((0, messages_gen_js_1.CreateTextNode)(id, parentID, index));
273
+ this.app.send(new messages_js_1.CreateTextNode(id, parentID, index));
271
274
  this.sendNodeData(id, parent, node.data);
272
275
  }
273
276
  return true;
274
277
  }
275
278
  if (recentsType === RecentsType.Removed && parentID !== undefined) {
276
- this.app.send((0, messages_gen_js_1.MoveNode)(id, parentID, index));
279
+ this.app.send(new messages_js_1.MoveNode(id, parentID, index));
277
280
  }
278
281
  const attr = this.attributesMap.get(id);
279
282
  if (attr !== undefined) {
@@ -314,8 +317,7 @@ class Observer {
314
317
  });
315
318
  this.clear();
316
319
  }
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)
320
+ // ISSSUE
319
321
  observeRoot(node, beforeCommit, nodeToBind = node) {
320
322
  this.observer.observe(node, {
321
323
  childList: true,
@@ -1,4 +1,4 @@
1
- import Observer from './observer.js';
1
+ import Observer from "./observer.js";
2
2
  export default class ShadowRootObserver extends Observer {
3
3
  observe(el: Element): void;
4
4
  }
@@ -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 messages_gen_js_1 = require("../messages.gen.js");
4
+ const messages_js_1 = require("../../common/messages.js");
5
5
  class ShadowRootObserver extends observer_js_1.default {
6
6
  observe(el) {
7
7
  const shRoot = el.shadowRoot;
@@ -11,10 +11,10 @@ class ShadowRootObserver extends observer_js_1.default {
11
11
  } // log
12
12
  this.observeRoot(shRoot, (rootID) => {
13
13
  if (rootID === undefined) {
14
- console.log('OpenReplay: Shadow Root was not bound');
14
+ console.log("OpenReplay: Shadow Root was not bound");
15
15
  return;
16
16
  }
17
- this.app.send((0, messages_gen_js_1.CreateIFrameDocument)(hostID, rootID));
17
+ this.app.send((0, messages_js_1.CreateIFrameDocument)(hostID, rootID));
18
18
  });
19
19
  }
20
20
  }
@@ -1,21 +1,11 @@
1
- import Observer from './observer.js';
2
- import App from '../index.js';
1
+ import Observer from "./observer.js";
2
+ 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
- };
12
6
  export default class TopObserver extends Observer {
13
7
  private readonly options;
14
8
  constructor(app: App, options: Partial<Options>);
15
- private readonly contextCallbacks;
16
- private readonly contextsSet;
17
- attachContextCallback(cb: ContextCallback): void;
18
- getDocumentOffset(doc: Document): Offset;
19
9
  private iframeObservers;
20
10
  private handleIframe;
21
11
  private shadowRootObservers;
@@ -23,4 +13,3 @@ export default class TopObserver extends Observer {
23
13
  observe(): void;
24
14
  disconnect(): void;
25
15
  }
26
- export {};
@@ -4,85 +4,51 @@ 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 messages_gen_js_1 = require("../messages.gen.js");
7
+ const messages_js_1 = require("../../common/messages.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
- }
13
9
  const attachShadowNativeFn = utils_js_1.IN_BROWSER ? Element.prototype.attachShadow : () => new ShadowRoot();
14
10
  class TopObserver extends observer_js_1.default {
15
11
  constructor(app, options) {
16
12
  super(app, true);
17
- this.contextCallbacks = [];
18
- // Attached once per Tracker instance
19
- this.contextsSet = new Set();
20
13
  this.iframeObservers = [];
21
14
  this.shadowRootObservers = [];
22
15
  this.options = Object.assign({
23
- captureIFrames: true,
16
+ captureIFrames: true
24
17
  }, options);
25
18
  // IFrames
26
- this.app.nodes.attachNodeCallback((node) => {
27
- if ((0, guards_js_1.hasTag)(node, 'IFRAME') &&
28
- ((this.options.captureIFrames && !(0, utils_js_1.hasOpenreplayAttribute)(node, 'obscured')) ||
29
- (0, utils_js_1.hasOpenreplayAttribute)(node, 'capture'))) {
19
+ this.app.nodes.attachNodeCallback(node => {
20
+ if ((0, guards_js_1.hasTag)(node, "IFRAME") &&
21
+ ((this.options.captureIFrames && !(0, utils_js_1.hasOpenreplayAttribute)(node, "obscured"))
22
+ || (0, utils_js_1.hasOpenreplayAttribute)(node, "capture"))) {
30
23
  this.handleIframe(node);
31
24
  }
32
25
  });
33
26
  // ShadowDOM
34
- this.app.nodes.attachNodeCallback((node) => {
27
+ this.app.nodes.attachNodeCallback(node => {
35
28
  if ((0, guards_js_1.isElementNode)(node) && node.shadowRoot !== null) {
36
29
  this.handleShadowRoot(node.shadowRoot);
37
30
  }
38
31
  });
39
32
  }
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
- }
50
33
  handleIframe(iframe) {
51
34
  let doc = null;
52
- let win = null;
53
35
  const handle = this.app.safe(() => {
54
36
  const id = this.app.nodes.getID(iframe);
55
37
  if (id === undefined) {
56
- //log
38
+ 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) {
57
45
  return;
58
46
  }
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
- }
47
+ const observer = new iframe_observer_js_1.default(this.app);
48
+ this.iframeObservers.push(observer);
49
+ observer.observe(iframe);
84
50
  });
85
- iframe.addEventListener('load', handle); // why app.attachEventListener not working?
51
+ iframe.addEventListener("load", handle); // why app.attachEventListener not working?
86
52
  handle();
87
53
  }
88
54
  handleShadowRoot(shRoot) {
@@ -94,26 +60,25 @@ class TopObserver extends observer_js_1.default {
94
60
  // Protection from several subsequent calls?
95
61
  const observer = this;
96
62
  Element.prototype.attachShadow = function () {
97
- // eslint-disable-next-line
98
63
  const shadow = attachShadowNativeFn.apply(this, arguments);
99
64
  observer.handleShadowRoot(shadow);
100
65
  return shadow;
101
66
  };
102
67
  // Can observe documentElement (<html>) here, because it is not supposed to be changing.
103
68
  // However, it is possible in some exotic cases and may cause an ignorance of the newly created <html>
104
- // In this case context.document have to be observed, but this will cause
105
- // the change in the re-player behaviour caused by CreateDocument message:
69
+ // In this case context.document have to be observed, but this will cause
70
+ // the change in the re-player behaviour caused by CreateDocument message:
106
71
  // the 0-node ("fRoot") will become #document rather than documentElement as it is now.
107
72
  // Alternatively - observe(#document) then bindNode(documentElement)
108
73
  this.observeRoot(window.document, () => {
109
- this.app.send((0, messages_gen_js_1.CreateDocument)());
74
+ this.app.send(new messages_js_1.CreateDocument());
110
75
  }, window.document.documentElement);
111
76
  }
112
77
  disconnect() {
113
78
  Element.prototype.attachShadow = attachShadowNativeFn;
114
- this.iframeObservers.forEach((o) => o.disconnect());
79
+ this.iframeObservers.forEach(o => o.disconnect());
115
80
  this.iframeObservers = [];
116
- this.shadowRootObservers.forEach((o) => o.disconnect());
81
+ this.shadowRootObservers.forEach(o => o.disconnect());
117
82
  this.shadowRootObservers = [];
118
83
  super.disconnect();
119
84
  }
@@ -1,4 +1,4 @@
1
- import type App from './index.js';
1
+ import type App from "./index.js";
2
2
  export interface Options {
3
3
  obscureTextEmails: boolean;
4
4
  obscureTextNumbers: boolean;
@@ -14,20 +14,20 @@ class Sanitizer {
14
14
  }
15
15
  handleNode(id, parentID, node) {
16
16
  if (this.masked.has(parentID) ||
17
- ((0, guards_js_1.isElementNode)(node) && (0, utils_js_1.hasOpenreplayAttribute)(node, 'masked'))) {
17
+ ((0, guards_js_1.isElementNode)(node) &&
18
+ (0, utils_js_1.hasOpenreplayAttribute)(node, 'masked'))) {
18
19
  this.masked.add(id);
19
20
  }
20
21
  if (this.maskedContainers.has(parentID) ||
21
- ((0, guards_js_1.isElementNode)(node) && (0, utils_js_1.hasOpenreplayAttribute)(node, 'htmlmasked'))) {
22
+ ((0, guards_js_1.isElementNode)(node) &&
23
+ (0, utils_js_1.hasOpenreplayAttribute)(node, 'htmlmasked'))) {
22
24
  this.maskedContainers.add(id);
23
25
  }
24
26
  }
25
27
  sanitize(id, data) {
26
28
  if (this.masked.has(id)) {
27
29
  // TODO: is it the best place to put trim() ? Might trimmed spaces be considered in layout in certain cases?
28
- return data
29
- .trim()
30
- .replace(/[^\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/g, '█');
30
+ return data.trim().replace(/[^\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/g, '█');
31
31
  }
32
32
  if (this.options.obscureTextNumbers) {
33
33
  data = data.replace(/\d/g, '0');
@@ -1,37 +1,19 @@
1
- import type App from './index.js';
2
1
  interface SessionInfo {
3
- sessionID: string | undefined;
2
+ sessionID: string | null;
4
3
  metadata: Record<string, string>;
5
4
  userID: string | null;
6
- timestamp: number;
7
- projectID?: string;
8
5
  }
9
6
  declare type OnUpdateCallback = (i: Partial<SessionInfo>) => void;
10
- export declare type Options = {
11
- session_token_key: string;
12
- session_pageno_key: string;
13
- };
14
7
  export default class Session {
15
- private readonly app;
16
- private readonly options;
17
8
  private metadata;
18
9
  private userID;
19
10
  private sessionID;
20
- private readonly callbacks;
21
- private timestamp;
22
- private projectID;
23
- constructor(app: App, options: Options);
11
+ private callbacks;
24
12
  attachUpdateCallback(cb: OnUpdateCallback): void;
25
13
  private handleUpdate;
26
14
  update(newInfo: Partial<SessionInfo>): void;
27
15
  setMetadata(key: string, value: string): void;
28
16
  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;
35
17
  getInfo(): SessionInfo;
36
18
  reset(): void;
37
19
  }