wspromisify 2.7.1 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -61,8 +61,10 @@ Default constructor config is
61
61
  timeout: 1400,
62
62
  // Reconnect timeout in seconds or null.
63
63
  reconnect: 2,
64
- // Attempts before silently givin' up.
65
- reconnection_attempts: 25 // defaults to Infinity.
64
+ // Attempts before silently givin' up. Defaults to Infinity.
65
+ reconnection_attempts: 25
66
+ // Time in seconds after the connection is closed if nothing was sent explicitly by send(). Defaults to Infinity.
67
+ max_idle_time: 25
66
68
  // Lazy connect: connects only if something sent (then sends all of them!)
67
69
  lazy: false,
68
70
  // Existing socket if you already have one to augment with this force.
package/dist/bundle.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";const t=Symbol("Placeholder"),e=e=>{let n=0;for(const s of e)s!==t&&n++;return n},n=(e,n)=>{const s=e.length,o=e.slice(),r=n.length;let i=r,c=0;for(;i&&c<s;c++)o[c]===t&&(o[c]=n[r-i],i--);for(c=s;i;c++,i--)o[c]=n[r-i];return o},s=(t,o,r)=>{const i=t.length-o.length-e(r);if(i<1)return t(...n(o,r));{const e=(...e)=>s(t,n(o,r),e);return e.$args_left=i,e}},o=t=>(...n)=>t.length>e(n)?s(t,[],n):t(...n);function r(e){return function(n,s){const o=n===t,r=arguments.length;if(1===r&&o)throw new Error("Senseless placeholder usage.");return r>1?o?(e=>function(n){return n===t?e:e(n)})((t=>e(t,s))):e(n,s):t=>e(n,t)}}function i(t){return o(t)}const c=void 0,l=1/0,u=t=>typeof t,a=t=>null===t,h={u:"U",b:"B",n:"N",s:"S",f:"F"},f=Symbol(),d=t=>{const e=u(t);return"object"===e?a(t)?"Null":t.constructor.name:h[e[0]]+e.slice(1)},p=t=>t.length,g=r(((t,e)=>t===e)),m=r(((t,e)=>{const n=d(t);if(g(n,d(e))&&(g(n,"Object")||g(n,"Array"))){if(a(t)||a(e))return g(t,e);if(g(t,e))return!0;for(const n of[t,e])for(const s in n)if(!(g(n,e)&&s in t||g(n,t)&&s in e&&m(t[s],e[s])))return!1;return!0}return g(t,e)})),y=r(((t,e)=>(e.push(t),e))),w=i(((t,e,n)=>n.reduce(t,e))),b=o(((t,e,n,s)=>t(s)?e(s):n(s))),_=(...e)=>(...n)=>{let s,o=!0;for(let r=p(e)-1;r>-1;r--)o?(o=!1,s=e[r](...n)):s=s===t?e[r]():e[r](s);return s},S=r(((t,e)=>e[t])),k=i(((t,e,n)=>n.slice(t,(t=>"number"==u(t))(e)?e:l))),v=S(0);k(1,l);const P=r(((t,e)=>e.find(t))),E=t=>()=>t,A=r(((t,e)=>e.split(t))),N=E(!0),W=E(!1),j=r(((t,e)=>w(((e,n)=>P((e=>t(n,e)),e)?e:y(n,e)),[],e)))(m),q=i(((t,e,n)=>p(e)?(t=>a(t)||(t=>t===c)(t))(n)?t:_((s=>s in n?q(t,k(1,l,e),n[s]):t),v)(e):n));q(c),_(b(m(f),W,N),q(f));const C=r(((t,e)=>e.map(t))),{floor:O}=Math,Q="0123456789abcdefghijklmnopqrstuvwxyz",$=_((t=>Object.fromEntries(t)),C(((t,e)=>[t,e])),A(""));class z{abc;abclen;c2pos;standard;setABC(t){if(!_(m(p(e=t)),p,j,A(""))(e))throw new Error("Not all chars are unique!");var e;this.abc=t,this.abclen=t.length,this.standard=Q.startsWith(t),this.c2pos=$(t)}zip(t){const{abc:e,abclen:n}=this;let s="";for(;t>0;)s=e[t%n]+s,t=O(t/n);return s||"0"}unzip(t){const{standard:e,abclen:n,c2pos:s}=this;if(e)return parseInt(t,n);const o=t.length;let r=0;for(let e=0;e<o;e++)r+=s[t[e]]*n**(o-e-1);return r}constructor(t){this.setABC(t||Q+"ABCDEFGHIJKLMNOPQRSTUVWXYZ")}}const R=new z;R.setABC.bind(R),R.zip.bind(R),R.unzip.bind(R);const T=(()=>{try{return WebSocket||null}catch{return null}})(),B=(t,e,n)=>t.addEventListener(e,n),x=(t,e)=>setTimeout(e,t),D={data_type:"json",log:()=>null,timer:!1,url:"localhost",timeout:1400,reconnect:2,reconnection_attempts:1/0,lazy:!1,socket:null,adapter:(t,e)=>new WebSocket(t,e),encode:(t,e,{server:n})=>JSON.stringify({[n.id_key]:t,[n.data_key]:e}),decode:t=>JSON.parse(t),protocols:[],pipes:[],server:{id_key:"id",data_key:"data"},ping:{interval:55,content:{}}},L=Symbol("Placeholder"),U=t=>{let e=0;for(const n of t)n!==L&&e++;return e},F=(t,e)=>{const n=t.length,s=t.slice(),o=e.length;let r=o,i=0;for(;r&&i<n;i++)s[i]===L&&(s[i]=e[o-r],r--);for(i=n;r;i++,r--)s[i]=e[o-r];return s},I=(t,e,n)=>{const s=t.length-e.length-U(n);if(s<1)return t(...F(e,n));{const o=(...s)=>I(t,F(e,n),s);return o.$args_left=s,o}},J=t=>(...e)=>t.length>U(e)?I(t,[],e):t(...e);function M(t){return function(e,n){const s=e===L,o=arguments.length;if(1===o&&s)throw new Error("Senseless placeholder usage.");return o>1?s?(t=>function(e){return e===L?t:t(e)})((e=>t(e,n))):t(e,n):n=>t(e,n)}}function G(t){return J(t)}const H=/^(.*?)(8|16|32|64)(Clamped)?Array$/,K=void 0,V=1/0,X=t=>typeof t,Y=t=>null===t,Z=t=>"number"==X(t);const tt=t=>Y(t)||(t=>t===K)(t),et={u:"U",b:"B",n:"N",s:"S",f:"F"},nt=Symbol(),st=t=>{const e=X(t);return"object"===e?Y(t)?"Null":t.constructor.name:et[e[0]]+e.slice(1)},ot=M(((t,e)=>st(e)===t)),rt=t=>t.length,it=M(((t,e)=>t===e)),ct=M(((t,e)=>{const n=st(t);if(it(n,st(e))&&(it(n,"Object")||it(n,"Array")||(t=>H.test(t))(n))){if(Y(t)||Y(e))return it(t,e);if(it(t,e))return!0;for(const n of[t,e])for(const s in n)if(!(it(n,e)&&s in t||it(n,t)&&s in e&&ct(t[s],e[s])))return!1;return!0}return it(t,e)})),lt=M(((t,e)=>(e.push(t),e))),ut=G(((t,e,n)=>n.reduce(t,e))),at=M(((t,e)=>{const n=(t=>Array.isArray(t))(e);let s,o;n&&(s=0,o=[]);for(let s in e)t(e[s],s)||(n?o.push(+s):delete e[s]);if(n)for(const t of o)e.splice(t-s++,1);return e})),ht=J(((t,e,n,s)=>t(s)?e(s):n(s))),ft=(...t)=>(...e)=>{let n,s=!0;for(let o=rt(t)-1;o>-1;o--)s?(s=!1,n=t[o](...e)):n=n===L?t[o]():t[o](n);return n},dt=M(((t,e)=>e[t])),pt=G(((t,e,n)=>n.slice(t,Z(e)?e:V))),gt=dt(0);pt(1,V);const mt=M(((t,e)=>e.find(t))),yt=t=>()=>t,wt=yt(!0),bt=yt(!1),_t=M(((t,e)=>e(...t))),St=t=>(...e)=>{const n=t(...e),s=function(t){return"function"===X(t)}(n);return!s||s&&n.$args_left<=0?(t=>!t)(n):St(n)},kt=M(((t,e)=>ut(((e,n)=>mt((e=>t(n,e)),e)?e:lt(n,e)),[],e)));kt(ct);const vt=t=>{let e,n=!1;return(...s)=>n?e:(n=!0,e=t(...s))},Pt=G(((t,e,n)=>rt(e)?tt(n)?t:ft((s=>s in n?Pt(t,pt(1,V,e),n[s]):t),gt)(e):n));Pt(K),ft(ht(ct(nt),bt,wt),Pt(nt));const Et=G(((t,e,n)=>e(n)&&t(n))),At=St,Nt=new z,Wt=_t([]),jt=Et(ot("Number"),At(isNaN));module.exports=class{ws=null;forcibly_closed=!1;reconnect_timeout=null;queue={};onReadyQueue=[];onCloseQueue=[];handlers={open:[],close:[],message:[],error:[],timeout:[]};config={};pinger=null;get opened(){return 1===this.ws?.readyState}init_flush(){at(bt,this.queue)}call(t,...e){for(const n of this.handlers[t])n(...e)}log(t,e=null,n=null){const s=this.config;null!==n?s.log(t,n,e):s.timer?s.log(t,null,e):s.log(t,e)}resetPing(){const{config:t}=this;tt(this.pinger)||clearTimeout(this.pinger),t.ping&&(this.pinger=setTimeout((async()=>{if(this.forcibly_closed)return clearTimeout(this.pinger);this.opened&&(await this.send(t.ping.content),this.resetPing())}),1e3*t.ping.interval))}initSocket(t){const{queue:e,config:n}=this;this.ws=t,this.onReadyQueue.forEach((t=>t())),this.onReadyQueue.splice(0);const{id_key:s,data_key:o}=n.server;this.call("open",t);for(const n in e)t.send(e[n].msg);null!==this.reconnect_timeout&&(clearInterval(this.reconnect_timeout),this.reconnect_timeout=null),this.resetPing(),B(t,"close",(async(...t)=>{this.log("close"),this.ws=null,this.onCloseQueue.forEach(Wt),this.onCloseQueue.splice(0),this.call("close",...t);let{reconnect:e,reconnection_attempts:s}=n;if(jt(e)){const t=async()=>{if(this.forcibly_closed||!s)return;s--,this.log("reconnect"),tt(this.ws)||(this.ws.close(),this.ws=null);const n=await this.connect();tt(n)||(this.reconnect_timeout=setTimeout(t,1e3*e))};t()}})),B(t,"message",(t=>{try{const e=n.decode(t.data);if(this.call("message",{...t,data:e}),e[s]){const t=this.queue[e[s]];if(t){const n=t.sent_time?Date.now()-t.sent_time:null;this.log("message",e[o],n),t.ff(e[o])}}}catch(e){console.error(e,`WSP: Decode error. Got: ${t.data}`)}this.resetPing()}))}opening=!1;connect(){return new Promise((t=>{if(this.opened||this.opening)return t(null);this.opening=!0;const e=this.config,n=e.socket||e.adapter(e.url,e.protocols);if(!n||n.readyState>1)return this.opening=!1,this.ws=null,this.log("error","ready() on closing or closed state! status 2."),t(2);const s=vt((e=>{this.opening=!1,t(e)}));B(n,"error",vt((t=>{this.ws=null,this.log("error","status 3. Err: "+t.message),this.call("error",t),s(3)}))),n.readyState?(this.initSocket(n),s(null)):B(n,"open",vt((()=>{this.log("open"),this.initSocket(n),s(null)})))}))}get socket(){return this.ws}async ready(){return new Promise((t=>{this.opened?t():this.onReadyQueue.push(t)}))}on(t,e,n=wt,s=!1){const o=t=>n(t)&&e(t);return s?B(this.ws,t,o):this.handlers[t].push(o),o}off(t,e,n=!1){if(n)return((t,e,n)=>t.removeEventListener(e,n))(this.ws,t,e);const s=this.handlers[t],o=s.indexOf(e);~o&&s.splice(o,1)}async close(){return new Promise(((t,e)=>{null===this.ws?e("WSP: closing a non-inited socket!"):(this.onCloseQueue.push((()=>{this.init_flush(),t(null)})),this.ws.close(),this.ws=null,this.forcibly_closed=!0)}))}open(){if(!this.opened)return this.forcibly_closed=!1,this.connect()}async send(t,e={}){this.log("send",t);const{config:n,forcibly_closed:s,queue:o}=this,r={},{pipes:i,server:{data_key:c}}=n,l=Nt.zip(2147483637*Math.random()|0);if("object"==typeof e.top){if(e.top[c])throw new Error("Attempting to set data key/token via send() options!");Object.assign(r,e.top)}for(const e of i)t=e(t);if(s)throw new Error("Attempting to send via closed WebSocket connection!");const[u,a]=await Promise.all([n.encode(l,t,n),this.connect()]);if(a)throw new Error("ERR while opening connection #"+a);return this.opened&&(this.ws.send(u),this.resetPing()),new Promise(((e,s)=>{this.queue[l]={msg:u,ff(t){clearTimeout(this.timeout),delete o[l],e(t)},data_type:n.data_type,sent_time:n.timer?Date.now():null,timeout:x(n.timeout,(()=>{l in this.queue&&(this.call("timeout",t),s({"Websocket timeout expired":n.timeout,"for the message":t}),delete o[l])}))}}))}constructor(t={}){this.config=(t=>{if(null===T&&!("adapter"in t))throw new Error("\n This platform has no native WebSocket implementation.\n Please use 'ws' package as an adapter.\n See https://github.com/houd1ni/WebsocketPromisify/issues/23\n ");const e=Object.assign({},D,t),n=e.url;if("/"==n[0])try{const t=location.protocol.includes("s:")?"wss":"ws";e.url=`${t}://${location.hostname}:${location.port}${n}`}catch(t){throw new Error("WSP: URL starting with / in non-browser environment!")}return e})(t),this.config.lazy||this.connect()}};
1
+ "use strict";const e=Symbol("Placeholder"),t=t=>{let n=0;for(const s of t)s!==e&&n++;return n},n=(t,n)=>{const s=t.length,o=t.slice(),r=n.length;let i=r,l=0;for(;i&&l<s;l++)o[l]===e&&(o[l]=n[r-i],i--);for(l=s;i;l++,i--)o[l]=n[r-i];return o},s=(e,o,r)=>{const i=e.length-o.length-t(r);if(i<1)return e(...n(o,r));{const t=(...t)=>s(e,n(o,r),t);return t.$args_left=i,t}},o=e=>(...n)=>e.length>t(n)?s(e,[],n):e(...n);function r(t){return function(n,s){const o=n===e,r=arguments.length;if(1===r&&o)throw new Error("Senseless placeholder usage.");return r>1?o?(t=>function(n){return n===e?t:t(n)})((e=>t(e,s))):t(n,s):e=>t(n,e)}}function i(e){return o(e)}const l=void 0,c=1/0,u=e=>typeof e,a=e=>null===e,h={u:"U",b:"B",n:"N",s:"S",f:"F"},f=Symbol(),d=e=>{const t=u(e);return"object"===t?a(e)?"Null":e.constructor.name:h[t[0]]+t.slice(1)},p=e=>e.length,g=r(((e,t)=>e===t)),m=r(((e,t)=>{const n=d(e);if(g(n,d(t))&&(g(n,"Object")||g(n,"Array"))){if(a(e)||a(t))return g(e,t);if(g(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(g(n,t)&&s in e||g(n,e)&&s in t&&m(e[s],t[s])))return!1;return!0}return g(e,t)})),y=r(((e,t)=>(t.push(e),t))),w=i(((e,t,n)=>n.reduce(e,t))),_=o(((e,t,n,s)=>e(s)?t(s):n(s))),b=(...t)=>(...n)=>{let s,o=!0;for(let r=p(t)-1;r>-1;r--)o?(o=!1,s=t[r](...n)):s=s===e?t[r]():t[r](s);return s},S=r(((e,t)=>t[e])),k=i(((e,t,n)=>n.slice(e,(e=>"number"==u(e))(t)?t:c))),P=S(0);k(1,c);const v=r(((e,t)=>t.find(e))),E=e=>()=>e,N=r(((e,t)=>t.split(e))),j=E(!0),A=E(!1),W=r(((e,t)=>w(((t,n)=>v((t=>e(n,t)),t)?t:y(n,t)),[],t)))(m),q=i(((e,t,n)=>p(t)?(e=>a(e)||(e=>e===l)(e))(n)?e:b((s=>s in n?q(e,k(1,c,t),n[s]):e),P)(t):n));q(l),b(_(m(f),A,j),q(f));const C=r(((e,t)=>t.map(e))),{floor:O}=Math,Q="0123456789abcdefghijklmnopqrstuvwxyz",$=b((e=>Object.fromEntries(e)),C(((e,t)=>[e,t])),N(""));class z{abc;abclen;c2pos;standard;setABC(e){if(!b(m(p(t=e)),p,W,N(""))(t))throw new Error("Not all chars are unique!");var t;this.abc=e,this.abclen=e.length,this.standard=Q.startsWith(e),this.c2pos=$(e)}zip(e){const{abc:t,abclen:n}=this;let s="";for(;e>0;)s=t[e%n]+s,e=O(e/n);return s||"0"}unzip(e){const{standard:t,abclen:n,c2pos:s}=this;if(t)return parseInt(e,n);const o=e.length;let r=0;for(let t=0;t<o;t++)r+=s[e[t]]*n**(o-t-1);return r}constructor(e){this.setABC(e||Q+"ABCDEFGHIJKLMNOPQRSTUVWXYZ")}}const R=new z;R.setABC.bind(R),R.zip.bind(R),R.unzip.bind(R);const T=(()=>{try{return WebSocket||null}catch{return null}})(),I=(e,t,n)=>e.addEventListener(t,n),x=(e,t)=>setTimeout(t,e),B={data_type:"json",log:()=>null,timer:!1,url:"localhost",timeout:1400,reconnect:2,reconnection_attempts:1/0,max_idle_time:1/0,lazy:!1,socket:null,adapter:(e,t)=>new WebSocket(e,t),encode:(e,t,{server:n})=>JSON.stringify({[n.id_key]:e,[n.data_key]:t}),decode:e=>JSON.parse(e),protocols:[],pipes:[],server:{id_key:"id",data_key:"data"},ping:{interval:55,content:{}}},D=Symbol("Placeholder"),L=e=>{let t=0;for(const n of e)n!==D&&t++;return t},U=(e,t)=>{const n=e.length,s=e.slice(),o=t.length;let r=o,i=0;for(;r&&i<n;i++)s[i]===D&&(s[i]=t[o-r],r--);for(i=n;r;i++,r--)s[i]=t[o-r];return s},F=(e,t,n)=>{const s=e.length-t.length-L(n);if(s<1)return e(...U(t,n));{const o=(...s)=>F(e,U(t,n),s);return o.$args_left=s,o}},J=e=>(...t)=>e.length>L(t)?F(e,[],t):e(...t);function M(e){return function(t,n){const s=t===D,o=arguments.length;if(1===o&&s)throw new Error("Senseless placeholder usage.");return o>1?s?(e=>function(t){return t===D?e:e(t)})((t=>e(t,n))):e(t,n):n=>e(t,n)}}function G(e){return J(e)}const H=/^(.*?)(8|16|32|64)(Clamped)?Array$/,K=void 0,V=1/0,X=e=>typeof e,Y=e=>null===e,Z=e=>"number"==X(e);const ee=e=>Y(e)||(e=>e===K)(e),te={u:"U",b:"B",n:"N",s:"S",f:"F"},ne=Symbol(),se=e=>{const t=X(e);return"object"===t?Y(e)?"Null":e.constructor.name:te[t[0]]+t.slice(1)},oe=M(((e,t)=>se(t)===e)),re=e=>e.length,ie=M(((e,t)=>e===t)),le=M(((e,t)=>{const n=se(e);if(ie(n,se(t))&&(ie(n,"Object")||ie(n,"Array")||(e=>H.test(e))(n))){if(Y(e)||Y(t))return ie(e,t);if(ie(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(ie(n,t)&&s in e||ie(n,e)&&s in t&&le(e[s],t[s])))return!1;return!0}return ie(e,t)})),ce=M(((e,t)=>(t.push(e),t))),ue=G(((e,t,n)=>n.reduce(e,t))),ae=M(((e,t)=>{const n=(e=>Array.isArray(e))(t);let s,o;n&&(s=0,o=[]);for(let s in t)e(t[s],s)||(n?o.push(+s):delete t[s]);if(n)for(const e of o)t.splice(e-s++,1);return t})),he=J(((e,t,n,s)=>e(s)?t(s):n(s))),fe=(...e)=>(...t)=>{let n,s=!0;for(let o=re(e)-1;o>-1;o--)s?(s=!1,n=e[o](...t)):n=n===D?e[o]():e[o](n);return n},de=M(((e,t)=>t[e])),pe=G(((e,t,n)=>n.slice(e,Z(t)?t:V))),ge=de(0);pe(1,V);const me=M(((e,t)=>t.find(e))),ye=e=>()=>e,we=ye(!0),_e=ye(!1),be=M(((e,t)=>t(...e))),Se=e=>(...t)=>{const n=e(...t),s=function(e){return"function"===X(e)}(n);return!s||s&&n.$args_left<=0?(e=>!e)(n):Se(n)},ke=M(((e,t)=>ue(((t,n)=>me((t=>e(n,t)),t)?t:ce(n,t)),[],t)));ke(le);const Pe=e=>{let t,n=!1;return(...s)=>n?t:(n=!0,t=e(...s))},ve=G(((e,t,n)=>re(t)?ee(n)?e:fe((s=>s in n?ve(e,pe(1,V,t),n[s]):e),ge)(t):n));ve(K),fe(he(le(ne),_e,we),ve(ne));const Ee=G(((e,t,n)=>t(n)&&e(n))),Ne=Se,je=new z,Ae=be([]),We=Ee(oe("Number"),Ne(isNaN));module.exports=class{ws=null;intentionally_closed=!1;reconnect_timeout=null;queue={};onReadyQueue=[];onCloseQueue=[];handlers={open:[],close:[],message:[],error:[],timeout:[]};config={};ping_timer=null;idle_timer=null;get opened(){return 1===this.ws?.readyState}init_flush(){ae(_e,this.queue)}call(e,...t){for(const n of this.handlers[e])n(...t)}log(e,t=null,n=null){const{config:s}=this;null===n?s.timer?s.log(e,null,t):s.log(e,t):s.log(e,n,t)}resetPing(){const{config:{ping:e},ping_timer:t}=this;e&&(ee(t)||clearTimeout(t),this.ping_timer=x(1e3*e.interval,(async()=>{const{ping_timer:t,opened:n}=this;n?(await this.send(e.content),this.resetPing()):clearTimeout(t)})))}resetIdle(){const{config:{max_idle_time:e},idle_timer:t}=this;e!==1/0&&(ee(t)||clearTimeout(t),this.idle_timer=x(1e3*e,(()=>this.opened&&this.close())))}initSocket(e){const{queue:t,config:n}=this;this.ws=e,this.onReadyQueue.forEach((e=>e())),this.onReadyQueue.splice(0);const{id_key:s,data_key:o}=n.server;this.call("open",e);for(const n in t)e.send(t[n].msg);null!==this.reconnect_timeout&&(clearInterval(this.reconnect_timeout),this.reconnect_timeout=null),this.resetPing(),this.resetIdle(),I(e,"close",(async(...e)=>{this.log("close"),this.ws=null,this.onCloseQueue.forEach(Ae),this.onCloseQueue.splice(0),this.call("close",...e);let{reconnect:t,reconnection_attempts:s}=n;if(We(t)){const e=async()=>{if(this.intentionally_closed||!s)return;s--,this.log("reconnect"),ee(this.ws)||(this.ws.close(),this.ws=null);const n=await this.connect();ee(n)||(this.reconnect_timeout=setTimeout(e,1e3*t))};e()}})),I(e,"message",(e=>{try{const t=n.decode(e.data);if(this.call("message",{...e,data:t}),t[s]){const e=this.queue[t[s]];if(e){const n=e.sent_time?Date.now()-e.sent_time:null;this.log("message",t[o],n),e.ff(t[o])}}}catch(t){console.error(t,`WSP: Decode error. Got: ${e.data}`)}this.resetPing(),this.resetIdle()}))}opening=!1;connect(){return new Promise((e=>{if(this.opened||this.opening)return e(null);this.opening=!0;const t=this.config,n=t.socket||t.adapter(t.url,t.protocols);if(!n||n.readyState>1)return this.opening=!1,this.ws=null,this.log("error","ready() on closing or closed state! status 2."),e(2);const s=Pe((t=>{this.opening=!1,e(t)}));I(n,"error",Pe((e=>{this.ws=null,this.log("error","status 3. Err: "+e.message),this.call("error",e),s(3)}))),n.readyState?(this.initSocket(n),s(null)):I(n,"open",Pe((()=>{this.log("open"),this.initSocket(n),s(null)})))}))}get socket(){return this.ws}async ready(){return new Promise((e=>{this.opened?e():this.onReadyQueue.push(e)}))}on(e,t,n=we,s=!1){const o=e=>n(e)&&t(e);return s?I(this.ws,e,o):this.handlers[e].push(o),o}off(e,t,n=!1){if(n)return((e,t,n)=>e.removeEventListener(t,n))(this.ws,e,t);const s=this.handlers[e],o=s.indexOf(t);~o&&s.splice(o,1)}async close(){return new Promise(((e,t)=>{null===this.ws?t("WSP: closing a non-inited socket!"):(this.onCloseQueue.push((()=>{this.init_flush(),e(null)})),this.ws.close(),this.ws=null,this.intentionally_closed=!0)}))}open(){if(!this.opened)return this.intentionally_closed=!1,this.connect()}async send(e,t={}){this.log("send",e);const{config:n,queue:s}=this,o={},{pipes:r,server:{data_key:i}}=n,l=je.zip(2147483637*Math.random()|0);if("object"==typeof t.top){if(t.top[i])throw new Error("Attempting to set data key/token via send() options!");Object.assign(o,t.top)}for(const t of r)e=t(e);const[c,u]=await Promise.all([n.encode(l,e,n),this.connect()]);if(u)throw new Error("ERR while opening connection #"+u);return this.opened&&(this.ws.send(c),this.resetPing(),this.resetIdle()),new Promise(((t,o)=>{this.queue[l]={msg:c,ff(e){clearTimeout(this.timeout),delete s[l],t(e)},data_type:n.data_type,sent_time:n.timer?Date.now():null,timeout:x(n.timeout,(()=>{l in this.queue&&(this.call("timeout",e),o({"Websocket timeout expired":n.timeout,"for the message":e}),delete s[l])}))}}))}constructor(e={}){this.config=(e=>{if(null===T&&!("adapter"in e))throw new Error("\n This platform has no native WebSocket implementation.\n Please use 'ws' package as an adapter.\n See https://github.com/houd1ni/WebsocketPromisify/issues/23\n ");const t=Object.assign({},B,e),n=t.url;if("/"==n[0])try{const e=location.protocol.includes("s:")?"wss":"ws";t.url=`${e}://${location.hostname}:${location.port}${n}`}catch(e){throw new Error("WSP: URL starting with / in non-browser environment!")}return t})(e),this.config.lazy||this.connect()}};
package/dist/bundle.d.ts CHANGED
@@ -26,6 +26,7 @@ declare namespace wsc {
26
26
  timeout: number;
27
27
  reconnect: number;
28
28
  reconnection_attempts: number;
29
+ max_idle_time: number;
29
30
  lazy: boolean;
30
31
  socket: Socket | null;
31
32
  adapter: (host: string, protocols?: string[]) => Socket;
@@ -59,19 +60,21 @@ declare namespace wsc {
59
60
  }
60
61
  declare class WebSocketClient {
61
62
  private ws;
62
- private forcibly_closed;
63
+ private intentionally_closed;
63
64
  private reconnect_timeout;
64
65
  private queue;
65
66
  private onReadyQueue;
66
67
  private onCloseQueue;
67
68
  private handlers;
68
69
  private config;
69
- private pinger;
70
+ private ping_timer;
71
+ private idle_timer;
70
72
  private get opened();
71
73
  private init_flush;
72
74
  private call;
73
75
  private log;
74
76
  private resetPing;
77
+ private resetIdle;
75
78
  private initSocket;
76
79
  private opening;
77
80
  private connect;
package/dist/bundle.mjs CHANGED
@@ -1 +1 @@
1
- const t=Symbol("Placeholder"),e=e=>{let n=0;for(const s of e)s!==t&&n++;return n},n=(e,n)=>{const s=e.length,o=e.slice(),r=n.length;let i=r,c=0;for(;i&&c<s;c++)o[c]===t&&(o[c]=n[r-i],i--);for(c=s;i;c++,i--)o[c]=n[r-i];return o},s=(t,o,r)=>{const i=t.length-o.length-e(r);if(i<1)return t(...n(o,r));{const e=(...e)=>s(t,n(o,r),e);return e.$args_left=i,e}},o=t=>(...n)=>t.length>e(n)?s(t,[],n):t(...n);function r(e){return function(n,s){const o=n===t,r=arguments.length;if(1===r&&o)throw new Error("Senseless placeholder usage.");return r>1?o?(e=>function(n){return n===t?e:e(n)})((t=>e(t,s))):e(n,s):t=>e(n,t)}}function i(t){return o(t)}const c=void 0,l=1/0,u=t=>typeof t,a=t=>null===t,h={u:"U",b:"B",n:"N",s:"S",f:"F"},f=Symbol(),d=t=>{const e=u(t);return"object"===e?a(t)?"Null":t.constructor.name:h[e[0]]+e.slice(1)},p=t=>t.length,g=r(((t,e)=>t===e)),m=r(((t,e)=>{const n=d(t);if(g(n,d(e))&&(g(n,"Object")||g(n,"Array"))){if(a(t)||a(e))return g(t,e);if(g(t,e))return!0;for(const n of[t,e])for(const s in n)if(!(g(n,e)&&s in t||g(n,t)&&s in e&&m(t[s],e[s])))return!1;return!0}return g(t,e)})),y=r(((t,e)=>(e.push(t),e))),w=i(((t,e,n)=>n.reduce(t,e))),b=o(((t,e,n,s)=>t(s)?e(s):n(s))),_=(...e)=>(...n)=>{let s,o=!0;for(let r=p(e)-1;r>-1;r--)o?(o=!1,s=e[r](...n)):s=s===t?e[r]():e[r](s);return s},S=r(((t,e)=>e[t])),k=i(((t,e,n)=>n.slice(t,(t=>"number"==u(t))(e)?e:l))),v=S(0);k(1,l);const P=r(((t,e)=>e.find(t))),E=t=>()=>t,A=r(((t,e)=>e.split(t))),N=E(!0),W=E(!1),j=r(((t,e)=>w(((e,n)=>P((e=>t(n,e)),e)?e:y(n,e)),[],e)))(m),q=i(((t,e,n)=>p(e)?(t=>a(t)||(t=>t===c)(t))(n)?t:_((s=>s in n?q(t,k(1,l,e),n[s]):t),v)(e):n));q(c),_(b(m(f),W,N),q(f));const C=r(((t,e)=>e.map(t))),{floor:O}=Math,Q="0123456789abcdefghijklmnopqrstuvwxyz",$=_((t=>Object.fromEntries(t)),C(((t,e)=>[t,e])),A(""));class z{abc;abclen;c2pos;standard;setABC(t){if(!_(m(p(e=t)),p,j,A(""))(e))throw new Error("Not all chars are unique!");var e;this.abc=t,this.abclen=t.length,this.standard=Q.startsWith(t),this.c2pos=$(t)}zip(t){const{abc:e,abclen:n}=this;let s="";for(;t>0;)s=e[t%n]+s,t=O(t/n);return s||"0"}unzip(t){const{standard:e,abclen:n,c2pos:s}=this;if(e)return parseInt(t,n);const o=t.length;let r=0;for(let e=0;e<o;e++)r+=s[t[e]]*n**(o-e-1);return r}constructor(t){this.setABC(t||Q+"ABCDEFGHIJKLMNOPQRSTUVWXYZ")}}const R=new z;R.setABC.bind(R),R.zip.bind(R),R.unzip.bind(R);const T=(()=>{try{return WebSocket||null}catch{return null}})(),B=(t,e,n)=>t.addEventListener(e,n),x=(t,e)=>setTimeout(e,t),D={data_type:"json",log:()=>null,timer:!1,url:"localhost",timeout:1400,reconnect:2,reconnection_attempts:1/0,lazy:!1,socket:null,adapter:(t,e)=>new WebSocket(t,e),encode:(t,e,{server:n})=>JSON.stringify({[n.id_key]:t,[n.data_key]:e}),decode:t=>JSON.parse(t),protocols:[],pipes:[],server:{id_key:"id",data_key:"data"},ping:{interval:55,content:{}}},L=Symbol("Placeholder"),U=t=>{let e=0;for(const n of t)n!==L&&e++;return e},F=(t,e)=>{const n=t.length,s=t.slice(),o=e.length;let r=o,i=0;for(;r&&i<n;i++)s[i]===L&&(s[i]=e[o-r],r--);for(i=n;r;i++,r--)s[i]=e[o-r];return s},I=(t,e,n)=>{const s=t.length-e.length-U(n);if(s<1)return t(...F(e,n));{const o=(...s)=>I(t,F(e,n),s);return o.$args_left=s,o}},J=t=>(...e)=>t.length>U(e)?I(t,[],e):t(...e);function M(t){return function(e,n){const s=e===L,o=arguments.length;if(1===o&&s)throw new Error("Senseless placeholder usage.");return o>1?s?(t=>function(e){return e===L?t:t(e)})((e=>t(e,n))):t(e,n):n=>t(e,n)}}function G(t){return J(t)}const H=/^(.*?)(8|16|32|64)(Clamped)?Array$/,K=void 0,V=1/0,X=t=>typeof t,Y=t=>null===t,Z=t=>"number"==X(t);const tt=t=>Y(t)||(t=>t===K)(t),et={u:"U",b:"B",n:"N",s:"S",f:"F"},nt=Symbol(),st=t=>{const e=X(t);return"object"===e?Y(t)?"Null":t.constructor.name:et[e[0]]+e.slice(1)},ot=M(((t,e)=>st(e)===t)),rt=t=>t.length,it=M(((t,e)=>t===e)),ct=M(((t,e)=>{const n=st(t);if(it(n,st(e))&&(it(n,"Object")||it(n,"Array")||(t=>H.test(t))(n))){if(Y(t)||Y(e))return it(t,e);if(it(t,e))return!0;for(const n of[t,e])for(const s in n)if(!(it(n,e)&&s in t||it(n,t)&&s in e&&ct(t[s],e[s])))return!1;return!0}return it(t,e)})),lt=M(((t,e)=>(e.push(t),e))),ut=G(((t,e,n)=>n.reduce(t,e))),at=M(((t,e)=>{const n=(t=>Array.isArray(t))(e);let s,o;n&&(s=0,o=[]);for(let s in e)t(e[s],s)||(n?o.push(+s):delete e[s]);if(n)for(const t of o)e.splice(t-s++,1);return e})),ht=J(((t,e,n,s)=>t(s)?e(s):n(s))),ft=(...t)=>(...e)=>{let n,s=!0;for(let o=rt(t)-1;o>-1;o--)s?(s=!1,n=t[o](...e)):n=n===L?t[o]():t[o](n);return n},dt=M(((t,e)=>e[t])),pt=G(((t,e,n)=>n.slice(t,Z(e)?e:V))),gt=dt(0);pt(1,V);const mt=M(((t,e)=>e.find(t))),yt=t=>()=>t,wt=yt(!0),bt=yt(!1),_t=M(((t,e)=>e(...t))),St=t=>(...e)=>{const n=t(...e),s=function(t){return"function"===X(t)}(n);return!s||s&&n.$args_left<=0?(t=>!t)(n):St(n)},kt=M(((t,e)=>ut(((e,n)=>mt((e=>t(n,e)),e)?e:lt(n,e)),[],e)));kt(ct);const vt=t=>{let e,n=!1;return(...s)=>n?e:(n=!0,e=t(...s))},Pt=G(((t,e,n)=>rt(e)?tt(n)?t:ft((s=>s in n?Pt(t,pt(1,V,e),n[s]):t),gt)(e):n));Pt(K),ft(ht(ct(nt),bt,wt),Pt(nt));const Et=G(((t,e,n)=>e(n)&&t(n))),At=St,Nt=new z,Wt=_t([]),jt=Et(ot("Number"),At(isNaN));class qt{ws=null;forcibly_closed=!1;reconnect_timeout=null;queue={};onReadyQueue=[];onCloseQueue=[];handlers={open:[],close:[],message:[],error:[],timeout:[]};config={};pinger=null;get opened(){return 1===this.ws?.readyState}init_flush(){at(bt,this.queue)}call(t,...e){for(const n of this.handlers[t])n(...e)}log(t,e=null,n=null){const s=this.config;null!==n?s.log(t,n,e):s.timer?s.log(t,null,e):s.log(t,e)}resetPing(){const{config:t}=this;tt(this.pinger)||clearTimeout(this.pinger),t.ping&&(this.pinger=setTimeout((async()=>{if(this.forcibly_closed)return clearTimeout(this.pinger);this.opened&&(await this.send(t.ping.content),this.resetPing())}),1e3*t.ping.interval))}initSocket(t){const{queue:e,config:n}=this;this.ws=t,this.onReadyQueue.forEach((t=>t())),this.onReadyQueue.splice(0);const{id_key:s,data_key:o}=n.server;this.call("open",t);for(const n in e)t.send(e[n].msg);null!==this.reconnect_timeout&&(clearInterval(this.reconnect_timeout),this.reconnect_timeout=null),this.resetPing(),B(t,"close",(async(...t)=>{this.log("close"),this.ws=null,this.onCloseQueue.forEach(Wt),this.onCloseQueue.splice(0),this.call("close",...t);let{reconnect:e,reconnection_attempts:s}=n;if(jt(e)){const t=async()=>{if(this.forcibly_closed||!s)return;s--,this.log("reconnect"),tt(this.ws)||(this.ws.close(),this.ws=null);const n=await this.connect();tt(n)||(this.reconnect_timeout=setTimeout(t,1e3*e))};t()}})),B(t,"message",(t=>{try{const e=n.decode(t.data);if(this.call("message",{...t,data:e}),e[s]){const t=this.queue[e[s]];if(t){const n=t.sent_time?Date.now()-t.sent_time:null;this.log("message",e[o],n),t.ff(e[o])}}}catch(e){console.error(e,`WSP: Decode error. Got: ${t.data}`)}this.resetPing()}))}opening=!1;connect(){return new Promise((t=>{if(this.opened||this.opening)return t(null);this.opening=!0;const e=this.config,n=e.socket||e.adapter(e.url,e.protocols);if(!n||n.readyState>1)return this.opening=!1,this.ws=null,this.log("error","ready() on closing or closed state! status 2."),t(2);const s=vt((e=>{this.opening=!1,t(e)}));B(n,"error",vt((t=>{this.ws=null,this.log("error","status 3. Err: "+t.message),this.call("error",t),s(3)}))),n.readyState?(this.initSocket(n),s(null)):B(n,"open",vt((()=>{this.log("open"),this.initSocket(n),s(null)})))}))}get socket(){return this.ws}async ready(){return new Promise((t=>{this.opened?t():this.onReadyQueue.push(t)}))}on(t,e,n=wt,s=!1){const o=t=>n(t)&&e(t);return s?B(this.ws,t,o):this.handlers[t].push(o),o}off(t,e,n=!1){if(n)return((t,e,n)=>t.removeEventListener(e,n))(this.ws,t,e);const s=this.handlers[t],o=s.indexOf(e);~o&&s.splice(o,1)}async close(){return new Promise(((t,e)=>{null===this.ws?e("WSP: closing a non-inited socket!"):(this.onCloseQueue.push((()=>{this.init_flush(),t(null)})),this.ws.close(),this.ws=null,this.forcibly_closed=!0)}))}open(){if(!this.opened)return this.forcibly_closed=!1,this.connect()}async send(t,e={}){this.log("send",t);const{config:n,forcibly_closed:s,queue:o}=this,r={},{pipes:i,server:{data_key:c}}=n,l=Nt.zip(2147483637*Math.random()|0);if("object"==typeof e.top){if(e.top[c])throw new Error("Attempting to set data key/token via send() options!");Object.assign(r,e.top)}for(const e of i)t=e(t);if(s)throw new Error("Attempting to send via closed WebSocket connection!");const[u,a]=await Promise.all([n.encode(l,t,n),this.connect()]);if(a)throw new Error("ERR while opening connection #"+a);return this.opened&&(this.ws.send(u),this.resetPing()),new Promise(((e,s)=>{this.queue[l]={msg:u,ff(t){clearTimeout(this.timeout),delete o[l],e(t)},data_type:n.data_type,sent_time:n.timer?Date.now():null,timeout:x(n.timeout,(()=>{l in this.queue&&(this.call("timeout",t),s({"Websocket timeout expired":n.timeout,"for the message":t}),delete o[l])}))}}))}constructor(t={}){this.config=(t=>{if(null===T&&!("adapter"in t))throw new Error("\n This platform has no native WebSocket implementation.\n Please use 'ws' package as an adapter.\n See https://github.com/houd1ni/WebsocketPromisify/issues/23\n ");const e=Object.assign({},D,t),n=e.url;if("/"==n[0])try{const t=location.protocol.includes("s:")?"wss":"ws";e.url=`${t}://${location.hostname}:${location.port}${n}`}catch(t){throw new Error("WSP: URL starting with / in non-browser environment!")}return e})(t),this.config.lazy||this.connect()}}export{qt as default};
1
+ const e=Symbol("Placeholder"),t=t=>{let n=0;for(const s of t)s!==e&&n++;return n},n=(t,n)=>{const s=t.length,o=t.slice(),r=n.length;let i=r,l=0;for(;i&&l<s;l++)o[l]===e&&(o[l]=n[r-i],i--);for(l=s;i;l++,i--)o[l]=n[r-i];return o},s=(e,o,r)=>{const i=e.length-o.length-t(r);if(i<1)return e(...n(o,r));{const t=(...t)=>s(e,n(o,r),t);return t.$args_left=i,t}},o=e=>(...n)=>e.length>t(n)?s(e,[],n):e(...n);function r(t){return function(n,s){const o=n===e,r=arguments.length;if(1===r&&o)throw new Error("Senseless placeholder usage.");return r>1?o?(t=>function(n){return n===e?t:t(n)})((e=>t(e,s))):t(n,s):e=>t(n,e)}}function i(e){return o(e)}const l=void 0,c=1/0,u=e=>typeof e,a=e=>null===e,h={u:"U",b:"B",n:"N",s:"S",f:"F"},f=Symbol(),d=e=>{const t=u(e);return"object"===t?a(e)?"Null":e.constructor.name:h[t[0]]+t.slice(1)},p=e=>e.length,g=r(((e,t)=>e===t)),m=r(((e,t)=>{const n=d(e);if(g(n,d(t))&&(g(n,"Object")||g(n,"Array"))){if(a(e)||a(t))return g(e,t);if(g(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(g(n,t)&&s in e||g(n,e)&&s in t&&m(e[s],t[s])))return!1;return!0}return g(e,t)})),y=r(((e,t)=>(t.push(e),t))),w=i(((e,t,n)=>n.reduce(e,t))),_=o(((e,t,n,s)=>e(s)?t(s):n(s))),b=(...t)=>(...n)=>{let s,o=!0;for(let r=p(t)-1;r>-1;r--)o?(o=!1,s=t[r](...n)):s=s===e?t[r]():t[r](s);return s},S=r(((e,t)=>t[e])),k=i(((e,t,n)=>n.slice(e,(e=>"number"==u(e))(t)?t:c))),P=S(0);k(1,c);const v=r(((e,t)=>t.find(e))),E=e=>()=>e,N=r(((e,t)=>t.split(e))),j=E(!0),A=E(!1),W=r(((e,t)=>w(((t,n)=>v((t=>e(n,t)),t)?t:y(n,t)),[],t)))(m),q=i(((e,t,n)=>p(t)?(e=>a(e)||(e=>e===l)(e))(n)?e:b((s=>s in n?q(e,k(1,c,t),n[s]):e),P)(t):n));q(l),b(_(m(f),A,j),q(f));const C=r(((e,t)=>t.map(e))),{floor:O}=Math,Q="0123456789abcdefghijklmnopqrstuvwxyz",$=b((e=>Object.fromEntries(e)),C(((e,t)=>[e,t])),N(""));class z{abc;abclen;c2pos;standard;setABC(e){if(!b(m(p(t=e)),p,W,N(""))(t))throw new Error("Not all chars are unique!");var t;this.abc=e,this.abclen=e.length,this.standard=Q.startsWith(e),this.c2pos=$(e)}zip(e){const{abc:t,abclen:n}=this;let s="";for(;e>0;)s=t[e%n]+s,e=O(e/n);return s||"0"}unzip(e){const{standard:t,abclen:n,c2pos:s}=this;if(t)return parseInt(e,n);const o=e.length;let r=0;for(let t=0;t<o;t++)r+=s[e[t]]*n**(o-t-1);return r}constructor(e){this.setABC(e||Q+"ABCDEFGHIJKLMNOPQRSTUVWXYZ")}}const R=new z;R.setABC.bind(R),R.zip.bind(R),R.unzip.bind(R);const T=(()=>{try{return WebSocket||null}catch{return null}})(),I=(e,t,n)=>e.addEventListener(t,n),x=(e,t)=>setTimeout(t,e),B={data_type:"json",log:()=>null,timer:!1,url:"localhost",timeout:1400,reconnect:2,reconnection_attempts:1/0,max_idle_time:1/0,lazy:!1,socket:null,adapter:(e,t)=>new WebSocket(e,t),encode:(e,t,{server:n})=>JSON.stringify({[n.id_key]:e,[n.data_key]:t}),decode:e=>JSON.parse(e),protocols:[],pipes:[],server:{id_key:"id",data_key:"data"},ping:{interval:55,content:{}}},D=Symbol("Placeholder"),L=e=>{let t=0;for(const n of e)n!==D&&t++;return t},U=(e,t)=>{const n=e.length,s=e.slice(),o=t.length;let r=o,i=0;for(;r&&i<n;i++)s[i]===D&&(s[i]=t[o-r],r--);for(i=n;r;i++,r--)s[i]=t[o-r];return s},F=(e,t,n)=>{const s=e.length-t.length-L(n);if(s<1)return e(...U(t,n));{const o=(...s)=>F(e,U(t,n),s);return o.$args_left=s,o}},J=e=>(...t)=>e.length>L(t)?F(e,[],t):e(...t);function M(e){return function(t,n){const s=t===D,o=arguments.length;if(1===o&&s)throw new Error("Senseless placeholder usage.");return o>1?s?(e=>function(t){return t===D?e:e(t)})((t=>e(t,n))):e(t,n):n=>e(t,n)}}function G(e){return J(e)}const H=/^(.*?)(8|16|32|64)(Clamped)?Array$/,K=void 0,V=1/0,X=e=>typeof e,Y=e=>null===e,Z=e=>"number"==X(e);const ee=e=>Y(e)||(e=>e===K)(e),te={u:"U",b:"B",n:"N",s:"S",f:"F"},ne=Symbol(),se=e=>{const t=X(e);return"object"===t?Y(e)?"Null":e.constructor.name:te[t[0]]+t.slice(1)},oe=M(((e,t)=>se(t)===e)),re=e=>e.length,ie=M(((e,t)=>e===t)),le=M(((e,t)=>{const n=se(e);if(ie(n,se(t))&&(ie(n,"Object")||ie(n,"Array")||(e=>H.test(e))(n))){if(Y(e)||Y(t))return ie(e,t);if(ie(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(ie(n,t)&&s in e||ie(n,e)&&s in t&&le(e[s],t[s])))return!1;return!0}return ie(e,t)})),ce=M(((e,t)=>(t.push(e),t))),ue=G(((e,t,n)=>n.reduce(e,t))),ae=M(((e,t)=>{const n=(e=>Array.isArray(e))(t);let s,o;n&&(s=0,o=[]);for(let s in t)e(t[s],s)||(n?o.push(+s):delete t[s]);if(n)for(const e of o)t.splice(e-s++,1);return t})),he=J(((e,t,n,s)=>e(s)?t(s):n(s))),fe=(...e)=>(...t)=>{let n,s=!0;for(let o=re(e)-1;o>-1;o--)s?(s=!1,n=e[o](...t)):n=n===D?e[o]():e[o](n);return n},de=M(((e,t)=>t[e])),pe=G(((e,t,n)=>n.slice(e,Z(t)?t:V))),ge=de(0);pe(1,V);const me=M(((e,t)=>t.find(e))),ye=e=>()=>e,we=ye(!0),_e=ye(!1),be=M(((e,t)=>t(...e))),Se=e=>(...t)=>{const n=e(...t),s=function(e){return"function"===X(e)}(n);return!s||s&&n.$args_left<=0?(e=>!e)(n):Se(n)},ke=M(((e,t)=>ue(((t,n)=>me((t=>e(n,t)),t)?t:ce(n,t)),[],t)));ke(le);const Pe=e=>{let t,n=!1;return(...s)=>n?t:(n=!0,t=e(...s))},ve=G(((e,t,n)=>re(t)?ee(n)?e:fe((s=>s in n?ve(e,pe(1,V,t),n[s]):e),ge)(t):n));ve(K),fe(he(le(ne),_e,we),ve(ne));const Ee=G(((e,t,n)=>t(n)&&e(n))),Ne=Se,je=new z,Ae=be([]),We=Ee(oe("Number"),Ne(isNaN));class qe{ws=null;intentionally_closed=!1;reconnect_timeout=null;queue={};onReadyQueue=[];onCloseQueue=[];handlers={open:[],close:[],message:[],error:[],timeout:[]};config={};ping_timer=null;idle_timer=null;get opened(){return 1===this.ws?.readyState}init_flush(){ae(_e,this.queue)}call(e,...t){for(const n of this.handlers[e])n(...t)}log(e,t=null,n=null){const{config:s}=this;null===n?s.timer?s.log(e,null,t):s.log(e,t):s.log(e,n,t)}resetPing(){const{config:{ping:e},ping_timer:t}=this;e&&(ee(t)||clearTimeout(t),this.ping_timer=x(1e3*e.interval,(async()=>{const{ping_timer:t,opened:n}=this;n?(await this.send(e.content),this.resetPing()):clearTimeout(t)})))}resetIdle(){const{config:{max_idle_time:e},idle_timer:t}=this;e!==1/0&&(ee(t)||clearTimeout(t),this.idle_timer=x(1e3*e,(()=>this.opened&&this.close())))}initSocket(e){const{queue:t,config:n}=this;this.ws=e,this.onReadyQueue.forEach((e=>e())),this.onReadyQueue.splice(0);const{id_key:s,data_key:o}=n.server;this.call("open",e);for(const n in t)e.send(t[n].msg);null!==this.reconnect_timeout&&(clearInterval(this.reconnect_timeout),this.reconnect_timeout=null),this.resetPing(),this.resetIdle(),I(e,"close",(async(...e)=>{this.log("close"),this.ws=null,this.onCloseQueue.forEach(Ae),this.onCloseQueue.splice(0),this.call("close",...e);let{reconnect:t,reconnection_attempts:s}=n;if(We(t)){const e=async()=>{if(this.intentionally_closed||!s)return;s--,this.log("reconnect"),ee(this.ws)||(this.ws.close(),this.ws=null);const n=await this.connect();ee(n)||(this.reconnect_timeout=setTimeout(e,1e3*t))};e()}})),I(e,"message",(e=>{try{const t=n.decode(e.data);if(this.call("message",{...e,data:t}),t[s]){const e=this.queue[t[s]];if(e){const n=e.sent_time?Date.now()-e.sent_time:null;this.log("message",t[o],n),e.ff(t[o])}}}catch(t){console.error(t,`WSP: Decode error. Got: ${e.data}`)}this.resetPing(),this.resetIdle()}))}opening=!1;connect(){return new Promise((e=>{if(this.opened||this.opening)return e(null);this.opening=!0;const t=this.config,n=t.socket||t.adapter(t.url,t.protocols);if(!n||n.readyState>1)return this.opening=!1,this.ws=null,this.log("error","ready() on closing or closed state! status 2."),e(2);const s=Pe((t=>{this.opening=!1,e(t)}));I(n,"error",Pe((e=>{this.ws=null,this.log("error","status 3. Err: "+e.message),this.call("error",e),s(3)}))),n.readyState?(this.initSocket(n),s(null)):I(n,"open",Pe((()=>{this.log("open"),this.initSocket(n),s(null)})))}))}get socket(){return this.ws}async ready(){return new Promise((e=>{this.opened?e():this.onReadyQueue.push(e)}))}on(e,t,n=we,s=!1){const o=e=>n(e)&&t(e);return s?I(this.ws,e,o):this.handlers[e].push(o),o}off(e,t,n=!1){if(n)return((e,t,n)=>e.removeEventListener(t,n))(this.ws,e,t);const s=this.handlers[e],o=s.indexOf(t);~o&&s.splice(o,1)}async close(){return new Promise(((e,t)=>{null===this.ws?t("WSP: closing a non-inited socket!"):(this.onCloseQueue.push((()=>{this.init_flush(),e(null)})),this.ws.close(),this.ws=null,this.intentionally_closed=!0)}))}open(){if(!this.opened)return this.intentionally_closed=!1,this.connect()}async send(e,t={}){this.log("send",e);const{config:n,queue:s}=this,o={},{pipes:r,server:{data_key:i}}=n,l=je.zip(2147483637*Math.random()|0);if("object"==typeof t.top){if(t.top[i])throw new Error("Attempting to set data key/token via send() options!");Object.assign(o,t.top)}for(const t of r)e=t(e);const[c,u]=await Promise.all([n.encode(l,e,n),this.connect()]);if(u)throw new Error("ERR while opening connection #"+u);return this.opened&&(this.ws.send(c),this.resetPing(),this.resetIdle()),new Promise(((t,o)=>{this.queue[l]={msg:c,ff(e){clearTimeout(this.timeout),delete s[l],t(e)},data_type:n.data_type,sent_time:n.timer?Date.now():null,timeout:x(n.timeout,(()=>{l in this.queue&&(this.call("timeout",e),o({"Websocket timeout expired":n.timeout,"for the message":e}),delete s[l])}))}}))}constructor(e={}){this.config=(e=>{if(null===T&&!("adapter"in e))throw new Error("\n This platform has no native WebSocket implementation.\n Please use 'ws' package as an adapter.\n See https://github.com/houd1ni/WebsocketPromisify/issues/23\n ");const t=Object.assign({},B,e),n=t.url;if("/"==n[0])try{const e=location.protocol.includes("s:")?"wss":"ws";t.url=`${e}://${location.hostname}:${location.port}${n}`}catch(e){throw new Error("WSP: URL starting with / in non-browser environment!")}return t})(e),this.config.lazy||this.connect()}}export{qe as default};
package/package.json CHANGED
@@ -41,7 +41,7 @@
41
41
  "prod": "npm run gentypes && npm run prod:es && npm run prod:cjs",
42
42
  "all": "npm run dev && npm run prod"
43
43
  },
44
- "version": "2.7.1",
44
+ "version": "2.8.0",
45
45
  "type": "module",
46
46
  "exports": {
47
47
  ".": {
package/src/WSC.ts CHANGED
@@ -20,14 +20,15 @@ type EventHandlers = {
20
20
 
21
21
  class WebSocketClient {
22
22
  private ws: wsc.Socket|null = null
23
- private forcibly_closed = false
23
+ private intentionally_closed = false
24
24
  private reconnect_timeout: NodeJS.Timeout|null = null
25
25
  private queue: Record<string, wsc.Message> = {}
26
26
  private onReadyQueue: AnyFunc[] = []
27
27
  private onCloseQueue: AnyFunc[] = []
28
28
  private handlers: EventHandlers = { open: [], close: [], message: [], error: [], timeout: [] }
29
29
  private config = <wsc.Config>{}
30
- private pinger: NodeJS.Timeout|null = null
30
+ private ping_timer: NodeJS.Timeout|null = null
31
+ private idle_timer: NodeJS.Timeout|null = null
31
32
  private get opened() { return this.ws?.readyState===1 } // The only opened state.
32
33
 
33
34
  private init_flush(): void {
@@ -39,30 +40,34 @@ class WebSocketClient {
39
40
  }
40
41
 
41
42
  private log(event: string, message: any = null, time: number|null = null): void {
42
- const config = this.config
43
- if(time !== null) {
43
+ const {config} = this
44
+ if(time === null)
45
+ if(config.timer) config.log(event, null, message)
46
+ else config.log(event, message)
47
+ else
44
48
  config.log(event, time, message)
45
- } else {
46
- if(config.timer) {
47
- config.log(event, null, message)
48
- } else {
49
- config.log(event, message)
50
- }
51
- }
52
49
  }
53
50
 
54
51
  private resetPing() {
55
- const {config} = this
56
- if(!isNil(this.pinger))
57
- clearTimeout(this.pinger as NodeJS.Timeout)
58
- if(config.ping) {
59
- this.pinger = setTimeout(async () => {
60
- if(this.forcibly_closed) return clearTimeout(this.pinger as NodeJS.Timeout)
61
- if(this.opened) {
62
- await this.send(config.ping.content)
52
+ const {config: {ping}, ping_timer} = this
53
+ if(ping) {
54
+ if(!isNil(ping_timer))
55
+ clearTimeout(ping_timer as NodeJS.Timeout)
56
+ this.ping_timer = sett(ping.interval*1e3, async () => {
57
+ const {ping_timer, opened} = this
58
+ if(opened) {
59
+ await this.send(ping.content)
63
60
  this.resetPing()
64
- }
65
- }, config.ping.interval*1e3)
61
+ } else clearTimeout(ping_timer!)
62
+ })
63
+ }
64
+ }
65
+
66
+ private resetIdle() {
67
+ const {config: {max_idle_time: time}, idle_timer} = this
68
+ if(time!==Infinity) {
69
+ if(!isNil(idle_timer)) clearTimeout(idle_timer!)
70
+ this.idle_timer = sett(time*1e3, () => this.opened && this.close())
66
71
  }
67
72
  }
68
73
 
@@ -79,7 +84,7 @@ class WebSocketClient {
79
84
  clearInterval(this.reconnect_timeout)
80
85
  this.reconnect_timeout = null
81
86
  }
82
- this.resetPing()
87
+ this.resetPing(); this.resetIdle()
83
88
  add_event(ws, 'close', async (...e) => {
84
89
  this.log('close')
85
90
  this.ws = null
@@ -90,7 +95,7 @@ class WebSocketClient {
90
95
  let {reconnect, reconnection_attempts} = config
91
96
  if(isNumber(reconnect)) {
92
97
  const reconnectFunc = async () => {
93
- if(this.forcibly_closed || !reconnection_attempts) return;
98
+ if(this.intentionally_closed || !reconnection_attempts) return;
94
99
  reconnection_attempts--
95
100
  this.log('reconnect')
96
101
  if(!isNil(this.ws)) {
@@ -124,6 +129,7 @@ class WebSocketClient {
124
129
  console.error(err, `WSP: Decode error. Got: ${e.data}`)
125
130
  }
126
131
  this.resetPing()
132
+ this.resetIdle()
127
133
  })
128
134
  }
129
135
 
@@ -202,14 +208,14 @@ class WebSocketClient {
202
208
  })
203
209
  this.ws.close()
204
210
  this.ws = null
205
- this.forcibly_closed = true
211
+ this.intentionally_closed = true
206
212
  }
207
213
  })
208
214
  }
209
215
 
210
216
  public open() {
211
217
  if(!this.opened) {
212
- this.forcibly_closed = false
218
+ this.intentionally_closed = false
213
219
  return this.connect()
214
220
  }
215
221
  }
@@ -223,7 +229,7 @@ class WebSocketClient {
223
229
  opts = <wsc.SendOptions>{}
224
230
  ): Promise<ResponseDataType> {
225
231
  this.log('send', message_data)
226
- const {config, forcibly_closed, queue} = this
232
+ const {config, queue} = this
227
233
  const message = {}
228
234
  const {pipes, server: {data_key}} = config
229
235
 
@@ -235,9 +241,6 @@ class WebSocketClient {
235
241
  Object.assign(message, opts.top)
236
242
  }
237
243
  for(const pipe of pipes) message_data = pipe(message_data)
238
-
239
- if(forcibly_closed)
240
- throw new Error('Attempting to send via closed WebSocket connection!')
241
244
  const [msg, err] = await Promise.all([
242
245
  config.encode(message_id, message_data, config),
243
246
  this.connect()
@@ -246,6 +249,7 @@ class WebSocketClient {
246
249
  if(this.opened) {
247
250
  this.ws!.send(msg)
248
251
  this.resetPing()
252
+ this.resetIdle()
249
253
  }
250
254
 
251
255
  return new Promise((ff, rj) => {
package/src/config.ts CHANGED
@@ -11,6 +11,7 @@ const default_config = <wsc.Config>{
11
11
  timeout: 1400,
12
12
  reconnect: 2, // Reconnect timeout in seconds or null.
13
13
  reconnection_attempts: Infinity,
14
+ max_idle_time: Infinity,
14
15
  lazy: false,
15
16
  socket: null,
16
17
  adapter: ((host, protocols) => new WebSocket(host, protocols)),
package/src/types.ts CHANGED
@@ -32,6 +32,7 @@ declare namespace wsc {
32
32
  timeout: number
33
33
  reconnect: number
34
34
  reconnection_attempts: number
35
+ max_idle_time: number
35
36
  lazy: boolean
36
37
  socket: Socket | null
37
38
  adapter: (host: string, protocols?: string[]) => Socket