@openreplay/tracker-assist
Advanced tools
Comparing version 3.4.16 to 3.5.0
@@ -0,4 +1,18 @@ | ||
import type { Properties } from 'csstype'; | ||
declare type ButtonOptions = HTMLButtonElement | string | { | ||
innerHTML: string; | ||
style?: Properties; | ||
}; | ||
interface ConfirmWindowOptions { | ||
text: string; | ||
style?: Properties; | ||
confirmBtn: ButtonOptions; | ||
declineBtn: ButtonOptions; | ||
} | ||
export declare type Options = string | Partial<ConfirmWindowOptions>; | ||
export declare const callConfirmDefault: (opts: Options) => ConfirmWindowOptions; | ||
export declare const controlConfirmDefault: (opts: Options) => ConfirmWindowOptions; | ||
export default class ConfirmWindow { | ||
private wrapper; | ||
constructor(text: string, styles?: Object); | ||
constructor(options: ConfirmWindowOptions); | ||
private resolve; | ||
@@ -10,1 +24,2 @@ private reject; | ||
} | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const declineIcon = `<svg xmlns="http://www.w3.org/2000/svg" height="22" width="22" viewBox="0 0 128 128" ><g id="Circle_Grid" data-name="Circle Grid"><circle cx="64" cy="64" fill="#ef5261" r="64"/></g><g id="icon"><path d="m57.831 70.1c8.79 8.79 17.405 12.356 20.508 9.253l4.261-4.26a7.516 7.516 0 0 1 10.629 0l9.566 9.566a7.516 7.516 0 0 1 0 10.629l-7.453 7.453c-7.042 7.042-27.87-2.358-47.832-22.319-9.976-9.981-16.519-19.382-20.748-28.222s-5.086-16.091-1.567-19.61l7.453-7.453a7.516 7.516 0 0 1 10.629 0l9.566 9.563a7.516 7.516 0 0 1 0 10.629l-4.264 4.271c-3.103 3.1.462 11.714 9.252 20.5z" fill="#eeefee"/></g></svg>`; | ||
exports.controlConfirmDefault = exports.callConfirmDefault = void 0; | ||
const icons_js_1 = require("./icons.js"); | ||
function confirmDefault(opts, confirmBtn, declineBtn, text) { | ||
const isStr = typeof opts === "string"; | ||
return Object.assign({ | ||
text: isStr ? opts : text, | ||
confirmBtn, | ||
declineBtn, | ||
}, isStr ? undefined : opts); | ||
} | ||
const callConfirmDefault = (opts) => confirmDefault(opts, icons_js_1.acceptCall, icons_js_1.declineCall, "You have an incoming call. Do you want to answer?"); | ||
exports.callConfirmDefault = callConfirmDefault; | ||
const controlConfirmDefault = (opts) => confirmDefault(opts, icons_js_1.remoteControl, icons_js_1.cross, "Allow remote control?"); | ||
exports.controlConfirmDefault = controlConfirmDefault; | ||
function makeButton(options) { | ||
if (options instanceof HTMLButtonElement) { | ||
return options; | ||
} | ||
const btn = document.createElement('button'); | ||
Object.assign(btn.style, { | ||
background: "transparent", | ||
padding: 0, | ||
margin: 0, | ||
border: 0, | ||
cursor: "pointer", | ||
borderRadius: "50%", | ||
width: "22px", | ||
height: "22px", | ||
color: "white", // TODO: nice text button in case when only text is passed | ||
}); | ||
if (typeof options === "string") { | ||
btn.innerHTML = options; | ||
} | ||
else { | ||
btn.innerHTML = options.innerHTML; | ||
Object.assign(btn.style, options.style); | ||
} | ||
return btn; | ||
} | ||
class ConfirmWindow { | ||
constructor(text, styles) { | ||
constructor(options) { | ||
this.resolve = () => { }; | ||
@@ -11,24 +49,10 @@ this.reject = () => { }; | ||
const p = document.createElement('p'); | ||
p.innerText = text; | ||
p.innerText = options.text; | ||
const buttons = document.createElement('div'); | ||
const answerBtn = document.createElement('button'); | ||
answerBtn.innerHTML = declineIcon.replace('fill="#ef5261"', 'fill="green"'); | ||
const declineBtn = document.createElement('button'); | ||
declineBtn.innerHTML = declineIcon; | ||
buttons.appendChild(answerBtn); | ||
const confirmBtn = makeButton(options.confirmBtn); | ||
const declineBtn = makeButton(options.declineBtn); | ||
buttons.appendChild(confirmBtn); | ||
buttons.appendChild(declineBtn); | ||
popup.appendChild(p); | ||
popup.appendChild(buttons); | ||
const btnStyles = { | ||
borderRadius: "50%", | ||
width: "22px", | ||
height: "22px", | ||
background: "transparent", | ||
padding: 0, | ||
margin: 0, | ||
border: 0, | ||
cursor: "pointer", | ||
}; | ||
Object.assign(answerBtn.style, btnStyles); | ||
Object.assign(declineBtn.style, btnStyles); | ||
Object.assign(buttons.style, { | ||
@@ -53,3 +77,3 @@ marginTop: "10px", | ||
boxShadow: "0 0 20px rgb(0 0 0 / 20%)", | ||
}, styles); | ||
}, options.style); | ||
Object.assign(wrapper.style, { | ||
@@ -66,3 +90,3 @@ position: "fixed", | ||
this.wrapper = wrapper; | ||
answerBtn.onclick = () => { | ||
confirmBtn.onclick = () => { | ||
this._remove(); | ||
@@ -69,0 +93,0 @@ this.resolve(true); |
import './_slim.js'; | ||
import { App } from '@openreplay/tracker/cjs'; | ||
export interface Options { | ||
onAgentConnect: () => ((() => {}) | void); | ||
onCallStart: () => ((() => {}) | void); | ||
confirmText: string; | ||
confirmStyle: Object; | ||
session_calling_peer_key: string; | ||
config: RTCConfiguration; | ||
} | ||
import type { App } from '@openreplay/tracker/cjs'; | ||
import type { Options } from './Assist.js'; | ||
import Assist from './Assist.js'; | ||
export default function (opts?: Partial<Options>): (app: App | null, appOptions?: { | ||
__debug_log?: boolean; | ||
__DISABLE_SECURE_MODE?: boolean; | ||
}) => void; | ||
}) => Assist | undefined; |
225
cjs/index.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
require("./_slim.js"); | ||
const peerjs_1 = require("peerjs"); | ||
const BufferingConnection_js_1 = require("./BufferingConnection.js"); | ||
const Mouse_js_1 = require("./Mouse.js"); | ||
const CallWindow_js_1 = require("./CallWindow.js"); | ||
const ConfirmWindow_js_1 = require("./ConfirmWindow.js"); | ||
const LocalStream_js_1 = require("./LocalStream.js"); | ||
var CallingState; | ||
(function (CallingState) { | ||
CallingState[CallingState["Requesting"] = 0] = "Requesting"; | ||
CallingState[CallingState["True"] = 1] = "True"; | ||
CallingState[CallingState["False"] = 2] = "False"; | ||
})(CallingState || (CallingState = {})); | ||
; | ||
//@ts-ignore peerjs hack for webpack5 (?!) TODO: ES/node modules; | ||
peerjs_1.default = peerjs_1.default.default || peerjs_1.default; | ||
// type IncomeMessages = | ||
// "call_end" | | ||
// { type: "agent_name", name: string } | | ||
// { type: "click", x: number, y: number } | | ||
// { x: number, y: number } | ||
const Assist_js_1 = require("./Assist.js"); | ||
function default_1(opts) { | ||
const options = Object.assign({ | ||
confirmText: "You have an incoming call. Do you want to answer?", | ||
confirmStyle: {}, | ||
session_calling_peer_key: "__openreplay_calling_peer", | ||
config: null, | ||
onCallStart: () => { }, | ||
onAgentConnect: () => { }, | ||
}, opts); | ||
return function (app, appOptions = {}) { | ||
@@ -39,194 +12,12 @@ var _a; | ||
} | ||
function log(...args) { | ||
// TODO: use centralised warn/log from tracker (?) | ||
appOptions.__debug_log && console.log("OpenReplay Assist. ", ...args); | ||
if (!app.checkRequiredVersion || !app.checkRequiredVersion("3.5.0")) { | ||
console.warn("OpenReplay Assist: couldn't load. The minimum required version of @openreplay/tracker/cjs@3.5.0 is not met"); | ||
return; | ||
} | ||
function warn(...args) { | ||
appOptions.__debug_log && console.warn("OpenReplay Assist. ", ...args); | ||
} | ||
let assistDemandedRestart = false; | ||
let peer = null; | ||
// This is required because internal peerjs connection list is not stable. https://peerjs.com/docs.html#peerconnections | ||
const openDataConnections = {}; | ||
app.addCommitCallback(function (messages) { | ||
Object.values(openDataConnections).forEach(buffConn => buffConn.send(messages)); | ||
}); | ||
app.attachStopCallback(function () { | ||
if (assistDemandedRestart) { | ||
return; | ||
} | ||
if (peer) { | ||
peer.destroy(); | ||
log('Peer destroyed!'); | ||
} | ||
}); | ||
app.attachStartCallback(function () { | ||
if (assistDemandedRestart) { | ||
return; | ||
} | ||
const peerID = `${app.getProjectKey()}-${app.getSessionID()}`; | ||
const _opt = { | ||
// @ts-ignore | ||
host: app.getHost(), | ||
path: '/assist', | ||
port: location.protocol === 'http:' && appOptions.__DISABLE_SECURE_MODE ? 80 : 443, | ||
debug: appOptions.__debug_log ? 2 : 0, // 0 Print nothing //1 Prints only errors. / 2 Prints errors and warnings. / 3 Prints all logs. | ||
}; | ||
if (options.config) { | ||
_opt['config'] = options.config; | ||
} | ||
peer = new peerjs_1.default(peerID, _opt); | ||
log('Peer created: ', peer); | ||
peer.on('error', e => warn("Peer error: ", e.type, e)); | ||
peer.on('connection', function (conn) { | ||
window.addEventListener("beforeunload", () => conn.open && conn.send("unload")); | ||
log('Connecting...'); | ||
conn.on('open', function () { | ||
log('Connection opened.'); | ||
assistDemandedRestart = true; | ||
app.stop(); | ||
openDataConnections[conn.peer] = new BufferingConnection_js_1.default(conn); | ||
const onAgentDisconnect = options.onAgentConnect(); | ||
conn.on('close', () => { | ||
onAgentDisconnect && onAgentDisconnect(); | ||
log("Connection close: ", conn.peer); | ||
delete openDataConnections[conn.peer]; // TODO: check if works properly | ||
}); | ||
app.start().then(() => { assistDemandedRestart = false; }); | ||
}); | ||
}); | ||
let callingState = CallingState.False; | ||
peer.on('call', function (call) { | ||
var _a; | ||
log("Call: ", call); | ||
if (!peer) { | ||
return; | ||
} | ||
const dataConn = (_a = openDataConnections[call.peer]) === null || _a === void 0 ? void 0 : _a.conn; | ||
if (callingState !== CallingState.False || !dataConn || !dataConn.open) { | ||
call.close(); | ||
warn("Call closed instantly: ", callingState, dataConn, dataConn.open); | ||
return; | ||
} | ||
function setCallingState(newState) { | ||
if (newState === CallingState.True) { | ||
sessionStorage.setItem(options.session_calling_peer_key, call.peer); | ||
} | ||
else if (newState === CallingState.False) { | ||
sessionStorage.removeItem(options.session_calling_peer_key); | ||
} | ||
callingState = newState; | ||
} | ||
const notifyCallEnd = () => { | ||
dataConn.open && dataConn.send("call_end"); | ||
}; | ||
let confirmAnswer; | ||
const callingPeer = sessionStorage.getItem(options.session_calling_peer_key); | ||
if (callingPeer === call.peer) { | ||
confirmAnswer = Promise.resolve(true); | ||
} | ||
else { | ||
setCallingState(CallingState.Requesting); | ||
const confirm = new ConfirmWindow_js_1.default(options.confirmText, options.confirmStyle); | ||
confirmAnswer = confirm.mount(); | ||
dataConn.on('data', (data) => { | ||
if (data === "call_end") { | ||
log("Received call_end during confirm window opened"); | ||
confirm.remove(); | ||
setCallingState(CallingState.False); | ||
} | ||
}); | ||
} | ||
confirmAnswer.then(agreed => { | ||
if (!agreed || !dataConn.open) { | ||
!dataConn.open && warn("Call cancelled because data connection is closed."); | ||
call.close(); | ||
notifyCallEnd(); | ||
setCallingState(CallingState.False); | ||
return; | ||
} | ||
const onCallEnd = options.onCallStart(); | ||
const mouse = new Mouse_js_1.default(); | ||
let callUI = new CallWindow_js_1.default(); | ||
const handleCallEnd = () => { | ||
onCallEnd && onCallEnd(); | ||
mouse.remove(); | ||
callUI.remove(); | ||
setCallingState(CallingState.False); | ||
}; | ||
const initiateCallEnd = () => { | ||
log("initiateCallEnd"); | ||
call.close(); | ||
notifyCallEnd(); | ||
handleCallEnd(); | ||
}; | ||
(0, LocalStream_js_1.default)().then(lStream => { | ||
dataConn.on("close", handleCallEnd); // For what case? | ||
//call.on('close', onClose); // Works from time to time (peerjs bug) | ||
const checkConnInterval = setInterval(() => { | ||
if (!dataConn.open) { | ||
initiateCallEnd(); | ||
clearInterval(checkConnInterval); | ||
} | ||
if (!call.open) { | ||
handleCallEnd(); | ||
clearInterval(checkConnInterval); | ||
} | ||
}, 3000); | ||
call.on('error', e => { | ||
warn("Call error:", e); | ||
initiateCallEnd(); | ||
}); | ||
call.on('stream', function (rStream) { | ||
callUI.setRemoteStream(rStream); | ||
const onInteraction = () => { | ||
callUI.playRemote(); | ||
document.removeEventListener("click", onInteraction); | ||
}; | ||
document.addEventListener("click", onInteraction); | ||
}); | ||
dataConn.on('data', (data) => { | ||
log("Income data: ", data); | ||
if (!data) { | ||
return; | ||
} | ||
if (data === "call_end") { | ||
return handleCallEnd(); | ||
} | ||
if (data.name === 'string') { | ||
return callUI.setAssistentName(data.name); | ||
} | ||
if (data.type === "scroll" && Array.isArray(data.delta)) { | ||
return mouse.scroll(data.delta); | ||
} | ||
if (data.type === "click" && typeof data.x === 'number' && typeof data.y === 'number') { | ||
return mouse.click([data.x, data.y]); | ||
} | ||
if (typeof data.x === 'number' && typeof data.y === 'number') { | ||
return mouse.move([data.x, data.y]); | ||
} | ||
}); | ||
lStream.onVideoTrack(vTrack => { | ||
const sender = call.peerConnection.getSenders().find(s => { var _a; return ((_a = s.track) === null || _a === void 0 ? void 0 : _a.kind) === "video"; }); | ||
if (!sender) { | ||
warn("No video sender found"); | ||
return; | ||
} | ||
log("sender found:", sender); | ||
sender.replaceTrack(vTrack); | ||
}); | ||
callUI.setCallEndAction(initiateCallEnd); | ||
callUI.setLocalStream(lStream); | ||
call.answer(lStream.stream); | ||
setCallingState(CallingState.True); | ||
}) | ||
.catch(e => { | ||
warn("Audio mediadevice request error:", e); | ||
handleCallEnd(); | ||
}); | ||
}).catch(); // in case of Confirm.remove() without any confirmation | ||
}); | ||
}); | ||
app.notify.log("OpenReplay Assist initializing."); | ||
const assist = new Assist_js_1.default(app, opts, appOptions.__DISABLE_SECURE_MODE); | ||
app.debug.log(assist); | ||
return assist; | ||
}; | ||
} | ||
exports.default = default_1; |
@@ -6,2 +6,3 @@ declare type XY = [number, number]; | ||
constructor(); | ||
mount(): void; | ||
move(pos: XY): void; | ||
@@ -8,0 +9,0 @@ getPosition(): XY; |
@@ -25,2 +25,4 @@ "use strict"; | ||
}); | ||
} | ||
mount() { | ||
document.body.appendChild(this.mouse); | ||
@@ -27,0 +29,0 @@ window.addEventListener("scroll", this.handleWScroll); |
@@ -0,4 +1,18 @@ | ||
import type { Properties } from 'csstype'; | ||
declare type ButtonOptions = HTMLButtonElement | string | { | ||
innerHTML: string; | ||
style?: Properties; | ||
}; | ||
interface ConfirmWindowOptions { | ||
text: string; | ||
style?: Properties; | ||
confirmBtn: ButtonOptions; | ||
declineBtn: ButtonOptions; | ||
} | ||
export declare type Options = string | Partial<ConfirmWindowOptions>; | ||
export declare const callConfirmDefault: (opts: Options) => ConfirmWindowOptions; | ||
export declare const controlConfirmDefault: (opts: Options) => ConfirmWindowOptions; | ||
export default class ConfirmWindow { | ||
private wrapper; | ||
constructor(text: string, styles?: Object); | ||
constructor(options: ConfirmWindowOptions); | ||
private resolve; | ||
@@ -10,1 +24,2 @@ private reject; | ||
} | ||
export {}; |
@@ -1,4 +0,39 @@ | ||
const declineIcon = `<svg xmlns="http://www.w3.org/2000/svg" height="22" width="22" viewBox="0 0 128 128" ><g id="Circle_Grid" data-name="Circle Grid"><circle cx="64" cy="64" fill="#ef5261" r="64"/></g><g id="icon"><path d="m57.831 70.1c8.79 8.79 17.405 12.356 20.508 9.253l4.261-4.26a7.516 7.516 0 0 1 10.629 0l9.566 9.566a7.516 7.516 0 0 1 0 10.629l-7.453 7.453c-7.042 7.042-27.87-2.358-47.832-22.319-9.976-9.981-16.519-19.382-20.748-28.222s-5.086-16.091-1.567-19.61l7.453-7.453a7.516 7.516 0 0 1 10.629 0l9.566 9.563a7.516 7.516 0 0 1 0 10.629l-4.264 4.271c-3.103 3.1.462 11.714 9.252 20.5z" fill="#eeefee"/></g></svg>`; | ||
import { declineCall, acceptCall, cross, remoteControl } from './icons.js'; | ||
function confirmDefault(opts, confirmBtn, declineBtn, text) { | ||
const isStr = typeof opts === "string"; | ||
return Object.assign({ | ||
text: isStr ? opts : text, | ||
confirmBtn, | ||
declineBtn, | ||
}, isStr ? undefined : opts); | ||
} | ||
export const callConfirmDefault = (opts) => confirmDefault(opts, acceptCall, declineCall, "You have an incoming call. Do you want to answer?"); | ||
export const controlConfirmDefault = (opts) => confirmDefault(opts, remoteControl, cross, "Allow remote control?"); | ||
function makeButton(options) { | ||
if (options instanceof HTMLButtonElement) { | ||
return options; | ||
} | ||
const btn = document.createElement('button'); | ||
Object.assign(btn.style, { | ||
background: "transparent", | ||
padding: 0, | ||
margin: 0, | ||
border: 0, | ||
cursor: "pointer", | ||
borderRadius: "50%", | ||
width: "22px", | ||
height: "22px", | ||
color: "white", // TODO: nice text button in case when only text is passed | ||
}); | ||
if (typeof options === "string") { | ||
btn.innerHTML = options; | ||
} | ||
else { | ||
btn.innerHTML = options.innerHTML; | ||
Object.assign(btn.style, options.style); | ||
} | ||
return btn; | ||
} | ||
export default class ConfirmWindow { | ||
constructor(text, styles) { | ||
constructor(options) { | ||
this.resolve = () => { }; | ||
@@ -9,24 +44,10 @@ this.reject = () => { }; | ||
const p = document.createElement('p'); | ||
p.innerText = text; | ||
p.innerText = options.text; | ||
const buttons = document.createElement('div'); | ||
const answerBtn = document.createElement('button'); | ||
answerBtn.innerHTML = declineIcon.replace('fill="#ef5261"', 'fill="green"'); | ||
const declineBtn = document.createElement('button'); | ||
declineBtn.innerHTML = declineIcon; | ||
buttons.appendChild(answerBtn); | ||
const confirmBtn = makeButton(options.confirmBtn); | ||
const declineBtn = makeButton(options.declineBtn); | ||
buttons.appendChild(confirmBtn); | ||
buttons.appendChild(declineBtn); | ||
popup.appendChild(p); | ||
popup.appendChild(buttons); | ||
const btnStyles = { | ||
borderRadius: "50%", | ||
width: "22px", | ||
height: "22px", | ||
background: "transparent", | ||
padding: 0, | ||
margin: 0, | ||
border: 0, | ||
cursor: "pointer", | ||
}; | ||
Object.assign(answerBtn.style, btnStyles); | ||
Object.assign(declineBtn.style, btnStyles); | ||
Object.assign(buttons.style, { | ||
@@ -51,3 +72,3 @@ marginTop: "10px", | ||
boxShadow: "0 0 20px rgb(0 0 0 / 20%)", | ||
}, styles); | ||
}, options.style); | ||
Object.assign(wrapper.style, { | ||
@@ -64,3 +85,3 @@ position: "fixed", | ||
this.wrapper = wrapper; | ||
answerBtn.onclick = () => { | ||
confirmBtn.onclick = () => { | ||
this._remove(); | ||
@@ -67,0 +88,0 @@ this.resolve(true); |
import './_slim.js'; | ||
import { App } from '@openreplay/tracker'; | ||
export interface Options { | ||
onAgentConnect: () => ((() => {}) | void); | ||
onCallStart: () => ((() => {}) | void); | ||
confirmText: string; | ||
confirmStyle: Object; | ||
session_calling_peer_key: string; | ||
config: RTCConfiguration; | ||
} | ||
import type { App } from '@openreplay/tracker'; | ||
import type { Options } from './Assist.js'; | ||
import Assist from './Assist.js'; | ||
export default function (opts?: Partial<Options>): (app: App | null, appOptions?: { | ||
__debug_log?: boolean; | ||
__DISABLE_SECURE_MODE?: boolean; | ||
}) => void; | ||
}) => Assist | undefined; |
225
lib/index.js
import './_slim.js'; | ||
import Peer from 'peerjs'; | ||
import BufferingConnection from './BufferingConnection.js'; | ||
import Mouse from './Mouse.js'; | ||
import CallWindow from './CallWindow.js'; | ||
import ConfirmWindow from './ConfirmWindow.js'; | ||
import RequestLocalStream from './LocalStream.js'; | ||
var CallingState; | ||
(function (CallingState) { | ||
CallingState[CallingState["Requesting"] = 0] = "Requesting"; | ||
CallingState[CallingState["True"] = 1] = "True"; | ||
CallingState[CallingState["False"] = 2] = "False"; | ||
})(CallingState || (CallingState = {})); | ||
; | ||
//@ts-ignore peerjs hack for webpack5 (?!) TODO: ES/node modules; | ||
Peer = Peer.default || Peer; | ||
// type IncomeMessages = | ||
// "call_end" | | ||
// { type: "agent_name", name: string } | | ||
// { type: "click", x: number, y: number } | | ||
// { x: number, y: number } | ||
import Assist from './Assist.js'; | ||
export default function (opts) { | ||
const options = Object.assign({ | ||
confirmText: "You have an incoming call. Do you want to answer?", | ||
confirmStyle: {}, | ||
session_calling_peer_key: "__openreplay_calling_peer", | ||
config: null, | ||
onCallStart: () => { }, | ||
onAgentConnect: () => { }, | ||
}, opts); | ||
return function (app, appOptions = {}) { | ||
@@ -37,193 +10,11 @@ var _a; | ||
} | ||
function log(...args) { | ||
// TODO: use centralised warn/log from tracker (?) | ||
appOptions.__debug_log && console.log("OpenReplay Assist. ", ...args); | ||
if (!app.checkRequiredVersion || !app.checkRequiredVersion("3.5.0")) { | ||
console.warn("OpenReplay Assist: couldn't load. The minimum required version of @openreplay/tracker@3.5.0 is not met"); | ||
return; | ||
} | ||
function warn(...args) { | ||
appOptions.__debug_log && console.warn("OpenReplay Assist. ", ...args); | ||
} | ||
let assistDemandedRestart = false; | ||
let peer = null; | ||
// This is required because internal peerjs connection list is not stable. https://peerjs.com/docs.html#peerconnections | ||
const openDataConnections = {}; | ||
app.addCommitCallback(function (messages) { | ||
Object.values(openDataConnections).forEach(buffConn => buffConn.send(messages)); | ||
}); | ||
app.attachStopCallback(function () { | ||
if (assistDemandedRestart) { | ||
return; | ||
} | ||
if (peer) { | ||
peer.destroy(); | ||
log('Peer destroyed!'); | ||
} | ||
}); | ||
app.attachStartCallback(function () { | ||
if (assistDemandedRestart) { | ||
return; | ||
} | ||
const peerID = `${app.getProjectKey()}-${app.getSessionID()}`; | ||
const _opt = { | ||
// @ts-ignore | ||
host: app.getHost(), | ||
path: '/assist', | ||
port: location.protocol === 'http:' && appOptions.__DISABLE_SECURE_MODE ? 80 : 443, | ||
debug: appOptions.__debug_log ? 2 : 0, // 0 Print nothing //1 Prints only errors. / 2 Prints errors and warnings. / 3 Prints all logs. | ||
}; | ||
if (options.config) { | ||
_opt['config'] = options.config; | ||
} | ||
peer = new Peer(peerID, _opt); | ||
log('Peer created: ', peer); | ||
peer.on('error', e => warn("Peer error: ", e.type, e)); | ||
peer.on('connection', function (conn) { | ||
window.addEventListener("beforeunload", () => conn.open && conn.send("unload")); | ||
log('Connecting...'); | ||
conn.on('open', function () { | ||
log('Connection opened.'); | ||
assistDemandedRestart = true; | ||
app.stop(); | ||
openDataConnections[conn.peer] = new BufferingConnection(conn); | ||
const onAgentDisconnect = options.onAgentConnect(); | ||
conn.on('close', () => { | ||
onAgentDisconnect && onAgentDisconnect(); | ||
log("Connection close: ", conn.peer); | ||
delete openDataConnections[conn.peer]; // TODO: check if works properly | ||
}); | ||
app.start().then(() => { assistDemandedRestart = false; }); | ||
}); | ||
}); | ||
let callingState = CallingState.False; | ||
peer.on('call', function (call) { | ||
var _a; | ||
log("Call: ", call); | ||
if (!peer) { | ||
return; | ||
} | ||
const dataConn = (_a = openDataConnections[call.peer]) === null || _a === void 0 ? void 0 : _a.conn; | ||
if (callingState !== CallingState.False || !dataConn || !dataConn.open) { | ||
call.close(); | ||
warn("Call closed instantly: ", callingState, dataConn, dataConn.open); | ||
return; | ||
} | ||
function setCallingState(newState) { | ||
if (newState === CallingState.True) { | ||
sessionStorage.setItem(options.session_calling_peer_key, call.peer); | ||
} | ||
else if (newState === CallingState.False) { | ||
sessionStorage.removeItem(options.session_calling_peer_key); | ||
} | ||
callingState = newState; | ||
} | ||
const notifyCallEnd = () => { | ||
dataConn.open && dataConn.send("call_end"); | ||
}; | ||
let confirmAnswer; | ||
const callingPeer = sessionStorage.getItem(options.session_calling_peer_key); | ||
if (callingPeer === call.peer) { | ||
confirmAnswer = Promise.resolve(true); | ||
} | ||
else { | ||
setCallingState(CallingState.Requesting); | ||
const confirm = new ConfirmWindow(options.confirmText, options.confirmStyle); | ||
confirmAnswer = confirm.mount(); | ||
dataConn.on('data', (data) => { | ||
if (data === "call_end") { | ||
log("Received call_end during confirm window opened"); | ||
confirm.remove(); | ||
setCallingState(CallingState.False); | ||
} | ||
}); | ||
} | ||
confirmAnswer.then(agreed => { | ||
if (!agreed || !dataConn.open) { | ||
!dataConn.open && warn("Call cancelled because data connection is closed."); | ||
call.close(); | ||
notifyCallEnd(); | ||
setCallingState(CallingState.False); | ||
return; | ||
} | ||
const onCallEnd = options.onCallStart(); | ||
const mouse = new Mouse(); | ||
let callUI = new CallWindow(); | ||
const handleCallEnd = () => { | ||
onCallEnd && onCallEnd(); | ||
mouse.remove(); | ||
callUI.remove(); | ||
setCallingState(CallingState.False); | ||
}; | ||
const initiateCallEnd = () => { | ||
log("initiateCallEnd"); | ||
call.close(); | ||
notifyCallEnd(); | ||
handleCallEnd(); | ||
}; | ||
RequestLocalStream().then(lStream => { | ||
dataConn.on("close", handleCallEnd); // For what case? | ||
//call.on('close', onClose); // Works from time to time (peerjs bug) | ||
const checkConnInterval = setInterval(() => { | ||
if (!dataConn.open) { | ||
initiateCallEnd(); | ||
clearInterval(checkConnInterval); | ||
} | ||
if (!call.open) { | ||
handleCallEnd(); | ||
clearInterval(checkConnInterval); | ||
} | ||
}, 3000); | ||
call.on('error', e => { | ||
warn("Call error:", e); | ||
initiateCallEnd(); | ||
}); | ||
call.on('stream', function (rStream) { | ||
callUI.setRemoteStream(rStream); | ||
const onInteraction = () => { | ||
callUI.playRemote(); | ||
document.removeEventListener("click", onInteraction); | ||
}; | ||
document.addEventListener("click", onInteraction); | ||
}); | ||
dataConn.on('data', (data) => { | ||
log("Income data: ", data); | ||
if (!data) { | ||
return; | ||
} | ||
if (data === "call_end") { | ||
return handleCallEnd(); | ||
} | ||
if (data.name === 'string') { | ||
return callUI.setAssistentName(data.name); | ||
} | ||
if (data.type === "scroll" && Array.isArray(data.delta)) { | ||
return mouse.scroll(data.delta); | ||
} | ||
if (data.type === "click" && typeof data.x === 'number' && typeof data.y === 'number') { | ||
return mouse.click([data.x, data.y]); | ||
} | ||
if (typeof data.x === 'number' && typeof data.y === 'number') { | ||
return mouse.move([data.x, data.y]); | ||
} | ||
}); | ||
lStream.onVideoTrack(vTrack => { | ||
const sender = call.peerConnection.getSenders().find(s => { var _a; return ((_a = s.track) === null || _a === void 0 ? void 0 : _a.kind) === "video"; }); | ||
if (!sender) { | ||
warn("No video sender found"); | ||
return; | ||
} | ||
log("sender found:", sender); | ||
sender.replaceTrack(vTrack); | ||
}); | ||
callUI.setCallEndAction(initiateCallEnd); | ||
callUI.setLocalStream(lStream); | ||
call.answer(lStream.stream); | ||
setCallingState(CallingState.True); | ||
}) | ||
.catch(e => { | ||
warn("Audio mediadevice request error:", e); | ||
handleCallEnd(); | ||
}); | ||
}).catch(); // in case of Confirm.remove() without any confirmation | ||
}); | ||
}); | ||
app.notify.log("OpenReplay Assist initializing."); | ||
const assist = new Assist(app, opts, appOptions.__DISABLE_SECURE_MODE); | ||
app.debug.log(assist); | ||
return assist; | ||
}; | ||
} |
@@ -6,2 +6,3 @@ declare type XY = [number, number]; | ||
constructor(); | ||
mount(): void; | ||
move(pos: XY): void; | ||
@@ -8,0 +9,0 @@ getPosition(): XY; |
@@ -23,2 +23,4 @@ export default class Mouse { | ||
}); | ||
} | ||
mount() { | ||
document.body.appendChild(this.mouse); | ||
@@ -25,0 +27,0 @@ window.addEventListener("scroll", this.handleWScroll); |
{ | ||
"name": "@openreplay/tracker-assist", | ||
"description": "Tracker plugin for screen assistance through the WebRTC", | ||
"version": "3.4.16", | ||
"version": "3.5.0", | ||
"keywords": [ | ||
@@ -18,4 +18,8 @@ "WebRTC", | ||
"build": "npm run build-es && npm run build-cjs", | ||
"build-es": "rm -Rf lib && tsc", | ||
"build-cjs": "rm -Rf cjs && tsc --project tsconfig-cjs.json && echo '{ \"type\": \"commonjs\" }' > cjs/package.json && replace-in-files cjs/* --string='@openreplay/tracker' --replacement='@openreplay/tracker/cjs' && replace-in-files cjs/* --string='/lib/' --replacement='/'", | ||
"build-es": "rm -Rf lib && tsc && npm run replace-versions", | ||
"build-cjs": "rm -Rf cjs && tsc --project tsconfig-cjs.json && echo '{ \"type\": \"commonjs\" }' > cjs/package.json && npm run replace-paths && npm run replace-versions", | ||
"replace-paths": "replace-in-files cjs/* --string='@openreplay/tracker' --replacement='@openreplay/tracker/cjs' && replace-in-files cjs/* --string='/lib/' --replacement='/'", | ||
"replace-versions": "npm run replace-pkg-version && npm run replace-req-version", | ||
"replace-pkg-version": "replace-in-files lib/* cjs/* --string='PACKAGE_VERSION' --replacement=$npm_package_version", | ||
"replace-req-version": "replace-in-files lib/* cjs/* --string='REQUIRED_TRACKER_VERSION' --replacement='3.5.0'", | ||
"prepublishOnly": "npm run build" | ||
@@ -25,9 +29,10 @@ }, | ||
"npm-dragndrop": "^1.2.0", | ||
"peerjs": "^1.3.2" | ||
"peerjs": "^1.3.2", | ||
"socket.io-client": "^4.4.1" | ||
}, | ||
"peerDependencies": { | ||
"@openreplay/tracker": "^3.4.8" | ||
"@openreplay/tracker": "^3.5.0" | ||
}, | ||
"devDependencies": { | ||
"@openreplay/tracker": "^3.4.8", | ||
"@openreplay/tracker": "file:../tracker", | ||
"prettier": "^1.18.2", | ||
@@ -34,0 +39,0 @@ "replace-in-files-cli": "^1.0.0", |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
83922
4
36
1912
3
+ Addedsocket.io-client@^4.4.1
+ Added@socket.io/component-emitter@3.1.2(transitive)
+ Addeddebug@4.3.7(transitive)
+ Addedengine.io-client@6.6.3(transitive)
+ Addedengine.io-parser@5.2.3(transitive)
+ Addedms@2.1.3(transitive)
+ Addedsocket.io-client@4.8.1(transitive)
+ Addedsocket.io-parser@4.2.4(transitive)
+ Addedws@8.17.1(transitive)
+ Addedxmlhttprequest-ssl@2.1.2(transitive)