@openreplay/tracker 3.6.0-beta.0 → 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 (126) hide show
  1. package/cjs/app/guards.d.ts +1 -2
  2. package/cjs/app/guards.js +3 -6
  3. package/cjs/app/index.d.ts +22 -24
  4. package/cjs/app/index.js +84 -85
  5. package/cjs/app/logger.js +3 -6
  6. package/cjs/app/nodes.js +0 -2
  7. package/cjs/app/observer/iframe_observer.d.ts +1 -1
  8. package/cjs/app/observer/iframe_observer.js +3 -3
  9. package/cjs/app/observer/observer.d.ts +3 -2
  10. package/cjs/app/observer/observer.js +52 -50
  11. package/cjs/app/observer/shadow_root_observer.d.ts +1 -1
  12. package/cjs/app/observer/shadow_root_observer.js +3 -3
  13. package/cjs/app/observer/top_observer.d.ts +2 -11
  14. package/cjs/app/observer/top_observer.js +23 -52
  15. package/cjs/app/sanitizer.d.ts +1 -1
  16. package/cjs/app/sanitizer.js +5 -5
  17. package/cjs/app/session.d.ts +2 -18
  18. package/cjs/app/session.js +6 -55
  19. package/cjs/app/ticker.d.ts +1 -1
  20. package/cjs/common/messages.d.ts +444 -0
  21. package/cjs/common/messages.js +794 -0
  22. package/cjs/common/types.d.ts +9 -0
  23. package/cjs/common/{interaction.js → types.js} +0 -0
  24. package/cjs/common/{interaction.d.ts → webworker.d.ts} +5 -5
  25. package/cjs/common/webworker.js +2 -0
  26. package/cjs/index.d.ts +10 -10
  27. package/cjs/index.js +37 -42
  28. package/cjs/modules/connection.d.ts +1 -1
  29. package/cjs/modules/connection.js +2 -2
  30. package/cjs/modules/console.d.ts +1 -1
  31. package/cjs/modules/console.js +21 -7
  32. package/cjs/modules/cssrules.d.ts +1 -1
  33. package/cjs/modules/cssrules.js +14 -18
  34. package/cjs/modules/exception.d.ts +3 -3
  35. package/cjs/modules/exception.js +20 -25
  36. package/cjs/modules/img.d.ts +1 -1
  37. package/cjs/modules/img.js +26 -39
  38. package/cjs/modules/input.d.ts +1 -1
  39. package/cjs/modules/input.js +21 -21
  40. package/cjs/modules/longtasks.d.ts +2 -0
  41. package/cjs/modules/longtasks.js +26 -0
  42. package/cjs/modules/mouse.d.ts +1 -1
  43. package/cjs/modules/mouse.js +43 -50
  44. package/cjs/modules/performance.d.ts +1 -1
  45. package/cjs/modules/performance.js +2 -2
  46. package/cjs/modules/scroll.d.ts +1 -1
  47. package/cjs/modules/scroll.js +7 -16
  48. package/cjs/modules/timing.d.ts +1 -1
  49. package/cjs/modules/timing.js +26 -14
  50. package/cjs/modules/viewport.d.ts +1 -1
  51. package/cjs/modules/viewport.js +4 -4
  52. package/cjs/utils.js +7 -7
  53. package/cjs/vendors/finder/finder.js +48 -53
  54. package/lib/app/guards.d.ts +1 -2
  55. package/lib/app/guards.js +2 -4
  56. package/lib/app/index.d.ts +22 -24
  57. package/lib/app/index.js +92 -93
  58. package/lib/app/logger.js +3 -6
  59. package/lib/app/nodes.js +0 -2
  60. package/lib/app/observer/iframe_observer.d.ts +1 -1
  61. package/lib/app/observer/iframe_observer.js +3 -3
  62. package/lib/app/observer/observer.d.ts +3 -2
  63. package/lib/app/observer/observer.js +53 -51
  64. package/lib/app/observer/shadow_root_observer.d.ts +1 -1
  65. package/lib/app/observer/shadow_root_observer.js +3 -3
  66. package/lib/app/observer/top_observer.d.ts +2 -11
  67. package/lib/app/observer/top_observer.js +27 -56
  68. package/lib/app/sanitizer.d.ts +1 -1
  69. package/lib/app/sanitizer.js +7 -7
  70. package/lib/app/session.d.ts +2 -18
  71. package/lib/app/session.js +6 -55
  72. package/lib/app/ticker.d.ts +1 -1
  73. package/lib/common/messages.d.ts +444 -0
  74. package/lib/common/messages.js +790 -0
  75. package/lib/common/tsconfig.tsbuildinfo +1 -1
  76. package/lib/common/types.d.ts +9 -0
  77. package/lib/common/{interaction.js → types.js} +0 -0
  78. package/lib/common/{interaction.d.ts → webworker.d.ts} +5 -5
  79. package/lib/common/webworker.js +1 -0
  80. package/lib/index.d.ts +10 -10
  81. package/lib/index.js +50 -55
  82. package/lib/modules/connection.d.ts +1 -1
  83. package/lib/modules/connection.js +2 -2
  84. package/lib/modules/console.d.ts +1 -1
  85. package/lib/modules/console.js +22 -8
  86. package/lib/modules/cssrules.d.ts +1 -1
  87. package/lib/modules/cssrules.js +15 -19
  88. package/lib/modules/exception.d.ts +3 -3
  89. package/lib/modules/exception.js +20 -25
  90. package/lib/modules/img.d.ts +1 -1
  91. package/lib/modules/img.js +28 -41
  92. package/lib/modules/input.d.ts +1 -1
  93. package/lib/modules/input.js +23 -23
  94. package/lib/modules/longtasks.d.ts +2 -0
  95. package/lib/modules/longtasks.js +23 -0
  96. package/lib/modules/mouse.d.ts +1 -1
  97. package/lib/modules/mouse.js +46 -53
  98. package/lib/modules/performance.d.ts +1 -1
  99. package/lib/modules/performance.js +3 -3
  100. package/lib/modules/scroll.d.ts +1 -1
  101. package/lib/modules/scroll.js +8 -17
  102. package/lib/modules/timing.d.ts +1 -1
  103. package/lib/modules/timing.js +28 -16
  104. package/lib/modules/viewport.d.ts +1 -1
  105. package/lib/modules/viewport.js +4 -4
  106. package/lib/utils.js +7 -7
  107. package/lib/vendors/finder/finder.js +48 -53
  108. package/package.json +10 -27
  109. package/.eslintignore +0 -8
  110. package/.prettierignore +0 -1
  111. package/cjs/app/messages.d.ts +0 -52
  112. package/cjs/app/messages.gen.d.ts +0 -57
  113. package/cjs/app/messages.gen.js +0 -494
  114. package/cjs/app/messages.js +0 -235
  115. package/cjs/common/messages.gen.d.ts +0 -382
  116. package/cjs/common/messages.gen.js +0 -62
  117. package/cjs/modules/adoptedStyleSheets.d.ts +0 -2
  118. package/cjs/modules/adoptedStyleSheets.js +0 -127
  119. package/lib/app/messages.d.ts +0 -52
  120. package/lib/app/messages.gen.d.ts +0 -57
  121. package/lib/app/messages.gen.js +0 -435
  122. package/lib/app/messages.js +0 -182
  123. package/lib/common/messages.gen.d.ts +0 -382
  124. package/lib/common/messages.gen.js +0 -59
  125. package/lib/modules/adoptedStyleSheets.d.ts +0 -2
  126. package/lib/modules/adoptedStyleSheets.js +0 -124
@@ -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,19 +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 ContextCallback = (context: Window & typeof globalThis) => void;
7
- declare type Offset = {
8
- top: number;
9
- left: number;
10
- };
11
6
  export default class TopObserver extends Observer {
12
7
  private readonly options;
13
8
  constructor(app: App, options: Partial<Options>);
14
- private readonly contextCallbacks;
15
- attachContextCallback(cb: ContextCallback): void;
16
- getDocumentOffset(doc: Document): Offset;
17
9
  private iframeObservers;
18
10
  private handleIframe;
19
11
  private shadowRootObservers;
@@ -21,4 +13,3 @@ export default class TopObserver extends Observer {
21
13
  observe(): void;
22
14
  disconnect(): void;
23
15
  }
24
- export {};
@@ -4,79 +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
13
  this.iframeObservers = [];
19
14
  this.shadowRootObservers = [];
20
15
  this.options = Object.assign({
21
- captureIFrames: true,
16
+ captureIFrames: true
22
17
  }, options);
23
18
  // IFrames
24
- this.app.nodes.attachNodeCallback((node) => {
25
- if ((0, guards_js_1.hasTag)(node, 'IFRAME') &&
26
- ((this.options.captureIFrames && !(0, utils_js_1.hasOpenreplayAttribute)(node, 'obscured')) ||
27
- (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"))) {
28
23
  this.handleIframe(node);
29
24
  }
30
25
  });
31
26
  // ShadowDOM
32
- this.app.nodes.attachNodeCallback((node) => {
27
+ this.app.nodes.attachNodeCallback(node => {
33
28
  if ((0, guards_js_1.isElementNode)(node) && node.shadowRoot !== null) {
34
29
  this.handleShadowRoot(node.shadowRoot);
35
30
  }
36
31
  });
37
32
  }
38
- // Attached once per Tracker instance
39
- attachContextCallback(cb) {
40
- this.contextCallbacks.push(cb);
41
- }
42
- // Le truc
43
- getDocumentOffset(doc) {
44
- if (isPatchedDocument(doc)) {
45
- return doc.__openreplay__getOffset();
46
- }
47
- return { top: 0, left: 0 };
48
- }
49
33
  handleIframe(iframe) {
50
34
  let doc = null;
51
- let win = null;
52
35
  const handle = this.app.safe(() => {
53
36
  const id = this.app.nodes.getID(iframe);
54
37
  if (id === undefined) {
55
- //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) {
56
45
  return;
57
46
  }
58
- const currentWin = iframe.contentWindow;
59
- const currentDoc = iframe.contentDocument;
60
- if (currentDoc && currentDoc !== doc) {
61
- const observer = new iframe_observer_js_1.default(this.app);
62
- this.iframeObservers.push(observer);
63
- observer.observe(iframe);
64
- doc = currentDoc;
65
- doc.__openreplay__getOffset = () => {
66
- const { top, left } = this.getDocumentOffset(iframe.ownerDocument);
67
- return {
68
- top: iframe.offsetTop + top,
69
- left: iframe.offsetLeft + left,
70
- };
71
- };
72
- }
73
- if (currentWin && currentWin !== win) {
74
- //@ts-ignore https://github.com/microsoft/TypeScript/issues/41684
75
- this.contextCallbacks.forEach((cb) => cb(currentWin));
76
- win = currentWin;
77
- }
47
+ const observer = new iframe_observer_js_1.default(this.app);
48
+ this.iframeObservers.push(observer);
49
+ observer.observe(iframe);
78
50
  });
79
- iframe.addEventListener('load', handle); // why app.attachEventListener not working?
51
+ iframe.addEventListener("load", handle); // why app.attachEventListener not working?
80
52
  handle();
81
53
  }
82
54
  handleShadowRoot(shRoot) {
@@ -88,26 +60,25 @@ class TopObserver extends observer_js_1.default {
88
60
  // Protection from several subsequent calls?
89
61
  const observer = this;
90
62
  Element.prototype.attachShadow = function () {
91
- // eslint-disable-next-line
92
63
  const shadow = attachShadowNativeFn.apply(this, arguments);
93
64
  observer.handleShadowRoot(shadow);
94
65
  return shadow;
95
66
  };
96
67
  // Can observe documentElement (<html>) here, because it is not supposed to be changing.
97
68
  // However, it is possible in some exotic cases and may cause an ignorance of the newly created <html>
98
- // In this case context.document have to be observed, but this will cause
99
- // 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:
100
71
  // the 0-node ("fRoot") will become #document rather than documentElement as it is now.
101
72
  // Alternatively - observe(#document) then bindNode(documentElement)
102
73
  this.observeRoot(window.document, () => {
103
- this.app.send((0, messages_gen_js_1.CreateDocument)());
74
+ this.app.send(new messages_js_1.CreateDocument());
104
75
  }, window.document.documentElement);
105
76
  }
106
77
  disconnect() {
107
78
  Element.prototype.attachShadow = attachShadowNativeFn;
108
- this.iframeObservers.forEach((o) => o.disconnect());
79
+ this.iframeObservers.forEach(o => o.disconnect());
109
80
  this.iframeObservers = [];
110
- this.shadowRootObservers.forEach((o) => o.disconnect());
81
+ this.shadowRootObservers.forEach(o => o.disconnect());
111
82
  this.shadowRootObservers = [];
112
83
  super.disconnect();
113
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,35 +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
5
  }
8
6
  declare type OnUpdateCallback = (i: Partial<SessionInfo>) => void;
9
- export declare type Options = {
10
- session_token_key: string;
11
- session_pageno_key: string;
12
- };
13
7
  export default class Session {
14
- private readonly app;
15
- private options;
16
8
  private metadata;
17
9
  private userID;
18
10
  private sessionID;
19
- private readonly callbacks;
20
- private timestamp;
21
- constructor(app: App, options: Options);
11
+ private callbacks;
22
12
  attachUpdateCallback(cb: OnUpdateCallback): void;
23
13
  private handleUpdate;
24
14
  update(newInfo: Partial<SessionInfo>): void;
25
15
  setMetadata(key: string, value: string): void;
26
16
  setUserID(userID: string): void;
27
- private getPageNumber;
28
- incPageNo(): number;
29
- getSessionToken(): string | undefined;
30
- setSessionToken(token: string): void;
31
- applySessionHash(hash: string): void;
32
- getSessionHash(): string;
33
17
  getInfo(): SessionInfo;
34
18
  reset(): void;
35
19
  }
@@ -1,13 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  class Session {
4
- constructor(app, options) {
5
- this.app = app;
6
- this.options = options;
4
+ constructor() {
7
5
  this.metadata = {};
8
6
  this.userID = null;
7
+ this.sessionID = null;
9
8
  this.callbacks = [];
10
- this.timestamp = 0;
11
9
  }
12
10
  attachUpdateCallback(cb) {
13
11
  this.callbacks.push(cb);
@@ -19,22 +17,18 @@ class Session {
19
17
  if (newInfo.sessionID == null) {
20
18
  delete newInfo.sessionID;
21
19
  }
22
- this.callbacks.forEach((cb) => cb(newInfo));
20
+ this.callbacks.forEach(cb => cb(newInfo));
23
21
  }
24
22
  update(newInfo) {
25
- if (newInfo.userID !== undefined) {
26
- // TODO clear nullable/undefinable types
23
+ if (newInfo.userID !== undefined) { // TODO clear nullable/undefinable types
27
24
  this.userID = newInfo.userID;
28
25
  }
29
26
  if (newInfo.metadata !== undefined) {
30
- Object.entries(newInfo.metadata).forEach(([k, v]) => (this.metadata[k] = v));
27
+ Object.entries(newInfo.metadata).forEach(([k, v]) => this.metadata[k] = v);
31
28
  }
32
29
  if (newInfo.sessionID !== undefined) {
33
30
  this.sessionID = newInfo.sessionID;
34
31
  }
35
- if (newInfo.timestamp !== undefined) {
36
- this.timestamp = newInfo.timestamp;
37
- }
38
32
  this.handleUpdate(newInfo);
39
33
  }
40
34
  setMetadata(key, value) {
@@ -45,60 +39,17 @@ class Session {
45
39
  this.userID = userID;
46
40
  this.handleUpdate({ userID });
47
41
  }
48
- getPageNumber() {
49
- const pageNoStr = this.app.sessionStorage.getItem(this.options.session_pageno_key);
50
- if (pageNoStr == null) {
51
- return undefined;
52
- }
53
- return parseInt(pageNoStr);
54
- }
55
- incPageNo() {
56
- let pageNo = this.getPageNumber();
57
- if (pageNo === undefined) {
58
- pageNo = 0;
59
- }
60
- else {
61
- pageNo++;
62
- }
63
- this.app.sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
64
- return pageNo;
65
- }
66
- getSessionToken() {
67
- return this.app.sessionStorage.getItem(this.options.session_token_key) || undefined;
68
- }
69
- setSessionToken(token) {
70
- this.app.sessionStorage.setItem(this.options.session_token_key, token);
71
- }
72
- applySessionHash(hash) {
73
- const [pageNoStr, token] = decodeURI(hash).split('&');
74
- if (!pageNoStr || !token) {
75
- return;
76
- }
77
- this.app.sessionStorage.setItem(this.options.session_token_key, token);
78
- this.app.sessionStorage.setItem(this.options.session_pageno_key, pageNoStr);
79
- }
80
- getSessionHash() {
81
- const pageNo = this.getPageNumber();
82
- const token = this.getSessionToken();
83
- if (pageNo === undefined || token === undefined) {
84
- return '';
85
- }
86
- return encodeURI(String(pageNo) + "&" + token);
87
- }
88
42
  getInfo() {
89
43
  return {
90
44
  sessionID: this.sessionID,
91
45
  metadata: this.metadata,
92
46
  userID: this.userID,
93
- timestamp: this.timestamp,
94
47
  };
95
48
  }
96
49
  reset() {
97
- this.app.sessionStorage.removeItem(this.options.session_token_key);
98
50
  this.metadata = {};
99
51
  this.userID = null;
100
- this.sessionID = undefined;
101
- this.timestamp = 0;
52
+ this.sessionID = null;
102
53
  }
103
54
  }
104
55
  exports.default = Session;
@@ -1,4 +1,4 @@
1
- import App from './index.js';
1
+ import App from "./index.js";
2
2
  declare type Callback = () => void;
3
3
  export default class Ticker {
4
4
  private readonly app;