@openreplay/tracker 3.6.3 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/.eslintignore +8 -0
  2. package/.prettierignore +1 -0
  3. package/LICENSE +1 -1
  4. package/cjs/app/guards.d.ts +2 -1
  5. package/cjs/app/guards.js +6 -3
  6. package/cjs/app/index.d.ts +28 -23
  7. package/cjs/app/index.js +101 -83
  8. package/cjs/app/logger.js +6 -3
  9. package/cjs/app/messages.d.ts +52 -0
  10. package/cjs/app/messages.gen.d.ts +57 -0
  11. package/cjs/app/messages.gen.js +493 -0
  12. package/cjs/app/messages.js +234 -0
  13. package/cjs/app/nodes.d.ts +1 -1
  14. package/cjs/app/nodes.js +2 -0
  15. package/cjs/app/observer/iframe_observer.d.ts +1 -1
  16. package/cjs/app/observer/iframe_observer.js +3 -3
  17. package/cjs/app/observer/observer.d.ts +2 -3
  18. package/cjs/app/observer/observer.js +50 -52
  19. package/cjs/app/observer/shadow_root_observer.d.ts +1 -1
  20. package/cjs/app/observer/shadow_root_observer.js +3 -3
  21. package/cjs/app/observer/top_observer.d.ts +13 -2
  22. package/cjs/app/observer/top_observer.js +58 -23
  23. package/cjs/app/sanitizer.d.ts +1 -1
  24. package/cjs/app/sanitizer.js +5 -5
  25. package/cjs/app/session.d.ts +20 -2
  26. package/cjs/app/session.js +65 -6
  27. package/cjs/app/ticker.d.ts +1 -1
  28. package/cjs/common/{webworker.d.ts → interaction.d.ts} +5 -5
  29. package/cjs/common/{types.js → interaction.js} +0 -0
  30. package/cjs/common/messages.gen.d.ts +382 -0
  31. package/cjs/common/{webworker.js → messages.gen.js} +1 -0
  32. package/cjs/index.d.ts +10 -9
  33. package/cjs/index.js +47 -36
  34. package/cjs/modules/adoptedStyleSheets.d.ts +2 -0
  35. package/cjs/modules/adoptedStyleSheets.js +127 -0
  36. package/cjs/modules/connection.d.ts +1 -1
  37. package/cjs/modules/connection.js +2 -2
  38. package/cjs/modules/console.d.ts +1 -1
  39. package/cjs/modules/console.js +7 -21
  40. package/cjs/modules/cssrules.d.ts +1 -1
  41. package/cjs/modules/cssrules.js +18 -14
  42. package/cjs/modules/exception.d.ts +3 -3
  43. package/cjs/modules/exception.js +23 -18
  44. package/cjs/modules/img.d.ts +1 -1
  45. package/cjs/modules/img.js +39 -26
  46. package/cjs/modules/input.d.ts +1 -1
  47. package/cjs/modules/input.js +21 -21
  48. package/cjs/modules/mouse.d.ts +1 -1
  49. package/cjs/modules/mouse.js +50 -43
  50. package/cjs/modules/performance.d.ts +1 -1
  51. package/cjs/modules/performance.js +2 -2
  52. package/cjs/modules/scroll.d.ts +1 -1
  53. package/cjs/modules/scroll.js +16 -7
  54. package/cjs/modules/timing.d.ts +1 -1
  55. package/cjs/modules/timing.js +14 -26
  56. package/cjs/modules/viewport.d.ts +1 -1
  57. package/cjs/modules/viewport.js +4 -4
  58. package/cjs/utils.js +7 -7
  59. package/cjs/vendors/finder/finder.js +53 -48
  60. package/lib/app/guards.d.ts +2 -1
  61. package/lib/app/guards.js +4 -2
  62. package/lib/app/index.d.ts +28 -23
  63. package/lib/app/index.js +109 -91
  64. package/lib/app/logger.js +6 -3
  65. package/lib/app/messages.d.ts +52 -0
  66. package/lib/app/messages.gen.d.ts +57 -0
  67. package/lib/app/messages.gen.js +434 -0
  68. package/lib/app/messages.js +181 -0
  69. package/lib/app/nodes.d.ts +1 -1
  70. package/lib/app/nodes.js +2 -0
  71. package/lib/app/observer/iframe_observer.d.ts +1 -1
  72. package/lib/app/observer/iframe_observer.js +3 -3
  73. package/lib/app/observer/observer.d.ts +2 -3
  74. package/lib/app/observer/observer.js +51 -53
  75. package/lib/app/observer/shadow_root_observer.d.ts +1 -1
  76. package/lib/app/observer/shadow_root_observer.js +3 -3
  77. package/lib/app/observer/top_observer.d.ts +13 -2
  78. package/lib/app/observer/top_observer.js +62 -27
  79. package/lib/app/sanitizer.d.ts +1 -1
  80. package/lib/app/sanitizer.js +7 -7
  81. package/lib/app/session.d.ts +20 -2
  82. package/lib/app/session.js +65 -6
  83. package/lib/app/ticker.d.ts +1 -1
  84. package/lib/common/{webworker.d.ts → interaction.d.ts} +5 -5
  85. package/lib/common/{types.js → interaction.js} +0 -0
  86. package/lib/common/messages.gen.d.ts +382 -0
  87. package/lib/common/messages.gen.js +2 -0
  88. package/lib/common/tsconfig.tsbuildinfo +1 -1
  89. package/lib/index.d.ts +10 -9
  90. package/lib/index.js +60 -49
  91. package/lib/modules/adoptedStyleSheets.d.ts +2 -0
  92. package/lib/modules/adoptedStyleSheets.js +124 -0
  93. package/lib/modules/connection.d.ts +1 -1
  94. package/lib/modules/connection.js +2 -2
  95. package/lib/modules/console.d.ts +1 -1
  96. package/lib/modules/console.js +8 -22
  97. package/lib/modules/cssrules.d.ts +1 -1
  98. package/lib/modules/cssrules.js +19 -15
  99. package/lib/modules/exception.d.ts +3 -3
  100. package/lib/modules/exception.js +23 -18
  101. package/lib/modules/img.d.ts +1 -1
  102. package/lib/modules/img.js +41 -28
  103. package/lib/modules/input.d.ts +1 -1
  104. package/lib/modules/input.js +23 -23
  105. package/lib/modules/mouse.d.ts +1 -1
  106. package/lib/modules/mouse.js +53 -46
  107. package/lib/modules/performance.d.ts +1 -1
  108. package/lib/modules/performance.js +3 -3
  109. package/lib/modules/scroll.d.ts +1 -1
  110. package/lib/modules/scroll.js +17 -8
  111. package/lib/modules/timing.d.ts +1 -1
  112. package/lib/modules/timing.js +16 -28
  113. package/lib/modules/viewport.d.ts +1 -1
  114. package/lib/modules/viewport.js +4 -4
  115. package/lib/utils.js +7 -7
  116. package/lib/vendors/finder/finder.js +53 -48
  117. package/package.json +27 -10
  118. package/cjs/common/messages.d.ts +0 -444
  119. package/cjs/common/messages.js +0 -794
  120. package/cjs/common/types.d.ts +0 -9
  121. package/cjs/modules/longtasks.d.ts +0 -2
  122. package/cjs/modules/longtasks.js +0 -26
  123. package/lib/common/messages.d.ts +0 -444
  124. package/lib/common/messages.js +0 -790
  125. package/lib/common/types.d.ts +0 -9
  126. package/lib/common/webworker.js +0 -1
  127. package/lib/modules/longtasks.d.ts +0 -2
  128. package/lib/modules/longtasks.js +0 -23
@@ -4,51 +4,85 @@ 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_js_1 = require("../../common/messages.js");
7
+ const messages_gen_js_1 = require("../messages.gen.js");
8
8
  const utils_js_1 = require("../../utils.js");
9
+ function isPatchedDocument(doc) {
10
+ // @ts-ignore
11
+ return typeof doc.__openreplay__getOffset === 'function';
12
+ }
9
13
  const attachShadowNativeFn = utils_js_1.IN_BROWSER ? Element.prototype.attachShadow : () => new ShadowRoot();
10
14
  class TopObserver extends observer_js_1.default {
11
15
  constructor(app, options) {
12
16
  super(app, true);
17
+ this.contextCallbacks = [];
18
+ // Attached once per Tracker instance
19
+ this.contextsSet = new Set();
13
20
  this.iframeObservers = [];
14
21
  this.shadowRootObservers = [];
15
22
  this.options = Object.assign({
16
- captureIFrames: true
23
+ captureIFrames: true,
17
24
  }, options);
18
25
  // IFrames
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"))) {
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'))) {
23
30
  this.handleIframe(node);
24
31
  }
25
32
  });
26
33
  // ShadowDOM
27
- this.app.nodes.attachNodeCallback(node => {
34
+ this.app.nodes.attachNodeCallback((node) => {
28
35
  if ((0, guards_js_1.isElementNode)(node) && node.shadowRoot !== null) {
29
36
  this.handleShadowRoot(node.shadowRoot);
30
37
  }
31
38
  });
32
39
  }
40
+ attachContextCallback(cb) {
41
+ this.contextCallbacks.push(cb);
42
+ }
43
+ // Le truc
44
+ getDocumentOffset(doc) {
45
+ if (isPatchedDocument(doc)) {
46
+ return doc.__openreplay__getOffset();
47
+ }
48
+ return { top: 0, left: 0 };
49
+ }
33
50
  handleIframe(iframe) {
34
51
  let doc = null;
52
+ let win = null;
35
53
  const handle = this.app.safe(() => {
36
54
  const id = this.app.nodes.getID(iframe);
37
55
  if (id === undefined) {
56
+ //log
38
57
  return;
39
- } //log
40
- if (iframe.contentDocument === doc) {
41
- return;
42
- } // How frequently can it happen?
43
- doc = iframe.contentDocument;
44
- if (!doc || !iframe.contentWindow) {
45
- return;
46
58
  }
47
- const observer = new iframe_observer_js_1.default(this.app);
48
- this.iframeObservers.push(observer);
49
- observer.observe(iframe);
59
+ const currentWin = iframe.contentWindow;
60
+ const currentDoc = iframe.contentDocument;
61
+ if (currentDoc && currentDoc !== doc) {
62
+ const observer = new iframe_observer_js_1.default(this.app);
63
+ this.iframeObservers.push(observer);
64
+ observer.observe(iframe);
65
+ doc = currentDoc;
66
+ doc.__openreplay__getOffset = () => {
67
+ const { top, left } = this.getDocumentOffset(iframe.ownerDocument);
68
+ return {
69
+ top: iframe.offsetTop + top,
70
+ left: iframe.offsetLeft + left,
71
+ };
72
+ };
73
+ }
74
+ if (currentWin &&
75
+ // Sometimes currentWin.window is null (not in specification). Such window object is not functional
76
+ currentWin === currentWin.window &&
77
+ !this.contextsSet.has(currentWin) // for each context callbacks called once per Tracker (TopObserver) instance
78
+ ) {
79
+ this.contextsSet.add(currentWin);
80
+ //@ts-ignore https://github.com/microsoft/TypeScript/issues/41684
81
+ this.contextCallbacks.forEach((cb) => cb(currentWin));
82
+ win = currentWin;
83
+ }
50
84
  });
51
- iframe.addEventListener("load", handle); // why app.attachEventListener not working?
85
+ iframe.addEventListener('load', handle); // why app.attachEventListener not working?
52
86
  handle();
53
87
  }
54
88
  handleShadowRoot(shRoot) {
@@ -60,25 +94,26 @@ class TopObserver extends observer_js_1.default {
60
94
  // Protection from several subsequent calls?
61
95
  const observer = this;
62
96
  Element.prototype.attachShadow = function () {
97
+ // eslint-disable-next-line
63
98
  const shadow = attachShadowNativeFn.apply(this, arguments);
64
99
  observer.handleShadowRoot(shadow);
65
100
  return shadow;
66
101
  };
67
102
  // Can observe documentElement (<html>) here, because it is not supposed to be changing.
68
103
  // However, it is possible in some exotic cases and may cause an ignorance of the newly created <html>
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:
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:
71
106
  // the 0-node ("fRoot") will become #document rather than documentElement as it is now.
72
107
  // Alternatively - observe(#document) then bindNode(documentElement)
73
108
  this.observeRoot(window.document, () => {
74
- this.app.send(new messages_js_1.CreateDocument());
109
+ this.app.send((0, messages_gen_js_1.CreateDocument)());
75
110
  }, window.document.documentElement);
76
111
  }
77
112
  disconnect() {
78
113
  Element.prototype.attachShadow = attachShadowNativeFn;
79
- this.iframeObservers.forEach(o => o.disconnect());
114
+ this.iframeObservers.forEach((o) => o.disconnect());
80
115
  this.iframeObservers = [];
81
- this.shadowRootObservers.forEach(o => o.disconnect());
116
+ this.shadowRootObservers.forEach((o) => o.disconnect());
82
117
  this.shadowRootObservers = [];
83
118
  super.disconnect();
84
119
  }
@@ -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) &&
18
- (0, utils_js_1.hasOpenreplayAttribute)(node, 'masked'))) {
17
+ ((0, guards_js_1.isElementNode)(node) && (0, utils_js_1.hasOpenreplayAttribute)(node, 'masked'))) {
19
18
  this.masked.add(id);
20
19
  }
21
20
  if (this.maskedContainers.has(parentID) ||
22
- ((0, guards_js_1.isElementNode)(node) &&
23
- (0, utils_js_1.hasOpenreplayAttribute)(node, 'htmlmasked'))) {
21
+ ((0, guards_js_1.isElementNode)(node) && (0, utils_js_1.hasOpenreplayAttribute)(node, 'htmlmasked'))) {
24
22
  this.maskedContainers.add(id);
25
23
  }
26
24
  }
27
25
  sanitize(id, data) {
28
26
  if (this.masked.has(id)) {
29
27
  // TODO: is it the best place to put trim() ? Might trimmed spaces be considered in layout in certain cases?
30
- return data.trim().replace(/[^\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/g, '█');
28
+ return data
29
+ .trim()
30
+ .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,19 +1,37 @@
1
+ import type App from './index.js';
1
2
  interface SessionInfo {
2
- sessionID: string | null;
3
+ sessionID: string | undefined;
3
4
  metadata: Record<string, string>;
4
5
  userID: string | null;
6
+ timestamp: number;
7
+ projectID?: string;
5
8
  }
6
9
  declare type OnUpdateCallback = (i: Partial<SessionInfo>) => void;
10
+ export declare type Options = {
11
+ session_token_key: string;
12
+ session_pageno_key: string;
13
+ };
7
14
  export default class Session {
15
+ private readonly app;
16
+ private readonly options;
8
17
  private metadata;
9
18
  private userID;
10
19
  private sessionID;
11
- private callbacks;
20
+ private readonly callbacks;
21
+ private timestamp;
22
+ private projectID;
23
+ constructor(app: App, options: Options);
12
24
  attachUpdateCallback(cb: OnUpdateCallback): void;
13
25
  private handleUpdate;
14
26
  update(newInfo: Partial<SessionInfo>): void;
15
27
  setMetadata(key: string, value: string): void;
16
28
  setUserID(userID: string): void;
29
+ private getPageNumber;
30
+ incPageNo(): number;
31
+ getSessionToken(): string | undefined;
32
+ setSessionToken(token: string): void;
33
+ applySessionHash(hash: string): void;
34
+ getSessionHash(): string | undefined;
17
35
  getInfo(): SessionInfo;
18
36
  reset(): void;
19
37
  }
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  class Session {
4
- constructor() {
4
+ constructor(app, options) {
5
+ this.app = app;
6
+ this.options = options;
5
7
  this.metadata = {};
6
8
  this.userID = null;
7
- this.sessionID = null;
8
9
  this.callbacks = [];
10
+ this.timestamp = 0;
9
11
  }
10
12
  attachUpdateCallback(cb) {
11
13
  this.callbacks.push(cb);
@@ -17,18 +19,25 @@ class Session {
17
19
  if (newInfo.sessionID == null) {
18
20
  delete newInfo.sessionID;
19
21
  }
20
- this.callbacks.forEach(cb => cb(newInfo));
22
+ this.callbacks.forEach((cb) => cb(newInfo));
21
23
  }
22
24
  update(newInfo) {
23
- if (newInfo.userID !== undefined) { // TODO clear nullable/undefinable types
25
+ if (newInfo.userID !== undefined) {
26
+ // TODO clear nullable/undefinable types
24
27
  this.userID = newInfo.userID;
25
28
  }
26
29
  if (newInfo.metadata !== undefined) {
27
- Object.entries(newInfo.metadata).forEach(([k, v]) => this.metadata[k] = v);
30
+ Object.entries(newInfo.metadata).forEach(([k, v]) => (this.metadata[k] = v));
28
31
  }
29
32
  if (newInfo.sessionID !== undefined) {
30
33
  this.sessionID = newInfo.sessionID;
31
34
  }
35
+ if (newInfo.timestamp !== undefined) {
36
+ this.timestamp = newInfo.timestamp;
37
+ }
38
+ if (newInfo.projectID !== undefined) {
39
+ this.projectID = newInfo.projectID;
40
+ }
32
41
  this.handleUpdate(newInfo);
33
42
  }
34
43
  setMetadata(key, value) {
@@ -39,17 +48,67 @@ class Session {
39
48
  this.userID = userID;
40
49
  this.handleUpdate({ userID });
41
50
  }
51
+ getPageNumber() {
52
+ const pageNoStr = this.app.sessionStorage.getItem(this.options.session_pageno_key);
53
+ if (pageNoStr == null) {
54
+ return undefined;
55
+ }
56
+ return parseInt(pageNoStr);
57
+ }
58
+ incPageNo() {
59
+ let pageNo = this.getPageNumber();
60
+ if (pageNo === undefined) {
61
+ pageNo = 0;
62
+ }
63
+ else {
64
+ pageNo++;
65
+ }
66
+ this.app.sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
67
+ return pageNo;
68
+ }
69
+ getSessionToken() {
70
+ return this.app.sessionStorage.getItem(this.options.session_token_key) || undefined;
71
+ }
72
+ setSessionToken(token) {
73
+ this.app.sessionStorage.setItem(this.options.session_token_key, token);
74
+ }
75
+ applySessionHash(hash) {
76
+ const hashParts = decodeURI(hash).split('&');
77
+ let token = hash;
78
+ let pageNoStr = '100500'; // back-compat for sessionToken
79
+ if (hashParts.length == 2) {
80
+ ;
81
+ [token, pageNoStr] = hashParts;
82
+ }
83
+ if (!pageNoStr || !token) {
84
+ return;
85
+ }
86
+ this.app.sessionStorage.setItem(this.options.session_token_key, token);
87
+ this.app.sessionStorage.setItem(this.options.session_pageno_key, pageNoStr);
88
+ }
89
+ getSessionHash() {
90
+ const pageNo = this.getPageNumber();
91
+ const token = this.getSessionToken();
92
+ if (pageNo === undefined || token === undefined) {
93
+ return;
94
+ }
95
+ return encodeURI(String(pageNo) + '&' + token);
96
+ }
42
97
  getInfo() {
43
98
  return {
44
99
  sessionID: this.sessionID,
45
100
  metadata: this.metadata,
46
101
  userID: this.userID,
102
+ timestamp: this.timestamp,
103
+ projectID: this.projectID,
47
104
  };
48
105
  }
49
106
  reset() {
107
+ this.app.sessionStorage.removeItem(this.options.session_token_key);
50
108
  this.metadata = {};
51
109
  this.userID = null;
52
- this.sessionID = null;
110
+ this.sessionID = undefined;
111
+ this.timestamp = 0;
53
112
  }
54
113
  }
55
114
  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;
@@ -1,19 +1,19 @@
1
+ import Message from './messages.gen.js';
1
2
  export interface Options {
2
3
  connAttemptCount?: number;
3
4
  connAttemptGap?: number;
4
5
  }
5
6
  declare type Start = {
6
- type: "start";
7
+ type: 'start';
7
8
  ingestPoint: string;
8
9
  pageNo: number;
9
10
  timestamp: number;
11
+ url: string;
10
12
  } & Options;
11
13
  declare type Auth = {
12
- type: "auth";
14
+ type: 'auth';
13
15
  token: string;
14
16
  beaconSizeLimit?: number;
15
17
  };
16
- export declare type WorkerMessageData = null | "stop" | Start | Auth | Array<{
17
- _id: number;
18
- }>;
18
+ export declare type WorkerMessageData = null | 'stop' | Start | Auth | Array<Message>;
19
19
  export {};
File without changes