@openreplay/tracker 3.4.17 → 3.5.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.
- package/README.md +8 -1
- package/cjs/app/index.d.ts +23 -3
- package/cjs/app/index.js +78 -60
- package/cjs/app/logger.d.ts +27 -0
- package/cjs/app/logger.js +42 -0
- package/cjs/index.d.ts +0 -1
- package/cjs/index.js +2 -5
- package/cjs/modules/console.js +1 -1
- package/cjs/modules/mouse.js +2 -0
- package/cjs/utils.d.ts +0 -8
- package/cjs/utils.js +3 -4
- package/lib/app/index.d.ts +23 -3
- package/lib/app/index.js +79 -61
- package/lib/app/logger.d.ts +27 -0
- package/lib/app/logger.js +39 -1
- package/lib/index.d.ts +0 -1
- package/lib/index.js +2 -5
- package/lib/modules/console.js +1 -1
- package/lib/modules/mouse.js +2 -0
- package/lib/utils.d.ts +0 -8
- package/lib/utils.js +2 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,14 @@ import Tracker from '@openreplay/tracker';
|
|
|
18
18
|
const tracker = new Tracker({
|
|
19
19
|
projectKey: YOUR_PROJECT_KEY,
|
|
20
20
|
});
|
|
21
|
-
tracker.start(
|
|
21
|
+
tracker.start({
|
|
22
|
+
userID: "Mr.Smith",
|
|
23
|
+
metadata: {
|
|
24
|
+
version: "3.5.0",
|
|
25
|
+
balance: "10M",
|
|
26
|
+
role: "admin",
|
|
27
|
+
}
|
|
28
|
+
});
|
|
22
29
|
```
|
|
23
30
|
|
|
24
31
|
Then you can use OpenReplay JavaScript API anywhere in your code.
|
package/cjs/app/index.d.ts
CHANGED
|
@@ -2,8 +2,10 @@ import Message from "../messages/message.js";
|
|
|
2
2
|
import Nodes from "./nodes.js";
|
|
3
3
|
import Sanitizer from "./sanitizer.js";
|
|
4
4
|
import Ticker from "./ticker.js";
|
|
5
|
+
import Logger from "./logger.js";
|
|
5
6
|
import type { Options as ObserverOptions } from "./observer/top_observer.js";
|
|
6
7
|
import type { Options as SanitizerOptions } from "./sanitizer.js";
|
|
8
|
+
import type { Options as LoggerOptions } from "./logger.js";
|
|
7
9
|
import type { Options as WebworkerOptions } from "../messages/webworker.js";
|
|
8
10
|
export interface OnStartInfo {
|
|
9
11
|
sessionID: string;
|
|
@@ -12,6 +14,7 @@ export interface OnStartInfo {
|
|
|
12
14
|
}
|
|
13
15
|
export interface StartOptions {
|
|
14
16
|
userID?: string;
|
|
17
|
+
metadata?: Record<string, string>;
|
|
15
18
|
forceNew: boolean;
|
|
16
19
|
}
|
|
17
20
|
declare type AppOptions = {
|
|
@@ -23,20 +26,24 @@ declare type AppOptions = {
|
|
|
23
26
|
local_uuid_key: string;
|
|
24
27
|
ingestPoint: string;
|
|
25
28
|
resourceBaseHref: string | null;
|
|
29
|
+
verbose: boolean;
|
|
26
30
|
__is_snippet: boolean;
|
|
27
31
|
__debug_report_edp: string | null;
|
|
28
|
-
|
|
32
|
+
__debug__?: LoggerOptions;
|
|
29
33
|
onStart?: (info: OnStartInfo) => void;
|
|
30
34
|
} & WebworkerOptions;
|
|
31
35
|
export declare type Options = AppOptions & ObserverOptions & SanitizerOptions;
|
|
32
36
|
declare type Callback = () => void;
|
|
33
37
|
declare type CommitCallback = (messages: Array<Message>) => void;
|
|
38
|
+
export declare const CANCELED = "canceled";
|
|
34
39
|
export declare const DEFAULT_INGEST_POINT = "https://api.openreplay.com/ingest";
|
|
35
40
|
export default class App {
|
|
36
41
|
readonly nodes: Nodes;
|
|
37
42
|
readonly ticker: Ticker;
|
|
38
43
|
readonly projectKey: string;
|
|
39
44
|
readonly sanitizer: Sanitizer;
|
|
45
|
+
readonly debug: Logger;
|
|
46
|
+
readonly notify: Logger;
|
|
40
47
|
private readonly messages;
|
|
41
48
|
private readonly observer;
|
|
42
49
|
private readonly startCallbacks;
|
|
@@ -46,7 +53,8 @@ export default class App {
|
|
|
46
53
|
private readonly revID;
|
|
47
54
|
private _sessionID;
|
|
48
55
|
private _userID;
|
|
49
|
-
private
|
|
56
|
+
private _metadata;
|
|
57
|
+
private activityState;
|
|
50
58
|
private version;
|
|
51
59
|
private readonly worker?;
|
|
52
60
|
constructor(projectKey: string, sessionToken: string | null | undefined, options: Partial<Options>);
|
|
@@ -54,11 +62,23 @@ export default class App {
|
|
|
54
62
|
send(message: Message, urgent?: boolean): void;
|
|
55
63
|
private commit;
|
|
56
64
|
attachCommitCallback(cb: CommitCallback): void;
|
|
57
|
-
addCommitCallback(cb: CommitCallback): void;
|
|
58
65
|
safe<T extends (...args: any[]) => void>(fn: T): T;
|
|
59
66
|
attachStartCallback(cb: Callback): void;
|
|
60
67
|
attachStopCallback(cb: Callback): void;
|
|
61
68
|
attachEventListener(target: EventTarget, type: string, listener: EventListener, useSafe?: boolean, useCapture?: boolean): void;
|
|
69
|
+
checkRequiredVersion(version: string): boolean;
|
|
70
|
+
private getStartInfo;
|
|
71
|
+
getSessionInfo(): {
|
|
72
|
+
userUUID: string | null;
|
|
73
|
+
projectKey: string;
|
|
74
|
+
revID: string;
|
|
75
|
+
timestamp: number;
|
|
76
|
+
trackerVersion: string;
|
|
77
|
+
userID: string | null;
|
|
78
|
+
isSnippet: boolean;
|
|
79
|
+
sessionID: string | null;
|
|
80
|
+
metadata: Record<string, string>;
|
|
81
|
+
};
|
|
62
82
|
getSessionToken(): string | undefined;
|
|
63
83
|
getSessionID(): string | undefined;
|
|
64
84
|
getHost(): string;
|
package/cjs/app/index.js
CHANGED
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_INGEST_POINT = void 0;
|
|
3
|
+
exports.DEFAULT_INGEST_POINT = exports.CANCELED = void 0;
|
|
4
4
|
const utils_js_1 = require("../utils.js");
|
|
5
5
|
const index_js_1 = require("../messages/index.js");
|
|
6
6
|
const nodes_js_1 = require("./nodes.js");
|
|
7
7
|
const top_observer_js_1 = require("./observer/top_observer.js");
|
|
8
8
|
const sanitizer_js_1 = require("./sanitizer.js");
|
|
9
9
|
const ticker_js_1 = require("./ticker.js");
|
|
10
|
+
const logger_js_1 = require("./logger.js");
|
|
10
11
|
const performance_js_1 = require("../modules/performance.js");
|
|
12
|
+
var ActivityState;
|
|
13
|
+
(function (ActivityState) {
|
|
14
|
+
ActivityState[ActivityState["NotActive"] = 0] = "NotActive";
|
|
15
|
+
ActivityState[ActivityState["Starting"] = 1] = "Starting";
|
|
16
|
+
ActivityState[ActivityState["Active"] = 2] = "Active";
|
|
17
|
+
})(ActivityState || (ActivityState = {}));
|
|
18
|
+
exports.CANCELED = "canceled";
|
|
11
19
|
// TODO: use backendHost only
|
|
12
20
|
exports.DEFAULT_INGEST_POINT = 'https://api.openreplay.com/ingest';
|
|
13
21
|
class App {
|
|
14
22
|
constructor(projectKey, sessionToken, options) {
|
|
23
|
+
// if (options.onStart !== undefined) {
|
|
24
|
+
// deprecationWarn("'onStart' option", "tracker.start().then(/* handle session info */)")
|
|
25
|
+
// } ?? maybe onStart is good
|
|
15
26
|
this.messages = [];
|
|
16
27
|
this.startCallbacks = [];
|
|
17
28
|
this.stopCallbacks = [];
|
|
18
29
|
this.commitCallbacks = [];
|
|
19
30
|
this._sessionID = null;
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
31
|
+
this._userID = null;
|
|
32
|
+
this._metadata = {};
|
|
33
|
+
this.activityState = ActivityState.NotActive;
|
|
34
|
+
this.version = '3.5.0'; // TODO: version compatability check inside each plugin.
|
|
22
35
|
this.projectKey = projectKey;
|
|
23
36
|
this.options = Object.assign({
|
|
24
37
|
revID: '',
|
|
@@ -29,9 +42,9 @@ class App {
|
|
|
29
42
|
local_uuid_key: '__openreplay_uuid',
|
|
30
43
|
ingestPoint: exports.DEFAULT_INGEST_POINT,
|
|
31
44
|
resourceBaseHref: null,
|
|
45
|
+
verbose: false,
|
|
32
46
|
__is_snippet: false,
|
|
33
47
|
__debug_report_edp: null,
|
|
34
|
-
__debug_log: false,
|
|
35
48
|
}, options);
|
|
36
49
|
if (sessionToken != null) {
|
|
37
50
|
sessionStorage.setItem(this.options.session_token_key, sessionToken);
|
|
@@ -42,6 +55,8 @@ class App {
|
|
|
42
55
|
this.observer = new top_observer_js_1.default(this, options);
|
|
43
56
|
this.ticker = new ticker_js_1.default(this);
|
|
44
57
|
this.ticker.attach(() => this.commit());
|
|
58
|
+
this.debug = new logger_js_1.default(this.options.__debug__);
|
|
59
|
+
this.notify = new logger_js_1.default(this.options.verbose ? logger_js_1.LogLevel.Warnings : logger_js_1.LogLevel.Silent);
|
|
45
60
|
try {
|
|
46
61
|
this.worker = new Worker(URL.createObjectURL(new Blob([`"use strict";function t(t){function s(...s){return new t(...s)}return s.prototype=t.prototype,s}const s=new Map;const i=t(class{constructor(t,s,i){this.pageNo=t,this.firstIndex=s,this.timestamp=i,this._id=80}encode(t){return t.uint(80)&&t.uint(this.pageNo)&&t.uint(this.firstIndex)&&t.int(this.timestamp)}});s.set(80,i);const n=t(class{constructor(t){this.timestamp=t,this._id=0}encode(t){return t.uint(0)&&t.uint(this.timestamp)}});s.set(0,n);const e=t(class{constructor(t,s,i){this.url=t,this.referrer=s,this.navigationStart=i,this._id=4}encode(t){return t.uint(4)&&t.string(this.url)&&t.string(this.referrer)&&t.uint(this.navigationStart)}});s.set(4,e);const r=t(class{constructor(t,s){this.width=t,this.height=s,this._id=5}encode(t){return t.uint(5)&&t.uint(this.width)&&t.uint(this.height)}});s.set(5,r);const o=t(class{constructor(t,s){this.x=t,this.y=s,this._id=6}encode(t){return t.uint(6)&&t.int(this.x)&&t.int(this.y)}});s.set(6,o);const h=t(class{constructor(){this._id=7}encode(t){return t.uint(7)}});s.set(7,h);const c=t(class{constructor(t,s,i,n,e){this.id=t,this.parentID=s,this.index=i,this.tag=n,this.svg=e,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)}});s.set(8,c);const u=t(class{constructor(t,s,i){this.id=t,this.parentID=s,this.index=i,this._id=9}encode(t){return t.uint(9)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});s.set(9,u);const a=t(class{constructor(t,s,i){this.id=t,this.parentID=s,this.index=i,this._id=10}encode(t){return t.uint(10)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});s.set(10,a);const d=t(class{constructor(t){this.id=t,this._id=11}encode(t){return t.uint(11)&&t.uint(this.id)}});s.set(11,d);const l=t(class{constructor(t,s,i){this.id=t,this.name=s,this.value=i,this._id=12}encode(t){return t.uint(12)&&t.uint(this.id)&&t.string(this.name)&&t.string(this.value)}});s.set(12,l);const g=t(class{constructor(t,s){this.id=t,this.name=s,this._id=13}encode(t){return t.uint(13)&&t.uint(this.id)&&t.string(this.name)}});s.set(13,g);const f=t(class{constructor(t,s){this.id=t,this.data=s,this._id=14}encode(t){return t.uint(14)&&t.uint(this.id)&&t.string(this.data)}});s.set(14,f);const p=t(class{constructor(t,s,i){this.id=t,this.x=s,this.y=i,this._id=16}encode(t){return t.uint(16)&&t.uint(this.id)&&t.int(this.x)&&t.int(this.y)}});s.set(16,p);const m=t(class{constructor(t,s){this.id=t,this.label=s,this._id=17}encode(t){return t.uint(17)&&t.uint(this.id)&&t.string(this.label)}});s.set(17,m);const _=t(class{constructor(t,s,i){this.id=t,this.value=s,this.mask=i,this._id=18}encode(t){return t.uint(18)&&t.uint(this.id)&&t.string(this.value)&&t.int(this.mask)}});s.set(18,_);const y=t(class{constructor(t,s){this.id=t,this.checked=s,this._id=19}encode(t){return t.uint(19)&&t.uint(this.id)&&t.boolean(this.checked)}});s.set(19,y);const v=t(class{constructor(t,s){this.x=t,this.y=s,this._id=20}encode(t){return t.uint(20)&&t.uint(this.x)&&t.uint(this.y)}});s.set(20,v);const S=t(class{constructor(t,s){this.level=t,this.value=s,this._id=22}encode(t){return t.uint(22)&&t.string(this.level)&&t.string(this.value)}});s.set(22,S);const b=t(class{constructor(t,s,i,n,e,r,o,h,c){this.requestStart=t,this.responseStart=s,this.responseEnd=i,this.domContentLoadedEventStart=n,this.domContentLoadedEventEnd=e,this.loadEventStart=r,this.loadEventEnd=o,this.firstPaint=h,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)}});s.set(23,b);const x=t(class{constructor(t,s,i){this.speedIndex=t,this.visuallyComplete=s,this.timeToInteractive=i,this._id=24}encode(t){return t.uint(24)&&t.uint(this.speedIndex)&&t.uint(this.visuallyComplete)&&t.uint(this.timeToInteractive)}});s.set(24,x);const E=t(class{constructor(t,s,i){this.name=t,this.message=s,this.payload=i,this._id=25}encode(t){return t.uint(25)&&t.string(this.name)&&t.string(this.message)&&t.string(this.payload)}});s.set(25,E);const k=t(class{constructor(t,s){this.name=t,this.payload=s,this._id=27}encode(t){return t.uint(27)&&t.string(this.name)&&t.string(this.payload)}});s.set(27,k);const I=t(class{constructor(t){this.id=t,this._id=28}encode(t){return t.uint(28)&&t.string(this.id)}});s.set(28,I);const z=t(class{constructor(t){this.id=t,this._id=29}encode(t){return t.uint(29)&&t.string(this.id)}});s.set(29,z);const w=t(class{constructor(t,s){this.key=t,this.value=s,this._id=30}encode(t){return t.uint(30)&&t.string(this.key)&&t.string(this.value)}});s.set(30,w);const T=t(class{constructor(t,s,i){this.id=t,this.rule=s,this.index=i,this._id=37}encode(t){return t.uint(37)&&t.uint(this.id)&&t.string(this.rule)&&t.uint(this.index)}});s.set(37,T);const L=t(class{constructor(t,s){this.id=t,this.index=s,this._id=38}encode(t){return t.uint(38)&&t.uint(this.id)&&t.uint(this.index)}});s.set(38,L);const A=t(class{constructor(t,s,i,n,e,r,o){this.method=t,this.url=s,this.request=i,this.response=n,this.status=e,this.timestamp=r,this.duration=o,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)}});s.set(39,A);const C=t(class{constructor(t,s,i,n){this.name=t,this.duration=s,this.args=i,this.result=n,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)}});s.set(40,C);const M=t(class{constructor(t,s){this.key=t,this.value=s,this._id=41}encode(t){return t.uint(41)&&t.string(this.key)&&t.string(this.value)}});s.set(41,M);const R=t(class{constructor(t){this.type=t,this._id=42}encode(t){return t.uint(42)&&t.string(this.type)}});s.set(42,R);const N=t(class{constructor(t,s,i){this.action=t,this.state=s,this.duration=i,this._id=44}encode(t){return t.uint(44)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});s.set(44,N);const D=t(class{constructor(t,s){this.mutation=t,this.state=s,this._id=45}encode(t){return t.uint(45)&&t.string(this.mutation)&&t.string(this.state)}});s.set(45,D);const U=t(class{constructor(t,s){this.type=t,this.payload=s,this._id=46}encode(t){return t.uint(46)&&t.string(this.type)&&t.string(this.payload)}});s.set(46,U);const O=t(class{constructor(t,s,i){this.action=t,this.state=s,this.duration=i,this._id=47}encode(t){return t.uint(47)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});s.set(47,O);const q=t(class{constructor(t,s,i,n){this.operationKind=t,this.operationName=s,this.variables=i,this.response=n,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)}});s.set(48,q);const H=t(class{constructor(t,s,i,n){this.frames=t,this.ticks=s,this.totalJSHeapSize=i,this.usedJSHeapSize=n,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)}});s.set(49,H);const P=t(class{constructor(t,s,i,n,e,r,o,h){this.timestamp=t,this.duration=s,this.ttfb=i,this.headerSize=n,this.encodedBodySize=e,this.decodedBodySize=r,this.url=o,this.initiator=h,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)}});s.set(53,P);const B=t(class{constructor(t,s){this.downlink=t,this.type=s,this._id=54}encode(t){return t.uint(54)&&t.uint(this.downlink)&&t.string(this.type)}});s.set(54,B);const J=t(class{constructor(t){this.hidden=t,this._id=55}encode(t){return t.uint(55)&&t.boolean(this.hidden)}});s.set(55,J);const j=t(class{constructor(t,s,i,n,e,r,o){this.timestamp=t,this.duration=s,this.context=i,this.containerType=n,this.containerSrc=e,this.containerId=r,this.containerName=o,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)}});s.set(59,j);const G=t(class{constructor(t,s,i,n){this.id=t,this.name=s,this.value=i,this.baseURL=n,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)}});s.set(60,G);const K=t(class{constructor(t,s,i){this.id=t,this.data=s,this.baseURL=i,this._id=61}encode(t){return t.uint(61)&&t.uint(this.id)&&t.string(this.data)&&t.string(this.baseURL)}});s.set(61,K);const X=t(class{constructor(t,s){this.type=t,this.value=s,this._id=63}encode(t){return t.uint(63)&&t.string(this.type)&&t.string(this.value)}});s.set(63,X);const F=t(class{constructor(t,s){this.name=t,this.payload=s,this._id=64}encode(t){return t.uint(64)&&t.string(this.name)&&t.string(this.payload)}});s.set(64,F);const Q=t(class{constructor(){this._id=65}encode(t){return t.uint(65)}});s.set(65,Q);const V=t(class{constructor(t,s,i,n){this.id=t,this.rule=s,this.index=i,this.baseURL=n,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)}});s.set(67,V);const W=t(class{constructor(t,s,i,n){this.id=t,this.hesitationTime=s,this.label=i,this.selector=n,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)}});s.set(69,W);const Y=t(class{constructor(t,s){this.frameID=t,this.id=s,this._id=70}encode(t){return t.uint(70)&&t.uint(this.frameID)&&t.uint(this.id)}});s.set(70,Y);const Z="function"==typeof TextEncoder?new TextEncoder:{encode(t){const s=t.length,i=new Uint8Array(3*s);let n=-1;for(var e=0,r=0,o=0;o!==s;){if(e=t.charCodeAt(o),o+=1,e>=55296&&e<=56319){if(o===s){i[n+=1]=239,i[n+=1]=191,i[n+=1]=189;break}if(!((r=t.charCodeAt(o))>=56320&&r<=57343)){i[n+=1]=239,i[n+=1]=191,i[n+=1]=189;continue}if(o+=1,(e=1024*(e-55296)+r-56320+65536)>65535){i[n+=1]=240|e>>>18,i[n+=1]=128|e>>>12&63,i[n+=1]=128|e>>>6&63,i[n+=1]=128|63&e;continue}}e<=127?i[n+=1]=0|e:e<=2047?(i[n+=1]=192|e>>>6,i[n+=1]=128|63&e):(i[n+=1]=224|e>>>12,i[n+=1]=128|e>>>6&63,i[n+=1]=128|63&e)}return i.subarray(0,n+1)}};class tt{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 s=Z.encode(t),i=s.byteLength;return!(!this.uint(i)||this.offset+i>this.size)&&(this.data.set(s,this.offset),this.offset+=i,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}let st=1e6,it=2e5,nt=new tt(it),et="",rt="",ot=0,ht=0,ct=0,ut=0,at=!0;function dt(){return new i(ot,ut,ht).encode(nt)}let lt=null;const gt=[];let ft,pt=!1,mt=0,_t=8e3,yt=10;function vt(){if(at||""===rt||""===et)return;const t=nt.flush();pt?gt.push(t):(pt=!0,function t(s){const i=new XMLHttpRequest;i.open("POST",et+"/v1/web/i",!1),i.setRequestHeader("Authorization","Bearer "+rt),i.onreadystatechange=function(){if(4===this.readyState){if(0==this.status)return;if(this.status>=400)return pt=!1,St(),gt.length=0,401===this.status?void self.postMessage("restart"):void self.postMessage(null);const s=gt.shift();s?t(s):pt=!1}},i.onerror=function(i){if(mt>=yt)return St(),void self.postMessage(null);mt++,setTimeout(()=>t(s),_t)},i.send(s.buffer)}(t)),at=!0,dt()}function St(){et="",rt="",null!==lt&&(clearInterval(lt),lt=null),nt.reset()}self.onmessage=({data:t})=>{if(null!==t)return"stop"===t?(vt(),void St()):Array.isArray(t)?void t.forEach(t=>{const i=new(s.get(t._id));if(Object.assign(i,t),i instanceof n?ht=i.timestamp:i instanceof J&&(i.hidden?ft=setTimeout(()=>self.postMessage("restart"),18e5):clearTimeout(ft)),nt.checkpoint(),!i.encode(nt)&&(vt(),!i.encode(nt)))for(;!i.encode(nt);){if(it===st)return console.warn("OpenReplay: beacon size overflow."),nt.reset(),void dt();it=Math.min(2*it,st),nt=new tt(it),dt()}ut++,at=!1}):(et=t.ingestPoint||et,rt=t.token||rt,ot=t.pageNo||ot,ht=t.startTimestamp||ht,ct=t.timeAdjustment||ct,yt=t.connAttemptCount||yt,_t=t.connAttemptGap||_t,st=t.beaconSizeLimit||st,it=Math.min(st,t.beaconSize||it),nt.isEmpty()&&dt(),void(null===lt&&(lt=setInterval(vt,1e4))));vt()};
|
|
47
62
|
`], { type: 'text/javascript' })));
|
|
@@ -58,7 +73,8 @@ class App {
|
|
|
58
73
|
this.stop();
|
|
59
74
|
this.start({
|
|
60
75
|
forceNew: true,
|
|
61
|
-
userID: this._userID,
|
|
76
|
+
userID: this._userID || undefined,
|
|
77
|
+
metadata: this._metadata || undefined,
|
|
62
78
|
});
|
|
63
79
|
}
|
|
64
80
|
};
|
|
@@ -87,12 +103,10 @@ class App {
|
|
|
87
103
|
})
|
|
88
104
|
});
|
|
89
105
|
}
|
|
90
|
-
|
|
91
|
-
(0, utils_js_1.warn)("OpenReplay error: ", context, e);
|
|
92
|
-
}
|
|
106
|
+
this.debug.error("OpenReplay error: ", context, e);
|
|
93
107
|
}
|
|
94
108
|
send(message, urgent = false) {
|
|
95
|
-
if (
|
|
109
|
+
if (this.activityState !== ActivityState.Active) {
|
|
96
110
|
return;
|
|
97
111
|
}
|
|
98
112
|
this.messages.push(message);
|
|
@@ -111,10 +125,6 @@ class App {
|
|
|
111
125
|
attachCommitCallback(cb) {
|
|
112
126
|
this.commitCallbacks.push(cb);
|
|
113
127
|
}
|
|
114
|
-
// @Depricated (TODO: remove in 3.5.*)
|
|
115
|
-
addCommitCallback(cb) {
|
|
116
|
-
this.attachCommitCallback(cb);
|
|
117
|
-
}
|
|
118
128
|
safe(fn) {
|
|
119
129
|
const app = this;
|
|
120
130
|
return function (...args) {
|
|
@@ -143,6 +153,30 @@ class App {
|
|
|
143
153
|
this.attachStartCallback(() => target.addEventListener(type, listener, useCapture));
|
|
144
154
|
this.attachStopCallback(() => target.removeEventListener(type, listener, useCapture));
|
|
145
155
|
}
|
|
156
|
+
checkRequiredVersion(version) {
|
|
157
|
+
const reqVer = version.split('.');
|
|
158
|
+
const ver = this.version.split('.');
|
|
159
|
+
for (let i = 0; i < ver.length; i++) {
|
|
160
|
+
if (Number(ver[i]) < Number(reqVer[i]) || isNaN(Number(ver[i])) || isNaN(Number(reqVer[i]))) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
getStartInfo() {
|
|
167
|
+
return {
|
|
168
|
+
userUUID: localStorage.getItem(this.options.local_uuid_key),
|
|
169
|
+
projectKey: this.projectKey,
|
|
170
|
+
revID: this.revID,
|
|
171
|
+
timestamp: (0, utils_js_1.timestamp)(),
|
|
172
|
+
trackerVersion: this.version,
|
|
173
|
+
userID: this._userID,
|
|
174
|
+
isSnippet: this.options.__is_snippet,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
getSessionInfo() {
|
|
178
|
+
return Object.assign({ sessionID: this._sessionID, metadata: this._metadata }, this.getStartInfo());
|
|
179
|
+
}
|
|
146
180
|
getSessionToken() {
|
|
147
181
|
const token = sessionStorage.getItem(this.options.session_token_key);
|
|
148
182
|
if (token !== null) {
|
|
@@ -182,7 +216,7 @@ class App {
|
|
|
182
216
|
return url.startsWith(this.options.ingestPoint);
|
|
183
217
|
}
|
|
184
218
|
active() {
|
|
185
|
-
return this.
|
|
219
|
+
return this.activityState === ActivityState.Active;
|
|
186
220
|
}
|
|
187
221
|
resetNextPageSession(flag) {
|
|
188
222
|
if (flag) {
|
|
@@ -196,10 +230,10 @@ class App {
|
|
|
196
230
|
if (!this.worker) {
|
|
197
231
|
return Promise.reject("No worker found: perhaps, CSP is not set.");
|
|
198
232
|
}
|
|
199
|
-
if (this.
|
|
233
|
+
if (this.activityState !== ActivityState.NotActive) {
|
|
200
234
|
return Promise.reject("OpenReplay: trying to call `start()` on the instance that has been started already.");
|
|
201
235
|
}
|
|
202
|
-
this.
|
|
236
|
+
this.activityState = ActivityState.Starting;
|
|
203
237
|
let pageNo = 0;
|
|
204
238
|
const pageNoStr = sessionStorage.getItem(this.options.session_pageno_key);
|
|
205
239
|
if (pageNoStr != null) {
|
|
@@ -207,91 +241,75 @@ class App {
|
|
|
207
241
|
pageNo++;
|
|
208
242
|
}
|
|
209
243
|
sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
|
|
210
|
-
|
|
244
|
+
this._userID = startOpts.userID || null;
|
|
245
|
+
this._metadata = startOpts.metadata || {}; // TODO: update both dynamically on corresponding messages
|
|
246
|
+
const startInfo = this.getStartInfo();
|
|
211
247
|
const messageData = {
|
|
212
248
|
ingestPoint: this.options.ingestPoint,
|
|
213
249
|
pageNo,
|
|
214
|
-
startTimestamp,
|
|
250
|
+
startTimestamp: startInfo.timestamp,
|
|
215
251
|
connAttemptCount: this.options.connAttemptCount,
|
|
216
252
|
connAttemptGap: this.options.connAttemptGap,
|
|
217
253
|
};
|
|
218
254
|
this.worker.postMessage(messageData); // brings delay of 10th ms?
|
|
219
|
-
// let token = sessionStorage.getItem(this.options.session_token_key)
|
|
220
|
-
// const tokenIsActive = localStorage.getItem("__or_at_" + token)
|
|
221
|
-
// if (tokenIsActive) {
|
|
222
|
-
// token = null
|
|
223
|
-
// }
|
|
224
255
|
const sReset = sessionStorage.getItem(this.options.session_reset_key);
|
|
225
256
|
sessionStorage.removeItem(this.options.session_reset_key);
|
|
226
|
-
this._userID = startOpts.userID || undefined;
|
|
227
257
|
return window.fetch(this.options.ingestPoint + '/v1/web/start', {
|
|
228
258
|
method: 'POST',
|
|
229
259
|
headers: {
|
|
230
260
|
'Content-Type': 'application/json',
|
|
231
261
|
},
|
|
232
|
-
body: JSON.stringify({
|
|
233
|
-
|
|
234
|
-
userUUID: localStorage.getItem(this.options.local_uuid_key),
|
|
235
|
-
projectKey: this.projectKey,
|
|
236
|
-
revID: this.revID,
|
|
237
|
-
timestamp: startTimestamp,
|
|
238
|
-
trackerVersion: this.version,
|
|
239
|
-
isSnippet: this.options.__is_snippet,
|
|
240
|
-
deviceMemory: performance_js_1.deviceMemory,
|
|
241
|
-
jsHeapSizeLimit: performance_js_1.jsHeapSizeLimit,
|
|
242
|
-
reset: startOpts.forceNew || sReset !== null,
|
|
243
|
-
userID: this._userID,
|
|
244
|
-
}),
|
|
262
|
+
body: JSON.stringify(Object.assign(Object.assign({}, startInfo), { token: sessionStorage.getItem(this.options.session_token_key), deviceMemory: performance_js_1.deviceMemory,
|
|
263
|
+
jsHeapSizeLimit: performance_js_1.jsHeapSizeLimit, reset: startOpts.forceNew || sReset !== null })),
|
|
245
264
|
})
|
|
246
265
|
.then(r => {
|
|
247
266
|
if (r.status === 200) {
|
|
248
267
|
return r.json();
|
|
249
268
|
}
|
|
250
|
-
else {
|
|
251
|
-
return r.text().then(text =>
|
|
252
|
-
|
|
253
|
-
|
|
269
|
+
else {
|
|
270
|
+
return r.text().then(text => text === exports.CANCELED
|
|
271
|
+
? Promise.reject(exports.CANCELED)
|
|
272
|
+
: Promise.reject(`Server error: ${r.status}. ${text}`));
|
|
254
273
|
}
|
|
255
274
|
})
|
|
256
275
|
.then(r => {
|
|
276
|
+
if (!this.worker) {
|
|
277
|
+
return Promise.reject("no worker found after start request (this might not happen)");
|
|
278
|
+
}
|
|
257
279
|
const { token, userUUID, sessionID, beaconSizeLimit } = r;
|
|
258
280
|
if (typeof token !== 'string' ||
|
|
259
281
|
typeof userUUID !== 'string' ||
|
|
260
282
|
(typeof beaconSizeLimit !== 'number' && typeof beaconSizeLimit !== 'undefined')) {
|
|
261
|
-
|
|
283
|
+
return Promise.reject(`Incorrect server response: ${JSON.stringify(r)}`);
|
|
262
284
|
}
|
|
263
285
|
sessionStorage.setItem(this.options.session_token_key, token);
|
|
264
286
|
localStorage.setItem(this.options.local_uuid_key, userUUID);
|
|
265
|
-
// localStorage.setItem("__or_at_" + token, "true")
|
|
266
|
-
// this.attachEventListener(window, 'beforeunload', ()=>{
|
|
267
|
-
// localStorage.removeItem("__or_at_" + token)
|
|
268
|
-
// }, false);
|
|
269
|
-
// this.attachEventListener(window, 'pagehide', ()=>{
|
|
270
|
-
// localStorage.removeItem("__or_at_" + token)
|
|
271
|
-
// }, false);
|
|
272
287
|
if (typeof sessionID === 'string') {
|
|
273
288
|
this._sessionID = sessionID;
|
|
274
289
|
}
|
|
275
|
-
|
|
276
|
-
throw new Error("no worker found after start request (this might not happen)");
|
|
277
|
-
}
|
|
290
|
+
this.activityState = ActivityState.Active;
|
|
278
291
|
this.worker.postMessage({ token, beaconSizeLimit });
|
|
279
292
|
this.startCallbacks.forEach((cb) => cb());
|
|
280
293
|
this.observer.observe();
|
|
281
294
|
this.ticker.start();
|
|
282
|
-
(
|
|
295
|
+
Object.entries(this._metadata).forEach(([key, value]) => this.send(new index_js_1.Metadata(key, value)));
|
|
296
|
+
this.notify.log("OpenReplay tracking started.");
|
|
297
|
+
// TODO: get rid of onStart
|
|
283
298
|
const onStartInfo = { sessionToken: token, userUUID, sessionID };
|
|
284
299
|
if (typeof this.options.onStart === 'function') {
|
|
285
300
|
this.options.onStart(onStartInfo);
|
|
286
301
|
}
|
|
287
302
|
return onStartInfo;
|
|
288
303
|
})
|
|
289
|
-
.catch(
|
|
304
|
+
.catch(reason => {
|
|
290
305
|
sessionStorage.removeItem(this.options.session_token_key);
|
|
291
306
|
this.stop();
|
|
292
|
-
(
|
|
293
|
-
|
|
294
|
-
|
|
307
|
+
//if (reason === CANCELED) { return Promise.resolve(CANCELED) } // TODO: what to return ????? Throwing is baad
|
|
308
|
+
if (reason !== exports.CANCELED) {
|
|
309
|
+
this.notify.log("OpenReplay was unable to start. ", reason);
|
|
310
|
+
this._debug("session_start", reason);
|
|
311
|
+
}
|
|
312
|
+
return Promise.reject(reason);
|
|
295
313
|
});
|
|
296
314
|
}
|
|
297
315
|
start(options = { forceNew: false }) {
|
|
@@ -311,7 +329,7 @@ class App {
|
|
|
311
329
|
}
|
|
312
330
|
}
|
|
313
331
|
stop() {
|
|
314
|
-
if (this.
|
|
332
|
+
if (this.activityState !== ActivityState.NotActive) {
|
|
315
333
|
try {
|
|
316
334
|
if (this.worker) {
|
|
317
335
|
this.worker.postMessage("stop");
|
|
@@ -321,10 +339,10 @@ class App {
|
|
|
321
339
|
this.nodes.clear();
|
|
322
340
|
this.ticker.stop();
|
|
323
341
|
this.stopCallbacks.forEach((cb) => cb());
|
|
324
|
-
|
|
342
|
+
this.notify.log("OpenReplay tracking stopped.");
|
|
325
343
|
}
|
|
326
344
|
finally {
|
|
327
|
-
this.
|
|
345
|
+
this.activityState = ActivityState.NotActive;
|
|
328
346
|
}
|
|
329
347
|
}
|
|
330
348
|
}
|
package/cjs/app/logger.d.ts
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const LogLevel: {
|
|
2
|
+
readonly Verbose: 4;
|
|
3
|
+
readonly Errors: 4;
|
|
4
|
+
readonly Warnings: 3;
|
|
5
|
+
readonly Log: 2;
|
|
6
|
+
readonly Silent: 0;
|
|
7
|
+
};
|
|
8
|
+
declare type LogLevel = typeof LogLevel[keyof typeof LogLevel];
|
|
9
|
+
declare type CustomLevel = {
|
|
10
|
+
error: boolean;
|
|
11
|
+
warn: boolean;
|
|
12
|
+
log: boolean;
|
|
13
|
+
};
|
|
14
|
+
interface _Options {
|
|
15
|
+
level: LogLevel | CustomLevel;
|
|
16
|
+
messages?: number[];
|
|
17
|
+
}
|
|
18
|
+
export declare type Options = true | _Options | LogLevel;
|
|
19
|
+
export default class Logger {
|
|
20
|
+
private readonly options;
|
|
21
|
+
private readonly opts;
|
|
22
|
+
constructor(options?: Options);
|
|
23
|
+
log(...args: any): void;
|
|
24
|
+
warn(...args: any): void;
|
|
25
|
+
error(...args: any): void;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
package/cjs/app/logger.js
CHANGED
|
@@ -1 +1,43 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LogLevel = void 0;
|
|
4
|
+
exports.LogLevel = {
|
|
5
|
+
Verbose: 4,
|
|
6
|
+
Errors: 4,
|
|
7
|
+
Warnings: 3,
|
|
8
|
+
Log: 2,
|
|
9
|
+
Silent: 0,
|
|
10
|
+
};
|
|
11
|
+
function IsCustomLevel(l) {
|
|
12
|
+
return typeof l === 'object';
|
|
13
|
+
}
|
|
14
|
+
class Logger {
|
|
15
|
+
constructor(options = exports.LogLevel.Silent) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
this.opts = options === true
|
|
18
|
+
? { level: exports.LogLevel.Verbose }
|
|
19
|
+
: typeof options === "number" ? { level: options } : options;
|
|
20
|
+
}
|
|
21
|
+
log(...args) {
|
|
22
|
+
if (IsCustomLevel(this.opts.level)
|
|
23
|
+
? this.opts.level.log
|
|
24
|
+
: this.opts.level >= exports.LogLevel.Log) {
|
|
25
|
+
console.log(...args);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
warn(...args) {
|
|
29
|
+
if (IsCustomLevel(this.opts.level)
|
|
30
|
+
? this.opts.level.warn
|
|
31
|
+
: this.opts.level >= exports.LogLevel.Warnings) {
|
|
32
|
+
console.warn(...args);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
error(...args) {
|
|
36
|
+
if (IsCustomLevel(this.opts.level)
|
|
37
|
+
? this.opts.level.error
|
|
38
|
+
: this.opts.level >= exports.LogLevel.Errors) {
|
|
39
|
+
console.error(...args);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.default = Logger;
|
package/cjs/index.d.ts
CHANGED
|
@@ -24,7 +24,6 @@ export default class API {
|
|
|
24
24
|
constructor(options: Options);
|
|
25
25
|
use<T>(fn: (app: App | null, options?: Options) => T): T;
|
|
26
26
|
isActive(): boolean;
|
|
27
|
-
active(): boolean;
|
|
28
27
|
start(startOpts?: StartOptions): Promise<OnStartInfo>;
|
|
29
28
|
stop(): void;
|
|
30
29
|
getSessionToken(): string | null | undefined;
|
package/cjs/index.js
CHANGED
|
@@ -129,7 +129,7 @@ class API {
|
|
|
129
129
|
// no-cors issue only with text/plain or not-set Content-Type
|
|
130
130
|
// req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
131
131
|
req.send(JSON.stringify({
|
|
132
|
-
trackerVersion: '3.
|
|
132
|
+
trackerVersion: '3.5.0',
|
|
133
133
|
projectKey: options.projectKey,
|
|
134
134
|
doNotTrack,
|
|
135
135
|
// TODO: add precise reason (an exact API missing)
|
|
@@ -145,10 +145,6 @@ class API {
|
|
|
145
145
|
}
|
|
146
146
|
return this.app.active();
|
|
147
147
|
}
|
|
148
|
-
active() {
|
|
149
|
-
(0, utils_js_1.deprecationWarn)("'active' method", "'isActive' method", "/");
|
|
150
|
-
return this.isActive();
|
|
151
|
-
}
|
|
152
148
|
start(startOpts) {
|
|
153
149
|
if (!utils_js_1.IN_BROWSER) {
|
|
154
150
|
console.error(`OpenReplay: you are trying to start Tracker on a node.js environment. If you want to use OpenReplay with SSR, please, use componentDidMount or useEffect API for placing the \`tracker.start()\` line. Check documentation on ${utils_js_1.DOCS_HOST}${DOCS_SETUP}`);
|
|
@@ -157,6 +153,7 @@ class API {
|
|
|
157
153
|
if (this.app === null) {
|
|
158
154
|
return Promise.reject("Browser doesn't support required api, or doNotTrack is active.");
|
|
159
155
|
}
|
|
156
|
+
// TODO: check argument typing
|
|
160
157
|
return this.app.start(startOpts);
|
|
161
158
|
}
|
|
162
159
|
stop() {
|
package/cjs/modules/console.js
CHANGED
package/cjs/modules/mouse.js
CHANGED
|
@@ -57,6 +57,7 @@ function _getTarget(target) {
|
|
|
57
57
|
if (tag === 'BUTTON' ||
|
|
58
58
|
tag === 'A' ||
|
|
59
59
|
tag === 'LI' ||
|
|
60
|
+
tag === 'SELECT' ||
|
|
60
61
|
element.onclick != null ||
|
|
61
62
|
element.getAttribute('role') === 'button' ||
|
|
62
63
|
(0, utils_js_1.getLabelAttribute)(element) !== null) {
|
|
@@ -83,6 +84,7 @@ function default_1(app) {
|
|
|
83
84
|
if (tag === 'BUTTON' ||
|
|
84
85
|
tag === 'A' ||
|
|
85
86
|
tag === 'LI' ||
|
|
87
|
+
tag === 'SELECT' ||
|
|
86
88
|
target.onclick != null ||
|
|
87
89
|
target.getAttribute('role') === 'button') {
|
|
88
90
|
const label = app.sanitizer.getInnerTextSecure(target);
|
package/cjs/utils.d.ts
CHANGED
|
@@ -3,14 +3,6 @@ export declare const stars: (str: string) => string;
|
|
|
3
3
|
export declare function normSpaces(str: string): string;
|
|
4
4
|
export declare function isURL(s: string): boolean;
|
|
5
5
|
export declare const IN_BROWSER: boolean;
|
|
6
|
-
export declare const log: {
|
|
7
|
-
(...data: any[]): void;
|
|
8
|
-
(message?: any, ...optionalParams: any[]): void;
|
|
9
|
-
};
|
|
10
|
-
export declare const warn: {
|
|
11
|
-
(...data: any[]): void;
|
|
12
|
-
(message?: any, ...optionalParams: any[]): void;
|
|
13
|
-
};
|
|
14
6
|
export declare const DOCS_HOST = "https://docs.openreplay.com";
|
|
15
7
|
export declare function deprecationWarn(nameOfFeature: string, useInstead: string, docsPath?: string): void;
|
|
16
8
|
export declare function getLabelAttribute(e: Element): string | null;
|
package/cjs/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hasOpenreplayAttribute = exports.getLabelAttribute = exports.deprecationWarn = exports.DOCS_HOST = exports.
|
|
3
|
+
exports.hasOpenreplayAttribute = exports.getLabelAttribute = exports.deprecationWarn = exports.DOCS_HOST = exports.IN_BROWSER = exports.isURL = exports.normSpaces = exports.stars = exports.timestamp = void 0;
|
|
4
4
|
function timestamp() {
|
|
5
5
|
return Math.round(performance.now()) + performance.timing.navigationStart;
|
|
6
6
|
}
|
|
@@ -18,15 +18,14 @@ function isURL(s) {
|
|
|
18
18
|
}
|
|
19
19
|
exports.isURL = isURL;
|
|
20
20
|
exports.IN_BROWSER = !(typeof window === "undefined");
|
|
21
|
-
|
|
22
|
-
exports.warn = console.warn;
|
|
21
|
+
// TODO: JOIN IT WITH LOGGER somehow (use logging decorators?); Don't forget about index.js loggin when there is no logger instance.
|
|
23
22
|
exports.DOCS_HOST = 'https://docs.openreplay.com';
|
|
24
23
|
const warnedFeatures = {};
|
|
25
24
|
function deprecationWarn(nameOfFeature, useInstead, docsPath = "/") {
|
|
26
25
|
if (warnedFeatures[nameOfFeature]) {
|
|
27
26
|
return;
|
|
28
27
|
}
|
|
29
|
-
|
|
28
|
+
console.warn(`OpenReplay: ${nameOfFeature} is deprecated. ${useInstead ? `Please, use ${useInstead} instead.` : ""} Visit ${exports.DOCS_HOST}${docsPath} for more information.`);
|
|
30
29
|
warnedFeatures[nameOfFeature] = true;
|
|
31
30
|
}
|
|
32
31
|
exports.deprecationWarn = deprecationWarn;
|
package/lib/app/index.d.ts
CHANGED
|
@@ -2,8 +2,10 @@ import Message from "../messages/message.js";
|
|
|
2
2
|
import Nodes from "./nodes.js";
|
|
3
3
|
import Sanitizer from "./sanitizer.js";
|
|
4
4
|
import Ticker from "./ticker.js";
|
|
5
|
+
import Logger from "./logger.js";
|
|
5
6
|
import type { Options as ObserverOptions } from "./observer/top_observer.js";
|
|
6
7
|
import type { Options as SanitizerOptions } from "./sanitizer.js";
|
|
8
|
+
import type { Options as LoggerOptions } from "./logger.js";
|
|
7
9
|
import type { Options as WebworkerOptions } from "../messages/webworker.js";
|
|
8
10
|
export interface OnStartInfo {
|
|
9
11
|
sessionID: string;
|
|
@@ -12,6 +14,7 @@ export interface OnStartInfo {
|
|
|
12
14
|
}
|
|
13
15
|
export interface StartOptions {
|
|
14
16
|
userID?: string;
|
|
17
|
+
metadata?: Record<string, string>;
|
|
15
18
|
forceNew: boolean;
|
|
16
19
|
}
|
|
17
20
|
declare type AppOptions = {
|
|
@@ -23,20 +26,24 @@ declare type AppOptions = {
|
|
|
23
26
|
local_uuid_key: string;
|
|
24
27
|
ingestPoint: string;
|
|
25
28
|
resourceBaseHref: string | null;
|
|
29
|
+
verbose: boolean;
|
|
26
30
|
__is_snippet: boolean;
|
|
27
31
|
__debug_report_edp: string | null;
|
|
28
|
-
|
|
32
|
+
__debug__?: LoggerOptions;
|
|
29
33
|
onStart?: (info: OnStartInfo) => void;
|
|
30
34
|
} & WebworkerOptions;
|
|
31
35
|
export declare type Options = AppOptions & ObserverOptions & SanitizerOptions;
|
|
32
36
|
declare type Callback = () => void;
|
|
33
37
|
declare type CommitCallback = (messages: Array<Message>) => void;
|
|
38
|
+
export declare const CANCELED = "canceled";
|
|
34
39
|
export declare const DEFAULT_INGEST_POINT = "https://api.openreplay.com/ingest";
|
|
35
40
|
export default class App {
|
|
36
41
|
readonly nodes: Nodes;
|
|
37
42
|
readonly ticker: Ticker;
|
|
38
43
|
readonly projectKey: string;
|
|
39
44
|
readonly sanitizer: Sanitizer;
|
|
45
|
+
readonly debug: Logger;
|
|
46
|
+
readonly notify: Logger;
|
|
40
47
|
private readonly messages;
|
|
41
48
|
private readonly observer;
|
|
42
49
|
private readonly startCallbacks;
|
|
@@ -46,7 +53,8 @@ export default class App {
|
|
|
46
53
|
private readonly revID;
|
|
47
54
|
private _sessionID;
|
|
48
55
|
private _userID;
|
|
49
|
-
private
|
|
56
|
+
private _metadata;
|
|
57
|
+
private activityState;
|
|
50
58
|
private version;
|
|
51
59
|
private readonly worker?;
|
|
52
60
|
constructor(projectKey: string, sessionToken: string | null | undefined, options: Partial<Options>);
|
|
@@ -54,11 +62,23 @@ export default class App {
|
|
|
54
62
|
send(message: Message, urgent?: boolean): void;
|
|
55
63
|
private commit;
|
|
56
64
|
attachCommitCallback(cb: CommitCallback): void;
|
|
57
|
-
addCommitCallback(cb: CommitCallback): void;
|
|
58
65
|
safe<T extends (...args: any[]) => void>(fn: T): T;
|
|
59
66
|
attachStartCallback(cb: Callback): void;
|
|
60
67
|
attachStopCallback(cb: Callback): void;
|
|
61
68
|
attachEventListener(target: EventTarget, type: string, listener: EventListener, useSafe?: boolean, useCapture?: boolean): void;
|
|
69
|
+
checkRequiredVersion(version: string): boolean;
|
|
70
|
+
private getStartInfo;
|
|
71
|
+
getSessionInfo(): {
|
|
72
|
+
userUUID: string | null;
|
|
73
|
+
projectKey: string;
|
|
74
|
+
revID: string;
|
|
75
|
+
timestamp: number;
|
|
76
|
+
trackerVersion: string;
|
|
77
|
+
userID: string | null;
|
|
78
|
+
isSnippet: boolean;
|
|
79
|
+
sessionID: string | null;
|
|
80
|
+
metadata: Record<string, string>;
|
|
81
|
+
};
|
|
62
82
|
getSessionToken(): string | undefined;
|
|
63
83
|
getSessionID(): string | undefined;
|
|
64
84
|
getHost(): string;
|
package/lib/app/index.js
CHANGED
|
@@ -1,21 +1,34 @@
|
|
|
1
|
-
import { timestamp
|
|
2
|
-
import { Timestamp } from "../messages/index.js";
|
|
1
|
+
import { timestamp } from "../utils.js";
|
|
2
|
+
import { Timestamp, Metadata } from "../messages/index.js";
|
|
3
3
|
import Nodes from "./nodes.js";
|
|
4
4
|
import Observer from "./observer/top_observer.js";
|
|
5
5
|
import Sanitizer from "./sanitizer.js";
|
|
6
6
|
import Ticker from "./ticker.js";
|
|
7
|
+
import Logger, { LogLevel } from "./logger.js";
|
|
7
8
|
import { deviceMemory, jsHeapSizeLimit } from "../modules/performance.js";
|
|
9
|
+
var ActivityState;
|
|
10
|
+
(function (ActivityState) {
|
|
11
|
+
ActivityState[ActivityState["NotActive"] = 0] = "NotActive";
|
|
12
|
+
ActivityState[ActivityState["Starting"] = 1] = "Starting";
|
|
13
|
+
ActivityState[ActivityState["Active"] = 2] = "Active";
|
|
14
|
+
})(ActivityState || (ActivityState = {}));
|
|
15
|
+
export const CANCELED = "canceled";
|
|
8
16
|
// TODO: use backendHost only
|
|
9
17
|
export const DEFAULT_INGEST_POINT = 'https://api.openreplay.com/ingest';
|
|
10
18
|
export default class App {
|
|
11
19
|
constructor(projectKey, sessionToken, options) {
|
|
20
|
+
// if (options.onStart !== undefined) {
|
|
21
|
+
// deprecationWarn("'onStart' option", "tracker.start().then(/* handle session info */)")
|
|
22
|
+
// } ?? maybe onStart is good
|
|
12
23
|
this.messages = [];
|
|
13
24
|
this.startCallbacks = [];
|
|
14
25
|
this.stopCallbacks = [];
|
|
15
26
|
this.commitCallbacks = [];
|
|
16
27
|
this._sessionID = null;
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
28
|
+
this._userID = null;
|
|
29
|
+
this._metadata = {};
|
|
30
|
+
this.activityState = ActivityState.NotActive;
|
|
31
|
+
this.version = '3.5.0'; // TODO: version compatability check inside each plugin.
|
|
19
32
|
this.projectKey = projectKey;
|
|
20
33
|
this.options = Object.assign({
|
|
21
34
|
revID: '',
|
|
@@ -26,9 +39,9 @@ export default class App {
|
|
|
26
39
|
local_uuid_key: '__openreplay_uuid',
|
|
27
40
|
ingestPoint: DEFAULT_INGEST_POINT,
|
|
28
41
|
resourceBaseHref: null,
|
|
42
|
+
verbose: false,
|
|
29
43
|
__is_snippet: false,
|
|
30
44
|
__debug_report_edp: null,
|
|
31
|
-
__debug_log: false,
|
|
32
45
|
}, options);
|
|
33
46
|
if (sessionToken != null) {
|
|
34
47
|
sessionStorage.setItem(this.options.session_token_key, sessionToken);
|
|
@@ -39,6 +52,8 @@ export default class App {
|
|
|
39
52
|
this.observer = new Observer(this, options);
|
|
40
53
|
this.ticker = new Ticker(this);
|
|
41
54
|
this.ticker.attach(() => this.commit());
|
|
55
|
+
this.debug = new Logger(this.options.__debug__);
|
|
56
|
+
this.notify = new Logger(this.options.verbose ? LogLevel.Warnings : LogLevel.Silent);
|
|
42
57
|
try {
|
|
43
58
|
this.worker = new Worker(URL.createObjectURL(new Blob([`"use strict";function t(t){function s(...s){return new t(...s)}return s.prototype=t.prototype,s}const s=new Map;const i=t(class{constructor(t,s,i){this.pageNo=t,this.firstIndex=s,this.timestamp=i,this._id=80}encode(t){return t.uint(80)&&t.uint(this.pageNo)&&t.uint(this.firstIndex)&&t.int(this.timestamp)}});s.set(80,i);const n=t(class{constructor(t){this.timestamp=t,this._id=0}encode(t){return t.uint(0)&&t.uint(this.timestamp)}});s.set(0,n);const e=t(class{constructor(t,s,i){this.url=t,this.referrer=s,this.navigationStart=i,this._id=4}encode(t){return t.uint(4)&&t.string(this.url)&&t.string(this.referrer)&&t.uint(this.navigationStart)}});s.set(4,e);const r=t(class{constructor(t,s){this.width=t,this.height=s,this._id=5}encode(t){return t.uint(5)&&t.uint(this.width)&&t.uint(this.height)}});s.set(5,r);const o=t(class{constructor(t,s){this.x=t,this.y=s,this._id=6}encode(t){return t.uint(6)&&t.int(this.x)&&t.int(this.y)}});s.set(6,o);const h=t(class{constructor(){this._id=7}encode(t){return t.uint(7)}});s.set(7,h);const c=t(class{constructor(t,s,i,n,e){this.id=t,this.parentID=s,this.index=i,this.tag=n,this.svg=e,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)}});s.set(8,c);const u=t(class{constructor(t,s,i){this.id=t,this.parentID=s,this.index=i,this._id=9}encode(t){return t.uint(9)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});s.set(9,u);const a=t(class{constructor(t,s,i){this.id=t,this.parentID=s,this.index=i,this._id=10}encode(t){return t.uint(10)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});s.set(10,a);const d=t(class{constructor(t){this.id=t,this._id=11}encode(t){return t.uint(11)&&t.uint(this.id)}});s.set(11,d);const l=t(class{constructor(t,s,i){this.id=t,this.name=s,this.value=i,this._id=12}encode(t){return t.uint(12)&&t.uint(this.id)&&t.string(this.name)&&t.string(this.value)}});s.set(12,l);const g=t(class{constructor(t,s){this.id=t,this.name=s,this._id=13}encode(t){return t.uint(13)&&t.uint(this.id)&&t.string(this.name)}});s.set(13,g);const f=t(class{constructor(t,s){this.id=t,this.data=s,this._id=14}encode(t){return t.uint(14)&&t.uint(this.id)&&t.string(this.data)}});s.set(14,f);const p=t(class{constructor(t,s,i){this.id=t,this.x=s,this.y=i,this._id=16}encode(t){return t.uint(16)&&t.uint(this.id)&&t.int(this.x)&&t.int(this.y)}});s.set(16,p);const m=t(class{constructor(t,s){this.id=t,this.label=s,this._id=17}encode(t){return t.uint(17)&&t.uint(this.id)&&t.string(this.label)}});s.set(17,m);const _=t(class{constructor(t,s,i){this.id=t,this.value=s,this.mask=i,this._id=18}encode(t){return t.uint(18)&&t.uint(this.id)&&t.string(this.value)&&t.int(this.mask)}});s.set(18,_);const y=t(class{constructor(t,s){this.id=t,this.checked=s,this._id=19}encode(t){return t.uint(19)&&t.uint(this.id)&&t.boolean(this.checked)}});s.set(19,y);const v=t(class{constructor(t,s){this.x=t,this.y=s,this._id=20}encode(t){return t.uint(20)&&t.uint(this.x)&&t.uint(this.y)}});s.set(20,v);const S=t(class{constructor(t,s){this.level=t,this.value=s,this._id=22}encode(t){return t.uint(22)&&t.string(this.level)&&t.string(this.value)}});s.set(22,S);const b=t(class{constructor(t,s,i,n,e,r,o,h,c){this.requestStart=t,this.responseStart=s,this.responseEnd=i,this.domContentLoadedEventStart=n,this.domContentLoadedEventEnd=e,this.loadEventStart=r,this.loadEventEnd=o,this.firstPaint=h,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)}});s.set(23,b);const x=t(class{constructor(t,s,i){this.speedIndex=t,this.visuallyComplete=s,this.timeToInteractive=i,this._id=24}encode(t){return t.uint(24)&&t.uint(this.speedIndex)&&t.uint(this.visuallyComplete)&&t.uint(this.timeToInteractive)}});s.set(24,x);const E=t(class{constructor(t,s,i){this.name=t,this.message=s,this.payload=i,this._id=25}encode(t){return t.uint(25)&&t.string(this.name)&&t.string(this.message)&&t.string(this.payload)}});s.set(25,E);const k=t(class{constructor(t,s){this.name=t,this.payload=s,this._id=27}encode(t){return t.uint(27)&&t.string(this.name)&&t.string(this.payload)}});s.set(27,k);const I=t(class{constructor(t){this.id=t,this._id=28}encode(t){return t.uint(28)&&t.string(this.id)}});s.set(28,I);const z=t(class{constructor(t){this.id=t,this._id=29}encode(t){return t.uint(29)&&t.string(this.id)}});s.set(29,z);const w=t(class{constructor(t,s){this.key=t,this.value=s,this._id=30}encode(t){return t.uint(30)&&t.string(this.key)&&t.string(this.value)}});s.set(30,w);const T=t(class{constructor(t,s,i){this.id=t,this.rule=s,this.index=i,this._id=37}encode(t){return t.uint(37)&&t.uint(this.id)&&t.string(this.rule)&&t.uint(this.index)}});s.set(37,T);const L=t(class{constructor(t,s){this.id=t,this.index=s,this._id=38}encode(t){return t.uint(38)&&t.uint(this.id)&&t.uint(this.index)}});s.set(38,L);const A=t(class{constructor(t,s,i,n,e,r,o){this.method=t,this.url=s,this.request=i,this.response=n,this.status=e,this.timestamp=r,this.duration=o,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)}});s.set(39,A);const C=t(class{constructor(t,s,i,n){this.name=t,this.duration=s,this.args=i,this.result=n,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)}});s.set(40,C);const M=t(class{constructor(t,s){this.key=t,this.value=s,this._id=41}encode(t){return t.uint(41)&&t.string(this.key)&&t.string(this.value)}});s.set(41,M);const R=t(class{constructor(t){this.type=t,this._id=42}encode(t){return t.uint(42)&&t.string(this.type)}});s.set(42,R);const N=t(class{constructor(t,s,i){this.action=t,this.state=s,this.duration=i,this._id=44}encode(t){return t.uint(44)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});s.set(44,N);const D=t(class{constructor(t,s){this.mutation=t,this.state=s,this._id=45}encode(t){return t.uint(45)&&t.string(this.mutation)&&t.string(this.state)}});s.set(45,D);const U=t(class{constructor(t,s){this.type=t,this.payload=s,this._id=46}encode(t){return t.uint(46)&&t.string(this.type)&&t.string(this.payload)}});s.set(46,U);const O=t(class{constructor(t,s,i){this.action=t,this.state=s,this.duration=i,this._id=47}encode(t){return t.uint(47)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});s.set(47,O);const q=t(class{constructor(t,s,i,n){this.operationKind=t,this.operationName=s,this.variables=i,this.response=n,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)}});s.set(48,q);const H=t(class{constructor(t,s,i,n){this.frames=t,this.ticks=s,this.totalJSHeapSize=i,this.usedJSHeapSize=n,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)}});s.set(49,H);const P=t(class{constructor(t,s,i,n,e,r,o,h){this.timestamp=t,this.duration=s,this.ttfb=i,this.headerSize=n,this.encodedBodySize=e,this.decodedBodySize=r,this.url=o,this.initiator=h,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)}});s.set(53,P);const B=t(class{constructor(t,s){this.downlink=t,this.type=s,this._id=54}encode(t){return t.uint(54)&&t.uint(this.downlink)&&t.string(this.type)}});s.set(54,B);const J=t(class{constructor(t){this.hidden=t,this._id=55}encode(t){return t.uint(55)&&t.boolean(this.hidden)}});s.set(55,J);const j=t(class{constructor(t,s,i,n,e,r,o){this.timestamp=t,this.duration=s,this.context=i,this.containerType=n,this.containerSrc=e,this.containerId=r,this.containerName=o,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)}});s.set(59,j);const G=t(class{constructor(t,s,i,n){this.id=t,this.name=s,this.value=i,this.baseURL=n,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)}});s.set(60,G);const K=t(class{constructor(t,s,i){this.id=t,this.data=s,this.baseURL=i,this._id=61}encode(t){return t.uint(61)&&t.uint(this.id)&&t.string(this.data)&&t.string(this.baseURL)}});s.set(61,K);const X=t(class{constructor(t,s){this.type=t,this.value=s,this._id=63}encode(t){return t.uint(63)&&t.string(this.type)&&t.string(this.value)}});s.set(63,X);const F=t(class{constructor(t,s){this.name=t,this.payload=s,this._id=64}encode(t){return t.uint(64)&&t.string(this.name)&&t.string(this.payload)}});s.set(64,F);const Q=t(class{constructor(){this._id=65}encode(t){return t.uint(65)}});s.set(65,Q);const V=t(class{constructor(t,s,i,n){this.id=t,this.rule=s,this.index=i,this.baseURL=n,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)}});s.set(67,V);const W=t(class{constructor(t,s,i,n){this.id=t,this.hesitationTime=s,this.label=i,this.selector=n,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)}});s.set(69,W);const Y=t(class{constructor(t,s){this.frameID=t,this.id=s,this._id=70}encode(t){return t.uint(70)&&t.uint(this.frameID)&&t.uint(this.id)}});s.set(70,Y);const Z="function"==typeof TextEncoder?new TextEncoder:{encode(t){const s=t.length,i=new Uint8Array(3*s);let n=-1;for(var e=0,r=0,o=0;o!==s;){if(e=t.charCodeAt(o),o+=1,e>=55296&&e<=56319){if(o===s){i[n+=1]=239,i[n+=1]=191,i[n+=1]=189;break}if(!((r=t.charCodeAt(o))>=56320&&r<=57343)){i[n+=1]=239,i[n+=1]=191,i[n+=1]=189;continue}if(o+=1,(e=1024*(e-55296)+r-56320+65536)>65535){i[n+=1]=240|e>>>18,i[n+=1]=128|e>>>12&63,i[n+=1]=128|e>>>6&63,i[n+=1]=128|63&e;continue}}e<=127?i[n+=1]=0|e:e<=2047?(i[n+=1]=192|e>>>6,i[n+=1]=128|63&e):(i[n+=1]=224|e>>>12,i[n+=1]=128|e>>>6&63,i[n+=1]=128|63&e)}return i.subarray(0,n+1)}};class tt{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 s=Z.encode(t),i=s.byteLength;return!(!this.uint(i)||this.offset+i>this.size)&&(this.data.set(s,this.offset),this.offset+=i,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}let st=1e6,it=2e5,nt=new tt(it),et="",rt="",ot=0,ht=0,ct=0,ut=0,at=!0;function dt(){return new i(ot,ut,ht).encode(nt)}let lt=null;const gt=[];let ft,pt=!1,mt=0,_t=8e3,yt=10;function vt(){if(at||""===rt||""===et)return;const t=nt.flush();pt?gt.push(t):(pt=!0,function t(s){const i=new XMLHttpRequest;i.open("POST",et+"/v1/web/i",!1),i.setRequestHeader("Authorization","Bearer "+rt),i.onreadystatechange=function(){if(4===this.readyState){if(0==this.status)return;if(this.status>=400)return pt=!1,St(),gt.length=0,401===this.status?void self.postMessage("restart"):void self.postMessage(null);const s=gt.shift();s?t(s):pt=!1}},i.onerror=function(i){if(mt>=yt)return St(),void self.postMessage(null);mt++,setTimeout(()=>t(s),_t)},i.send(s.buffer)}(t)),at=!0,dt()}function St(){et="",rt="",null!==lt&&(clearInterval(lt),lt=null),nt.reset()}self.onmessage=({data:t})=>{if(null!==t)return"stop"===t?(vt(),void St()):Array.isArray(t)?void t.forEach(t=>{const i=new(s.get(t._id));if(Object.assign(i,t),i instanceof n?ht=i.timestamp:i instanceof J&&(i.hidden?ft=setTimeout(()=>self.postMessage("restart"),18e5):clearTimeout(ft)),nt.checkpoint(),!i.encode(nt)&&(vt(),!i.encode(nt)))for(;!i.encode(nt);){if(it===st)return console.warn("OpenReplay: beacon size overflow."),nt.reset(),void dt();it=Math.min(2*it,st),nt=new tt(it),dt()}ut++,at=!1}):(et=t.ingestPoint||et,rt=t.token||rt,ot=t.pageNo||ot,ht=t.startTimestamp||ht,ct=t.timeAdjustment||ct,yt=t.connAttemptCount||yt,_t=t.connAttemptGap||_t,st=t.beaconSizeLimit||st,it=Math.min(st,t.beaconSize||it),nt.isEmpty()&&dt(),void(null===lt&&(lt=setInterval(vt,1e4))));vt()};
|
|
44
59
|
`], { type: 'text/javascript' })));
|
|
@@ -55,7 +70,8 @@ export default class App {
|
|
|
55
70
|
this.stop();
|
|
56
71
|
this.start({
|
|
57
72
|
forceNew: true,
|
|
58
|
-
userID: this._userID,
|
|
73
|
+
userID: this._userID || undefined,
|
|
74
|
+
metadata: this._metadata || undefined,
|
|
59
75
|
});
|
|
60
76
|
}
|
|
61
77
|
};
|
|
@@ -84,12 +100,10 @@ export default class App {
|
|
|
84
100
|
})
|
|
85
101
|
});
|
|
86
102
|
}
|
|
87
|
-
|
|
88
|
-
warn("OpenReplay error: ", context, e);
|
|
89
|
-
}
|
|
103
|
+
this.debug.error("OpenReplay error: ", context, e);
|
|
90
104
|
}
|
|
91
105
|
send(message, urgent = false) {
|
|
92
|
-
if (
|
|
106
|
+
if (this.activityState !== ActivityState.Active) {
|
|
93
107
|
return;
|
|
94
108
|
}
|
|
95
109
|
this.messages.push(message);
|
|
@@ -108,10 +122,6 @@ export default class App {
|
|
|
108
122
|
attachCommitCallback(cb) {
|
|
109
123
|
this.commitCallbacks.push(cb);
|
|
110
124
|
}
|
|
111
|
-
// @Depricated (TODO: remove in 3.5.*)
|
|
112
|
-
addCommitCallback(cb) {
|
|
113
|
-
this.attachCommitCallback(cb);
|
|
114
|
-
}
|
|
115
125
|
safe(fn) {
|
|
116
126
|
const app = this;
|
|
117
127
|
return function (...args) {
|
|
@@ -140,6 +150,30 @@ export default class App {
|
|
|
140
150
|
this.attachStartCallback(() => target.addEventListener(type, listener, useCapture));
|
|
141
151
|
this.attachStopCallback(() => target.removeEventListener(type, listener, useCapture));
|
|
142
152
|
}
|
|
153
|
+
checkRequiredVersion(version) {
|
|
154
|
+
const reqVer = version.split('.');
|
|
155
|
+
const ver = this.version.split('.');
|
|
156
|
+
for (let i = 0; i < ver.length; i++) {
|
|
157
|
+
if (Number(ver[i]) < Number(reqVer[i]) || isNaN(Number(ver[i])) || isNaN(Number(reqVer[i]))) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
getStartInfo() {
|
|
164
|
+
return {
|
|
165
|
+
userUUID: localStorage.getItem(this.options.local_uuid_key),
|
|
166
|
+
projectKey: this.projectKey,
|
|
167
|
+
revID: this.revID,
|
|
168
|
+
timestamp: timestamp(),
|
|
169
|
+
trackerVersion: this.version,
|
|
170
|
+
userID: this._userID,
|
|
171
|
+
isSnippet: this.options.__is_snippet,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
getSessionInfo() {
|
|
175
|
+
return Object.assign({ sessionID: this._sessionID, metadata: this._metadata }, this.getStartInfo());
|
|
176
|
+
}
|
|
143
177
|
getSessionToken() {
|
|
144
178
|
const token = sessionStorage.getItem(this.options.session_token_key);
|
|
145
179
|
if (token !== null) {
|
|
@@ -179,7 +213,7 @@ export default class App {
|
|
|
179
213
|
return url.startsWith(this.options.ingestPoint);
|
|
180
214
|
}
|
|
181
215
|
active() {
|
|
182
|
-
return this.
|
|
216
|
+
return this.activityState === ActivityState.Active;
|
|
183
217
|
}
|
|
184
218
|
resetNextPageSession(flag) {
|
|
185
219
|
if (flag) {
|
|
@@ -193,10 +227,10 @@ export default class App {
|
|
|
193
227
|
if (!this.worker) {
|
|
194
228
|
return Promise.reject("No worker found: perhaps, CSP is not set.");
|
|
195
229
|
}
|
|
196
|
-
if (this.
|
|
230
|
+
if (this.activityState !== ActivityState.NotActive) {
|
|
197
231
|
return Promise.reject("OpenReplay: trying to call `start()` on the instance that has been started already.");
|
|
198
232
|
}
|
|
199
|
-
this.
|
|
233
|
+
this.activityState = ActivityState.Starting;
|
|
200
234
|
let pageNo = 0;
|
|
201
235
|
const pageNoStr = sessionStorage.getItem(this.options.session_pageno_key);
|
|
202
236
|
if (pageNoStr != null) {
|
|
@@ -204,91 +238,75 @@ export default class App {
|
|
|
204
238
|
pageNo++;
|
|
205
239
|
}
|
|
206
240
|
sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
|
|
207
|
-
|
|
241
|
+
this._userID = startOpts.userID || null;
|
|
242
|
+
this._metadata = startOpts.metadata || {}; // TODO: update both dynamically on corresponding messages
|
|
243
|
+
const startInfo = this.getStartInfo();
|
|
208
244
|
const messageData = {
|
|
209
245
|
ingestPoint: this.options.ingestPoint,
|
|
210
246
|
pageNo,
|
|
211
|
-
startTimestamp,
|
|
247
|
+
startTimestamp: startInfo.timestamp,
|
|
212
248
|
connAttemptCount: this.options.connAttemptCount,
|
|
213
249
|
connAttemptGap: this.options.connAttemptGap,
|
|
214
250
|
};
|
|
215
251
|
this.worker.postMessage(messageData); // brings delay of 10th ms?
|
|
216
|
-
// let token = sessionStorage.getItem(this.options.session_token_key)
|
|
217
|
-
// const tokenIsActive = localStorage.getItem("__or_at_" + token)
|
|
218
|
-
// if (tokenIsActive) {
|
|
219
|
-
// token = null
|
|
220
|
-
// }
|
|
221
252
|
const sReset = sessionStorage.getItem(this.options.session_reset_key);
|
|
222
253
|
sessionStorage.removeItem(this.options.session_reset_key);
|
|
223
|
-
this._userID = startOpts.userID || undefined;
|
|
224
254
|
return window.fetch(this.options.ingestPoint + '/v1/web/start', {
|
|
225
255
|
method: 'POST',
|
|
226
256
|
headers: {
|
|
227
257
|
'Content-Type': 'application/json',
|
|
228
258
|
},
|
|
229
|
-
body: JSON.stringify({
|
|
230
|
-
|
|
231
|
-
userUUID: localStorage.getItem(this.options.local_uuid_key),
|
|
232
|
-
projectKey: this.projectKey,
|
|
233
|
-
revID: this.revID,
|
|
234
|
-
timestamp: startTimestamp,
|
|
235
|
-
trackerVersion: this.version,
|
|
236
|
-
isSnippet: this.options.__is_snippet,
|
|
237
|
-
deviceMemory,
|
|
238
|
-
jsHeapSizeLimit,
|
|
239
|
-
reset: startOpts.forceNew || sReset !== null,
|
|
240
|
-
userID: this._userID,
|
|
241
|
-
}),
|
|
259
|
+
body: JSON.stringify(Object.assign(Object.assign({}, startInfo), { token: sessionStorage.getItem(this.options.session_token_key), deviceMemory,
|
|
260
|
+
jsHeapSizeLimit, reset: startOpts.forceNew || sReset !== null })),
|
|
242
261
|
})
|
|
243
262
|
.then(r => {
|
|
244
263
|
if (r.status === 200) {
|
|
245
264
|
return r.json();
|
|
246
265
|
}
|
|
247
|
-
else {
|
|
248
|
-
return r.text().then(text =>
|
|
249
|
-
|
|
250
|
-
|
|
266
|
+
else {
|
|
267
|
+
return r.text().then(text => text === CANCELED
|
|
268
|
+
? Promise.reject(CANCELED)
|
|
269
|
+
: Promise.reject(`Server error: ${r.status}. ${text}`));
|
|
251
270
|
}
|
|
252
271
|
})
|
|
253
272
|
.then(r => {
|
|
273
|
+
if (!this.worker) {
|
|
274
|
+
return Promise.reject("no worker found after start request (this might not happen)");
|
|
275
|
+
}
|
|
254
276
|
const { token, userUUID, sessionID, beaconSizeLimit } = r;
|
|
255
277
|
if (typeof token !== 'string' ||
|
|
256
278
|
typeof userUUID !== 'string' ||
|
|
257
279
|
(typeof beaconSizeLimit !== 'number' && typeof beaconSizeLimit !== 'undefined')) {
|
|
258
|
-
|
|
280
|
+
return Promise.reject(`Incorrect server response: ${JSON.stringify(r)}`);
|
|
259
281
|
}
|
|
260
282
|
sessionStorage.setItem(this.options.session_token_key, token);
|
|
261
283
|
localStorage.setItem(this.options.local_uuid_key, userUUID);
|
|
262
|
-
// localStorage.setItem("__or_at_" + token, "true")
|
|
263
|
-
// this.attachEventListener(window, 'beforeunload', ()=>{
|
|
264
|
-
// localStorage.removeItem("__or_at_" + token)
|
|
265
|
-
// }, false);
|
|
266
|
-
// this.attachEventListener(window, 'pagehide', ()=>{
|
|
267
|
-
// localStorage.removeItem("__or_at_" + token)
|
|
268
|
-
// }, false);
|
|
269
284
|
if (typeof sessionID === 'string') {
|
|
270
285
|
this._sessionID = sessionID;
|
|
271
286
|
}
|
|
272
|
-
|
|
273
|
-
throw new Error("no worker found after start request (this might not happen)");
|
|
274
|
-
}
|
|
287
|
+
this.activityState = ActivityState.Active;
|
|
275
288
|
this.worker.postMessage({ token, beaconSizeLimit });
|
|
276
289
|
this.startCallbacks.forEach((cb) => cb());
|
|
277
290
|
this.observer.observe();
|
|
278
291
|
this.ticker.start();
|
|
279
|
-
|
|
292
|
+
Object.entries(this._metadata).forEach(([key, value]) => this.send(new Metadata(key, value)));
|
|
293
|
+
this.notify.log("OpenReplay tracking started.");
|
|
294
|
+
// TODO: get rid of onStart
|
|
280
295
|
const onStartInfo = { sessionToken: token, userUUID, sessionID };
|
|
281
296
|
if (typeof this.options.onStart === 'function') {
|
|
282
297
|
this.options.onStart(onStartInfo);
|
|
283
298
|
}
|
|
284
299
|
return onStartInfo;
|
|
285
300
|
})
|
|
286
|
-
.catch(
|
|
301
|
+
.catch(reason => {
|
|
287
302
|
sessionStorage.removeItem(this.options.session_token_key);
|
|
288
303
|
this.stop();
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
304
|
+
//if (reason === CANCELED) { return Promise.resolve(CANCELED) } // TODO: what to return ????? Throwing is baad
|
|
305
|
+
if (reason !== CANCELED) {
|
|
306
|
+
this.notify.log("OpenReplay was unable to start. ", reason);
|
|
307
|
+
this._debug("session_start", reason);
|
|
308
|
+
}
|
|
309
|
+
return Promise.reject(reason);
|
|
292
310
|
});
|
|
293
311
|
}
|
|
294
312
|
start(options = { forceNew: false }) {
|
|
@@ -308,7 +326,7 @@ export default class App {
|
|
|
308
326
|
}
|
|
309
327
|
}
|
|
310
328
|
stop() {
|
|
311
|
-
if (this.
|
|
329
|
+
if (this.activityState !== ActivityState.NotActive) {
|
|
312
330
|
try {
|
|
313
331
|
if (this.worker) {
|
|
314
332
|
this.worker.postMessage("stop");
|
|
@@ -318,10 +336,10 @@ export default class App {
|
|
|
318
336
|
this.nodes.clear();
|
|
319
337
|
this.ticker.stop();
|
|
320
338
|
this.stopCallbacks.forEach((cb) => cb());
|
|
321
|
-
log("OpenReplay tracking stopped.");
|
|
339
|
+
this.notify.log("OpenReplay tracking stopped.");
|
|
322
340
|
}
|
|
323
341
|
finally {
|
|
324
|
-
this.
|
|
342
|
+
this.activityState = ActivityState.NotActive;
|
|
325
343
|
}
|
|
326
344
|
}
|
|
327
345
|
}
|
package/lib/app/logger.d.ts
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const LogLevel: {
|
|
2
|
+
readonly Verbose: 4;
|
|
3
|
+
readonly Errors: 4;
|
|
4
|
+
readonly Warnings: 3;
|
|
5
|
+
readonly Log: 2;
|
|
6
|
+
readonly Silent: 0;
|
|
7
|
+
};
|
|
8
|
+
declare type LogLevel = typeof LogLevel[keyof typeof LogLevel];
|
|
9
|
+
declare type CustomLevel = {
|
|
10
|
+
error: boolean;
|
|
11
|
+
warn: boolean;
|
|
12
|
+
log: boolean;
|
|
13
|
+
};
|
|
14
|
+
interface _Options {
|
|
15
|
+
level: LogLevel | CustomLevel;
|
|
16
|
+
messages?: number[];
|
|
17
|
+
}
|
|
18
|
+
export declare type Options = true | _Options | LogLevel;
|
|
19
|
+
export default class Logger {
|
|
20
|
+
private readonly options;
|
|
21
|
+
private readonly opts;
|
|
22
|
+
constructor(options?: Options);
|
|
23
|
+
log(...args: any): void;
|
|
24
|
+
warn(...args: any): void;
|
|
25
|
+
error(...args: any): void;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
package/lib/app/logger.js
CHANGED
|
@@ -1 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
export const LogLevel = {
|
|
2
|
+
Verbose: 4,
|
|
3
|
+
Errors: 4,
|
|
4
|
+
Warnings: 3,
|
|
5
|
+
Log: 2,
|
|
6
|
+
Silent: 0,
|
|
7
|
+
};
|
|
8
|
+
function IsCustomLevel(l) {
|
|
9
|
+
return typeof l === 'object';
|
|
10
|
+
}
|
|
11
|
+
export default class Logger {
|
|
12
|
+
constructor(options = LogLevel.Silent) {
|
|
13
|
+
this.options = options;
|
|
14
|
+
this.opts = options === true
|
|
15
|
+
? { level: LogLevel.Verbose }
|
|
16
|
+
: typeof options === "number" ? { level: options } : options;
|
|
17
|
+
}
|
|
18
|
+
log(...args) {
|
|
19
|
+
if (IsCustomLevel(this.opts.level)
|
|
20
|
+
? this.opts.level.log
|
|
21
|
+
: this.opts.level >= LogLevel.Log) {
|
|
22
|
+
console.log(...args);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
warn(...args) {
|
|
26
|
+
if (IsCustomLevel(this.opts.level)
|
|
27
|
+
? this.opts.level.warn
|
|
28
|
+
: this.opts.level >= LogLevel.Warnings) {
|
|
29
|
+
console.warn(...args);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
error(...args) {
|
|
33
|
+
if (IsCustomLevel(this.opts.level)
|
|
34
|
+
? this.opts.level.error
|
|
35
|
+
: this.opts.level >= LogLevel.Errors) {
|
|
36
|
+
console.error(...args);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -24,7 +24,6 @@ export default class API {
|
|
|
24
24
|
constructor(options: Options);
|
|
25
25
|
use<T>(fn: (app: App | null, options?: Options) => T): T;
|
|
26
26
|
isActive(): boolean;
|
|
27
|
-
active(): boolean;
|
|
28
27
|
start(startOpts?: StartOptions): Promise<OnStartInfo>;
|
|
29
28
|
stop(): void;
|
|
30
29
|
getSessionToken(): string | null | undefined;
|
package/lib/index.js
CHANGED
|
@@ -125,7 +125,7 @@ export default class API {
|
|
|
125
125
|
// no-cors issue only with text/plain or not-set Content-Type
|
|
126
126
|
// req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
127
127
|
req.send(JSON.stringify({
|
|
128
|
-
trackerVersion: '3.
|
|
128
|
+
trackerVersion: '3.5.0',
|
|
129
129
|
projectKey: options.projectKey,
|
|
130
130
|
doNotTrack,
|
|
131
131
|
// TODO: add precise reason (an exact API missing)
|
|
@@ -141,10 +141,6 @@ export default class API {
|
|
|
141
141
|
}
|
|
142
142
|
return this.app.active();
|
|
143
143
|
}
|
|
144
|
-
active() {
|
|
145
|
-
deprecationWarn("'active' method", "'isActive' method", "/");
|
|
146
|
-
return this.isActive();
|
|
147
|
-
}
|
|
148
144
|
start(startOpts) {
|
|
149
145
|
if (!IN_BROWSER) {
|
|
150
146
|
console.error(`OpenReplay: you are trying to start Tracker on a node.js environment. If you want to use OpenReplay with SSR, please, use componentDidMount or useEffect API for placing the \`tracker.start()\` line. Check documentation on ${DOCS_HOST}${DOCS_SETUP}`);
|
|
@@ -153,6 +149,7 @@ export default class API {
|
|
|
153
149
|
if (this.app === null) {
|
|
154
150
|
return Promise.reject("Browser doesn't support required api, or doNotTrack is active.");
|
|
155
151
|
}
|
|
152
|
+
// TODO: check argument typing
|
|
156
153
|
return this.app.start(startOpts);
|
|
157
154
|
}
|
|
158
155
|
stop() {
|
package/lib/modules/console.js
CHANGED
package/lib/modules/mouse.js
CHANGED
|
@@ -55,6 +55,7 @@ function _getTarget(target) {
|
|
|
55
55
|
if (tag === 'BUTTON' ||
|
|
56
56
|
tag === 'A' ||
|
|
57
57
|
tag === 'LI' ||
|
|
58
|
+
tag === 'SELECT' ||
|
|
58
59
|
element.onclick != null ||
|
|
59
60
|
element.getAttribute('role') === 'button' ||
|
|
60
61
|
getLabelAttribute(element) !== null) {
|
|
@@ -81,6 +82,7 @@ export default function (app) {
|
|
|
81
82
|
if (tag === 'BUTTON' ||
|
|
82
83
|
tag === 'A' ||
|
|
83
84
|
tag === 'LI' ||
|
|
85
|
+
tag === 'SELECT' ||
|
|
84
86
|
target.onclick != null ||
|
|
85
87
|
target.getAttribute('role') === 'button') {
|
|
86
88
|
const label = app.sanitizer.getInnerTextSecure(target);
|
package/lib/utils.d.ts
CHANGED
|
@@ -3,14 +3,6 @@ export declare const stars: (str: string) => string;
|
|
|
3
3
|
export declare function normSpaces(str: string): string;
|
|
4
4
|
export declare function isURL(s: string): boolean;
|
|
5
5
|
export declare const IN_BROWSER: boolean;
|
|
6
|
-
export declare const log: {
|
|
7
|
-
(...data: any[]): void;
|
|
8
|
-
(message?: any, ...optionalParams: any[]): void;
|
|
9
|
-
};
|
|
10
|
-
export declare const warn: {
|
|
11
|
-
(...data: any[]): void;
|
|
12
|
-
(message?: any, ...optionalParams: any[]): void;
|
|
13
|
-
};
|
|
14
6
|
export declare const DOCS_HOST = "https://docs.openreplay.com";
|
|
15
7
|
export declare function deprecationWarn(nameOfFeature: string, useInstead: string, docsPath?: string): void;
|
|
16
8
|
export declare function getLabelAttribute(e: Element): string | null;
|
package/lib/utils.js
CHANGED
|
@@ -12,15 +12,14 @@ export function isURL(s) {
|
|
|
12
12
|
return s.substr(0, 8) === 'https://' || s.substr(0, 7) === 'http://';
|
|
13
13
|
}
|
|
14
14
|
export const IN_BROWSER = !(typeof window === "undefined");
|
|
15
|
-
|
|
16
|
-
export const warn = console.warn;
|
|
15
|
+
// TODO: JOIN IT WITH LOGGER somehow (use logging decorators?); Don't forget about index.js loggin when there is no logger instance.
|
|
17
16
|
export const DOCS_HOST = 'https://docs.openreplay.com';
|
|
18
17
|
const warnedFeatures = {};
|
|
19
18
|
export function deprecationWarn(nameOfFeature, useInstead, docsPath = "/") {
|
|
20
19
|
if (warnedFeatures[nameOfFeature]) {
|
|
21
20
|
return;
|
|
22
21
|
}
|
|
23
|
-
warn(`OpenReplay: ${nameOfFeature} is deprecated. ${useInstead ? `Please, use ${useInstead} instead.` : ""} Visit ${DOCS_HOST}${docsPath} for more information.`);
|
|
22
|
+
console.warn(`OpenReplay: ${nameOfFeature} is deprecated. ${useInstead ? `Please, use ${useInstead} instead.` : ""} Visit ${DOCS_HOST}${docsPath} for more information.`);
|
|
24
23
|
warnedFeatures[nameOfFeature] = true;
|
|
25
24
|
}
|
|
26
25
|
export function getLabelAttribute(e) {
|