@openreplay/tracker 3.5.16-beta.1 → 3.5.16-beta.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.
- package/cjs/app/index.d.ts +2 -3
- package/cjs/app/index.js +16 -13
- package/cjs/app/nodes.d.ts +8 -1
- package/cjs/app/nodes.js +28 -7
- package/cjs/index.js +1 -1
- package/lib/app/index.d.ts +2 -3
- package/lib/app/index.js +16 -13
- package/lib/app/nodes.d.ts +8 -1
- package/lib/app/nodes.js +28 -7
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/cjs/app/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type Message from "../common/messages.js";
|
|
2
|
-
import Nodes from "./nodes.js";
|
|
2
|
+
import Nodes, { CheckOptions } from "./nodes.js";
|
|
3
3
|
import Sanitizer from "./sanitizer.js";
|
|
4
4
|
import Ticker from "./ticker.js";
|
|
5
5
|
import Logger from "./logger.js";
|
|
@@ -49,7 +49,7 @@ declare type AppOptions = {
|
|
|
49
49
|
maxMemorySize: number;
|
|
50
50
|
memoryCheckInterval: number;
|
|
51
51
|
onStart?: StartCallback;
|
|
52
|
-
} & WebworkerOptions;
|
|
52
|
+
} & WebworkerOptions & CheckOptions;
|
|
53
53
|
export declare type Options = AppOptions & ObserverOptions & SanitizerOptions;
|
|
54
54
|
export declare const DEFAULT_INGEST_POINT = "https://api.openreplay.com/ingest";
|
|
55
55
|
export default class App {
|
|
@@ -62,7 +62,6 @@ export default class App {
|
|
|
62
62
|
readonly session: Session;
|
|
63
63
|
readonly localStorage: Storage;
|
|
64
64
|
readonly sessionStorage: Storage;
|
|
65
|
-
private gc;
|
|
66
65
|
private readonly messages;
|
|
67
66
|
private readonly observer;
|
|
68
67
|
private readonly startCallbacks;
|
package/cjs/app/index.js
CHANGED
|
@@ -27,12 +27,13 @@ class App {
|
|
|
27
27
|
// if (options.onStart !== undefined) {
|
|
28
28
|
// deprecationWarn("'onStart' option", "tracker.start().then(/* handle session info */)")
|
|
29
29
|
// } ?? maybe onStart is good
|
|
30
|
+
// private gc?: NodeJS.Timer = undefined;
|
|
30
31
|
this.messages = [];
|
|
31
32
|
this.startCallbacks = [];
|
|
32
33
|
this.stopCallbacks = [];
|
|
33
34
|
this.commitCallbacks = [];
|
|
34
35
|
this.activityState = ActivityState.NotActive;
|
|
35
|
-
this.version = '3.5.16-beta.
|
|
36
|
+
this.version = '3.5.16-beta.2'; // TODO: version compatability check inside each plugin.
|
|
36
37
|
this.projectKey = projectKey;
|
|
37
38
|
this.options = Object.assign({
|
|
38
39
|
revID: '',
|
|
@@ -48,12 +49,12 @@ class App {
|
|
|
48
49
|
__debug_report_edp: null,
|
|
49
50
|
localStorage: window.localStorage,
|
|
50
51
|
sessionStorage: window.sessionStorage,
|
|
51
|
-
maxMemorySize:
|
|
52
|
+
maxMemorySize: 550 * 1e6,
|
|
52
53
|
memoryCheckInterval: 2 * 60 * 1000,
|
|
53
54
|
}, options);
|
|
54
55
|
this.revID = this.options.revID;
|
|
55
56
|
this.sanitizer = new sanitizer_js_1.default(this, options);
|
|
56
|
-
this.nodes = new nodes_js_1.default(this.options.node_id);
|
|
57
|
+
this.nodes = new nodes_js_1.default(this.options.node_id, this.options.maxMemorySize, this.options.memoryCheckInterval);
|
|
57
58
|
this.observer = new top_observer_js_1.default(this, options);
|
|
58
59
|
this.ticker = new ticker_js_1.default(this);
|
|
59
60
|
this.ticker.attach(() => this.commit());
|
|
@@ -145,6 +146,7 @@ class App {
|
|
|
145
146
|
fn.apply(this, args);
|
|
146
147
|
}
|
|
147
148
|
catch (e) {
|
|
149
|
+
console.error(e);
|
|
148
150
|
app._debug("safe_fn_call", e);
|
|
149
151
|
// time: timestamp(),
|
|
150
152
|
// name: e.name,
|
|
@@ -318,16 +320,16 @@ class App {
|
|
|
318
320
|
this.observer.observe();
|
|
319
321
|
this.ticker.start();
|
|
320
322
|
this.notify.log("OpenReplay tracking started.");
|
|
321
|
-
// GC
|
|
322
|
-
if (this.gc) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
323
|
+
// // GC
|
|
324
|
+
// if (!this.gc) {
|
|
325
|
+
// this.gc = setInterval(() => {
|
|
326
|
+
// console.log('checking')
|
|
327
|
+
// // @ts-ignore
|
|
328
|
+
// if (window.performance.memory.usedJSHeapSize > this.options.maxMemorySize) {
|
|
329
|
+
// this.restart();
|
|
330
|
+
// }
|
|
331
|
+
// }, this.options.memoryCheckInterval)
|
|
332
|
+
// }
|
|
331
333
|
// get rid of onStart ?
|
|
332
334
|
if (typeof this.options.onStart === 'function') {
|
|
333
335
|
this.options.onStart(onStartInfo);
|
|
@@ -364,6 +366,7 @@ class App {
|
|
|
364
366
|
stop(calledFromAPI = false, restarting = false) {
|
|
365
367
|
if (this.activityState !== ActivityState.NotActive) {
|
|
366
368
|
try {
|
|
369
|
+
// this.gc && clearInterval(this.gc)
|
|
367
370
|
this.sanitizer.clear();
|
|
368
371
|
this.observer.disconnect();
|
|
369
372
|
this.nodes.clear();
|
package/cjs/app/nodes.d.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
1
2
|
declare type NodeCallback = (node: Node, isStart: boolean) => void;
|
|
3
|
+
export interface CheckOptions {
|
|
4
|
+
maxMemorySize: number;
|
|
5
|
+
memoryCheckInterval: number;
|
|
6
|
+
}
|
|
2
7
|
export default class Nodes {
|
|
3
8
|
private readonly node_id;
|
|
4
9
|
private nodes;
|
|
5
10
|
private readonly nodeCallbacks;
|
|
6
11
|
private readonly elementListeners;
|
|
7
|
-
|
|
12
|
+
gc: NodeJS.Timer | undefined;
|
|
13
|
+
constructor(node_id: string, maxMemorySize: CheckOptions["maxMemorySize"], memoryCheckInterval: CheckOptions["memoryCheckInterval"]);
|
|
8
14
|
attachNodeCallback(nodeCallback: NodeCallback): void;
|
|
9
15
|
attachElementListener(type: string, node: Element, elementListener: EventListener): void;
|
|
10
16
|
registerNode(node: Node): [id: number, isNew: boolean];
|
|
11
17
|
unregisterNode(node: Node): number | undefined;
|
|
18
|
+
cleanTree(): void;
|
|
12
19
|
callNodeCallbacks(node: Node, isStart: boolean): void;
|
|
13
20
|
getID(node: Node): number | undefined;
|
|
14
21
|
getNode(id: number): Node | undefined;
|
package/cjs/app/nodes.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
class Nodes {
|
|
4
|
-
constructor(node_id) {
|
|
4
|
+
constructor(node_id, maxMemorySize, memoryCheckInterval) {
|
|
5
5
|
this.node_id = node_id;
|
|
6
6
|
this.nodes = [];
|
|
7
7
|
this.nodeCallbacks = [];
|
|
8
8
|
this.elementListeners = new Map();
|
|
9
|
+
this.gc = setInterval(() => {
|
|
10
|
+
// @ts-ignore should use settings object here
|
|
11
|
+
if (window.performance.memory.usedJSHeapSize > maxMemorySize) {
|
|
12
|
+
this.cleanTree();
|
|
13
|
+
}
|
|
14
|
+
}, memoryCheckInterval);
|
|
9
15
|
}
|
|
10
16
|
attachNodeCallback(nodeCallback) {
|
|
11
17
|
this.nodeCallbacks.push(nodeCallback);
|
|
@@ -47,12 +53,23 @@ class Nodes {
|
|
|
47
53
|
}
|
|
48
54
|
return id;
|
|
49
55
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
cleanTree() {
|
|
57
|
+
// sadly we keep empty items in array here resulting in some memory still being used
|
|
58
|
+
// but its still better than keeping dead nodes or undef elements
|
|
59
|
+
// plus we keep our index positions for new/alive nodes
|
|
60
|
+
// performance test: 3ms for 30k nodes with 17k dead ones
|
|
61
|
+
for (let i = 0; i < this.nodes.length; i++) {
|
|
62
|
+
const node = this.nodes[i];
|
|
63
|
+
if (node === undefined) {
|
|
64
|
+
delete this.nodes[i];
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (!document.contains(node)) {
|
|
68
|
+
this.unregisterNode(node);
|
|
69
|
+
delete this.nodes[i];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
56
73
|
callNodeCallbacks(node, isStart) {
|
|
57
74
|
this.nodeCallbacks.forEach((cb) => cb(node, isStart));
|
|
58
75
|
}
|
|
@@ -71,6 +88,10 @@ class Nodes {
|
|
|
71
88
|
this.unregisterNode(node);
|
|
72
89
|
}
|
|
73
90
|
this.nodes.length = 0;
|
|
91
|
+
if (this.gc) {
|
|
92
|
+
clearInterval(this.gc);
|
|
93
|
+
this.gc = undefined;
|
|
94
|
+
}
|
|
74
95
|
}
|
|
75
96
|
}
|
|
76
97
|
exports.default = Nodes;
|
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.16-beta.
|
|
130
|
+
trackerVersion: '3.5.16-beta.2',
|
|
131
131
|
projectKey: options.projectKey,
|
|
132
132
|
doNotTrack,
|
|
133
133
|
// TODO: add precise reason (an exact API missing)
|
package/lib/app/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type Message from "../common/messages.js";
|
|
2
|
-
import Nodes from "./nodes.js";
|
|
2
|
+
import Nodes, { CheckOptions } from "./nodes.js";
|
|
3
3
|
import Sanitizer from "./sanitizer.js";
|
|
4
4
|
import Ticker from "./ticker.js";
|
|
5
5
|
import Logger from "./logger.js";
|
|
@@ -49,7 +49,7 @@ declare type AppOptions = {
|
|
|
49
49
|
maxMemorySize: number;
|
|
50
50
|
memoryCheckInterval: number;
|
|
51
51
|
onStart?: StartCallback;
|
|
52
|
-
} & WebworkerOptions;
|
|
52
|
+
} & WebworkerOptions & CheckOptions;
|
|
53
53
|
export declare type Options = AppOptions & ObserverOptions & SanitizerOptions;
|
|
54
54
|
export declare const DEFAULT_INGEST_POINT = "https://api.openreplay.com/ingest";
|
|
55
55
|
export default class App {
|
|
@@ -62,7 +62,6 @@ export default class App {
|
|
|
62
62
|
readonly session: Session;
|
|
63
63
|
readonly localStorage: Storage;
|
|
64
64
|
readonly sessionStorage: Storage;
|
|
65
|
-
private gc;
|
|
66
65
|
private readonly messages;
|
|
67
66
|
private readonly observer;
|
|
68
67
|
private readonly startCallbacks;
|
package/lib/app/index.js
CHANGED
|
@@ -24,12 +24,13 @@ export default class App {
|
|
|
24
24
|
// if (options.onStart !== undefined) {
|
|
25
25
|
// deprecationWarn("'onStart' option", "tracker.start().then(/* handle session info */)")
|
|
26
26
|
// } ?? maybe onStart is good
|
|
27
|
+
// private gc?: NodeJS.Timer = undefined;
|
|
27
28
|
this.messages = [];
|
|
28
29
|
this.startCallbacks = [];
|
|
29
30
|
this.stopCallbacks = [];
|
|
30
31
|
this.commitCallbacks = [];
|
|
31
32
|
this.activityState = ActivityState.NotActive;
|
|
32
|
-
this.version = '3.5.16-beta.
|
|
33
|
+
this.version = '3.5.16-beta.2'; // TODO: version compatability check inside each plugin.
|
|
33
34
|
this.projectKey = projectKey;
|
|
34
35
|
this.options = Object.assign({
|
|
35
36
|
revID: '',
|
|
@@ -45,12 +46,12 @@ export default class App {
|
|
|
45
46
|
__debug_report_edp: null,
|
|
46
47
|
localStorage: window.localStorage,
|
|
47
48
|
sessionStorage: window.sessionStorage,
|
|
48
|
-
maxMemorySize:
|
|
49
|
+
maxMemorySize: 550 * 1e6,
|
|
49
50
|
memoryCheckInterval: 2 * 60 * 1000,
|
|
50
51
|
}, options);
|
|
51
52
|
this.revID = this.options.revID;
|
|
52
53
|
this.sanitizer = new Sanitizer(this, options);
|
|
53
|
-
this.nodes = new Nodes(this.options.node_id);
|
|
54
|
+
this.nodes = new Nodes(this.options.node_id, this.options.maxMemorySize, this.options.memoryCheckInterval);
|
|
54
55
|
this.observer = new Observer(this, options);
|
|
55
56
|
this.ticker = new Ticker(this);
|
|
56
57
|
this.ticker.attach(() => this.commit());
|
|
@@ -142,6 +143,7 @@ export default class App {
|
|
|
142
143
|
fn.apply(this, args);
|
|
143
144
|
}
|
|
144
145
|
catch (e) {
|
|
146
|
+
console.error(e);
|
|
145
147
|
app._debug("safe_fn_call", e);
|
|
146
148
|
// time: timestamp(),
|
|
147
149
|
// name: e.name,
|
|
@@ -315,16 +317,16 @@ export default class App {
|
|
|
315
317
|
this.observer.observe();
|
|
316
318
|
this.ticker.start();
|
|
317
319
|
this.notify.log("OpenReplay tracking started.");
|
|
318
|
-
// GC
|
|
319
|
-
if (this.gc) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
320
|
+
// // GC
|
|
321
|
+
// if (!this.gc) {
|
|
322
|
+
// this.gc = setInterval(() => {
|
|
323
|
+
// console.log('checking')
|
|
324
|
+
// // @ts-ignore
|
|
325
|
+
// if (window.performance.memory.usedJSHeapSize > this.options.maxMemorySize) {
|
|
326
|
+
// this.restart();
|
|
327
|
+
// }
|
|
328
|
+
// }, this.options.memoryCheckInterval)
|
|
329
|
+
// }
|
|
328
330
|
// get rid of onStart ?
|
|
329
331
|
if (typeof this.options.onStart === 'function') {
|
|
330
332
|
this.options.onStart(onStartInfo);
|
|
@@ -361,6 +363,7 @@ export default class App {
|
|
|
361
363
|
stop(calledFromAPI = false, restarting = false) {
|
|
362
364
|
if (this.activityState !== ActivityState.NotActive) {
|
|
363
365
|
try {
|
|
366
|
+
// this.gc && clearInterval(this.gc)
|
|
364
367
|
this.sanitizer.clear();
|
|
365
368
|
this.observer.disconnect();
|
|
366
369
|
this.nodes.clear();
|
package/lib/app/nodes.d.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
1
2
|
declare type NodeCallback = (node: Node, isStart: boolean) => void;
|
|
3
|
+
export interface CheckOptions {
|
|
4
|
+
maxMemorySize: number;
|
|
5
|
+
memoryCheckInterval: number;
|
|
6
|
+
}
|
|
2
7
|
export default class Nodes {
|
|
3
8
|
private readonly node_id;
|
|
4
9
|
private nodes;
|
|
5
10
|
private readonly nodeCallbacks;
|
|
6
11
|
private readonly elementListeners;
|
|
7
|
-
|
|
12
|
+
gc: NodeJS.Timer | undefined;
|
|
13
|
+
constructor(node_id: string, maxMemorySize: CheckOptions["maxMemorySize"], memoryCheckInterval: CheckOptions["memoryCheckInterval"]);
|
|
8
14
|
attachNodeCallback(nodeCallback: NodeCallback): void;
|
|
9
15
|
attachElementListener(type: string, node: Element, elementListener: EventListener): void;
|
|
10
16
|
registerNode(node: Node): [id: number, isNew: boolean];
|
|
11
17
|
unregisterNode(node: Node): number | undefined;
|
|
18
|
+
cleanTree(): void;
|
|
12
19
|
callNodeCallbacks(node: Node, isStart: boolean): void;
|
|
13
20
|
getID(node: Node): number | undefined;
|
|
14
21
|
getNode(id: number): Node | undefined;
|
package/lib/app/nodes.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
export default class Nodes {
|
|
2
|
-
constructor(node_id) {
|
|
2
|
+
constructor(node_id, maxMemorySize, memoryCheckInterval) {
|
|
3
3
|
this.node_id = node_id;
|
|
4
4
|
this.nodes = [];
|
|
5
5
|
this.nodeCallbacks = [];
|
|
6
6
|
this.elementListeners = new Map();
|
|
7
|
+
this.gc = setInterval(() => {
|
|
8
|
+
// @ts-ignore should use settings object here
|
|
9
|
+
if (window.performance.memory.usedJSHeapSize > maxMemorySize) {
|
|
10
|
+
this.cleanTree();
|
|
11
|
+
}
|
|
12
|
+
}, memoryCheckInterval);
|
|
7
13
|
}
|
|
8
14
|
attachNodeCallback(nodeCallback) {
|
|
9
15
|
this.nodeCallbacks.push(nodeCallback);
|
|
@@ -45,12 +51,23 @@ export default class Nodes {
|
|
|
45
51
|
}
|
|
46
52
|
return id;
|
|
47
53
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
cleanTree() {
|
|
55
|
+
// sadly we keep empty items in array here resulting in some memory still being used
|
|
56
|
+
// but its still better than keeping dead nodes or undef elements
|
|
57
|
+
// plus we keep our index positions for new/alive nodes
|
|
58
|
+
// performance test: 3ms for 30k nodes with 17k dead ones
|
|
59
|
+
for (let i = 0; i < this.nodes.length; i++) {
|
|
60
|
+
const node = this.nodes[i];
|
|
61
|
+
if (node === undefined) {
|
|
62
|
+
delete this.nodes[i];
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (!document.contains(node)) {
|
|
66
|
+
this.unregisterNode(node);
|
|
67
|
+
delete this.nodes[i];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
54
71
|
callNodeCallbacks(node, isStart) {
|
|
55
72
|
this.nodeCallbacks.forEach((cb) => cb(node, isStart));
|
|
56
73
|
}
|
|
@@ -69,5 +86,9 @@ export default class Nodes {
|
|
|
69
86
|
this.unregisterNode(node);
|
|
70
87
|
}
|
|
71
88
|
this.nodes.length = 0;
|
|
89
|
+
if (this.gc) {
|
|
90
|
+
clearInterval(this.gc);
|
|
91
|
+
this.gc = undefined;
|
|
92
|
+
}
|
|
72
93
|
}
|
|
73
94
|
}
|
package/lib/index.js
CHANGED
|
@@ -123,7 +123,7 @@ export default class API {
|
|
|
123
123
|
// no-cors issue only with text/plain or not-set Content-Type
|
|
124
124
|
// req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
125
125
|
req.send(JSON.stringify({
|
|
126
|
-
trackerVersion: '3.5.16-beta.
|
|
126
|
+
trackerVersion: '3.5.16-beta.2',
|
|
127
127
|
projectKey: options.projectKey,
|
|
128
128
|
doNotTrack,
|
|
129
129
|
// TODO: add precise reason (an exact API missing)
|