wspromisify 2.7.0 → 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,6 +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. 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
64
68
  // Lazy connect: connects only if something sent (then sends all of them!)
65
69
  lazy: false,
66
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}`)}}))}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){e(t),clearTimeout(this.timeout),delete o[l]},data_type:n.data_type,sent_time:n.timer?Date.now():null,timeout:x(n.timeout,(()=>{this.queue[l]&&(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}`)}}))}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){e(t),clearTimeout(this.timeout),delete o[l]},data_type:n.data_type,sent_time:n.timer?Date.now():null,timeout:x(n.timeout,(()=>{this.queue[l]&&(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.0",
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)) {
@@ -123,6 +128,8 @@ class WebSocketClient {
123
128
  } catch (err) {
124
129
  console.error(err, `WSP: Decode error. Got: ${e.data}`)
125
130
  }
131
+ this.resetPing()
132
+ this.resetIdle()
126
133
  })
127
134
  }
128
135
 
@@ -201,14 +208,14 @@ class WebSocketClient {
201
208
  })
202
209
  this.ws.close()
203
210
  this.ws = null
204
- this.forcibly_closed = true
211
+ this.intentionally_closed = true
205
212
  }
206
213
  })
207
214
  }
208
215
 
209
216
  public open() {
210
217
  if(!this.opened) {
211
- this.forcibly_closed = false
218
+ this.intentionally_closed = false
212
219
  return this.connect()
213
220
  }
214
221
  }
@@ -222,7 +229,7 @@ class WebSocketClient {
222
229
  opts = <wsc.SendOptions>{}
223
230
  ): Promise<ResponseDataType> {
224
231
  this.log('send', message_data)
225
- const {config, forcibly_closed, queue} = this
232
+ const {config, queue} = this
226
233
  const message = {}
227
234
  const {pipes, server: {data_key}} = config
228
235
 
@@ -234,9 +241,6 @@ class WebSocketClient {
234
241
  Object.assign(message, opts.top)
235
242
  }
236
243
  for(const pipe of pipes) message_data = pipe(message_data)
237
-
238
- if(forcibly_closed)
239
- throw new Error('Attempting to send via closed WebSocket connection!')
240
244
  const [msg, err] = await Promise.all([
241
245
  config.encode(message_id, message_data, config),
242
246
  this.connect()
@@ -245,20 +249,20 @@ class WebSocketClient {
245
249
  if(this.opened) {
246
250
  this.ws!.send(msg)
247
251
  this.resetPing()
252
+ this.resetIdle()
248
253
  }
249
254
 
250
255
  return new Promise((ff, rj) => {
251
256
  this.queue[message_id] = {
252
257
  msg, ff(x: any) {
253
- ff(x)
254
- // cleanup.
255
258
  clearTimeout(this.timeout) // from this object!
256
259
  delete queue[message_id]
260
+ ff(x)
257
261
  },
258
262
  data_type: config.data_type,
259
263
  sent_time: config.timer ? Date.now() : null,
260
264
  timeout: sett(config.timeout, () => {
261
- if(this.queue[message_id]) {
265
+ if(message_id in this.queue) {
262
266
  this.call('timeout', message_data)
263
267
  rj({'Websocket timeout expired': config.timeout, 'for the message': message_data})
264
268
  delete queue[message_id]
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