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

@testrtc/watchrtc-sdk

Package Overview
Dependencies
Maintainers
2
Versions
127
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@testrtc/watchrtc-sdk - npm Package Compare versions

Comparing version 1.29.1 to 1.29.2

lib/interfaces.js

46

lib/index.d.ts
import "./types";
import { IWatchRTCConfiguration } from "./interfaces";
import { IWatchRTCConfiguration, Rating } from "./interfaces";
/**
* Initialize SDK. Can be called multiple times but it will be initialized only at the first time.
* Use 'start' function after if you don't have rtcRoomId and rtcPeerId yet.
* Use 'setConfig' function after if you don't have rtcRoomId and rtcPeerId yet.
* @param watchrtc

@@ -10,2 +10,6 @@ * @param prefixesToWrap

export declare const init: (watchrtcConfig?: IWatchRTCConfiguration | undefined) => void;
/**
* You also can use watchRTC.setConfig function to set watchRTC configuration after calling init()
* and before the creation of RTCPeerConnection objects
*/
export declare const setConfig: (watchrtcConfig: IWatchRTCConfiguration) => void;

@@ -17,11 +21,49 @@ /**

export declare const addTags: (rtcTags: string[]) => void;
/**
* Set user rating and/or comment for peer session
* @param rating number from 1 to 5
* @param comment string
*/
export declare const setUserRating: (rating: Rating, comment?: string | undefined) => void;
/**
* Disables data collection
*/
export declare const disableDataCollection: () => void;
/**
* Enables data collection
*/
export declare const enableDataCollection: () => void;
declare const _default: {
/**
* Initialize SDK. Can be called multiple times but it will be initialized only at the first time.
* Use 'setConfig' function after if you don't have rtcRoomId and rtcPeerId yet.
* @param watchrtc
* @param prefixesToWrap
*/
init: (watchrtcConfig?: IWatchRTCConfiguration | undefined) => void;
/**
* Add tags for peer session
* @param rtcTags[]
*/
addTags: (rtcTags: string[]) => void;
/**
* Set user rating and/or comment for peer session
* @param rating number from 1 to 5
* @param comment string
*/
setUserRating: (rating: Rating, comment?: string | undefined) => void;
/**
* You also can use watchRTC.setConfig function to set watchRTC configuration after calling init()
* and before the creation of RTCPeerConnection objects
*/
setConfig: (watchrtcConfig: IWatchRTCConfiguration) => void;
/**
* Disables data collection
*/
disableDataCollection: () => void;
/**
* Enables data collection
*/
enableDataCollection: () => void;
};
export default _default;

2

lib/index.js

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

!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.watchRTC=n():e.watchRTC=n()}(self,(function(){return(e={607:(e,n,t)=>{"use strict";n.xt=n.Zt=n.zl=n.v6=n.S1=void 0,t(699);var o=t(231);n.S1=function(e){o.initSDK(e,["","webkit","moz"])},n.v6=function(e){o.setConfig(e)},n.zl=function(e){o.addTags(e)},n.Zt=function(){o.disableDataCollection()},n.xt=function(){o.enableDataCollection()},n.default={init:n.S1,addTags:n.zl,setConfig:n.v6,disableDataCollection:n.Zt,enableDataCollection:n.xt}},231:function(e,n,t){"use strict";var o=this&&this.__assign||function(){return(o=Object.assign||function(e){for(var n,t=1,o=arguments.length;t<o;t++)for(var i in n=arguments[t])Object.prototype.hasOwnProperty.call(n,i)&&(e[i]=n[i]);return e}).apply(this,arguments)},i=this&&this.__spreadArrays||function(){for(var e=0,n=0,t=arguments.length;n<t;n++)e+=arguments[n].length;var o=Array(e),i=0;for(n=0;n<t;n++)for(var r=arguments[n],a=0,c=r.length;a<c;a++,i++)o[i]=r[a];return o};Object.defineProperty(n,"__esModule",{value:!0}),n.enableDataCollection=n.disableDataCollection=n.addTags=n.setConfig=n.initSDK=void 0;var r,a,c=t(85),s=t(593),l=t(412),d=!!window.mozRTCPeerConnection,u=!!window.RTCIceGatherer,f=(!d&&window.RTCPeerConnection&&window.navigator.webkitGetUserMedia,{}),p={rtcRoomId:void 0,rtcPeerId:void 0},g=null,v=null,h=0,m=!1,y=function(e){var n;if(void 0===e&&(e=!1),(null===(n=null==v?void 0:v.connection)||void 0===n?void 0:n.readyState)===WebSocket.OPEN){if(!s.isRoomIdOrPeerIdChanged(p,g)||!e)return void((null==g?void 0:g.debug)&&console.log.apply(console,i(s.logPrefix("info"),["maybeOpenWebsocketConnection. WS connection already opened"])));(null==g?void 0:g.debug)&&console.log.apply(console,i(s.logPrefix("info"),["maybeOpenWebsocketConnection. Closing WS connection"])),null==v||v.close()}var t=s.countOfValidConnections(f);if(t>0&&!m){var c=s.validateConfig(g),d=Object.keys(f)[t-1];if(c){g.rtcTags&&(Array.isArray(g.rtcTags)?g.rtcTags.some((function(e){return e.includes(",")}))&&console.info.apply(console,i(s.logPrefix("info"),["To apply multiple tags please use an array and not comma separated values."])):(console.info.apply(console,i(s.logPrefix("info"),["config.rtcTags must be an array."])),g.rtcTags=void 0));var y=!!g.rtcToken,C=s.getWSConnectionData(y?g.rtcToken:g.rtcApiKey,g.proxyUrl||g.wsUrl);m=!0,h=Date.now(),null==v||v.connect(C.url+"?"+(y?"token":"apiKey")+"="+C.key+"&timestamp="+Date.now(),(function(e){p.rtcRoomId=g.rtcRoomId,p.rtcPeerId=g.rtcPeerId,m=!1,console.info.apply(console,i(s.logPrefix("info"),["Connection established. watchRTCConnectionId: "+e.connectionId+" sdkVersion:"+l.default])),r("watchrtc",d,o(o(o({},g),e),{sdkVersion:l.default})),u||(window.clearInterval(a),a=window.setInterval((function(){0===s.countOfValidConnections(f)?h&&h+2e4<Date.now()&&(window.clearInterval(a),null==v||v.close(),console.info.apply(console,i(s.logPrefix("info"),["Last connection closed. watchRTCConnectionId: "+e.connectionId+" sdkVersion: "+l.default]))):(h=Date.now(),Object.values(f).forEach((function(e){"closed"!==e.pc.signalingState&&b(e)})))}),e.interval))}),(function(){m=!1,h=0}))}else m=!1}},b=function(e){if(e){var n=e.id,t=e.pc,o=e.prev;t.getStats(null).then((function(t){var i=s.map2obj(t),a=JSON.parse(JSON.stringify(i)),c=s.deltaCompression(o,i);null!==(null==c?void 0:c.timestamp)&&(null==c?void 0:c.timestamp)!==-1/0&&r("getstats",n,s.deltaCompression(e.prev,i)),e.prev=a}))}};n.initSDK=function(e,n){if(!window.watchRTCInitialized){window.watchRTCInitialized=!0;var t=0;if(v=new c.default({debug:null==e?void 0:e.debug}),window.wrtcSocket=v,g=e,r=v.trace,n.forEach((function(e){if(window[e+"RTCPeerConnection"]&&("webkit"!==e||!u)){var n=window[e+"RTCPeerConnection"],a=function(e,a){(null==e?void 0:e.watchrtc)&&(g=o(o({},g),e.watchrtc)),(null==g?void 0:g.debug)&&console.info.apply(console,i(s.logPrefix("info"),["new RTCPeerConnection called.",{config:e,constraints:a}]));var c=new n(e,a),l="PC_"+t++;return c.__rtcStatsId=l,f[l]={id:l,pc:c,validConnection:!1},e||(e={nullConfig:!0}),((e=JSON.parse(JSON.stringify(e)))&&e.iceServers||[]).forEach((function(e){delete e.credential})),(null==e?void 0:e.watchrtc)&&delete e.watchrtc,e.browserType=d?"moz":u?"edge":"webkit",r("create",l,e),a&&r("constraints",l,a),c.addEventListener("icecandidate",(function(e){r("onicecandidate",l,e.candidate)})),c.addEventListener("addstream",(function(e){r("onaddstream",l,e.stream.id+" "+e.stream.getTracks().map((function(e){return e.kind+":"+e.id})))})),c.addEventListener("track",(function(e){r("ontrack",l,e.track.kind+":"+e.track.id+" "+e.streams.map((function(e){return"stream:"+e.id})))})),c.addEventListener("removestream",(function(e){r("onremovestream",l,e.stream.id+" "+e.stream.getTracks().map((function(e){return e.kind+":"+e.id})))})),c.addEventListener("signalingstatechange",(function(){f[l]&&!f[l].validConnection&&(f[l].validConnection=!0,setTimeout((function(){y(!0)}),5e3)),r("onsignalingstatechange",l,c.signalingState)})),c.addEventListener("iceconnectionstatechange",(function(){r("oniceconnectionstatechange",l,c.iceConnectionState)})),c.addEventListener("icegatheringstatechange",(function(){r("onicegatheringstatechange",l,c.iceGatheringState)})),c.addEventListener("connectionstatechange",(function(){r("onconnectionstatechange",l,c.connectionState)})),c.addEventListener("negotiationneeded",(function(){r("onnegotiationneeded",l,void 0)})),c.addEventListener("datachannel",(function(e){r("ondatachannel",l,[e.channel.id,e.channel.label])})),u||c.addEventListener("iceconnectionstatechange",(function(){"connected"===c.iceConnectionState&&b(f[l])})),c};["createDataChannel"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){return r(e,this.__rtcStatsId,arguments),t.apply(this,arguments)})})),["close"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){return r(e,this.__rtcStatsId,arguments),delete f[this.__rtcStatsId],t.apply(this,arguments)})})),["addStream","removeStream"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){var n=arguments[0],o=n.getTracks().map((function(e){return e.kind+":"+e.id})).join(",");return r(e,this.__rtcStatsId,n.id+" "+o),t.apply(this,arguments)})})),["addTrack"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){var n=arguments[0],o=[].slice.call(arguments,1);return r(e,this.__rtcStatsId,n.kind+":"+n.id+" "+(o.map((function(e){return"stream:"+e.id})).join(";")||"-")),t.apply(this,arguments)})})),["removeTrack"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){var n=arguments[0].track;return r(e,this.__rtcStatsId,n?n.kind+":"+n.id:"null"),t.apply(this,arguments)})})),["createOffer","createAnswer"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){var n,o=this.__rtcStatsId,i=arguments;return 1===arguments.length&&"object"==typeof arguments[0]?n=arguments[0]:3===arguments.length&&"object"==typeof arguments[2]&&(n=arguments[2]),r(e,this.__rtcStatsId,n),t.apply(this,n?[n]:void 0).then((function(n){if(r(e+"OnSuccess",o,n),!(i.length>0&&"function"==typeof i[0]))return n;i[0].apply(null,[n])}),(function(n){if(r(e+"OnFailure",o,n.toString()),!(i.length>1&&"function"==typeof i[1]))throw n;i[1].apply(null,[n])}))})})),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){var n=this.__rtcStatsId,o=arguments;return r(e,this.__rtcStatsId,o[0]),t.apply(this,[o[0]]).then((function(){r(e+"OnSuccess",n,void 0),o.length>=2&&"function"==typeof o[1]&&o[1].apply(null,[])}),(function(t){if(r(e+"OnFailure",n,t.toString()),!(o.length>=3&&"function"==typeof o[2]))throw t;o[2].apply(null,[t])}))})})),n.generateCertificate&&Object.defineProperty(a,"generateCertificate",{get:function(){return arguments.length?n.generateCertificate.apply(null,arguments):n.generateCertificate}}),window[e+"RTCPeerConnection"]=a,window[e+"RTCPeerConnection"].prototype=n.prototype}})),n.forEach((function(e){var n=e+(e.length?"GetUserMedia":"getUserMedia");if(navigator[n]){var t=navigator[n].bind(navigator);navigator[n]=function(){r("getUserMedia",null,arguments[0]);var e=arguments[1],n=arguments[2];t(arguments[0],(function(n){r("getUserMediaOnSuccess",null,s.dumpStream(n)),e&&e(n)}),(function(e){r("getUserMediaOnFailure",null,e.name),n&&n(e)}))}.bind(navigator)}})),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){var a=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(){return r("navigator.mediaDevices.getUserMedia",null,arguments[0]),a.apply(navigator.mediaDevices,arguments).then((function(e){return r("navigator.mediaDevices.getUserMediaOnSuccess",null,s.dumpStream(e)),e}),(function(e){return r("navigator.mediaDevices.getUserMediaOnFailure",null,e.name),Promise.reject(e)}))}.bind(navigator.mediaDevices)}if(navigator.mediaDevices&&navigator.mediaDevices.getDisplayMedia){var l=navigator.mediaDevices.getDisplayMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getDisplayMedia=function(){return r("navigator.mediaDevices.getDisplayMedia",null,arguments[0]),l.apply(navigator.mediaDevices,arguments).then((function(e){return r("navigator.mediaDevices.getDisplayMediaOnSuccess",null,s.dumpStream(e)),e}),(function(e){return r("navigator.mediaDevices.getDisplayMediaOnFailure",null,e.name),Promise.reject(e)}))}.bind(navigator.mediaDevices)}}},n.setConfig=function(e){window.watchRTCInitialized?(void 0!==e.debug&&e.debug!==g.debug&&(null==v||v.toggleDebug(e.debug)),g=o(o({},g),e),y()):console.info.apply(console,i(s.logPrefix("error"),["SDK is not initialized. Use 'init' function fisrt."]))},n.addTags=function(e){window.watchRTCInitialized?e&&Array.isArray(e)?r("addRtcTags",null,{rtcTags:e}):console.info.apply(console,i(s.logPrefix("error"),["addTags excepts only array of strings"])):console.info.apply(console,i(s.logPrefix("error"),["SDK is not initialized. Use 'init' function fisrt."]))},n.disableDataCollection=function(){window.watchRTCInitialized?null==v||v.disableDataCollection():console.info.apply(console,i(s.logPrefix("error"),["SDK is not initialized. Use 'init' function fisrt."]))},n.enableDataCollection=function(){window.watchRTCInitialized?null==v||v.enableDataCollection():console.info.apply(console,i(s.logPrefix("error"),["SDK is not initialized. Use 'init' function fisrt."]))}},699:(e,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0})},593:function(e,n){"use strict";var t=this&&this.__spreadArrays||function(){for(var e=0,n=0,t=arguments.length;n<t;n++)e+=arguments[n].length;var o=Array(e),i=0;for(n=0;n<t;n++)for(var r=arguments[n],a=0,c=r.length;a<c;a++,i++)o[i]=r[a];return o};Object.defineProperty(n,"__esModule",{value:!0}),n.isRoomIdOrPeerIdChanged=n.countOfValidConnections=n.validateConfig=n.getWSConnectionData=n.dumpStream=n.map2obj=n.mangleChromeStats=n.deltaCompression=n.logPrefix=void 0,n.logPrefix=function(e){return void 0===e&&(e="info"),"error"===e?["%cwatchRTC %cERROR","background: gold; color: black; padding: 2px 0.5em; border-radius: 0.5em;","background: red; color: white; padding: 2px 0.5em; border-radius: 0.5em;"]:["%cwatchRTC","background: gold; color: black; padding: 2px 0.5em; border-radius: 0.5em;"]},n.deltaCompression=function(e,n){e=e||{},n=n||{},n=JSON.parse(JSON.stringify(n)),Object.keys(n).forEach((function(t){var o=n[t];delete o.id,e[t]&&Object.keys(o).forEach((function(i){o[i]===e[t][i]&&delete n[t][i],(0===Object.keys(o).length||1===Object.keys(o).length&&o.timestamp)&&delete n[t]}))}));var t=-1/0;return Object.keys(n).forEach((function(e){var o=n[e];o.timestamp>t&&(t=o.timestamp)})),Object.keys(n).forEach((function(e){var o=n[e];o.timestamp===t&&(o.timestamp=0)})),n.timestamp=t,n},n.mangleChromeStats=function(e,n){var t={};return n.result().forEach((function(e){var n={id:e.id,timestamp:e.timestamp.getTime(),type:e.type};e.names().forEach((function(t){n[t]=e.stat(t)})),t[n.id]=n})),t},n.map2obj=function(e){if(!e.entries)return e;var n={};return e.forEach((function(e,t){n[t]=e})),n},n.dumpStream=function(e){return{id:e.id,tracks:e.getTracks().map((function(e){return{id:e.id,kind:e.kind,label:e.label,enabled:e.enabled,muted:e.muted,readyState:e.readyState}}))}},n.getWSConnectionData=function(e,n){var t="wss://watchrtc.testrtc.com",o=e.split(":");return-1!==e.indexOf("local")?{url:n||"ws://localhost:9101",key:o[1]}:-1!==e.indexOf("staging")?{url:n||"wss://watchrtc-staging2.testrtc.com",key:o[1]}:-1!==e.indexOf("production")?{url:n||t,key:o[1]}:{url:n||t,key:o[0]}},n.validateConfig=function(e){return!(null==e?void 0:e.rtcApiKey)&&(null==e?void 0:e.debug)?(console.info.apply(console,t(n.logPrefix("error"),["config.rtcApiKey or config.rtcToken need to be provided."])),!1):!(!(null==e?void 0:e.rtcRoomId)||!(null==e?void 0:e.rtcPeerId))||((null==e?void 0:e.debug)&&console.info.apply(console,t(n.logPrefix("info"),["rtcRoomId or rtcPeerId is empty."])),!1)},n.countOfValidConnections=function(e){return Object.keys(e).filter((function(n){return e[n].validConnection})).length},n.isRoomIdOrPeerIdChanged=function(e,o){var i=!1;return o.rtcRoomId&&e.rtcRoomId&&e.rtcRoomId!==o.rtcRoomId&&(i=!0),o.rtcPeerId&&e.rtcPeerId&&e.rtcPeerId!==o.rtcPeerId&&(i=!0),i&&o.debug&&console.log.apply(console,t(n.logPrefix("info"),["maybeOpenWebsocketConnection. rtcRoomId or rtcPeerId has been changed",{old:{rtcRoomId:e.rtcRoomId,rtcPeerId:e.rtcPeerId},new:{rtcRoomId:o.rtcRoomId,rtcPeerId:o.rtcPeerId}}])),i}},412:(e,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.default="1.29.1"},85:function(e,n,t){"use strict";var o=this&&this.__spreadArrays||function(){for(var e=0,n=0,t=arguments.length;n<t;n++)e+=arguments[n].length;var o=Array(e),i=0;for(n=0;n<t;n++)for(var r=arguments[n],a=0,c=r.length;a<c;a++,i++)o[i]=r[a];return o};Object.defineProperty(n,"__esModule",{value:!0});var i=t(593),r=t(354),a=function(){function e(n){this.connection=null,this.buffer=[],this.sendInterval=1,this.onClose=function(){},this.debug=!1,this.dataCollection=!0,e._instance?console.info.apply(console,o(i.logPrefix("info"),["WatchRTCSocket instance already created"])):(e._instance=this,this.debug=!!n.debug)}return e.prototype.connect=function(n,t,r){e._instance.connection&&e._instance.connection.close();var a=e._instance;e._instance.connection=new WebSocket(n,"2.0"),e._instance.connection.onopen=function(e){},e._instance.connection.onclose=function(e){},e._instance.connection.onmessage=function(n){var c;try{var s=JSON.parse(n.data);s.error?(null===(c=null==a?void 0:a.connection)||void 0===c||c.close(),a.connection=null,console.info.apply(console,o(i.logPrefix("error"),["\n"+s.error])),r(s.error)):(s.sendInterval&&(e._instance.sendInterval=s.sendInterval),t(s))}catch(e){console.info.apply(console,o(i.logPrefix("error"),[{err:e.stack}])),r(e.message)}},e._instance.connection.onerror=function(e){console.info.apply(console,o(i.logPrefix("error"),["\n",e])),r(e)}},e.prototype.trace=function(){for(var n=[],t=0;t<arguments.length;t++)n[t]=arguments[t];var a=Array.prototype.slice.call(n);if(a.push(Date.now()),a[1]instanceof RTCPeerConnection&&(a[1]=a[1].__rtcStatsId),e._instance.dataCollection)if(e._instance.connection){if(e._instance.connection.readyState===WebSocket.OPEN&&(e._instance.buffer.push(a),e._instance.buffer.length>=e._instance.sendInterval)){var c=JSON.stringify(e._instance.buffer),s=r.compressToEncodedURIComponent(c);e._instance.debug&&(console.log.apply(console,o(i.logPrefix("info"),["lines: "+c.length])),console.log.apply(console,o(i.logPrefix("info"),["compressedMessage: "+s.length]))),e._instance.buffer=[],e._instance.connection.send(s)}}else{if(e._instance.buffer.length>1e3)return;e._instance.buffer.push(a)}},e.prototype.close=function(){e._instance.buffer=[],e._instance.connection&&(e._instance.connection.close(),e._instance.onClose(),e._instance.connection=null)},e.prototype.disableDataCollection=function(){e._instance.debug&&console.log.apply(console,o(i.logPrefix("info"),["Data collection disabled."])),e._instance.dataCollection=!1},e.prototype.enableDataCollection=function(){e._instance.debug&&console.log.apply(console,o(i.logPrefix("info"),["Data collection enabled."])),e._instance.dataCollection=!0},e.prototype.toggleDebug=function(n){e._instance.debug=n},e}();n.default=a},354:(e,n,t)=>{var o,i=function(){function e(e,n){if(!i[e]){i[e]={};for(var t=0;t<e.length;t++)i[e][e.charAt(t)]=t}return i[e][n]}var n=String.fromCharCode,t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",i={},r={compressToBase64:function(e){if(null==e)return"";var n=r._compress(e,6,(function(e){return t.charAt(e)}));switch(n.length%4){default:case 0:return n;case 1:return n+"===";case 2:return n+"==";case 3:return n+"="}},decompressFromBase64:function(n){return null==n?"":""==n?null:r._decompress(n.length,32,(function(o){return e(t,n.charAt(o))}))},compressToUTF16:function(e){return null==e?"":r._compress(e,15,(function(e){return n(e+32)}))+" "},decompressFromUTF16:function(e){return null==e?"":""==e?null:r._decompress(e.length,16384,(function(n){return e.charCodeAt(n)-32}))},compressToUint8Array:function(e){for(var n=r.compress(e),t=new Uint8Array(2*n.length),o=0,i=n.length;i>o;o++){var a=n.charCodeAt(o);t[2*o]=a>>>8,t[2*o+1]=a%256}return t},decompressFromUint8Array:function(e){if(null==e)return r.decompress(e);for(var t=new Array(e.length/2),o=0,i=t.length;i>o;o++)t[o]=256*e[2*o]+e[2*o+1];var a=[];return t.forEach((function(e){a.push(n(e))})),r.decompress(a.join(""))},compressToEncodedURIComponent:function(e){return null==e?"":r._compress(e,6,(function(e){return o.charAt(e)}))},decompressFromEncodedURIComponent:function(n){return null==n?"":""==n?null:(n=n.replace(/ /g,"+"),r._decompress(n.length,32,(function(t){return e(o,n.charAt(t))})))},compress:function(e){return r._compress(e,16,(function(e){return n(e)}))},_compress:function(e,n,t){if(null==e)return"";var o,i,r,a={},c={},s="",l="",d="",u=2,f=3,p=2,g=[],v=0,h=0;for(r=0;r<e.length;r+=1)if(s=e.charAt(r),Object.prototype.hasOwnProperty.call(a,s)||(a[s]=f++,c[s]=!0),l=d+s,Object.prototype.hasOwnProperty.call(a,l))d=l;else{if(Object.prototype.hasOwnProperty.call(c,d)){if(d.charCodeAt(0)<256){for(o=0;p>o;o++)v<<=1,h==n-1?(h=0,g.push(t(v)),v=0):h++;for(i=d.charCodeAt(0),o=0;8>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1}else{for(i=1,o=0;p>o;o++)v=v<<1|i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i=0;for(i=d.charCodeAt(0),o=0;16>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1}0==--u&&(u=Math.pow(2,p),p++),delete c[d]}else for(i=a[d],o=0;p>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1;0==--u&&(u=Math.pow(2,p),p++),a[l]=f++,d=String(s)}if(""!==d){if(Object.prototype.hasOwnProperty.call(c,d)){if(d.charCodeAt(0)<256){for(o=0;p>o;o++)v<<=1,h==n-1?(h=0,g.push(t(v)),v=0):h++;for(i=d.charCodeAt(0),o=0;8>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1}else{for(i=1,o=0;p>o;o++)v=v<<1|i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i=0;for(i=d.charCodeAt(0),o=0;16>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1}0==--u&&(u=Math.pow(2,p),p++),delete c[d]}else for(i=a[d],o=0;p>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1;0==--u&&(u=Math.pow(2,p),p++)}for(i=2,o=0;p>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1;for(;;){if(v<<=1,h==n-1){g.push(t(v));break}h++}return g.join("")},decompress:function(e){return null==e?"":""==e?null:r._decompress(e.length,32768,(function(n){return e.charCodeAt(n)}))},_decompress:function(e,t,o){var i,r,a,c,s,l,d,u=[],f=4,p=4,g=3,v="",h=[],m={val:o(0),position:t,index:1};for(i=0;3>i;i+=1)u[i]=i;for(a=0,s=Math.pow(2,2),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;switch(a){case 0:for(a=0,s=Math.pow(2,8),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;d=n(a);break;case 1:for(a=0,s=Math.pow(2,16),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;d=n(a);break;case 2:return""}for(u[3]=d,r=d,h.push(d);;){if(m.index>e)return"";for(a=0,s=Math.pow(2,g),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;switch(d=a){case 0:for(a=0,s=Math.pow(2,8),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;u[p++]=n(a),d=p-1,f--;break;case 1:for(a=0,s=Math.pow(2,16),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;u[p++]=n(a),d=p-1,f--;break;case 2:return h.join("")}if(0==f&&(f=Math.pow(2,g),g++),u[d])v=u[d];else{if(d!==p)return null;v=r+r.charAt(0)}h.push(v),u[p++]=r+v.charAt(0),r=v,0==--f&&(f=Math.pow(2,g),g++)}}};return r}();void 0===(o=function(){return i}.call(n,t,n,e))||(e.exports=o)}},n={},function t(o){if(n[o])return n[o].exports;var i=n[o]={exports:{}};return e[o].call(i.exports,i,i.exports,t),i.exports}(607)).default;var e,n}));
!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.watchRTC=n():e.watchRTC=n()}(self,(function(){return(e={607:(e,n,t)=>{"use strict";n.xt=n.Zt=n.IO=n.zl=n.v6=n.S1=void 0,t(699);var o=t(231);n.S1=function(e){o.initSDK(e,["","webkit","moz"])},n.v6=function(e){o.setConfig(e)},n.zl=function(e){o.addTags(e)},n.IO=function(e,n){o.setUserRating(e,n)},n.Zt=function(){o.disableDataCollection()},n.xt=function(){o.enableDataCollection()},n.default={init:n.S1,addTags:n.zl,setUserRating:n.IO,setConfig:n.v6,disableDataCollection:n.Zt,enableDataCollection:n.xt}},231:function(e,n,t){"use strict";var o=this&&this.__assign||function(){return(o=Object.assign||function(e){for(var n,t=1,o=arguments.length;t<o;t++)for(var i in n=arguments[t])Object.prototype.hasOwnProperty.call(n,i)&&(e[i]=n[i]);return e}).apply(this,arguments)},i=this&&this.__spreadArrays||function(){for(var e=0,n=0,t=arguments.length;n<t;n++)e+=arguments[n].length;var o=Array(e),i=0;for(n=0;n<t;n++)for(var r=arguments[n],a=0,c=r.length;a<c;a++,i++)o[i]=r[a];return o};Object.defineProperty(n,"__esModule",{value:!0}),n.enableDataCollection=n.disableDataCollection=n.setUserRating=n.addTags=n.setConfig=n.initSDK=void 0;var r,a,c=t(85),s=t(911),l=t(593),d=t(412),u=!!window.mozRTCPeerConnection,f=!!window.RTCIceGatherer,p=(!u&&window.RTCPeerConnection&&window.navigator.webkitGetUserMedia,{}),g={rtcRoomId:void 0,rtcPeerId:void 0,projectId:void 0},v=null,h=null,m=null,y=0,b=!1,C=function(e){var n;if(void 0===e&&(e=!1),(null===(n=null==m?void 0:m.connection)||void 0===n?void 0:n.readyState)===WebSocket.OPEN){if(!l.isRoomIdOrPeerIdChanged(g,v)||!e)return void((null==v?void 0:v.debug)&&console.log.apply(console,i(l.logPrefix("info"),["maybeOpenWebsocketConnection. WS connection already opened"])));(null==v?void 0:v.debug)&&console.log.apply(console,i(l.logPrefix("info"),["maybeOpenWebsocketConnection. Closing WS connection"])),null==m||m.close()}var t=l.countOfValidConnections(p);if(t>0&&!b){var c=l.validateConfig(v),s=Object.keys(p)[t-1];if(c){v.rtcTags&&(Array.isArray(v.rtcTags)?v.rtcTags.some((function(e){return e.includes(",")}))&&console.info.apply(console,i(l.logPrefix("info"),["To apply multiple tags please use an array and not comma separated values."])):(console.info.apply(console,i(l.logPrefix("info"),["config.rtcTags must be an array."])),v.rtcTags=void 0));var u=!!v.rtcToken,h=l.getConnectionData("ws",u?v.rtcToken:v.rtcApiKey,v.proxyUrl||v.wsUrl);b=!0,y=Date.now(),null==m||m.connect(h.url+"?"+(u?"token":"apiKey")+"="+h.key+"&timestamp="+Date.now(),(function(e){g.rtcRoomId=v.rtcRoomId,g.rtcPeerId=v.rtcPeerId,g.projectId=e.projectId,b=!1,console.info.apply(console,i(l.logPrefix("info"),["Connection established. watchRTCConnectionId: "+e.connectionId+" sdkVersion:"+d.default])),r("watchrtc",s,o(o(o({},v),e),{sdkVersion:d.default})),f||(window.clearInterval(a),a=window.setInterval((function(){0===l.countOfValidConnections(p)?y&&y+2e4<Date.now()&&(window.clearInterval(a),null==m||m.close(),console.info.apply(console,i(l.logPrefix("info"),["Last connection closed. watchRTCConnectionId: "+e.connectionId+" sdkVersion: "+d.default]))):(y=Date.now(),Object.values(p).forEach((function(e){"closed"!==e.pc.signalingState&&w(e)})))}),e.interval))}),(function(){b=!1,y=0}))}else b=!1}},w=function(e){if(e){var n=e.id,t=e.pc,o=e.prev;t.getStats(null).then((function(t){var i=l.map2obj(t),a=JSON.parse(JSON.stringify(i)),c=l.deltaCompression(o,i);null!==(null==c?void 0:c.timestamp)&&(null==c?void 0:c.timestamp)!==-1/0&&r("getstats",n,l.deltaCompression(e.prev,i)),e.prev=a}))}};n.initSDK=function(e,n){if(!window.watchRTCInitialized){window.watchRTCInitialized=!0;var t=0;if(m=new c.default({debug:null==e?void 0:e.debug}),h=new s.default({debug:null==e?void 0:e.debug}),v=e,r=m.trace,n.forEach((function(e){if(window[e+"RTCPeerConnection"]&&("webkit"!==e||!f)){var n=window[e+"RTCPeerConnection"],a=function(e,a){(null==e?void 0:e.watchrtc)&&(v=o(o({},v),e.watchrtc)),(null==v?void 0:v.debug)&&console.info.apply(console,i(l.logPrefix("info"),["new RTCPeerConnection called.",{config:e,constraints:a}]));var c=new n(e,a),s="PC_"+t++;return c.__rtcStatsId=s,p[s]={id:s,pc:c,validConnection:!1},e||(e={nullConfig:!0}),((e=JSON.parse(JSON.stringify(e)))&&e.iceServers||[]).forEach((function(e){delete e.credential})),(null==e?void 0:e.watchrtc)&&delete e.watchrtc,e.browserType=u?"moz":f?"edge":"webkit",r("create",s,e),a&&r("constraints",s,a),c.addEventListener("icecandidate",(function(e){r("onicecandidate",s,e.candidate)})),c.addEventListener("addstream",(function(e){r("onaddstream",s,e.stream.id+" "+e.stream.getTracks().map((function(e){return e.kind+":"+e.id})))})),c.addEventListener("track",(function(e){r("ontrack",s,e.track.kind+":"+e.track.id+" "+e.streams.map((function(e){return"stream:"+e.id})))})),c.addEventListener("removestream",(function(e){r("onremovestream",s,e.stream.id+" "+e.stream.getTracks().map((function(e){return e.kind+":"+e.id})))})),c.addEventListener("signalingstatechange",(function(){p[s]&&!p[s].validConnection&&(p[s].validConnection=!0,setTimeout((function(){C(!0)}),5e3)),r("onsignalingstatechange",s,c.signalingState)})),c.addEventListener("iceconnectionstatechange",(function(){r("oniceconnectionstatechange",s,c.iceConnectionState)})),c.addEventListener("icegatheringstatechange",(function(){r("onicegatheringstatechange",s,c.iceGatheringState)})),c.addEventListener("connectionstatechange",(function(){r("onconnectionstatechange",s,c.connectionState)})),c.addEventListener("negotiationneeded",(function(){r("onnegotiationneeded",s,void 0)})),c.addEventListener("datachannel",(function(e){r("ondatachannel",s,[e.channel.id,e.channel.label])})),f||c.addEventListener("iceconnectionstatechange",(function(){"connected"===c.iceConnectionState&&w(p[s])})),c};["createDataChannel"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){return r(e,this.__rtcStatsId,arguments),t.apply(this,arguments)})})),["close"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){return r(e,this.__rtcStatsId,arguments),delete p[this.__rtcStatsId],t.apply(this,arguments)})})),["addStream","removeStream"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){var n=arguments[0],o=n.getTracks().map((function(e){return e.kind+":"+e.id})).join(",");return r(e,this.__rtcStatsId,n.id+" "+o),t.apply(this,arguments)})})),["addTrack"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){var n=arguments[0],o=[].slice.call(arguments,1);return r(e,this.__rtcStatsId,n.kind+":"+n.id+" "+(o.map((function(e){return"stream:"+e.id})).join(";")||"-")),t.apply(this,arguments)})})),["removeTrack"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){var n=arguments[0].track;return r(e,this.__rtcStatsId,n?n.kind+":"+n.id:"null"),t.apply(this,arguments)})})),["createOffer","createAnswer"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){var n,o=this.__rtcStatsId,i=arguments;return 1===arguments.length&&"object"==typeof arguments[0]?n=arguments[0]:3===arguments.length&&"object"==typeof arguments[2]&&(n=arguments[2]),r(e,this.__rtcStatsId,n),t.apply(this,n?[n]:void 0).then((function(n){if(r(e+"OnSuccess",o,n),!(i.length>0&&"function"==typeof i[0]))return n;i[0].apply(null,[n])}),(function(n){if(r(e+"OnFailure",o,n.toString()),!(i.length>1&&"function"==typeof i[1]))throw n;i[1].apply(null,[n])}))})})),["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach((function(e){var t=n.prototype[e];t&&(n.prototype[e]=function(){var n=this.__rtcStatsId,o=arguments;return r(e,this.__rtcStatsId,o[0]),t.apply(this,[o[0]]).then((function(){r(e+"OnSuccess",n,void 0),o.length>=2&&"function"==typeof o[1]&&o[1].apply(null,[])}),(function(t){if(r(e+"OnFailure",n,t.toString()),!(o.length>=3&&"function"==typeof o[2]))throw t;o[2].apply(null,[t])}))})})),n.generateCertificate&&Object.defineProperty(a,"generateCertificate",{get:function(){return arguments.length?n.generateCertificate.apply(null,arguments):n.generateCertificate}}),window[e+"RTCPeerConnection"]=a,window[e+"RTCPeerConnection"].prototype=n.prototype}})),n.forEach((function(e){var n=e+(e.length?"GetUserMedia":"getUserMedia");if(navigator[n]){var t=navigator[n].bind(navigator);navigator[n]=function(){r("getUserMedia",null,arguments[0]);var e=arguments[1],n=arguments[2];t(arguments[0],(function(n){r("getUserMediaOnSuccess",null,l.dumpStream(n)),e&&e(n)}),(function(e){r("getUserMediaOnFailure",null,e.name),n&&n(e)}))}.bind(navigator)}})),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){var a=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(){return r("navigator.mediaDevices.getUserMedia",null,arguments[0]),a.apply(navigator.mediaDevices,arguments).then((function(e){return r("navigator.mediaDevices.getUserMediaOnSuccess",null,l.dumpStream(e)),e}),(function(e){return r("navigator.mediaDevices.getUserMediaOnFailure",null,e.name),Promise.reject(e)}))}.bind(navigator.mediaDevices)}if(navigator.mediaDevices&&navigator.mediaDevices.getDisplayMedia){var d=navigator.mediaDevices.getDisplayMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getDisplayMedia=function(){return r("navigator.mediaDevices.getDisplayMedia",null,arguments[0]),d.apply(navigator.mediaDevices,arguments).then((function(e){return r("navigator.mediaDevices.getDisplayMediaOnSuccess",null,l.dumpStream(e)),e}),(function(e){return r("navigator.mediaDevices.getDisplayMediaOnFailure",null,e.name),Promise.reject(e)}))}.bind(navigator.mediaDevices)}}},n.setConfig=function(e){window.watchRTCInitialized?(void 0!==e.debug&&e.debug!==v.debug&&(null==m||m.toggleDebug(e.debug)),v=o(o({},v),e),C()):console.info.apply(console,i(l.logPrefix("error"),["SDK is not initialized. Use 'init' function fisrt."]))},n.addTags=function(e){var n;if(window.watchRTCInitialized)if(e&&Array.isArray(e)){var t=["rtcTags",null,{rtcTags:e}];(null===(n=null==m?void 0:m.connection)||void 0===n?void 0:n.readyState)===WebSocket.OPEN?r.apply(void 0,t):_.apply(void 0,t)}else console.info.apply(console,i(l.logPrefix("error"),["addTags excepts only array of strings"]));else console.info.apply(console,i(l.logPrefix("error"),["SDK is not initialized. Use 'init' function fisrt."]))},n.setUserRating=function(e,n){var t;if(window.watchRTCInitialized){if(l.validateRating(e)){var o=["userRating",null,{rating:e,ratingComment:n}];(null===(t=null==m?void 0:m.connection)||void 0===t?void 0:t.readyState)===WebSocket.OPEN?r.apply(void 0,o):_.apply(void 0,o)}}else console.info.apply(console,i(l.logPrefix("error"),["SDK is not initialized. Use 'init' function fisrt."]))},n.disableDataCollection=function(){window.watchRTCInitialized?null==m||m.disableDataCollection():console.info.apply(console,i(l.logPrefix("error"),["SDK is not initialized. Use 'init' function fisrt."]))},n.enableDataCollection=function(){window.watchRTCInitialized?null==m||m.enableDataCollection():console.info.apply(console,i(l.logPrefix("error"),["SDK is not initialized. Use 'init' function fisrt."]))};var _=function(){for(var e=[],n=0;n<arguments.length;n++)e[n]=arguments[n];if(g.rtcRoomId&&g.rtcPeerId&&g.projectId){var t=l.getConnectionData("http",v.rtcApiKey);null==h||h.trace.apply(h,i([t.url+"/trace",g.projectId,g.rtcRoomId,g.rtcPeerId],e))}else console.log.apply(console,i(l.logPrefix("info"),["Cannot do http trace before connection established"]))}},699:(e,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0})},593:function(e,n){"use strict";var t=this&&this.__spreadArrays||function(){for(var e=0,n=0,t=arguments.length;n<t;n++)e+=arguments[n].length;var o=Array(e),i=0;for(n=0;n<t;n++)for(var r=arguments[n],a=0,c=r.length;a<c;a++,i++)o[i]=r[a];return o};Object.defineProperty(n,"__esModule",{value:!0}),n.validateRating=n.isRoomIdOrPeerIdChanged=n.countOfValidConnections=n.validateConfig=n.getConnectionData=n.dumpStream=n.map2obj=n.mangleChromeStats=n.deltaCompression=n.logPrefix=void 0,n.logPrefix=function(e){return void 0===e&&(e="info"),"error"===e?["%cwatchRTC %cERROR","background: gold; color: black; padding: 2px 0.5em; border-radius: 0.5em;","background: red; color: white; padding: 2px 0.5em; border-radius: 0.5em;"]:["%cwatchRTC","background: gold; color: black; padding: 2px 0.5em; border-radius: 0.5em;"]},n.deltaCompression=function(e,n){e=e||{},n=n||{},n=JSON.parse(JSON.stringify(n)),Object.keys(n).forEach((function(t){var o=n[t];delete o.id,e[t]&&Object.keys(o).forEach((function(i){o[i]===e[t][i]&&delete n[t][i],(0===Object.keys(o).length||1===Object.keys(o).length&&o.timestamp)&&delete n[t]}))}));var t=-1/0;return Object.keys(n).forEach((function(e){var o=n[e];o.timestamp>t&&(t=o.timestamp)})),Object.keys(n).forEach((function(e){var o=n[e];o.timestamp===t&&(o.timestamp=0)})),n.timestamp=t,n},n.mangleChromeStats=function(e,n){var t={};return n.result().forEach((function(e){var n={id:e.id,timestamp:e.timestamp.getTime(),type:e.type};e.names().forEach((function(t){n[t]=e.stat(t)})),t[n.id]=n})),t},n.map2obj=function(e){if(!e.entries)return e;var n={};return e.forEach((function(e,t){n[t]=e})),n},n.dumpStream=function(e){return{id:e.id,tracks:e.getTracks().map((function(e){return{id:e.id,kind:e.kind,label:e.label,enabled:e.enabled,muted:e.muted,readyState:e.readyState}}))}},n.getConnectionData=function(e,n,t){var o=("ws"==e?"ws":"http")+"://localhost:9101",i=("ws"==e?"wss":"https")+"://watchrtc-staging2.testrtc.com",r=("ws"==e?"wss":"https")+"://watchrtc.testrtc.com",a=n.split(":");return-1!==n.indexOf("local")?{url:t||o,key:a[1]}:-1!==n.indexOf("staging")?{url:t||i,key:a[1]}:-1!==n.indexOf("production")?{url:t||r,key:a[1]}:{url:t||r,key:a[0]}},n.validateConfig=function(e){return!(null==e?void 0:e.rtcApiKey)&&(null==e?void 0:e.debug)?(console.info.apply(console,t(n.logPrefix("error"),["config.rtcApiKey or config.rtcToken need to be provided."])),!1):!(!(null==e?void 0:e.rtcRoomId)||!(null==e?void 0:e.rtcPeerId))||((null==e?void 0:e.debug)&&console.info.apply(console,t(n.logPrefix("info"),["rtcRoomId or rtcPeerId is empty."])),!1)},n.countOfValidConnections=function(e){return Object.keys(e).filter((function(n){return e[n].validConnection})).length},n.isRoomIdOrPeerIdChanged=function(e,o){var i=!1;return o.rtcRoomId&&e.rtcRoomId&&e.rtcRoomId!==o.rtcRoomId&&(i=!0),o.rtcPeerId&&e.rtcPeerId&&e.rtcPeerId!==o.rtcPeerId&&(i=!0),i&&o.debug&&console.log.apply(console,t(n.logPrefix("info"),["maybeOpenWebsocketConnection. rtcRoomId or rtcPeerId has been changed",{old:{rtcRoomId:e.rtcRoomId,rtcPeerId:e.rtcPeerId},new:{rtcRoomId:o.rtcRoomId,rtcPeerId:o.rtcPeerId}}])),i},n.validateRating=function(e){return e?!("number"!=typeof e||e<1&&e>5)||(console.info.apply(console,t(n.logPrefix("error"),["rating parameter should be number from 1 to 5"])),!1):(console.info.apply(console,t(n.logPrefix("error"),["rating parameter is required"])),!1)}},412:(e,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.default="1.29.2"},911:function(e,n,t){"use strict";var o=this&&this.__spreadArrays||function(){for(var e=0,n=0,t=arguments.length;n<t;n++)e+=arguments[n].length;var o=Array(e),i=0;for(n=0;n<t;n++)for(var r=arguments[n],a=0,c=r.length;a<c;a++,i++)o[i]=r[a];return o};Object.defineProperty(n,"__esModule",{value:!0});var i=t(593),r=function(){function e(n){this.debug=!1,e._instance?console.info.apply(console,o(i.logPrefix("info"),["WatchRTCSocket instance already created"])):(e._instance=this,this.debug=!!n.debug)}return e.prototype.trace=function(e,n,t,r){for(var a=[],c=4;c<arguments.length;c++)a[c-4]=arguments[c];var s=Array.prototype.slice.call(a);s.push(Date.now()),s[1]instanceof RTCPeerConnection&&(s[1]=s[1].__rtcStatsId);var l=fetch(e,{method:"POST",mode:"cors",cache:"no-cache",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({data:a,projectId:n,rtcRoomId:t,rtcPeerId:r})});l.then().catch((function(e){return console.log.apply(console,o(i.logPrefix("error"),[e.message,{err:e.stack}]))}))},e}();n.default=r},85:function(e,n,t){"use strict";var o=this&&this.__spreadArrays||function(){for(var e=0,n=0,t=arguments.length;n<t;n++)e+=arguments[n].length;var o=Array(e),i=0;for(n=0;n<t;n++)for(var r=arguments[n],a=0,c=r.length;a<c;a++,i++)o[i]=r[a];return o};Object.defineProperty(n,"__esModule",{value:!0});var i=t(593),r=t(354),a=function(){function e(n){this.connection=null,this.buffer=[],this.sendInterval=1,this.onClose=function(){},this.debug=!1,this.dataCollection=!0,e._instance?console.info.apply(console,o(i.logPrefix("info"),["WatchRTCSocket instance already created"])):(e._instance=this,this.debug=!!n.debug)}return e.prototype.connect=function(n,t,r){e._instance.connection&&e._instance.connection.close();var a=e._instance;e._instance.connection=new WebSocket(n,"2.0"),e._instance.connection.onopen=function(e){},e._instance.connection.onclose=function(e){},e._instance.connection.onmessage=function(n){var c;try{var s=JSON.parse(n.data);s.error?(null===(c=null==a?void 0:a.connection)||void 0===c||c.close(),a.connection=null,console.info.apply(console,o(i.logPrefix("error"),["\n"+s.error])),r(s.error)):(s.sendInterval&&(e._instance.sendInterval=s.sendInterval),t(s))}catch(e){console.info.apply(console,o(i.logPrefix("error"),[{err:e.stack}])),r(e.message)}},e._instance.connection.onerror=function(e){console.info.apply(console,o(i.logPrefix("error"),["\n",e])),r(e)}},e.prototype.trace=function(){for(var n=[],t=0;t<arguments.length;t++)n[t]=arguments[t];var a=Array.prototype.slice.call(n);if(a.push(Date.now()),a[1]instanceof RTCPeerConnection&&(a[1]=a[1].__rtcStatsId),e._instance.dataCollection)if(e._instance.connection){if(e._instance.connection.readyState===WebSocket.OPEN&&(e._instance.buffer.push(a),e._instance.buffer.length>=e._instance.sendInterval)){var c=JSON.stringify(e._instance.buffer),s=r.compressToEncodedURIComponent(c);e._instance.debug&&(console.log.apply(console,o(i.logPrefix("info"),["lines: "+c.length])),console.log.apply(console,o(i.logPrefix("info"),["compressedMessage: "+s.length]))),e._instance.buffer=[],e._instance.connection.send(s)}}else{if(e._instance.buffer.length>1e3)return;e._instance.buffer.push(a)}},e.prototype.close=function(){e._instance.buffer=[],e._instance.connection&&(e._instance.connection.close(),e._instance.onClose(),e._instance.connection=null)},e.prototype.disableDataCollection=function(){e._instance.debug&&console.log.apply(console,o(i.logPrefix("info"),["Data collection disabled."])),e._instance.dataCollection=!1},e.prototype.enableDataCollection=function(){e._instance.debug&&console.log.apply(console,o(i.logPrefix("info"),["Data collection enabled."])),e._instance.dataCollection=!0},e.prototype.toggleDebug=function(n){e._instance.debug=n},e}();n.default=a},354:(e,n,t)=>{var o,i=function(){function e(e,n){if(!i[e]){i[e]={};for(var t=0;t<e.length;t++)i[e][e.charAt(t)]=t}return i[e][n]}var n=String.fromCharCode,t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",i={},r={compressToBase64:function(e){if(null==e)return"";var n=r._compress(e,6,(function(e){return t.charAt(e)}));switch(n.length%4){default:case 0:return n;case 1:return n+"===";case 2:return n+"==";case 3:return n+"="}},decompressFromBase64:function(n){return null==n?"":""==n?null:r._decompress(n.length,32,(function(o){return e(t,n.charAt(o))}))},compressToUTF16:function(e){return null==e?"":r._compress(e,15,(function(e){return n(e+32)}))+" "},decompressFromUTF16:function(e){return null==e?"":""==e?null:r._decompress(e.length,16384,(function(n){return e.charCodeAt(n)-32}))},compressToUint8Array:function(e){for(var n=r.compress(e),t=new Uint8Array(2*n.length),o=0,i=n.length;i>o;o++){var a=n.charCodeAt(o);t[2*o]=a>>>8,t[2*o+1]=a%256}return t},decompressFromUint8Array:function(e){if(null==e)return r.decompress(e);for(var t=new Array(e.length/2),o=0,i=t.length;i>o;o++)t[o]=256*e[2*o]+e[2*o+1];var a=[];return t.forEach((function(e){a.push(n(e))})),r.decompress(a.join(""))},compressToEncodedURIComponent:function(e){return null==e?"":r._compress(e,6,(function(e){return o.charAt(e)}))},decompressFromEncodedURIComponent:function(n){return null==n?"":""==n?null:(n=n.replace(/ /g,"+"),r._decompress(n.length,32,(function(t){return e(o,n.charAt(t))})))},compress:function(e){return r._compress(e,16,(function(e){return n(e)}))},_compress:function(e,n,t){if(null==e)return"";var o,i,r,a={},c={},s="",l="",d="",u=2,f=3,p=2,g=[],v=0,h=0;for(r=0;r<e.length;r+=1)if(s=e.charAt(r),Object.prototype.hasOwnProperty.call(a,s)||(a[s]=f++,c[s]=!0),l=d+s,Object.prototype.hasOwnProperty.call(a,l))d=l;else{if(Object.prototype.hasOwnProperty.call(c,d)){if(d.charCodeAt(0)<256){for(o=0;p>o;o++)v<<=1,h==n-1?(h=0,g.push(t(v)),v=0):h++;for(i=d.charCodeAt(0),o=0;8>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1}else{for(i=1,o=0;p>o;o++)v=v<<1|i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i=0;for(i=d.charCodeAt(0),o=0;16>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1}0==--u&&(u=Math.pow(2,p),p++),delete c[d]}else for(i=a[d],o=0;p>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1;0==--u&&(u=Math.pow(2,p),p++),a[l]=f++,d=String(s)}if(""!==d){if(Object.prototype.hasOwnProperty.call(c,d)){if(d.charCodeAt(0)<256){for(o=0;p>o;o++)v<<=1,h==n-1?(h=0,g.push(t(v)),v=0):h++;for(i=d.charCodeAt(0),o=0;8>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1}else{for(i=1,o=0;p>o;o++)v=v<<1|i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i=0;for(i=d.charCodeAt(0),o=0;16>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1}0==--u&&(u=Math.pow(2,p),p++),delete c[d]}else for(i=a[d],o=0;p>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1;0==--u&&(u=Math.pow(2,p),p++)}for(i=2,o=0;p>o;o++)v=v<<1|1&i,h==n-1?(h=0,g.push(t(v)),v=0):h++,i>>=1;for(;;){if(v<<=1,h==n-1){g.push(t(v));break}h++}return g.join("")},decompress:function(e){return null==e?"":""==e?null:r._decompress(e.length,32768,(function(n){return e.charCodeAt(n)}))},_decompress:function(e,t,o){var i,r,a,c,s,l,d,u=[],f=4,p=4,g=3,v="",h=[],m={val:o(0),position:t,index:1};for(i=0;3>i;i+=1)u[i]=i;for(a=0,s=Math.pow(2,2),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;switch(a){case 0:for(a=0,s=Math.pow(2,8),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;d=n(a);break;case 1:for(a=0,s=Math.pow(2,16),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;d=n(a);break;case 2:return""}for(u[3]=d,r=d,h.push(d);;){if(m.index>e)return"";for(a=0,s=Math.pow(2,g),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;switch(d=a){case 0:for(a=0,s=Math.pow(2,8),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;u[p++]=n(a),d=p-1,f--;break;case 1:for(a=0,s=Math.pow(2,16),l=1;l!=s;)c=m.val&m.position,m.position>>=1,0==m.position&&(m.position=t,m.val=o(m.index++)),a|=(c>0?1:0)*l,l<<=1;u[p++]=n(a),d=p-1,f--;break;case 2:return h.join("")}if(0==f&&(f=Math.pow(2,g),g++),u[d])v=u[d];else{if(d!==p)return null;v=r+r.charAt(0)}h.push(v),u[p++]=r+v.charAt(0),r=v,0==--f&&(f=Math.pow(2,g),g++)}}};return r}();void 0===(o=function(){return i}.call(n,t,n,e))||(e.exports=o)}},n={},function t(o){if(n[o])return n[o].exports;var i=n[o]={exports:{}};return e[o].call(i.exports,i,i.exports,t),i.exports}(607)).default;var e,n}));
//# sourceMappingURL=index.js.map

@@ -10,2 +10,3 @@ export interface RTCPeerConnectionInformation {

rtcPeerId: string | undefined;
projectId: string | undefined;
}

@@ -27,2 +28,2 @@ export interface IWatchRTCConfiguration {

}
export declare type Rate = 1 | 2 | 3 | 4 | 5;
export declare type Rating = 1 | 2 | 3 | 4 | 5;

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

import { IWatchRTCConfiguration } from "./interfaces";
import { IWatchRTCConfiguration, Rating } from "./interfaces";
/**

@@ -14,3 +14,9 @@ * Initialize SDK.

export declare const addTags: (rtcTags?: string[] | undefined) => void;
/**
* Set user rating and/or comment for peer session
* @param rating number from 1 to 5
* @param comment string
*/
export declare const setUserRating: (rating: Rating, ratingComment?: string | undefined) => void;
export declare const disableDataCollection: () => void;
export declare const enableDataCollection: () => void;

@@ -21,141 +21,129 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.setUserRating = exports.initSDK = void 0;
exports.enableDataCollection = exports.disableDataCollection = exports.setUserRating = exports.addTags = exports.setConfig = exports.initSDK = void 0;
var watchrtcsocket_1 = require("./watchrtcsocket");
var watchrtchttp_1 = require("./watchrtchttp");
var utils_1 = require("./utils");
var version_1 = require("./version");
var utils_1 = require("./utils");
var standardGetstats = true;
// transforms a maplike to an object. Mostly for getStats +
// JSON.parse(JSON.stringify())
var map2obj = function (m) {
if (!m.entries) {
return m;
}
var o = {};
m.forEach(function (v, k) {
o[k] = v;
});
return o;
var isFirefox = !!window.mozRTCPeerConnection;
var isEdge = !!window.RTCIceGatherer;
var isSafari = !isFirefox && window.RTCPeerConnection && !window.navigator.webkitGetUserMedia;
// Data structure for RTCPeerConnection related stuff we need
var openChannels = {};
var watchrtcIdentifiers = {
rtcRoomId: undefined,
rtcPeerId: undefined,
projectId: undefined,
};
// apply a delta compression to the stats report. Reduces size by ~90%.
// To reduce further, report keys could be compressed.
var deltaCompression = function (oldStats, newStats) {
oldStats = oldStats || {};
newStats = newStats || {};
newStats = JSON.parse(JSON.stringify(newStats));
Object.keys(newStats).forEach(function (id) {
var report = newStats[id];
delete report.id;
if (!oldStats[id]) {
var watchrtcConfig = null;
var http = null;
var socket = null;
var trace;
var lastConnectionOpen = 0; // so we know when was the last active connection seen
var getStatsInterval;
var tryingToConnectSocket = false;
var maybeOpenWebsocketConnection = function (forceRecreate) {
var _a;
if (forceRecreate === void 0) { forceRecreate = false; }
var opened = ((_a = socket === null || socket === void 0 ? void 0 : socket.connection) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN;
if (opened) {
var roomIdOrPeerIdChanged = utils_1.isRoomIdOrPeerIdChanged(watchrtcIdentifiers, watchrtcConfig);
if (roomIdOrPeerIdChanged && forceRecreate) {
if (watchrtcConfig === null || watchrtcConfig === void 0 ? void 0 : watchrtcConfig.debug) {
console.log.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["maybeOpenWebsocketConnection. Closing WS connection"]));
}
socket === null || socket === void 0 ? void 0 : socket.close();
}
else {
if (watchrtcConfig === null || watchrtcConfig === void 0 ? void 0 : watchrtcConfig.debug) {
console.log.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["maybeOpenWebsocketConnection. WS connection already opened"]));
}
return;
}
Object.keys(report).forEach(function (name) {
if (report[name] === oldStats[id][name]) {
delete newStats[id][name];
}
var connectionCount = utils_1.countOfValidConnections(openChannels);
if (connectionCount > 0 && !tryingToConnectSocket) {
var canConnect = utils_1.validateConfig(watchrtcConfig);
var id_1 = Object.keys(openChannels)[connectionCount - 1]; // not very critical, but for consistency with trace
if (canConnect) {
if (watchrtcConfig.rtcTags) {
if (!Array.isArray(watchrtcConfig.rtcTags)) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["config.rtcTags must be an array."]));
watchrtcConfig.rtcTags = undefined;
}
else if (watchrtcConfig.rtcTags.some(function (x) { return x.includes(","); })) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["To apply multiple tags please use an array and not comma separated values."]));
}
}
if (Object.keys(report).length === 0) {
delete newStats[id];
}
else if (Object.keys(report).length === 1 && report.timestamp) {
delete newStats[id];
}
});
});
var timestamp = -Infinity;
Object.keys(newStats).forEach(function (id) {
var report = newStats[id];
if (report.timestamp > timestamp) {
timestamp = report.timestamp;
var useToken = !!watchrtcConfig.rtcToken;
var wsConnectionData = utils_1.getConnectionData("ws", useToken ? watchrtcConfig.rtcToken : watchrtcConfig.rtcApiKey, watchrtcConfig.proxyUrl || watchrtcConfig.wsUrl);
tryingToConnectSocket = true;
lastConnectionOpen = Date.now();
socket === null || socket === void 0 ? void 0 : socket.connect(wsConnectionData.url + "?" + (useToken ? "token" : "apiKey") + "=" + wsConnectionData.key + "&timestamp=" + Date.now(), function (data) {
watchrtcIdentifiers.rtcRoomId = watchrtcConfig.rtcRoomId;
watchrtcIdentifiers.rtcPeerId = watchrtcConfig.rtcPeerId;
watchrtcIdentifiers.projectId = data.projectId;
tryingToConnectSocket = false;
console.info.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["Connection established. watchRTCConnectionId: " + data.connectionId + " sdkVersion:" + version_1.default]));
trace("watchrtc", id_1, __assign(__assign(__assign({}, watchrtcConfig), data), { sdkVersion: version_1.default }));
if (!isEdge) {
window.clearInterval(getStatsInterval);
getStatsInterval = window.setInterval(function () {
if (utils_1.countOfValidConnections(openChannels) === 0) {
// if we don't have any connection for 20 sec we can close the socket
if (lastConnectionOpen && lastConnectionOpen + 20000 < Date.now()) {
window.clearInterval(getStatsInterval);
socket === null || socket === void 0 ? void 0 : socket.close();
console.info.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["Last connection closed. watchRTCConnectionId: " + data.connectionId + " sdkVersion: " + version_1.default]));
}
}
else {
lastConnectionOpen = Date.now();
Object.values(openChannels).forEach(function (pcInfo) {
if (pcInfo.pc.signalingState !== "closed") {
getStats(pcInfo);
}
});
}
}, data.interval);
}
}, function () {
tryingToConnectSocket = false;
lastConnectionOpen = 0;
});
}
});
Object.keys(newStats).forEach(function (id) {
var report = newStats[id];
if (report.timestamp === timestamp) {
report.timestamp = 0;
else {
tryingToConnectSocket = false;
}
});
newStats.timestamp = timestamp;
return newStats;
};
var mangleChromeStats = function (pc, response) {
var standardReport = {};
var reports = response.result();
reports.forEach(function (report) {
var standardStats = {
id: report.id,
timestamp: report.timestamp.getTime(),
type: report.type,
};
report.names().forEach(function (name) {
standardStats[name] = report.stat(name);
});
standardReport[standardStats.id] = standardStats;
});
return standardReport;
};
var dumpStream = function (stream) {
return {
id: stream.id,
tracks: stream.getTracks().map(function (track) {
return {
id: track.id,
kind: track.kind,
label: track.label,
enabled: track.enabled,
muted: track.muted,
readyState: track.readyState,
};
}),
};
};
var getWSConnectionData = function (rtcApiKey, overriddenWsUrl) {
var localUrl = "ws://localhost:9101";
var stagingUrl = "wss://watchrtc-staging2.testrtc.com";
var productionUrl = "wss://watchrtc.testrtc.com";
var splitted = rtcApiKey.split(":");
if (rtcApiKey.indexOf("local") !== -1) {
return {
url: overriddenWsUrl || localUrl,
apiKey: splitted[1],
};
}
else if (rtcApiKey.indexOf("staging") !== -1) {
return {
url: overriddenWsUrl || stagingUrl,
apiKey: splitted[1],
};
}
else if (rtcApiKey.indexOf("production") !== -1) {
return {
url: overriddenWsUrl || productionUrl,
apiKey: splitted[1],
};
}
else {
return {
url: overriddenWsUrl || productionUrl,
apiKey: splitted[0],
};
}
};
var validateConfig = function (config) {
if (!config) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["config is required."]));
return false;
var getStats = function (pcInfo) {
if (pcInfo) {
var id_2 = pcInfo.id, pc_1 = pcInfo.pc, prev_1 = pcInfo.prev;
if (standardGetstats || isFirefox || isSafari) {
pc_1.getStats(null).then(function (res) {
var now = utils_1.map2obj(res);
var base = JSON.parse(JSON.stringify(now)); // our new prev
var data = utils_1.deltaCompression(prev_1, now);
if ((data === null || data === void 0 ? void 0 : data.timestamp) !== null && (data === null || data === void 0 ? void 0 : data.timestamp) !== -Infinity) {
trace("getstats", id_2, utils_1.deltaCompression(pcInfo.prev, now));
}
pcInfo.prev = base;
});
}
else {
pc_1.getStats(function (res) {
var now = utils_1.mangleChromeStats(pc_1, res);
var base = JSON.parse(JSON.stringify(now)); // our new prev
var data = utils_1.deltaCompression(prev_1, now);
if ((data === null || data === void 0 ? void 0 : data.timestamp) !== null && (data === null || data === void 0 ? void 0 : data.timestamp) !== -Infinity) {
trace("getstats", id_2, utils_1.deltaCompression(prev_1, now));
}
pcInfo.prev = base;
});
}
}
else if (!config.rtcApiKey) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["config.rtcApiKey is required."]));
return false;
}
else if (!config.rtcRoomId) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["config.rtcRoomId is required."]));
return false;
}
else if (!config.rtcPeerId) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["config.rtcPeerId is required."]));
return false;
}
return true;
};
/**
* Initialize SDK. Can be called multiple times but it will be initialized only at the first time.
* Initialize SDK.
* @param watchrtc

@@ -173,89 +161,6 @@ * @param prefixesToWrap

var peerconnectioncounter = 0;
var watchrtcConfig = null;
var lastConnectionOpen = 0; // so we know when was the last active connection seen
var getStatsInterval;
var tryingToConnectSocket = false;
var socket = new watchrtcsocket_1.default();
var trace = socket.trace;
// Data structure for RTCPeerConnection related stuff we need
var openChannels = {};
var isFirefox = !!window.mozRTCPeerConnection;
var isEdge = !!window.RTCIceGatherer;
var isSafari = !isFirefox && window.RTCPeerConnection && !window.navigator.webkitGetUserMedia;
var countOfValidConnections = function () {
return Object.keys(openChannels).filter(function (id) { return openChannels[id].validConnection; }).length;
};
var maybeOpenWebsocketConnection = function () {
var connectionCount = countOfValidConnections();
if (connectionCount > 0 && !tryingToConnectSocket) {
tryingToConnectSocket = true;
var canConnect = validateConfig(watchrtcConfig);
// not very critical, but for consistency with trace
var id_1 = Object.keys(openChannels)[connectionCount - 1];
if (canConnect) {
if (watchrtcConfig.rtcTags && !Array.isArray(watchrtcConfig.rtcTags)) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["config.rtcTags must be an array."]));
watchrtcConfig.rtcTags = undefined;
}
var wsConnectionData = getWSConnectionData(watchrtcConfig.rtcApiKey, watchrtcConfig.proxyUrl || watchrtcConfig.wsUrl);
lastConnectionOpen = Date.now();
socket.connect(wsConnectionData.url + "?apiKey=" + wsConnectionData.apiKey + "&timestamp=" + Date.now(), function (data) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["Connection established. watchRTCConnectionId: " + data.connectionId + " sdkVersion:" + version_1.default]));
trace("watchrtc", id_1, __assign(__assign(__assign({}, watchrtcConfig), data), { sdkVersion: version_1.default }));
if (!isEdge) {
window.clearInterval(getStatsInterval);
getStatsInterval = window.setInterval(function () {
if (countOfValidConnections() === 0) {
// if we don't have any connection for 20 sec we can close the socket
if (lastConnectionOpen && lastConnectionOpen + 20000 < Date.now()) {
tryingToConnectSocket = false;
window.clearInterval(getStatsInterval);
socket.close();
console.info.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["Last connection closed. watchRTCConnectionId: " + data.connectionId + " sdkVersion: " + version_1.default]));
}
}
else {
lastConnectionOpen = Date.now();
Object.values(openChannels).forEach(function (pcInfo) {
if (pcInfo.pc.signalingState !== "closed") {
getStats(pcInfo);
}
});
}
}, data.interval);
}
}, function () {
tryingToConnectSocket = false;
lastConnectionOpen = 0;
});
}
}
};
var getStats = function (pcInfo) {
if (pcInfo) {
var id_2 = pcInfo.id, pc_1 = pcInfo.pc, prev_1 = pcInfo.prev;
if (standardGetstats || isFirefox || isSafari) {
pc_1.getStats(null).then(function (res) {
var now = map2obj(res);
var base = JSON.parse(JSON.stringify(now)); // our new prev
var data = deltaCompression(prev_1, now);
if ((data === null || data === void 0 ? void 0 : data.timestamp) !== null && (data === null || data === void 0 ? void 0 : data.timestamp) !== -Infinity) {
trace("getstats", id_2, deltaCompression(pcInfo.prev, now));
}
pcInfo.prev = base;
});
}
else {
pc_1.getStats(function (res) {
var now = mangleChromeStats(pc_1, res);
var base = JSON.parse(JSON.stringify(now)); // our new prev
var data = deltaCompression(prev_1, now);
if ((data === null || data === void 0 ? void 0 : data.timestamp) !== null && (data === null || data === void 0 ? void 0 : data.timestamp) !== -Infinity) {
trace("getstats", id_2, deltaCompression(prev_1, now));
}
pcInfo.prev = base;
});
}
}
};
socket = new watchrtcsocket_1.default({ debug: watchrtc === null || watchrtc === void 0 ? void 0 : watchrtc.debug });
http = new watchrtchttp_1.default({ debug: watchrtc === null || watchrtc === void 0 ? void 0 : watchrtc.debug });
watchrtcConfig = watchrtc;
trace = socket.trace;
prefixesToWrap.forEach(function (prefix) {

@@ -271,2 +176,11 @@ if (!window[prefix + "RTCPeerConnection"]) {

var peerconnection = function (config, constraints) {
if (config === null || config === void 0 ? void 0 : config.watchrtc) {
watchrtcConfig = __assign(__assign({}, watchrtcConfig), config.watchrtc);
}
if (watchrtcConfig === null || watchrtcConfig === void 0 ? void 0 : watchrtcConfig.debug) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["new RTCPeerConnection called.", {
config: config,
constraints: constraints,
}]));
}
var pc = new origPeerConnection(config, constraints);

@@ -280,3 +194,2 @@ var id = "PC_" + peerconnectioncounter++;

};
watchrtcConfig = watchrtc || (config === null || config === void 0 ? void 0 : config.watchrtc);
if (!config) {

@@ -337,3 +250,5 @@ config = { nullConfig: true };

openChannels[id].validConnection = true;
setTimeout(maybeOpenWebsocketConnection, 5000);
setTimeout(function () {
maybeOpenWebsocketConnection(true);
}, 5000);
}

@@ -366,3 +281,3 @@ trace("onsignalingstatechange", id, pc.signalingState);

};
["createDataChannel", "close"].forEach(function (method) {
["createDataChannel"].forEach(function (method) {
var nativeMethod = origPeerConnection.prototype[method];

@@ -372,2 +287,11 @@ if (nativeMethod) {

trace(method, this.__rtcStatsId, arguments);
return nativeMethod.apply(this, arguments);
};
}
});
["close"].forEach(function (method) {
var nativeMethod = origPeerConnection.prototype[method];
if (nativeMethod) {
origPeerConnection.prototype[method] = function () {
trace(method, this.__rtcStatsId, arguments);
delete openChannels[this.__rtcStatsId];

@@ -507,3 +431,3 @@ return nativeMethod.apply(this, arguments);

// to acquire the cam (in chrome)
trace("getUserMediaOnSuccess", null, dumpStream(stream));
trace("getUserMediaOnSuccess", null, utils_1.dumpStream(stream));
if (cb) {

@@ -526,3 +450,3 @@ cb(stream);

return origGetUserMedia_1.apply(navigator.mediaDevices, arguments).then(function (stream) {
trace("navigator.mediaDevices.getUserMediaOnSuccess", null, dumpStream(stream));
trace("navigator.mediaDevices.getUserMediaOnSuccess", null, utils_1.dumpStream(stream));
return stream;

@@ -542,3 +466,3 @@ }, function (err) {

return origGetDisplayMedia_1.apply(navigator.mediaDevices, arguments).then(function (stream) {
trace("navigator.mediaDevices.getDisplayMediaOnSuccess", null, dumpStream(stream));
trace("navigator.mediaDevices.getDisplayMediaOnSuccess", null, utils_1.dumpStream(stream));
return stream;

@@ -553,13 +477,102 @@ }, function (err) {

};
exports.setUserRating = function (rate, rateReason) {
exports.setConfig = function (newWatchrtcConfig) {
var initialized = window.watchRTCInitialized;
if (!initialized) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["SDK is not initialized. Use 'init' function fisrt."]));
return;
}
// if debug mode changed
// change it in socket service too
if (newWatchrtcConfig.debug !== undefined && newWatchrtcConfig.debug !== watchrtcConfig.debug) {
socket === null || socket === void 0 ? void 0 : socket.toggleDebug(newWatchrtcConfig.debug);
}
watchrtcConfig = __assign(__assign({}, watchrtcConfig), newWatchrtcConfig);
maybeOpenWebsocketConnection();
};
/**
* Add tags for peer session
* @param rtcTags[]
*/
exports.addTags = function (
/** ["tag1", "tag2", "tag3"] */
rtcTags) {
var _a;
if (rate) {
if (watchrtcsocket_1.default._instance &&
((_a = watchrtcsocket_1.default._instance.connection) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN) {
watchrtcsocket_1.default._instance.trace("userRating", "", { rate: rate, rateReason: rateReason });
}
else {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["Please set user rating before websocket connection is closed."]));
}
var initialized = window.watchRTCInitialized;
if (!initialized) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["SDK is not initialized. Use 'init' function fisrt."]));
return;
}
if (!rtcTags || !Array.isArray(rtcTags)) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["addTags excepts only array of strings"]));
return;
}
var opened = ((_a = socket === null || socket === void 0 ? void 0 : socket.connection) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN;
var data = ["rtcTags", null, { rtcTags: rtcTags }];
if (opened) {
trace.apply(void 0, data);
}
else {
httpTrace.apply(void 0, data);
}
};
/**
* Set user rating and/or comment for peer session
* @param rating number from 1 to 5
* @param comment string
*/
exports.setUserRating = function (
/** 1 | 2 | 3 | 4 | 5 */
rating, ratingComment) {
var _a;
var initialized = window.watchRTCInitialized;
if (!initialized) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["SDK is not initialized. Use 'init' function fisrt."]));
return;
}
var isValidRating = utils_1.validateRating(rating);
if (!isValidRating) {
return;
}
var opened = ((_a = socket === null || socket === void 0 ? void 0 : socket.connection) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN;
var data = ["userRating", null, { rating: rating, ratingComment: ratingComment }];
if (opened) {
trace.apply(void 0, data);
}
else {
httpTrace.apply(void 0, data);
}
};
exports.disableDataCollection = function () {
var initialized = window.watchRTCInitialized;
if (!initialized) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["SDK is not initialized. Use 'init' function fisrt."]));
return;
}
socket === null || socket === void 0 ? void 0 : socket.disableDataCollection();
};
exports.enableDataCollection = function () {
var initialized = window.watchRTCInitialized;
if (!initialized) {
console.info.apply(console, __spreadArrays(utils_1.logPrefix("error"), ["SDK is not initialized. Use 'init' function fisrt."]));
return;
}
socket === null || socket === void 0 ? void 0 : socket.enableDataCollection();
};
var httpTrace = function () {
var data = [];
for (var _i = 0; _i < arguments.length; _i++) {
data[_i] = arguments[_i];
}
if (!watchrtcIdentifiers.rtcRoomId ||
!watchrtcIdentifiers.rtcPeerId ||
!watchrtcIdentifiers.projectId) {
console.log.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["Cannot do http trace before connection established"]));
return;
}
var httpConnectionData = utils_1.getConnectionData("http", watchrtcConfig.rtcApiKey);
http === null || http === void 0 ? void 0 : http.trace.apply(http, __spreadArrays([httpConnectionData.url + "/trace", watchrtcIdentifiers.projectId,
watchrtcIdentifiers.rtcRoomId,
watchrtcIdentifiers.rtcPeerId], data));
};
// (window as any).setUserRating = setUserRating;
// (window as any).addTags = addTags;

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

import { IWatchRTCConfiguration, IWatchrtcIdentifiers, RTCPeerConnectionInformation } from "./interfaces";
import { IWatchRTCConfiguration, IWatchrtcIdentifiers, Rating, RTCPeerConnectionInformation } from "./interfaces";
export declare const logPrefix: (type?: "error" | "info") => string[];

@@ -10,3 +10,3 @@ export declare const deltaCompression: (oldStats: any, newStats: any) => any;

};
export declare const getWSConnectionData: (key: string, overriddenWsUrl?: string | undefined) => {
export declare const getConnectionData: (type: "ws" | "http", key: string, overriddenWsUrl?: string | undefined) => {
url: string;

@@ -20,1 +20,2 @@ key: string;

export declare const isRoomIdOrPeerIdChanged: (watchrtcIdentifiers: IWatchrtcIdentifiers, watchrtcConfig: IWatchRTCConfiguration) => boolean;
export declare const validateRating: (rating: Rating) => boolean;
"use strict";
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.logPrefix = void 0;
exports.validateRating = exports.isRoomIdOrPeerIdChanged = exports.countOfValidConnections = exports.validateConfig = exports.getConnectionData = exports.dumpStream = exports.map2obj = exports.mangleChromeStats = exports.deltaCompression = exports.logPrefix = void 0;
exports.logPrefix = function (type) {

@@ -17,1 +24,168 @@ if (type === void 0) { type = "info"; }

};
// apply a delta compression to the stats report. Reduces size by ~90%.
// To reduce further, report keys could be compressed.
exports.deltaCompression = function (oldStats, newStats) {
oldStats = oldStats || {};
newStats = newStats || {};
newStats = JSON.parse(JSON.stringify(newStats));
Object.keys(newStats).forEach(function (id) {
var report = newStats[id];
delete report.id;
if (!oldStats[id]) {
return;
}
Object.keys(report).forEach(function (name) {
if (report[name] === oldStats[id][name]) {
delete newStats[id][name];
}
if (Object.keys(report).length === 0) {
delete newStats[id];
}
else if (Object.keys(report).length === 1 && report.timestamp) {
delete newStats[id];
}
});
});
var timestamp = -Infinity;
Object.keys(newStats).forEach(function (id) {
var report = newStats[id];
if (report.timestamp > timestamp) {
timestamp = report.timestamp;
}
});
Object.keys(newStats).forEach(function (id) {
var report = newStats[id];
if (report.timestamp === timestamp) {
report.timestamp = 0;
}
});
newStats.timestamp = timestamp;
return newStats;
};
exports.mangleChromeStats = function (pc, response) {
var standardReport = {};
var reports = response.result();
reports.forEach(function (report) {
var standardStats = {
id: report.id,
timestamp: report.timestamp.getTime(),
type: report.type,
};
report.names().forEach(function (name) {
standardStats[name] = report.stat(name);
});
standardReport[standardStats.id] = standardStats;
});
return standardReport;
};
// transforms a maplike to an object. Mostly for getStats +
// JSON.parse(JSON.stringify())
exports.map2obj = function (m) {
if (!m.entries) {
return m;
}
var o = {};
m.forEach(function (v, k) {
o[k] = v;
});
return o;
};
exports.dumpStream = function (stream) {
return {
id: stream.id,
tracks: stream.getTracks().map(function (track) {
return {
id: track.id,
kind: track.kind,
label: track.label,
enabled: track.enabled,
muted: track.muted,
readyState: track.readyState,
};
}),
};
};
exports.getConnectionData = function (type, key, overriddenWsUrl) {
var localUrl = (type == "ws" ? "ws" : "http") + "://localhost:9101";
var stagingUrl = (type == "ws" ? "wss" : "https") + "://watchrtc-staging2.testrtc.com";
var productionUrl = (type == "ws" ? "wss" : "https") + "://watchrtc.testrtc.com";
var splitted = key.split(":");
if (key.indexOf("local") !== -1) {
return {
url: overriddenWsUrl || localUrl,
key: splitted[1],
};
}
else if (key.indexOf("staging") !== -1) {
return {
url: overriddenWsUrl || stagingUrl,
key: splitted[1],
};
}
else if (key.indexOf("production") !== -1) {
return {
url: overriddenWsUrl || productionUrl,
key: splitted[1],
};
}
else {
return {
url: overriddenWsUrl || productionUrl,
key: splitted[0],
};
}
};
exports.validateConfig = function (config) {
if (!(config === null || config === void 0 ? void 0 : config.rtcApiKey)) {
if (config === null || config === void 0 ? void 0 : config.debug) {
console.info.apply(console, __spreadArrays(exports.logPrefix("error"), ["config.rtcApiKey or config.rtcToken need to be provided."]));
return false;
}
}
if (!(config === null || config === void 0 ? void 0 : config.rtcRoomId) || !(config === null || config === void 0 ? void 0 : config.rtcPeerId)) {
if (config === null || config === void 0 ? void 0 : config.debug) {
console.info.apply(console, __spreadArrays(exports.logPrefix("info"), ["rtcRoomId or rtcPeerId is empty."]));
}
return false;
}
return true;
};
exports.countOfValidConnections = function (openChannels) { return Object.keys(openChannels).filter(function (id) { return openChannels[id].validConnection; }).length; };
exports.isRoomIdOrPeerIdChanged = function (watchrtcIdentifiers, watchrtcConfig) {
var changed = false;
if (watchrtcConfig.rtcRoomId &&
watchrtcIdentifiers.rtcRoomId &&
watchrtcIdentifiers.rtcRoomId !== watchrtcConfig.rtcRoomId) {
changed = true;
}
if (watchrtcConfig.rtcPeerId &&
watchrtcIdentifiers.rtcPeerId &&
watchrtcIdentifiers.rtcPeerId !== watchrtcConfig.rtcPeerId) {
changed = true;
}
if (changed && watchrtcConfig.debug) {
console.log.apply(console, __spreadArrays(exports.logPrefix("info"), ["maybeOpenWebsocketConnection. rtcRoomId or rtcPeerId has been changed",
{
old: {
rtcRoomId: watchrtcIdentifiers.rtcRoomId,
rtcPeerId: watchrtcIdentifiers.rtcPeerId,
},
new: {
rtcRoomId: watchrtcConfig.rtcRoomId,
rtcPeerId: watchrtcConfig.rtcPeerId,
},
}]));
}
return changed;
};
exports.validateRating = function (rating) {
if (!rating) {
console.info.apply(console, __spreadArrays(exports.logPrefix("error"), ["rating parameter is required"]));
return false;
}
if (typeof rating !== "number" || (rating < 1 && rating > 5)) {
console.info.apply(console, __spreadArrays(exports.logPrefix("error"), ["rating parameter should be number from 1 to 5"]));
return false;
}
return true;
};

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

declare const _default: "1.29.1";
declare const _default: "1.29.2";
export default _default;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = "1.28.3";
exports.default = "1.29.0";

@@ -11,5 +11,6 @@ "use strict";

var utils_1 = require("./utils");
var LZString = require("./lz-string");
var PROTOCOL_VERSION = "2.0";
var WatchRTCSocket = /** @class */ (function () {
function WatchRTCSocket() {
function WatchRTCSocket(options) {
this.connection = null;

@@ -19,2 +20,4 @@ this.buffer = [];

this.onClose = function () { };
this.debug = false;
this.dataCollection = true;
if (WatchRTCSocket._instance) {

@@ -25,2 +28,3 @@ console.info.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["WatchRTCSocket instance already created"]));

WatchRTCSocket._instance = this;
this.debug = !!options.debug;
}

@@ -32,6 +36,6 @@ }

}
var _this = WatchRTCSocket._instance;
WatchRTCSocket._instance.connection = new WebSocket(url, PROTOCOL_VERSION);
WatchRTCSocket._instance.connection.onopen = function (_e) { };
WatchRTCSocket._instance.connection.onclose = function (_e) { };
var _this = WatchRTCSocket._instance;
WatchRTCSocket._instance.connection.onmessage = function (e) {

@@ -74,2 +78,5 @@ var _a;

}
if (!WatchRTCSocket._instance.dataCollection) {
return;
}
if (!WatchRTCSocket._instance.connection) {

@@ -86,4 +93,9 @@ if (WatchRTCSocket._instance.buffer.length > 1000) {

var lines = JSON.stringify(WatchRTCSocket._instance.buffer);
var compressedMessage = LZString.compressToEncodedURIComponent(lines);
if (WatchRTCSocket._instance.debug) {
console.log.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["lines: " + lines.length]));
console.log.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["compressedMessage: " + compressedMessage.length]));
}
WatchRTCSocket._instance.buffer = [];
WatchRTCSocket._instance.connection.send(lines);
WatchRTCSocket._instance.connection.send(compressedMessage);
}

@@ -100,4 +112,19 @@ }

};
WatchRTCSocket.prototype.disableDataCollection = function () {
if (WatchRTCSocket._instance.debug) {
console.log.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["Data collection disabled."]));
}
WatchRTCSocket._instance.dataCollection = false;
};
WatchRTCSocket.prototype.enableDataCollection = function () {
if (WatchRTCSocket._instance.debug) {
console.log.apply(console, __spreadArrays(utils_1.logPrefix("info"), ["Data collection enabled."]));
}
WatchRTCSocket._instance.dataCollection = true;
};
WatchRTCSocket.prototype.toggleDebug = function (debug) {
WatchRTCSocket._instance.debug = debug;
};
return WatchRTCSocket;
}());
exports.default = WatchRTCSocket;
{
"name": "@testrtc/watchrtc-sdk",
"version": "1.29.1",
"description": "gather WebRTC API traces and statistics",
"version": "1.29.2",
"description": "Monitor your WebRTC application by collecting WebRTC statistics from end users\n\n",
"main": "lib/index.js",

@@ -26,3 +26,9 @@ "types": "lib/index.d.ts",

"webrtc",
"rtcpeerconnection"
"rtcpeerconnection",
"monitoring",
"stats",
"analytics",
"testrtc",
"library",
"sdk"
],

@@ -29,0 +35,0 @@ "author": "testRTC",

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

# watchRTC JS SDK
watchRTC enables application developers to collect, track and analyze telemetry and metrics of real users on any WebRTC application.

@@ -5,14 +7,16 @@

Please check out our [watchRTC knowledge base](https://testrtc.com/article-categories/watchrtc/) to learn more about the features and capabilities of this WebRTC monitoring service.
## Installation
#### via Yarn
#### via NPM
```bash
yarn add @testrtc/watchrtc-sdk
npm install @testrtc/watchrtc-sdk
```
#### via NPM
#### via Yarn
```bash
npm install @testrtc/watchrtc-sdk
yarn add @testrtc/watchrtc-sdk
```

@@ -30,2 +34,4 @@

### Inclusion and initialization
The watchRTC.init() needs to take place prior to including or loading any 3rd party SDKs that interact with WebRTC - failing to do so may hinder our ability to collect data.

@@ -68,5 +74,6 @@

This will transparently modify the RTCPeerConnection objects, allowing it to connect to the watchRTC backend service transparently to your application.
The watchRTC parameter is needed to make this connection.
### Configuration
Configuring the SDK to connect to the watchRTC backend requires passing the following parameters to the SDK:
- rtcApiKey - watchRTC API key, as provided by testRTC

@@ -78,22 +85,18 @@ - rtcRoomId - an identifier to the session/room/conference. This will enable an analysis of all participants in the same room as a single logical unit

```javascript
var pc = new RTCPeerConnection({
...,
watchrtc:{
rtcApiKey: "watchRTC API key",
rtcRoomId: "identifier for the session",
rtcPeerId: "identifier for the current peer",
rtcTags: ["tag1", "tag2", "tag3"]
}
});
```
Based on your application's logic, you can and should pass these configuration parameters at different stages.
Instead of calling
1. In the call to the `watchRTC.init()`
2. In the call to `watchRTC.setConfig()`
3. Upon the creation of an `RTCPeerConnection()`
```javascript
watchRTC.init();
```
#### via watchRTC.init()
you can use next approach - this is useful when you don't have a direct/easy access to the RTCPeerConnection object:
Passing configuration parameters in the init() is the direct/easy way to provide this information.
This is useful if you are planning to use a known/specific roomId for this session.
The disadvantage of this approach is that it is rigid, and doesn't allow much flexibility.
You can call the init() function multiple times but it will be initialized only on the first call.
```javascript

@@ -108,4 +111,12 @@ watchRTC.init({

You also can use `watchRTC.setConfig` function to set watchRTC configuration after calling init() and before the creation of RTCPeerConnection objects:
#### via watchRTC.setConfig()
You can use `watchRTC.setConfig()` function to set watchRTC configuration after calling `watchRTC.init()` and before the creation of RTCPeerConnection objects.
This approach is useful if you don't have the information needed in your `watchRTC.init()` call or when you don't have direct/easy access to the RTCPeerConnection objects (for example, when using a third party CPaaS SDK).
If needed, you can pass the rtcApiKey in the `watchRTC.init()` call while passing the rtcRomId, rtcPeerId and rtcTags in the `watchRTC.setConfig()` call.
You can call this function multiple times, usually whenever a new session/room needs to be created or entered.
```javascript

@@ -120,10 +131,37 @@ watchRTC.setConfig({

This will override peerconnection and will use those values.
#### via RTCPeerConnection()
You can use `watchRTC.disableDataCollection()` and `watchRTC.disableDataCollection()` to control what data you want to send.
If you have direct access to the RTCPeerConnection object creation, then you can add the necessary configuration parameters there. This gives you the highest level of control over what is done.
### Initialize SDK. Can be called multiple times but it will be initialized only at the first time.
```javascript
var pc = new RTCPeerConnection({
...,
watchrtc:{
rtcApiKey: "watchRTC API key",
rtcRoomId: "identifier for the session",
rtcPeerId: "identifier for the current peer",
rtcTags: ["tag1", "tag2", "tag3"]
}
});
```
# Samples
### Enabling and disabling data collection
When needed, you can temporarily disable data collection. This is important for example if you want to conduct a pre-call test but you aren't interesting in collecting that data.
For that, you can use `watchRTC.enableDataCollection()` and `watchRTC.disableDataCollection()` to control what data you want to send.
## Samples
Additional samples on how to integrate the watchRTC SDK can be found on our official github reporistory:
https://github.com/testRTC/sample-Twilio-video-app-React-TypeScript-watchRTC
## Changelog
### 1.29.2 (July 22, 2021)
#### New features
#### Bug fixes

Sorry, the diff of this file is not supported yet

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