const URL_API_AUTHENTICATE = "https://jar-api.getdownstream.com/api/v1"; const URL_API_HELPER = "https://jar-api.getdownstream.com/helpers"; const URL_SOCKET = "https://jar-api.getdownstream.com/"; /*! * Socket.IO v4.5.3 * (c) 2014-2022 Guillermo Rauch * Released under the MIT License. */ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).io=e()}(this,(function(){"use strict";function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=new Array(e);n=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,s=!0,a=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return s=t.done,t},e:function(t){a=!0,o=t},f:function(){try{s||null==n.return||n.return()}finally{if(a)throw o}}}}var m=Object.create(null);m.open="0",m.close="1",m.ping="2",m.pong="3",m.message="4",m.upgrade="5",m.noop="6";var b=Object.create(null);Object.keys(m).forEach((function(t){b[m[t]]=t}));for(var k={type:"error",data:"parser error"},w="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===Object.prototype.toString.call(Blob),_="function"==typeof ArrayBuffer,O=function(t,e,n){var r,i=t.type,o=t.data;return w&&o instanceof Blob?e?n(o):E(o,n):_&&(o instanceof ArrayBuffer||(r=o,"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(r):r&&r.buffer instanceof ArrayBuffer))?e?n(o):E(new Blob([o]),n):n(m[i]+(o||""))},E=function(t,e){var n=new FileReader;return n.onload=function(){var t=n.result.split(",")[1];e("b"+t)},n.readAsDataURL(t)},A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",R="undefined"==typeof Uint8Array?[]:new Uint8Array(256),T=0;T1?{type:b[n],data:t.substring(1)}:{type:b[n]}:k},S=function(t,e){if(C){var n=function(t){var e,n,r,i,o,s=.75*t.length,a=t.length,c=0;"="===t[t.length-1]&&(s--,"="===t[t.length-2]&&s--);var u=new ArrayBuffer(s),h=new Uint8Array(u);for(e=0;e>4,h[c++]=(15&r)<<4|i>>2,h[c++]=(3&i)<<6|63&o;return u}(t);return N(n,e)}return{base64:!0,data:t}},N=function(t,e){return"blob"===e&&t instanceof ArrayBuffer?new Blob([t]):t},x=String.fromCharCode(30);function L(t){if(t)return function(t){for(var e in L.prototype)t[e]=L.prototype[e];return t}(t)}L.prototype.on=L.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},L.prototype.once=function(t,e){function n(){this.off(t,n),e.apply(this,arguments)}return n.fn=e,this.on(t,n),this},L.prototype.off=L.prototype.removeListener=L.prototype.removeAllListeners=L.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n,r=this._callbacks["$"+t];if(!r)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var i=0;i1?e-1:0),r=1;r0);return e}function W(){var t=z(+new Date);return t!==F?(K=0,F=t):t+"."+z(K++)}for(;Y<64;Y++)H[V[Y]]=Y;function $(t){var e="";for(var n in t)t.hasOwnProperty(n)&&(e.length&&(e+="&"),e+=encodeURIComponent(n)+"="+encodeURIComponent(t[n]));return e}function J(t){for(var e={},n=t.split("&"),r=0,i=n.length;r0&&void 0!==arguments[0]?arguments[0]:{};return i(t,{xd:this.xd,xs:this.xs},this.opts),new nt(this.uri(),t)}},{key:"doWrite",value:function(t,e){var n=this,r=this.request({method:"POST",data:t});r.on("success",e),r.on("error",(function(t,e){n.onError("xhr post error",t,e)}))}},{key:"doPoll",value:function(){var t=this,e=this.request();e.on("data",this.onData.bind(this)),e.on("error",(function(e,n){t.onError("xhr poll error",e,n)})),this.pollXhr=e}}]),s}(U),nt=function(t){o(i,t);var n=p(i);function i(t,r){var o;return e(this,i),D(f(o=n.call(this)),r),o.opts=r,o.method=r.method||"GET",o.uri=t,o.async=!1!==r.async,o.data=void 0!==r.data?r.data:null,o.create(),o}return r(i,[{key:"create",value:function(){var t=this,e=j(this.opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");e.xdomain=!!this.opts.xd,e.xscheme=!!this.opts.xs;var n=this.xhr=new Q(e);try{n.open(this.method,this.uri,this.async);try{if(this.opts.extraHeaders)for(var r in n.setDisableHeaderCheck&&n.setDisableHeaderCheck(!0),this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(r)&&n.setRequestHeader(r,this.opts.extraHeaders[r])}catch(t){}if("POST"===this.method)try{n.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(t){}try{n.setRequestHeader("Accept","*/*")}catch(t){}"withCredentials"in n&&(n.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(n.timeout=this.opts.requestTimeout),n.onreadystatechange=function(){4===n.readyState&&(200===n.status||1223===n.status?t.onLoad():t.setTimeoutFn((function(){t.onError("number"==typeof n.status?n.status:0)}),0))},n.send(this.data)}catch(e){return void this.setTimeoutFn((function(){t.onError(e)}),0)}"undefined"!=typeof document&&(this.index=i.requestsCount++,i.requests[this.index]=this)}},{key:"onError",value:function(t){this.emitReserved("error",t,this.xhr),this.cleanup(!0)}},{key:"cleanup",value:function(t){if(void 0!==this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=Z,t)try{this.xhr.abort()}catch(t){}"undefined"!=typeof document&&delete i.requests[this.index],this.xhr=null}}},{key:"onLoad",value:function(){var t=this.xhr.responseText;null!==t&&(this.emitReserved("data",t),this.emitReserved("success"),this.cleanup())}},{key:"abort",value:function(){this.cleanup()}}]),i}(L);if(nt.requestsCount=0,nt.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",rt);else if("function"==typeof addEventListener){addEventListener("onpagehide"in P?"pagehide":"unload",rt,!1)}function rt(){for(var t in nt.requests)nt.requests.hasOwnProperty(t)&&nt.requests[t].abort()}var it="function"==typeof Promise&&"function"==typeof Promise.resolve?function(t){return Promise.resolve().then(t)}:function(t,e){return e(t,0)},ot=P.WebSocket||P.MozWebSocket,st="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase(),at=function(t){o(i,t);var n=p(i);function i(t){var r;return e(this,i),(r=n.call(this,t)).supportsBinary=!t.forceBase64,r}return r(i,[{key:"name",get:function(){return"websocket"}},{key:"doOpen",value:function(){if(this.check()){var t=this.uri(),e=this.opts.protocols,n=st?{}:j(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(n.headers=this.opts.extraHeaders);try{this.ws=st?new ot(t,e,n):e?new ot(t,e):new ot(t)}catch(t){return this.emitReserved("error",t)}this.ws.binaryType=this.socket.binaryType||"arraybuffer",this.addEventListeners()}}},{key:"addEventListeners",value:function(){var t=this;this.ws.onopen=function(){t.opts.autoUnref&&t.ws._socket.unref(),t.onOpen()},this.ws.onclose=function(e){return t.onClose({description:"websocket connection closed",context:e})},this.ws.onmessage=function(e){return t.onData(e.data)},this.ws.onerror=function(e){return t.onError("websocket error",e)}}},{key:"write",value:function(t){var e=this;this.writable=!1;for(var n=function(n){var r=t[n],i=n===t.length-1;O(r,e.supportsBinary,(function(t){try{e.ws.send(t)}catch(t){}i&&it((function(){e.writable=!0,e.emitReserved("drain")}),e.setTimeoutFn)}))},r=0;r1&&void 0!==arguments[1]?arguments[1]:{};return e(this,a),r=s.call(this),n&&"object"===t(n)&&(o=n,n=null),n?(n=ft(n),o.hostname=n.host,o.secure="https"===n.protocol||"wss"===n.protocol,o.port=n.port,n.query&&(o.query=n.query)):o.host&&(o.hostname=ft(o.host).host),D(f(r),o),r.secure=null!=o.secure?o.secure:"undefined"!=typeof location&&"https:"===location.protocol,o.hostname&&!o.port&&(o.port=r.secure?"443":"80"),r.hostname=o.hostname||("undefined"!=typeof location?location.hostname:"localhost"),r.port=o.port||("undefined"!=typeof location&&location.port?location.port:r.secure?"443":"80"),r.transports=o.transports||["polling","websocket"],r.readyState="",r.writeBuffer=[],r.prevBufferLen=0,r.opts=i({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!0},o),r.opts.path=r.opts.path.replace(/\/$/,"")+"/","string"==typeof r.opts.query&&(r.opts.query=J(r.opts.query)),r.id=null,r.upgrades=null,r.pingInterval=null,r.pingTimeout=null,r.pingTimeoutTimer=null,"function"==typeof addEventListener&&(r.opts.closeOnBeforeunload&&(r.beforeunloadEventListener=function(){r.transport&&(r.transport.removeAllListeners(),r.transport.close())},addEventListener("beforeunload",r.beforeunloadEventListener,!1)),"localhost"!==r.hostname&&(r.offlineEventListener=function(){r.onClose("transport close",{description:"network connection lost"})},addEventListener("offline",r.offlineEventListener,!1))),r.open(),r}return r(a,[{key:"createTransport",value:function(t){var e=i({},this.opts.query);e.EIO=4,e.transport=t,this.id&&(e.sid=this.id);var n=i({},this.opts.transportOptions[t],this.opts,{query:e,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return new ct[t](n)}},{key:"open",value:function(){var t,e=this;if(this.opts.rememberUpgrade&&a.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))t="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((function(){e.emitReserved("error","No transports available")}),0);t=this.transports[0]}this.readyState="opening";try{t=this.createTransport(t)}catch(t){return this.transports.shift(),void this.open()}t.open(),this.setTransport(t)}},{key:"setTransport",value:function(t){var e=this;this.transport&&this.transport.removeAllListeners(),this.transport=t,t.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(function(t){return e.onClose("transport close",t)}))}},{key:"probe",value:function(t){var e=this,n=this.createTransport(t),r=!1;a.priorWebsocketSuccess=!1;var i=function(){r||(n.send([{type:"ping",data:"probe"}]),n.once("packet",(function(t){if(!r)if("pong"===t.type&&"probe"===t.data){if(e.upgrading=!0,e.emitReserved("upgrading",n),!n)return;a.priorWebsocketSuccess="websocket"===n.name,e.transport.pause((function(){r||"closed"!==e.readyState&&(f(),e.setTransport(n),n.send([{type:"upgrade"}]),e.emitReserved("upgrade",n),n=null,e.upgrading=!1,e.flush())}))}else{var i=new Error("probe error");i.transport=n.name,e.emitReserved("upgradeError",i)}})))};function o(){r||(r=!0,f(),n.close(),n=null)}var s=function(t){var r=new Error("probe error: "+t);r.transport=n.name,o(),e.emitReserved("upgradeError",r)};function c(){s("transport closed")}function u(){s("socket closed")}function h(t){n&&t.name!==n.name&&o()}var f=function(){n.removeListener("open",i),n.removeListener("error",s),n.removeListener("close",c),e.off("close",u),e.off("upgrading",h)};n.once("open",i),n.once("error",s),n.once("close",c),this.once("close",u),this.once("upgrading",h),n.open()}},{key:"onOpen",value:function(){if(this.readyState="open",a.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade&&this.transport.pause)for(var t=0,e=this.upgrades.length;t1))return this.writeBuffer;for(var t,e=1,n=0;n=57344?n+=3:(r++,n+=4);return n}(t):Math.ceil(1.33*(t.byteLength||t.size))),n>0&&e>this.maxPayload)return this.writeBuffer.slice(0,n);e+=2}return this.writeBuffer}},{key:"write",value:function(t,e,n){return this.sendPacket("message",t,e,n),this}},{key:"send",value:function(t,e,n){return this.sendPacket("message",t,e,n),this}},{key:"sendPacket",value:function(t,e,n,r){if("function"==typeof e&&(r=e,e=void 0),"function"==typeof n&&(r=n,n=null),"closing"!==this.readyState&&"closed"!==this.readyState){(n=n||{}).compress=!1!==n.compress;var i={type:t,data:e,options:n};this.emitReserved("packetCreate",i),this.writeBuffer.push(i),r&&this.once("flush",r),this.flush()}}},{key:"close",value:function(){var t=this,e=function(){t.onClose("forced close"),t.transport.close()},n=function n(){t.off("upgrade",n),t.off("upgradeError",n),e()},r=function(){t.once("upgrade",n),t.once("upgradeError",n)};return"opening"!==this.readyState&&"open"!==this.readyState||(this.readyState="closing",this.writeBuffer.length?this.once("drain",(function(){t.upgrading?r():e()})):this.upgrading?r():e()),this}},{key:"onError",value:function(t){a.priorWebsocketSuccess=!1,this.emitReserved("error",t),this.onClose("transport error",t)}},{key:"onClose",value:function(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"closing"!==this.readyState||(this.clearTimeoutFn(this.pingTimeoutTimer),this.transport.removeAllListeners("close"),this.transport.close(),this.transport.removeAllListeners(),"function"==typeof removeEventListener&&(removeEventListener("beforeunload",this.beforeunloadEventListener,!1),removeEventListener("offline",this.offlineEventListener,!1)),this.readyState="closed",this.id=null,this.emitReserved("close",t,e),this.writeBuffer=[],this.prevBufferLen=0)}},{key:"filterUpgrades",value:function(t){for(var e=[],n=0,r=t.length;n0;case Ot.ACK:case Ot.BINARY_ACK:return Array.isArray(n)}}}]),a}(L),Rt=function(){function t(n){e(this,t),this.packet=n,this.buffers=[],this.reconPack=n}return r(t,[{key:"takeBinaryData",value:function(t){if(this.buffers.push(t),this.buffers.length===this.reconPack.attachments){var e=wt(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null}},{key:"finishedReconstruction",value:function(){this.reconPack=null,this.buffers=[]}}]),t}(),Tt=Object.freeze({__proto__:null,protocol:5,get PacketType(){return Ot},Encoder:Et,Decoder:At});function Ct(t,e,n){return t.on(e,n),function(){t.off(e,n)}}var Bt=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1}),St=function(t){o(i,t);var n=p(i);function i(t,r,o){var s;return e(this,i),(s=n.call(this)).connected=!1,s.receiveBuffer=[],s.sendBuffer=[],s.ids=0,s.acks={},s.flags={},s.io=t,s.nsp=r,o&&o.auth&&(s.auth=o.auth),s.io._autoConnect&&s.open(),s}return r(i,[{key:"disconnected",get:function(){return!this.connected}},{key:"subEvents",value:function(){if(!this.subs){var t=this.io;this.subs=[Ct(t,"open",this.onopen.bind(this)),Ct(t,"packet",this.onpacket.bind(this)),Ct(t,"error",this.onerror.bind(this)),Ct(t,"close",this.onclose.bind(this))]}}},{key:"active",get:function(){return!!this.subs}},{key:"connect",value:function(){return this.connected||(this.subEvents(),this.io._reconnecting||this.io.open(),"open"===this.io._readyState&&this.onopen()),this}},{key:"open",value:function(){return this.connect()}},{key:"send",value:function(){for(var t=arguments.length,e=new Array(t),n=0;n1?e-1:0),r=1;r0&&t.jitter<=1?t.jitter:0,this.attempts=0}Nt.prototype.duration=function(){var t=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var e=Math.random(),n=Math.floor(e*this.jitter*t);t=0==(1&Math.floor(10*e))?t-n:t+n}return 0|Math.min(t,this.max)},Nt.prototype.reset=function(){this.attempts=0},Nt.prototype.setMin=function(t){this.ms=t},Nt.prototype.setMax=function(t){this.max=t},Nt.prototype.setJitter=function(t){this.jitter=t};var xt=function(n){o(s,n);var i=p(s);function s(n,r){var o,a;e(this,s),(o=i.call(this)).nsps={},o.subs=[],n&&"object"===t(n)&&(r=n,n=void 0),(r=r||{}).path=r.path||"/socket.io",o.opts=r,D(f(o),r),o.reconnection(!1!==r.reconnection),o.reconnectionAttempts(r.reconnectionAttempts||1/0),o.reconnectionDelay(r.reconnectionDelay||1e3),o.reconnectionDelayMax(r.reconnectionDelayMax||5e3),o.randomizationFactor(null!==(a=r.randomizationFactor)&&void 0!==a?a:.5),o.backoff=new Nt({min:o.reconnectionDelay(),max:o.reconnectionDelayMax(),jitter:o.randomizationFactor()}),o.timeout(null==r.timeout?2e4:r.timeout),o._readyState="closed",o.uri=n;var c=r.parser||Tt;return o.encoder=new c.Encoder,o.decoder=new c.Decoder,o._autoConnect=!1!==r.autoConnect,o._autoConnect&&o.open(),o}return r(s,[{key:"reconnection",value:function(t){return arguments.length?(this._reconnection=!!t,this):this._reconnection}},{key:"reconnectionAttempts",value:function(t){return void 0===t?this._reconnectionAttempts:(this._reconnectionAttempts=t,this)}},{key:"reconnectionDelay",value:function(t){var e;return void 0===t?this._reconnectionDelay:(this._reconnectionDelay=t,null===(e=this.backoff)||void 0===e||e.setMin(t),this)}},{key:"randomizationFactor",value:function(t){var e;return void 0===t?this._randomizationFactor:(this._randomizationFactor=t,null===(e=this.backoff)||void 0===e||e.setJitter(t),this)}},{key:"reconnectionDelayMax",value:function(t){var e;return void 0===t?this._reconnectionDelayMax:(this._reconnectionDelayMax=t,null===(e=this.backoff)||void 0===e||e.setMax(t),this)}},{key:"timeout",value:function(t){return arguments.length?(this._timeout=t,this):this._timeout}},{key:"maybeReconnectOnOpen",value:function(){!this._reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()}},{key:"open",value:function(t){var e=this;if(~this._readyState.indexOf("open"))return this;this.engine=new lt(this.uri,this.opts);var n=this.engine,r=this;this._readyState="opening",this.skipReconnect=!1;var i=Ct(n,"open",(function(){r.onopen(),t&&t()})),o=Ct(n,"error",(function(n){r.cleanup(),r._readyState="closed",e.emitReserved("error",n),t?t(n):r.maybeReconnectOnOpen()}));if(!1!==this._timeout){var s=this._timeout;0===s&&i();var a=this.setTimeoutFn((function(){i(),n.close(),n.emit("error",new Error("timeout"))}),s);this.opts.autoUnref&&a.unref(),this.subs.push((function(){clearTimeout(a)}))}return this.subs.push(i),this.subs.push(o),this}},{key:"connect",value:function(t){return this.open(t)}},{key:"onopen",value:function(){this.cleanup(),this._readyState="open",this.emitReserved("open");var t=this.engine;this.subs.push(Ct(t,"ping",this.onping.bind(this)),Ct(t,"data",this.ondata.bind(this)),Ct(t,"error",this.onerror.bind(this)),Ct(t,"close",this.onclose.bind(this)),Ct(this.decoder,"decoded",this.ondecoded.bind(this)))}},{key:"onping",value:function(){this.emitReserved("ping")}},{key:"ondata",value:function(t){try{this.decoder.add(t)}catch(t){this.onclose("parse error",t)}}},{key:"ondecoded",value:function(t){var e=this;it((function(){e.emitReserved("packet",t)}),this.setTimeoutFn)}},{key:"onerror",value:function(t){this.emitReserved("error",t)}},{key:"socket",value:function(t,e){var n=this.nsps[t];return n||(n=new St(this,t,e),this.nsps[t]=n),n}},{key:"_destroy",value:function(t){for(var e=0,n=Object.keys(this.nsps);e=this._reconnectionAttempts)this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{var n=this.backoff.duration();this._reconnecting=!0;var r=this.setTimeoutFn((function(){e.skipReconnect||(t.emitReserved("reconnect_attempt",e.backoff.attempts),e.skipReconnect||e.open((function(n){n?(e._reconnecting=!1,e.reconnect(),t.emitReserved("reconnect_error",n)):e.onreconnect()})))}),n);this.opts.autoUnref&&r.unref(),this.subs.push((function(){clearTimeout(r)}))}}},{key:"onreconnect",value:function(){var t=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",t)}}]),s}(L),Lt={};function Pt(e,n){"object"===t(e)&&(n=e,e=void 0);var r,i=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2?arguments[2]:void 0,r=t;n=n||"undefined"!=typeof location&&location,null==t&&(t=n.protocol+"//"+n.host),"string"==typeof t&&("/"===t.charAt(0)&&(t="/"===t.charAt(1)?n.protocol+t:n.host+t),/^(https?|wss?):\/\//.test(t)||(t=void 0!==n?n.protocol+"//"+t:"https://"+t),r=ft(t)),r.port||(/^(http|ws)$/.test(r.protocol)?r.port="80":/^(http|ws)s$/.test(r.protocol)&&(r.port="443")),r.path=r.path||"/";var i=-1!==r.host.indexOf(":")?"["+r.host+"]":r.host;return r.id=r.protocol+"://"+i+":"+r.port+e,r.href=r.protocol+"://"+i+(n&&n.port===r.port?"":":"+r.port),r}(e,(n=n||{}).path||"/socket.io"),o=i.source,s=i.id,a=i.path,c=Lt[s]&&a in Lt[s].nsps;return n.forceNew||n["force new connection"]||!1===n.multiplex||c?r=new xt(o,n):(Lt[s]||(Lt[s]=new xt(o,n)),r=Lt[s]),i.query&&!n.query&&(n.query=i.queryKey),r.socket(i.path,n)}return i(Pt,{Manager:xt,Socket:St,io:Pt,connect:Pt}),Pt})); class Base { #params = {}; #hooks = {}; #lang = new JAR_LANG(); #logger = new Logger(); /** * The function `_set` is used to set key-value pairs in an object and allows for chaining by * returning `this`. * @param _key - _key * @param _value - It looks like the value parameter is missing. Could you please provide the value * that you would like to set for the key? * @returns The method is returning the current instance of the object, allowing for method * chaining. */ set(_key, _value) { this.#params[_key] = _value; return this; } get logger () { return this.#logger; } set logger (val) { this.#logger = val; } /** * The function `get` retrieves a value from the `params` object based on the provided key, returning * `null` if the key is not found. * @param _key - The `_key` parameter is used as a key to access a value in the `params` object. The * `get` method checks if the `_key` exists in the `params` object and returns the corresponding value * if it does. If the `_key` is not found in the `params * @returns If the key exists in the `params` object, the value associated with that key will be * returned. If the key does not exist or is undefined, then `null` will be returned. */ get(_key) { if ("undefined" === typeof this.#params[_key]) return null; return this.#params[_key]; } get lang() { return this.#lang; } //filter override message fallback to system language based on endpoind key filter(key, override_message = null, fallback = '', ...params) { // when overrider message exist if (override_message) { return this.format(override_message, ...params); } const formated_key = this.lang.clean_key(key); const sys_message = this.lang.format(formated_key, ...params); if (!sys_message){ return fallback; } return sys_message; } /* * @description: to add call back function into a hook which can be later triggered by run_hooks * same level components or object * @param: _key * @param: function _func * @return this * */ add_hooks(_key, _func) { if ("function" !== typeof _func) return this; if ("undefined" === typeof this.#hooks[_key]) this.#hooks[_key] = []; this.#hooks[_key].push(_func); return this; }// end of function add hooks /* * @description: to call all functions being added into hook referenced * by _key, and passing data among components of the same level * @param: _key * @param: mixed _the_data * @return this * */ run_hooks(_key, _the_data = null) { if ("undefined" === typeof this.#hooks) return this; if ("undefined" === typeof this.#hooks[_key]) return this; if (this.#hooks[_key].length === 0) return this; this.#hooks[_key].forEach((_single_function) => { if ("function" === typeof _single_function) { _single_function(_the_data); } }); return this; } // end of running hooks /** * to add callback fucntion into window can be use global scope which can be later triggered by run_global_hooks * @param: _key * @param: _func * @return: this */ add_global_hooks(_key, _func){ if("function" !== typeof _func) return this; if("undefined" === typeof window._global_hooks) window._global_hooks = {}; if("undefined" === typeof window._global_hooks[_key]) window._global_hooks[_key] = []; window._global_hooks[_key].push(_func); return this; }// end of function add hooks /** * to call all function being added to global scope based on key * @param: _key * @param: _the_data * @return: this */ run_global_hooks(_key, _the_data = null){ if("undefined" === typeof window._global_hooks[_key]) return this; if(window._global_hooks[_key].length === 0) return this; window._global_hooks[_key].forEach((_single_function) => { if("function" === typeof _single_function) { _single_function(_the_data); } }); return this; } // end of running hooks /** * The `clear_storage` function clears all localStorage items that are associated with a specific * version. * @returns The `clear_storage()` function is returning `this`. */ clear_storage() { let current_version = localStorage.getItem("jar-sdk-v1"); if (null === current_version) return this; Object.keys(localStorage).forEach(s => { let the_key = this.generate_storage_key("", current_version); if (s.indexOf(the_key) > -1) { localStorage.removeItem(s); } }); return this; } /** * The function generates a storage key based on the provided key and version, encoding the key using * base64 if it is not undefined, null, or empty. * @param key - The `key` parameter is a value that will be used to generate a storage key. * @param version - The `version` parameter in the `generate_storage_key` function is used to specify * the version of the storage key being generated. If the `version` parameter is not provided or is * `undefined` or `null`, the function defaults to using the string "v1app" as the version. * @returns The function `generate_storage_key` returns a string that combines the `version`, * `"vt-jar"`, and a base64 encoded `key` if it is defined and not null. If the `version` is undefined * or null, it defaults to "v1app". */ generate_storage_key(key, version) { if ("undefined" === typeof version || null === version) { version = "v1" + "app"; } return `${version}-${"vt-jar"}-` + (("undefined" !== typeof key && null !== key && key.length > 0) ? btoa(key) : ""); } /** * The function `check_storage_version` checks and updates the version of a storage item in the local * storage. * @returns The `check_storage_version()` function is returning `this`, which refers to the current * object instance. */ check_storage_version() { let current_version = localStorage.getItem("jar-sdk-v1"), new_version = "v1" + "app"; if (current_version !== new_version) { this.clear_storage(); } localStorage.setItem("jar-sdk-v1", new_version); return this; } /** * The function `save_to_storage` saves a key-value pair to the localStorage after checking the storage * version. * @param key - The `key` parameter is a unique identifier or name that is used to store and retrieve * the `value` in the storage system. It helps to uniquely identify the data that is being saved or * retrieved. * @param value - The `value` parameter in the `save_to_storage` function represents the data that you * want to save to the storage. It could be a string, number, object, or any other type of data that * you want to store in the localStorage under the specified key. * @returns The `save_to_storage` method is returning `this`, which refers to the current object * instance. */ save_to_storage(key, value) { this.check_storage_version(); localStorage.setItem(this.generate_storage_key(key), value); return this; } /** * The function `get_from_storage` retrieves data from localStorage after checking the storage * version. * @param key - The `key` parameter is used to identify the specific data that you want to retrieve * from the storage. It is passed to the `get_from_storage` function to fetch the corresponding * data from the storage using the generated storage key. * @returns The data stored in the localStorage corresponding to the provided key is being * returned. */ get_from_storage(key) { this.check_storage_version(); let the_data = localStorage.getItem(this.generate_storage_key(key)); return the_data; } /** * format string with dynamic data * @param: msg * @param: ...params * @return formated string */ format(msg, ...params){ if(null !== params && params.length > 0){ params.forEach((s,index) => { msg = msg.replace(`{${index}}`, s); }) } return msg; } /** * log data to debug when #dev is endable * @param: params * @return: void */ log(...params) { if (!this.logger) { return; } const data = params.map((s) => JSON.stringify(s)); const white_message = this.logger.colorize(params).white; console.log(white_message); } /** * format log in case error * @param: params * @return: void */ error(...params) { if (!this.logger) { return; } const data = params.map((s) => JSON.stringify(s)); const red_message = this.logger.colorize(params).red; console.log(red_message); } /** * format log info debug * @param: params * @return: void */ info(...params) { if (!this.logger) { return; } const data = params.map((s) => JSON.stringify(s)); const green_message = this.logger.colorize(params).green; console.log(green_message); } /** * formating warning log * @param: params * @return: void */ warn(...params) { if (!this.logger) { return; } const data = params.map((s) => JSON.stringify(s)); const yellow_message = this.logger.colorize(params).yellow; console.log(yellow_message); } } // object lang template when request to application downstream, free to modify let RESPONSE_TEMPLATE = { default_success: "Request success", default_failed: "Request failed", timeout: "Request timeout", failed_empty_token: "The token provided is empty", failed_incorrect_token: "The token provided is incorrect.", failed_no_capability: "Sorry, you don't have sufficient permissions to access this resource", failed_restricted_application: "Application is restricted", failed_deactivate_token: "Application was deactivated", expried_token: "Token has expired", failed_application: "Can't get application", authorize_failed: "Failed to authorize", failed_not_found: "No matching records were found", failed_validate: "Invalid request, please try again", authorize_success: "Authorized", success_agent_search: 'Retrived {0} agent{1}. Current page {2}, total of {3} records', failed_agent_search: 'Failed search agent', success_agent_detail: 'Retrived agent data', failed_agent_detail: 'Failed get agent', success_agent_set_display_in_search: 'Set agent seting display updated successfully', failed_agent_set_display_in_search: 'Agent seting display failed', success_agent_set_show_landing_page: 'Set landing page successfully', failed_agent_set_show_landing_page: 'Set landing page failed', success_agent_get_media: 'Found agent media', failed_agent_get_media: 'Agent get media failed', success_agent_set_media: 'Agent media set successfully', failed_agent_set_media: 'Agent set media failed', success_agent_delete_media: 'Delete agent media successfully', failed_agent_delete_media: 'Delete agent media failed', success_agent_set_purl: 'Agent purl set successfully', failed_agent_set_purl: 'Agent purl set failed', success_agent_get_purl: 'Agent Purl retrieved successfully', failed_agent_get_purl: 'Agent purl retrieved failed', success_agent_set_featureds: 'Agent set as featured successfully', failed_agent_set_featured: 'Agent set featured failed', }; class JAR_LANG { static timeout = RESPONSE_TEMPLATE['timeout']; static default_success = RESPONSE_TEMPLATE['default_success']; static token_expired = RESPONSE_TEMPLATE['expried_token']; /** * retrieve system message based on key * @param: __key * return: */ __get(__key) { if (undefined === __key || 'undefined' === typeof __key || undefined === RESPONSE_TEMPLATE[__key]) { return ""; } return RESPONSE_TEMPLATE[__key]; } /** * set system lang * @param: __key * @param: __val * @return: this */ __set(__key, __val) { RESPONSE_TEMPLATE.__key = __val; return this; } /** * override system lang with object langs * this function must be run before other process search system lang * @param: langs * @return: this */ apply_langs_override(langs) { if ('object' !== typeof langs) return this; let langs_key = Object.keys(RESPONSE_TEMPLATE); for(let __key in RESPONSE_TEMPLATE) { if (!langs_key.indexOf(__key) || 'string' !== typeof RESPONSE_TEMPLATE[__key]) { continue; } this.__set(__key,langs[__key]); } return this; } /** * convert key with prefix 'success' before search system lang * @param: key * @return: key (formated) */ get_success_key(key) { return 'success_' + key; } /** * conver key with prefix 'failed' before search system lang * @param: key * @return: key (formated) */ get_failed_key(key) { return 'failed_' + key; } /** * clean key before search system lang * @param: key * @return: key (formated) */ clean_key(key){ return key.replaceAll("/", "_").replaceAll(" ","").replaceAll("-", "_"); } /** * formating string with dynamic data param * @param: key * @param: params * @return: the_language (formated string) * */ format(key, ...params){ key = this.clean_key(key); let the_language = this.__get(key); if ('' === the_language) the_language = key; if(null !== params && params.length > 0){ params.forEach((s,index) => { the_language = the_language.replace(`{${index}}`, s); }) } return the_language; } } class Logger { #colorize = (...args) => ({ black: `\x1b[30m${args.join(' ')}`, red: `\x1b[31m${args.join(' ')}`, green: `\x1b[32m${args.join(' ')}`, yellow: `\x1b[33m${args.join(' ')}`, blue: `\x1b[34m${args.join(' ')}`, magenta: `\x1b[35m${args.join(' ')}`, cyan: `\x1b[36m${args.join(' ')}`, white: `\x1b[37m${args.join(' ')}`, }); get colorize () { return this.#colorize; } } class Helper extends Base { #url_helper = URL_API_HELPER; /** * To check status of helper function * @return */ health () { let headers = { 'Content-Type': 'application/json', }; let posting_data = { keyword: '' } let res = fetch(`${this.#url_helper}/city/search`, { method: 'POST', headers: headers, body: JSON.stringify(posting_data) }) .then(response => response.json()) .then(data => this.#get_data_helper_success(data)) .catch(error => this.#get_data_helper_error(error)); return res; } /** * To search city base on city name * @param: city_name * @return: */ city_search(city_name) { let headers = { 'Content-Type': 'application/json', }; let posting_data = { keyword: city_name } let res = fetch(`${this.#url_helper}/city/search`, { method: 'POST', headers: headers, body: JSON.stringify(posting_data) }) .then(response => response.json()) .then(data => this.#get_data_helper_success(data)) .catch(error => this.#get_data_helper_error(error)); return res; } /** * To search county base on state,county, status, sort, page, rows * @param: state * @param: county * @param: status * @param: sort * @param: page * @param: rows * @return: */ county_list(state, county, status, sort, page, rows) { let headers = { 'Content-Type': 'application/json', }; let posting_data = { state: state, county: county, status: status, sort: sort, page_number: page, num_rows: rows } let res = fetch(`${this.#url_helper}/county/list`, { method: 'POST', headers: headers, body: JSON.stringify(posting_data) }) .then(response => response.json()) .then(data => this.#get_data_helper_success(data)) .catch(error => this.#get_data_helper_error(error)); return res; } /** * To search city base on county and state * @param: county, state * @retrun: */ city_list_by_county(counties, state) { let headers = { 'Content-Type': 'application/json', }; let posting_data = { counties: counties, state: state } let res = fetch(`${this.#url_helper}/city/list-by-county`, { method: 'POST', headers: headers, body: JSON.stringify(posting_data) }) .then(response => response.json()) .then(data => this.#get_data_helper_success(data)) .catch(error => this.#get_data_helper_error(error)); return res; } /** * To search zipcode * @param: zipcode * @return: */ city_list_by_zipcode(zipcode) { let headers = { 'Content-Type': 'application/json', }; let posting_data = { zipcode: zipcode } let res = fetch(`${this.#url_helper}/city/list-by-zipcode`, { method: 'POST', headers: headers, body: JSON.stringify(posting_data) }) .then(response => response.json()) .then(data => this.#get_data_helper_success(data)) .catch(error => this.#get_data_helper_error(error)); return res; } /** * handle success helper request * @param: data * @return: data */ #get_data_helper_success (data) { return data; } /** * handle failed helper request * @param: error * @return: error */ #get_data_helper_error(error) { return error } /** * function to show avaliable entity with function * @return: array */ help() { return [ { method: 'helper.county_list', params: [ { state: 'string', county: 'string', status: 'int', sort: 'int', page: 'int', rows: 'int' } ], response: Promise, response_type: { status: 'bool', messages: 'array', data: { id: 'int', county: 'string', state: 'string', status: 'int', jar_core: 'int', id_created_by: 'int', created_on: 'date', id_updated_by: 'int', updated_on: 'date', } } }, { method: 'helper.city_search', params: [ { keyword: 'string' } ], response: Promise, response_type: { status: 'bool', messages: 'array', data: { city: 'string', county: 'string', state: 'string' } } }, { method: 'helper.city_by_county', params: [ { county: 'string', state: 'string' } ], response: Promise, response_type: { status: 'bool', messages: 'array', data: { city: 'string', county: 'string', state: 'string' } } }, { method: 'helper.city_list_by_zipcode', params: [ { zipcode: 'string', } ], response: Promise, response_type: { status: 'bool', messages: 'array', data: { city: 'string', zipcode: 'string', county: 'string', state: 'string' } } }, { method: 'agent.search', params: [ { keyword: 'string', zipcode: 'string', city: 'string', county: 'string', state: 'string', page: 'string' } ], response: Promise, response_type: { status: 'bool', messages: 'array', data: { id: 'string', address : "string", agent_level : "string", agent_type : 'string', apt : "string", cell_phone : "string", city : "string", code : "string", created_on : "string", direct_deposit : 'string', display_in_search : "string", dob : "string", email : "string", extension : 'string', fax : "string", featured_agent : "string", first_name : "string", id : "string", id_county : 'string', id_created_by : "string", id_team : "string", id_updated_by : "string", languages : "string", last_name : "string", media_image : "string", middle_name : 'string', npn : 'srting', office_phone : "string", paid_to_name : 'string', paid_to_tin : 'string', permission_contact: "string", portal_access : "string", portal_access_level : "string", primary_language : 'string', purl : "string", secondary_language : 'string', show_landing_page : "string", ssn : "string", start_date : "date", state : "string", status : "string", tax_id : 'stirng', team_agent_level : "string", team_status: 'string', termination_date : 'data', updated_on : 'date', zip : 'string' } } }, { method: 'agent.search_v2', params: [ { keyword: 'string', zipcode: 'string', city: 'string', county: 'string', state: 'string', language: 'string', page: 'string' } ], response: Promise, response_type: { status: 'bool', messages: 'array', data: { id: 'string', address : "string", agent_level : "string", agent_type : 'string', apt : "string", cell_phone : "string", city : "string", code : "string", created_on : "string", direct_deposit : 'string', display_in_search : "string", dob : "string", email : "string", extension : 'string', fax : "string", featured_agent : "string", first_name : "string", id : "string", id_county : 'string', id_created_by : "string", id_team : "string", id_updated_by : "string", languages : "string", last_name : "string", media_image : "string", middle_name : 'string', npn : 'srting', office_phone : "string", paid_to_name : 'string', paid_to_tin : 'string', permission_contact: "string", portal_access : "string", portal_access_level : "string", primary_language : 'string', purl : "string", secondary_language : 'string', show_landing_page : "string", ssn : "string", start_date : "date", state : "string", status : "string", tax_id : 'stirng', team_agent_level : "string", team_status: 'string', termination_date : 'data', updated_on : 'date', zip : 'string' } } }, { method: 'agent.get_detail', params: [ { id_agent: 'int' } ], response: Promise, response_type: { status: 'bool', messages: 'array', errors: 'array', data: 'object' } }, { method: 'agent.set_display_search', params: [ { id_agent: 'int', input_display: 'bool' } ], response: Promise, response_type: { status: 'bool', messages: 'array', errors: 'array' } }, { method: 'agent.set_show_landing_page', params: [ { id_agent: 'int', input_show_landing_page: 'bool' } ], response: Promise, response_type: { status: 'bool', messages: 'array', errors: 'array' } }, { method: 'agent.get_media', params: [ { id_agent: 'int', } ], response: Promise, response_type: { status: 'bool', messages: 'array', data: { id: 'string', media_image: 'string', url: 'string' }, errors: 'array' } }, { method: 'agent.set_media', params: [ { id_agent: 'int', file_media: 'file', } ], response: Promise, response_type: { status: 'bool', messages: 'array', filename: 'string', url: 'string', errors: 'array' } }, { method: 'agent.remove_media', params: [ { id_agent: 'int', } ], response: Promise, response_type: { status: 'bool', messages: 'array', errors: 'array' } }, { method: 'agent.set_purl', params: [ { id_agent: 'int', input_purl: 'string', } ], response: Promise, response_type: { status: 'bool', messages: 'array', errors: 'array' } }, { method: 'agent.lookup_purl', params: [ { purl: 'string', } ], response: Promise, response_type: { status: 'bool', messages: 'array', errors: 'array', data: { agency_details: {}, agent_basic_info: {}, agent_cities: {}, approved_health_plans: {}, entity_meta: {}, ready_to_sell_status: {} } } }, { method: 'agent.set_feature', params: [ { id_agent: 'int', input_featured_agent: 'string', } ], response: Promise, response_type: { status: 'bool', messages: 'array', errors: 'array' } }, ] } } class JARSDK extends Base { #controller = new AbortController(); #signal = this.#controller.signal; #url_api_authenticate = URL_API_AUTHENTICATE; #url_socket = URL_SOCKET; #is_ready = false; #app_key = ""; #app_token = ""; #expired_date = ""; #app_secret = ""; #timeout = 3; #request_timeout = null; #config_language = null; #dev = false; #step = 0; #agent = null; #delay_refesh_token = 0; helper = null; /** * initial SDK with config object */ constructor(config) { super(); // allow show log when enable dev mode if (undefined === config || "undefined" === typeof config) { return } this.dev = ((config['dev'] ?? false) === true); // set timeout request if (undefined !== config['timeout']) { this.timeout = parseInt(config['timeout']); } if (undefined !== config['langs']) { this.#config_language = new JAR_LANG(); // apply object lang can be override the response message this.#config_language.apply_langs_override(config['langs']); // this.add_golobal_hooks('apply_lang') } } get agent() { return this.#agent; } set dev(val) { this.#dev = (val === true); } get dev() { return this.#dev; } get step () { return this.#step; } get is_dev() { return this.#dev === true; } get timeout() { return this.#timeout; } /** * to write the pretty log with step for easyly debuging * @param: ...params * @return: void */ #write_step (...params) { if (!this.logger) { return this;} this.#step++; let data = []; try { data = params.map((s) => JSON.stringify(s)); }catch(e) { console.log(params); //console.log('error passing data', params); } let glue_message = this.logger.colorize(`(${this.step}) `).blue, cyan_message = this.logger.colorize(data).cyan; console.log(glue_message + cyan_message); } /** set request timeout with second unit * convert mins -> ms to use with setTimeout function * @param: value; * @return: this; */ set timeout(value) { value = parseInt(value); if (value > 10) { value = 10; } this.#timeout = value * 1000; return this; } /** * application. * The `init` function initializes sets up actions, and sets authentication for the * @param key - The `key` parameter is typically a unique identifier or token used for authentication * or authorization purposes in a software system. It is used to verify the identity of the user or * application making the request and to grant access to specific resources or functionalities based on * the permissions associated with that key. * @param secret - The `secret` parameter is typically a confidential piece of information used for * authentication or encryption purposes. It is meant to be kept secure and should not be shared * publicly. * @returns In the `init` function, the code is returning `undefined`. This is because the `return` * statement at the end of the function does not have a value specified, so it implicitly returns * `undefined`. */ init(key, secret) { // disable log when config enable if (!this.is_dev) { this.logger = false; } this.#write_step('init', [key, secret]); // when application authorized, ready to attch agent request window.addEventListener('jar-application-ready', (event) => { //console.log('jar-application-ready', event); }); if ("undefined" === typeof key || key === "") { this.error("You are missing a key"); return this; } if ("undefined" === typeof secret || secret === "") { this.error("You are missing a secret"); return this; } this.set("actions", []); this.add_hooks("jar-application-ready", (e) => { try { this.log('run hook jar-application-ready'); this.#setup_agent(); this.#setup_helper(); this.#setup_event_socket(); let event = new CustomEvent('jar-application-ready', { detail: { message: 'Authorized success' } }); window.dispatchEvent(event); this.#is_ready = true; } catch(e) { this.error('error ', e); } }); this.#set_authentication(key, secret); return } /** * setup agent with config data * @return: this */ #setup_agent() { this.#write_step('setup_agent'); this.#agent = new Agent(this.#app_key, this.#app_token, this.#app_secret, this.timeout); return this; } /** * setup helper and check status of helper * @return: void */ async #setup_helper() { this.#write_step('setup_helper'); this.helper = new Helper(); const data = await this.helper.health(); if ((data.name ?? '') === 'TypeError') { return this.error("Setup helper failed"); } this.info('setup helper'); // console.log('instruction', this.helper.help()); // let city_resp = await this.helper.city_search('a'); // console.log(city_resp); // let county_resp = await this.helper.county_list('a'); // console.log('county', county_resp); // let res_city_by_county = await this.helper.city_list_by_county('C'); // console.log(res_city_by_county); // let res_zip = await this.helper.city_list_by_zipcode(1); // console.log('res', res_zip); } /** * The function `setup_event_socket` establishes a WebSocket connection to a specified server and emits * a token creation event with the provided token. */ #setup_event_socket() { this.#write_step('setup_event_socket') let socket = io(this.#url_socket, { transports: ["websocket", "polling"] // use WebSocket first, if available }); socket.connect(); socket.on("connect", () => { //console.log('socket connected', socket.connected); // true }); socket.on("disconnect", () => { this.info('reconnect socket'); socket.connect(); }); //socket.on('connect', () => { // this.info('socket connected'); // this.set("socket_id", socket.id); //}); socket.on('app-key-and-app-secret-change', (data) => { this.info('update key and secret', JSON.stringify(data)); this.#set_authentication(data.key, data.secret); }) socket.on('token-create-new', (data) => { this.info('token was be updated', JSON.stringify(data)); this.#set_token(data.token); }) } /** * The function set_authentication takes in a key and secret, sets them as properties of an object, and * then calls another private method authentication_application. * @param key - The `key` parameter is typically a unique identifier or token that is used for * authentication purposes. It is used to verify the identity of the application or user making the * request. * @param secret - The secret parameter is typically a confidential piece of information used for * authentication purposes, such as an API key or password. It is important to keep the secret secure * and not share it publicly. * @returns . */ async #set_authentication(key, secret) { this.#write_step('set_authentication', [key, secret]); this.#app_key = key; this.#app_secret = secret; let req = new Request(); let res = await req.authentication(key, secret); if (false === (res['status'] ?? false )) { return this.error('Authorize failed'); } this.#set_token(res['data']['token']) this.#set_expired(res['data']['token_expiration']) return this; } #set_expired(expired_date) { this.#write_step('set_expired', expired_date); if (this.#expired_date === expired_date || 'number' !== expired_date) return this; this.#expired_date = expired_date; let current_date = new Date(), current_date_utc = current_date.toUTCString(), current_timestamp = Date.parse(current_date_utc)/ 1000; this.log('current_date_utc', current_date_utc, current_timestamp); setTimeout(()=> { this.warn("Refesh token"); this.#set_authentication(this.#app_key, this.#app_secret); }, (expired_date - current_timestamp) + this.#delay_refesh_token); return this; } /** * The function `set_token` sets the `app_token` property and runs the "jar-application-ready" * hooks. * @param token - The `token` parameter is a piece of information that is passed to the `set_token` * method. This method sets the `app_token` property to the value of the `token` parameter and then * runs a hook named "jar-application-ready". */ #set_token(token) { this.#write_step('set_token', token); this.#app_token = token; if (this.#is_ready) { return this; } this.run_hooks("jar-application-ready"); } /** * The function `set_action` adds a new action to a list of actions stored in the object. * @param action - The `action` parameter in the `#set_action(action)` function represents the * action that you want to add to the list of actions. It is the input that will be pushed into the * `actions` array. * @returns The `set_action` method is returning the updated list of actions after adding the new * action to it. */ #set_action(action) { this.#write_step('set_action'); let actions = this.get("actions"); actions.push(action) return this.set("actions", actions); } /** * The function #get_data_helper_success(data) checks if the data status is defined and returns the * data if it is, otherwise it calls the #get_data_helper_error function with the errors. * @param data - The `data` parameter is an object that contains information about the status of a * request and any errors that may have occurred during the process. The `status` property of the * `data` object indicates the success or failure of the request, and the `errors` property contains * any error messages if the * @returns The function `get_data_helper_success` is returning the `data` object if the `status` * property is defined and truthy. If the `status` property is either undefined or falsy, it will call * the `get_data_helper_error` function with the `errors` property of the `data` object as an argument. */ #get_data_helper_success(data) { this.#write_step('get_data_helper_success', data); if ("undefined" === typeof data.status || !data.status) { return this.#get_data_helper_error(data); } return data; } /** * The function #get_data_helper_error logs an error message to the console and returns the error. * @param error - The `error` parameter in the `get_data_helper_error` function is used to store the * error object that is passed to the function when it is called. The function then logs the error to * the console and returns it. * @returns The error that is being passed to the `get_data_helper_error` function is being logged to * the console and then returned by the function. */ #get_data_helper_error(error) { this.#write_step(error) return error; } } class Request extends Base { #token = null; #secret = null; #key = null; #url_api_authenticate = URL_API_AUTHENTICATE; #controller = new AbortController(); #signal = this.#controller.signal; #timeout = null; #timeout_request = null; /** * setup request before send data * */ constructor (key, token, secret, timeout = 3000) { super(); this.#token = token; this.#key = key; this.#secret = secret; this.#timeout = timeout this.add_hooks('clear-timeout', () => { clearTimeout(this.#timeout_request); }) } /** * handle send data with app_key, app_token * can be override message response when returned empty message * * @param: endpoint * @param: payload * @param: override_message * @return: */ send_data(endpoint, payload, override_message = null) { let signal = this.#signal; const headers = { "app-key": this.#key, "app-token": this.#token, 'Content-Type': 'application/json', }; this.set('endpoint', endpoint); this.set('payload', payload); this.set('override_message', override_message); this.#timeout_request = setTimeout(() => { this.warn('timeout request'); this.#controller.abort(JAR_LANG.timeout); }, this.#timeout); const res = fetch(`${this.#url_api_authenticate}/${endpoint}`, { method: 'POST', headers: headers, body: JSON.stringify(payload), signal }) .then(response => { return response.json() }) .then((data) => this.send_data_success(data, override_message)) .catch((error) => this.send_data_error(error, override_message)) ; return res; } /** * handle success request * NOTE: Empty message response will be format with * $1: record being displayed, * $2: is_plural, * $3: current_page, * $4: total_record * * @param: the_data * @param: override_message * @return: the_data */ send_data_success(the_data, override_message = null) { if ( "undefined" === the_data.status || !the_data.status) { return this.send_data_failed(the_data, override_message); } this.run_hooks('clear-timeout'); //fallback when message response empty if (false === (the_data['messages'] ?? false) || '' === (the_data['messages'] ?? []).join('')) { const displayed_record = Array.isArray(the_data['data']) ? (the_data['data'] ?? []).length : 1; let format_data = [ displayed_record, displayed_record > 1 ? 's' : '', the_data['page'] ?? 1, the_data['total'] ?? 1 ]; // parameter to format message resoponse the_data['messages'] = this.filter( this.lang.get_success_key(this.get('endpoint')), override_message !== null ? (override_message.success ?? null) : null, JAR_LANG.default_success, ...format_data, ) ; } return the_data; } /** * handle failed request * @param: error * @param: override_message * @return error */ send_data_error(error, override_message = null) { this.run_hooks('clear-timeout'); if ((error.name ?? '') === 'AbortError') { let error_data = error; error_data['type'] = 'request_timeout'; error_data['status'] = false; return error_data; } return error; } // handle data resoponse in case faield // when token expired system will automate reauthorize async send_data_failed(data, override_message = null) { this.run_hooks('clear-timeout'); if (false === (data['errors'] ?? false) || '' === (data['errors'] ?? []).join('')) { data['errors'] = this.filter( this.lang.get_failed_key( this.get('endpoint')), override_message !== null ? (override_message.failed ?? null) : null, JAR_LANG.default_failed ) } return data; } /** * The `authentication` function sends a POST request with authentication data and * handles the response accordingly. * @returns The `authentication()` function is returning Promise */ authentication(key, secret) { let signal = this.#signal, headers = { 'Content-Type': 'application/json', }; let posting_data = { app_key: key, app_secret: secret } this.set('actions', {endpoint: 'authorize'}); let res = fetch(`${this.#url_api_authenticate}/authorize`, { method: 'POST', headers: headers, body: JSON.stringify(posting_data), signal }) .then(response => response.json()) .then(data => this.#authentication_application_success(data)) .catch(error => this.#authentication_application_error(error)); return res; } /** * handle success request authenticate * @param: data * @return: data */ #authentication_application_success(data) { if ("undefined" === typeof data.status || !data.status) { return this.#authentication_application_error(data); } return data; } /** * handle error request authenticate * @param: data * @return: data */ #authentication_application_error(data) { return data; } } class RequestMedia extends Request { #token = null; #secret = null; #key = null; #url_api_authenticate = URL_API_AUTHENTICATE; #controller = new AbortController(); #signal = this.#controller.signal; #timeout_request = null; #timeout = null; /** * set request media with config */ constructor(key, token, secret, timeout = 3000) { super(key, token,secret, timeout); this.#secret = secret; this.#token = token; this.#key = key; } /** * send request with file using FormData(), header will not have Content-Type * @param: endpoint * @param: payload * @return */ send_data(endpoint, payload) { let signal = this.#signal; const headers = { "app-key": this.#key, "app-token": this.#token, signal }; const form_data = this.#collect_data(payload); this.set('endpoint', endpoint); this.set('payload', payload); // { // console.log('timeout request'); // this.#controller.abort(); // alert('request timeout'); // }, this.#timeout); const res = fetch(`${this.#url_api_authenticate}/${endpoint}`, { method: 'POST', headers: headers, body: form_data }) .then(response => { return response.json() }) .then((data) => this.send_data_success(data)) .catch((error) => this.send_data_error(error)) ; return res; } /** * prepare to collect data of payload into FormData object * @param: payload * @return: FormData */ #collect_data(payload) { let form_data = new FormData(); if (Array.isArray(payload)) { payload.forEach((val, key) => { form_data.append(key, val); }) } if (typeof payload === 'object') { for(const key in payload) { form_data.append(key, payload[key]); } } return form_data; } } class Agent extends Base { #request = null; #request_media = null; /** * concret agent entity with conig * for prepare request object before send request */ constructor (key, token, secret, timeout) { super(); this.#request = new Request(key, token, secret, timeout); this.#request_media = new RequestMedia(key, token, secret, timeout); } /** * The function `agent_search` takes in search parameters such as keyword, zipcode, cities, county, * state, and page number to search for agents and returns the search results. * @param keyword - The `keyword` parameter is used to specify the search term or keyword that will * be used to find agents. * @param zipcode - The `zipcode` parameter in the `agent_search` function refers to the zip code * that will be used as a search criteria for finding agents. It is a numerical value that * represents a specific geographic area within a country. * @param cities - The `cities` parameter in the `agent_search` function refers to a list of cities * that you want to include in the search criteria for finding agents. This parameter allows you to * specify one or more cities to narrow down the search results to agents located in those specific * cities. * @param county - County refers to a specific geographic area within a state, typically smaller * than the state itself but larger than a city or town. It is often used for administrative and * geographical purposes. In the context of the `agent_search` function, the `county` parameter * would represent the county in which the search for * @param state - The `state` parameter in the `agent_search` function refers to the state in which * you are searching for agents. It is a part of the search criteria along with other parameters * like `keyword`, `zipcode`, `cities`, `county`, and `page`. When calling the `agent_search` * @param page - The `page` parameter in the `agent_search` function is used to specify the page * number of results to retrieve. It helps in paginating the search results, allowing users to * navigate through multiple pages of search results. * @returns The `agent_search` function is returning the result of sending data to the * 'agent/search' endpoint with the specified payload containing the keyword, zipcode, cities, * county, state, and page information. */ search(keyword, zipcode, cities, county, state, page = 1) { let action = { endpoint: 'agent/search', payload: { input_keyword: keyword, input_zip: zipcode, input_cities: cities, input_county: county, input_state: state, input_page: page, } } this.set('actions', action); return this.#request.send_data(action.endpoint, action.payload, { success: 'Threre are {0} agent{1} being displayed on page {2}. There are total of {3} record match', failed: 'System found no record' }); } get_detail(id) { let action = { endpoint: 'agent/details', payload: { input_id: id } } this.set('actions', action); return this.#request.send_data(action.endpoint, action.payload, { success: 'Get agent successfully', failed: 'System found no record' }); } /** * The function `agent_search` takes in search parameters such as keyword, zipcode, cities, county, * state, and page number to search for agents and returns the search results. * @param keyword - The `keyword` parameter is used to specify the search term or keyword that will * be used to find agents. * @param zipcode - The `zipcode` parameter in the `agent_search` function refers to the zip code * that will be used as a search criteria for finding agents. It is a numerical value that * represents a specific geographic area within a country. * @param cities - The `cities` parameter in the `agent_search` function refers to a list of cities * that you want to include in the search criteria for finding agents. This parameter allows you to * specify one or more cities to narrow down the search results to agents located in those specific * cities. * @param county - County refers to a specific geographic area within a state, typically smaller * than the state itself but larger than a city or town. It is often used for administrative and * geographical purposes. In the context of the `agent_search` function, the `county` parameter * would represent the county in which the search for * @param state - The `state` parameter in the `agent_search` function refers to the state in which * you are searching for agents. It is a part of the search criteria along with other parameters * like `keyword`, `zipcode`, `cities`, `county`, and `page`. When calling the `agent_search` * @param language - The `language` parameter in the `agent_search` function refers to the language in which searching for agent * @param page - The `page` parameter in the `agent_search` function is used to specify the page * number of results to retrieve. It helps in paginating the search results, allowing users to * navigate through multiple pages of search results. * @returns The `agent_search` function is returning the result of sending data to the * 'agent/search' endpoint with the specified payload containing the keyword, zipcode, cities, * county, state, and page information. */ search_v2(keyword, zipcode, cities, county, state, language, page = 1) { let action = { endpoint: 'agent/search', payload: { input_keyword: keyword, input_zip: zipcode, input_cities: cities, input_county: county, input_state: state, input_language: language, input_page: page, } } this.set('actions', action); return this.#request.send_data(action.endpoint, action.payload, { success: 'Threre are {0} agent{1} being displayed on page {2}. There are total of {3} record match', failed: 'System found no record' }); } get_detail(id) { let action = { endpoint: 'agent/details', payload: { input_id: id } } this.set('actions', action); return this.#request.send_data(action.endpoint, action.payload, { success: 'Get agent successfully', failed: 'System found no record' }); } /** * The function `agent_set_display_search` sets the display in search for a given agent ID. * @param id_agent - The `id_agent` parameter in the `agent_set_display_search` function likely * refers to the unique identifier or ID of the agent whose display settings are being updated in * the search functionality. This ID is used to identify the specific agent for whom the display * settings are being modified. * @param input_display - The `input_display` parameter in the `agent_set_display_search` function * likely refers to the display value that you want to set for a specific agent in a search * context. This value could be how the agent's information or details are displayed in a search * result or interface. It could include formatting, * @returns The `agent_set_display_search` function is returning the result of calling * `this.#request.send_data(action.endpoint, action.payload)`, which sends the data to the specified * endpoint with the given payload. */ set_display_search(id_agent, input_display) { let action = { endpoint: 'agent/set-display-in-search', payload: { input_id: id_agent, input_display: input_display } } this.set('actions', action); return this.#request.send_data(action.endpoint, action.payload, { success: 'Seting agent dispaly successfully', failed: 'Failed to set agent dispaly' }) } /** * The function `agent_set_show_landing_page` sets the show landing page status for a specific * agent. * @param id_agent - The `id_agent` parameter is the identifier of the agent for whom you want to * set the show landing page. This could be a unique identifier or reference to a specific agent in * your system. * @param input_show_landing_page - The `input_show_landing_page` parameter is a boolean value that * determines whether the landing page should be shown or not. You can pass `true` if you want to * show the landing page, and `false` if you want to hide it. * @returns The function `agent_set_show_landing_page` is returning the result of calling * `this.#request.send_data(action.endpoint, action.payload)`, which sends the data to the specified * endpoint with the payload containing the agent ID and the show landing page input. */ set_show_landing_page(id_agent, input_show_landing_page) { let actions = { endpoint: 'agent/set-show-landing-page', payload: { input_id: id_agent, input_show_landing_page: input_show_landing_page } } this.set('actions', actions); return this.#request.send_data(actions.endpoint, actions.payload, { success: 'Seting landing page successfully', failed: 'Failed to update setting show landing page' }) } /** * The `agent_get_media` function sends a request to retrieve media data for a specified agent ID. * @param id_agent - The `id_agent` parameter in the `agent_get_media` function is used to specify * the identifier of the agent for which you want to retrieve media information. This identifier * helps the function target the specific agent and fetch the relevant media data associated with * that agent. * @returns The `agent_get_media` function is returning the result of calling * `this.#request.send_data(action.endpoint, action.payload)`. */ get_media(id_agent) { const actions = { endpoint: 'agent/get-media', payload: { input_id: id_agent } } this.set('actions', actions); return this.#request.send_data(actions.endpoint, actions.payload, { success: 'Retrieved agent media successfully', failed: 'Failed to get agent media' }) } /** * The function `agent_set_media` uploads a file to a specific endpoint with authentication headers * using Fetch API in JavaScript. * @param id_agent - The `id_agent` parameter in the `agent_set_media` function represents the * identifier of the agent to which the media file will be associated. This identifier is used to * link the uploaded media file to a specific agent within the system. * @param el_input_file - `el_input_file` is a reference to an HTML input element of type file. * This element is typically used to allow users to select files from their device. * @returns The `agent_set_media` function is returning a Promise. The function makes a POST * request to the specified endpoint with the provided headers and form data containing the * selected file and agent ID. The response from the server is then parsed as JSON and logged to * the console. If there is an error during the fetch request, the error is caught and logged to * the console as well. */ set_media(id_agent, file_media) { const actions = { endpoint: 'agent/set-media', payload: { input_id: id_agent, input_file: file_media } } this.set('actions', actions); return this.#request_media.send_data(actions.endpoint, actions.payload, { success: 'Set media agent successfully', failed: 'Failed to set meida agent' }); } /** * The function `agent_remove_media` removes media associated with a specific agent by sending a * delete request to the server. * @param id_agent - The `id_agent` parameter in the `agent_remove_media` function likely refers to * the unique identifier or ID of the agent whose media you want to delete. This ID is used to * specify which agent's media should be removed when calling this function. * @returns The `agent_remove_media` function is returning the result of calling * `this.send_data(action.endpoint, action.payload)`, which is the response from sending data to * the 'agent/delete-media' endpoint with the payload containing the input_id specified as * id_agent. */ remove_media(id_agent) { const actions = { endpoint: 'agent/delete-media', payload: { input_id: id_agent } } //this.#set_action(action); this.set('actions', actions); return this.#request.send_data(actions.endpoint, actions.payload, { success: 'Removed media agent successfully', failed: 'Failed to remove media agent' }) } /** * The function `agent_set_purl` sets a personalized URL for a given agent ID. * @param id_agent - The `id_agent` parameter is the identifier of the agent for which you want to * set a PURL (Persistent Uniform Resource Locator). This identifier is used to specify the agent * to which the PURL will be associated. * @param input_purl - The `input_purl` parameter in the `agent_set_purl` function is the * Persistent Uniform Resource Locator (PURL) that you want to set for a specific agent identified * by `id_agent`. The PURL is a type of URL that acts as a permanent identifier for a resource, * allowing * @returns The `agent_set_purl` function is returning the result of calling * `this.send_data(action.endpoint, action.payload)`. */ set_purl(id_agent, input_purl) { const actions = { endpoint: 'agent/set-purl', payload: { input_id: id_agent, input_purl: input_purl } } //this.#set_action(action); this.set('actions', actions); return this.#request.send_data(actions.endpoint, actions.payload, { success: 'Seting purl successfully', failed: 'Failed to set prul' }) } /** * The function `agent_lookup_purl` takes an agent ID as input, sets up an action object with the * endpoint and payload, and sends the data to the specified endpoint for agent lookup. * @param id_agent - The `id_agent` parameter is the identifier used to look up an agent in the * system. It is passed to the `agent_lookup_purl` function to retrieve information about a * specific agent based on this identifier. * @returns The `agent_lookup_purl` function is returning the result of calling * `this.send_data(action.endpoint, action.payload)`. */ lookup_purl(purl) { const actions = { endpoint: 'agent/purl-lookup', payload: { input_purl: purl } } //this.#set_action(action); this.set('actions', actions); return this.#request.send_data(actions.endpoint, actions.payload, { success: 'Retrieved purl data', failed: 'Failed to lookup purl' }) } /** * The function `agent_set_feature` sets a specified agent as featured by sending a request to the * server. * @param id_agent - The `id_agent` parameter likely refers to the unique identifier of the agent * whose feature is being set. This identifier is used to specify which agent's feature is being * updated. * @param input_featured_agent - The `input_featured_agent` parameter likely refers to the agent * that you want to set as featured. This could be a specific agent ID or some other identifier * that distinguishes the agent as featured. * @returns The `agent_set_feature` function is returning the result of sending data to the * 'agent/set-featured' endpoint with the provided payload, which includes the `id_agent` and * `input_featured_agent` values. */ set_feature(id_agent, input_featured_agent) { const actions = { endpoint: 'agent/set-featured', payload: { input_id: id_agent, input_featured_agent: input_featured_agent } } //this.#set_action(action); this.set('actions', actions); return this.#request.send_data(actions.endpoint, actions.payload, { success: 'Setting featured for agent successfully', failed: 'Failed to seting feature for agent' }) } }