Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mouselog

Package Overview
Dependencies
Maintainers
2
Versions
57
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mouselog - npm Package Compare versions

Comparing version 0.0.9-beta1 to 0.0.9-beta2

523

build/mouselog.js

@@ -101,89 +101,91 @@ (function webpackUniversalModuleDefinition(root, factory) {

class Config {
// Set up a default config
constructor() {
// Type: string, REQUIRED
// Endpoint Url
this.uploadEndpoint = "http://localhost:9000";
// Type: string
// Website ID
this.websiteId = "unknown";
// Default config
let config = {
// Type: string, REQUIRED
// Endpoint Url
uploadEndpoint: "http://localhost:9000",
// Endpoint type, "absolute" or "relative"
this.endpointType = "absolute";
// Type: string
// Website ID
websiteId: "unknown",
// Upload mode, "mixed", "periodic" or "event-triggered"
this.uploadMode = "mixed";
// Endpoint type, "absolute" or "relative"
endpointType: "absolute",
// Type: number
// If `uploadMode` is "mixed", "periodic", data will be uploaded every `uploadPeriod` ms.
// If no data are collected in a period, no data will be uploaded
this.uploadPeriod = 5000;
// Upload mode, "mixed", "periodic" or "event-triggered"
uploadMode: "mixed",
// Type: number
// If `uploadMode` == "event-triggered"
// The website interaction data will be uploaded when every `frequency` events are captured.
this.frequency = 50;
// Type: number
// If `uploadMode` is "mixed", "periodic", data will be uploaded every `uploadPeriod` ms.
// If no data are collected in a period, no data will be uploaded
uploadPeriod: 5000,
// Type: bool
// Use GET method to upload data? (stringified data will be embedded in URI)
this.enableGet = false;
// Type: number
// If `uploadMode` == "event-triggered"
// The website interaction data will be uploaded when every `frequency` events are captured.
frequency: 50,
// Type: number
// Time interval for resending the failed trace data
this.resendInterval = 3000;
// Type: bool
// Use GET method to upload data? (stringified data will be embedded in URI)
enableGet: false,
this._requiredParams = [
"uploadEndpoint",
]
}
// Type: number
// Time interval for resending the failed trace data
resendInterval: 3000,
}
build(config) {
try {
this._requiredParams.forEach(key => {
if (!config.hasOwnProperty(key)) {
throw new Error(`Param ${key} is required but not declared.`);
}
});
// Overwrite the default config
Object.keys(config).forEach( key => {
// Overwriting Class private members / function method is not allowed
if (this[key] && !key.startsWith("_") && typeof(this[key]) != "function") {
this[key] = config[key]
}
})
// ----------------------------
this.absoluteUrl = this._formatUrl();
} catch(err) {
console.log(err);
return false;
}
return true;
}
let requiredParams = [
"uploadEndpoint",
];
update(config) {
return this.build(config);
}
// Returns a boolean indicating if config is built successfully
let buildConfig = (params) => {
try {
requiredParams.forEach(key => {
if (!(params.hasOwnProperty(key))) {
throw new Error(`Param ${key} is required but not declared.`);
_formatUrl() {
let url = this.uploadEndpoint;
if (this.endpointType == "relative") {
if (url.startsWith("./")) {
url = url.slice(1);
} else if (url[0] !== "/") {
url = "/" + url;
}
});
config = Object.assign(config, params);
config.absoluteUrl = formatUrl();
} catch(err) {
console.log(err);
return false;
}
return true;
}
let updateConfig = (params) => {
// Generate new config
return buildConfig(params);
}
let formatUrl = () => {
let url = config.uploadEndpoint
if (config.endpointType == "relative") {
// Format the head (the path should start with '/')
if (url.startsWith("./")) {
url = url.slice(1);
} else if (url[0] !== "/") {
url = "/" + url;
// Format the tail
if (url[url.length-1] === "/") {
url = url.slice(0, url.length-1);
}
// Construct absolute URL
url = `${window.location.origin}${url}`
} else if (this.endpointType !== "absolute") {
throw new Error('`endpointType` can only be "absolute" or "relative"');
}
// Format the tail
if (url[url.length-1] === "/") {
url = url.slice(0, url.length-1);
}
// Construct absolute URL
url = `${window.location.origin}${url}`
} else if (config.endpointType !== "absolute") {
throw new Error('`endpointType` can only be "absolute" or "relative"');
return url;
}
return url;
}
module.exports = { config, buildConfig, updateConfig }
module.exports = { Config };

@@ -194,27 +196,6 @@ /***/ }),

let mouselog = __webpack_require__(2);
const uuidv4 = __webpack_require__(2);
const Uploader = __webpack_require__(5);
let { Config } = __webpack_require__(0);
function run(config) {
mouselog.run(config);
}
function stop() {
mouselog.stop();
}
module.exports = { run, stop };
/***/ }),
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "run", function() { return run; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "stop", function() { return stop; });
const uuidv4 = __webpack_require__(3);
const Uploader = __webpack_require__(6);
let { config, buildConfig } = __webpack_require__(0);
let targetEvents = [

@@ -232,189 +213,207 @@ "mousemove",

];
let pageLoadTime = new Date();
let uploader;
let impressionId;
let eventsList;
let pageLoadTime;
let uploadIdx;
let uploadInterval; // For "periodic" upload mode
let uploadTimeout; // For "mixed" upload mode
function getRelativeTimestampInSeconds() {
let diff = new Date() - pageLoadTime;
return Math.trunc(diff) / 1000;
}
class Mouselog{
constructor() {
this.config = new Config();
this.impressionId = uuidv4();
this.mouselogLoadTime = new Date();
this.uploader = new Uploader();
this.eventsList = [];
this.uploadInterval; // For "periodic" upload mode
this.uploadTimeout; // For "mixed" upload mode
}
function getButton(btn) {
if (btn === '2') {
return 'Right';
} else {
return ""
_clearBuffer() {
this.eventsList = [];
}
}
function newTrace() {
let trace = {
id: '0',
idx: uploadIdx,
url: window.location.hostname ? window.location.hostname : "localhost",
path: window.location.pathname,
width: document.body.scrollWidth,
height: document.body.scrollHeight,
pageLoadTime: pageLoadTime,
label: -1,
guess: -1,
events: []
}
uploadIdx += 1;
return trace;
}
_newTrace() {
let trace = {
id: '0',
idx: this.uploadIdx,
url: window.location.hostname ? window.location.hostname : "localhost",
path: window.location.pathname,
width: document.body.scrollWidth,
height: document.body.scrollHeight,
pageLoadTime: pageLoadTime,
label: -1,
guess: -1,
events: []
}
this.uploadIdx += 1;
return trace;
}
function uploadTrace() {
let trace = newTrace();
trace.events = eventsList;
eventsList = [];
return uploader.upload(trace); // This is a promise
}
_mouseHandler(evt) {
// PC's Chrome on Mobile mode can still receive "contextmenu" event with zero X, Y, so we ignore these events.
if (evt.type === 'contextmenu' && evt.pageX === 0 && evt.pageY === 0) {
return;
}
let x = evt.pageX;
let y = evt.pageY;
if (x === undefined) {
x = evt.changedTouches[0].pageX;
y = evt.changedTouches[0].pageY;
}
let tmpEvt = {
// TODO: Is `id` be used to order the event by timestamp?
id: this.eventsList.length,
timestamp: getRelativeTimestampInSeconds(),
type: evt.type,
x: x,
y: y,
button: getButton(evt.button)
}
function periodUploadTimeout() {
clearTimeout(uploadTimeout);
uploadTimeout = setTimeout(() => {
if (eventsList.length > 0) {
uploadTrace();
if (evt.type == "wheel") {
tmpEvt.deltaX = evt.deltaX;
tmpEvt.deltaY = evt.deltaY;
}
}, config.uploadPeriod);
}
this.eventsList.push(tmpEvt);
function periodUploadInterval() {
clearInterval(uploadInterval);
uploadInterval = setInterval(() => {
if (eventsList.length != 0) {
uploadTrace();
if ( this.config.uploadMode == "event-triggered" && this.eventsList.length % this.config.frequency == 0 ) {
this._uploadTrace();
}
}, config.uploadPeriod);
}
function mouseHandler(evt) {
// PC's Chrome on Mobile mode can still receive "contextmenu" event with zero X, Y, so we ignore these events.
if (evt.type === 'contextmenu' && evt.pageX === 0 && evt.pageY === 0) {
return;
if ( this.config.uploadMode == "mixed" && this.eventsList.length % this.config.frequency == 0) {
this._periodUploadTimeout();
this._uploadTrace();
}
}
let x = evt.pageX;
let y = evt.pageY;
if (x === undefined) {
x = evt.changedTouches[0].pageX;
y = evt.changedTouches[0].pageY;
_fetchConfigFromServer() {
// Upload an empty trace to fetch config from server
let trace = this._newTrace();
return this.uploader.upload(trace); // This is a promise
}
let tmpEvt = {
id: eventsList.length,
timestamp: getRelativeTimestampInSeconds(),
type: evt.type,
x: x,
y: y,
button: getButton(evt.button)
_uploadTrace() {
let trace = this._newTrace();
trace.events = this.eventsList;
this.eventsList = [];
return this.uploader.upload(trace); // This is a promise
}
if (evt.type == "wheel") {
tmpEvt.deltaX = evt.deltaX;
tmpEvt.deltaY = evt.deltaY;
_periodUploadTimeout() {
clearTimeout(this.uploadTimeout);
this.uploadTimeout = setTimeout(() => {
if (this.eventsList.length > 0) {
this._uploadTrace();
}
})
}
eventsList.push(tmpEvt);
if ( config.uploadMode == "event-triggered" && eventsList.length % config.frequency == 0 ) {
uploadTrace();
_periodUploadInterval() {
clearInterval(this.uploadInterval);
this.uploadInterval = setInterval(() => {
if (this.eventsList.length > 0) {
this._uploadTrace();
}
}, this.config.uploadPeriod);
}
if ( config.uploadMode == "mixed" && eventsList.length % config.frequency == 0) {
periodUploadTimeout();
uploadTrace();
_runCollector() {
targetEvents.forEach( s => {
window.document.addEventListener(s, (evt) => this._mouseHandler(evt));
});
if (this.config.uploadMode === "periodic") {
this._periodUploadInterval();
}
if (this.config.uploadMode === "mixed") {
this._periodUploadTimeout();
}
}
}
function clearBuffer() {
eventsList = [];
}
_stopCollector() {
targetEvents.forEach( s => {
window.document.removeEventListener(s, (evt) => this._mouseHandler(evt));
});
clearInterval(this.uploadInterval);
clearTimeout(this.uploadTimeout);
}
// Initialize the mouselog
function init(params) {
clearBuffer();
pageLoadTime = new Date();
uploadIdx = 0;
uploader = new Uploader();
impressionId = uuidv4();
uploader.setImpressionId(impressionId);
if (buildConfig(params)) {
// Async: Upload an empty data to ofetch config from backend
uploadTrace().then( result => {
if (result.status === 0) { // Config is updated successfully
resetCollector();
} else {
console.log(result.msg);
console.log("Fail to overwrite config with server config.")
_resetCollector() {
this._stopCollector();
this._runCollector();
}
_init(config) {
this.impressionId = uuidv4();
this._clearBuffer();
this.uploadIdx = 0;
this.uploader = new Uploader(this.impressionId, this.config);
this.uploader.setImpressionId(this.impressionId);
if (this.config.build(config)) {
// Async: Upload an empty data to fetch config from server
this._fetchConfigFromServer().then( result => {
if (result.status == 1) {
if (this.config.update(result.config)) {
this._resetCollector();
this.uploader.setConfig(this.config);
console.log("Config updated.")
} else {
throw new Error(`Unable to update config with server config.`);
}
} else {
throw new Error(`Fail to get config from server.`);
}
}).catch(err => {
console.log(err);
});
window.onbeforeunload = (evt) => {
if (this.eventsList.length != 0) {
this._uploadTrace();
}
}
});
onbeforeunload = (evt) => {
if (eventsList.length != 0) {
uploadTrace();
}
return {status: 0};
} else {
return {status: -1, msg: `Invalid configuration.`};
}
return {status: 0, msg: `Invalid configuration.`};
} else {
return {status: -1, msg: `Invalid configuration.`}
}
}
function runCollector() {
targetEvents.forEach( s => {
window.document.addEventListener(s, (evt) => mouseHandler(evt));
});
run(config) {
let res = this._init(config);
if (res.status == 0) {
this._runCollector();
this.uploader.start(this.impressionId);
console.log("Mouselog agent is activated!");
} else {
console.log(res.msg);
console.log("Fail to initialize Mouselog agent.");
}
}
if (config.uploadMode === "periodic") {
periodUploadInterval();
}
if (config.uploadMode == "mixed") {
periodUploadTimeout();
stop() {
this.uploader.stop();
this._stopCollector();
this._clearBuffer();
console.log(`Mouselog agent ${this.impressionId} is stopped!`);
}
}
function stopCollector() {
targetEvents.forEach( s => {
window.document.removeEventListener(s, (evt) => mouseHandler(evt));
});
clearInterval(uploadInterval);
clearTimeout(uploadTimeout);
function getRelativeTimestampInSeconds() {
let diff = new Date() - pageLoadTime;
return Math.trunc(diff) / 1000;
}
function resetCollector(removeData = false) {
stopCollector();
runCollector();
}
function run(params) {
let res = init(params);
if (res.status == 0) {
runCollector();
uploader.start(impressionId);
console.log("Mouselog agent is activated!");
function getButton(btn) {
if (btn === '2') {
return 'Right';
} else {
console.log(res.msg);
console.log("Fail to initialize Mouselog agent.");
return ""
}
}
function stop() {
uploader.stop();
stopCollector();
clearBuffer();
console.log("Mouselog agent is stopped!");
}
module.exports = { Mouselog };
/***/ }),
/* 3 */
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
var rng = __webpack_require__(4);
var bytesToUuid = __webpack_require__(5);
var rng = __webpack_require__(3);
var bytesToUuid = __webpack_require__(4);

@@ -450,3 +449,3 @@ function v4(options, buf, offset) {

/***/ }),
/* 4 */
/* 3 */
/***/ (function(module, exports) {

@@ -491,3 +490,3 @@

/***/ }),
/* 5 */
/* 4 */
/***/ (function(module, exports) {

@@ -524,3 +523,3 @@

/***/ }),
/* 6 */
/* 5 */
/***/ (function(module, exports, __webpack_require__) {

@@ -537,11 +536,12 @@

class Uploader {
constructor() {
constructor(impressionId, config) {
this.impressionId = impressionId;
this.config = config;
this.resendQueue = [];
}
start(impressionId) {
this.impressionId = impressionId;
start() {
this.resendInterval = setInterval(()=>{
this._resendFailedData.call(this);
}, config.resendInterval);
}, this.config.resendInterval);
}

@@ -555,3 +555,3 @@

upload(data) {
// resolve(true/false): uploaded success/fail.
// resolve({status:-1/0/1, ...}): uploading success/fail.
// reject(ErrorMessage): Errors occur when updating the config.

@@ -567,5 +567,7 @@ return new Promise( (resolve, reject) => {

if (resObj.msg == "config") {
if (!updateConfig(resObj.data)) {
resolve({status: -1, msg: `Data is uploaded, but errors occur when updating config.`});
};
resolve({
status: 1,
msg: `Get config from server`,
config: resObj.data
});
}

@@ -579,3 +581,6 @@ resolve({status: 0});

this._appendFailedData(data);
resolve({status: -1, msg: `Fail to upload a bunch of data: ${err.message}`});
resolve({
status: -1,
msg: `Fail to upload a bunch of data, ${err.message}`
});
})

@@ -589,2 +594,8 @@ });

setConfig(config) {
this.stop();
this.config = config;
this.start();
}
_resendFailedData() {

@@ -613,4 +624,4 @@ let i = 0;

_upload(encodedData) {
if (config.enableGet) {
return fetch(`${config.absoluteUrl}/api/upload-trace?websiteId=${config.websiteId}&impressionId=${this.impressionId}&data=${encodedData}`, {
if (this.config.enableGet) {
return fetch(`${this.config.absoluteUrl}/api/upload-trace?websiteId=${this.config.websiteId}&impressionId=${this.impressionId}&data=${encodedData}`, {
method: "GET",

@@ -620,3 +631,3 @@ credentials: "include"

} else {
return fetch(`${config.absoluteUrl}/api/upload-trace?websiteId=${config.websiteId}&impressionId=${this.impressionId}`, {
return fetch(`${this.config.absoluteUrl}/api/upload-trace?websiteId=${this.config.websiteId}&impressionId=${this.impressionId}`, {
method: "POST",

@@ -623,0 +634,0 @@ credentials: "include",

@@ -1,1 +0,1 @@

!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.mouselog=t():e.mouselog=t()}(window,(function(){return function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=1)}([function(e,t){let n={uploadEndpoint:"http://localhost:9000",websiteId:"unknown",endpointType:"absolute",uploadMode:"mixed",uploadPeriod:5e3,frequency:50,enableGet:!1,resendInterval:3e3},o=["uploadEndpoint"],r=e=>{try{o.forEach(t=>{if(!e.hasOwnProperty(t))throw new Error(`Param ${t} is required but not declared.`)}),n=Object.assign(n,e),n.absoluteUrl=i()}catch(e){return console.log(e),!1}return!0},i=()=>{let e=n.uploadEndpoint;if("relative"==n.endpointType)e.startsWith("./")?e=e.slice(1):"/"!==e[0]&&(e="/"+e),"/"===e[e.length-1]&&(e=e.slice(0,e.length-1)),e=`${window.location.origin}${e}`;else if("absolute"!==n.endpointType)throw new Error('`endpointType` can only be "absolute" or "relative"');return e};e.exports={config:n,buildConfig:r,updateConfig:e=>r(e)}},function(e,t,n){let o=n(2);e.exports={run:function(e){o.run(e)},stop:function(){o.stop()}}},function(e,t,n){"use strict";n.r(t),n.d(t,"run",(function(){return j})),n.d(t,"stop",(function(){return M}));const o=n(3),r=n(6);let i,s,a,u,l,d,c,{config:p,buildConfig:f}=n(0),g=["mousemove","mousedown","mouseup","mouseclick","dblclick","contextmenu","wheel","torchstart","touchmove","touchend"];function h(){let e=new Date-u;return Math.trunc(e)/1e3}function m(){let e=function(){let e={id:"0",idx:l,url:window.location.hostname?window.location.hostname:"localhost",path:window.location.pathname,width:document.body.scrollWidth,height:document.body.scrollHeight,pageLoadTime:u,label:-1,guess:-1,events:[]};return l+=1,e}();return e.events=a,a=[],i.upload(e)}function y(){clearTimeout(c),c=setTimeout(()=>{a.length>0&&m()},p.uploadPeriod)}function b(e){if("contextmenu"===e.type&&0===e.pageX&&0===e.pageY)return;let t=e.pageX,n=e.pageY;void 0===t&&(t=e.changedTouches[0].pageX,n=e.changedTouches[0].pageY);let o={id:a.length,timestamp:h(),type:e.type,x:t,y:n,button:(r=e.button,"2"===r?"Right":"")};var r;"wheel"==e.type&&(o.deltaX=e.deltaX,o.deltaY=e.deltaY),a.push(o),"event-triggered"==p.uploadMode&&a.length%p.frequency==0&&m(),"mixed"==p.uploadMode&&a.length%p.frequency==0&&(y(),m())}function w(){a=[]}function v(e){return w(),u=new Date,l=0,i=new r,s=o(),i.setImpressionId(s),f(e)?(m().then(e=>{0===e.status?(x(),I()):(console.log(e.msg),console.log("Fail to overwrite config with server config."))}),onbeforeunload=e=>{0!=a.length&&m()},{status:0,msg:"Invalid configuration."}):{status:-1,msg:"Invalid configuration."}}function I(){g.forEach(e=>{window.document.addEventListener(e,e=>b(e))}),"periodic"===p.uploadMode&&(clearInterval(d),d=setInterval(()=>{0!=a.length&&m()},p.uploadPeriod)),"mixed"==p.uploadMode&&y()}function x(){g.forEach(e=>{window.document.removeEventListener(e,e=>b(e))}),clearInterval(d),clearTimeout(c)}function j(e){let t=v(e);0==t.status?(I(),i.start(s),console.log("Mouselog agent is activated!")):(console.log(t.msg),console.log("Fail to initialize Mouselog agent."))}function M(){i.stop(),x(),w(),console.log("Mouselog agent is stopped!")}},function(e,t,n){var o=n(4),r=n(5);e.exports=function(e,t,n){var i=t&&n||0;"string"==typeof e&&(t="binary"===e?new Array(16):null,e=null);var s=(e=e||{}).random||(e.rng||o)();if(s[6]=15&s[6]|64,s[8]=63&s[8]|128,t)for(var a=0;a<16;++a)t[i+a]=s[a];return t||r(s)}},function(e,t){var n="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof window.msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto);if(n){var o=new Uint8Array(16);e.exports=function(){return n(o),o}}else{var r=new Array(16);e.exports=function(){for(var e,t=0;t<16;t++)0==(3&t)&&(e=4294967296*Math.random()),r[t]=e>>>((3&t)<<3)&255;return r}}},function(e,t){for(var n=[],o=0;o<256;++o)n[o]=(o+256).toString(16).substr(1);e.exports=function(e,t){var o=t||0,r=n;return[r[e[o++]],r[e[o++]],r[e[o++]],r[e[o++]],"-",r[e[o++]],r[e[o++]],"-",r[e[o++]],r[e[o++]],"-",r[e[o++]],r[e[o++]],"-",r[e[o++]],r[e[o++]],r[e[o++]],r[e[o++]],r[e[o++]],r[e[o++]]].join("")}},function(e,t,n){let{config:o,updateConfig:r}=n(0),i=0,s=1,a=2;e.exports=class{constructor(){this.resendQueue=[]}start(e){this.impressionId=e,this.resendInterval=setInterval(()=>{this._resendFailedData.call(this)},o.resendInterval)}stop(){clearInterval(this.resendInterval)}upload(e){return new Promise((t,n)=>{let o=JSON.stringify(e);this._upload(o).then(e=>{if(200!=e.status)throw new Error("Response status code is not 200.");e.json().then(e=>{if("ok"!==e.status)throw new Error("Response object status is not ok.");"config"==e.msg&&(r(e.data)||t({status:-1,msg:"Data is uploaded, but errors occur when updating config."})),t({status:0})})}).catch(n=>{this._appendFailedData(e),t({status:-1,msg:`Fail to upload a bunch of data: ${n.message}`})})})}setImpressionId(e){this.impressionId=e}_resendFailedData(){let e=0,t=this.resendQueue[e];for(;e<this.resendQueue.length;)t.status==a?this.resendQueue.splice(e,1):(e+=1,t.status==i&&(t.status=s,this.upload(t.data).then(e=>{t.status=e?a:i})))}_upload(e){return o.enableGet?fetch(`${o.absoluteUrl}/api/upload-trace?websiteId=${o.websiteId}&impressionId=${this.impressionId}&data=${e}`,{method:"GET",credentials:"include"}):fetch(`${o.absoluteUrl}/api/upload-trace?websiteId=${o.websiteId}&impressionId=${this.impressionId}`,{method:"POST",credentials:"include",body:e})}_appendFailedData(e){this.resendQueue.push({status:i,data:e})}}}])}));
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.mouselog=e():t.mouselog=e()}(window,(function(){return function(t){var e={};function o(i){if(e[i])return e[i].exports;var s=e[i]={i:i,l:!1,exports:{}};return t[i].call(s.exports,s,s.exports,o),s.l=!0,s.exports}return o.m=t,o.c=e,o.d=function(t,e,i){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(o.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var s in t)o.d(i,s,function(e){return t[e]}.bind(null,s));return i},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="",o(o.s=1)}([function(t,e){t.exports={Config:class{constructor(){this.uploadEndpoint="http://localhost:9000",this.websiteId="unknown",this.endpointType="absolute",this.uploadMode="mixed",this.uploadPeriod=5e3,this.frequency=50,this.enableGet=!1,this.resendInterval=3e3,this._requiredParams=["uploadEndpoint"]}build(t){try{this._requiredParams.forEach(e=>{if(!t.hasOwnProperty(e))throw new Error(`Param ${e} is required but not declared.`)}),Object.keys(t).forEach(e=>{this[e]&&!e.startsWith("_")&&"function"!=typeof this[e]&&(this[e]=t[e])}),this.absoluteUrl=this._formatUrl()}catch(t){return console.log(t),!1}return!0}update(t){return this.build(t)}_formatUrl(){let t=this.uploadEndpoint;if("relative"==this.endpointType)t.startsWith("./")?t=t.slice(1):"/"!==t[0]&&(t="/"+t),"/"===t[t.length-1]&&(t=t.slice(0,t.length-1)),t=`${window.location.origin}${t}`;else if("absolute"!==this.endpointType)throw new Error('`endpointType` can only be "absolute" or "relative"');return t}}}},function(t,e,o){const i=o(2),s=o(5);let{Config:n}=o(0),r=["mousemove","mousedown","mouseup","mouseclick","dblclick","contextmenu","wheel","torchstart","touchmove","touchend"],a=new Date;function l(){let t=new Date-a;return Math.trunc(t)/1e3}function u(t){return"2"===t?"Right":""}t.exports={Mouselog:class{constructor(){this.config=new n,this.impressionId=i(),this.mouselogLoadTime=new Date,this.uploader=new s,this.eventsList=[],this.uploadInterval,this.uploadTimeout}_clearBuffer(){this.eventsList=[]}_newTrace(){let t={id:"0",idx:this.uploadIdx,url:window.location.hostname?window.location.hostname:"localhost",path:window.location.pathname,width:document.body.scrollWidth,height:document.body.scrollHeight,pageLoadTime:a,label:-1,guess:-1,events:[]};return this.uploadIdx+=1,t}_mouseHandler(t){if("contextmenu"===t.type&&0===t.pageX&&0===t.pageY)return;let e=t.pageX,o=t.pageY;void 0===e&&(e=t.changedTouches[0].pageX,o=t.changedTouches[0].pageY);let i={id:this.eventsList.length,timestamp:l(),type:t.type,x:e,y:o,button:u(t.button)};"wheel"==t.type&&(i.deltaX=t.deltaX,i.deltaY=t.deltaY),this.eventsList.push(i),"event-triggered"==this.config.uploadMode&&this.eventsList.length%this.config.frequency==0&&this._uploadTrace(),"mixed"==this.config.uploadMode&&this.eventsList.length%this.config.frequency==0&&(this._periodUploadTimeout(),this._uploadTrace())}_fetchConfigFromServer(){let t=this._newTrace();return this.uploader.upload(t)}_uploadTrace(){let t=this._newTrace();return t.events=this.eventsList,this.eventsList=[],this.uploader.upload(t)}_periodUploadTimeout(){clearTimeout(this.uploadTimeout),this.uploadTimeout=setTimeout(()=>{this.eventsList.length>0&&this._uploadTrace()})}_periodUploadInterval(){clearInterval(this.uploadInterval),this.uploadInterval=setInterval(()=>{this.eventsList.length>0&&this._uploadTrace()},this.config.uploadPeriod)}_runCollector(){r.forEach(t=>{window.document.addEventListener(t,t=>this._mouseHandler(t))}),"periodic"===this.config.uploadMode&&this._periodUploadInterval(),"mixed"===this.config.uploadMode&&this._periodUploadTimeout()}_stopCollector(){r.forEach(t=>{window.document.removeEventListener(t,t=>this._mouseHandler(t))}),clearInterval(this.uploadInterval),clearTimeout(this.uploadTimeout)}_resetCollector(){this._stopCollector(),this._runCollector()}_init(t){return this.impressionId=i(),this._clearBuffer(),this.uploadIdx=0,this.uploader=new s(this.impressionId,this.config),this.uploader.setImpressionId(this.impressionId),this.config.build(t)?(this._fetchConfigFromServer().then(t=>{if(1!=t.status)throw new Error("Fail to get config from server.");if(!this.config.update(t.config))throw new Error("Unable to update config with server config.");this._resetCollector(),this.uploader.setConfig(this.config),console.log("Config updated.")}).catch(t=>{console.log(t)}),window.onbeforeunload=t=>{0!=this.eventsList.length&&this._uploadTrace()},{status:0}):{status:-1,msg:"Invalid configuration."}}run(t){let e=this._init(t);0==e.status?(this._runCollector(),this.uploader.start(this.impressionId),console.log("Mouselog agent is activated!")):(console.log(e.msg),console.log("Fail to initialize Mouselog agent."))}stop(){this.uploader.stop(),this._stopCollector(),this._clearBuffer(),console.log(`Mouselog agent ${this.impressionId} is stopped!`)}}}},function(t,e,o){var i=o(3),s=o(4);t.exports=function(t,e,o){var n=e&&o||0;"string"==typeof t&&(e="binary"===t?new Array(16):null,t=null);var r=(t=t||{}).random||(t.rng||i)();if(r[6]=15&r[6]|64,r[8]=63&r[8]|128,e)for(var a=0;a<16;++a)e[n+a]=r[a];return e||s(r)}},function(t,e){var o="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof window.msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto);if(o){var i=new Uint8Array(16);t.exports=function(){return o(i),i}}else{var s=new Array(16);t.exports=function(){for(var t,e=0;e<16;e++)0==(3&e)&&(t=4294967296*Math.random()),s[e]=t>>>((3&e)<<3)&255;return s}}},function(t,e){for(var o=[],i=0;i<256;++i)o[i]=(i+256).toString(16).substr(1);t.exports=function(t,e){var i=e||0,s=o;return[s[t[i++]],s[t[i++]],s[t[i++]],s[t[i++]],"-",s[t[i++]],s[t[i++]],"-",s[t[i++]],s[t[i++]],"-",s[t[i++]],s[t[i++]],"-",s[t[i++]],s[t[i++]],s[t[i++]],s[t[i++]],s[t[i++]],s[t[i++]]].join("")}},function(t,e,o){let{config:i,updateConfig:s}=o(0),n=0,r=1,a=2;t.exports=class{constructor(t,e){this.impressionId=t,this.config=e,this.resendQueue=[]}start(){this.resendInterval=setInterval(()=>{this._resendFailedData.call(this)},this.config.resendInterval)}stop(){clearInterval(this.resendInterval)}upload(t){return new Promise((e,o)=>{let i=JSON.stringify(t);this._upload(i).then(t=>{if(200!=t.status)throw new Error("Response status code is not 200.");t.json().then(t=>{if("ok"!==t.status)throw new Error("Response object status is not ok.");"config"==t.msg&&e({status:1,msg:"Get config from server",config:t.data}),e({status:0})})}).catch(o=>{this._appendFailedData(t),e({status:-1,msg:`Fail to upload a bunch of data, ${o.message}`})})})}setImpressionId(t){this.impressionId=t}setConfig(t){this.stop(),this.config=t,this.start()}_resendFailedData(){let t=0,e=this.resendQueue[t];for(;t<this.resendQueue.length;)e.status==a?this.resendQueue.splice(t,1):(t+=1,e.status==n&&(e.status=r,this.upload(e.data).then(t=>{e.status=t?a:n})))}_upload(t){return this.config.enableGet?fetch(`${this.config.absoluteUrl}/api/upload-trace?websiteId=${this.config.websiteId}&impressionId=${this.impressionId}&data=${t}`,{method:"GET",credentials:"include"}):fetch(`${this.config.absoluteUrl}/api/upload-trace?websiteId=${this.config.websiteId}&impressionId=${this.impressionId}`,{method:"POST",credentials:"include",body:t})}_appendFailedData(t){this.resendQueue.push({status:n,data:t})}}}])}));

@@ -0,87 +1,89 @@

class Config {
// Set up a default config
constructor() {
// Type: string, REQUIRED
// Endpoint Url
this.uploadEndpoint = "http://localhost:9000";
// Type: string
// Website ID
this.websiteId = "unknown";
// Default config
let config = {
// Type: string, REQUIRED
// Endpoint Url
uploadEndpoint: "http://localhost:9000",
// Endpoint type, "absolute" or "relative"
this.endpointType = "absolute";
// Type: string
// Website ID
websiteId: "unknown",
// Upload mode, "mixed", "periodic" or "event-triggered"
this.uploadMode = "mixed";
// Endpoint type, "absolute" or "relative"
endpointType: "absolute",
// Type: number
// If `uploadMode` is "mixed", "periodic", data will be uploaded every `uploadPeriod` ms.
// If no data are collected in a period, no data will be uploaded
this.uploadPeriod = 5000;
// Upload mode, "mixed", "periodic" or "event-triggered"
uploadMode: "mixed",
// Type: number
// If `uploadMode` == "event-triggered"
// The website interaction data will be uploaded when every `frequency` events are captured.
this.frequency = 50;
// Type: number
// If `uploadMode` is "mixed", "periodic", data will be uploaded every `uploadPeriod` ms.
// If no data are collected in a period, no data will be uploaded
uploadPeriod: 5000,
// Type: bool
// Use GET method to upload data? (stringified data will be embedded in URI)
this.enableGet = false;
// Type: number
// If `uploadMode` == "event-triggered"
// The website interaction data will be uploaded when every `frequency` events are captured.
frequency: 50,
// Type: number
// Time interval for resending the failed trace data
this.resendInterval = 3000;
// Type: bool
// Use GET method to upload data? (stringified data will be embedded in URI)
enableGet: false,
this._requiredParams = [
"uploadEndpoint",
]
}
// Type: number
// Time interval for resending the failed trace data
resendInterval: 3000,
}
build(config) {
try {
this._requiredParams.forEach(key => {
if (!config.hasOwnProperty(key)) {
throw new Error(`Param ${key} is required but not declared.`);
}
});
// Overwrite the default config
Object.keys(config).forEach( key => {
// Overwriting Class private members / function method is not allowed
if (this[key] && !key.startsWith("_") && typeof(this[key]) != "function") {
this[key] = config[key]
}
})
// ----------------------------
this.absoluteUrl = this._formatUrl();
} catch(err) {
console.log(err);
return false;
}
return true;
}
let requiredParams = [
"uploadEndpoint",
];
update(config) {
return this.build(config);
}
// Returns a boolean indicating if config is built successfully
let buildConfig = (params) => {
try {
requiredParams.forEach(key => {
if (!(params.hasOwnProperty(key))) {
throw new Error(`Param ${key} is required but not declared.`);
_formatUrl() {
let url = this.uploadEndpoint;
if (this.endpointType == "relative") {
if (url.startsWith("./")) {
url = url.slice(1);
} else if (url[0] !== "/") {
url = "/" + url;
}
});
config = Object.assign(config, params);
config.absoluteUrl = formatUrl();
} catch(err) {
console.log(err);
return false;
}
return true;
}
let updateConfig = (params) => {
// Generate new config
return buildConfig(params);
}
let formatUrl = () => {
let url = config.uploadEndpoint
if (config.endpointType == "relative") {
// Format the head (the path should start with '/')
if (url.startsWith("./")) {
url = url.slice(1);
} else if (url[0] !== "/") {
url = "/" + url;
// Format the tail
if (url[url.length-1] === "/") {
url = url.slice(0, url.length-1);
}
// Construct absolute URL
url = `${window.location.origin}${url}`
} else if (this.endpointType !== "absolute") {
throw new Error('`endpointType` can only be "absolute" or "relative"');
}
// Format the tail
if (url[url.length-1] === "/") {
url = url.slice(0, url.length-1);
}
// Construct absolute URL
url = `${window.location.origin}${url}`
} else if (config.endpointType !== "absolute") {
throw new Error('`endpointType` can only be "absolute" or "relative"');
return url;
}
return url;
}
module.exports = { config, buildConfig, updateConfig }
module.exports = { Config };
const uuidv4 = require('uuid/v4');
const Uploader = require('./uploader');
let { config, buildConfig } = require('./config');
let { Config } = require('./config');
let targetEvents = [

@@ -18,180 +17,199 @@ "mousemove",

];
let pageLoadTime = new Date();
let uploader;
let impressionId;
let eventsList;
let pageLoadTime;
let uploadIdx;
let uploadInterval; // For "periodic" upload mode
let uploadTimeout; // For "mixed" upload mode
function getRelativeTimestampInSeconds() {
let diff = new Date() - pageLoadTime;
return Math.trunc(diff) / 1000;
}
class Mouselog{
constructor() {
this.config = new Config();
this.impressionId = uuidv4();
this.mouselogLoadTime = new Date();
this.uploader = new Uploader();
this.eventsList = [];
this.uploadInterval; // For "periodic" upload mode
this.uploadTimeout; // For "mixed" upload mode
}
function getButton(btn) {
if (btn === '2') {
return 'Right';
} else {
return ""
_clearBuffer() {
this.eventsList = [];
}
}
function newTrace() {
let trace = {
id: '0',
idx: uploadIdx,
url: window.location.hostname ? window.location.hostname : "localhost",
path: window.location.pathname,
width: document.body.scrollWidth,
height: document.body.scrollHeight,
pageLoadTime: pageLoadTime,
label: -1,
guess: -1,
events: []
}
uploadIdx += 1;
return trace;
}
_newTrace() {
let trace = {
id: '0',
idx: this.uploadIdx,
url: window.location.hostname ? window.location.hostname : "localhost",
path: window.location.pathname,
width: document.body.scrollWidth,
height: document.body.scrollHeight,
pageLoadTime: pageLoadTime,
label: -1,
guess: -1,
events: []
}
this.uploadIdx += 1;
return trace;
}
function uploadTrace() {
let trace = newTrace();
trace.events = eventsList;
eventsList = [];
return uploader.upload(trace); // This is a promise
}
_mouseHandler(evt) {
// PC's Chrome on Mobile mode can still receive "contextmenu" event with zero X, Y, so we ignore these events.
if (evt.type === 'contextmenu' && evt.pageX === 0 && evt.pageY === 0) {
return;
}
let x = evt.pageX;
let y = evt.pageY;
if (x === undefined) {
x = evt.changedTouches[0].pageX;
y = evt.changedTouches[0].pageY;
}
let tmpEvt = {
// TODO: Is `id` be used to order the event by timestamp?
id: this.eventsList.length,
timestamp: getRelativeTimestampInSeconds(),
type: evt.type,
x: x,
y: y,
button: getButton(evt.button)
}
function periodUploadTimeout() {
clearTimeout(uploadTimeout);
uploadTimeout = setTimeout(() => {
if (eventsList.length > 0) {
uploadTrace();
if (evt.type == "wheel") {
tmpEvt.deltaX = evt.deltaX;
tmpEvt.deltaY = evt.deltaY;
}
}, config.uploadPeriod);
}
this.eventsList.push(tmpEvt);
function periodUploadInterval() {
clearInterval(uploadInterval);
uploadInterval = setInterval(() => {
if (eventsList.length != 0) {
uploadTrace();
if ( this.config.uploadMode == "event-triggered" && this.eventsList.length % this.config.frequency == 0 ) {
this._uploadTrace();
}
}, config.uploadPeriod);
}
function mouseHandler(evt) {
// PC's Chrome on Mobile mode can still receive "contextmenu" event with zero X, Y, so we ignore these events.
if (evt.type === 'contextmenu' && evt.pageX === 0 && evt.pageY === 0) {
return;
if ( this.config.uploadMode == "mixed" && this.eventsList.length % this.config.frequency == 0) {
this._periodUploadTimeout();
this._uploadTrace();
}
}
let x = evt.pageX;
let y = evt.pageY;
if (x === undefined) {
x = evt.changedTouches[0].pageX;
y = evt.changedTouches[0].pageY;
_fetchConfigFromServer() {
// Upload an empty trace to fetch config from server
let trace = this._newTrace();
return this.uploader.upload(trace); // This is a promise
}
let tmpEvt = {
id: eventsList.length,
timestamp: getRelativeTimestampInSeconds(),
type: evt.type,
x: x,
y: y,
button: getButton(evt.button)
_uploadTrace() {
let trace = this._newTrace();
trace.events = this.eventsList;
this.eventsList = [];
return this.uploader.upload(trace); // This is a promise
}
if (evt.type == "wheel") {
tmpEvt.deltaX = evt.deltaX;
tmpEvt.deltaY = evt.deltaY;
_periodUploadTimeout() {
clearTimeout(this.uploadTimeout);
this.uploadTimeout = setTimeout(() => {
if (this.eventsList.length > 0) {
this._uploadTrace();
}
})
}
eventsList.push(tmpEvt);
if ( config.uploadMode == "event-triggered" && eventsList.length % config.frequency == 0 ) {
uploadTrace();
_periodUploadInterval() {
clearInterval(this.uploadInterval);
this.uploadInterval = setInterval(() => {
if (this.eventsList.length > 0) {
this._uploadTrace();
}
}, this.config.uploadPeriod);
}
if ( config.uploadMode == "mixed" && eventsList.length % config.frequency == 0) {
periodUploadTimeout();
uploadTrace();
_runCollector() {
targetEvents.forEach( s => {
window.document.addEventListener(s, (evt) => this._mouseHandler(evt));
});
if (this.config.uploadMode === "periodic") {
this._periodUploadInterval();
}
if (this.config.uploadMode === "mixed") {
this._periodUploadTimeout();
}
}
}
function clearBuffer() {
eventsList = [];
}
_stopCollector() {
targetEvents.forEach( s => {
window.document.removeEventListener(s, (evt) => this._mouseHandler(evt));
});
clearInterval(this.uploadInterval);
clearTimeout(this.uploadTimeout);
}
// Initialize the mouselog
function init(params) {
clearBuffer();
pageLoadTime = new Date();
uploadIdx = 0;
uploader = new Uploader();
impressionId = uuidv4();
uploader.setImpressionId(impressionId);
if (buildConfig(params)) {
// Async: Upload an empty data to ofetch config from backend
uploadTrace().then( result => {
if (result.status === 0) { // Config is updated successfully
resetCollector();
} else {
console.log(result.msg);
console.log("Fail to overwrite config with server config.")
_resetCollector() {
this._stopCollector();
this._runCollector();
}
_init(config) {
this.impressionId = uuidv4();
this._clearBuffer();
this.uploadIdx = 0;
this.uploader = new Uploader(this.impressionId, this.config);
this.uploader.setImpressionId(this.impressionId);
if (this.config.build(config)) {
// Async: Upload an empty data to fetch config from server
this._fetchConfigFromServer().then( result => {
if (result.status == 1) {
if (this.config.update(result.config)) {
this._resetCollector();
this.uploader.setConfig(this.config);
console.log("Config updated.")
} else {
throw new Error(`Unable to update config with server config.`);
}
} else {
throw new Error(`Fail to get config from server.`);
}
}).catch(err => {
console.log(err);
});
window.onbeforeunload = (evt) => {
if (this.eventsList.length != 0) {
this._uploadTrace();
}
}
});
onbeforeunload = (evt) => {
if (eventsList.length != 0) {
uploadTrace();
}
return {status: 0};
} else {
return {status: -1, msg: `Invalid configuration.`};
}
return {status: 0, msg: `Invalid configuration.`};
} else {
return {status: -1, msg: `Invalid configuration.`}
}
}
function runCollector() {
targetEvents.forEach( s => {
window.document.addEventListener(s, (evt) => mouseHandler(evt));
});
run(config) {
let res = this._init(config);
if (res.status == 0) {
this._runCollector();
this.uploader.start(this.impressionId);
console.log("Mouselog agent is activated!");
} else {
console.log(res.msg);
console.log("Fail to initialize Mouselog agent.");
}
}
if (config.uploadMode === "periodic") {
periodUploadInterval();
}
if (config.uploadMode == "mixed") {
periodUploadTimeout();
stop() {
this.uploader.stop();
this._stopCollector();
this._clearBuffer();
console.log(`Mouselog agent ${this.impressionId} is stopped!`);
}
}
function stopCollector() {
targetEvents.forEach( s => {
window.document.removeEventListener(s, (evt) => mouseHandler(evt));
});
clearInterval(uploadInterval);
clearTimeout(uploadTimeout);
function getRelativeTimestampInSeconds() {
let diff = new Date() - pageLoadTime;
return Math.trunc(diff) / 1000;
}
function resetCollector(removeData = false) {
stopCollector();
runCollector();
}
export function run(params) {
let res = init(params);
if (res.status == 0) {
runCollector();
uploader.start(impressionId);
console.log("Mouselog agent is activated!");
function getButton(btn) {
if (btn === '2') {
return 'Right';
} else {
console.log(res.msg);
console.log("Fail to initialize Mouselog agent.");
return ""
}
}
export function stop() {
uploader.stop();
stopCollector();
clearBuffer();
console.log("Mouselog agent is stopped!");
}
module.exports = { Mouselog };
{
"name": "mouselog",
"version": "0.0.9-beta1",
"version": "0.0.9-beta2",
"description": "The mouse tracking agent for Mouselog.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -15,3 +15,4 @@ [![NPM version](https://img.shields.io/npm/v/mouselog)](https://www.npmjs.com/package/mouselog)

<script>
mouselog.run({
var agent = new mouselog.Mouselog();
agent.run({
uploadEndpoint: "Your_Server_Url",

@@ -29,3 +30,4 @@ websiteId: "Your_Website_Id",

script.onload = () => {
mouselog.run({
var agent = new mouselog.Mouselog();
agent.run({
uploadEndpoint: "Your_Server_Url",

@@ -57,4 +59,5 @@ websiteId: "Your_Website_Id",

```Javascript
const mouselog = require('mouselog');
mouselog.run({
const { Mouselog } = require('mouselog');
let agent = new Mouselog();
agent.run({
uploadEndpoint: "Your_Server_Url",

@@ -65,3 +68,3 @@ websiteId: "Your_Website_Id",

```
You can also deactivate Mouselog by calling `mouselog.stop()`.
You can also deactivate Mouselog by calling `agent.stop()`.

@@ -68,0 +71,0 @@

@@ -10,11 +10,12 @@ let {config, updateConfig} = require('./config');

class Uploader {
constructor() {
constructor(impressionId, config) {
this.impressionId = impressionId;
this.config = config;
this.resendQueue = [];
}
start(impressionId) {
this.impressionId = impressionId;
start() {
this.resendInterval = setInterval(()=>{
this._resendFailedData.call(this);
}, config.resendInterval);
}, this.config.resendInterval);
}

@@ -28,3 +29,3 @@

upload(data) {
// resolve(true/false): uploaded success/fail.
// resolve({status:-1/0/1, ...}): uploading success/fail.
// reject(ErrorMessage): Errors occur when updating the config.

@@ -40,5 +41,7 @@ return new Promise( (resolve, reject) => {

if (resObj.msg == "config") {
if (!updateConfig(resObj.data)) {
resolve({status: -1, msg: `Data is uploaded, but errors occur when updating config.`});
};
resolve({
status: 1,
msg: `Get config from server`,
config: resObj.data
});
}

@@ -52,3 +55,6 @@ resolve({status: 0});

this._appendFailedData(data);
resolve({status: -1, msg: `Fail to upload a bunch of data: ${err.message}`});
resolve({
status: -1,
msg: `Fail to upload a bunch of data, ${err.message}`
});
})

@@ -62,2 +68,8 @@ });

setConfig(config) {
this.stop();
this.config = config;
this.start();
}
_resendFailedData() {

@@ -86,4 +98,4 @@ let i = 0;

_upload(encodedData) {
if (config.enableGet) {
return fetch(`${config.absoluteUrl}/api/upload-trace?websiteId=${config.websiteId}&impressionId=${this.impressionId}&data=${encodedData}`, {
if (this.config.enableGet) {
return fetch(`${this.config.absoluteUrl}/api/upload-trace?websiteId=${this.config.websiteId}&impressionId=${this.impressionId}&data=${encodedData}`, {
method: "GET",

@@ -93,3 +105,3 @@ credentials: "include"

} else {
return fetch(`${config.absoluteUrl}/api/upload-trace?websiteId=${config.websiteId}&impressionId=${this.impressionId}`, {
return fetch(`${this.config.absoluteUrl}/api/upload-trace?websiteId=${this.config.websiteId}&impressionId=${this.impressionId}`, {
method: "POST",

@@ -96,0 +108,0 @@ credentials: "include",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc