@openreplay/tracker 3.5.12 → 3.5.13-beta.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 (62) hide show
  1. package/cjs/app/guards.d.ts +17 -0
  2. package/cjs/app/guards.js +24 -0
  3. package/cjs/app/index.d.ts +4 -0
  4. package/cjs/app/index.js +20 -16
  5. package/cjs/app/nodes.d.ts +1 -1
  6. package/cjs/app/observer/observer.d.ts +2 -2
  7. package/cjs/app/observer/observer.js +38 -46
  8. package/cjs/app/observer/top_observer.js +3 -3
  9. package/cjs/app/sanitizer.js +2 -2
  10. package/cjs/index.js +1 -1
  11. package/cjs/modules/console.d.ts +1 -1
  12. package/cjs/modules/console.js +2 -1
  13. package/cjs/modules/cssrules.d.ts +1 -1
  14. package/cjs/modules/cssrules.js +2 -4
  15. package/cjs/modules/exception.d.ts +1 -1
  16. package/cjs/modules/img.d.ts +1 -1
  17. package/cjs/modules/img.js +2 -1
  18. package/cjs/modules/input.d.ts +1 -1
  19. package/cjs/modules/input.js +13 -12
  20. package/cjs/modules/longtasks.d.ts +1 -1
  21. package/cjs/modules/mouse.d.ts +1 -1
  22. package/cjs/modules/mouse.js +3 -2
  23. package/cjs/modules/performance.d.ts +1 -1
  24. package/cjs/modules/scroll.d.ts +1 -1
  25. package/cjs/modules/scroll.js +5 -5
  26. package/cjs/modules/timing.d.ts +1 -1
  27. package/cjs/modules/timing.js +2 -1
  28. package/cjs/modules/viewport.d.ts +1 -1
  29. package/lib/app/guards.d.ts +17 -0
  30. package/lib/app/guards.js +16 -0
  31. package/lib/app/index.d.ts +4 -0
  32. package/lib/app/index.js +20 -16
  33. package/lib/app/nodes.d.ts +1 -1
  34. package/lib/app/observer/observer.d.ts +2 -2
  35. package/lib/app/observer/observer.js +34 -42
  36. package/lib/app/observer/top_observer.js +3 -3
  37. package/lib/app/sanitizer.js +2 -2
  38. package/lib/common/tsconfig.tsbuildinfo +1 -1
  39. package/lib/index.js +1 -1
  40. package/lib/modules/console.d.ts +1 -1
  41. package/lib/modules/console.js +2 -1
  42. package/lib/modules/cssrules.d.ts +1 -1
  43. package/lib/modules/cssrules.js +2 -4
  44. package/lib/modules/exception.d.ts +1 -1
  45. package/lib/modules/img.d.ts +1 -1
  46. package/lib/modules/img.js +2 -1
  47. package/lib/modules/input.d.ts +1 -1
  48. package/lib/modules/input.js +13 -12
  49. package/lib/modules/longtasks.d.ts +1 -1
  50. package/lib/modules/mouse.d.ts +1 -1
  51. package/lib/modules/mouse.js +3 -2
  52. package/lib/modules/performance.d.ts +1 -1
  53. package/lib/modules/scroll.d.ts +1 -1
  54. package/lib/modules/scroll.js +5 -5
  55. package/lib/modules/timing.d.ts +1 -1
  56. package/lib/modules/timing.js +2 -1
  57. package/lib/modules/viewport.d.ts +1 -1
  58. package/package.json +1 -1
  59. package/cjs/app/context.d.ts +0 -18
  60. package/cjs/app/context.js +0 -73
  61. package/lib/app/context.d.ts +0 -18
  62. package/lib/app/context.js +0 -68
@@ -2,12 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getInputLabel = void 0;
4
4
  const utils_js_1 = require("../utils.js");
5
+ const guards_js_1 = require("../app/guards.js");
5
6
  const messages_js_1 = require("../common/messages.js");
6
7
  function isTextEditable(node) {
7
- if (node instanceof HTMLTextAreaElement) {
8
+ if ((0, guards_js_1.hasTag)(node, "TEXTAREA")) {
8
9
  return true;
9
10
  }
10
- if (!(node instanceof HTMLInputElement)) {
11
+ if (!(0, guards_js_1.hasTag)(node, "INPUT")) {
11
12
  return false;
12
13
  }
13
14
  const type = node.type;
@@ -19,7 +20,7 @@ function isTextEditable(node) {
19
20
  type === 'range');
20
21
  }
21
22
  function isCheckable(node) {
22
- if (!(node instanceof HTMLInputElement)) {
23
+ if (!(0, guards_js_1.hasTag)(node, "INPUT")) {
23
24
  return false;
24
25
  }
25
26
  const type = node.type;
@@ -29,7 +30,7 @@ const labelElementFor = utils_js_1.IN_BROWSER && 'labels' in HTMLInputElement.pr
29
30
  ? (node) => {
30
31
  let p = node;
31
32
  while ((p = p.parentNode) !== null) {
32
- if (p instanceof HTMLLabelElement) {
33
+ if ((0, guards_js_1.hasTag)(p, "LABEL")) {
33
34
  return p;
34
35
  }
35
36
  }
@@ -41,7 +42,7 @@ const labelElementFor = utils_js_1.IN_BROWSER && 'labels' in HTMLInputElement.pr
41
42
  : (node) => {
42
43
  let p = node;
43
44
  while ((p = p.parentNode) !== null) {
44
- if (p instanceof HTMLLabelElement) {
45
+ if ((0, guards_js_1.hasTag)(p, "LABEL")) {
45
46
  return p;
46
47
  }
47
48
  }
@@ -71,7 +72,7 @@ function default_1(app, opts) {
71
72
  const options = Object.assign({
72
73
  obscureInputNumbers: true,
73
74
  obscureInputEmails: true,
74
- defaultInputMode: 0 /* Plain */,
75
+ defaultInputMode: 0 /* InputMode.Plain */,
75
76
  }, opts);
76
77
  function sendInputTarget(id, node) {
77
78
  const label = getInputLabel(node);
@@ -83,22 +84,22 @@ function default_1(app, opts) {
83
84
  let value = node.value;
84
85
  let inputMode = options.defaultInputMode;
85
86
  if (node.type === 'password' || (0, utils_js_1.hasOpenreplayAttribute)(node, 'hidden')) {
86
- inputMode = 2 /* Hidden */;
87
+ inputMode = 2 /* InputMode.Hidden */;
87
88
  }
88
89
  else if ((0, utils_js_1.hasOpenreplayAttribute)(node, 'obscured') ||
89
- (inputMode === 0 /* Plain */ &&
90
+ (inputMode === 0 /* InputMode.Plain */ &&
90
91
  ((options.obscureInputNumbers && /\d\d\d\d/.test(value)) ||
91
92
  (options.obscureInputEmails &&
92
93
  (node.type === 'email' || !!~value.indexOf('@')))))) {
93
- inputMode = 1 /* Obscured */;
94
+ inputMode = 1 /* InputMode.Obscured */;
94
95
  }
95
96
  let mask = 0;
96
97
  switch (inputMode) {
97
- case 2 /* Hidden */:
98
+ case 2 /* InputMode.Hidden */:
98
99
  mask = -1;
99
100
  value = '';
100
101
  break;
101
- case 1 /* Obscured */:
102
+ case 1 /* InputMode.Obscured */:
102
103
  mask = value.length;
103
104
  value = '';
104
105
  break;
@@ -148,7 +149,7 @@ function default_1(app, opts) {
148
149
  return;
149
150
  }
150
151
  // TODO: support multiple select (?): use selectedOptions; Need send target?
151
- if (node instanceof HTMLSelectElement) {
152
+ if ((0, guards_js_1.hasTag)(node, "SELECT")) {
152
153
  sendInputValue(id, node);
153
154
  app.attachEventListener(node, "change", () => {
154
155
  sendInputValue(id, node);
@@ -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;
@@ -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;
@@ -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 input_js_1 = require("./input.js");
@@ -49,7 +50,7 @@ function _getTarget(target) {
49
50
  }
50
51
  element = element.parentElement;
51
52
  }
52
- if (target instanceof SVGElement) {
53
+ if ((0, guards_js_1.isSVGElement)(target)) {
53
54
  let owner = target.ownerSVGElement;
54
55
  while (owner !== null) {
55
56
  target = owner;
@@ -79,7 +80,7 @@ function default_1(app) {
79
80
  if (dl !== null) {
80
81
  return dl;
81
82
  }
82
- if (target instanceof HTMLInputElement) {
83
+ if ((0, guards_js_1.hasTag)(target, "INPUT")) {
83
84
  return (0, input_js_1.getInputLabel)(target);
84
85
  }
85
86
  if (isClickable(target)) {
@@ -1,4 +1,4 @@
1
- import App from "../app/index.js";
1
+ import type App from "../app/index.js";
2
2
  export declare const deviceMemory: number;
3
3
  export declare const jsHeapSizeLimit: number;
4
4
  export interface Options {
@@ -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;
@@ -22,11 +22,11 @@ function default_1(app) {
22
22
  documentScroll = false;
23
23
  nodeScroll.clear();
24
24
  });
25
- app.nodes.attachNodeCallback(node => {
26
- if (node instanceof Element && node.scrollLeft + node.scrollTop > 0) {
27
- nodeScroll.set(node, [node.scrollLeft, node.scrollTop]);
28
- }
29
- });
25
+ // app.nodes.attachNodeCallback(node => {
26
+ // if (isElementNode(node) && node.scrollLeft + node.scrollTop > 0) {
27
+ // nodeScroll.set(node, [node.scrollLeft, node.scrollTop]);
28
+ // }
29
+ // })
30
30
  app.attachEventListener(window, 'scroll', (e) => {
31
31
  const target = e.target;
32
32
  if (target === document) {
@@ -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
  captureResourceTimings: boolean;
4
4
  capturePageLoadTimings: boolean;
@@ -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
  function getPaintBlocks(resources) {
@@ -9,7 +10,7 @@ function getPaintBlocks(resources) {
9
10
  for (let i = 0; i < elements.length; i++) {
10
11
  const element = elements[i];
11
12
  let src = '';
12
- if (element instanceof HTMLImageElement) {
13
+ if ((0, guards_js_1.hasTag)(element, "IMG")) {
13
14
  src = element.currentSrc || element.src;
14
15
  }
15
16
  if (!src) {
@@ -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;
@@ -0,0 +1,17 @@
1
+ export declare function isSVGElement(node: Element): node is SVGElement;
2
+ export declare function isElementNode(node: Node): node is Element;
3
+ export declare function isTextNode(node: Node): node is Text;
4
+ export declare function isRootNode(node: Node): boolean;
5
+ declare type TagTypeMap = {
6
+ HTML: HTMLHtmlElement;
7
+ IMG: HTMLImageElement;
8
+ INPUT: HTMLInputElement;
9
+ TEXTAREA: HTMLTextAreaElement;
10
+ SELECT: HTMLSelectElement;
11
+ LABEL: HTMLLabelElement;
12
+ IFRAME: HTMLIFrameElement;
13
+ STYLE: HTMLStyleElement | SVGStyleElement;
14
+ LINK: HTMLLinkElement;
15
+ };
16
+ export declare function hasTag<T extends keyof TagTypeMap>(el: Node, tagName: T): el is TagTypeMap[typeof tagName];
17
+ export {};
@@ -0,0 +1,16 @@
1
+ export function isSVGElement(node) {
2
+ return node.namespaceURI === 'http://www.w3.org/2000/svg';
3
+ }
4
+ export function isElementNode(node) {
5
+ return node.nodeType === Node.ELEMENT_NODE;
6
+ }
7
+ export function isTextNode(node) {
8
+ return node.nodeType === Node.TEXT_NODE;
9
+ }
10
+ export function isRootNode(node) {
11
+ return node.nodeType === Node.DOCUMENT_NODE ||
12
+ node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
13
+ }
14
+ export function hasTag(el, tagName) {
15
+ return el.nodeName.toUpperCase() === tagName;
16
+ }
@@ -44,6 +44,8 @@ declare type AppOptions = {
44
44
  __is_snippet: boolean;
45
45
  __debug_report_edp: string | null;
46
46
  __debug__?: LoggerOptions;
47
+ localStorage: Storage;
48
+ sessionStorage: Storage;
47
49
  onStart?: StartCallback;
48
50
  } & WebworkerOptions;
49
51
  export declare type Options = AppOptions & ObserverOptions & SanitizerOptions;
@@ -56,6 +58,8 @@ export default class App {
56
58
  readonly debug: Logger;
57
59
  readonly notify: Logger;
58
60
  readonly session: Session;
61
+ readonly localStorage: Storage;
62
+ readonly sessionStorage: Storage;
59
63
  private readonly messages;
60
64
  private readonly observer;
61
65
  private readonly startCallbacks;
package/lib/app/index.js CHANGED
@@ -29,7 +29,7 @@ export default class App {
29
29
  this.stopCallbacks = [];
30
30
  this.commitCallbacks = [];
31
31
  this.activityState = ActivityState.NotActive;
32
- this.version = '3.5.12'; // TODO: version compatability check inside each plugin.
32
+ this.version = '3.5.13-beta.0'; // TODO: version compatability check inside each plugin.
33
33
  this.projectKey = projectKey;
34
34
  this.options = Object.assign({
35
35
  revID: '',
@@ -43,10 +43,9 @@ export default class App {
43
43
  verbose: false,
44
44
  __is_snippet: false,
45
45
  __debug_report_edp: null,
46
+ localStorage: window.localStorage,
47
+ sessionStorage: window.sessionStorage,
46
48
  }, options);
47
- if (sessionToken != null) {
48
- sessionStorage.setItem(this.options.session_token_key, sessionToken);
49
- }
50
49
  this.revID = this.options.revID;
51
50
  this.sanitizer = new Sanitizer(this, options);
52
51
  this.nodes = new Nodes(this.options.node_id);
@@ -56,6 +55,11 @@ export default class App {
56
55
  this.debug = new Logger(this.options.__debug__);
57
56
  this.notify = new Logger(this.options.verbose ? LogLevel.Warnings : LogLevel.Silent);
58
57
  this.session = new Session(this);
58
+ this.localStorage = this.options.localStorage;
59
+ this.sessionStorage = this.options.sessionStorage;
60
+ if (sessionToken != null) {
61
+ this.sessionStorage.setItem(this.options.session_token_key, sessionToken);
62
+ }
59
63
  try {
60
64
  this.worker = new Worker(URL.createObjectURL(new Blob([`"use strict";function t(t){function i(...i){return new t(...i)}return i.prototype=t.prototype,i}const i=new Map;const s=t(class{constructor(t,i,s){this.pageNo=t,this.firstIndex=i,this.timestamp=s,this._id=80}encode(t){return t.uint(80)&&t.uint(this.pageNo)&&t.uint(this.firstIndex)&&t.int(this.timestamp)}});i.set(80,s);const e=t(class{constructor(t){this.timestamp=t,this._id=0}encode(t){return t.uint(0)&&t.uint(this.timestamp)}});i.set(0,e);const n=t(class{constructor(t,i,s){this.url=t,this.referrer=i,this.navigationStart=s,this._id=4}encode(t){return t.uint(4)&&t.string(this.url)&&t.string(this.referrer)&&t.uint(this.navigationStart)}});i.set(4,n);const r=t(class{constructor(t,i){this.width=t,this.height=i,this._id=5}encode(t){return t.uint(5)&&t.uint(this.width)&&t.uint(this.height)}});i.set(5,r);const h=t(class{constructor(t,i){this.x=t,this.y=i,this._id=6}encode(t){return t.uint(6)&&t.int(this.x)&&t.int(this.y)}});i.set(6,h);const o=t(class{constructor(){this._id=7}encode(t){return t.uint(7)}});i.set(7,o);const c=t(class{constructor(t,i,s,e,n){this.id=t,this.parentID=i,this.index=s,this.tag=e,this.svg=n,this._id=8}encode(t){return t.uint(8)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)&&t.string(this.tag)&&t.boolean(this.svg)}});i.set(8,c);const a=t(class{constructor(t,i,s){this.id=t,this.parentID=i,this.index=s,this._id=9}encode(t){return t.uint(9)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});i.set(9,a);const u=t(class{constructor(t,i,s){this.id=t,this.parentID=i,this.index=s,this._id=10}encode(t){return t.uint(10)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});i.set(10,u);const d=t(class{constructor(t){this.id=t,this._id=11}encode(t){return t.uint(11)&&t.uint(this.id)}});i.set(11,d);const l=t(class{constructor(t,i,s){this.id=t,this.name=i,this.value=s,this._id=12}encode(t){return t.uint(12)&&t.uint(this.id)&&t.string(this.name)&&t.string(this.value)}});i.set(12,l);const p=t(class{constructor(t,i){this.id=t,this.name=i,this._id=13}encode(t){return t.uint(13)&&t.uint(this.id)&&t.string(this.name)}});i.set(13,p);const m=t(class{constructor(t,i){this.id=t,this.data=i,this._id=14}encode(t){return t.uint(14)&&t.uint(this.id)&&t.string(this.data)}});i.set(14,m);const g=t(class{constructor(t,i,s){this.id=t,this.x=i,this.y=s,this._id=16}encode(t){return t.uint(16)&&t.uint(this.id)&&t.int(this.x)&&t.int(this.y)}});i.set(16,g);const f=t(class{constructor(t,i){this.id=t,this.label=i,this._id=17}encode(t){return t.uint(17)&&t.uint(this.id)&&t.string(this.label)}});i.set(17,f);const y=t(class{constructor(t,i,s){this.id=t,this.value=i,this.mask=s,this._id=18}encode(t){return t.uint(18)&&t.uint(this.id)&&t.string(this.value)&&t.int(this.mask)}});i.set(18,y);const _=t(class{constructor(t,i){this.id=t,this.checked=i,this._id=19}encode(t){return t.uint(19)&&t.uint(this.id)&&t.boolean(this.checked)}});i.set(19,_);const v=t(class{constructor(t,i){this.x=t,this.y=i,this._id=20}encode(t){return t.uint(20)&&t.uint(this.x)&&t.uint(this.y)}});i.set(20,v);const b=t(class{constructor(t,i){this.level=t,this.value=i,this._id=22}encode(t){return t.uint(22)&&t.string(this.level)&&t.string(this.value)}});i.set(22,b);const S=t(class{constructor(t,i,s,e,n,r,h,o,c){this.requestStart=t,this.responseStart=i,this.responseEnd=s,this.domContentLoadedEventStart=e,this.domContentLoadedEventEnd=n,this.loadEventStart=r,this.loadEventEnd=h,this.firstPaint=o,this.firstContentfulPaint=c,this._id=23}encode(t){return t.uint(23)&&t.uint(this.requestStart)&&t.uint(this.responseStart)&&t.uint(this.responseEnd)&&t.uint(this.domContentLoadedEventStart)&&t.uint(this.domContentLoadedEventEnd)&&t.uint(this.loadEventStart)&&t.uint(this.loadEventEnd)&&t.uint(this.firstPaint)&&t.uint(this.firstContentfulPaint)}});i.set(23,S);const w=t(class{constructor(t,i,s){this.speedIndex=t,this.visuallyComplete=i,this.timeToInteractive=s,this._id=24}encode(t){return t.uint(24)&&t.uint(this.speedIndex)&&t.uint(this.visuallyComplete)&&t.uint(this.timeToInteractive)}});i.set(24,w);const E=t(class{constructor(t,i,s){this.name=t,this.message=i,this.payload=s,this._id=25}encode(t){return t.uint(25)&&t.string(this.name)&&t.string(this.message)&&t.string(this.payload)}});i.set(25,E);const x=t(class{constructor(t,i){this.name=t,this.payload=i,this._id=27}encode(t){return t.uint(27)&&t.string(this.name)&&t.string(this.payload)}});i.set(27,x);const T=t(class{constructor(t){this.id=t,this._id=28}encode(t){return t.uint(28)&&t.string(this.id)}});i.set(28,T);const z=t(class{constructor(t){this.id=t,this._id=29}encode(t){return t.uint(29)&&t.string(this.id)}});i.set(29,z);const k=t(class{constructor(t,i){this.key=t,this.value=i,this._id=30}encode(t){return t.uint(30)&&t.string(this.key)&&t.string(this.value)}});i.set(30,k);const I=t(class{constructor(t,i,s){this.id=t,this.rule=i,this.index=s,this._id=37}encode(t){return t.uint(37)&&t.uint(this.id)&&t.string(this.rule)&&t.uint(this.index)}});i.set(37,I);const M=t(class{constructor(t,i){this.id=t,this.index=i,this._id=38}encode(t){return t.uint(38)&&t.uint(this.id)&&t.uint(this.index)}});i.set(38,M);const B=t(class{constructor(t,i,s,e,n,r,h){this.method=t,this.url=i,this.request=s,this.response=e,this.status=n,this.timestamp=r,this.duration=h,this._id=39}encode(t){return t.uint(39)&&t.string(this.method)&&t.string(this.url)&&t.string(this.request)&&t.string(this.response)&&t.uint(this.status)&&t.uint(this.timestamp)&&t.uint(this.duration)}});i.set(39,B);const L=t(class{constructor(t,i,s,e){this.name=t,this.duration=i,this.args=s,this.result=e,this._id=40}encode(t){return t.uint(40)&&t.string(this.name)&&t.uint(this.duration)&&t.string(this.args)&&t.string(this.result)}});i.set(40,L);const C=t(class{constructor(t,i){this.key=t,this.value=i,this._id=41}encode(t){return t.uint(41)&&t.string(this.key)&&t.string(this.value)}});i.set(41,C);const A=t(class{constructor(t){this.type=t,this._id=42}encode(t){return t.uint(42)&&t.string(this.type)}});i.set(42,A);const U=t(class{constructor(t,i,s){this.action=t,this.state=i,this.duration=s,this._id=44}encode(t){return t.uint(44)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});i.set(44,U);const N=t(class{constructor(t,i){this.mutation=t,this.state=i,this._id=45}encode(t){return t.uint(45)&&t.string(this.mutation)&&t.string(this.state)}});i.set(45,N);const R=t(class{constructor(t,i){this.type=t,this.payload=i,this._id=46}encode(t){return t.uint(46)&&t.string(this.type)&&t.string(this.payload)}});i.set(46,R);const O=t(class{constructor(t,i,s){this.action=t,this.state=i,this.duration=s,this._id=47}encode(t){return t.uint(47)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});i.set(47,O);const P=t(class{constructor(t,i,s,e){this.operationKind=t,this.operationName=i,this.variables=s,this.response=e,this._id=48}encode(t){return t.uint(48)&&t.string(this.operationKind)&&t.string(this.operationName)&&t.string(this.variables)&&t.string(this.response)}});i.set(48,P);const q=t(class{constructor(t,i,s,e){this.frames=t,this.ticks=i,this.totalJSHeapSize=s,this.usedJSHeapSize=e,this._id=49}encode(t){return t.uint(49)&&t.int(this.frames)&&t.int(this.ticks)&&t.uint(this.totalJSHeapSize)&&t.uint(this.usedJSHeapSize)}});i.set(49,q);const D=t(class{constructor(t,i,s,e,n,r,h,o){this.timestamp=t,this.duration=i,this.ttfb=s,this.headerSize=e,this.encodedBodySize=n,this.decodedBodySize=r,this.url=h,this.initiator=o,this._id=53}encode(t){return t.uint(53)&&t.uint(this.timestamp)&&t.uint(this.duration)&&t.uint(this.ttfb)&&t.uint(this.headerSize)&&t.uint(this.encodedBodySize)&&t.uint(this.decodedBodySize)&&t.string(this.url)&&t.string(this.initiator)}});i.set(53,D);const W=t(class{constructor(t,i){this.downlink=t,this.type=i,this._id=54}encode(t){return t.uint(54)&&t.uint(this.downlink)&&t.string(this.type)}});i.set(54,W);const H=t(class{constructor(t){this.hidden=t,this._id=55}encode(t){return t.uint(55)&&t.boolean(this.hidden)}});i.set(55,H);const J=t(class{constructor(t,i,s,e,n,r,h){this.timestamp=t,this.duration=i,this.context=s,this.containerType=e,this.containerSrc=n,this.containerId=r,this.containerName=h,this._id=59}encode(t){return t.uint(59)&&t.uint(this.timestamp)&&t.uint(this.duration)&&t.uint(this.context)&&t.uint(this.containerType)&&t.string(this.containerSrc)&&t.string(this.containerId)&&t.string(this.containerName)}});i.set(59,J);const F=t(class{constructor(t,i,s,e){this.id=t,this.name=i,this.value=s,this.baseURL=e,this._id=60}encode(t){return t.uint(60)&&t.uint(this.id)&&t.string(this.name)&&t.string(this.value)&&t.string(this.baseURL)}});i.set(60,F);const X=t(class{constructor(t,i,s){this.id=t,this.data=i,this.baseURL=s,this._id=61}encode(t){return t.uint(61)&&t.uint(this.id)&&t.string(this.data)&&t.string(this.baseURL)}});i.set(61,X);const G=t(class{constructor(t,i){this.type=t,this.value=i,this._id=63}encode(t){return t.uint(63)&&t.string(this.type)&&t.string(this.value)}});i.set(63,G);const K=t(class{constructor(t,i){this.name=t,this.payload=i,this._id=64}encode(t){return t.uint(64)&&t.string(this.name)&&t.string(this.payload)}});i.set(64,K);const j=t(class{constructor(){this._id=65}encode(t){return t.uint(65)}});i.set(65,j);const Q=t(class{constructor(t,i,s,e){this.id=t,this.rule=i,this.index=s,this.baseURL=e,this._id=67}encode(t){return t.uint(67)&&t.uint(this.id)&&t.string(this.rule)&&t.uint(this.index)&&t.string(this.baseURL)}});i.set(67,Q);const V=t(class{constructor(t,i,s,e){this.id=t,this.hesitationTime=i,this.label=s,this.selector=e,this._id=69}encode(t){return t.uint(69)&&t.uint(this.id)&&t.uint(this.hesitationTime)&&t.string(this.label)&&t.string(this.selector)}});i.set(69,V);const Y=t(class{constructor(t,i){this.frameID=t,this.id=i,this._id=70}encode(t){return t.uint(70)&&t.uint(this.frameID)&&t.uint(this.id)}});i.set(70,Y);class Z{constructor(t,i,s,e=10,n=1e3){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.ingestURL=t+"/v1/web/i"}authorise(t){this.token=t}push(t){this.busy||!this.token?this.queue.push(t):this.sendBatch(t)}retry(t){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure():(this.attemptsCount++,setTimeout(()=>this.sendBatch(t),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t){this.busy=!0,fetch(this.ingestURL,{body:t,method:"POST",headers:{Authorization:"Bearer "+this.token},keepalive:t.length<65536}).then(i=>{if(401===i.status)return this.busy=!1,void this.onUnauthorised();if(i.status>=400)return void this.retry(t);this.attemptsCount=0;const s=this.queue.shift();s?this.sendBatch(s):this.busy=!1}).catch(i=>{console.warn("OpenReplay:",i),this.retry(t)})}clean(){this.queue.length=0}}const tt="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(var n=0,r=0,h=0;h!==i;){if(n=t.charCodeAt(h),h+=1,n>=55296&&n<=56319){if(h===i){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;break}if(!((r=t.charCodeAt(h))>=56320&&r<=57343)){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;continue}if(h+=1,(n=1024*(n-55296)+r-56320+65536)>65535){s[e+=1]=240|n>>>18,s[e+=1]=128|n>>>12&63,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n;continue}}n<=127?s[e+=1]=0|n:n<=2047?(s[e+=1]=192|n>>>6,s[e+=1]=128|63&n):(s[e+=1]=224|n>>>12,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n)}return s.subarray(0,e+1)}};class it{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}checkpoint(){this.checkpointOffset=this.offset}isEmpty(){return 0===this.offset}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(t){const i=tt.encode(t),s=i.byteLength;return!(!this.uint(s)||this.offset+s>this.size)&&(this.data.set(i,this.offset),this.offset+=s,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}class st{constructor(t,i,s){this.pageNo=t,this.timestamp=i,this.onBatch=s,this.nextIndex=0,this.beaconSize=2e5,this.writer=new it(this.beaconSize),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepareBatchMeta()}prepareBatchMeta(){return new s(this.pageNo,this.nextIndex,this.timestamp).encode(this.writer)}setBeaconSizeLimit(t){this.beaconSizeLimit=t}writeMessage(t){if(t instanceof e&&(this.timestamp=t.timestamp),!t.encode(this.writer))for(this.isEmpty||(this.onBatch(this.writer.flush()),this.prepareBatchMeta());!t.encode(this.writer);){if(this.beaconSize===this.beaconSizeLimit)return console.warn("OpenReplay: beacon size overflow. Skipping large message."),this.writer.reset(),this.prepareBatchMeta(),void(this.isEmpty=!0);this.beaconSize=Math.min(2*this.beaconSize,this.beaconSizeLimit),this.writer=new it(this.beaconSize),this.prepareBatchMeta()}this.writer.checkpoint(),this.nextIndex++,this.isEmpty=!1}finaliseBatch(){this.isEmpty||(this.onBatch(this.writer.flush()),this.prepareBatchMeta(),this.isEmpty=!0)}clean(){this.writer.reset()}}let et=null,nt=null;function rt(){nt&&nt.finaliseBatch()}function ht(){null!==ct&&(clearInterval(ct),ct=null),nt&&(nt.clean(),nt=null)}let ot,ct=null;self.onmessage=({data:t})=>{if(null!=t){if("stop"===t)return rt(),void ht();if(Array.isArray(t)){if(!nt)throw new Error("WebWorker: writer not initialised.");const s=nt;t.forEach(t=>{const e=new(i.get(t._id));Object.assign(e,t),e instanceof H&&(e.hidden?ot=setTimeout(()=>self.postMessage("restart"),18e5):clearTimeout(ot)),s.writeMessage(e)})}else{if("start"===t.type)return et=new Z(t.ingestPoint,()=>{self.postMessage("restart")},()=>{et&&(et.clean(),et=null),ht(),self.postMessage("failed")},t.connAttemptCount,t.connAttemptGap),nt=new st(t.pageNo,t.timestamp,t=>et&&et.push(t)),void(null===ct&&(ct=setInterval(rt,1e4)));if("auth"===t.type){if(!et)throw new Error("WebWorker: sender not initialised. Recieved auth.");if(!nt)throw new Error("WebWorker: writer not initialised. Recieved auth.");return et.authorise(t.token),void(t.beaconSizeLimit&&nt.setBeaconSizeLimit(t.beaconSizeLimit))}}}else rt()};
61
65
  `], { type: 'text/javascript' })));
@@ -163,7 +167,7 @@ export default class App {
163
167
  }
164
168
  getStartInfo() {
165
169
  return {
166
- userUUID: localStorage.getItem(this.options.local_uuid_key),
170
+ userUUID: this.localStorage.getItem(this.options.local_uuid_key),
167
171
  projectKey: this.projectKey,
168
172
  revID: this.revID,
169
173
  timestamp: timestamp(),
@@ -175,7 +179,7 @@ export default class App {
175
179
  return Object.assign(Object.assign({}, this.session.getInfo()), this.getStartInfo());
176
180
  }
177
181
  getSessionToken() {
178
- const token = sessionStorage.getItem(this.options.session_token_key);
182
+ const token = this.sessionStorage.getItem(this.options.session_token_key);
179
183
  if (token !== null) {
180
184
  return token;
181
185
  }
@@ -217,10 +221,10 @@ export default class App {
217
221
  }
218
222
  resetNextPageSession(flag) {
219
223
  if (flag) {
220
- sessionStorage.setItem(this.options.session_reset_key, 't');
224
+ this.sessionStorage.setItem(this.options.session_reset_key, 't');
221
225
  }
222
226
  else {
223
- sessionStorage.removeItem(this.options.session_reset_key);
227
+ this.sessionStorage.removeItem(this.options.session_reset_key);
224
228
  }
225
229
  }
226
230
  _start(startOpts) {
@@ -232,12 +236,12 @@ export default class App {
232
236
  }
233
237
  this.activityState = ActivityState.Starting;
234
238
  let pageNo = 0;
235
- const pageNoStr = sessionStorage.getItem(this.options.session_pageno_key);
239
+ const pageNoStr = this.sessionStorage.getItem(this.options.session_pageno_key);
236
240
  if (pageNoStr != null) {
237
241
  pageNo = parseInt(pageNoStr);
238
242
  pageNo++;
239
243
  }
240
- sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
244
+ this.sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
241
245
  const startInfo = this.getStartInfo();
242
246
  const startWorkerMsg = {
243
247
  type: "start",
@@ -248,14 +252,14 @@ export default class App {
248
252
  connAttemptGap: this.options.connAttemptGap,
249
253
  };
250
254
  this.worker.postMessage(startWorkerMsg); // brings delay of 10th ms?
251
- const sReset = sessionStorage.getItem(this.options.session_reset_key);
252
- sessionStorage.removeItem(this.options.session_reset_key);
255
+ const sReset = this.sessionStorage.getItem(this.options.session_reset_key);
256
+ this.sessionStorage.removeItem(this.options.session_reset_key);
253
257
  return window.fetch(this.options.ingestPoint + '/v1/web/start', {
254
258
  method: 'POST',
255
259
  headers: {
256
260
  'Content-Type': 'application/json',
257
261
  },
258
- body: JSON.stringify(Object.assign(Object.assign({}, startInfo), { userID: startOpts.userID || this.session.getInfo().userID, token: sessionStorage.getItem(this.options.session_token_key), deviceMemory,
262
+ body: JSON.stringify(Object.assign(Object.assign({}, startInfo), { userID: startOpts.userID || this.session.getInfo().userID, token: this.sessionStorage.getItem(this.options.session_token_key), deviceMemory,
259
263
  jsHeapSizeLimit, reset: startOpts.forceNew || sReset !== null })),
260
264
  })
261
265
  .then(r => {
@@ -278,8 +282,8 @@ export default class App {
278
282
  (typeof beaconSizeLimit !== 'number' && typeof beaconSizeLimit !== 'undefined')) {
279
283
  return Promise.reject(`Incorrect server response: ${JSON.stringify(r)}`);
280
284
  }
281
- sessionStorage.setItem(this.options.session_token_key, token);
282
- localStorage.setItem(this.options.local_uuid_key, userUUID);
285
+ this.sessionStorage.setItem(this.options.session_token_key, token);
286
+ this.localStorage.setItem(this.options.local_uuid_key, userUUID);
283
287
  this.session.update(Object.assign({ sessionID }, startOpts));
284
288
  this.activityState = ActivityState.Active;
285
289
  const startWorkerMsg = {
@@ -300,7 +304,7 @@ export default class App {
300
304
  return SuccessfulStart(onStartInfo);
301
305
  })
302
306
  .catch(reason => {
303
- sessionStorage.removeItem(this.options.session_token_key);
307
+ this.sessionStorage.removeItem(this.options.session_token_key);
304
308
  this.stop();
305
309
  if (reason === CANCELED) {
306
310
  return UnsuccessfulStart(CANCELED);
@@ -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): [number, boolean];
10
+ registerNode(node: Node): [id: number, isNew: boolean];
11
11
  unregisterNode(node: Node): number | undefined;
12
12
  callNodeCallbacks(node: Node): void;
13
13
  getID(node: Node): number | undefined;
@@ -4,11 +4,11 @@ export default abstract class Observer {
4
4
  protected readonly isTopContext: boolean;
5
5
  private readonly observer;
6
6
  private readonly commited;
7
- private readonly recents;
8
- private readonly myNodes;
9
7
  private readonly indexes;
10
8
  private readonly attributesList;
11
9
  private readonly textSet;
10
+ private readonly newSet;
11
+ private readonly affectedSet;
12
12
  constructor(app: App, isTopContext?: boolean);
13
13
  private clear;
14
14
  private sendNodeAttribute;
@@ -1,13 +1,10 @@
1
1
  import { RemoveNodeAttribute, SetNodeAttribute, SetNodeAttributeURLBased, SetCSSDataURLBased, SetNodeData, CreateTextNode, CreateElementNode, MoveNode, RemoveNode, } from "../../common/messages.js";
2
- import { isInstance, inDocument } from "../context.js";
3
- function isSVGElement(node) {
4
- return node.namespaceURI === 'http://www.w3.org/2000/svg';
5
- }
2
+ import { isRootNode, isTextNode, isElementNode, isSVGElement, hasTag, } from "../guards.js";
6
3
  function isIgnored(node) {
7
- if (isInstance(node, Text)) {
4
+ if (isTextNode(node)) {
8
5
  return false;
9
6
  }
10
- if (!isInstance(node, Element)) {
7
+ if (!isElementNode(node)) {
11
8
  return true;
12
9
  }
13
10
  const tag = node.tagName.toUpperCase();
@@ -22,9 +19,6 @@ function isIgnored(node) {
22
19
  tag === 'TITLE' ||
23
20
  tag === 'BASE');
24
21
  }
25
- function isRootNode(node) {
26
- return isInstance(node, Document) || isInstance(node, ShadowRoot);
27
- }
28
22
  function isObservable(node) {
29
23
  if (isRootNode(node)) {
30
24
  return true;
@@ -36,20 +30,23 @@ export default class Observer {
36
30
  this.app = app;
37
31
  this.isTopContext = isTopContext;
38
32
  this.commited = [];
39
- this.recents = [];
40
- this.myNodes = [];
41
33
  this.indexes = [];
42
34
  this.attributesList = [];
43
35
  this.textSet = new Set();
36
+ this.newSet = new Set();
37
+ this.affectedSet = new Set();
44
38
  this.observer = new MutationObserver(this.app.safe((mutations) => {
45
39
  for (const mutation of mutations) {
46
40
  const target = mutation.target;
47
41
  const type = mutation.type;
48
- if (!isObservable(target) || !inDocument(target)) {
42
+ if (!isObservable(target) /*|| !inDocument() */) {
49
43
  continue;
50
44
  }
51
45
  if (type === 'childList') {
52
46
  for (let i = 0; i < mutation.removedNodes.length; i++) {
47
+ // TODO: handle node removal separately from binding.
48
+ // Node removals should go first in the commit.
49
+ // To check: MoveNode and other possible unbinding behaviours
53
50
  this.bindTree(mutation.removedNodes[i]);
54
51
  }
55
52
  for (let i = 0; i < mutation.addedNodes.length; i++) {
@@ -61,9 +58,6 @@ export default class Observer {
61
58
  if (id === undefined) {
62
59
  continue;
63
60
  }
64
- if (id >= this.recents.length) { // TODO: something more convinient
65
- this.recents[id] = undefined;
66
- }
67
61
  if (type === 'attributes') {
68
62
  const name = mutation.attributeName;
69
63
  if (name === null) {
@@ -74,10 +68,12 @@ export default class Observer {
74
68
  this.attributesList[id] = attr = new Set();
75
69
  }
76
70
  attr.add(name);
71
+ this.affectedSet.add(id);
77
72
  continue;
78
73
  }
79
74
  if (type === 'characterData') {
80
75
  this.textSet.add(id);
76
+ this.affectedSet.add(id);
81
77
  continue;
82
78
  }
83
79
  }
@@ -86,10 +82,11 @@ export default class Observer {
86
82
  }
87
83
  clear() {
88
84
  this.commited.length = 0;
89
- this.recents.length = 0;
90
85
  this.indexes.length = 1;
91
86
  this.attributesList.length = 0;
92
87
  this.textSet.clear();
88
+ this.newSet.clear();
89
+ this.affectedSet.clear();
93
90
  }
94
91
  sendNodeAttribute(id, node, name, value) {
95
92
  if (isSVGElement(node)) {
@@ -119,7 +116,7 @@ export default class Observer {
119
116
  return;
120
117
  }
121
118
  if (name === 'value' &&
122
- isInstance(node, HTMLInputElement) &&
119
+ hasTag(node, "INPUT") &&
123
120
  node.type !== 'button' &&
124
121
  node.type !== 'reset' &&
125
122
  node.type !== 'submit') {
@@ -129,7 +126,7 @@ export default class Observer {
129
126
  this.app.send(new RemoveNodeAttribute(id, name));
130
127
  return;
131
128
  }
132
- if (name === 'style' || name === 'href' && isInstance(node, HTMLLinkElement)) {
129
+ if (name === 'style' || name === 'href' && hasTag(node, "LINK")) {
133
130
  this.app.send(new SetNodeAttributeURLBased(id, name, value, this.app.getBaseHref()));
134
131
  return;
135
132
  }
@@ -139,7 +136,7 @@ export default class Observer {
139
136
  this.app.send(new SetNodeAttribute(id, name, value));
140
137
  }
141
138
  sendNodeData(id, parentElement, data) {
142
- if (isInstance(parentElement, HTMLStyleElement) || isInstance(parentElement, SVGStyleElement)) {
139
+ if (hasTag(parentElement, "STYLE")) {
143
140
  this.app.send(new SetCSSDataURLBased(id, data, this.app.getBaseHref()));
144
141
  return;
145
142
  }
@@ -147,10 +144,11 @@ export default class Observer {
147
144
  this.app.send(new SetNodeData(id, data));
148
145
  }
149
146
  bindNode(node) {
150
- const r = this.app.nodes.registerNode(node);
151
- const id = r[0];
152
- this.recents[id] = r[1] || this.recents[id] || false;
153
- this.myNodes[id] = true;
147
+ const [id, isNew] = this.app.nodes.registerNode(node);
148
+ if (isNew) {
149
+ this.newSet.add(id);
150
+ }
151
+ this.affectedSet.add(id);
154
152
  }
155
153
  bindTree(node) {
156
154
  if (!isObservable(node)) {
@@ -170,7 +168,8 @@ export default class Observer {
170
168
  }
171
169
  unbindNode(node) {
172
170
  const id = this.app.nodes.unregisterNode(node);
173
- if (id !== undefined && this.recents[id] === false) {
171
+ // if (id !== undefined && this.recents[id] === false) { // In the old version it === flase when bindNode() was called on node but it was not new
172
+ if (id !== undefined && !this.newSet.has(id) && this.affectedSet.has(id)) { // Unbinding logic should be simplified. Node removals should go first.
174
173
  this.app.send(new RemoveNode(id));
175
174
  }
176
175
  }
@@ -183,7 +182,7 @@ export default class Observer {
183
182
  // Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
184
183
  // TODO: get rid of "special" cases (there is an issue with CreateDocument altered behaviour though)
185
184
  // TODO: Clean the logic (though now it workd fine)
186
- if (!isInstance(node, HTMLHtmlElement) || !this.isTopContext) {
185
+ if (!hasTag(node, "HTML") || !this.isTopContext) {
187
186
  if (parent === null) {
188
187
  this.unbindNode(node);
189
188
  return false;
@@ -210,15 +209,15 @@ export default class Observer {
210
209
  sibling = sibling.previousSibling;
211
210
  }
212
211
  if (sibling === null) {
213
- this.indexes[id] = 0; //
212
+ this.indexes[id] = 0;
214
213
  }
215
- const isNew = this.recents[id];
214
+ const isNew = this.newSet.has(id);
216
215
  const index = this.indexes[id];
217
216
  if (index === undefined) {
218
217
  throw 'commitNode: missing node index';
219
218
  }
220
219
  if (isNew === true) {
221
- if (isInstance(node, Element)) {
220
+ if (isElementNode(node)) {
222
221
  if (parentID !== undefined) {
223
222
  this.app.send(new CreateElementNode(id, parentID, index, node.tagName, isSVGElement(node)));
224
223
  }
@@ -227,7 +226,7 @@ export default class Observer {
227
226
  this.sendNodeAttribute(id, node, attr.nodeName, attr.value);
228
227
  }
229
228
  }
230
- else if (isInstance(node, Text)) {
229
+ else if (isTextNode(node)) {
231
230
  // for text node id != 0, hence parentID !== undefined and parent is Element
232
231
  this.app.send(new CreateTextNode(id, parentID, index));
233
232
  this.sendNodeData(id, parent, node.data);
@@ -235,11 +234,12 @@ export default class Observer {
235
234
  return true;
236
235
  }
237
236
  if (isNew === false && parentID !== undefined) {
237
+ // does this happen a lot?
238
238
  this.app.send(new MoveNode(id, parentID, index));
239
239
  }
240
240
  const attr = this.attributesList[id];
241
241
  if (attr !== undefined) {
242
- if (!isInstance(node, Element)) {
242
+ if (!isElementNode(node)) {
243
243
  throw 'commitNode: node is not an element';
244
244
  }
245
245
  for (const name of attr) {
@@ -247,7 +247,7 @@ export default class Observer {
247
247
  }
248
248
  }
249
249
  if (this.textSet.has(id)) {
250
- if (!isInstance(node, Text)) {
250
+ if (!isTextNode(node)) {
251
251
  throw 'commitNode: node is not a text';
252
252
  }
253
253
  // for text node id != 0, hence parent is Element
@@ -268,19 +268,12 @@ export default class Observer {
268
268
  }
269
269
  commitNodes() {
270
270
  let node;
271
- for (let id = 0; id < this.recents.length; id++) {
272
- // TODO: make things/logic nice here.
273
- // commit required in any case if recents[id] true or false (in case of unbinding) or undefined (in case of attr change).
274
- // Possible solution: separate new node commit (recents) and new attribute/move node commit
275
- // Otherwise commitNode is called on each node, which might be a lot
276
- if (!this.myNodes[id]) {
277
- continue;
278
- }
271
+ this.affectedSet.forEach(id => {
279
272
  this.commitNode(id);
280
- if (this.recents[id] === true && (node = this.app.nodes.getNode(id))) {
273
+ if (this.newSet.has(id) && (node = this.app.nodes.getNode(id))) {
281
274
  this.app.nodes.callNodeCallbacks(node);
282
275
  }
283
- }
276
+ });
284
277
  this.clear();
285
278
  }
286
279
  // ISSSUE
@@ -300,6 +293,5 @@ export default class Observer {
300
293
  disconnect() {
301
294
  this.observer.disconnect();
302
295
  this.clear();
303
- this.myNodes.length = 0;
304
296
  }
305
297
  }