@honeybbq/teamspeak-client 0.3.1 → 0.3.2
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/dist/address-BR-5unVo.cjs.map +1 -1
- package/dist/address-BfmovVpp.js.map +1 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/client.d.ts +16 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/command/index.cjs +1 -1
- package/dist/command/index.mjs +1 -1
- package/dist/command/parser.d.ts.map +1 -1
- package/dist/{crypt-init2-D70ha4LB.js → crypt-init2-BcGT--df.js} +2 -2
- package/dist/{crypt-init2-D70ha4LB.js.map → crypt-init2-BcGT--df.js.map} +1 -1
- package/dist/{crypt-init2-DparLekm.cjs → crypt-init2-Bkee1YxV.cjs} +2 -2
- package/dist/{crypt-init2-DparLekm.cjs.map → crypt-init2-Bkee1YxV.cjs.map} +1 -1
- package/dist/crypto/identity.d.ts +13 -1
- package/dist/crypto/identity.d.ts.map +1 -1
- package/dist/crypto/index.cjs +1 -1
- package/dist/crypto/index.d.ts +2 -1
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/crypto/index.mjs +3 -3
- package/dist/{crypto-CDlweUL3.cjs → crypto-BfDd9DP6.cjs} +2 -2
- package/dist/{crypto-CDlweUL3.cjs.map → crypto-BfDd9DP6.cjs.map} +1 -1
- package/dist/{crypto-Bg02m4ZE.js → crypto-DLV3oH5F.js} +12 -12
- package/dist/{crypto-Bg02m4ZE.js.map → crypto-DLV3oH5F.js.map} +1 -1
- package/dist/{handler-DI_abe9c.js → handler-BpdZFsKo.js} +104 -102
- package/dist/handler-BpdZFsKo.js.map +1 -0
- package/dist/handler-aywHvv7I.cjs +2 -0
- package/dist/handler-aywHvv7I.cjs.map +1 -0
- package/dist/handshake/index.cjs +1 -1
- package/dist/handshake/index.mjs +1 -1
- package/dist/handshake.d.ts +9 -0
- package/dist/handshake.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +294 -290
- package/dist/index.mjs.map +1 -1
- package/dist/{parser-DZMv3Jm-.js → parser-BX8NEiBe.js} +4 -4
- package/dist/parser-BX8NEiBe.js.map +1 -0
- package/dist/parser-BfwYH2fT.cjs +2 -0
- package/dist/parser-BfwYH2fT.cjs.map +1 -0
- package/dist/{primitives-xIr6Tjk4.js → primitives-CdX74Rgu.js} +194 -190
- package/dist/primitives-CdX74Rgu.js.map +1 -0
- package/dist/primitives-DkwW7wcP.cjs +2 -0
- package/dist/primitives-DkwW7wcP.cjs.map +1 -0
- package/dist/transfer.d.ts.map +1 -1
- package/dist/transport/handler.d.ts +9 -1
- package/dist/transport/handler.d.ts.map +1 -1
- package/dist/transport/index.cjs +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -2
- package/dist/handler-DI_abe9c.js.map +0 -1
- package/dist/handler-DuwoO5RC.cjs +0 -2
- package/dist/handler-DuwoO5RC.cjs.map +0 -1
- package/dist/parser-CL33R9tr.cjs +0 -2
- package/dist/parser-CL33R9tr.cjs.map +0 -1
- package/dist/parser-DZMv3Jm-.js.map +0 -1
- package/dist/primitives-cNNAeFCo.cjs +0 -2
- package/dist/primitives-cNNAeFCo.cjs.map +0 -1
- package/dist/primitives-xIr6Tjk4.js.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./address-BR-5unVo.cjs"),t=require("./crypt-handshake-CQkQreLx.cjs");let n=require("node:dns/promises"),r=require("node:dgram");var i=function(e){return e[e.Voice=0]=`Voice`,e[e.VoiceWhisper=1]=`VoiceWhisper`,e[e.Command=2]=`Command`,e[e.CommandLow=3]=`CommandLow`,e[e.Ping=4]=`Ping`,e[e.Pong=5]=`Pong`,e[e.Ack=6]=`Ack`,e[e.AckLow=7]=`AckLow`,e[e.Init1=8]=`Init1`,e}({}),a=function(e){return e[e.Fragmented=16]=`Fragmented`,e[e.NewProtocol=32]=`NewProtocol`,e[e.Compressed=64]=`Compressed`,e[e.Unencrypted=128]=`Unencrypted`,e}({});function o(e){return e.typeFlagged&15}function s(e){return e.typeFlagged&240}function c(e){return!!(s(e)&128)}function l(e){let t=new Uint8Array(5),n=new DataView(t.buffer);return n.setUint16(0,e.id,!1),n.setUint16(2,e.clientID,!1),t[4]=e.typeFlagged,t}function u(e){return{id:new DataView(e.buffer,e.byteOffset,e.byteLength).getUint16(0,!1),typeFlagged:e[2]}}function d(e){let t=new DataView(e.buffer,e.byteOffset,e.byteLength);return{id:t.getUint16(0,!1),clientID:t.getUint16(2,!1),typeFlagged:e[4]}}var f=class{#e=0;#t=0;#n;#r;constructor(e,t){this.#n=e,this.#r=t}get generation(){return this.#t}advance(e){if(e<=0)return;let t=this.#e+e,n=Math.floor(t/this.#n);n>0&&(this.#t=Math.min(this.#t+n,4294967295)),this.#e=t%this.#n}advanceToExcluded(e){let t=e-this.#e;t<0&&(t+=this.#n),this.advance(t+1)}syncTo(e){let t=e-this.#e;t<0&&(t+=this.#n),this.advance(t)}isInWindow(e){let t=this.#e+this.#r;return t<this.#n?e>=this.#e&&e<t:e>=this.#e||e<t-this.#n}mappedToIndex(e){return this.#i(e)?e+this.#n-this.#e:e-this.#e}isOldPacket(e){return this.mappedToIndex(e)<0}isFuturePacket(e){return this.mappedToIndex(e)>=this.#r}#i(e){return this.#e>this.#n-this.#r&&e<this.#e+this.#r-this.#n}getGeneration(e){return this.#i(e)?this.#t+1:this.#t}reset(){this.#e=0,this.#t=0}},p=4096,m=class{#e=new Int32Array(p);decompress(e){let{headerLen:t,decompressedSize:n,flags:r}=h(e),i=new Uint8Array(n);if(!(r&1))return i.set(e.slice(t,t+n)),i;this.#e.fill(0);let a={control:1,sourcePos:t,destPos:0,nextHashed:0};for(;this.#t(e,a);)if(a.control&1){if(!this.#n(e,i,a))break}else if(this.#r(e,i,n,a))break;return i}#t(e,t){return t.control===1?t.sourcePos+4>e.length?!1:(t.control=(e[t.sourcePos]|e[t.sourcePos+1]<<8|e[t.sourcePos+2]<<16|e[t.sourcePos+3]<<24)>>>0,t.sourcePos+=4,!0):!0}#n(e,t,n){if(n.control=n.control>>>1>>>0,n.sourcePos+2>e.length)return!1;let r=e[n.sourcePos],i=e[n.sourcePos+1];n.sourcePos+=2;let a=r>>4|i<<4,o=r&15;if(o!==0)o+=2;else{if(n.sourcePos>=e.length)return!1;o=e[n.sourcePos],n.sourcePos++}let s=this.#e[a];for(let e=0;e<o;e++)n.destPos<t.length&&s+e<n.destPos&&(t[n.destPos]=t[s+e],n.destPos++);let c=n.destPos+1-o;return this.#i(t,n,c),n.nextHashed=n.destPos,!0}#r(e,t,n,r){let i=Math.max(n,10)-10;if(r.destPos>=i){for(;r.destPos<n;){if(r.control===1){if(r.sourcePos+=4,r.sourcePos>e.length)break;r.control=(e[r.sourcePos-4]|e[r.sourcePos-3]<<8|e[r.sourcePos-2]<<16|e[r.sourcePos-1]<<24)>>>0}if(r.sourcePos>=e.length)break;t[r.destPos++]=e[r.sourcePos++],r.control=r.control>>>1>>>0}return!0}if(r.sourcePos>=e.length||r.destPos>=t.length)return!0;t[r.destPos++]=e[r.sourcePos++],r.control=r.control>>>1>>>0;let a=Math.max(r.destPos-2,0);return this.#i(t,r,a),r.nextHashed<a&&(r.nextHashed=a),!1}#i(e,t,n){for(;t.nextHashed<n&&!(t.nextHashed+3>e.length);){let n=(e[t.nextHashed]|e[t.nextHashed+1]<<8|e[t.nextHashed+2]<<16)>>>0,r=(n>>12^n)&4095;this.#e[r]=t.nextHashed,t.nextHashed++}}};function h(e){if(e.length<3)throw Error(`QuickLZ: data too short`);let t=e[0];if((t>>2&3)!=1)throw Error(`QuickLZ: only level 1 is supported`);let n=t&2?9:3;if(e.length<n)throw Error(`QuickLZ: data too short for header`);let r;return r=t&2?(e[5]|e[6]<<8|e[7]<<16|e[8]<<24)>>>0:e[2],{headerLen:n,decompressedSize:r,flags:t}}var g=1024,_=5e3,v=6e4,y=1e3,b=8,x=3,S=5,C=500,w=100,T=class{onPacket=null;onClosed=null;#e;#t;#n;#r=null;#i=0;#a=!1;#o=null;#s=null;#c=Date.now();#l=new Uint16Array(9);#u=new Uint32Array(9);#d=new f(65536,g);#f=new f(65536,g);#p=new f(65536,g);#m=new f(65536,g);#h=new Map;#g=new Map;#_=new Map;#v=null;constructor(t,n=e.o,r){this.#e=t,this.#t=n,this.#n=r}setClientID(e){this.#i=e}async connect(t){let{host:i,port:a}=e.r(t),o=parseInt(a,10),{address:s,family:c}=await(0,n.lookup)(i),l=c===6,u=this.#n?this.#n(l?6:4):(0,r.createSocket)(l?`udp6`:`udp4`);await new Promise((e,t)=>{let n=e=>{u.close(),t(e)};u.once(`error`,n),u.connect(o,s,()=>{u.off(`error`,n),this.start(u),e()})})}start(e){this.#r=e,this.#a=!1,this.#c=Date.now(),e.on(`message`,e=>{this.#c=Date.now(),this.#S(new Uint8Array(e.buffer,e.byteOffset,e.byteLength))}),e.on(`error`,e=>{this.#t.error(`udp error`,e),this.#z(e)}),e.on(`close`,()=>this.#z(null)),this.#l[i.Command]=1,this.#l[i.Init1]=101;let n=t.n(this.#e,null);n&&this.#b(i.Init1,n,0);let r=setInterval(()=>{this.#e.cryptoInitComplete&&this.sendPacket(i.Ping,new Uint8Array,a.Unencrypted)},_);this.#o=()=>clearInterval(r);let o=setInterval(()=>this.#L(),w);this.#s=()=>clearInterval(o)}receivedFinalInitAck(){this.#v=null}sendPacket(e,t,n){let r=!this.#e.cryptoInitComplete;if(t.length>487&&e!==i.Voice&&e!==i.VoiceWhisper){this.#y(e,t,n,r);return}this.#b(e,t,n,r)}sendVoicePacket(e,t){let n=this.#l[i.Voice],r=this.#u[i.Voice];this.#l[i.Voice]=n+1&65535,this.#l[i.Voice]===0&&this.#u[i.Voice]++;let o=x+e.length,s=new Uint8Array(o);new DataView(s.buffer).setUint16(0,n,!1),s[2]=t,s.set(e,x);let c=l({typeFlagged:i.Voice|a.Unencrypted,id:n,clientID:this.#i,generationID:r,data:s,receivedAt:0}),u=new Uint8Array(13+o);u.set(this.#e.fakeSignature,0),u.set(c,b),u.set(s,13),this.#x(u)}sendWhisperPacket(e,t,n){if(t.length===0)throw Error(`whisper requires at least one target`);if(t.length>32)throw Error(`too many whisper targets`);if(t.some(e=>!Number.isInteger(e)||e<0||e>65535))throw RangeError(`invalid whisper target`);let r=this.#l[i.VoiceWhisper],o=this.#u[i.VoiceWhisper];this.#l[i.VoiceWhisper]=r+1&65535,this.#l[i.VoiceWhisper]===0&&(this.#u[i.VoiceWhisper]=o+1>>>0);let s=S+t.length*2+e.length,c=new Uint8Array(s),u=new DataView(c.buffer);u.setUint16(0,r,!1),c[2]=n,c[3]=0,c[4]=t.length;for(let e=0;e<t.length;e++)u.setUint16(S+e*2,t[e],!1);c.set(e,S+t.length*2);let d=l({typeFlagged:i.VoiceWhisper|a.Unencrypted,id:r,clientID:this.#i,generationID:o,data:c,receivedAt:0}),f=new Uint8Array(13+s);f.set(this.#e.fakeSignature,0),f.set(d,b),f.set(c,13),this.#x(f)}close(){this.#a||(this.#a=!0,this.#o?.(),this.#s?.(),this.#r?.close())}#y(e,t,n,r){let i=0,o=!0;for(;i<t.length;){let s=Math.min(t.length-i,487),c=i+s===t.length,l=n;o!==c&&(l|=a.Fragmented),this.#b(e,t.slice(i,i+s),l,r),i+=s,o=!1}}#b(e,t,n,r=!this.#e.cryptoInitComplete){n=E(e,n);let[i,o]=this.#F(e),s={typeFlagged:e|n,id:i,clientID:this.#i,generationID:o,data:t,receivedAt:0},c=(n&a.Unencrypted)!==0,u=l(s),[d,f]=this.#e.encrypt(e,i,o,u,t,r,c),p=new Uint8Array(13+d.length);p.set(f.slice(0,b),0),p.set(u,b),p.set(d,13),this.#x(p);let m={packet:s,firstSend:Date.now(),lastSend:Date.now(),retryCount:0,nextInterval:C};this.#I(e,s,m)}#x(e){if(this.#r)try{this.#r.send(Buffer.from(e),e=>{e&&this.#t.warn(`udp send error`,e)})}catch(e){let t=e instanceof Error?e:Error(String(e));this.#t.error(`udp send failed`,t),this.#z(t)}}#S(e){if(e.length<11)return;let t=e.slice(0,b),n=e.slice(b,11),r=e.slice(11),a=u(n),s={...a,clientID:0,generationID:this.#C(a.id,a.typeFlagged&15),data:new Uint8Array,receivedAt:Date.now()},c=this.#w(s,n,r,t);if(c!==null){if(s.data=c.plaintext,o(s)===i.Ping){this.#D(s.id,c.dummyUsed);return}this.#T(s,c.dummyUsed)&&(this.#O(s),this.#P(s))}}#C(e,t){switch(t){case i.Command:return this.#d.getGeneration(e);case i.CommandLow:return this.#f.getGeneration(e);case i.Ack:return this.#p.getGeneration(e);case i.AckLow:return this.#m.getGeneration(e);default:return 0}}#w(e,t,n,r){let c=(s(e)&a.Unencrypted)!==0,l=!this.#e.cryptoInitComplete,u=l,d=o(e),f=e.generationID;try{return{plaintext:this.#e.decrypt(d,e.id,f,t,n,r,l,c),dummyUsed:u}}catch{for(let i of[-1,1]){let a=f+i;if(!(a<0))try{return{plaintext:this.#e.decrypt(d,e.id,a,t,n,r,!1,!1),dummyUsed:!1}}catch{}}if(d===i.Command||d===i.CommandLow||d===i.Ack)try{return{plaintext:this.#e.decrypt(d,e.id,f,t,n,r,!0,c),dummyUsed:!0}}catch{}return null}}#T(e,t){let n=o(e);if(n!==i.Command&&n!==i.CommandLow)return!0;let r=n===i.Command?this.#d:this.#f,a=n===i.Command?i.Ack:i.AckLow;return r.isInWindow(e.id)?(this.#E(e.id,a,t),!0):(r.isOldPacket(e.id)&&this.#E(e.id,a,t),!1)}#E(e,t,n){let r=new Uint8Array(2);new DataView(r.buffer).setUint16(0,e,!1),this.#b(t,r,0,n)}#D(e,t){let n=new Uint8Array(2);new DataView(n.buffer).setUint16(0,e,!1),this.#b(i.Pong,n,a.Unencrypted,t)}#O(e){let t=o(e);if(t!==i.Command&&t!==i.CommandLow){this.onPacket?.(e);return}let n=t===i.Command,r=n?this.#h:this.#g,a=n?this.#d:this.#f;for(r.set(e.id,e),n?this.#j(r,a,!0):this.#j(r,a,!1);;){let e=n?this.#k:this.#A,t=r.get(e);if(t===void 0)break;let i=this.#M(t,r,e,a);if(!i)break;let[o,s]=i;n?this.#k=s:this.#A=s,this.#N(o),this.onPacket?.(o)}}#k=0;#A=0;#j(e,t,n){let r=n?this.#k:this.#A;for(;!e.has(r)&&D(e,r);)r=r+1&65535,t.advance(1);n?this.#k=r:this.#A=r}#M(e,t,n,r){if((s(e)&a.Fragmented)===0)return t.delete(n),r.advance(1),[e,n+1&65535];let i=[],o=0,c=n,l=!1,u=!1;for(;;){let e=t.get(c);if(!e)return null;i.push(e),o+=e.data.length;let n=(s(e)&a.Fragmented)!==0;if(!l){if(l=!0,!n){u=!0;break}}else if(n){u=!0;break}c=c+1&65535}if(!u)return null;let d=new Uint8Array(o),f=0;for(let e of i)d.set(e.data,f),f+=e.data.length,t.delete(n),r.advance(1),n=n+1&65535;return e.data=d,e.typeFlagged&=~a.Fragmented,[e,n]}#N(e){if((s(e)&a.Compressed)!==0)try{e.data=new m().decompress(e.data),e.typeFlagged&=~a.Compressed}catch(t){this.#t.debug(`decompression failed`,{id:e.id,err:t})}}#P(e){let t=o(e);if(t===i.Init1){this.#v=null;return}if((t===i.Ack||t===i.AckLow)&&e.data.length>=2){let n=new DataView(e.data.buffer,e.data.byteOffset).getUint16(0,!1),r=(t===i.Ack?i.Command:i.CommandLow)<<16|n;this.#_.delete(r)}}#F(e){let t=this.#l[e],n=this.#u[e];return e===i.Init1?[t,n]:(this.#l[e]=t+1&65535,this.#l[e]===0&&(this.#u[e]=n+1>>>0),e===i.Command?this.#p.advanceToExcluded(t):e===i.CommandLow&&this.#m.advanceToExcluded(t),[t,n])}#I(e,t,n){if(e===i.Init1){this.#v=n;return}if(e===i.Command||e===i.CommandLow){let r=e<<16|t.id;this.#_.set(r,n)}}#L(){let e=Date.now();if(e-this.#c>v){this.#t.warn(`idle timeout`),this.#z(Error(`idle timeout`));return}this.#v&&this.#R(this.#v,e);for(let[t,n]of this.#_){if(e-n.firstSend>v){this.#_.delete(t),this.#z(Error(`packet ack timeout`));return}this.#R(n,e)}}#R(e,t){if(t-e.lastSend<e.nextInterval)return;e.lastSend=t,e.retryCount++,e.nextInterval=Math.min(e.nextInterval*2,y);let n=!this.#e.cryptoInitComplete,r=(s(e.packet)&a.Unencrypted)!==0,i=l(e.packet),c=o(e.packet),[u,d]=this.#e.encrypt(c,e.packet.id,e.packet.generationID,i,e.packet.data,n,r),f=new Uint8Array(13+u.length);f.set(d.slice(0,b),0),f.set(i,b),f.set(u,13),this.#x(f)}#z(e){this.#a||(this.close(),this.onClosed?.(e))}};function E(e,t){return e===i.Command||e===i.CommandLow?t|a.NewProtocol:t}function D(e,t){let n=Date.now();for(let[r,i]of e)if((r-t+65536&65535)<32768&&n-i.receivedAt>5e3)return!0;return!1}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return d}});
|
|
2
|
+
//# sourceMappingURL=handler-aywHvv7I.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-aywHvv7I.cjs","names":["noopLogger","splitHostPort","lookup","createSocket","processInit1","require_address","require_crypt_handshake","node_dns_promises","node_dgram","PacketType","\"Voice\"","\"VoiceWhisper\"","\"Command\"","\"CommandLow\"","\"Ping\"","\"Pong\"","\"Ack\"","\"AckLow\"","\"Init1\"","PacketFlags","\"Fragmented\"","\"NewProtocol\"","\"Compressed\"","\"Unencrypted\"","packetType","p","packetFlags","isUnencrypted","buildC2SHeader","header","view","parseS2CHeader","raw","parseC2SHeader","GenerationWindow","#mod","mod","#receiveWindow","windowSize","#generation","amount","newBaseOffset","#mappedBaseOffset","genStep","moveDist","mappedValue","maxOffset","#isNextGen","TABLE_SIZE","Qlz","parseQlzHeader","data","dest","decompressedSize","flags","headerLen","#hashtable","state","#ensureControl","#processReference","#processLiteral","st","b1","b2","hash","matchlen","offset","i","end","#updateHashtable","threshold","v","RECEIVE_PACKET_WINDOW_SIZE","PING_INTERVAL_MS","PACKET_TIMEOUT_MS","MAX_RETRY_INTERVAL_MS","TAG_SIZE","VOICE_HEADER_SIZE","WHISPER_HEADER_SIZE","RESEND_BASE_INTERVAL_MS","RESEND_LOOP_INTERVAL_MS","PacketHandler","#crypt","crypt","#logger","logger","#socketFactory","socketFactory","#clientID","id","addr","portNumber","port","host","family6","family","socket","onError","reject","error","address","resolve","#conn","conn","#closed","#lastMessageReceived","#handleRawPacket","msg","err","#triggerClose","#packetCounter","init1Data","#sendPacketRaw","pingTimer","#stopPing","resendTimer","#checkResends","#stopResend","#initPacketCheck","dummy","pType","#sendSplitPacket","pID","pGen","#generationCounter","payloadLen","voicePayload","codec","final","#write","targetClientIds","whisperPayload","index","pos","first","blockSize","last","pFlags","applyProtocolFlags","#nextPacketIdentity","unencrypted","ciphertext","tag","rp","#trackResend","normalized","parsed","#resolveGeneration","decrypted","#decryptPacketData","#sendPong","#handleCommandWindowAndAck","#handlePacketQueue","#updatePostReceiveState","#recvWindowCommand","#recvWindowCommandLow","#sendWindowCommand","#sendWindowCommandLow","dummyUsed","gen","guessGen","win","ackType","#sendAck","ackData","packetID","pongData","isCommand","queue","#commandQueue","#commandLowQueue","#fastForwardMissingPackets","current","#_nextCommandID","#_nextCommandLowID","packet","result","#tryReassemble","reassembled","newNext","#tryDecompress","nextID","hasOldNewerPacket","startPacket","fragments","totalSize","currID","startSeen","complete","frag","fragmented","combined","ackID","key","#ackManager","now","#doResend","pkg"],"sources":["../src/transport/packet.ts","../src/transport/generation-window.ts","../src/transport/quicklz.ts","../src/transport/handler.ts"],"sourcesContent":["export const enum PacketType {\n Voice = 0,\n VoiceWhisper = 1,\n Command = 2,\n CommandLow = 3,\n Ping = 4,\n Pong = 5,\n Ack = 6,\n AckLow = 7,\n Init1 = 8,\n}\n\nexport const enum PacketFlags {\n Fragmented = 0x10,\n NewProtocol = 0x20,\n Compressed = 0x40,\n Unencrypted = 0x80,\n}\n\nexport interface Packet {\n /** Type byte combined with flags (low nibble = type, high nibble = flags). */\n typeFlagged: number;\n id: number;\n clientID: number;\n generationID: number;\n data: Uint8Array;\n receivedAt: number; // Date.now()\n}\n\nexport function packetType(p: Packet): PacketType {\n return (p.typeFlagged & 0x0f) as PacketType;\n}\n\nexport function packetFlags(p: Packet): number {\n return p.typeFlagged & 0xf0;\n}\n\nexport function isUnencrypted(p: Packet): boolean {\n return (packetFlags(p) & PacketFlags.Unencrypted) !== 0;\n}\n\n/** Build the 5-byte client-to-server header: [packetID(2), clientID(2), typeFlagged(1)]. */\nexport function buildC2SHeader(p: Packet): Uint8Array {\n const header = new Uint8Array(5);\n const view = new DataView(header.buffer);\n view.setUint16(0, p.id, false);\n view.setUint16(2, p.clientID, false);\n header[4] = p.typeFlagged;\n return header;\n}\n\n/** Parse a 3-byte server-to-client header. */\nexport function parseS2CHeader(raw: Uint8Array): Pick<Packet, \"id\" | \"typeFlagged\"> {\n const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);\n return {\n id: view.getUint16(0, false),\n typeFlagged: raw[2]!,\n };\n}\n\n/** Parse a 5-byte client-to-server header. */\nexport function parseC2SHeader(raw: Uint8Array): Pick<Packet, \"id\" | \"clientID\" | \"typeFlagged\"> {\n const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);\n return {\n id: view.getUint16(0, false),\n clientID: view.getUint16(2, false),\n typeFlagged: raw[4]!,\n };\n}\n","export class GenerationWindow {\n #mappedBaseOffset = 0;\n #generation = 0;\n readonly #mod: number;\n readonly #receiveWindow: number;\n\n constructor(mod: number, windowSize: number) {\n this.#mod = mod;\n this.#receiveWindow = windowSize;\n }\n\n get generation(): number {\n return this.#generation;\n }\n\n advance(amount: number): void {\n if (amount <= 0) return;\n const newBaseOffset = this.#mappedBaseOffset + amount;\n const genStep = Math.floor(newBaseOffset / this.#mod);\n if (genStep > 0) {\n this.#generation = Math.min(this.#generation + genStep, 0xffff_ffff);\n }\n this.#mappedBaseOffset = newBaseOffset % this.#mod;\n }\n\n advanceToExcluded(mappedValue: number): void {\n let moveDist = mappedValue - this.#mappedBaseOffset;\n if (moveDist < 0) moveDist += this.#mod;\n this.advance(moveDist + 1);\n }\n\n syncTo(mappedValue: number): void {\n let moveDist = mappedValue - this.#mappedBaseOffset;\n if (moveDist < 0) moveDist += this.#mod;\n this.advance(moveDist);\n }\n\n isInWindow(mappedValue: number): boolean {\n const maxOffset = this.#mappedBaseOffset + this.#receiveWindow;\n if (maxOffset < this.#mod) {\n return mappedValue >= this.#mappedBaseOffset && mappedValue < maxOffset;\n }\n return mappedValue >= this.#mappedBaseOffset || mappedValue < maxOffset - this.#mod;\n }\n\n mappedToIndex(mappedValue: number): number {\n if (this.#isNextGen(mappedValue)) {\n return mappedValue + this.#mod - this.#mappedBaseOffset;\n }\n return mappedValue - this.#mappedBaseOffset;\n }\n\n isOldPacket(mappedValue: number): boolean {\n return this.mappedToIndex(mappedValue) < 0;\n }\n\n isFuturePacket(mappedValue: number): boolean {\n return this.mappedToIndex(mappedValue) >= this.#receiveWindow;\n }\n\n #isNextGen(mappedValue: number): boolean {\n return (\n this.#mappedBaseOffset > this.#mod - this.#receiveWindow &&\n mappedValue < this.#mappedBaseOffset + this.#receiveWindow - this.#mod\n );\n }\n\n getGeneration(mappedValue: number): number {\n if (this.#isNextGen(mappedValue)) return this.#generation + 1;\n return this.#generation;\n }\n\n reset(): void {\n this.#mappedBaseOffset = 0;\n this.#generation = 0;\n }\n}\n","const TABLE_SIZE = 4096;\n\ninterface QlzState {\n control: number;\n sourcePos: number;\n destPos: number;\n nextHashed: number;\n}\n\nexport class Qlz {\n #hashtable = new Int32Array(TABLE_SIZE);\n\n decompress(data: Uint8Array): Uint8Array {\n const { headerLen, decompressedSize, flags } = parseQlzHeader(data);\n\n const dest = new Uint8Array(decompressedSize);\n\n if ((flags & 0x01) === 0) {\n dest.set(data.slice(headerLen, headerLen + decompressedSize));\n return dest;\n }\n\n this.#hashtable.fill(0);\n\n const state: QlzState = {\n control: 1,\n sourcePos: headerLen,\n destPos: 0,\n nextHashed: 0,\n };\n\n while (this.#ensureControl(data, state)) {\n if ((state.control & 1) !== 0) {\n if (!this.#processReference(data, dest, state)) break;\n } else {\n if (this.#processLiteral(data, dest, decompressedSize, state)) break;\n }\n }\n\n return dest;\n }\n\n #ensureControl(data: Uint8Array, st: QlzState): boolean {\n if (st.control !== 1) return true;\n if (st.sourcePos + 4 > data.length) return false;\n st.control =\n (data[st.sourcePos]! |\n (data[st.sourcePos + 1]! << 8) |\n (data[st.sourcePos + 2]! << 16) |\n (data[st.sourcePos + 3]! << 24)) >>>\n 0;\n st.sourcePos += 4;\n return true;\n }\n\n #processReference(data: Uint8Array, dest: Uint8Array, st: QlzState): boolean {\n st.control = (st.control >>> 1) >>> 0;\n if (st.sourcePos + 2 > data.length) return false;\n\n const b1 = data[st.sourcePos]!;\n const b2 = data[st.sourcePos + 1]!;\n st.sourcePos += 2;\n\n const hash = (b1 >> 4) | (b2 << 4);\n let matchlen = b1 & 0x0f;\n if (matchlen !== 0) {\n matchlen += 2;\n } else {\n if (st.sourcePos >= data.length) return false;\n matchlen = data[st.sourcePos]!;\n st.sourcePos++;\n }\n\n const offset = this.#hashtable[hash]!;\n for (let i = 0; i < matchlen; i++) {\n if (st.destPos < dest.length && offset + i < st.destPos) {\n dest[st.destPos] = dest[offset + i]!;\n st.destPos++;\n }\n }\n\n const end = st.destPos + 1 - matchlen;\n this.#updateHashtable(dest, st, end);\n st.nextHashed = st.destPos;\n\n return true;\n }\n\n #processLiteral(\n data: Uint8Array,\n dest: Uint8Array,\n decompressedSize: number,\n st: QlzState,\n ): boolean {\n const threshold = Math.max(decompressedSize, 10) - 10;\n if (st.destPos >= threshold) {\n while (st.destPos < decompressedSize) {\n if (st.control === 1) {\n st.sourcePos += 4;\n if (st.sourcePos > data.length) break;\n st.control =\n (data[st.sourcePos - 4]! |\n (data[st.sourcePos - 3]! << 8) |\n (data[st.sourcePos - 2]! << 16) |\n (data[st.sourcePos - 1]! << 24)) >>>\n 0;\n }\n if (st.sourcePos >= data.length) break;\n dest[st.destPos++] = data[st.sourcePos++]!;\n st.control = (st.control >>> 1) >>> 0;\n }\n return true;\n }\n\n if (st.sourcePos >= data.length || st.destPos >= dest.length) return true;\n\n dest[st.destPos++] = data[st.sourcePos++]!;\n st.control = (st.control >>> 1) >>> 0;\n\n const end = Math.max(st.destPos - 2, 0);\n this.#updateHashtable(dest, st, end);\n if (st.nextHashed < end) st.nextHashed = end;\n\n return false;\n }\n\n #updateHashtable(dest: Uint8Array, st: QlzState, end: number): void {\n while (st.nextHashed < end) {\n if (st.nextHashed + 3 > dest.length) break;\n const v =\n (dest[st.nextHashed]! |\n (dest[st.nextHashed + 1]! << 8) |\n (dest[st.nextHashed + 2]! << 16)) >>>\n 0;\n const hash = ((v >> 12) ^ v) & 0xfff;\n this.#hashtable[hash] = st.nextHashed;\n st.nextHashed++;\n }\n }\n}\n\nfunction parseQlzHeader(data: Uint8Array): {\n headerLen: number;\n decompressedSize: number;\n flags: number;\n} {\n if (data.length < 3) throw new Error(\"QuickLZ: data too short\");\n\n const flags = data[0]!;\n const level = (flags >> 2) & 0x03;\n if (level !== 1) throw new Error(\"QuickLZ: only level 1 is supported\");\n\n const headerLen = (flags & 0x02) !== 0 ? 9 : 3;\n if (data.length < headerLen) throw new Error(\"QuickLZ: data too short for header\");\n\n let decompressedSize: number;\n if ((flags & 0x02) !== 0) {\n decompressedSize = (data[5]! | (data[6]! << 8) | (data[7]! << 16) | (data[8]! << 24)) >>> 0;\n } else {\n decompressedSize = data[2]!;\n }\n\n return { headerLen, decompressedSize, flags };\n}\n","import { createSocket, type Socket as UdpSocket } from \"node:dgram\";\nimport { lookup } from \"node:dns/promises\";\nimport { splitHostPort } from \"../address.js\";\nimport type { Crypt } from \"../crypto/crypt.js\";\nimport type { Logger } from \"../types.js\";\nimport { noopLogger } from \"../types.js\";\nimport {\n type Packet,\n PacketType,\n PacketFlags,\n packetType,\n packetFlags,\n buildC2SHeader,\n parseS2CHeader,\n} from \"./packet.js\";\nimport { GenerationWindow } from \"./generation-window.js\";\nimport { Qlz } from \"./quicklz.js\";\nimport { processInit1 } from \"../handshake/crypt-handshake.js\";\n\nconst MAX_OUT_PACKET_SIZE = 500;\nconst RECEIVE_PACKET_WINDOW_SIZE = 1024;\nconst PING_INTERVAL_MS = 5_000;\nconst PACKET_TIMEOUT_MS = 60_000;\nconst MAX_RETRY_INTERVAL_MS = 1_000;\nconst HEADER_SIZE = 5;\nconst TAG_SIZE = 8;\nconst VOICE_HEADER_SIZE = 3;\nconst WHISPER_HEADER_SIZE = 5;\nconst RESEND_BASE_INTERVAL_MS = 500;\nconst RESEND_LOOP_INTERVAL_MS = 100;\n\ninterface ResendPacket {\n packet: Packet;\n firstSend: number;\n lastSend: number;\n retryCount: number;\n nextInterval: number;\n}\n\n/**\n * Creates the UDP socket the client talks through.\n *\n * Receives the resolved address family (4 or 6) and returns a socket of that\n * family. Supplying one lets an application route through a proxy or tunnel,\n * or drive the client from something other than a real socket.\n */\nexport type SocketFactory = (family: 4 | 6) => UdpSocket;\n\nexport class PacketHandler {\n onPacket: ((p: Packet) => void) | null = null;\n onClosed: ((err: Error | null) => void) | null = null;\n\n readonly #crypt: Crypt;\n readonly #logger: Logger;\n readonly #socketFactory: SocketFactory | undefined;\n\n #conn: UdpSocket | null = null;\n #clientID = 0;\n #closed = false;\n #stopPing: (() => void) | null = null;\n #stopResend: (() => void) | null = null;\n #lastMessageReceived = Date.now();\n\n #packetCounter = new Uint16Array(9);\n #generationCounter = new Uint32Array(9);\n\n #recvWindowCommand = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #recvWindowCommandLow = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #sendWindowCommand = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #sendWindowCommandLow = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n\n #commandQueue = new Map<number, Packet>();\n #commandLowQueue = new Map<number, Packet>();\n #ackManager = new Map<number, ResendPacket>();\n #initPacketCheck: ResendPacket | null = null;\n\n constructor(crypt: Crypt, logger: Logger = noopLogger, socketFactory?: SocketFactory) {\n this.#crypt = crypt;\n this.#logger = logger;\n this.#socketFactory = socketFactory;\n }\n\n setClientID(id: number): void {\n this.#clientID = id;\n }\n\n async connect(addr: string): Promise<void> {\n const { host, port } = splitHostPort(addr);\n const portNumber = parseInt(port, 10);\n\n // Resolve before choosing a socket family. `isIP()` only recognises literal\n // addresses and returns 0 for every hostname, so picking the family from it\n // sent every hostname to a udp4 socket — and a udp4 socket handed a name\n // that resolves to IPv6 drops the datagrams with no error at all. On a\n // stock macOS/Linux box `localhost` resolves to ::1 first, so that path\n // silently never connected. Let DNS decide, then match the family.\n const { address, family } = await lookup(host);\n\n const family6 = family === 6;\n const socket = this.#socketFactory\n ? this.#socketFactory(family6 ? 6 : 4)\n : createSocket(family6 ? \"udp6\" : \"udp4\");\n\n await new Promise<void>((resolve, reject) => {\n const onError = (error: Error) => {\n socket.close();\n reject(error);\n };\n socket.once(\"error\", onError);\n // Connect to the resolved address, not the original host, so the socket\n // cannot end up talking to a different family than it was created for.\n socket.connect(portNumber, address, () => {\n socket.off(\"error\", onError);\n this.start(socket);\n resolve();\n });\n });\n }\n\n start(conn: UdpSocket): void {\n this.#conn = conn;\n this.#closed = false;\n this.#lastMessageReceived = Date.now();\n\n conn.on(\"message\", (msg) => {\n this.#lastMessageReceived = Date.now();\n this.#handleRawPacket(new Uint8Array(msg.buffer, msg.byteOffset, msg.byteLength));\n });\n conn.on(\"error\", (err) => {\n this.#logger.error(\"udp error\", err);\n this.#triggerClose(err);\n });\n conn.on(\"close\", () => this.#triggerClose(null));\n\n this.#packetCounter[PacketType.Command] = 1;\n this.#packetCounter[PacketType.Init1] = 101;\n\n const init1Data = processInit1(this.#crypt, null);\n if (init1Data) this.#sendPacketRaw(PacketType.Init1, init1Data, 0);\n\n // Ping loop\n const pingTimer = setInterval(() => {\n if (this.#crypt.cryptoInitComplete) {\n this.sendPacket(PacketType.Ping, new Uint8Array(0), PacketFlags.Unencrypted);\n }\n }, PING_INTERVAL_MS);\n this.#stopPing = () => clearInterval(pingTimer);\n\n // Resend loop\n const resendTimer = setInterval(() => this.#checkResends(), RESEND_LOOP_INTERVAL_MS);\n this.#stopResend = () => clearInterval(resendTimer);\n }\n\n receivedFinalInitAck(): void {\n this.#initPacketCheck = null;\n }\n\n sendPacket(pType: PacketType, data: Uint8Array, flags: number): void {\n const dummy = !this.#crypt.cryptoInitComplete;\n if (data.length > 487 && pType !== PacketType.Voice && pType !== PacketType.VoiceWhisper) {\n this.#sendSplitPacket(pType, data, flags, dummy);\n return;\n }\n this.#sendPacketRaw(pType, data, flags, dummy);\n }\n\n sendVoicePacket(data: Uint8Array, codec: number): void {\n const pID = this.#packetCounter[PacketType.Voice]!;\n const pGen = this.#generationCounter[PacketType.Voice]!;\n this.#packetCounter[PacketType.Voice] = (pID + 1) & 0xffff;\n if (this.#packetCounter[PacketType.Voice] === 0) {\n this.#generationCounter[PacketType.Voice]!++;\n }\n\n const payloadLen = VOICE_HEADER_SIZE + data.length;\n const voicePayload = new Uint8Array(payloadLen);\n new DataView(voicePayload.buffer).setUint16(0, pID, false);\n voicePayload[2] = codec;\n voicePayload.set(data, VOICE_HEADER_SIZE);\n\n const p: Packet = {\n typeFlagged: PacketType.Voice | PacketFlags.Unencrypted,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data: voicePayload,\n receivedAt: 0,\n };\n\n const header = buildC2SHeader(p);\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + payloadLen);\n final.set(this.#crypt.fakeSignature, 0);\n final.set(header, TAG_SIZE);\n final.set(voicePayload, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n /** Send an unencrypted TeamSpeak voice whisper packet to up to 32 clients. */\n sendWhisperPacket(data: Uint8Array, targetClientIds: number[], codec: number): void {\n if (targetClientIds.length === 0) throw new Error(\"whisper requires at least one target\");\n if (targetClientIds.length > 32) throw new Error(\"too many whisper targets\");\n if (targetClientIds.some((id) => !Number.isInteger(id) || id < 0 || id > 0xffff)) {\n throw new RangeError(\"invalid whisper target\");\n }\n\n const pID = this.#packetCounter[PacketType.VoiceWhisper]!;\n const pGen = this.#generationCounter[PacketType.VoiceWhisper]!;\n this.#packetCounter[PacketType.VoiceWhisper] = (pID + 1) & 0xffff;\n if (this.#packetCounter[PacketType.VoiceWhisper] === 0) {\n this.#generationCounter[PacketType.VoiceWhisper] = (pGen + 1) >>> 0;\n }\n\n const payloadLen = WHISPER_HEADER_SIZE + targetClientIds.length * 2 + data.length;\n const whisperPayload = new Uint8Array(payloadLen);\n const view = new DataView(whisperPayload.buffer);\n view.setUint16(0, pID, false);\n whisperPayload[2] = codec;\n whisperPayload[3] = 0;\n whisperPayload[4] = targetClientIds.length;\n for (let index = 0; index < targetClientIds.length; index++) {\n view.setUint16(WHISPER_HEADER_SIZE + index * 2, targetClientIds[index]!, false);\n }\n whisperPayload.set(data, WHISPER_HEADER_SIZE + targetClientIds.length * 2);\n\n const packet: Packet = {\n typeFlagged: PacketType.VoiceWhisper | PacketFlags.Unencrypted,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data: whisperPayload,\n receivedAt: 0,\n };\n const header = buildC2SHeader(packet);\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + payloadLen);\n final.set(this.#crypt.fakeSignature, 0);\n final.set(header, TAG_SIZE);\n final.set(whisperPayload, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n close(): void {\n if (this.#closed) return;\n this.#closed = true;\n this.#stopPing?.();\n this.#stopResend?.();\n this.#conn?.close();\n }\n\n // ---- Private ---------------------------------------------------------------\n\n #sendSplitPacket(pType: PacketType, data: Uint8Array, flags: number, dummy: boolean): void {\n const maxSize = MAX_OUT_PACKET_SIZE - HEADER_SIZE - TAG_SIZE; // 487\n let pos = 0;\n let first = true;\n\n while (pos < data.length) {\n const blockSize = Math.min(data.length - pos, maxSize);\n const last = pos + blockSize === data.length;\n\n let pFlags = flags;\n if (first !== last) pFlags |= PacketFlags.Fragmented;\n\n this.#sendPacketRaw(pType, data.slice(pos, pos + blockSize), pFlags, dummy);\n pos += blockSize;\n first = false;\n }\n }\n\n #sendPacketRaw(\n pType: PacketType,\n data: Uint8Array,\n flags: number,\n dummy = !this.#crypt.cryptoInitComplete,\n ): void {\n flags = applyProtocolFlags(pType, flags);\n const [pID, pGen] = this.#nextPacketIdentity(pType);\n const p: Packet = {\n typeFlagged: pType | flags,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data,\n receivedAt: 0,\n };\n\n const unencrypted = (flags & PacketFlags.Unencrypted) !== 0;\n const header = buildC2SHeader(p);\n const [ciphertext, tag] = this.#crypt.encrypt(\n pType,\n pID,\n pGen,\n header,\n data,\n dummy,\n unencrypted,\n );\n\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + ciphertext.length);\n final.set(tag.slice(0, TAG_SIZE), 0);\n final.set(header, TAG_SIZE);\n final.set(ciphertext, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n\n const rp: ResendPacket = {\n packet: p,\n firstSend: Date.now(),\n lastSend: Date.now(),\n retryCount: 0,\n nextInterval: RESEND_BASE_INTERVAL_MS,\n };\n this.#trackResend(pType, p, rp);\n }\n\n #write(data: Uint8Array): void {\n if (!this.#conn) return;\n try {\n this.#conn.send(Buffer.from(data), (err) => {\n if (err) this.#logger.warn(\"udp send error\", err);\n });\n } catch (error: unknown) {\n const normalized = error instanceof Error ? error : new Error(String(error));\n // dgram can throw synchronously for an invalid family/address pair. A\n // malformed remote target must close this session, never escape from an\n // async socket callback and terminate the gateway process.\n this.#logger.error(\"udp send failed\", normalized);\n this.#triggerClose(normalized);\n }\n }\n\n #handleRawPacket(raw: Uint8Array): void {\n if (raw.length < 11) return;\n\n const tag = raw.slice(0, TAG_SIZE);\n const header = raw.slice(TAG_SIZE, TAG_SIZE + 3);\n const ciphertext = raw.slice(TAG_SIZE + 3);\n\n const parsed = parseS2CHeader(header);\n const p: Packet = {\n ...parsed,\n clientID: 0,\n generationID: this.#resolveGeneration(parsed.id, parsed.typeFlagged & 0x0f),\n data: new Uint8Array(0),\n receivedAt: Date.now(),\n };\n\n const decrypted = this.#decryptPacketData(p, header, ciphertext, tag);\n if (decrypted === null) return;\n p.data = decrypted.plaintext;\n\n const pType = packetType(p);\n\n if (pType === PacketType.Ping) {\n this.#sendPong(p.id, decrypted.dummyUsed);\n return;\n }\n\n if (!this.#handleCommandWindowAndAck(p, decrypted.dummyUsed)) return;\n\n this.#handlePacketQueue(p);\n this.#updatePostReceiveState(p);\n }\n\n #resolveGeneration(id: number, pType: number): number {\n switch (pType as PacketType) {\n case PacketType.Command:\n return this.#recvWindowCommand.getGeneration(id);\n case PacketType.CommandLow:\n return this.#recvWindowCommandLow.getGeneration(id);\n case PacketType.Ack:\n return this.#sendWindowCommand.getGeneration(id);\n case PacketType.AckLow:\n return this.#sendWindowCommandLow.getGeneration(id);\n default:\n return 0;\n }\n }\n\n #decryptPacketData(\n p: Packet,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): { plaintext: Uint8Array; dummyUsed: boolean } | null {\n const unencrypted = (packetFlags(p) & PacketFlags.Unencrypted) !== 0;\n const dummy = !this.#crypt.cryptoInitComplete;\n let dummyUsed = dummy;\n const pType = packetType(p);\n const gen = p.generationID;\n\n try {\n const plaintext = this.#crypt.decrypt(\n pType,\n p.id,\n gen,\n header,\n ciphertext,\n tag,\n dummy,\n unencrypted,\n );\n return { plaintext, dummyUsed };\n } catch {\n // Try adjacent generations\n for (const offset of [-1, 1]) {\n const guessGen = gen + offset;\n if (guessGen < 0) continue;\n try {\n const plaintext = this.#crypt.decrypt(\n pType,\n p.id,\n guessGen,\n header,\n ciphertext,\n tag,\n false,\n false,\n );\n return { plaintext, dummyUsed: false };\n } catch {\n // continue\n }\n }\n\n // Try dummy fallback for command/ack types\n if (\n pType === PacketType.Command ||\n pType === PacketType.CommandLow ||\n pType === PacketType.Ack\n ) {\n try {\n const plaintext = this.#crypt.decrypt(\n pType,\n p.id,\n gen,\n header,\n ciphertext,\n tag,\n true,\n unencrypted,\n );\n return { plaintext, dummyUsed: true };\n } catch {\n // fall through\n }\n }\n\n return null;\n }\n }\n\n #handleCommandWindowAndAck(p: Packet, dummyUsed: boolean): boolean {\n const pType = packetType(p);\n if (pType !== PacketType.Command && pType !== PacketType.CommandLow) return true;\n\n const win = pType === PacketType.Command ? this.#recvWindowCommand : this.#recvWindowCommandLow;\n const ackType = pType === PacketType.Command ? PacketType.Ack : PacketType.AckLow;\n\n if (!win.isInWindow(p.id)) {\n if (win.isOldPacket(p.id)) {\n this.#sendAck(p.id, ackType, dummyUsed);\n }\n return false;\n }\n this.#sendAck(p.id, ackType, dummyUsed);\n return true;\n }\n\n #sendAck(packetID: number, ackType: PacketType, dummyUsed: boolean): void {\n const ackData = new Uint8Array(2);\n new DataView(ackData.buffer).setUint16(0, packetID, false);\n this.#sendPacketRaw(ackType, ackData, 0, dummyUsed);\n }\n\n #sendPong(pID: number, dummyUsed: boolean): void {\n const pongData = new Uint8Array(2);\n new DataView(pongData.buffer).setUint16(0, pID, false);\n this.#sendPacketRaw(PacketType.Pong, pongData, PacketFlags.Unencrypted, dummyUsed);\n }\n\n #handlePacketQueue(p: Packet): void {\n const pType = packetType(p);\n if (pType !== PacketType.Command && pType !== PacketType.CommandLow) {\n this.onPacket?.(p);\n return;\n }\n\n const isCommand = pType === PacketType.Command;\n const queue = isCommand ? this.#commandQueue : this.#commandLowQueue;\n const win = isCommand ? this.#recvWindowCommand : this.#recvWindowCommandLow;\n\n queue.set(p.id, p);\n\n if (isCommand) {\n this.#fastForwardMissingPackets(queue, win, true);\n } else {\n this.#fastForwardMissingPackets(queue, win, false);\n }\n\n while (true) {\n const current = isCommand ? this.#_nextCommandID : this.#_nextCommandLowID;\n const packet = queue.get(current);\n if (packet === undefined) break;\n\n const result = this.#tryReassemble(packet, queue, current, win);\n if (!result) break;\n\n const [reassembled, newNext] = result;\n if (isCommand) this.#_nextCommandID = newNext;\n else this.#_nextCommandLowID = newNext;\n\n this.#tryDecompress(reassembled);\n this.onPacket?.(reassembled);\n }\n }\n\n #_nextCommandID = 0;\n #_nextCommandLowID = 0;\n\n #fastForwardMissingPackets(\n queue: Map<number, Packet>,\n win: GenerationWindow,\n isCommand: boolean,\n ): void {\n let nextID = isCommand ? this.#_nextCommandID : this.#_nextCommandLowID;\n while (!queue.has(nextID) && hasOldNewerPacket(queue, nextID)) {\n nextID = (nextID + 1) & 0xffff;\n win.advance(1);\n }\n if (isCommand) this.#_nextCommandID = nextID;\n else this.#_nextCommandLowID = nextID;\n }\n\n #tryReassemble(\n startPacket: Packet,\n queue: Map<number, Packet>,\n nextID: number,\n win: GenerationWindow,\n ): [reassembled: Packet, newNextID: number] | null {\n if ((packetFlags(startPacket) & PacketFlags.Fragmented) === 0) {\n queue.delete(nextID);\n win.advance(1);\n return [startPacket, (nextID + 1) & 0xffff];\n }\n\n const fragments: Packet[] = [];\n let totalSize = 0;\n let currID = nextID;\n let startSeen = false;\n let complete = false;\n\n while (true) {\n const frag = queue.get(currID);\n if (!frag) return null;\n fragments.push(frag);\n totalSize += frag.data.length;\n\n const fragmented = (packetFlags(frag) & PacketFlags.Fragmented) !== 0;\n if (!startSeen) {\n startSeen = true;\n if (!fragmented) {\n complete = true;\n break;\n }\n } else if (fragmented) {\n complete = true;\n break;\n }\n currID = (currID + 1) & 0xffff;\n }\n\n if (!complete) return null;\n\n const combined = new Uint8Array(totalSize);\n let pos = 0;\n for (const frag of fragments) {\n combined.set(frag.data, pos);\n pos += frag.data.length;\n queue.delete(nextID);\n win.advance(1);\n nextID = (nextID + 1) & 0xffff;\n }\n\n startPacket.data = combined;\n startPacket.typeFlagged &= ~PacketFlags.Fragmented;\n return [startPacket, nextID];\n }\n\n #tryDecompress(packet: Packet): void {\n if ((packetFlags(packet) & PacketFlags.Compressed) === 0) return;\n try {\n const qlz = new Qlz();\n packet.data = qlz.decompress(packet.data);\n packet.typeFlagged &= ~PacketFlags.Compressed;\n } catch (err) {\n this.#logger.debug(\"decompression failed\", { id: packet.id, err });\n }\n }\n\n #updatePostReceiveState(p: Packet): void {\n const pType = packetType(p);\n\n if (pType === PacketType.Init1) {\n this.#initPacketCheck = null;\n return;\n }\n\n if ((pType === PacketType.Ack || pType === PacketType.AckLow) && p.data.length >= 2) {\n const ackID = new DataView(p.data.buffer, p.data.byteOffset).getUint16(0, false);\n const targetType = pType === PacketType.Ack ? PacketType.Command : PacketType.CommandLow;\n const key = (targetType << 16) | ackID;\n this.#ackManager.delete(key);\n }\n }\n\n #nextPacketIdentity(pType: PacketType): [id: number, gen: number] {\n const pID = this.#packetCounter[pType]!;\n const pGen = this.#generationCounter[pType]!;\n\n if (pType === PacketType.Init1) return [pID, pGen];\n\n this.#packetCounter[pType] = (pID + 1) & 0xffff;\n if (this.#packetCounter[pType] === 0) {\n this.#generationCounter[pType] = (pGen + 1) >>> 0;\n }\n\n if (pType === PacketType.Command) {\n this.#sendWindowCommand.advanceToExcluded(pID);\n } else if (pType === PacketType.CommandLow) {\n this.#sendWindowCommandLow.advanceToExcluded(pID);\n }\n\n return [pID, pGen];\n }\n\n #trackResend(pType: PacketType, p: Packet, rp: ResendPacket): void {\n if (pType === PacketType.Init1) {\n this.#initPacketCheck = rp;\n return;\n }\n if (pType === PacketType.Command || pType === PacketType.CommandLow) {\n const key = (pType << 16) | p.id;\n this.#ackManager.set(key, rp);\n }\n }\n\n #checkResends(): void {\n const now = Date.now();\n\n if (now - this.#lastMessageReceived > PACKET_TIMEOUT_MS) {\n this.#logger.warn(\"idle timeout\");\n this.#triggerClose(new Error(\"idle timeout\"));\n return;\n }\n\n if (this.#initPacketCheck) {\n this.#doResend(this.#initPacketCheck, now);\n }\n\n for (const [key, rp] of this.#ackManager) {\n if (now - rp.firstSend > PACKET_TIMEOUT_MS) {\n this.#ackManager.delete(key);\n this.#triggerClose(new Error(\"packet ack timeout\"));\n return;\n }\n this.#doResend(rp, now);\n }\n }\n\n #doResend(rp: ResendPacket, now: number): void {\n if (now - rp.lastSend < rp.nextInterval) return;\n\n rp.lastSend = now;\n rp.retryCount++;\n rp.nextInterval = Math.min(rp.nextInterval * 2, MAX_RETRY_INTERVAL_MS);\n\n const dummy = !this.#crypt.cryptoInitComplete;\n const unencrypted = (packetFlags(rp.packet) & PacketFlags.Unencrypted) !== 0;\n const header = buildC2SHeader(rp.packet);\n const pType = packetType(rp.packet);\n\n const [ciphertext, tag] = this.#crypt.encrypt(\n pType,\n rp.packet.id,\n rp.packet.generationID,\n header,\n rp.packet.data,\n dummy,\n unencrypted,\n );\n\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + ciphertext.length);\n final.set(tag.slice(0, TAG_SIZE), 0);\n final.set(header, TAG_SIZE);\n final.set(ciphertext, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n #triggerClose(err: Error | null): void {\n if (this.#closed) return;\n this.close();\n this.onClosed?.(err);\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction applyProtocolFlags(pType: PacketType, flags: number): number {\n if (pType === PacketType.Command || pType === PacketType.CommandLow) {\n return flags | PacketFlags.NewProtocol;\n }\n return flags;\n}\n\nfunction hasOldNewerPacket(queue: Map<number, Packet>, nextID: number): boolean {\n const now = Date.now();\n for (const [id, pkg] of queue) {\n const diff = (id - nextID + 0x10000) & 0xffff;\n if (diff < 0x8000 && now - pkg.receivedAt > 5_000) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":"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"}
|
package/dist/handshake/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../crypt-handshake-CQkQreLx.cjs"),t=require("../crypt-init2-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../crypt-handshake-CQkQreLx.cjs"),t=require("../crypt-init2-Bkee1YxV.cjs");exports.INIT_VERSION=e.t,exports.LicenseChain=t.n,exports.cryptoInit2=t.t,exports.parseLicenses=t.r,exports.processInit1=e.n;
|
package/dist/handshake/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as e, t } from "../crypt-handshake-DziOY4Lq.js";
|
|
2
|
-
import { n, r, t as i } from "../crypt-init2-
|
|
2
|
+
import { n, r, t as i } from "../crypt-init2-BcGT--df.js";
|
|
3
3
|
export { t as INIT_VERSION, n as LicenseChain, i as cryptoInit2, r as parseLicenses, e as processInit1 };
|
package/dist/handshake.d.ts
CHANGED
|
@@ -5,5 +5,14 @@ export declare function handleHandshakeInitIV(client: Client, params: Record<str
|
|
|
5
5
|
export declare function handleHandshakeExpand2(client: Client, params: Record<string, string>): void;
|
|
6
6
|
/** Handle `initserver` — marks the client as connected. */
|
|
7
7
|
export declare function handleInitServer(client: Client, params: Record<string, string>): void;
|
|
8
|
+
/**
|
|
9
|
+
* Encode a password field for the command protocol.
|
|
10
|
+
*
|
|
11
|
+
* TeamSpeak expects password fields as base64(sha1(password)) — server and
|
|
12
|
+
* channel passwords during the handshake, the `clientmove` channel password,
|
|
13
|
+
* and the `cpw` field of the file transfer commands. Sending the plain text
|
|
14
|
+
* instead makes the server reject correct passwords with error 781.
|
|
15
|
+
*/
|
|
16
|
+
export declare function prepareClientPassword(password: string): string;
|
|
8
17
|
export declare function sendClientInit(client: Client): void;
|
|
9
18
|
//# sourceMappingURL=handshake.d.ts.map
|
package/dist/handshake.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../src/handshake.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../src/handshake.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,mEAAmE;AACnE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAQ1F;AAED,sEAAsE;AACtE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAY3F;AAED,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CA0BrF;AAwBD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG9D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGnD"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./address-BR-5unVo.cjs"),t=require("./primitives-cNNAeFCo.cjs"),n=require("./crypto-CDlweUL3.cjs"),r=require("./resolver-DCcmyWSK.cjs"),i=require("./handler-DuwoO5RC.cjs"),a=require("./command-DAK4pUBP.cjs"),o=require("./crypt-handshake-CQkQreLx.cjs"),s=require("./crypt-init2-DparLekm.cjs"),c=require("./parser-CL33R9tr.cjs");let l=require("node:crypto"),u=require("node:net");var d=class{#e=new Map;#t=0;#n=[];#r=!1;register(){this.#t++;let e=this.#t;return[e,new Promise(t=>{this.#e.set(e,t)})]}unregister(e){this.#e.delete(e)}signalWelcomeComplete(){this.#r=!0,this.#n=[]}buffer(e){this.#r&&this.#e.size!==0&&this.#n.push(e)}resolve(e,t){let n=this.#e.get(e);if(!n){this.#n=[];return}let r=this.#n;this.#n=[],this.#e.delete(e),n({err:t,data:r})}discardBuffer(){this.#n=[]}reset(){this.#e.clear(),this.#n=[],this.#r=!1,this.#t=0}};function f(e){let n=e.id??`0`,r=e.msg??``,i=e.return_code,a=null;n!==`0`&&(a=new t.C(n,r));let o=null;if(i!==void 0&&i!==``){let e=parseInt(i,10);isNaN(e)||(o=e)}return{err:a,rc:o}}function p(e,t){return e.includes(`return_code=`)?e:`${e} return_code=${t}`}var m=class{#e=new Map;#t=0;register(){this.#t++,this.#t>65535&&(this.#t=1);let e=this.#t;return[e,new Promise(t=>{this.#e.set(e,t)})]}unregister(e){this.#e.delete(e)}notify(e,t){let n=this.#e.get(e);n&&n(t)}reset(){this.#e.clear(),this.#t=0}};function h(e,n,r){return new Promise((i,a)=>{let o=(0,u.createConnection)({host:e,port:n},()=>{o.write(r,e=>{e?(o.destroy(),a(new t.b(`failed to send transfer key: ${e.message}`))):i(o)})});o.setTimeout(1e4),o.once(`error`,a),o.once(`timeout`,()=>{o.destroy(),a(new t.b(`connection timeout`))})})}async function g(e,t,n){let r=await h(e,t.port,t.fileTransferKey);await new Promise((e,t)=>{n.pipe(r),r.on(`finish`,e),r.on(`error`,t)})}async function _(e,t,n){let r=await h(e,t.port,t.fileTransferKey);await new Promise((e,t)=>{r.pipe(n),n.on(`finish`,e),r.on(`error`,t),n.on(`error`,t)})}function v(e,t,n,r,i,o){let s=t.startsWith(`/`)?t:`/${t}`;return a.t(`ftinitupload`,{cid:String(e),name:s,cpw:n,size:String(r),clientftfid:String(i),overwrite:o?`1`:`0`,resume:`0`})}function y(e,t,n,r){let i=t.startsWith(`/`)?t:`/${t}`;return a.t(`ftinitdownload`,{cid:String(e),name:i,cpw:n,clientftfid:String(r),seekpos:`0`})}function b(e,t){let n=t;for(let t=e.length-1;t>=0;t--)n=e[t](n);return n}function x(e,t){let n=t;for(let t=e.length-1;t>=0;t--)n=e[t](n);return n}function S(e,t){let n=t.alpha??``,r=t.beta??``,i=t.omega??``;e.crypt.initCrypto(n,r,i),e.logger.info(`crypto initialized (P-256 path), sending clientinit`),O(e)}function C(e,t){e.logger.info(`received initivexpand2`),e.handler.receivedFinalInitAck();let n=t.l??``,r=t.omega??``,i=t.proof??``,a=t.beta??``,o=T(e,a);s.t(e.crypt,n,r,i,a,o),O(e)}function w(e,t){let n=t.aclid??t.clid??``,r=n?parseInt(n,10):0;r>0&&(e.clid=r,e.handler.setClientID(r)),e.logger.info(`connected to server`,{selfId:e.clid}),e._markConnected(),setImmediate(()=>{let t=a.t(`clientupdate`,{client_input_muted:`0`,client_output_muted:`0`});e.sendCommandNoWait(t).catch(()=>{})})}function T(e,n){let[r,o]=t.r(),s=Buffer.from(r).toString(`base64`),c=E(e,r,n),l=a.n(`clientek`,[[`ek`,s],[`proof`,c]]);return e.handler.sendPacket(i.a.Command,Buffer.from(l),0),o}function E(e,n,r){let i=Buffer.from(r,`base64`),a=new Uint8Array(86);a.set(n.slice(0,32)),a.set(i.slice(0,Math.min(54,i.length)),32);let o=t.o(e.crypt.identity.privateKey,a);return Buffer.from(o).toString(`base64`)}function D(e){return e===``?``:(0,l.createHash)(`sha1`).update(e).digest().toString(`base64`)}function O(e){let t=k(e);e.handler.sendPacket(i.a.Command,Buffer.from(t),0)}function k(e){let t=e.crypt.identity.publicKeyBase64(),n=e.getClientInitOptions(),r=D(n.defaultChannelPassword),i=D(n.serverPassword),o=(0,l.createHash)(`sha1`).update(t).digest().toString(`base64`);return a.n(`clientinit`,[[`client_nickname`,e.nickname],[`client_version`,`3.?.? [Build: 5680278000]`],[`client_platform`,`Windows`],[`client_input_hardware`,`1`],[`client_output_hardware`,`1`],[`client_default_channel`,n.defaultChannel],[`client_default_channel_password`,r],[`client_server_password`,i],[`client_meta_data`,``],[`client_version_sign`,`DX5NIYLvfJEUjuIbCidnoeozxIDRRkpq3I9vVMBmE9L2qnekOoBzSenkzsg2lC9CMv8K5hkEzhr2TYUYSwUXCg==`],[`client_key_offset`,String(e.crypt.identity.offset)],[`client_nickname_phonetic`,``],[`client_default_token`,``],[`hwid`,o]])}function A(e){if(e===``||e===void 0)return 0n;try{return BigInt(e)}catch{return 0n}}function j(e){let t=parseInt(e,10);return isNaN(t)||t<0||t>65535?0:t}function M(e){let t=parseInt(e,10);return isNaN(t)?0:t}function N(e,t){if(t===e)return!0;if(!t.startsWith(e))return!1;let n=t.slice(e.length);return/^\d+$/.test(n)}function P(e){let t=e.indexOf(` `);if(t<0)return[e];let n=e.slice(0,t),r=e.slice(t+1);if(!r.includes(`|`))return[e];let i=r.split(`|`),a=[],o=new Map;for(let e of i){if(e===``)continue;let t=e.split(` `).filter(Boolean),r=new Set;for(let e of t)r.add(F(e));let i=[];for(let[e,t]of o)r.has(e)||i.push(t);let s=[...i,...t];a.push(`${n} ${s.join(` `)}`),o=new Map;for(let e of s)o.set(F(e),e)}return a.length===0?[e]:a}function F(e){let t=e.indexOf(`=`);return t>0?e.slice(0,t):e}function ee(e,t,n,r){switch(e.name){case`notifycliententerview`:return I(e,n,r);case`notifyclientleftview`:return L(e,t,n);case`notifyclientmoved`:return R(e,n);case`notifytextmessage`:return z(e,n);case`notifyclientpoke`:return U(e);case`notifystartupload`:return{kind:`startUpload`,info:B(e)};case`notifystartdownload`:return{kind:`startDownload`,info:V(e)};case`notifystatusfiletransfer`:return{kind:`fileTransferStatus`,info:H(e)};default:return{kind:`unknown`}}}function I(e,t,n){let r=j(e.params.clid??``),i=A(e.params.ctid??``),a=M(e.params.client_type??``),o=e.params.client_servergroups??``,s={id:r,nickname:e.params.client_nickname??``,uid:e.params.client_unique_identifier??``,channelID:i,type:a,serverGroups:o?o.split(`,`):[]};return r!==0&&t.set(r,s),{kind:`clientEnter`,info:s}}function L(e,t,n){let r=j(e.params.clid??``),i=M(e.params.reasonid??``),a=r===t;return r!==0&&n.delete(r),{kind:`clientLeave`,event:{id:r,reasonID:i,reasonMsg:e.params.reasonmsg??``,targetID:j(e.params.targetid??``)},isSelf:a}}function R(e,t){let n=j(e.params.clid??``),r=A(e.params.ctid??``);if(n!==0){let e=t.get(n);e&&t.set(n,{...e,channelID:r})}return{kind:`clientMoved`,event:{id:n,targetChannelID:r,reasonID:M(e.params.reasonid??``),invokerID:j(e.params.invokerid??``),invokerName:e.params.invokername??``,invokerUID:e.params.invokeruid??``}}}function z(e,t){let n=j(e.params.invokerid??``),r=t.get(n);return{kind:`textMessage`,message:{targetMode:M(e.params.targetmode??``),targetID:A(e.params.target??``),invokerID:n,invokerName:e.params.invokername??``,invokerUID:e.params.invokeruid??r?.uid??``,message:a.i(e.params.msg??``),invokerGroups:r?.serverGroups??[]}}}function B(e){return{clientFileTransferID:j(e.params.clientftfid??``),serverFileTransferID:j(e.params.serverftfid??``),fileTransferKey:e.params.ftkey??``,port:j(e.params.port??``),seekPosition:A(e.params.seekpos??``)}}function V(e){return{clientFileTransferID:j(e.params.clientftfid??``),serverFileTransferID:j(e.params.serverftfid??``),fileTransferKey:e.params.ftkey??``,port:j(e.params.port??``),size:A(e.params.size??``)}}function H(e){return{clientFileTransferID:j(e.params.clientftfid??``),status:M(e.params.status??``),message:e.params.msg??``}}function U(e){return{kind:`poked`,event:{invokerID:j(e.params.invokerid??``),invokerName:a.i(e.params.invokername??``),invokerUID:e.params.invokeruid??``,message:a.i(e.params.msg??``)}}}var W=class e{static TOKEN_RATE=4;static TOKEN_MAX=8;#e=5;#t=Date.now();async wait(t){for(;;){if(t?.aborted)throw t.reason;let n=Date.now(),r=(n-this.#t)/1e3;if(this.#e=Math.min(this.#e+r*e.TOKEN_RATE,e.TOKEN_MAX),this.#t=n,this.#e>=1){--this.#e;return}let i=Math.ceil((1-this.#e)/e.TOKEN_RATE*1e3)+10;await new Promise((e,n)=>{let r=setTimeout(e,i);t&&t.addEventListener(`abort`,()=>{clearTimeout(r),n(t.reason)},{once:!0})})}}};function G(e){return{serverPassword:e.serverPassword??``,defaultChannel:e.defaultChannel??``,defaultChannelPassword:e.defaultChannelPassword??``}}var K=class{crypt;handler;logger;nickname;clid=0;#e;#t;#n;#r;#i=e.i.Disconnected;#a=new W;#o=new d;#s=new m;#c=new Map;#l=[];#u=null;#d=[];#f=[];#p=[];#m=[];#h=[];#g=[];#_=[];#v=[];#y=[];#b=[];#x=[];#S;#C;constructor(t,a,o,s={}){this.#e=t,this.#t=a,this.nickname=o,this.logger=s.logger??e.a,this.#n=s.resolver??new r.t(this.logger),this.#r=G(s),this.crypt=new n.t(t),this.handler=new i.t(this.crypt,this.logger),this.handler.onPacket=e=>this.#E(e),this.handler.onClosed=e=>this.#F(e),s.commandMiddleware&&this.#b.push(...s.commandMiddleware),s.eventMiddleware&&this.#x.push(...s.eventMiddleware),this.#S=this.#L(),this.#C=this.#R()}get status(){return this.#i}getClientInitOptions(){return this.#r}async connect(){if(this.#i!==e.i.Disconnected)throw new t.h;this.#w(),this.#i=e.i.Connecting;let n=await this.#T();this.logger.info(`connecting to server`,{address:n}),await this.handler.connect(n)}async disconnect(){if(this.#i===e.i.Disconnected)return;let t=this.#i===e.i.Connected;if(this.#i=e.i.Disconnected,this.logger.info(`disconnecting from server`),t)try{await this.execCommand(`clientdisconnect reasonmsg=Shutdown`,1e3)}catch{}this.handler.close();let n=this.#v.slice();for(let e of n)setImmediate(()=>e(void 0))}waitConnected(t){return this.#i===e.i.Connected?Promise.resolve():this.#u?Promise.reject(this.#u):new Promise((e,n)=>{let r={resolve:()=>{t?.removeEventListener(`abort`,i),e()},reject:e=>{t?.removeEventListener(`abort`,i),n(e)}},i=()=>{let e=this.#l.indexOf(r);e>=0&&this.#l.splice(e,1);let n=t?.reason;r.reject(n instanceof Error?n:Error(String(n??`Connection wait aborted`)))};this.#l.push(r),t?.aborted?i():t?.addEventListener(`abort`,i,{once:!0})})}async sendCommandNoWait(e){await this.#a.wait(),await this.#S(e)}async execCommand(e,t=1e4){await this.execCommandWithResponse(e,t)}async execCommandWithResponse(e,n=1e4){let[r,i]=this.#o.register(),a=p(e,r);try{await this.#a.wait(),await this.#S(a)}catch(e){throw this.#o.unregister(r),e}let o=await Promise.race([i,new Promise((r,i)=>setTimeout(()=>i(new t.g(e)),n))]);if(this.#o.unregister(r),o.err)throw o.err;return o.data}on(e,t){switch(e){case`textMessage`:this.#d.push(t);break;case`clientEnter`:this.#f.push(t);break;case`clientLeave`:this.#p.push(t);break;case`clientMoved`:this.#m.push(t);break;case`poked`:this.#h.push(t);break;case`voiceData`:this.#g.push(t);break;case`connected`:this.#_.push(t);break;case`disconnected`:this.#v.push(t);break;case`kicked`:this.#y.push(t)}return this}useCommandMiddleware(...e){return this.#b.push(...e),this.#S=this.#L(),this}useEventMiddleware(...e){return this.#x.push(...e),this.#C=this.#R(),this}clientID(){return this.clid}channelID(){return this.#c.get(this.clid)?.channelID??0n}sendWhisper(e,t,n){this.handler.sendWhisperPacket(e,t,n)}sendVoice(e,t){this.handler.sendVoicePacket(e,t)}async fileTransferInitUpload(e,n,r,i,a=!1){let[o,s]=this.#s.register(),c=v(e,n,r,i,o,a);try{await this.execCommand(c,1e4)}catch(e){throw this.#s.unregister(o),e}let l=await Promise.race([s,new Promise((e,n)=>setTimeout(()=>n(new t.x),1e4))]);if(this.#s.unregister(o),`size`in l)throw new t.b(`unexpected download response`);if(`status`in l){let e=l;throw new t.b(`${e.message} (status=${e.status})`)}return l}async fileTransferInitDownload(e,n,r){let[i,a]=this.#s.register(),o=y(e,n,r,i);try{await this.execCommand(o,1e4)}catch(e){throw this.#s.unregister(i),e}let s=await Promise.race([a,new Promise((e,n)=>setTimeout(()=>n(new t.x),1e4))]);if(this.#s.unregister(i),`seekPosition`in s)throw new t.b(`unexpected upload response`);if(`status`in s){let e=s;throw new t.b(`${e.message} (status=${e.status})`)}return s}uploadFileData(e,t,n){return g(e,t,n)}downloadFileData(e,t,n){return _(e,t,n)}_markConnected(){this.#i=e.i.Connected,this.#u=null;for(let e of this.#l)e.resolve();this.#l=[];let t=this.#_.slice();for(let e of t)setImmediate(()=>e())}#w(){this.#u=null,this.handler.close(),this.crypt=new n.t(this.#e),this.handler=new i.t(this.crypt,this.logger),this.handler.onPacket=e=>this.#E(e),this.handler.onClosed=e=>this.#F(e),this.#o.reset(),this.#s.reset(),this.#c.clear(),this.clid=0,this.#S=this.#L()}async#T(){let e=this.#t.includes(`:`)?this.#t:`${this.#t}:9987`;try{return(await this.#n.resolve(this.#t))[0]?.addr??e}catch{return e}}#E(e){this.#D(e)}#D(e){let t=e.typeFlagged&15;if(t===8){let t=o.n(this.crypt,e.data);t&&this.handler.sendPacket(i.a.Init1,t,0);return}if((t===0||t===1)&&e.data.length>5){this.#O(e.data);return}(t===2||t===3)&&e.data.length>0&&this.#k(Buffer.from(e.data).toString(`utf8`))}#O(e){if(this.#g.length===0)return;let t=new DataView(e.buffer,e.byteOffset,e.byteLength).getUint16(2,!1);if(t===this.clid)return;let n={clientId:t,codec:e[4],data:e.subarray(5)};for(let e of this.#g)setImmediate(()=>e(n))}#k(e){if(!e)return;let t=e.split(`\0`).join(`
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./address-BR-5unVo.cjs"),t=require("./primitives-DkwW7wcP.cjs"),n=require("./crypto-BfDd9DP6.cjs"),r=require("./resolver-DCcmyWSK.cjs"),i=require("./handler-aywHvv7I.cjs"),a=require("./command-DAK4pUBP.cjs"),o=require("./crypt-handshake-CQkQreLx.cjs"),s=require("./crypt-init2-Bkee1YxV.cjs"),c=require("./parser-BfwYH2fT.cjs");let l=require("node:crypto"),u=require("node:net");var d=class{#e=new Map;#t=0;#n=[];#r=!1;register(){this.#t++;let e=this.#t;return[e,new Promise(t=>{this.#e.set(e,t)})]}unregister(e){this.#e.delete(e)}signalWelcomeComplete(){this.#r=!0,this.#n=[]}buffer(e){this.#r&&this.#e.size!==0&&this.#n.push(e)}resolve(e,t){let n=this.#e.get(e);if(!n){this.#n=[];return}let r=this.#n;this.#n=[],this.#e.delete(e),n({err:t,data:r})}discardBuffer(){this.#n=[]}reset(){this.#e.clear(),this.#n=[],this.#r=!1,this.#t=0}};function f(e){let n=e.id??`0`,r=e.msg??``,i=e.return_code,a=null;n!==`0`&&(a=new t.w(n,r));let o=null;if(i!==void 0&&i!==``){let e=parseInt(i,10);isNaN(e)||(o=e)}return{err:a,rc:o}}function p(e,t){return e.includes(`return_code=`)?e:`${e} return_code=${t}`}function m(e,t){let n=t.alpha??``,r=t.beta??``,i=t.omega??``;e.crypt.initCrypto(n,r,i),e.logger.info(`crypto initialized (P-256 path), sending clientinit`),b(e)}function h(e,t){e.logger.info(`received initivexpand2`),e.handler.receivedFinalInitAck();let n=t.l??``,r=t.omega??``,i=t.proof??``,a=t.beta??``,o=_(e,a);s.t(e.crypt,n,r,i,a,o),b(e)}function g(e,n){let r=n.aclid??n.clid??``,i=r?parseInt(r,10):0;i>0&&(e.clid=i,e.handler.setClientID(i));let o=n.virtualserver_version;o&&(e.uidAlgorithm=t.h(o)),e.logger.info(`connected to server`,{selfId:e.clid}),e._markConnected(),setImmediate(()=>{let t=a.t(`clientupdate`,{client_input_muted:`0`,client_output_muted:`0`});e.sendCommandNoWait(t).catch(()=>{})})}function _(e,n){let[r,o]=t.r(),s=Buffer.from(r).toString(`base64`),c=v(e,r,n),l=a.n(`clientek`,[[`ek`,s],[`proof`,c]]);return e.handler.sendPacket(i.a.Command,Buffer.from(l),0),o}function v(e,n,r){let i=Buffer.from(r,`base64`),a=new Uint8Array(86);a.set(n.slice(0,32)),a.set(i.slice(0,Math.min(54,i.length)),32);let o=t.o(e.crypt.identity.privateKey,a);return Buffer.from(o).toString(`base64`)}function y(e){return e===``?``:(0,l.createHash)(`sha1`).update(e).digest().toString(`base64`)}function b(e){let t=x(e);e.handler.sendPacket(i.a.Command,Buffer.from(t),0)}function x(e){let t=e.crypt.identity.publicKeyBase64(),n=e.getClientInitOptions(),r=y(n.defaultChannelPassword),i=y(n.serverPassword),o=(0,l.createHash)(`sha1`).update(t).digest().toString(`base64`);return a.n(`clientinit`,[[`client_nickname`,e.nickname],[`client_version`,`3.?.? [Build: 5680278000]`],[`client_platform`,`Windows`],[`client_input_hardware`,`1`],[`client_output_hardware`,`1`],[`client_default_channel`,n.defaultChannel],[`client_default_channel_password`,r],[`client_server_password`,i],[`client_meta_data`,``],[`client_version_sign`,`DX5NIYLvfJEUjuIbCidnoeozxIDRRkpq3I9vVMBmE9L2qnekOoBzSenkzsg2lC9CMv8K5hkEzhr2TYUYSwUXCg==`],[`client_key_offset`,String(e.crypt.identity.offset)],[`client_nickname_phonetic`,``],[`client_default_token`,``],[`hwid`,o]])}var S=class{#e=new Map;#t=0;register(){this.#t++,this.#t>65535&&(this.#t=1);let e=this.#t;return[e,new Promise(t=>{this.#e.set(e,t)})]}unregister(e){this.#e.delete(e)}notify(e,t){let n=this.#e.get(e);n&&n(t)}reset(){this.#e.clear(),this.#t=0}};function C(e,n,r){return new Promise((i,a)=>{let o=(0,u.createConnection)({host:e,port:n},()=>{o.write(r,e=>{e?(o.destroy(),a(new t.x(`failed to send transfer key: ${e.message}`))):i(o)})});o.setTimeout(1e4),o.once(`error`,a),o.once(`timeout`,()=>{o.destroy(),a(new t.x(`connection timeout`))})})}async function w(e,t,n){let r=await C(e,t.port,t.fileTransferKey);await new Promise((e,t)=>{n.pipe(r),r.on(`finish`,e),r.on(`error`,t)})}async function T(e,t,n){let r=await C(e,t.port,t.fileTransferKey);await new Promise((e,t)=>{r.pipe(n),n.on(`finish`,e),r.on(`error`,t),n.on(`error`,t)})}function E(e,t,n,r,i,o){let s=t.startsWith(`/`)?t:`/${t}`;return a.t(`ftinitupload`,{cid:String(e),name:s,cpw:y(n),size:String(r),clientftfid:String(i),overwrite:o?`1`:`0`,resume:`0`})}function D(e,t,n,r){let i=t.startsWith(`/`)?t:`/${t}`;return a.t(`ftinitdownload`,{cid:String(e),name:i,cpw:y(n),clientftfid:String(r),seekpos:`0`})}function O(e,t){let n=t;for(let t=e.length-1;t>=0;t--)n=e[t](n);return n}function k(e,t){let n=t;for(let t=e.length-1;t>=0;t--)n=e[t](n);return n}function A(e){if(e===``||e===void 0)return 0n;try{return BigInt(e)}catch{return 0n}}function j(e){let t=parseInt(e,10);return isNaN(t)||t<0||t>65535?0:t}function M(e){let t=parseInt(e,10);return isNaN(t)?0:t}function N(e,t){if(t===e)return!0;if(!t.startsWith(e))return!1;let n=t.slice(e.length);return/^\d+$/.test(n)}function P(e){let t=e.indexOf(` `);if(t<0)return[e];let n=e.slice(0,t),r=e.slice(t+1);if(!r.includes(`|`))return[e];let i=r.split(`|`),a=[],o=new Map;for(let e of i){if(e===``)continue;let t=e.split(` `).filter(Boolean),r=new Set;for(let e of t)r.add(F(e));let i=[];for(let[e,t]of o)r.has(e)||i.push(t);let s=[...i,...t];a.push(`${n} ${s.join(` `)}`),o=new Map;for(let e of s)o.set(F(e),e)}return a.length===0?[e]:a}function F(e){let t=e.indexOf(`=`);return t>0?e.slice(0,t):e}function ee(e,t,n,r){switch(e.name){case`notifycliententerview`:return I(e,n,r);case`notifyclientleftview`:return L(e,t,n);case`notifyclientmoved`:return R(e,n);case`notifytextmessage`:return z(e,n);case`notifyclientpoke`:return U(e);case`notifystartupload`:return{kind:`startUpload`,info:B(e)};case`notifystartdownload`:return{kind:`startDownload`,info:V(e)};case`notifystatusfiletransfer`:return{kind:`fileTransferStatus`,info:H(e)};default:return{kind:`unknown`}}}function I(e,t,n){let r=j(e.params.clid??``),i=A(e.params.ctid??``),a=M(e.params.client_type??``),o=e.params.client_servergroups??``,s={id:r,nickname:e.params.client_nickname??``,uid:e.params.client_unique_identifier??``,channelID:i,type:a,serverGroups:o?o.split(`,`):[]};return r!==0&&t.set(r,s),{kind:`clientEnter`,info:s}}function L(e,t,n){let r=j(e.params.clid??``),i=M(e.params.reasonid??``),a=r===t;return r!==0&&n.delete(r),{kind:`clientLeave`,event:{id:r,reasonID:i,reasonMsg:e.params.reasonmsg??``,targetID:j(e.params.targetid??``)},isSelf:a}}function R(e,t){let n=j(e.params.clid??``),r=A(e.params.ctid??``);if(n!==0){let e=t.get(n);e&&t.set(n,{...e,channelID:r})}return{kind:`clientMoved`,event:{id:n,targetChannelID:r,reasonID:M(e.params.reasonid??``),invokerID:j(e.params.invokerid??``),invokerName:e.params.invokername??``,invokerUID:e.params.invokeruid??``}}}function z(e,t){let n=j(e.params.invokerid??``),r=t.get(n);return{kind:`textMessage`,message:{targetMode:M(e.params.targetmode??``),targetID:A(e.params.target??``),invokerID:n,invokerName:e.params.invokername??``,invokerUID:e.params.invokeruid??r?.uid??``,message:a.i(e.params.msg??``),invokerGroups:r?.serverGroups??[]}}}function B(e){return{clientFileTransferID:j(e.params.clientftfid??``),serverFileTransferID:j(e.params.serverftfid??``),fileTransferKey:e.params.ftkey??``,port:j(e.params.port??``),seekPosition:A(e.params.seekpos??``)}}function V(e){return{clientFileTransferID:j(e.params.clientftfid??``),serverFileTransferID:j(e.params.serverftfid??``),fileTransferKey:e.params.ftkey??``,port:j(e.params.port??``),size:A(e.params.size??``)}}function H(e){return{clientFileTransferID:j(e.params.clientftfid??``),status:M(e.params.status??``),message:e.params.msg??``}}function U(e){return{kind:`poked`,event:{invokerID:j(e.params.invokerid??``),invokerName:a.i(e.params.invokername??``),invokerUID:e.params.invokeruid??``,message:a.i(e.params.msg??``)}}}var W=class e{static TOKEN_RATE=4;static TOKEN_MAX=8;#e=5;#t=Date.now();async wait(t){for(;;){if(t?.aborted)throw t.reason;let n=Date.now(),r=(n-this.#t)/1e3;if(this.#e=Math.min(this.#e+r*e.TOKEN_RATE,e.TOKEN_MAX),this.#t=n,this.#e>=1){--this.#e;return}let i=Math.ceil((1-this.#e)/e.TOKEN_RATE*1e3)+10;await new Promise((e,n)=>{let r=setTimeout(e,i);t&&t.addEventListener(`abort`,()=>{clearTimeout(r),n(t.reason)},{once:!0})})}}};function G(e){return{serverPassword:e.serverPassword??``,defaultChannel:e.defaultChannel??``,defaultChannelPassword:e.defaultChannelPassword??``}}var K=class{crypt;handler;logger;nickname;clid=0;uidAlgorithm=`sha1`;#e;#t;#n;#r;#i;#a=e.i.Disconnected;#o=new W;#s=new d;#c=new S;#l=new Map;#u=[];#d=null;#f=[];#p=[];#m=[];#h=[];#g=[];#_=[];#v=[];#y=[];#b=[];#x=[];#S=[];#C;#w;constructor(t,a,o,s={}){this.#e=t,this.#t=a,this.nickname=o,this.logger=s.logger??e.a,this.#n=s.resolver??new r.t(this.logger),this.#r=G(s),this.#i=s.socketFactory,this.crypt=new n.t(t),this.handler=new i.t(this.crypt,this.logger,this.#i),this.handler.onPacket=e=>this.#D(e),this.handler.onClosed=e=>this.#I(e),s.commandMiddleware&&this.#x.push(...s.commandMiddleware),s.eventMiddleware&&this.#S.push(...s.eventMiddleware),this.#C=this.#R(),this.#w=this.#z()}get status(){return this.#a}getClientInitOptions(){return this.#r}async connect(){if(this.#a!==e.i.Disconnected)throw new t.g;this.#T(),this.#a=e.i.Connecting;let n=await this.#E();this.logger.info(`connecting to server`,{address:n}),await this.handler.connect(n)}async disconnect(){if(this.#a===e.i.Disconnected)return;let t=this.#a===e.i.Connected;if(this.#a=e.i.Disconnected,this.logger.info(`disconnecting from server`),t)try{await this.execCommand(`clientdisconnect reasonmsg=Shutdown`,1e3)}catch{}this.handler.close();let n=this.#y.slice();for(let e of n)setImmediate(()=>e(void 0))}waitConnected(t){return this.#a===e.i.Connected?Promise.resolve():this.#d?Promise.reject(this.#d):new Promise((e,n)=>{let r={resolve:()=>{t?.removeEventListener(`abort`,i),e()},reject:e=>{t?.removeEventListener(`abort`,i),n(e)}},i=()=>{let e=this.#u.indexOf(r);e>=0&&this.#u.splice(e,1);let n=t?.reason;r.reject(n instanceof Error?n:Error(String(n??`Connection wait aborted`)))};this.#u.push(r),t?.aborted?i():t?.addEventListener(`abort`,i,{once:!0})})}async sendCommandNoWait(e){await this.#o.wait(),await this.#C(e)}async execCommand(e,t=1e4){await this.execCommandWithResponse(e,t)}async execCommandWithResponse(e,n=1e4){let[r,i]=this.#s.register(),a=p(e,r);try{await this.#o.wait(),await this.#C(a)}catch(e){throw this.#s.unregister(r),e}let o=await Promise.race([i,new Promise((r,i)=>setTimeout(()=>i(new t._(e)),n))]);if(this.#s.unregister(r),o.err)throw o.err;return o.data}on(e,t){switch(e){case`textMessage`:this.#f.push(t);break;case`clientEnter`:this.#p.push(t);break;case`clientLeave`:this.#m.push(t);break;case`clientMoved`:this.#h.push(t);break;case`poked`:this.#g.push(t);break;case`voiceData`:this.#_.push(t);break;case`connected`:this.#v.push(t);break;case`disconnected`:this.#y.push(t);break;case`kicked`:this.#b.push(t)}return this}useCommandMiddleware(...e){return this.#x.push(...e),this.#C=this.#R(),this}useEventMiddleware(...e){return this.#S.push(...e),this.#w=this.#z(),this}clientID(){return this.clid}uniqueIdentifier(){return t.d(this.#e.publicKeyBase64(),this.uidAlgorithm)}channelID(){return this.#l.get(this.clid)?.channelID??0n}sendWhisper(e,t,n){this.handler.sendWhisperPacket(e,t,n)}sendVoice(e,t){this.handler.sendVoicePacket(e,t)}async fileTransferInitUpload(e,n,r,i,a=!1){let[o,s]=this.#c.register(),c=E(e,n,r,i,o,a);try{await this.execCommand(c,1e4)}catch(e){throw this.#c.unregister(o),e}let l=await Promise.race([s,new Promise((e,n)=>setTimeout(()=>n(new t.S),1e4))]);if(this.#c.unregister(o),`size`in l)throw new t.x(`unexpected download response`);if(`status`in l){let e=l;throw new t.x(`${e.message} (status=${e.status})`)}return l}async fileTransferInitDownload(e,n,r){let[i,a]=this.#c.register(),o=D(e,n,r,i);try{await this.execCommand(o,1e4)}catch(e){throw this.#c.unregister(i),e}let s=await Promise.race([a,new Promise((e,n)=>setTimeout(()=>n(new t.S),1e4))]);if(this.#c.unregister(i),`seekPosition`in s)throw new t.x(`unexpected upload response`);if(`status`in s){let e=s;throw new t.x(`${e.message} (status=${e.status})`)}return s}uploadFileData(e,t,n){return w(e,t,n)}downloadFileData(e,t,n){return T(e,t,n)}_markConnected(){this.#a=e.i.Connected,this.#d=null;for(let e of this.#u)e.resolve();this.#u=[];let t=this.#v.slice();for(let e of t)setImmediate(()=>e())}#T(){this.#d=null,this.handler.close(),this.crypt=new n.t(this.#e),this.handler=new i.t(this.crypt,this.logger,this.#i),this.handler.onPacket=e=>this.#D(e),this.handler.onClosed=e=>this.#I(e),this.#s.reset(),this.#c.reset(),this.#l.clear(),this.clid=0,this.#C=this.#R()}async#E(){let e=this.#t.includes(`:`)?this.#t:`${this.#t}:9987`;try{return(await this.#n.resolve(this.#t))[0]?.addr??e}catch{return e}}#D(e){this.#O(e)}#O(e){let t=e.typeFlagged&15;if(t===8){let t=o.n(this.crypt,e.data);t&&this.handler.sendPacket(i.a.Init1,t,0);return}if((t===0||t===1)&&e.data.length>5){this.#k(e.data);return}if((t===2||t===3)&&e.data.length>0){let t=Buffer.from(e.data).toString(`utf8`);process.env.TEAMSPEAK_TRACE_RAW&&process.stderr.write(`S2C ${JSON.stringify(t)}\n`),this.#A(t)}}#k(e){if(this.#_.length===0)return;let t=new DataView(e.buffer,e.byteOffset,e.byteLength).getUint16(2,!1);if(t===this.clid)return;let n={clientId:t,codec:e[4],data:e.subarray(5)};for(let e of this.#_)setImmediate(()=>e(n))}#A(e){if(!e)return;let t=e.split(`\0`).join(`
|
|
2
2
|
`).split(`
|
|
3
|
-
`);for(let e of t){let t=e.replace(/\r$/,``);if(t)for(let e of P(t))this.#
|
|
3
|
+
`);for(let e of t){let t=e.replace(/\r$/,``);if(t)for(let e of P(t))this.#j(e)}}#j(e){let t=c.t(e);if(t){if(t.name===``){Object.keys(t.params).length>0&&this.#s.buffer(t.params);return}if(t.name===`channellistfinished`){this.#s.signalWelcomeComplete();return}if(t.name.startsWith(`notify`)){let e=ee(t,this.clid,this.#l,this.nickname);this.#N(e,t.params);return}switch(t.name){case`clientinitiv`:m(this,t.params);break;case`initivexpand2`:h(this,t.params);break;case`initserver`:g(this,t.params);break;case`error`:this.#M(t.params);break;default:this.#s.buffer(t.params)}}}#M(t){let{err:n,rc:r}=f(t);if(r===null?this.#s.discardBuffer():this.#s.resolve(r,n),n&&this.#a!==e.i.Connected){this.#L(n);return}(t.id??`0`)===`3329`&&setImmediate(()=>this.disconnect().catch(()=>{}))}#N(e,t){switch(e.kind){case`clientEnter`:{let t=e.info;t.id!==0&&t.id===this.clid?this.nickname=t.nickname:t.id!==0&&this.clid===0&&N(this.nickname,t.nickname)&&(this.clid=t.id,this.handler.setClientID(t.id),this.nickname=t.nickname),this.#P(`clientEnter`,t);break}case`clientLeave`:if(this.#P(`clientLeave`,e.event),e.isSelf&&(e.event.reasonID===4||e.event.reasonID===5)){let t=e.event.reasonMsg;for(let e of this.#b)setImmediate(()=>e(t))}break;case`clientMoved`:this.#P(`clientMoved`,e.event);break;case`textMessage`:this.#P(`textMessage`,e.message);break;case`poked`:this.#P(`poked`,e.event);break;case`startUpload`:this.#c.notify(e.info.clientFileTransferID,e.info);break;case`startDownload`:this.#c.notify(e.info.clientFileTransferID,e.info);break;case`fileTransferStatus`:this.#c.notify(e.info.clientFileTransferID,e.info)}}#P(e,t){this.#w(t)}#F(e,t){switch(e){case`textMessage`:for(let e of this.#f)setImmediate(()=>e(t));break;case`clientEnter`:for(let e of this.#p)setImmediate(()=>e(t));break;case`clientLeave`:for(let e of this.#m)setImmediate(()=>e(t));break;case`clientMoved`:for(let e of this.#h)setImmediate(()=>e(t));break;case`poked`:for(let e of this.#g)setImmediate(()=>e(t))}}#I(t){if(this.#a===e.i.Disconnected)return;if(this.#a!==e.i.Connected){this.#L(t??Error(`Connection closed before the TeamSpeak handshake completed`));return}this.#a=e.i.Disconnected;let n=this.#y.slice();for(let e of n)setImmediate(()=>e(t??void 0))}#L(t){this.#d=t;let n=this.#u.splice(0);for(let e of n)e.reject(t);if(this.#a===e.i.Disconnected)return;this.#a=e.i.Disconnected,this.handler.close();let r=this.#y.slice();for(let e of r)setImmediate(()=>e(t))}#R(){return O(this.#x,async e=>{this.handler.sendPacket(i.a.Command,Buffer.from(e),0)})}#z(){return k(this.#S,e=>{typeof e==`object`&&e&&`invokerName`in e&&`message`in e&&`targetMode`in e?this.#F(`textMessage`,e):typeof e==`object`&&e&&`invokerName`in e&&`message`in e&&!(`targetMode`in e)?this.#F(`poked`,e):typeof e==`object`&&e&&`id`in e&&`uid`in e?this.#F(`clientEnter`,e):typeof e==`object`&&e&&`id`in e&&`reasonID`in e&&`targetChannelID`in e?this.#F(`clientMoved`,e):typeof e==`object`&&e&&`id`in e&&`reasonID`in e&&this.#F(`clientLeave`,e)})}};async function q(e,t,n,r){let i=a.n(`sendtextmessage`,[[`targetmode`,String(t)],[`target`,String(n)],[`msg`,r]]);await e.sendCommandNoWait(i)}async function J(e,t,n,r=``){let i=[[`clid`,String(t)],[`cid`,String(n)]];r&&i.push([`cpw`,y(r)]);let o=a.n(`clientmove`,i);await e.execCommand(o,1e4)}async function Y(e,t,n){let r=a.n(`clientpoke`,[[`clid`,String(t)],[`msg`,n]]);await e.execCommand(r,1e4)}async function X(e,t){let n=(await e.execCommandWithResponse(`clientinfo clid=${t}`,5e3))[0];if(!n)throw Error(`no data returned for client ${t}`);return n}async function Z(e){return(await e.execCommandWithResponse(`channellist`,5e3)).map(e=>({id:BigInt(e.cid??`0`),parentID:BigInt(e.pid??e.cpid??`0`),order:BigInt(e.channel_order??`0`),name:a.i(e.channel_name??``),description:``}))}async function Q(e){return(await e.execCommandWithResponse(`clientlist -uid -away -voice -groups`,5e3)).map(e=>{let t=e.client_servergroups??``;return{id:parseInt(e.clid??`0`,10),nickname:a.i(e.client_nickname??``),uid:e.client_unique_identifier??``,channelID:BigInt(e.cid??`0`),type:parseInt(e.client_type??`0`,10),serverGroups:t?t.split(`,`):[]}})}async function $(e,t,n){if(n.length===0)return;let r=n.join(`|`),i=a.t(`ftdeletefile`,{cid:String(t),cpw:``,name:r});await e.execCommand(i,1e4)}exports.AlreadyConnectedError=t.g,exports.Client=K,exports.ClientStatus=e.i,exports.CommandTimeoutError=t._,exports.CryptoInitError=t.v,exports.EAXTagMismatchError=t.y,exports.FakeSignatureMismatchError=t.b,exports.FileTransferError=t.x,exports.FileTransferTimeoutError=t.S,exports.Identity=t.l,exports.InvalidIdentityError=t.C,exports.ServerError=t.w,exports.TeamspeakError=t.T,exports.clientMove=J,exports.consoleLogger=e.a,exports.dialFileTransfer=C,exports.downloadFileData=T,exports.fileTransferDeleteFile=$,exports.generateIdentity=t.u,exports.getClientInfo=X,exports.getUidFromPublicKey=t.d,exports.identityFromString=t.p,exports.listChannels=Z,exports.listClients=Q,exports.noopLogger=e.o,exports.poke=Y,exports.sendTextMessage=q,exports.uploadFileData=w;
|
|
4
4
|
//# sourceMappingURL=index.cjs.map
|