@openreplay/tracker 3.5.12 → 3.5.14

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 (70) hide show
  1. package/cjs/app/guards.d.ts +18 -0
  2. package/cjs/app/guards.js +24 -0
  3. package/cjs/app/index.d.ts +5 -1
  4. package/cjs/app/index.js +55 -32
  5. package/cjs/app/nodes.d.ts +3 -3
  6. package/cjs/app/nodes.js +2 -2
  7. package/cjs/app/observer/observer.d.ts +1 -2
  8. package/cjs/app/observer/observer.js +73 -60
  9. package/cjs/app/observer/top_observer.js +3 -3
  10. package/cjs/app/sanitizer.d.ts +3 -1
  11. package/cjs/app/sanitizer.js +13 -2
  12. package/cjs/app/session.d.ts +2 -7
  13. package/cjs/app/session.js +24 -37
  14. package/cjs/index.js +2 -2
  15. package/cjs/modules/console.d.ts +1 -1
  16. package/cjs/modules/console.js +2 -1
  17. package/cjs/modules/cssrules.d.ts +1 -1
  18. package/cjs/modules/cssrules.js +2 -4
  19. package/cjs/modules/exception.d.ts +1 -1
  20. package/cjs/modules/img.d.ts +1 -1
  21. package/cjs/modules/img.js +14 -6
  22. package/cjs/modules/input.d.ts +2 -1
  23. package/cjs/modules/input.js +18 -20
  24. package/cjs/modules/longtasks.d.ts +1 -1
  25. package/cjs/modules/mouse.d.ts +1 -1
  26. package/cjs/modules/mouse.js +3 -2
  27. package/cjs/modules/performance.d.ts +1 -1
  28. package/cjs/modules/scroll.d.ts +1 -1
  29. package/cjs/modules/scroll.js +3 -2
  30. package/cjs/modules/timing.d.ts +1 -1
  31. package/cjs/modules/timing.js +2 -1
  32. package/cjs/modules/viewport.d.ts +1 -1
  33. package/lib/app/guards.d.ts +18 -0
  34. package/lib/app/guards.js +16 -0
  35. package/lib/app/index.d.ts +5 -1
  36. package/lib/app/index.js +56 -33
  37. package/lib/app/nodes.d.ts +3 -3
  38. package/lib/app/nodes.js +2 -2
  39. package/lib/app/observer/observer.d.ts +1 -2
  40. package/lib/app/observer/observer.js +70 -57
  41. package/lib/app/observer/top_observer.js +3 -3
  42. package/lib/app/sanitizer.d.ts +3 -1
  43. package/lib/app/sanitizer.js +13 -2
  44. package/lib/app/session.d.ts +2 -7
  45. package/lib/app/session.js +24 -37
  46. package/lib/common/tsconfig.tsbuildinfo +1 -1
  47. package/lib/index.js +2 -2
  48. package/lib/modules/console.d.ts +1 -1
  49. package/lib/modules/console.js +2 -1
  50. package/lib/modules/cssrules.d.ts +1 -1
  51. package/lib/modules/cssrules.js +2 -4
  52. package/lib/modules/exception.d.ts +1 -1
  53. package/lib/modules/img.d.ts +1 -1
  54. package/lib/modules/img.js +14 -6
  55. package/lib/modules/input.d.ts +2 -1
  56. package/lib/modules/input.js +18 -20
  57. package/lib/modules/longtasks.d.ts +1 -1
  58. package/lib/modules/mouse.d.ts +1 -1
  59. package/lib/modules/mouse.js +3 -2
  60. package/lib/modules/performance.d.ts +1 -1
  61. package/lib/modules/scroll.d.ts +1 -1
  62. package/lib/modules/scroll.js +3 -2
  63. package/lib/modules/timing.d.ts +1 -1
  64. package/lib/modules/timing.js +2 -1
  65. package/lib/modules/viewport.d.ts +1 -1
  66. package/package.json +7 -7
  67. package/cjs/app/context.d.ts +0 -18
  68. package/cjs/app/context.js +0 -73
  69. package/lib/app/context.d.ts +0 -18
  70. package/lib/app/context.js +0 -68
@@ -1,15 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const messages_js_1 = require("../../common/messages.js");
4
- const context_js_1 = require("../context.js");
5
- function isSVGElement(node) {
6
- return node.namespaceURI === 'http://www.w3.org/2000/svg';
7
- }
4
+ const guards_js_1 = require("../guards.js");
8
5
  function isIgnored(node) {
9
- if ((0, context_js_1.isInstance)(node, Text)) {
6
+ if ((0, guards_js_1.isTextNode)(node)) {
10
7
  return false;
11
8
  }
12
- if (!(0, context_js_1.isInstance)(node, Element)) {
9
+ if (!(0, guards_js_1.isElementNode)(node)) {
13
10
  return true;
14
11
  }
15
12
  const tag = node.tagName.toUpperCase();
@@ -24,30 +21,37 @@ function isIgnored(node) {
24
21
  tag === 'TITLE' ||
25
22
  tag === 'BASE');
26
23
  }
27
- function isRootNode(node) {
28
- return (0, context_js_1.isInstance)(node, Document) || (0, context_js_1.isInstance)(node, ShadowRoot);
29
- }
30
24
  function isObservable(node) {
31
- if (isRootNode(node)) {
25
+ if ((0, guards_js_1.isRootNode)(node)) {
32
26
  return true;
33
27
  }
34
28
  return !isIgnored(node);
35
29
  }
30
+ /*
31
+ TODO:
32
+ - fix unbinding logic + send all removals first (ensure sequence is correct)
33
+ - use document as a 0-node in the upper context (should be updated in player at first)
34
+ */
35
+ var RecentsType;
36
+ (function (RecentsType) {
37
+ RecentsType[RecentsType["New"] = 0] = "New";
38
+ RecentsType[RecentsType["Removed"] = 1] = "Removed";
39
+ RecentsType[RecentsType["Changed"] = 2] = "Changed";
40
+ })(RecentsType || (RecentsType = {}));
36
41
  class Observer {
37
42
  constructor(app, isTopContext = false) {
38
43
  this.app = app;
39
44
  this.isTopContext = isTopContext;
40
45
  this.commited = [];
41
- this.recents = [];
42
- this.myNodes = [];
46
+ this.recents = new Map();
43
47
  this.indexes = [];
44
- this.attributesList = [];
48
+ this.attributesMap = new Map();
45
49
  this.textSet = new Set();
46
50
  this.observer = new MutationObserver(this.app.safe((mutations) => {
47
- for (const mutation of mutations) {
51
+ for (const mutation of mutations) { // mutations order is sequential
48
52
  const target = mutation.target;
49
53
  const type = mutation.type;
50
- if (!isObservable(target) || !(0, context_js_1.inDocument)(target)) {
54
+ if (!isObservable(target)) {
51
55
  continue;
52
56
  }
53
57
  if (type === 'childList') {
@@ -63,17 +67,17 @@ class Observer {
63
67
  if (id === undefined) {
64
68
  continue;
65
69
  }
66
- if (id >= this.recents.length) { // TODO: something more convinient
67
- this.recents[id] = undefined;
70
+ if (!this.recents.has(id)) {
71
+ this.recents.set(id, RecentsType.Changed); // TODO only when altered
68
72
  }
69
73
  if (type === 'attributes') {
70
74
  const name = mutation.attributeName;
71
75
  if (name === null) {
72
76
  continue;
73
77
  }
74
- let attr = this.attributesList[id];
78
+ let attr = this.attributesMap.get(id);
75
79
  if (attr === undefined) {
76
- this.attributesList[id] = attr = new Set();
80
+ this.attributesMap.set(id, attr = new Set());
77
81
  }
78
82
  attr.add(name);
79
83
  continue;
@@ -88,13 +92,13 @@ class Observer {
88
92
  }
89
93
  clear() {
90
94
  this.commited.length = 0;
91
- this.recents.length = 0;
95
+ this.recents.clear();
92
96
  this.indexes.length = 1;
93
- this.attributesList.length = 0;
97
+ this.attributesMap.clear();
94
98
  this.textSet.clear();
95
99
  }
96
100
  sendNodeAttribute(id, node, name, value) {
97
- if (isSVGElement(node)) {
101
+ if ((0, guards_js_1.isSVGElement)(node)) {
98
102
  if (name.substr(0, 6) === 'xlink:') {
99
103
  name = name.substr(6);
100
104
  }
@@ -121,7 +125,7 @@ class Observer {
121
125
  return;
122
126
  }
123
127
  if (name === 'value' &&
124
- (0, context_js_1.isInstance)(node, HTMLInputElement) &&
128
+ (0, guards_js_1.hasTag)(node, "INPUT") &&
125
129
  node.type !== 'button' &&
126
130
  node.type !== 'reset' &&
127
131
  node.type !== 'submit') {
@@ -131,7 +135,7 @@ class Observer {
131
135
  this.app.send(new messages_js_1.RemoveNodeAttribute(id, name));
132
136
  return;
133
137
  }
134
- if (name === 'style' || name === 'href' && (0, context_js_1.isInstance)(node, HTMLLinkElement)) {
138
+ if (name === 'style' || name === 'href' && (0, guards_js_1.hasTag)(node, "LINK")) {
135
139
  this.app.send(new messages_js_1.SetNodeAttributeURLBased(id, name, value, this.app.getBaseHref()));
136
140
  return;
137
141
  }
@@ -141,7 +145,7 @@ class Observer {
141
145
  this.app.send(new messages_js_1.SetNodeAttribute(id, name, value));
142
146
  }
143
147
  sendNodeData(id, parentElement, data) {
144
- if ((0, context_js_1.isInstance)(parentElement, HTMLStyleElement) || (0, context_js_1.isInstance)(parentElement, SVGStyleElement)) {
148
+ if ((0, guards_js_1.hasTag)(parentElement, "STYLE") || (0, guards_js_1.hasTag)(parentElement, "style")) {
145
149
  this.app.send(new messages_js_1.SetCSSDataURLBased(id, data, this.app.getBaseHref()));
146
150
  return;
147
151
  }
@@ -149,10 +153,13 @@ class Observer {
149
153
  this.app.send(new messages_js_1.SetNodeData(id, data));
150
154
  }
151
155
  bindNode(node) {
152
- const r = this.app.nodes.registerNode(node);
153
- const id = r[0];
154
- this.recents[id] = r[1] || this.recents[id] || false;
155
- this.myNodes[id] = true;
156
+ const [id, isNew] = this.app.nodes.registerNode(node);
157
+ if (isNew) {
158
+ this.recents.set(id, RecentsType.New);
159
+ }
160
+ else if (!this.recents.has(id)) {
161
+ this.recents.set(id, RecentsType.Removed);
162
+ }
156
163
  }
157
164
  bindTree(node) {
158
165
  if (!isObservable(node)) {
@@ -172,20 +179,21 @@ class Observer {
172
179
  }
173
180
  unbindNode(node) {
174
181
  const id = this.app.nodes.unregisterNode(node);
175
- if (id !== undefined && this.recents[id] === false) {
182
+ if (id !== undefined && this.recents.get(id) === RecentsType.Removed) {
176
183
  this.app.send(new messages_js_1.RemoveNode(id));
177
184
  }
178
185
  }
186
+ // A top-consumption function on the infinite lists test. (~1% of performance resources)
179
187
  _commitNode(id, node) {
180
- if (isRootNode(node)) {
188
+ if ((0, guards_js_1.isRootNode)(node)) {
181
189
  return true;
182
190
  }
183
191
  const parent = node.parentNode;
184
192
  let parentID;
185
193
  // Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
186
194
  // TODO: get rid of "special" cases (there is an issue with CreateDocument altered behaviour though)
187
- // TODO: Clean the logic (though now it workd fine)
188
- if (!(0, context_js_1.isInstance)(node, HTMLHtmlElement) || !this.isTopContext) {
195
+ // TODO: Clean the logic (though now it workd fine)
196
+ if (!(0, guards_js_1.hasTag)(node, "HTML") || !this.isTopContext) {
189
197
  if (parent === null) {
190
198
  this.unbindNode(node);
191
199
  return false;
@@ -200,7 +208,11 @@ class Observer {
200
208
  return false;
201
209
  }
202
210
  this.app.sanitizer.handleNode(id, parentID, node);
211
+ if (this.app.sanitizer.isMaskedContainer(parentID)) {
212
+ return false;
213
+ }
203
214
  }
215
+ // From here parentID === undefined if node is top context HTML node
204
216
  let sibling = node.previousSibling;
205
217
  while (sibling !== null) {
206
218
  const siblingID = this.app.nodes.getID(sibling);
@@ -212,36 +224,45 @@ class Observer {
212
224
  sibling = sibling.previousSibling;
213
225
  }
214
226
  if (sibling === null) {
215
- this.indexes[id] = 0; //
227
+ this.indexes[id] = 0;
216
228
  }
217
- const isNew = this.recents[id];
229
+ const recentsType = this.recents.get(id);
230
+ const isNew = recentsType === RecentsType.New;
218
231
  const index = this.indexes[id];
219
232
  if (index === undefined) {
220
233
  throw 'commitNode: missing node index';
221
234
  }
222
- if (isNew === true) {
223
- if ((0, context_js_1.isInstance)(node, Element)) {
235
+ if (isNew) {
236
+ if ((0, guards_js_1.isElementNode)(node)) {
237
+ let el = node;
224
238
  if (parentID !== undefined) {
225
- this.app.send(new messages_js_1.CreateElementNode(id, parentID, index, node.tagName, isSVGElement(node)));
239
+ if (this.app.sanitizer.isMaskedContainer(id)) {
240
+ const width = el.clientWidth;
241
+ const height = el.clientHeight;
242
+ el = node.cloneNode();
243
+ el.style.width = width + 'px';
244
+ el.style.height = height + 'px';
245
+ }
246
+ this.app.send(new messages_js_1.CreateElementNode(id, parentID, index, el.tagName, (0, guards_js_1.isSVGElement)(node)));
226
247
  }
227
- for (let i = 0; i < node.attributes.length; i++) {
228
- const attr = node.attributes[i];
229
- this.sendNodeAttribute(id, node, attr.nodeName, attr.value);
248
+ for (let i = 0; i < el.attributes.length; i++) {
249
+ const attr = el.attributes[i];
250
+ this.sendNodeAttribute(id, el, attr.nodeName, attr.value);
230
251
  }
231
252
  }
232
- else if ((0, context_js_1.isInstance)(node, Text)) {
253
+ else if ((0, guards_js_1.isTextNode)(node)) {
233
254
  // for text node id != 0, hence parentID !== undefined and parent is Element
234
255
  this.app.send(new messages_js_1.CreateTextNode(id, parentID, index));
235
256
  this.sendNodeData(id, parent, node.data);
236
257
  }
237
258
  return true;
238
259
  }
239
- if (isNew === false && parentID !== undefined) {
260
+ if (recentsType === RecentsType.Removed && parentID !== undefined) {
240
261
  this.app.send(new messages_js_1.MoveNode(id, parentID, index));
241
262
  }
242
- const attr = this.attributesList[id];
263
+ const attr = this.attributesMap.get(id);
243
264
  if (attr !== undefined) {
244
- if (!(0, context_js_1.isInstance)(node, Element)) {
265
+ if (!(0, guards_js_1.isElementNode)(node)) {
245
266
  throw 'commitNode: node is not an element';
246
267
  }
247
268
  for (const name of attr) {
@@ -249,7 +270,7 @@ class Observer {
249
270
  }
250
271
  }
251
272
  if (this.textSet.has(id)) {
252
- if (!(0, context_js_1.isInstance)(node, Text)) {
273
+ if (!(0, guards_js_1.isTextNode)(node)) {
253
274
  throw 'commitNode: node is not a text';
254
275
  }
255
276
  // for text node id != 0, hence parent is Element
@@ -268,21 +289,14 @@ class Observer {
268
289
  }
269
290
  return (this.commited[id] = this._commitNode(id, node));
270
291
  }
271
- commitNodes() {
292
+ commitNodes(isStart = false) {
272
293
  let node;
273
- for (let id = 0; id < this.recents.length; id++) {
274
- // TODO: make things/logic nice here.
275
- // commit required in any case if recents[id] true or false (in case of unbinding) or undefined (in case of attr change).
276
- // Possible solution: separate new node commit (recents) and new attribute/move node commit
277
- // Otherwise commitNode is called on each node, which might be a lot
278
- if (!this.myNodes[id]) {
279
- continue;
280
- }
294
+ this.recents.forEach((type, id) => {
281
295
  this.commitNode(id);
282
- if (this.recents[id] === true && (node = this.app.nodes.getNode(id))) {
283
- this.app.nodes.callNodeCallbacks(node);
296
+ if (type === RecentsType.New && (node = this.app.nodes.getNode(id))) {
297
+ this.app.nodes.callNodeCallbacks(node, isStart);
284
298
  }
285
- }
299
+ });
286
300
  this.clear();
287
301
  }
288
302
  // ISSSUE
@@ -297,12 +311,11 @@ class Observer {
297
311
  });
298
312
  this.bindTree(nodeToBind);
299
313
  beforeCommit(this.app.nodes.getID(node));
300
- this.commitNodes();
314
+ this.commitNodes(true);
301
315
  }
302
316
  disconnect() {
303
317
  this.observer.disconnect();
304
318
  this.clear();
305
- this.myNodes.length = 0;
306
319
  }
307
320
  }
308
321
  exports.default = Observer;
@@ -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 context_js_1 = require("../context.js");
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
7
  const messages_js_1 = require("../../common/messages.js");
@@ -17,7 +17,7 @@ class TopObserver extends observer_js_1.default {
17
17
  }, options);
18
18
  // IFrames
19
19
  this.app.nodes.attachNodeCallback(node => {
20
- if ((0, context_js_1.isInstance)(node, HTMLIFrameElement) &&
20
+ if ((0, guards_js_1.hasTag)(node, "IFRAME") &&
21
21
  ((this.options.captureIFrames && !(0, utils_js_1.hasOpenreplayAttribute)(node, "obscured"))
22
22
  || (0, utils_js_1.hasOpenreplayAttribute)(node, "capture"))) {
23
23
  this.handleIframe(node);
@@ -25,7 +25,7 @@ class TopObserver extends observer_js_1.default {
25
25
  });
26
26
  // ShadowDOM
27
27
  this.app.nodes.attachNodeCallback(node => {
28
- if ((0, context_js_1.isInstance)(node, Element) && node.shadowRoot !== null) {
28
+ if ((0, guards_js_1.isElementNode)(node) && node.shadowRoot !== null) {
29
29
  this.handleShadowRoot(node.shadowRoot);
30
30
  }
31
31
  });
@@ -1,4 +1,4 @@
1
- import App from "./index.js";
1
+ import type App from "./index.js";
2
2
  export interface Options {
3
3
  obscureTextEmails: boolean;
4
4
  obscureTextNumbers: boolean;
@@ -6,11 +6,13 @@ export interface Options {
6
6
  export default class Sanitizer {
7
7
  private readonly app;
8
8
  private readonly masked;
9
+ private readonly maskedContainers;
9
10
  private readonly options;
10
11
  constructor(app: App, options: Partial<Options>);
11
12
  handleNode(id: number, parentID: number, node: Node): void;
12
13
  sanitize(id: number, data: string): string;
13
14
  isMasked(id: number): boolean;
15
+ isMaskedContainer(id: number): boolean;
14
16
  getInnerTextSecure(el: HTMLElement): string;
15
17
  clear(): void;
16
18
  }
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const utils_js_1 = require("../utils.js");
4
- const context_js_1 = require("./context.js");
4
+ const guards_js_1 = require("./guards.js");
5
5
  class Sanitizer {
6
6
  constructor(app, options) {
7
7
  this.app = app;
8
8
  this.masked = new Set();
9
+ this.maskedContainers = new Set();
9
10
  this.options = Object.assign({
10
11
  obscureTextEmails: true,
11
12
  obscureTextNumbers: false,
@@ -13,9 +14,15 @@ class Sanitizer {
13
14
  }
14
15
  handleNode(id, parentID, node) {
15
16
  if (this.masked.has(parentID) ||
16
- ((0, context_js_1.isInstance)(node, Element) && (0, utils_js_1.hasOpenreplayAttribute)(node, 'masked'))) {
17
+ ((0, guards_js_1.isElementNode)(node) &&
18
+ (0, utils_js_1.hasOpenreplayAttribute)(node, 'masked'))) {
17
19
  this.masked.add(id);
18
20
  }
21
+ if (this.maskedContainers.has(parentID) ||
22
+ ((0, guards_js_1.isElementNode)(node) &&
23
+ (0, utils_js_1.hasOpenreplayAttribute)(node, 'htmlmasked'))) {
24
+ this.maskedContainers.add(id);
25
+ }
19
26
  }
20
27
  sanitize(id, data) {
21
28
  if (this.masked.has(id)) {
@@ -33,6 +40,9 @@ class Sanitizer {
33
40
  isMasked(id) {
34
41
  return this.masked.has(id);
35
42
  }
43
+ isMaskedContainer(id) {
44
+ return this.maskedContainers.has(id);
45
+ }
36
46
  getInnerTextSecure(el) {
37
47
  const id = this.app.nodes.getID(el);
38
48
  if (!id) {
@@ -42,6 +52,7 @@ class Sanitizer {
42
52
  }
43
53
  clear() {
44
54
  this.masked.clear();
55
+ this.maskedContainers.clear();
45
56
  }
46
57
  }
47
58
  exports.default = Sanitizer;
@@ -1,4 +1,3 @@
1
- import App from "./index.js";
2
1
  interface SessionInfo {
3
2
  sessionID: string | null;
4
3
  metadata: Record<string, string>;
@@ -6,20 +5,16 @@ interface SessionInfo {
6
5
  }
7
6
  declare type OnUpdateCallback = (i: Partial<SessionInfo>) => void;
8
7
  export default class Session {
9
- private app;
10
8
  private metadata;
11
9
  private userID;
12
10
  private sessionID;
13
- private activityState;
14
11
  private callbacks;
15
- constructor(app: App);
16
12
  attachUpdateCallback(cb: OnUpdateCallback): void;
17
13
  private handleUpdate;
18
- update({ userID, metadata, sessionID }: Partial<SessionInfo>): void;
19
- private _setMetadata;
20
- private _setUserID;
14
+ update(newInfo: Partial<SessionInfo>): void;
21
15
  setMetadata(key: string, value: string): void;
22
16
  setUserID(userID: string): void;
23
17
  getInfo(): SessionInfo;
18
+ reset(): void;
24
19
  }
25
20
  export {};
@@ -1,61 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const messages_js_1 = require("../common/messages.js");
4
- var ActivityState;
5
- (function (ActivityState) {
6
- ActivityState[ActivityState["NotActive"] = 0] = "NotActive";
7
- ActivityState[ActivityState["Starting"] = 1] = "Starting";
8
- ActivityState[ActivityState["Active"] = 2] = "Active";
9
- })(ActivityState || (ActivityState = {}));
10
3
  class Session {
11
- constructor(app) {
12
- this.app = app;
4
+ constructor() {
13
5
  this.metadata = {};
14
6
  this.userID = null;
15
7
  this.sessionID = null;
16
- this.activityState = ActivityState.NotActive;
17
8
  this.callbacks = [];
18
9
  }
19
10
  attachUpdateCallback(cb) {
20
11
  this.callbacks.push(cb);
21
12
  }
22
- handleUpdate() {
23
- const sessInfo = this.getInfo();
24
- if (sessInfo.userID == null) {
25
- delete sessInfo.userID;
13
+ handleUpdate(newInfo) {
14
+ if (newInfo.userID == null) {
15
+ delete newInfo.userID;
26
16
  }
27
- if (sessInfo.sessionID == null) {
28
- delete sessInfo.sessionID;
17
+ if (newInfo.sessionID == null) {
18
+ delete newInfo.sessionID;
29
19
  }
30
- this.callbacks.forEach(cb => cb(sessInfo));
20
+ this.callbacks.forEach(cb => cb(newInfo));
31
21
  }
32
- update({ userID, metadata, sessionID }) {
33
- if (userID != null) { // TODO clear nullable/undefinable types
34
- this._setUserID(userID);
22
+ update(newInfo) {
23
+ if (newInfo.userID !== undefined) { // TODO clear nullable/undefinable types
24
+ this.userID = newInfo.userID;
35
25
  }
36
- if (metadata !== undefined) {
37
- Object.entries(metadata).forEach(kv => this._setMetadata(...kv));
26
+ if (newInfo.metadata !== undefined) {
27
+ Object.entries(newInfo.metadata).forEach(([k, v]) => this.metadata[k] = v);
38
28
  }
39
- if (sessionID !== undefined) {
40
- this.sessionID = sessionID;
29
+ if (newInfo.sessionID !== undefined) {
30
+ this.sessionID = newInfo.sessionID;
41
31
  }
42
- this.handleUpdate();
43
- }
44
- _setMetadata(key, value) {
45
- this.app.send(new messages_js_1.Metadata(key, value));
46
- this.metadata[key] = value;
47
- }
48
- _setUserID(userID) {
49
- this.app.send(new messages_js_1.UserID(userID));
50
- this.userID = userID;
32
+ this.handleUpdate(newInfo);
51
33
  }
52
34
  setMetadata(key, value) {
53
- this._setMetadata(key, value);
54
- this.handleUpdate();
35
+ this.metadata[key] = value;
36
+ this.handleUpdate({ metadata: { [key]: value } });
55
37
  }
56
38
  setUserID(userID) {
57
- this._setUserID(userID);
58
- this.handleUpdate();
39
+ this.userID = userID;
40
+ this.handleUpdate({ userID });
59
41
  }
60
42
  getInfo() {
61
43
  return {
@@ -64,5 +46,10 @@ class Session {
64
46
  userID: this.userID,
65
47
  };
66
48
  }
49
+ reset() {
50
+ this.metadata = {};
51
+ this.userID = null;
52
+ this.sessionID = null;
53
+ }
67
54
  }
68
55
  exports.default = Session;
package/cjs/index.js CHANGED
@@ -127,7 +127,7 @@ class API {
127
127
  // no-cors issue only with text/plain or not-set Content-Type
128
128
  // req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
129
129
  req.send(JSON.stringify({
130
- trackerVersion: '3.5.12',
130
+ trackerVersion: '3.5.14',
131
131
  projectKey: options.projectKey,
132
132
  doNotTrack,
133
133
  // TODO: add precise reason (an exact API missing)
@@ -158,7 +158,7 @@ class API {
158
158
  if (this.app === null) {
159
159
  return;
160
160
  }
161
- this.app.stop();
161
+ this.app.stop(true);
162
162
  }
163
163
  getSessionToken() {
164
164
  if (this.app === null) {
@@ -1,4 +1,4 @@
1
- import App from "../app/index.js";
1
+ import type App from "../app/index.js";
2
2
  export interface Options {
3
3
  consoleMethods: Array<string> | null;
4
4
  consoleThrottling: number;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const guards_js_1 = require("../app/guards.js");
3
4
  const utils_js_1 = require("../utils.js");
4
5
  const messages_js_1 = require("../common/messages.js");
5
6
  const printError = utils_js_1.IN_BROWSER && 'InstallTrigger' in window // detect Firefox
@@ -115,7 +116,7 @@ function default_1(app, opts) {
115
116
  });
116
117
  patchConsole(window.console);
117
118
  app.nodes.attachNodeCallback(app.safe(node => {
118
- if (node instanceof HTMLIFrameElement) {
119
+ if ((0, guards_js_1.hasTag)(node, "IFRAME")) { // TODO: newContextCallback
119
120
  let context = node.contentWindow;
120
121
  if (context) {
121
122
  patchConsole(context.console);
@@ -1,2 +1,2 @@
1
- import App from "../app/index.js";
1
+ import type App from "../app/index.js";
2
2
  export default function (app: App | null): void;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const messages_js_1 = require("../common/messages.js");
4
+ const guards_js_1 = require("../app/guards.js");
4
5
  function default_1(app) {
5
6
  if (app === null) {
6
7
  return;
@@ -32,10 +33,7 @@ function default_1(app) {
32
33
  return deleteRule.call(this, index);
33
34
  };
34
35
  app.nodes.attachNodeCallback((node) => {
35
- if (!(node instanceof HTMLStyleElement)) {
36
- return;
37
- }
38
- if (!(node.sheet instanceof CSSStyleSheet)) {
36
+ if (!(0, guards_js_1.hasTag)(node, "STYLE") || !node.sheet) {
39
37
  return;
40
38
  }
41
39
  if (node.textContent !== null && node.textContent.trim().length > 0) {
@@ -1,5 +1,5 @@
1
+ import type App from "../app/index.js";
1
2
  import type Message from "../common/messages.js";
2
- import App from "../app/index.js";
3
3
  export interface Options {
4
4
  captureExceptions: boolean;
5
5
  }
@@ -1,2 +1,2 @@
1
- import App from "../app/index.js";
1
+ import type App from "../app/index.js";
2
2
  export default function (app: App): void;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const utils_js_1 = require("../utils.js");
4
4
  const messages_js_1 = require("../common/messages.js");
5
+ const guards_js_1 = require("../app/guards.js");
5
6
  const PLACEHOLDER_SRC = "https://static.openreplay.com/tracker/placeholder.jpeg";
6
7
  function default_1(app) {
7
8
  function sendPlaceholder(id, node) {
@@ -19,7 +20,7 @@ function default_1(app) {
19
20
  if (id === undefined) {
20
21
  return;
21
22
  }
22
- const { src, complete, naturalWidth, naturalHeight } = this;
23
+ const { src, complete, naturalWidth, naturalHeight, srcset } = this;
23
24
  if (!complete) {
24
25
  return;
25
26
  }
@@ -33,29 +34,36 @@ function default_1(app) {
33
34
  }
34
35
  else {
35
36
  app.send(new messages_js_1.SetNodeAttributeURLBased(id, 'src', src, app.getBaseHref()));
37
+ srcset && app.send(new messages_js_1.SetNodeAttribute(id, 'srcset', srcset));
36
38
  }
37
39
  });
38
40
  const observer = new MutationObserver((mutations) => {
39
41
  for (const mutation of mutations) {
40
- if (mutation.type === "attributes" && mutation.attributeName === "src") {
42
+ if (mutation.type === "attributes") {
41
43
  const target = mutation.target;
42
44
  const id = app.nodes.getID(target);
43
45
  if (id === undefined) {
44
46
  return;
45
47
  }
46
- const src = target.src;
47
- app.send(new messages_js_1.SetNodeAttributeURLBased(id, 'src', src, app.getBaseHref()));
48
+ if (mutation.attributeName === "src") {
49
+ const src = target.src;
50
+ app.send(new messages_js_1.SetNodeAttributeURLBased(id, 'src', src, app.getBaseHref()));
51
+ }
52
+ if (mutation.attributeName === "srcset") {
53
+ const srcset = target.srcset;
54
+ app.send(new messages_js_1.SetNodeAttribute(id, 'srcset', srcset));
55
+ }
48
56
  }
49
57
  }
50
58
  });
51
59
  app.nodes.attachNodeCallback((node) => {
52
- if (!(node instanceof HTMLImageElement)) {
60
+ if (!(0, guards_js_1.hasTag)(node, "IMG")) {
53
61
  return;
54
62
  }
55
63
  app.nodes.attachElementListener('error', node, sendImgSrc);
56
64
  app.nodes.attachElementListener('load', node, sendImgSrc);
57
65
  sendImgSrc.call(node);
58
- observer.observe(node, { attributes: true });
66
+ observer.observe(node, { attributes: true, attributeFilter: ["src", "srcset"] });
59
67
  });
60
68
  }
61
69
  exports.default = default_1;
@@ -1,4 +1,4 @@
1
- import App from "../app/index.js";
1
+ import type App from "../app/index.js";
2
2
  declare type TextEditableElement = HTMLInputElement | HTMLTextAreaElement;
3
3
  export declare function getInputLabel(node: TextEditableElement): string;
4
4
  export declare const enum InputMode {
@@ -10,6 +10,7 @@ export interface Options {
10
10
  obscureInputNumbers: boolean;
11
11
  obscureInputEmails: boolean;
12
12
  defaultInputMode: InputMode;
13
+ obscureInputDates: boolean;
13
14
  }
14
15
  export default function (app: App, opts: Partial<Options>): void;
15
16
  export {};