@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 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.
@@ -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
- __debug_log: boolean;
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 isActive;
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.isActive = false;
21
- this.version = '3.4.17';
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
- if (this.options.__debug_log) {
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 (!this.isActive) {
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.isActive;
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.isActive) {
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.isActive = true;
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
- const startTimestamp = (0, utils_js_1.timestamp)();
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
- token: sessionStorage.getItem(this.options.session_token_key),
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 { // TODO: handle canceling && 403
251
- return r.text().then(text => {
252
- throw new Error(`Server error: ${r.status}. ${text}`);
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
- throw new Error(`Incorrect server response: ${JSON.stringify(r)}`);
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
- if (!this.worker) {
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
- (0, utils_js_1.log)("OpenReplay tracking started.");
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(e => {
304
+ .catch(reason => {
290
305
  sessionStorage.removeItem(this.options.session_token_key);
291
306
  this.stop();
292
- (0, utils_js_1.warn)("OpenReplay was unable to start. ", e);
293
- this._debug("session_start", e);
294
- throw e;
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.isActive) {
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
- (0, utils_js_1.log)("OpenReplay tracking stopped.");
342
+ this.notify.log("OpenReplay tracking stopped.");
325
343
  }
326
344
  finally {
327
- this.isActive = false;
345
+ this.activityState = ActivityState.NotActive;
328
346
  }
329
347
  }
330
348
  }
@@ -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.4.17',
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() {
@@ -18,7 +18,7 @@ function printString(arg) {
18
18
  if (Array.isArray(arg)) {
19
19
  return `Array(${arg.length})`;
20
20
  }
21
- return arg.toString();
21
+ return String(arg);
22
22
  }
23
23
  function printFloat(arg) {
24
24
  if (typeof arg !== 'number')
@@ -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.warn = exports.log = exports.IN_BROWSER = exports.isURL = exports.normSpaces = exports.stars = exports.timestamp = void 0;
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
- exports.log = console.log;
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
- (0, exports.warn)(`OpenReplay: ${nameOfFeature} is deprecated. ${useInstead ? `Please, use ${useInstead} instead.` : ""} Visit ${exports.DOCS_HOST}${docsPath} for more information.`);
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;
@@ -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
- __debug_log: boolean;
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 isActive;
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, log, warn } from "../utils.js";
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.isActive = false;
18
- this.version = '3.4.17';
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
- if (this.options.__debug_log) {
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 (!this.isActive) {
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.isActive;
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.isActive) {
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.isActive = true;
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
- const startTimestamp = timestamp();
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
- token: sessionStorage.getItem(this.options.session_token_key),
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 { // TODO: handle canceling && 403
248
- return r.text().then(text => {
249
- throw new Error(`Server error: ${r.status}. ${text}`);
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
- throw new Error(`Incorrect server response: ${JSON.stringify(r)}`);
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
- if (!this.worker) {
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
- log("OpenReplay tracking started.");
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(e => {
301
+ .catch(reason => {
287
302
  sessionStorage.removeItem(this.options.session_token_key);
288
303
  this.stop();
289
- warn("OpenReplay was unable to start. ", e);
290
- this._debug("session_start", e);
291
- throw e;
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.isActive) {
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.isActive = false;
342
+ this.activityState = ActivityState.NotActive;
325
343
  }
326
344
  }
327
345
  }
@@ -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
- "use strict";
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.4.17',
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() {
@@ -16,7 +16,7 @@ function printString(arg) {
16
16
  if (Array.isArray(arg)) {
17
17
  return `Array(${arg.length})`;
18
18
  }
19
- return arg.toString();
19
+ return String(arg);
20
20
  }
21
21
  function printFloat(arg) {
22
22
  if (typeof arg !== 'number')
@@ -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
- export const log = console.log;
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) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openreplay/tracker",
3
3
  "description": "The OpenReplay tracker main package",
4
- "version": "3.4.17",
4
+ "version": "3.5.0",
5
5
  "keywords": [
6
6
  "logging",
7
7
  "replay"