@honeybbq/teamspeak-client 0.1.1 → 0.2.1

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
@@ -46,7 +46,11 @@ import { Client, generateIdentity } from "@honeybbq/teamspeak-client";
46
46
  const identity = generateIdentity(8);
47
47
 
48
48
  // Create the client
49
- const client = new Client(identity, "localhost", "TSBot");
49
+ const client = new Client(identity, "localhost", "TSBot", {
50
+ serverPassword: process.env.TEAMSPEAK_SERVER_PASSWORD,
51
+ defaultChannel: "Lobby",
52
+ defaultChannelPassword: process.env.TEAMSPEAK_DEFAULT_CHANNEL_PASSWORD,
53
+ });
50
54
 
51
55
  // Register event handlers
52
56
  client.on("connected", () => {
@@ -148,9 +152,18 @@ const client = new Client(identity, "ts.example.com", "Bot", {
148
152
  resolver: customResolver,
149
153
  commandMiddleware: [loggingMiddleware],
150
154
  eventMiddleware: [filterMiddleware],
155
+ serverPassword: process.env.TEAMSPEAK_SERVER_PASSWORD,
156
+ defaultChannel: "Lobby",
157
+ defaultChannelPassword: process.env.TEAMSPEAK_DEFAULT_CHANNEL_PASSWORD,
151
158
  });
152
159
  ```
153
160
 
161
+ Connection auth options:
162
+
163
+ - `serverPassword`: plain-text server password; sent as the TeamSpeak protocol hash during `clientinit`
164
+ - `defaultChannel`: default channel name requested during `clientinit`
165
+ - `defaultChannelPassword`: plain-text password for `defaultChannel`; sent as the TeamSpeak protocol hash
166
+
154
167
  ## Subpath Exports
155
168
 
156
169
  The package provides granular subpath exports for advanced use cases:
package/dist/client.d.ts CHANGED
@@ -17,6 +17,12 @@ export declare class Client {
17
17
  /** @internal */ clid: number;
18
18
  constructor(identity: Identity, addr: string, nickname: string, options?: ClientOptions);
19
19
  get status(): ClientStatus;
20
+ /** @internal */
21
+ getClientInitOptions(): Readonly<{
22
+ serverPassword: string;
23
+ defaultChannel: string;
24
+ defaultChannelPassword: string;
25
+ }>;
20
26
  connect(): Promise<void>;
21
27
  disconnect(): Promise<void>;
22
28
  waitConnected(signal?: AbortSignal): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,MAAM,EAGX,YAAY,EAEb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAmBvD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAKD,qBAAa,MAAM;;IAEjB,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC;IAC9B,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC;IACxC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC;IAClC,gBAAgB,CAAC,IAAI,SAAK;gBA6Bd,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB;IAuB3F,IAAI,MAAM,IAAI,YAAY,CAEzB;IAIK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAaxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBjC,aAAa,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAY5C,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D,uBAAuB,CAC3B,GAAG,EAAE,MAAM,EACX,SAAS,SAAS,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IA2BpC,EAAE,CAAC,CAAC,SAAS,MAAM,QAAQ,EACzB,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,GAC9E,IAAI;IAiCP,oBAAoB,CAAC,GAAG,EAAE,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAMtD,kBAAkB,CAAC,GAAG,EAAE,EAAE,eAAe,EAAE,GAAG,IAAI;IAQlD,QAAQ,IAAI,MAAM;IAIlB,SAAS,IAAI,MAAM;IAKnB,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAM1C,sBAAsB,CAC1B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,SAAS,UAAQ,GAChB,OAAO,CAAC,cAAc,CAAC;IA2BpB,wBAAwB,CAC5B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC;IA2B5B,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjF,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrF,gBAAgB;IAChB,cAAc,IAAI,IAAI;CA0RvB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../src/handshake.ts"],"names":[],"mappings":"AAKA,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,CAoBrF;AAwBD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CA0BnD"}
1
+ {"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../src/handshake.ts"],"names":[],"mappings":"AAKA,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,CAoBrF;AA8BD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGnD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=handshake.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handshake.test.d.ts","sourceRoot":"","sources":["../src/handshake.test.ts"],"names":[],"mappings":""}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./types-DrnoCdSW.cjs`),t=require(`./primitives-bj-ml31v.cjs`),n=require(`./crypto-2veVY1fC.cjs`),r=require(`./resolver-Dey6omBe.cjs`),i=require(`./handler-CqCD93f0.cjs`),a=require(`./command-Cu2v-5-K.cjs`),o=require(`./crypt-handshake-Dbj2cSBZ.cjs`),s=require(`./crypt-init2-C2oihZ7e.cjs`),c=require(`./parser-DhAWj-TI.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`),D(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),D(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){let t=e.crypt.identity.publicKeyBase64(),n=(0,l.createHash)(`sha1`).update(t).digest().toString(`base64`),r=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`,``],[`client_default_channel_password`,``],[`client_server_password`,``],[`client_meta_data`,``],[`client_version_sign`,`DX5NIYLvfJEUjuIbCidnoeozxIDRRkpq3I9vVMBmE9L2qnekOoBzSenkzsg2lC9CMv8K5hkEzhr2TYUYSwUXCg==`],[`client_key_offset`,String(e.crypt.identity.offset)],[`client_nickname_phonetic`,``],[`client_default_token`,``],[`hwid`,n]]);e.handler.sendPacket(i.a.Command,Buffer.from(r),0)}function O(e){if(e===``||e===void 0)return 0n;try{return BigInt(e)}catch{return 0n}}function k(e){let t=parseInt(e,10);return isNaN(t)||t<0||t>65535?0:t}function A(e){let t=parseInt(e,10);return isNaN(t)?0:t}function j(e,t){if(t===e)return!0;if(!t.startsWith(e))return!1;let n=t.slice(e.length);return/^\d+$/.test(n)}function M(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=[];for(let e of i)e!==``&&a.push(`${n} ${e}`);return a.length===0?[e]:a}function N(e,t,n,r){switch(e.name){case`notifycliententerview`:return P(e,n,r);case`notifyclientleftview`:return F(e,t,n);case`notifyclientmoved`:return I(e,n);case`notifytextmessage`:return L(e,n);case`notifyclientpoke`:return V(e);case`notifystartupload`:return{kind:`startUpload`,info:R(e)};case`notifystartdownload`:return{kind:`startDownload`,info:z(e)};case`notifystatusfiletransfer`:return{kind:`fileTransferStatus`,info:B(e)};default:return{kind:`unknown`}}}function P(e,t,n){let r=k(e.params.clid??``),i=O(e.params.cid??``),a=A(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 F(e,t,n){let r=k(e.params.clid??``),i=A(e.params.reasonid??``),a=r===t;return r!==0&&n.delete(r),{kind:`clientLeave`,event:{id:r,reasonID:i,reasonMsg:e.params.reasonmsg??``,targetID:k(e.params.targetid??``)},isSelf:a}}function I(e,t){let n=k(e.params.clid??``),r=O(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:A(e.params.reasonid??``),invokerID:k(e.params.invokerid??``),invokerName:e.params.invokername??``,invokerUID:e.params.invokeruid??``}}}function L(e,t){let n=k(e.params.invokerid??``),r=t.get(n);return{kind:`textMessage`,message:{targetMode:A(e.params.targetmode??``),targetID:O(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 R(e){return{clientFileTransferID:k(e.params.clientftfid??``),serverFileTransferID:k(e.params.serverftfid??``),fileTransferKey:e.params.ftkey??``,port:k(e.params.port??``),seekPosition:O(e.params.seekpos??``)}}function z(e){return{clientFileTransferID:k(e.params.clientftfid??``),serverFileTransferID:k(e.params.serverftfid??``),fileTransferKey:e.params.ftkey??``,port:k(e.params.port??``),size:O(e.params.size??``)}}function B(e){return{clientFileTransferID:k(e.params.clientftfid??``),status:A(e.params.status??``),message:e.params.msg??``}}function V(e){return{kind:`poked`,event:{invokerID:k(e.params.invokerid??``),invokerName:a.i(e.params.invokername??``),invokerUID:e.params.invokeruid??``,message:a.i(e.params.msg??``)}}}var H=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})})}}},U=class{crypt;handler;logger;nickname;clid=0;#e;#t;#n;#r=e.t.Disconnected;#i=new H;#a=new d;#o=new m;#s=new Map;#c=[];#l=[];#u=[];#d=[];#f=[];#p=[];#m=[];#h=[];#g=[];#_=[];#v=[];#y=[];#b;#x;constructor(t,a,o,s={}){this.#e=t,this.#t=a,this.nickname=o,this.logger=s.logger??e.n,this.#n=s.resolver??new r.t(this.logger),this.crypt=new n.t(t),this.handler=new i.t(this.crypt,this.logger),this.handler.onPacket=e=>this.#w(e),this.handler.onClosed=e=>this.#N(e),s.commandMiddleware&&this.#v.push(...s.commandMiddleware),s.eventMiddleware&&this.#y.push(...s.eventMiddleware),this.#b=this.#P(),this.#x=this.#F()}get status(){return this.#r}async connect(){if(this.#r!==e.t.Disconnected)throw new t.h;this.#S(),this.#r=e.t.Connecting;let n=await this.#C();this.logger.info(`connecting to server`,{address:n}),await this.handler.connect(n)}async disconnect(){if(this.#r===e.t.Disconnected)return;let t=this.#r===e.t.Connected;if(this.#r=e.t.Disconnected,this.logger.info(`disconnecting from server`),t)try{await this.execCommand(`clientdisconnect reasonmsg=Shutdown`,1e3)}catch{}this.handler.close();let n=this.#g.slice();for(let e of n)setImmediate(()=>e(void 0))}waitConnected(t){return this.#r===e.t.Connected?Promise.resolve():new Promise((e,n)=>{this.#c.push(e),t&&t.addEventListener(`abort`,()=>n(t.reason),{once:!0})})}async sendCommandNoWait(e){await this.#i.wait(),await this.#b(e)}async execCommand(e,t=1e4){await this.execCommandWithResponse(e,t)}async execCommandWithResponse(e,n=1e4){let[r,i]=this.#a.register(),a=p(e,r);try{await this.#i.wait(),await this.#b(a)}catch(e){throw this.#a.unregister(r),e}let o=await Promise.race([i,new Promise((r,i)=>setTimeout(()=>i(new t.g(e)),n))]);if(this.#a.unregister(r),o.err)throw o.err;return o.data}on(e,t){switch(e){case`textMessage`:this.#l.push(t);break;case`clientEnter`:this.#u.push(t);break;case`clientLeave`:this.#d.push(t);break;case`clientMoved`:this.#f.push(t);break;case`poked`:this.#p.push(t);break;case`voiceData`:this.#m.push(t);break;case`connected`:this.#h.push(t);break;case`disconnected`:this.#g.push(t);break;case`kicked`:this.#_.push(t);break}return this}useCommandMiddleware(...e){return this.#v.push(...e),this.#b=this.#P(),this}useEventMiddleware(...e){return this.#y.push(...e),this.#x=this.#F(),this}clientID(){return this.clid}channelID(){return this.#s.get(this.clid)?.channelID??0n}sendVoice(e,t){this.handler.sendVoicePacket(e,t)}async fileTransferInitUpload(e,n,r,i,a=!1){let[o,s]=this.#o.register(),c=v(e,n,r,i,o,a);try{await this.execCommand(c,1e4)}catch(e){throw this.#o.unregister(o),e}let l=await Promise.race([s,new Promise((e,n)=>setTimeout(()=>n(new t.x),1e4))]);if(this.#o.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.#o.register(),o=y(e,n,r,i);try{await this.execCommand(o,1e4)}catch(e){throw this.#o.unregister(i),e}let s=await Promise.race([a,new Promise((e,n)=>setTimeout(()=>n(new t.x),1e4))]);if(this.#o.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.#r=e.t.Connected;for(let e of this.#c)e();this.#c=[];let t=this.#h.slice();for(let e of t)setImmediate(()=>e())}#S(){this.handler.close(),this.crypt=new n.t(this.#e),this.handler=new i.t(this.crypt,this.logger),this.handler.onPacket=e=>this.#w(e),this.handler.onClosed=e=>this.#N(e),this.#a.reset(),this.#o.reset(),this.#s.clear(),this.clid=0,this.#b=this.#P()}async#C(){let e=this.#t.includes(`:`)?this.#t:`${this.#t}:9987`;try{return(await this.#n.resolve(this.#t))[0]?.addr??e}catch{return e}}#w(e){this.#T(e)}#T(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.#E(e.data);return}(t===2||t===3)&&e.data.length>0&&this.#D(Buffer.from(e.data).toString(`utf8`))}#E(e){if(this.#m.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.#m)setImmediate(()=>e(n))}#D(e){if(!e)return;let t=e.split(/[\n\0]/);for(let e of t){let t=e.replace(/\r$/,``);if(t)for(let e of M(t))this.#O(e)}}#O(e){let t=c.t(e);if(!(!t||!t.name)){if(t.name.startsWith(`notify`)){let e=N(t,this.clid,this.#s,this.nickname);this.#A(e,t.params);return}switch(t.name){case`clientinitiv`:S(this,t.params);break;case`initivexpand2`:C(this,t.params);break;case`initserver`:w(this,t.params);break;case`error`:this.#k(t.params);break;default:{let e=t.params;if(t.name.includes(`=`)){let n=t.name.indexOf(`=`),r=t.name.slice(0,n),i=t.name.slice(n+1);e={[r]:i,...t.params}}this.#a.buffer(e);break}}}}#k(e){let{err:t,rc:n}=f(e);n===null?this.#a.discardBuffer():this.#a.resolve(n,t),(e.id??`0`)===`3329`&&setImmediate(()=>this.disconnect().catch(()=>{}))}#A(e,t){switch(e.kind){case`clientEnter`:{let t=e.info;t.id!==0&&j(this.nickname,t.nickname)&&(this.clid=t.id,this.handler.setClientID(t.id),this.#a.signalWelcomeComplete()),this.#j(`clientEnter`,t);break}case`clientLeave`:if(this.#j(`clientLeave`,e.event),e.isSelf&&(e.event.reasonID===4||e.event.reasonID===5)){let t=e.event.reasonMsg;for(let e of this.#_)setImmediate(()=>e(t))}break;case`clientMoved`:this.#j(`clientMoved`,e.event);break;case`textMessage`:this.#j(`textMessage`,e.message);break;case`poked`:this.#j(`poked`,e.event);break;case`startUpload`:this.#o.notify(e.info.clientFileTransferID,e.info);break;case`startDownload`:this.#o.notify(e.info.clientFileTransferID,e.info);break;case`fileTransferStatus`:this.#o.notify(e.info.clientFileTransferID,e.info);break}}#j(e,t){this.#x(t)}#M(e,t){switch(e){case`textMessage`:for(let e of this.#l)setImmediate(()=>e(t));break;case`clientEnter`:for(let e of this.#u)setImmediate(()=>e(t));break;case`clientLeave`:for(let e of this.#d)setImmediate(()=>e(t));break;case`clientMoved`:for(let e of this.#f)setImmediate(()=>e(t));break;case`poked`:for(let e of this.#p)setImmediate(()=>e(t));break}}#N(t){if(this.#r===e.t.Disconnected)return;this.#r=e.t.Disconnected;let n=this.#g.slice();for(let e of n)setImmediate(()=>e(t??void 0))}#P(){return b(this.#v,async e=>{this.handler.sendPacket(i.a.Command,Buffer.from(e),0)})}#F(){return x(this.#y,e=>{typeof e==`object`&&e&&`invokerName`in e&&`message`in e&&`targetMode`in e?this.#M(`textMessage`,e):typeof e==`object`&&e&&`invokerName`in e&&`message`in e&&!(`targetMode`in e)?this.#M(`poked`,e):typeof e==`object`&&e&&`id`in e&&`uid`in e?this.#M(`clientEnter`,e):typeof e==`object`&&e&&`id`in e&&`reasonID`in e&&`targetChannelID`in e?this.#M(`clientMoved`,e):typeof e==`object`&&e&&`id`in e&&`reasonID`in e&&this.#M(`clientLeave`,e)})}};async function W(e,t,n,r){let i=a.n(`sendtextmessage`,[[`targetmode`,String(t)],[`target`,String(n)],[`msg`,r]]);await e.sendCommandNoWait(i)}async function G(e,t,n,r=``){let i=[[`clid`,String(t)],[`cid`,String(n)]];r&&i.push([`cpw`,r]);let o=a.n(`clientmove`,i);await e.execCommand(o,1e4)}async function K(e,t,n){let r=a.n(`clientpoke`,[[`clid`,String(t)],[`msg`,n]]);await e.execCommand(r,1e4)}async function q(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 J(e){return(await e.execCommandWithResponse(`channellist`,5e3)).map(e=>({id:BigInt(e.cid??`0`),parentID:BigInt(e.pid??`0`),name:a.i(e.channel_name??``),description:``}))}async function Y(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 X(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.h,exports.Client=U,exports.ClientStatus=e.t,exports.CommandTimeoutError=t.g,exports.CryptoInitError=t._,exports.EAXTagMismatchError=t.v,exports.FakeSignatureMismatchError=t.y,exports.FileTransferError=t.b,exports.FileTransferTimeoutError=t.x,exports.Identity=t.l,exports.InvalidIdentityError=t.S,exports.ServerError=t.C,exports.TeamspeakError=t.w,exports.clientMove=G,exports.consoleLogger=e.n,exports.dialFileTransfer=h,exports.downloadFileData=_,exports.fileTransferDeleteFile=X,exports.generateIdentity=t.u,exports.getClientInfo=q,exports.getUidFromPublicKey=t.d,exports.identityFromString=t.p,exports.listChannels=J,exports.listClients=Y,exports.noopLogger=e.r,exports.poke=K,exports.sendTextMessage=W,exports.uploadFileData=g;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./types-DrnoCdSW.cjs`),t=require(`./primitives-bj-ml31v.cjs`),n=require(`./crypto-2veVY1fC.cjs`),r=require(`./resolver-Dey6omBe.cjs`),i=require(`./handler-CqCD93f0.cjs`),a=require(`./command-Cu2v-5-K.cjs`),o=require(`./crypt-handshake-Dbj2cSBZ.cjs`),s=require(`./crypt-init2-C2oihZ7e.cjs`),c=require(`./parser-DhAWj-TI.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=[];for(let e of i)e!==``&&a.push(`${n} ${e}`);return a.length===0?[e]:a}function F(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.cid??``),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.t.Disconnected;#a=new W;#o=new d;#s=new m;#c=new Map;#l=[];#u=[];#d=[];#f=[];#p=[];#m=[];#h=[];#g=[];#_=[];#v=[];#y=[];#b=[];#x;#S;constructor(t,a,o,s={}){this.#e=t,this.#t=a,this.nickname=o,this.logger=s.logger??e.n,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.#T(e),this.handler.onClosed=e=>this.#P(e),s.commandMiddleware&&this.#y.push(...s.commandMiddleware),s.eventMiddleware&&this.#b.push(...s.eventMiddleware),this.#x=this.#F(),this.#S=this.#I()}get status(){return this.#i}getClientInitOptions(){return this.#r}async connect(){if(this.#i!==e.t.Disconnected)throw new t.h;this.#C(),this.#i=e.t.Connecting;let n=await this.#w();this.logger.info(`connecting to server`,{address:n}),await this.handler.connect(n)}async disconnect(){if(this.#i===e.t.Disconnected)return;let t=this.#i===e.t.Connected;if(this.#i=e.t.Disconnected,this.logger.info(`disconnecting from server`),t)try{await this.execCommand(`clientdisconnect reasonmsg=Shutdown`,1e3)}catch{}this.handler.close();let n=this.#_.slice();for(let e of n)setImmediate(()=>e(void 0))}waitConnected(t){return this.#i===e.t.Connected?Promise.resolve():new Promise((e,n)=>{this.#l.push(e),t&&t.addEventListener(`abort`,()=>n(t.reason),{once:!0})})}async sendCommandNoWait(e){await this.#a.wait(),await this.#x(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.#x(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.#u.push(t);break;case`clientEnter`:this.#d.push(t);break;case`clientLeave`:this.#f.push(t);break;case`clientMoved`:this.#p.push(t);break;case`poked`:this.#m.push(t);break;case`voiceData`:this.#h.push(t);break;case`connected`:this.#g.push(t);break;case`disconnected`:this.#_.push(t);break;case`kicked`:this.#v.push(t);break}return this}useCommandMiddleware(...e){return this.#y.push(...e),this.#x=this.#F(),this}useEventMiddleware(...e){return this.#b.push(...e),this.#S=this.#I(),this}clientID(){return this.clid}channelID(){return this.#c.get(this.clid)?.channelID??0n}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.t.Connected;for(let e of this.#l)e();this.#l=[];let t=this.#g.slice();for(let e of t)setImmediate(()=>e())}#C(){this.handler.close(),this.crypt=new n.t(this.#e),this.handler=new i.t(this.crypt,this.logger),this.handler.onPacket=e=>this.#T(e),this.handler.onClosed=e=>this.#P(e),this.#o.reset(),this.#s.reset(),this.#c.clear(),this.clid=0,this.#x=this.#F()}async#w(){let e=this.#t.includes(`:`)?this.#t:`${this.#t}:9987`;try{return(await this.#n.resolve(this.#t))[0]?.addr??e}catch{return e}}#T(e){this.#E(e)}#E(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.#D(e.data);return}(t===2||t===3)&&e.data.length>0&&this.#O(Buffer.from(e.data).toString(`utf8`))}#D(e){if(this.#h.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.#h)setImmediate(()=>e(n))}#O(e){if(!e)return;let t=e.split(/[\n\0]/);for(let e of t){let t=e.replace(/\r$/,``);if(t)for(let e of P(t))this.#k(e)}}#k(e){let t=c.t(e);if(!(!t||!t.name)){if(t.name.startsWith(`notify`)){let e=F(t,this.clid,this.#c,this.nickname);this.#j(e,t.params);return}switch(t.name){case`clientinitiv`:S(this,t.params);break;case`initivexpand2`:C(this,t.params);break;case`initserver`:w(this,t.params);break;case`error`:this.#A(t.params);break;default:{let e=t.params;if(t.name.includes(`=`)){let n=t.name.indexOf(`=`),r=t.name.slice(0,n),i=t.name.slice(n+1);e={[r]:i,...t.params}}this.#o.buffer(e);break}}}}#A(e){let{err:t,rc:n}=f(e);n===null?this.#o.discardBuffer():this.#o.resolve(n,t),(e.id??`0`)===`3329`&&setImmediate(()=>this.disconnect().catch(()=>{}))}#j(e,t){switch(e.kind){case`clientEnter`:{let t=e.info;t.id!==0&&N(this.nickname,t.nickname)&&(this.clid=t.id,this.handler.setClientID(t.id),this.#o.signalWelcomeComplete()),this.#M(`clientEnter`,t);break}case`clientLeave`:if(this.#M(`clientLeave`,e.event),e.isSelf&&(e.event.reasonID===4||e.event.reasonID===5)){let t=e.event.reasonMsg;for(let e of this.#v)setImmediate(()=>e(t))}break;case`clientMoved`:this.#M(`clientMoved`,e.event);break;case`textMessage`:this.#M(`textMessage`,e.message);break;case`poked`:this.#M(`poked`,e.event);break;case`startUpload`:this.#s.notify(e.info.clientFileTransferID,e.info);break;case`startDownload`:this.#s.notify(e.info.clientFileTransferID,e.info);break;case`fileTransferStatus`:this.#s.notify(e.info.clientFileTransferID,e.info);break}}#M(e,t){this.#S(t)}#N(e,t){switch(e){case`textMessage`:for(let e of this.#u)setImmediate(()=>e(t));break;case`clientEnter`:for(let e of this.#d)setImmediate(()=>e(t));break;case`clientLeave`:for(let e of this.#f)setImmediate(()=>e(t));break;case`clientMoved`:for(let e of this.#p)setImmediate(()=>e(t));break;case`poked`:for(let e of this.#m)setImmediate(()=>e(t));break}}#P(t){if(this.#i===e.t.Disconnected)return;this.#i=e.t.Disconnected;let n=this.#_.slice();for(let e of n)setImmediate(()=>e(t??void 0))}#F(){return b(this.#y,async e=>{this.handler.sendPacket(i.a.Command,Buffer.from(e),0)})}#I(){return x(this.#b,e=>{typeof e==`object`&&e&&`invokerName`in e&&`message`in e&&`targetMode`in e?this.#N(`textMessage`,e):typeof e==`object`&&e&&`invokerName`in e&&`message`in e&&!(`targetMode`in e)?this.#N(`poked`,e):typeof e==`object`&&e&&`id`in e&&`uid`in e?this.#N(`clientEnter`,e):typeof e==`object`&&e&&`id`in e&&`reasonID`in e&&`targetChannelID`in e?this.#N(`clientMoved`,e):typeof e==`object`&&e&&`id`in e&&`reasonID`in e&&this.#N(`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`,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??`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.h,exports.Client=K,exports.ClientStatus=e.t,exports.CommandTimeoutError=t.g,exports.CryptoInitError=t._,exports.EAXTagMismatchError=t.v,exports.FakeSignatureMismatchError=t.y,exports.FileTransferError=t.b,exports.FileTransferTimeoutError=t.x,exports.Identity=t.l,exports.InvalidIdentityError=t.S,exports.ServerError=t.C,exports.TeamspeakError=t.w,exports.clientMove=J,exports.consoleLogger=e.n,exports.dialFileTransfer=h,exports.downloadFileData=_,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.r,exports.poke=Y,exports.sendTextMessage=q,exports.uploadFileData=g;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["#pending","#nextRC","#welcomeComplete","#buffer","#pending","#nextID","#lastUpdate","#tokens","#identity","#addr","#resolver","#handlePacket","#handleConnectionClosed","#cmdMiddlewares","#eventMiddlewares","#finalCmdHandler","#buildCmdHandler","#finalEvtHandler","#buildEvtHandler","#status","#resetForConnect","#resolveAddr","#disconnectedHandlers","#connectedResolvers","#throttle","#cmdTrack","#textMsgHandlers","#clientEnterHandlers","#clientLeaveHandlers","#clientMoveHandlers","#pokedHandlers","#voiceDataHandlers","#connectedHandlers","#kickedHandlers","#clients","#ftTrack","#handlePacketSync","#handleVoicePacket","#handleCommandLines","#handleCommandStr","#processNotificationResult","#handleError","#dispatchEvent","#dispatchEventDirect"],"sources":["../src/commands.ts","../src/transfer.ts","../src/events.ts","../src/handshake.ts","../src/helpers.ts","../src/notifications.ts","../src/throttle.ts","../src/client.ts","../src/api.ts"],"sourcesContent":["import { ServerError } from \"./errors.js\";\n\nexport interface CommandResult {\n err: Error | null;\n data: Record<string, string>[];\n}\n\n/**\n * Tracks in-flight commands by return_code.\n *\n * The TS3/TS5 server sends a \"welcome sequence\" of unsolicited data immediately\n * after the connection handshake (channellist, channelclientlist, etc.). This\n * data arrives on the event loop AFTER we may have registered our first pending\n * RC, which would contaminate our command responses.\n *\n * Solution: gate all row buffering on a `#welcomeComplete` flag. The flag is\n * set when `notifycliententerview` for our own clid arrives — the last event\n * the TS3/TS5 server sends in its welcome sequence. Any data arriving before\n * that is silently discarded.\n */\nexport class CommandTracker {\n readonly #pending = new Map<number, (result: CommandResult) => void>();\n #nextRC = 0;\n #buffer: Record<string, string>[] = [];\n\n /**\n * Set to true when we receive `notifycliententerview` for our own clid,\n * which marks the end of the server's welcome sequence.\n */\n #welcomeComplete = false;\n\n register(): [rc: number, promise: Promise<CommandResult>] {\n this.#nextRC++;\n const rc = this.#nextRC;\n const promise = new Promise<CommandResult>((resolve) => {\n this.#pending.set(rc, resolve);\n });\n return [rc, promise];\n }\n\n unregister(rc: number): void {\n this.#pending.delete(rc);\n }\n\n /**\n * Called when `notifycliententerview` for our own clid arrives.\n * Marks the welcome sequence as complete and discards any accumulated data.\n */\n signalWelcomeComplete(): void {\n this.#welcomeComplete = true;\n this.#buffer = [];\n }\n\n /**\n * Buffer a data row from the server. Rows arriving before the welcome\n * sequence is complete are silently discarded to prevent contamination.\n */\n buffer(params: Record<string, string>): void {\n if (!this.#welcomeComplete) return;\n if (this.#pending.size === 0) return;\n this.#buffer.push(params);\n }\n\n resolve(rc: number, err: Error | null): void {\n const resolve = this.#pending.get(rc);\n if (!resolve) {\n this.#buffer = [];\n return;\n }\n const data = this.#buffer;\n this.#buffer = [];\n this.#pending.delete(rc);\n resolve({ err, data });\n }\n\n discardBuffer(): void {\n this.#buffer = [];\n }\n\n reset(): void {\n this.#pending.clear();\n this.#buffer = [];\n this.#welcomeComplete = false;\n this.#nextRC = 0;\n }\n}\n\n/**\n * Parse and handle an `error` command from the server.\n * Returns the error (or null on success) and the resolved return_code.\n */\nexport function parseServerError(params: Record<string, string>): {\n err: Error | null;\n rc: number | null;\n} {\n const id = params[\"id\"] ?? \"0\";\n const msg = params[\"msg\"] ?? \"\";\n const rcStr = params[\"return_code\"];\n\n let err: Error | null = null;\n if (id !== \"0\") {\n err = new ServerError(id, msg);\n }\n\n let rc: number | null = null;\n if (rcStr !== undefined && rcStr !== \"\") {\n const parsed = parseInt(rcStr, 10);\n if (!isNaN(parsed)) rc = parsed;\n }\n\n return { err, rc };\n}\n\n/**\n * Append a return_code parameter to a command string if not already present.\n */\nexport function appendReturnCode(cmd: string, rc: number): string {\n if (cmd.includes(\"return_code=\")) return cmd;\n return `${cmd} return_code=${rc}`;\n}\n","import { createConnection } from \"node:net\";\nimport type { Readable, Writable } from \"node:stream\";\nimport type { FileUploadInfo, FileDownloadInfo } from \"./types.js\";\nimport { FileTransferError, FileTransferTimeoutError } from \"./errors.js\";\nimport { buildCommand } from \"./command/command.js\";\n\nexport interface FileTransferTracker {\n register(): [\n cftid: number,\n promise: Promise<\n FileUploadInfo | FileDownloadInfo | import(\"./types.js\").FileTransferStatusInfo\n >,\n ];\n unregister(cftid: number): void;\n notify(\n cftid: number,\n value: FileUploadInfo | FileDownloadInfo | import(\"./types.js\").FileTransferStatusInfo,\n ): void;\n reset(): void;\n}\n\ntype FtNotification =\n | FileUploadInfo\n | FileDownloadInfo\n | import(\"./types.js\").FileTransferStatusInfo;\n\nexport class FileTransferTracker {\n readonly #pending = new Map<number, (v: FtNotification) => void>();\n #nextID = 0;\n\n register(): [cftid: number, promise: Promise<FtNotification>] {\n this.#nextID++;\n if (this.#nextID > 65535) this.#nextID = 1;\n const cftid = this.#nextID;\n const promise = new Promise<FtNotification>((resolve) => {\n this.#pending.set(cftid, resolve);\n });\n return [cftid, promise];\n }\n\n unregister(cftid: number): void {\n this.#pending.delete(cftid);\n }\n\n notify(cftid: number, value: FtNotification): void {\n const resolve = this.#pending.get(cftid);\n if (resolve) resolve(value);\n }\n\n reset(): void {\n this.#pending.clear();\n this.#nextID = 0;\n }\n}\n\n/**\n * Open a TCP connection to the TS3 file transfer port and perform the\n * ftkey handshake. The caller is responsible for closing the socket.\n */\nexport function dialFileTransfer(\n host: string,\n port: number,\n key: string,\n): Promise<import(\"node:net\").Socket> {\n return new Promise((resolve, reject) => {\n const socket = createConnection({ host, port }, () => {\n socket.write(key, (err) => {\n if (err) {\n socket.destroy();\n reject(new FileTransferError(`failed to send transfer key: ${err.message}`));\n } else {\n resolve(socket);\n }\n });\n });\n socket.setTimeout(10_000);\n socket.once(\"error\", reject);\n socket.once(\"timeout\", () => {\n socket.destroy();\n reject(new FileTransferError(\"connection timeout\"));\n });\n });\n}\n\n/** Upload data via a TS3 file transfer connection. */\nexport async function uploadFileData(\n host: string,\n info: FileUploadInfo,\n data: Readable,\n): Promise<void> {\n const socket = await dialFileTransfer(host, info.port, info.fileTransferKey);\n await new Promise<void>((resolve, reject) => {\n data.pipe(socket);\n socket.on(\"finish\", resolve);\n socket.on(\"error\", reject);\n });\n}\n\n/** Download data via a TS3 file transfer connection. */\nexport async function downloadFileData(\n host: string,\n info: FileDownloadInfo,\n dest: Writable,\n): Promise<void> {\n const socket = await dialFileTransfer(host, info.port, info.fileTransferKey);\n await new Promise<void>((resolve, reject) => {\n socket.pipe(dest);\n dest.on(\"finish\", resolve);\n socket.on(\"error\", reject);\n dest.on(\"error\", reject);\n });\n}\n\n/**\n * Build a ftinitupload command string.\n */\nexport function buildFtInitUpload(\n channelID: bigint,\n path: string,\n password: string,\n size: bigint,\n cftid: number,\n overwrite: boolean,\n): string {\n const targetPath = path.startsWith(\"/\") ? path : `/${path}`;\n return buildCommand(\"ftinitupload\", {\n cid: String(channelID),\n name: targetPath,\n cpw: password,\n size: String(size),\n clientftfid: String(cftid),\n overwrite: overwrite ? \"1\" : \"0\",\n resume: \"0\",\n });\n}\n\n/**\n * Build a ftinitdownload command string.\n */\nexport function buildFtInitDownload(\n channelID: bigint,\n path: string,\n password: string,\n cftid: number,\n): string {\n const targetPath = path.startsWith(\"/\") ? path : `/${path}`;\n return buildCommand(\"ftinitdownload\", {\n cid: String(channelID),\n name: targetPath,\n cpw: password,\n clientftfid: String(cftid),\n seekpos: \"0\",\n });\n}\n\nexport { FileTransferError, FileTransferTimeoutError };\n","import type { EventMap, CommandMiddleware, EventMiddleware } from \"./types.js\";\n\ntype EventHandler<K extends keyof EventMap> = EventMap[K] extends void\n ? () => void\n : (payload: EventMap[K]) => void;\n\nexport type { EventHandler };\n\n/**\n * Compose a chain of middlewares around a base handler.\n * Rightmost middleware wraps the base first.\n */\nexport function buildCommandChain(\n middlewares: CommandMiddleware[],\n base: (cmd: string) => Promise<void>,\n): (cmd: string) => Promise<void> {\n let handler = base;\n for (let i = middlewares.length - 1; i >= 0; i--) {\n handler = middlewares[i]!(handler);\n }\n return handler;\n}\n\nexport function buildEventChain(\n middlewares: EventMiddleware[],\n base: (evt: EventMap[keyof EventMap]) => void,\n): (evt: EventMap[keyof EventMap]) => void {\n let handler = base;\n for (let i = middlewares.length - 1; i >= 0; i--) {\n handler = middlewares[i]!(handler);\n }\n return handler;\n}\n","import { createHash } from \"node:crypto\";\nimport { buildCommandOrdered, buildCommand } from \"./command/command.js\";\nimport { sign, generateTemporaryKey } from \"./crypto/primitives.js\";\nimport { cryptoInit2 } from \"./handshake/crypt-init2.js\";\nimport { PacketType } from \"./transport/packet.js\";\nimport type { Client } from \"./client.js\";\n\n/** Handle the `clientinitiv` message (P-256 based crypto path). */\nexport function handleHandshakeInitIV(client: Client, params: Record<string, string>): void {\n const alpha = params[\"alpha\"] ?? \"\";\n const beta = params[\"beta\"] ?? \"\";\n const omega = params[\"omega\"] ?? \"\";\n\n client.crypt.initCrypto(alpha, beta, omega);\n client.logger.info(\"crypto initialized (P-256 path), sending clientinit\");\n sendClientInit(client);\n}\n\n/** Handle the `initivexpand2` message (Ed25519 / TS3 crypto path). */\nexport function handleHandshakeExpand2(client: Client, params: Record<string, string>): void {\n client.logger.info(\"received initivexpand2\");\n client.handler.receivedFinalInitAck();\n\n const license = params[\"l\"] ?? \"\";\n const omega = params[\"omega\"] ?? \"\";\n const proof = params[\"proof\"] ?? \"\";\n const beta = params[\"beta\"] ?? \"\";\n\n const privateKey = sendClientEkPacket(client, beta);\n cryptoInit2(client.crypt, license, omega, proof, beta, privateKey);\n sendClientInit(client);\n}\n\n/** Handle `initserver` — marks the client as connected. */\nexport function handleInitServer(client: Client, params: Record<string, string>): void {\n const idStr = params[\"aclid\"] ?? params[\"clid\"] ?? \"\";\n const clid = idStr ? parseInt(idStr, 10) : 0;\n\n if (clid > 0) {\n client.clid = clid;\n client.handler.setClientID(clid);\n }\n\n client.logger.info(\"connected to server\", { selfId: client.clid });\n client._markConnected();\n\n // Inform the server about mute state\n setImmediate(() => {\n const updateCmd = buildCommand(\"clientupdate\", {\n client_input_muted: \"0\",\n client_output_muted: \"0\",\n });\n client.sendCommandNoWait(updateCmd).catch(() => {});\n });\n}\n\nfunction sendClientEkPacket(client: Client, beta: string): Uint8Array {\n const [publicKey, privateKey] = generateTemporaryKey();\n const ekBase64 = Buffer.from(publicKey).toString(\"base64\");\n const clientProof = buildClientEkProof(client, publicKey, beta);\n\n const clientEk = buildCommandOrdered(\"clientek\", [\n [\"ek\", ekBase64],\n [\"proof\", clientProof],\n ]);\n client.handler.sendPacket(PacketType.Command, Buffer.from(clientEk), 0);\n return privateKey;\n}\n\nfunction buildClientEkProof(client: Client, publicKey: Uint8Array, beta: string): string {\n const betaBytes = Buffer.from(beta, \"base64\");\n const toSign = new Uint8Array(86);\n toSign.set(publicKey.slice(0, 32));\n toSign.set(betaBytes.slice(0, Math.min(54, betaBytes.length)), 32);\n const sig = sign(client.crypt.identity.privateKey, toSign);\n return Buffer.from(sig).toString(\"base64\");\n}\n\nexport function sendClientInit(client: Client): void {\n const pubKeyBase64 = client.crypt.identity.publicKeyBase64();\n // HWID should match TS3 client UID format: base64(SHA1(publicKeyBase64))\n const hwid = createHash(\"sha1\").update(pubKeyBase64).digest().toString(\"base64\");\n\n const cmd = buildCommandOrdered(\"clientinit\", [\n [\"client_nickname\", client.nickname],\n [\"client_version\", \"3.?.? [Build: 5680278000]\"],\n [\"client_platform\", \"Windows\"],\n [\"client_input_hardware\", \"1\"],\n [\"client_output_hardware\", \"1\"],\n [\"client_default_channel\", \"\"],\n [\"client_default_channel_password\", \"\"],\n [\"client_server_password\", \"\"],\n [\"client_meta_data\", \"\"],\n [\n \"client_version_sign\",\n \"DX5NIYLvfJEUjuIbCidnoeozxIDRRkpq3I9vVMBmE9L2qnekOoBzSenkzsg2lC9CMv8K5hkEzhr2TYUYSwUXCg==\",\n ],\n [\"client_key_offset\", String(client.crypt.identity.offset)],\n [\"client_nickname_phonetic\", \"\"],\n [\"client_default_token\", \"\"],\n [\"hwid\", hwid],\n ]);\n\n client.handler.sendPacket(PacketType.Command, Buffer.from(cmd), 0);\n}\n","export function parseUint64(s: string): bigint {\n if (s === \"\" || s === undefined) return 0n;\n try {\n return BigInt(s);\n } catch {\n return 0n;\n }\n}\n\nexport function parseUint16(s: string): number {\n const v = parseInt(s, 10);\n if (isNaN(v) || v < 0 || v > 65535) return 0;\n return v;\n}\n\nexport function parseInt10(s: string): number {\n const v = parseInt(s, 10);\n return isNaN(v) ? 0 : v;\n}\n\n/**\n * Reports whether `actual` equals `expected` or equals `expected` followed by\n * only digits — the pattern TeamSpeak uses when a nickname is already taken.\n */\nexport function isAutoNicknameMatch(expected: string, actual: string): boolean {\n if (actual === expected) return true;\n if (!actual.startsWith(expected)) return false;\n const suffix = actual.slice(expected.length);\n return /^\\d+$/.test(suffix);\n}\n\n/**\n * Expand a pipe-separated multi-row TS3 command line into individual rows,\n * each prefixed with the command name.\n */\nexport function splitCommandRows(line: string): string[] {\n const spaceIdx = line.indexOf(\" \");\n if (spaceIdx < 0) return [line];\n\n const name = line.slice(0, spaceIdx);\n const rest = line.slice(spaceIdx + 1);\n\n if (!rest.includes(\"|\")) return [line];\n\n const parts = rest.split(\"|\");\n const rows: string[] = [];\n for (const part of parts) {\n if (part !== \"\") rows.push(`${name} ${part}`);\n }\n return rows.length === 0 ? [line] : rows;\n}\n","import type { Command } from \"./command/command.js\";\nimport { unescape } from \"./command/command.js\";\nimport type {\n ClientInfo,\n ClientLeftViewEvent,\n ClientMovedEvent,\n TextMessage,\n PokeEvent,\n FileUploadInfo,\n FileDownloadInfo,\n FileTransferStatusInfo,\n} from \"./types.js\";\nimport { parseUint64, parseUint16, parseInt10 } from \"./helpers.js\";\n\nexport type NotificationResult =\n | { kind: \"clientEnter\"; info: ClientInfo }\n | { kind: \"clientLeave\"; event: ClientLeftViewEvent; isSelf: boolean }\n | { kind: \"clientMoved\"; event: ClientMovedEvent }\n | { kind: \"textMessage\"; message: TextMessage }\n | { kind: \"poked\"; event: PokeEvent }\n | { kind: \"startUpload\"; info: FileUploadInfo }\n | { kind: \"startDownload\"; info: FileDownloadInfo }\n | { kind: \"fileTransferStatus\"; info: FileTransferStatusInfo }\n | { kind: \"unknown\" };\n\nexport function handleNotification(\n cmd: Command,\n selfCLID: number,\n clients: Map<number, ClientInfo>,\n nickname: string,\n): NotificationResult {\n switch (cmd.name) {\n case \"notifycliententerview\":\n return handleClientEnterView(cmd, clients, nickname);\n case \"notifyclientleftview\":\n return handleClientLeftView(cmd, selfCLID, clients);\n case \"notifyclientmoved\":\n return handleClientMoved(cmd, clients);\n case \"notifytextmessage\":\n return handleTextMessage(cmd, clients);\n case \"notifyclientpoke\":\n return handleClientPoked(cmd);\n case \"notifystartupload\":\n return { kind: \"startUpload\", info: handleStartUpload(cmd) };\n case \"notifystartdownload\":\n return { kind: \"startDownload\", info: handleStartDownload(cmd) };\n case \"notifystatusfiletransfer\":\n return { kind: \"fileTransferStatus\", info: handleFileTransferStatus(cmd) };\n default:\n return { kind: \"unknown\" };\n }\n}\n\nfunction handleClientEnterView(\n cmd: Command,\n clients: Map<number, ClientInfo>,\n nickname: string,\n): NotificationResult {\n const clid = parseUint16(cmd.params[\"clid\"] ?? \"\");\n const cid = parseUint64(cmd.params[\"cid\"] ?? \"\");\n const clientType = parseInt10(cmd.params[\"client_type\"] ?? \"\");\n const groupsStr = cmd.params[\"client_servergroups\"] ?? \"\";\n\n const info: ClientInfo = {\n id: clid,\n nickname: cmd.params[\"client_nickname\"] ?? \"\",\n uid: cmd.params[\"client_unique_identifier\"] ?? \"\",\n channelID: cid,\n type: clientType,\n serverGroups: groupsStr ? groupsStr.split(\",\") : [],\n };\n\n if (clid !== 0) {\n clients.set(clid, info);\n }\n\n return { kind: \"clientEnter\", info };\n}\n\nfunction handleClientLeftView(\n cmd: Command,\n selfCLID: number,\n clients: Map<number, ClientInfo>,\n): NotificationResult {\n const clid = parseUint16(cmd.params[\"clid\"] ?? \"\");\n const reasonID = parseInt10(cmd.params[\"reasonid\"] ?? \"\");\n\n const isSelf = clid === selfCLID;\n if (clid !== 0) clients.delete(clid);\n\n return {\n kind: \"clientLeave\",\n event: {\n id: clid,\n reasonID,\n reasonMsg: cmd.params[\"reasonmsg\"] ?? \"\",\n targetID: parseUint16(cmd.params[\"targetid\"] ?? \"\"),\n },\n isSelf,\n };\n}\n\nfunction handleClientMoved(cmd: Command, clients: Map<number, ClientInfo>): NotificationResult {\n const clid = parseUint16(cmd.params[\"clid\"] ?? \"\");\n const ctid = parseUint64(cmd.params[\"ctid\"] ?? \"\");\n\n if (clid !== 0) {\n const existing = clients.get(clid);\n if (existing) clients.set(clid, { ...existing, channelID: ctid });\n }\n\n return {\n kind: \"clientMoved\",\n event: {\n id: clid,\n targetChannelID: ctid,\n reasonID: parseInt10(cmd.params[\"reasonid\"] ?? \"\"),\n invokerID: parseUint16(cmd.params[\"invokerid\"] ?? \"\"),\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: cmd.params[\"invokeruid\"] ?? \"\",\n },\n };\n}\n\nfunction handleTextMessage(cmd: Command, clients: Map<number, ClientInfo>): NotificationResult {\n const invokerID = parseUint16(cmd.params[\"invokerid\"] ?? \"\");\n const invokerInfo = clients.get(invokerID);\n\n const message: TextMessage = {\n targetMode: parseInt10(cmd.params[\"targetmode\"] ?? \"\"),\n targetID: parseUint64(cmd.params[\"target\"] ?? \"\"),\n invokerID,\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: cmd.params[\"invokeruid\"] ?? invokerInfo?.uid ?? \"\",\n message: unescape(cmd.params[\"msg\"] ?? \"\"),\n invokerGroups: invokerInfo?.serverGroups ?? [],\n };\n\n return { kind: \"textMessage\", message };\n}\n\nfunction handleStartUpload(cmd: Command): FileUploadInfo {\n return {\n clientFileTransferID: parseUint16(cmd.params[\"clientftfid\"] ?? \"\"),\n serverFileTransferID: parseUint16(cmd.params[\"serverftfid\"] ?? \"\"),\n fileTransferKey: cmd.params[\"ftkey\"] ?? \"\",\n port: parseUint16(cmd.params[\"port\"] ?? \"\"),\n seekPosition: parseUint64(cmd.params[\"seekpos\"] ?? \"\"),\n };\n}\n\nfunction handleStartDownload(cmd: Command): FileDownloadInfo {\n return {\n clientFileTransferID: parseUint16(cmd.params[\"clientftfid\"] ?? \"\"),\n serverFileTransferID: parseUint16(cmd.params[\"serverftfid\"] ?? \"\"),\n fileTransferKey: cmd.params[\"ftkey\"] ?? \"\",\n port: parseUint16(cmd.params[\"port\"] ?? \"\"),\n size: parseUint64(cmd.params[\"size\"] ?? \"\"),\n };\n}\n\nfunction handleFileTransferStatus(cmd: Command): FileTransferStatusInfo {\n return {\n clientFileTransferID: parseUint16(cmd.params[\"clientftfid\"] ?? \"\"),\n status: parseInt10(cmd.params[\"status\"] ?? \"\"),\n message: cmd.params[\"msg\"] ?? \"\",\n };\n}\n\nfunction handleClientPoked(cmd: Command): NotificationResult {\n return {\n kind: \"poked\",\n event: {\n invokerID: parseUint16(cmd.params[\"invokerid\"] ?? \"\"),\n invokerName: unescape(cmd.params[\"invokername\"] ?? \"\"),\n invokerUID: cmd.params[\"invokeruid\"] ?? \"\",\n message: unescape(cmd.params[\"msg\"] ?? \"\"),\n },\n };\n}\n","/**\n * Token-bucket limiter for outbound TS3 commands.\n * Mirrors Go's commandThrottle.\n */\nexport class CommandThrottle {\n static readonly TOKEN_RATE = 4.0; // tokens per second\n static readonly TOKEN_MAX = 8.0; // bucket capacity\n\n #tokens = 5.0;\n #lastUpdate = Date.now();\n\n async wait(signal?: AbortSignal): Promise<void> {\n while (true) {\n if (signal?.aborted) throw signal.reason as Error;\n\n const now = Date.now();\n const elapsed = (now - this.#lastUpdate) / 1000;\n this.#tokens = Math.min(\n this.#tokens + elapsed * CommandThrottle.TOKEN_RATE,\n CommandThrottle.TOKEN_MAX,\n );\n this.#lastUpdate = now;\n\n if (this.#tokens >= 1.0) {\n this.#tokens -= 1.0;\n return;\n }\n\n const waitMs = Math.ceil(((1.0 - this.#tokens) / CommandThrottle.TOKEN_RATE) * 1000) + 10;\n\n await new Promise<void>((resolve, reject) => {\n const timer = setTimeout(resolve, waitMs);\n if (signal) {\n signal.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n reject(signal.reason as Error);\n },\n { once: true },\n );\n }\n });\n }\n }\n}\n","import {\n type EventMap,\n type ClientOptions,\n type CommandMiddleware,\n type EventMiddleware,\n type Logger,\n type AddrResolver,\n type ClientInfo,\n ClientStatus,\n consoleLogger,\n} from \"./types.js\";\nimport { AlreadyConnectedError } from \"./errors.js\";\nimport { Identity, Crypt } from \"./crypto/index.js\";\nimport { Resolver } from \"./discovery/resolver.js\";\nimport { PacketHandler } from \"./transport/handler.js\";\nimport { PacketType } from \"./transport/packet.js\";\nimport type { Packet } from \"./transport/packet.js\";\nimport { CommandTracker, appendReturnCode, parseServerError } from \"./commands.js\";\nimport {\n FileTransferTracker,\n buildFtInitUpload,\n buildFtInitDownload,\n dialFileTransfer,\n uploadFileData,\n downloadFileData,\n} from \"./transfer.js\";\nimport { buildCommandChain, buildEventChain } from \"./events.js\";\nimport { processInit1 } from \"./handshake/crypt-handshake.js\";\nimport { handleHandshakeInitIV, handleHandshakeExpand2, handleInitServer } from \"./handshake.js\";\nimport { handleNotification } from \"./notifications.js\";\nimport { parseCommand } from \"./command/parser.js\";\nimport { CommandThrottle } from \"./throttle.js\";\nimport { splitCommandRows, isAutoNicknameMatch } from \"./helpers.js\";\nimport type { FileUploadInfo, FileDownloadInfo } from \"./types.js\";\nimport { CommandTimeoutError, FileTransferTimeoutError, FileTransferError } from \"./errors.js\";\nimport type { Readable, Writable } from \"node:stream\";\n\nexport { ClientStatus };\n\nexport interface ClientState {\n status: ClientStatus;\n clid: number;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyHandler = (arg: any) => void;\n\nexport class Client {\n // Internal — accessible from handshake.ts helpers\n /** @internal */ crypt: Crypt;\n /** @internal */ handler: PacketHandler;\n /** @internal */ logger: Logger;\n /** @internal */ nickname: string;\n /** @internal */ clid = 0;\n\n #identity: Identity;\n #addr: string;\n #resolver: AddrResolver;\n #status: ClientStatus = ClientStatus.Disconnected;\n #throttle = new CommandThrottle();\n #cmdTrack = new CommandTracker();\n #ftTrack = new FileTransferTracker();\n #clients = new Map<number, ClientInfo>();\n #connectedResolvers: Array<() => void> = [];\n\n // Event handler lists\n #textMsgHandlers: Array<(msg: import(\"./types.js\").TextMessage) => void> = [];\n #clientEnterHandlers: Array<(info: ClientInfo) => void> = [];\n #clientLeaveHandlers: Array<(evt: import(\"./types.js\").ClientLeftViewEvent) => void> = [];\n #clientMoveHandlers: Array<(evt: import(\"./types.js\").ClientMovedEvent) => void> = [];\n #pokedHandlers: Array<(evt: import(\"./types.js\").PokeEvent) => void> = [];\n #voiceDataHandlers: Array<(data: import(\"./types.js\").VoiceData) => void> = [];\n #connectedHandlers: Array<() => void> = [];\n #disconnectedHandlers: Array<(err: Error | undefined) => void> = [];\n #kickedHandlers: Array<(msg: string) => void> = [];\n\n // Middleware\n #cmdMiddlewares: CommandMiddleware[] = [];\n #eventMiddlewares: EventMiddleware[] = [];\n #finalCmdHandler: (cmd: string) => Promise<void>;\n #finalEvtHandler: (evt: EventMap[keyof EventMap]) => void;\n\n constructor(identity: Identity, addr: string, nickname: string, options: ClientOptions = {}) {\n this.#identity = identity;\n this.#addr = addr;\n this.nickname = nickname;\n this.logger = options.logger ?? consoleLogger;\n this.#resolver = options.resolver ?? new Resolver(this.logger);\n\n this.crypt = new Crypt(identity);\n this.handler = new PacketHandler(this.crypt, this.logger);\n this.handler.onPacket = (p) => this.#handlePacket(p);\n this.handler.onClosed = (err) => this.#handleConnectionClosed(err);\n\n if (options.commandMiddleware) {\n this.#cmdMiddlewares.push(...options.commandMiddleware);\n }\n if (options.eventMiddleware) {\n this.#eventMiddlewares.push(...options.eventMiddleware);\n }\n\n this.#finalCmdHandler = this.#buildCmdHandler();\n this.#finalEvtHandler = this.#buildEvtHandler();\n }\n\n get status(): ClientStatus {\n return this.#status;\n }\n\n // ---- Connection -----------------------------------------------------------\n\n async connect(): Promise<void> {\n if (this.#status !== ClientStatus.Disconnected) {\n throw new AlreadyConnectedError();\n }\n\n this.#resetForConnect();\n this.#status = ClientStatus.Connecting;\n\n const targetAddr = await this.#resolveAddr();\n this.logger.info(\"connecting to server\", { address: targetAddr });\n await this.handler.connect(targetAddr);\n }\n\n async disconnect(): Promise<void> {\n if (this.#status === ClientStatus.Disconnected) return;\n\n const wasConnected = this.#status === ClientStatus.Connected;\n this.#status = ClientStatus.Disconnected;\n\n this.logger.info(\"disconnecting from server\");\n\n if (wasConnected) {\n try {\n await this.execCommand(\"clientdisconnect reasonmsg=Shutdown\", 1000);\n } catch {\n // best-effort\n }\n }\n\n this.handler.close();\n const handlers = this.#disconnectedHandlers.slice();\n for (const h of handlers) setImmediate(() => h(undefined));\n }\n\n waitConnected(signal?: AbortSignal): Promise<void> {\n if (this.#status === ClientStatus.Connected) return Promise.resolve();\n return new Promise<void>((resolve, reject) => {\n this.#connectedResolvers.push(resolve);\n if (signal) {\n signal.addEventListener(\"abort\", () => reject(signal.reason as Error), { once: true });\n }\n });\n }\n\n // ---- Commands ------------------------------------------------------------\n\n async sendCommandNoWait(cmd: string): Promise<void> {\n await this.#throttle.wait();\n await this.#finalCmdHandler(cmd);\n }\n\n async execCommand(cmd: string, timeoutMs = 10_000): Promise<void> {\n await this.execCommandWithResponse(cmd, timeoutMs);\n }\n\n async execCommandWithResponse(\n cmd: string,\n timeoutMs = 10_000,\n ): Promise<Record<string, string>[]> {\n const [rc, promise] = this.#cmdTrack.register();\n const withRc = appendReturnCode(cmd, rc);\n\n try {\n await this.#throttle.wait();\n await this.#finalCmdHandler(withRc);\n } catch (err) {\n this.#cmdTrack.unregister(rc);\n throw err;\n }\n\n const result = await Promise.race([\n promise,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new CommandTimeoutError(cmd)), timeoutMs),\n ),\n ]);\n\n this.#cmdTrack.unregister(rc);\n\n if (result.err) throw result.err;\n return result.data;\n }\n\n // ---- Events --------------------------------------------------------------\n\n on<K extends keyof EventMap>(\n event: K,\n handler: EventMap[K] extends void ? () => void : (payload: EventMap[K]) => void,\n ): this {\n switch (event) {\n case \"textMessage\":\n this.#textMsgHandlers.push(handler as AnyHandler);\n break;\n case \"clientEnter\":\n this.#clientEnterHandlers.push(handler as AnyHandler);\n break;\n case \"clientLeave\":\n this.#clientLeaveHandlers.push(handler as AnyHandler);\n break;\n case \"clientMoved\":\n this.#clientMoveHandlers.push(handler as AnyHandler);\n break;\n case \"poked\":\n this.#pokedHandlers.push(handler as AnyHandler);\n break;\n case \"voiceData\":\n this.#voiceDataHandlers.push(handler as AnyHandler);\n break;\n case \"connected\":\n this.#connectedHandlers.push(handler as () => void);\n break;\n case \"disconnected\":\n this.#disconnectedHandlers.push(handler as AnyHandler);\n break;\n case \"kicked\":\n this.#kickedHandlers.push(handler as AnyHandler);\n break;\n }\n return this;\n }\n\n useCommandMiddleware(...mw: CommandMiddleware[]): this {\n this.#cmdMiddlewares.push(...mw);\n this.#finalCmdHandler = this.#buildCmdHandler();\n return this;\n }\n\n useEventMiddleware(...mw: EventMiddleware[]): this {\n this.#eventMiddlewares.push(...mw);\n this.#finalEvtHandler = this.#buildEvtHandler();\n return this;\n }\n\n // ---- API shorthand -------------------------------------------------------\n\n clientID(): number {\n return this.clid;\n }\n\n channelID(): bigint {\n const info = this.#clients.get(this.clid);\n return info?.channelID ?? 0n;\n }\n\n sendVoice(data: Uint8Array, codec: number): void {\n this.handler.sendVoicePacket(data, codec);\n }\n\n // ---- File Transfer -------------------------------------------------------\n\n async fileTransferInitUpload(\n channelID: bigint,\n path: string,\n password: string,\n size: bigint,\n overwrite = false,\n ): Promise<FileUploadInfo> {\n const [cftid, ftPromise] = this.#ftTrack.register();\n const cmd = buildFtInitUpload(channelID, path, password, size, cftid, overwrite);\n\n try {\n await this.execCommand(cmd, 10_000);\n } catch (err) {\n this.#ftTrack.unregister(cftid);\n throw err;\n }\n\n const result = await Promise.race([\n ftPromise,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new FileTransferTimeoutError()), 10_000),\n ),\n ]);\n this.#ftTrack.unregister(cftid);\n\n if (\"size\" in result) throw new FileTransferError(\"unexpected download response\");\n if (\"status\" in result) {\n const st = result as import(\"./types.js\").FileTransferStatusInfo;\n throw new FileTransferError(`${st.message} (status=${st.status})`);\n }\n return result as FileUploadInfo;\n }\n\n async fileTransferInitDownload(\n channelID: bigint,\n path: string,\n password: string,\n ): Promise<FileDownloadInfo> {\n const [cftid, ftPromise] = this.#ftTrack.register();\n const cmd = buildFtInitDownload(channelID, path, password, cftid);\n\n try {\n await this.execCommand(cmd, 10_000);\n } catch (err) {\n this.#ftTrack.unregister(cftid);\n throw err;\n }\n\n const result = await Promise.race([\n ftPromise,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new FileTransferTimeoutError()), 10_000),\n ),\n ]);\n this.#ftTrack.unregister(cftid);\n\n if (\"seekPosition\" in result) throw new FileTransferError(\"unexpected upload response\");\n if (\"status\" in result) {\n const st = result as import(\"./types.js\").FileTransferStatusInfo;\n throw new FileTransferError(`${st.message} (status=${st.status})`);\n }\n return result as FileDownloadInfo;\n }\n\n uploadFileData(host: string, info: FileUploadInfo, data: Readable): Promise<void> {\n return uploadFileData(host, info, data);\n }\n\n downloadFileData(host: string, info: FileDownloadInfo, dest: Writable): Promise<void> {\n return downloadFileData(host, info, dest);\n }\n\n // ---- Internal (package-visible) ------------------------------------------\n\n /** @internal */\n _markConnected(): void {\n this.#status = ClientStatus.Connected;\n for (const resolve of this.#connectedResolvers) resolve();\n this.#connectedResolvers = [];\n const handlers = this.#connectedHandlers.slice();\n for (const h of handlers) setImmediate(() => h());\n }\n\n // ---- Private -------------------------------------------------------------\n\n #resetForConnect(): void {\n this.handler.close();\n this.crypt = new Crypt(this.#identity);\n this.handler = new PacketHandler(this.crypt, this.logger);\n this.handler.onPacket = (p) => this.#handlePacket(p);\n this.handler.onClosed = (err) => this.#handleConnectionClosed(err);\n this.#cmdTrack.reset();\n this.#ftTrack.reset();\n this.#clients.clear();\n this.clid = 0;\n this.#finalCmdHandler = this.#buildCmdHandler();\n }\n\n async #resolveAddr(): Promise<string> {\n const addrWithPort = this.#addr.includes(\":\") ? this.#addr : `${this.#addr}:9987`;\n try {\n const resolved = await this.#resolver.resolve(this.#addr);\n return resolved[0]?.addr ?? addrWithPort;\n } catch {\n return addrWithPort;\n }\n }\n\n #handlePacket(p: Packet): void {\n this.#handlePacketSync(p);\n }\n\n #handlePacketSync(p: Packet): void {\n const pType = p.typeFlagged & 0x0f;\n if (pType === 8 /* Init1 */) {\n const response = processInit1(this.crypt, p.data);\n if (response) {\n this.handler.sendPacket(PacketType.Init1, response, 0);\n }\n return;\n }\n\n if ((pType === 0 /* Voice */ || pType === 1) /* VoiceWhisper */ && p.data.length > 5) {\n this.#handleVoicePacket(p.data);\n return;\n }\n\n if ((pType === 2 /* Command */ || pType === 3) /* CommandLow */ && p.data.length > 0) {\n this.#handleCommandLines(Buffer.from(p.data).toString(\"utf8\"));\n }\n }\n\n /**\n * Parse an incoming S2C voice packet.\n * Format: [VId: u16] [CId: u16] [Codec: u8] [Data: var]\n */\n #handleVoicePacket(payload: Uint8Array): void {\n if (this.#voiceDataHandlers.length === 0) return;\n\n const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);\n const clientId = view.getUint16(2, false);\n if (clientId === this.clid) return;\n\n const codec = payload[4]!;\n const data = payload.subarray(5);\n\n const voiceData: import(\"./types.js\").VoiceData = { clientId, codec, data };\n for (const h of this.#voiceDataHandlers) setImmediate(() => h(voiceData));\n }\n\n #handleCommandLines(s: string): void {\n if (!s) return;\n const lines = s.split(/[\\n\\0]/);\n for (const line of lines) {\n const trimmed = line.replace(/\\r$/, \"\");\n if (!trimmed) continue;\n for (const row of splitCommandRows(trimmed)) {\n this.#handleCommandStr(row);\n }\n }\n }\n\n #handleCommandStr(s: string): void {\n const cmd = parseCommand(s);\n if (!cmd || !cmd.name) return;\n\n if (cmd.name.startsWith(\"notify\")) {\n const result = handleNotification(cmd, this.clid, this.#clients, this.nickname);\n this.#processNotificationResult(result, cmd.params);\n return;\n }\n\n switch (cmd.name) {\n case \"clientinitiv\":\n handleHandshakeInitIV(this, cmd.params);\n break;\n case \"initivexpand2\":\n handleHandshakeExpand2(this, cmd.params);\n break;\n case \"initserver\":\n handleInitServer(this, cmd.params);\n break;\n case \"error\":\n this.#handleError(cmd.params);\n break;\n default: {\n // TS5/TS6 servers send data rows without a command-name prefix.\n // In that case our parser treats the first key=value pair as the\n // \"command name\" (e.g. name=\"clid=1827\"). Reconstruct full params.\n let params = cmd.params;\n if (cmd.name.includes(\"=\")) {\n const eqIdx = cmd.name.indexOf(\"=\");\n const k = cmd.name.slice(0, eqIdx);\n const v = cmd.name.slice(eqIdx + 1);\n params = { [k]: v, ...cmd.params };\n }\n this.#cmdTrack.buffer(params);\n break;\n }\n }\n }\n\n #handleError(params: Record<string, string>): void {\n const { err, rc } = parseServerError(params);\n if (rc !== null) {\n this.#cmdTrack.resolve(rc, err);\n } else {\n // No return_code: server is acknowledging an unsolicited command\n // (welcome-sequence channellist, no-RC commands like clientupdate, etc.).\n // Discard any rows buffered since the last resolved command.\n this.#cmdTrack.discardBuffer();\n }\n\n const id = params[\"id\"] ?? \"0\";\n if (id === \"3329\") {\n setImmediate(() => this.disconnect().catch(() => {}));\n }\n }\n\n #processNotificationResult(\n result: import(\"./notifications.js\").NotificationResult,\n _params: Record<string, string>,\n ): void {\n switch (result.kind) {\n case \"clientEnter\": {\n const info = result.info;\n if (info.id !== 0 && isAutoNicknameMatch(this.nickname, info.nickname)) {\n this.clid = info.id;\n this.handler.setClientID(info.id);\n // Our own notifycliententerview is the last event in the TS3/TS5\n // welcome sequence. Signal that it's safe to buffer command responses.\n this.#cmdTrack.signalWelcomeComplete();\n }\n this.#dispatchEvent(\"clientEnter\", info);\n break;\n }\n case \"clientLeave\": {\n this.#dispatchEvent(\"clientLeave\", result.event);\n if (result.isSelf && (result.event.reasonID === 4 || result.event.reasonID === 5)) {\n const msg = result.event.reasonMsg;\n for (const h of this.#kickedHandlers) setImmediate(() => h(msg));\n }\n break;\n }\n case \"clientMoved\":\n this.#dispatchEvent(\"clientMoved\", result.event);\n break;\n case \"textMessage\":\n this.#dispatchEvent(\"textMessage\", result.message);\n break;\n case \"poked\":\n this.#dispatchEvent(\"poked\", result.event);\n break;\n case \"startUpload\":\n this.#ftTrack.notify(result.info.clientFileTransferID, result.info);\n break;\n case \"startDownload\":\n this.#ftTrack.notify(result.info.clientFileTransferID, result.info);\n break;\n case \"fileTransferStatus\":\n this.#ftTrack.notify(result.info.clientFileTransferID, result.info);\n break;\n }\n }\n\n #dispatchEvent<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n this.#finalEvtHandler(payload as EventMap[keyof EventMap]);\n }\n\n #dispatchEventDirect<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n switch (event) {\n case \"textMessage\":\n for (const h of this.#textMsgHandlers)\n setImmediate(() => h(payload as import(\"./types.js\").TextMessage));\n break;\n case \"clientEnter\":\n for (const h of this.#clientEnterHandlers) setImmediate(() => h(payload as ClientInfo));\n break;\n case \"clientLeave\":\n for (const h of this.#clientLeaveHandlers)\n setImmediate(() => h(payload as import(\"./types.js\").ClientLeftViewEvent));\n break;\n case \"clientMoved\":\n for (const h of this.#clientMoveHandlers)\n setImmediate(() => h(payload as import(\"./types.js\").ClientMovedEvent));\n break;\n case \"poked\":\n for (const h of this.#pokedHandlers)\n setImmediate(() => h(payload as import(\"./types.js\").PokeEvent));\n break;\n }\n }\n\n #handleConnectionClosed(err: Error | null): void {\n if (this.#status === ClientStatus.Disconnected) return;\n this.#status = ClientStatus.Disconnected;\n const handlers = this.#disconnectedHandlers.slice();\n for (const h of handlers) setImmediate(() => h(err ?? undefined));\n }\n\n #buildCmdHandler(): (cmd: string) => Promise<void> {\n const base = async (cmd: string): Promise<void> => {\n this.handler.sendPacket(PacketType.Command, Buffer.from(cmd), 0);\n };\n return buildCommandChain(this.#cmdMiddlewares, base);\n }\n\n #buildEvtHandler(): (evt: EventMap[keyof EventMap]) => void {\n const base = (evt: EventMap[keyof EventMap]): void => {\n // Determine which event type this is by checking the shape\n if (\n evt !== null &&\n evt !== undefined &&\n typeof evt === \"object\" &&\n \"invokerName\" in evt &&\n \"message\" in evt &&\n \"targetMode\" in evt\n ) {\n this.#dispatchEventDirect(\"textMessage\", evt as EventMap[\"textMessage\"]);\n } else if (\n evt !== null &&\n evt !== undefined &&\n typeof evt === \"object\" &&\n \"invokerName\" in evt &&\n \"message\" in evt &&\n !(\"targetMode\" in evt)\n ) {\n this.#dispatchEventDirect(\"poked\", evt as EventMap[\"poked\"]);\n } else if (\n evt !== null &&\n evt !== undefined &&\n typeof evt === \"object\" &&\n \"id\" in evt &&\n \"uid\" in evt\n ) {\n this.#dispatchEventDirect(\"clientEnter\", evt as EventMap[\"clientEnter\"]);\n } else if (\n evt !== null &&\n evt !== undefined &&\n typeof evt === \"object\" &&\n \"id\" in evt &&\n \"reasonID\" in evt &&\n \"targetChannelID\" in evt\n ) {\n this.#dispatchEventDirect(\"clientMoved\", evt as EventMap[\"clientMoved\"]);\n } else if (\n evt !== null &&\n evt !== undefined &&\n typeof evt === \"object\" &&\n \"id\" in evt &&\n \"reasonID\" in evt\n ) {\n this.#dispatchEventDirect(\"clientLeave\", evt as EventMap[\"clientLeave\"]);\n }\n };\n return buildEventChain(this.#eventMiddlewares, base);\n }\n}\n","import { buildCommandOrdered, buildCommand, unescape } from \"./command/command.js\";\nimport type { ChannelInfo, ClientInfo } from \"./types.js\";\nimport type { Client } from \"./client.js\";\n\n/** Send a text message to a client (targetMode=1), channel (2), or server (3). */\nexport async function sendTextMessage(\n client: Client,\n targetMode: number,\n targetID: bigint,\n message: string,\n): Promise<void> {\n const cmd = buildCommandOrdered(\"sendtextmessage\", [\n [\"targetmode\", String(targetMode)],\n [\"target\", String(targetID)],\n [\"msg\", message],\n ]);\n await client.sendCommandNoWait(cmd);\n}\n\n/** Move a client to a different channel. */\nexport async function clientMove(\n client: Client,\n clid: number,\n channelID: bigint,\n password = \"\",\n): Promise<void> {\n const params: Array<readonly [string, string]> = [\n [\"clid\", String(clid)],\n [\"cid\", String(channelID)],\n ];\n if (password) params.push([\"cpw\", password]);\n const cmd = buildCommandOrdered(\"clientmove\", params);\n await client.execCommand(cmd, 10_000);\n}\n\n/** Send a poke message to a client. */\nexport async function poke(client: Client, clid: number, message: string): Promise<void> {\n const cmd = buildCommandOrdered(\"clientpoke\", [\n [\"clid\", String(clid)],\n [\"msg\", message],\n ]);\n await client.execCommand(cmd, 10_000);\n}\n\n/** Fetch raw clientinfo for a given clid. */\nexport async function getClientInfo(client: Client, clid: number): Promise<Record<string, string>> {\n const data = await client.execCommandWithResponse(`clientinfo clid=${clid}`, 5_000);\n const row = data[0];\n if (!row) throw new Error(`no data returned for client ${clid}`);\n return row;\n}\n\n/** List all channels on the server. */\nexport async function listChannels(client: Client): Promise<ChannelInfo[]> {\n const data = await client.execCommandWithResponse(\"channellist\", 5_000);\n return data.map((item) => ({\n id: BigInt(item[\"cid\"] ?? \"0\"),\n parentID: BigInt(item[\"pid\"] ?? \"0\"),\n name: unescape(item[\"channel_name\"] ?? \"\"),\n description: \"\",\n }));\n}\n\n/** List all clients currently connected to the server. */\nexport async function listClients(client: Client): Promise<ClientInfo[]> {\n const data = await client.execCommandWithResponse(\"clientlist -uid -away -voice -groups\", 5_000);\n return data.map((item) => {\n const groupsStr = item[\"client_servergroups\"] ?? \"\";\n return {\n id: parseInt(item[\"clid\"] ?? \"0\", 10),\n nickname: unescape(item[\"client_nickname\"] ?? \"\"),\n uid: item[\"client_unique_identifier\"] ?? \"\",\n channelID: BigInt(item[\"cid\"] ?? \"0\"),\n type: parseInt(item[\"client_type\"] ?? \"0\", 10),\n serverGroups: groupsStr ? groupsStr.split(\",\") : [],\n };\n });\n}\n\n/** Delete a file on the server. */\nexport async function fileTransferDeleteFile(\n client: Client,\n channelID: bigint,\n paths: string[],\n): Promise<void> {\n if (paths.length === 0) return;\n const pathStr = paths.join(\"|\");\n const cmd = buildCommand(\"ftdeletefile\", {\n cid: String(channelID),\n cpw: \"\",\n name: pathStr,\n });\n await client.execCommand(cmd, 10_000);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["#pending","#nextRC","#welcomeComplete","#buffer","#pending","#nextID","#lastUpdate","#tokens","#identity","#addr","#resolver","#clientInitOptions","#handlePacket","#handleConnectionClosed","#cmdMiddlewares","#eventMiddlewares","#finalCmdHandler","#buildCmdHandler","#finalEvtHandler","#buildEvtHandler","#status","#resetForConnect","#resolveAddr","#disconnectedHandlers","#connectedResolvers","#throttle","#cmdTrack","#textMsgHandlers","#clientEnterHandlers","#clientLeaveHandlers","#clientMoveHandlers","#pokedHandlers","#voiceDataHandlers","#connectedHandlers","#kickedHandlers","#clients","#ftTrack","#handlePacketSync","#handleVoicePacket","#handleCommandLines","#handleCommandStr","#processNotificationResult","#handleError","#dispatchEvent","#dispatchEventDirect"],"sources":["../src/commands.ts","../src/transfer.ts","../src/events.ts","../src/handshake.ts","../src/helpers.ts","../src/notifications.ts","../src/throttle.ts","../src/client.ts","../src/api.ts"],"sourcesContent":["import { ServerError } from \"./errors.js\";\n\nexport interface CommandResult {\n err: Error | null;\n data: Record<string, string>[];\n}\n\n/**\n * Tracks in-flight commands by return_code.\n *\n * The TS3/TS5 server sends a \"welcome sequence\" of unsolicited data immediately\n * after the connection handshake (channellist, channelclientlist, etc.). This\n * data arrives on the event loop AFTER we may have registered our first pending\n * RC, which would contaminate our command responses.\n *\n * Solution: gate all row buffering on a `#welcomeComplete` flag. The flag is\n * set when `notifycliententerview` for our own clid arrives — the last event\n * the TS3/TS5 server sends in its welcome sequence. Any data arriving before\n * that is silently discarded.\n */\nexport class CommandTracker {\n readonly #pending = new Map<number, (result: CommandResult) => void>();\n #nextRC = 0;\n #buffer: Record<string, string>[] = [];\n\n /**\n * Set to true when we receive `notifycliententerview` for our own clid,\n * which marks the end of the server's welcome sequence.\n */\n #welcomeComplete = false;\n\n register(): [rc: number, promise: Promise<CommandResult>] {\n this.#nextRC++;\n const rc = this.#nextRC;\n const promise = new Promise<CommandResult>((resolve) => {\n this.#pending.set(rc, resolve);\n });\n return [rc, promise];\n }\n\n unregister(rc: number): void {\n this.#pending.delete(rc);\n }\n\n /**\n * Called when `notifycliententerview` for our own clid arrives.\n * Marks the welcome sequence as complete and discards any accumulated data.\n */\n signalWelcomeComplete(): void {\n this.#welcomeComplete = true;\n this.#buffer = [];\n }\n\n /**\n * Buffer a data row from the server. Rows arriving before the welcome\n * sequence is complete are silently discarded to prevent contamination.\n */\n buffer(params: Record<string, string>): void {\n if (!this.#welcomeComplete) return;\n if (this.#pending.size === 0) return;\n this.#buffer.push(params);\n }\n\n resolve(rc: number, err: Error | null): void {\n const resolve = this.#pending.get(rc);\n if (!resolve) {\n this.#buffer = [];\n return;\n }\n const data = this.#buffer;\n this.#buffer = [];\n this.#pending.delete(rc);\n resolve({ err, data });\n }\n\n discardBuffer(): void {\n this.#buffer = [];\n }\n\n reset(): void {\n this.#pending.clear();\n this.#buffer = [];\n this.#welcomeComplete = false;\n this.#nextRC = 0;\n }\n}\n\n/**\n * Parse and handle an `error` command from the server.\n * Returns the error (or null on success) and the resolved return_code.\n */\nexport function parseServerError(params: Record<string, string>): {\n err: Error | null;\n rc: number | null;\n} {\n const id = params[\"id\"] ?? \"0\";\n const msg = params[\"msg\"] ?? \"\";\n const rcStr = params[\"return_code\"];\n\n let err: Error | null = null;\n if (id !== \"0\") {\n err = new ServerError(id, msg);\n }\n\n let rc: number | null = null;\n if (rcStr !== undefined && rcStr !== \"\") {\n const parsed = parseInt(rcStr, 10);\n if (!isNaN(parsed)) rc = parsed;\n }\n\n return { err, rc };\n}\n\n/**\n * Append a return_code parameter to a command string if not already present.\n */\nexport function appendReturnCode(cmd: string, rc: number): string {\n if (cmd.includes(\"return_code=\")) return cmd;\n return `${cmd} return_code=${rc}`;\n}\n","import { createConnection } from \"node:net\";\nimport type { Readable, Writable } from \"node:stream\";\nimport type { FileUploadInfo, FileDownloadInfo } from \"./types.js\";\nimport { FileTransferError, FileTransferTimeoutError } from \"./errors.js\";\nimport { buildCommand } from \"./command/command.js\";\n\nexport interface FileTransferTracker {\n register(): [\n cftid: number,\n promise: Promise<\n FileUploadInfo | FileDownloadInfo | import(\"./types.js\").FileTransferStatusInfo\n >,\n ];\n unregister(cftid: number): void;\n notify(\n cftid: number,\n value: FileUploadInfo | FileDownloadInfo | import(\"./types.js\").FileTransferStatusInfo,\n ): void;\n reset(): void;\n}\n\ntype FtNotification =\n | FileUploadInfo\n | FileDownloadInfo\n | import(\"./types.js\").FileTransferStatusInfo;\n\nexport class FileTransferTracker {\n readonly #pending = new Map<number, (v: FtNotification) => void>();\n #nextID = 0;\n\n register(): [cftid: number, promise: Promise<FtNotification>] {\n this.#nextID++;\n if (this.#nextID > 65535) this.#nextID = 1;\n const cftid = this.#nextID;\n const promise = new Promise<FtNotification>((resolve) => {\n this.#pending.set(cftid, resolve);\n });\n return [cftid, promise];\n }\n\n unregister(cftid: number): void {\n this.#pending.delete(cftid);\n }\n\n notify(cftid: number, value: FtNotification): void {\n const resolve = this.#pending.get(cftid);\n if (resolve) resolve(value);\n }\n\n reset(): void {\n this.#pending.clear();\n this.#nextID = 0;\n }\n}\n\n/**\n * Open a TCP connection to the TS3 file transfer port and perform the\n * ftkey handshake. The caller is responsible for closing the socket.\n */\nexport function dialFileTransfer(\n host: string,\n port: number,\n key: string,\n): Promise<import(\"node:net\").Socket> {\n return new Promise((resolve, reject) => {\n const socket = createConnection({ host, port }, () => {\n socket.write(key, (err) => {\n if (err) {\n socket.destroy();\n reject(new FileTransferError(`failed to send transfer key: ${err.message}`));\n } else {\n resolve(socket);\n }\n });\n });\n socket.setTimeout(10_000);\n socket.once(\"error\", reject);\n socket.once(\"timeout\", () => {\n socket.destroy();\n reject(new FileTransferError(\"connection timeout\"));\n });\n });\n}\n\n/** Upload data via a TS3 file transfer connection. */\nexport async function uploadFileData(\n host: string,\n info: FileUploadInfo,\n data: Readable,\n): Promise<void> {\n const socket = await dialFileTransfer(host, info.port, info.fileTransferKey);\n await new Promise<void>((resolve, reject) => {\n data.pipe(socket);\n socket.on(\"finish\", resolve);\n socket.on(\"error\", reject);\n });\n}\n\n/** Download data via a TS3 file transfer connection. */\nexport async function downloadFileData(\n host: string,\n info: FileDownloadInfo,\n dest: Writable,\n): Promise<void> {\n const socket = await dialFileTransfer(host, info.port, info.fileTransferKey);\n await new Promise<void>((resolve, reject) => {\n socket.pipe(dest);\n dest.on(\"finish\", resolve);\n socket.on(\"error\", reject);\n dest.on(\"error\", reject);\n });\n}\n\n/**\n * Build a ftinitupload command string.\n */\nexport function buildFtInitUpload(\n channelID: bigint,\n path: string,\n password: string,\n size: bigint,\n cftid: number,\n overwrite: boolean,\n): string {\n const targetPath = path.startsWith(\"/\") ? path : `/${path}`;\n return buildCommand(\"ftinitupload\", {\n cid: String(channelID),\n name: targetPath,\n cpw: password,\n size: String(size),\n clientftfid: String(cftid),\n overwrite: overwrite ? \"1\" : \"0\",\n resume: \"0\",\n });\n}\n\n/**\n * Build a ftinitdownload command string.\n */\nexport function buildFtInitDownload(\n channelID: bigint,\n path: string,\n password: string,\n cftid: number,\n): string {\n const targetPath = path.startsWith(\"/\") ? path : `/${path}`;\n return buildCommand(\"ftinitdownload\", {\n cid: String(channelID),\n name: targetPath,\n cpw: password,\n clientftfid: String(cftid),\n seekpos: \"0\",\n });\n}\n\nexport { FileTransferError, FileTransferTimeoutError };\n","import type { EventMap, CommandMiddleware, EventMiddleware } from \"./types.js\";\n\ntype EventHandler<K extends keyof EventMap> = EventMap[K] extends void\n ? () => void\n : (payload: EventMap[K]) => void;\n\nexport type { EventHandler };\n\n/**\n * Compose a chain of middlewares around a base handler.\n * Rightmost middleware wraps the base first.\n */\nexport function buildCommandChain(\n middlewares: CommandMiddleware[],\n base: (cmd: string) => Promise<void>,\n): (cmd: string) => Promise<void> {\n let handler = base;\n for (let i = middlewares.length - 1; i >= 0; i--) {\n handler = middlewares[i]!(handler);\n }\n return handler;\n}\n\nexport function buildEventChain(\n middlewares: EventMiddleware[],\n base: (evt: EventMap[keyof EventMap]) => void,\n): (evt: EventMap[keyof EventMap]) => void {\n let handler = base;\n for (let i = middlewares.length - 1; i >= 0; i--) {\n handler = middlewares[i]!(handler);\n }\n return handler;\n}\n","import { createHash } from \"node:crypto\";\nimport { buildCommandOrdered, buildCommand } from \"./command/command.js\";\nimport { sign, generateTemporaryKey } from \"./crypto/primitives.js\";\nimport { cryptoInit2 } from \"./handshake/crypt-init2.js\";\nimport { PacketType } from \"./transport/packet.js\";\nimport type { Client } from \"./client.js\";\n\n/** Handle the `clientinitiv` message (P-256 based crypto path). */\nexport function handleHandshakeInitIV(client: Client, params: Record<string, string>): void {\n const alpha = params[\"alpha\"] ?? \"\";\n const beta = params[\"beta\"] ?? \"\";\n const omega = params[\"omega\"] ?? \"\";\n\n client.crypt.initCrypto(alpha, beta, omega);\n client.logger.info(\"crypto initialized (P-256 path), sending clientinit\");\n sendClientInit(client);\n}\n\n/** Handle the `initivexpand2` message (Ed25519 / TS3 crypto path). */\nexport function handleHandshakeExpand2(client: Client, params: Record<string, string>): void {\n client.logger.info(\"received initivexpand2\");\n client.handler.receivedFinalInitAck();\n\n const license = params[\"l\"] ?? \"\";\n const omega = params[\"omega\"] ?? \"\";\n const proof = params[\"proof\"] ?? \"\";\n const beta = params[\"beta\"] ?? \"\";\n\n const privateKey = sendClientEkPacket(client, beta);\n cryptoInit2(client.crypt, license, omega, proof, beta, privateKey);\n sendClientInit(client);\n}\n\n/** Handle `initserver` — marks the client as connected. */\nexport function handleInitServer(client: Client, params: Record<string, string>): void {\n const idStr = params[\"aclid\"] ?? params[\"clid\"] ?? \"\";\n const clid = idStr ? parseInt(idStr, 10) : 0;\n\n if (clid > 0) {\n client.clid = clid;\n client.handler.setClientID(clid);\n }\n\n client.logger.info(\"connected to server\", { selfId: client.clid });\n client._markConnected();\n\n // Inform the server about mute state\n setImmediate(() => {\n const updateCmd = buildCommand(\"clientupdate\", {\n client_input_muted: \"0\",\n client_output_muted: \"0\",\n });\n client.sendCommandNoWait(updateCmd).catch(() => {});\n });\n}\n\nfunction sendClientEkPacket(client: Client, beta: string): Uint8Array {\n const [publicKey, privateKey] = generateTemporaryKey();\n const ekBase64 = Buffer.from(publicKey).toString(\"base64\");\n const clientProof = buildClientEkProof(client, publicKey, beta);\n\n const clientEk = buildCommandOrdered(\"clientek\", [\n [\"ek\", ekBase64],\n [\"proof\", clientProof],\n ]);\n client.handler.sendPacket(PacketType.Command, Buffer.from(clientEk), 0);\n return privateKey;\n}\n\nfunction buildClientEkProof(client: Client, publicKey: Uint8Array, beta: string): string {\n const betaBytes = Buffer.from(beta, \"base64\");\n const toSign = new Uint8Array(86);\n toSign.set(publicKey.slice(0, 32));\n toSign.set(betaBytes.slice(0, Math.min(54, betaBytes.length)), 32);\n const sig = sign(client.crypt.identity.privateKey, toSign);\n return Buffer.from(sig).toString(\"base64\");\n}\n\nfunction prepareClientPassword(password: string): string {\n if (password === \"\") return \"\";\n // TeamSpeak expects password fields as base64(sha1(password)).\n return createHash(\"sha1\").update(password).digest().toString(\"base64\");\n}\n\nexport function sendClientInit(client: Client): void {\n const cmd = buildClientInitCommand(client);\n client.handler.sendPacket(PacketType.Command, Buffer.from(cmd), 0);\n}\n\nfunction buildClientInitCommand(client: Client): string {\n const pubKeyBase64 = client.crypt.identity.publicKeyBase64();\n const initOptions = client.getClientInitOptions();\n const defaultChannelPassword = prepareClientPassword(initOptions.defaultChannelPassword);\n const serverPassword = prepareClientPassword(initOptions.serverPassword);\n // HWID should match TS3 client UID format: base64(SHA1(publicKeyBase64))\n const hwid = createHash(\"sha1\").update(pubKeyBase64).digest().toString(\"base64\");\n\n return buildCommandOrdered(\"clientinit\", [\n [\"client_nickname\", client.nickname],\n [\"client_version\", \"3.?.? [Build: 5680278000]\"],\n [\"client_platform\", \"Windows\"],\n [\"client_input_hardware\", \"1\"],\n [\"client_output_hardware\", \"1\"],\n [\"client_default_channel\", initOptions.defaultChannel],\n [\"client_default_channel_password\", defaultChannelPassword],\n [\"client_server_password\", serverPassword],\n [\"client_meta_data\", \"\"],\n [\n \"client_version_sign\",\n \"DX5NIYLvfJEUjuIbCidnoeozxIDRRkpq3I9vVMBmE9L2qnekOoBzSenkzsg2lC9CMv8K5hkEzhr2TYUYSwUXCg==\",\n ],\n [\"client_key_offset\", String(client.crypt.identity.offset)],\n [\"client_nickname_phonetic\", \"\"],\n [\"client_default_token\", \"\"],\n [\"hwid\", hwid],\n ]);\n}\n","export function parseUint64(s: string): bigint {\n if (s === \"\" || s === undefined) return 0n;\n try {\n return BigInt(s);\n } catch {\n return 0n;\n }\n}\n\nexport function parseUint16(s: string): number {\n const v = parseInt(s, 10);\n if (isNaN(v) || v < 0 || v > 65535) return 0;\n return v;\n}\n\nexport function parseInt10(s: string): number {\n const v = parseInt(s, 10);\n return isNaN(v) ? 0 : v;\n}\n\n/**\n * Reports whether `actual` equals `expected` or equals `expected` followed by\n * only digits — the pattern TeamSpeak uses when a nickname is already taken.\n */\nexport function isAutoNicknameMatch(expected: string, actual: string): boolean {\n if (actual === expected) return true;\n if (!actual.startsWith(expected)) return false;\n const suffix = actual.slice(expected.length);\n return /^\\d+$/.test(suffix);\n}\n\n/**\n * Expand a pipe-separated multi-row TS3 command line into individual rows,\n * each prefixed with the command name.\n */\nexport function splitCommandRows(line: string): string[] {\n const spaceIdx = line.indexOf(\" \");\n if (spaceIdx < 0) return [line];\n\n const name = line.slice(0, spaceIdx);\n const rest = line.slice(spaceIdx + 1);\n\n if (!rest.includes(\"|\")) return [line];\n\n const parts = rest.split(\"|\");\n const rows: string[] = [];\n for (const part of parts) {\n if (part !== \"\") rows.push(`${name} ${part}`);\n }\n return rows.length === 0 ? [line] : rows;\n}\n","import type { Command } from \"./command/command.js\";\nimport { unescape } from \"./command/command.js\";\nimport type {\n ClientInfo,\n ClientLeftViewEvent,\n ClientMovedEvent,\n TextMessage,\n PokeEvent,\n FileUploadInfo,\n FileDownloadInfo,\n FileTransferStatusInfo,\n} from \"./types.js\";\nimport { parseUint64, parseUint16, parseInt10 } from \"./helpers.js\";\n\nexport type NotificationResult =\n | { kind: \"clientEnter\"; info: ClientInfo }\n | { kind: \"clientLeave\"; event: ClientLeftViewEvent; isSelf: boolean }\n | { kind: \"clientMoved\"; event: ClientMovedEvent }\n | { kind: \"textMessage\"; message: TextMessage }\n | { kind: \"poked\"; event: PokeEvent }\n | { kind: \"startUpload\"; info: FileUploadInfo }\n | { kind: \"startDownload\"; info: FileDownloadInfo }\n | { kind: \"fileTransferStatus\"; info: FileTransferStatusInfo }\n | { kind: \"unknown\" };\n\nexport function handleNotification(\n cmd: Command,\n selfCLID: number,\n clients: Map<number, ClientInfo>,\n nickname: string,\n): NotificationResult {\n switch (cmd.name) {\n case \"notifycliententerview\":\n return handleClientEnterView(cmd, clients, nickname);\n case \"notifyclientleftview\":\n return handleClientLeftView(cmd, selfCLID, clients);\n case \"notifyclientmoved\":\n return handleClientMoved(cmd, clients);\n case \"notifytextmessage\":\n return handleTextMessage(cmd, clients);\n case \"notifyclientpoke\":\n return handleClientPoked(cmd);\n case \"notifystartupload\":\n return { kind: \"startUpload\", info: handleStartUpload(cmd) };\n case \"notifystartdownload\":\n return { kind: \"startDownload\", info: handleStartDownload(cmd) };\n case \"notifystatusfiletransfer\":\n return { kind: \"fileTransferStatus\", info: handleFileTransferStatus(cmd) };\n default:\n return { kind: \"unknown\" };\n }\n}\n\nfunction handleClientEnterView(\n cmd: Command,\n clients: Map<number, ClientInfo>,\n nickname: string,\n): NotificationResult {\n const clid = parseUint16(cmd.params[\"clid\"] ?? \"\");\n const cid = parseUint64(cmd.params[\"cid\"] ?? \"\");\n const clientType = parseInt10(cmd.params[\"client_type\"] ?? \"\");\n const groupsStr = cmd.params[\"client_servergroups\"] ?? \"\";\n\n const info: ClientInfo = {\n id: clid,\n nickname: cmd.params[\"client_nickname\"] ?? \"\",\n uid: cmd.params[\"client_unique_identifier\"] ?? \"\",\n channelID: cid,\n type: clientType,\n serverGroups: groupsStr ? groupsStr.split(\",\") : [],\n };\n\n if (clid !== 0) {\n clients.set(clid, info);\n }\n\n return { kind: \"clientEnter\", info };\n}\n\nfunction handleClientLeftView(\n cmd: Command,\n selfCLID: number,\n clients: Map<number, ClientInfo>,\n): NotificationResult {\n const clid = parseUint16(cmd.params[\"clid\"] ?? \"\");\n const reasonID = parseInt10(cmd.params[\"reasonid\"] ?? \"\");\n\n const isSelf = clid === selfCLID;\n if (clid !== 0) clients.delete(clid);\n\n return {\n kind: \"clientLeave\",\n event: {\n id: clid,\n reasonID,\n reasonMsg: cmd.params[\"reasonmsg\"] ?? \"\",\n targetID: parseUint16(cmd.params[\"targetid\"] ?? \"\"),\n },\n isSelf,\n };\n}\n\nfunction handleClientMoved(cmd: Command, clients: Map<number, ClientInfo>): NotificationResult {\n const clid = parseUint16(cmd.params[\"clid\"] ?? \"\");\n const ctid = parseUint64(cmd.params[\"ctid\"] ?? \"\");\n\n if (clid !== 0) {\n const existing = clients.get(clid);\n if (existing) clients.set(clid, { ...existing, channelID: ctid });\n }\n\n return {\n kind: \"clientMoved\",\n event: {\n id: clid,\n targetChannelID: ctid,\n reasonID: parseInt10(cmd.params[\"reasonid\"] ?? \"\"),\n invokerID: parseUint16(cmd.params[\"invokerid\"] ?? \"\"),\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: cmd.params[\"invokeruid\"] ?? \"\",\n },\n };\n}\n\nfunction handleTextMessage(cmd: Command, clients: Map<number, ClientInfo>): NotificationResult {\n const invokerID = parseUint16(cmd.params[\"invokerid\"] ?? \"\");\n const invokerInfo = clients.get(invokerID);\n\n const message: TextMessage = {\n targetMode: parseInt10(cmd.params[\"targetmode\"] ?? \"\"),\n targetID: parseUint64(cmd.params[\"target\"] ?? \"\"),\n invokerID,\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: cmd.params[\"invokeruid\"] ?? invokerInfo?.uid ?? \"\",\n message: unescape(cmd.params[\"msg\"] ?? \"\"),\n invokerGroups: invokerInfo?.serverGroups ?? [],\n };\n\n return { kind: \"textMessage\", message };\n}\n\nfunction handleStartUpload(cmd: Command): FileUploadInfo {\n return {\n clientFileTransferID: parseUint16(cmd.params[\"clientftfid\"] ?? \"\"),\n serverFileTransferID: parseUint16(cmd.params[\"serverftfid\"] ?? \"\"),\n fileTransferKey: cmd.params[\"ftkey\"] ?? \"\",\n port: parseUint16(cmd.params[\"port\"] ?? \"\"),\n seekPosition: parseUint64(cmd.params[\"seekpos\"] ?? \"\"),\n };\n}\n\nfunction handleStartDownload(cmd: Command): FileDownloadInfo {\n return {\n clientFileTransferID: parseUint16(cmd.params[\"clientftfid\"] ?? \"\"),\n serverFileTransferID: parseUint16(cmd.params[\"serverftfid\"] ?? \"\"),\n fileTransferKey: cmd.params[\"ftkey\"] ?? \"\",\n port: parseUint16(cmd.params[\"port\"] ?? \"\"),\n size: parseUint64(cmd.params[\"size\"] ?? \"\"),\n };\n}\n\nfunction handleFileTransferStatus(cmd: Command): FileTransferStatusInfo {\n return {\n clientFileTransferID: parseUint16(cmd.params[\"clientftfid\"] ?? \"\"),\n status: parseInt10(cmd.params[\"status\"] ?? \"\"),\n message: cmd.params[\"msg\"] ?? \"\",\n };\n}\n\nfunction handleClientPoked(cmd: Command): NotificationResult {\n return {\n kind: \"poked\",\n event: {\n invokerID: parseUint16(cmd.params[\"invokerid\"] ?? \"\"),\n invokerName: unescape(cmd.params[\"invokername\"] ?? \"\"),\n invokerUID: cmd.params[\"invokeruid\"] ?? \"\",\n message: unescape(cmd.params[\"msg\"] ?? \"\"),\n },\n };\n}\n","/**\n * Token-bucket limiter for outbound TS3 commands.\n * Mirrors Go's commandThrottle.\n */\nexport class CommandThrottle {\n static readonly TOKEN_RATE = 4.0; // tokens per second\n static readonly TOKEN_MAX = 8.0; // bucket capacity\n\n #tokens = 5.0;\n #lastUpdate = Date.now();\n\n async wait(signal?: AbortSignal): Promise<void> {\n while (true) {\n if (signal?.aborted) throw signal.reason as Error;\n\n const now = Date.now();\n const elapsed = (now - this.#lastUpdate) / 1000;\n this.#tokens = Math.min(\n this.#tokens + elapsed * CommandThrottle.TOKEN_RATE,\n CommandThrottle.TOKEN_MAX,\n );\n this.#lastUpdate = now;\n\n if (this.#tokens >= 1.0) {\n this.#tokens -= 1.0;\n return;\n }\n\n const waitMs = Math.ceil(((1.0 - this.#tokens) / CommandThrottle.TOKEN_RATE) * 1000) + 10;\n\n await new Promise<void>((resolve, reject) => {\n const timer = setTimeout(resolve, waitMs);\n if (signal) {\n signal.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n reject(signal.reason as Error);\n },\n { once: true },\n );\n }\n });\n }\n }\n}\n","import {\n type EventMap,\n type ClientOptions,\n type CommandMiddleware,\n type EventMiddleware,\n type Logger,\n type AddrResolver,\n type ClientInfo,\n ClientStatus,\n consoleLogger,\n} from \"./types.js\";\nimport { AlreadyConnectedError } from \"./errors.js\";\nimport { Identity, Crypt } from \"./crypto/index.js\";\nimport { Resolver } from \"./discovery/resolver.js\";\nimport { PacketHandler } from \"./transport/handler.js\";\nimport { PacketType } from \"./transport/packet.js\";\nimport type { Packet } from \"./transport/packet.js\";\nimport { CommandTracker, appendReturnCode, parseServerError } from \"./commands.js\";\nimport {\n FileTransferTracker,\n buildFtInitUpload,\n buildFtInitDownload,\n dialFileTransfer,\n uploadFileData,\n downloadFileData,\n} from \"./transfer.js\";\nimport { buildCommandChain, buildEventChain } from \"./events.js\";\nimport { processInit1 } from \"./handshake/crypt-handshake.js\";\nimport { handleHandshakeInitIV, handleHandshakeExpand2, handleInitServer } from \"./handshake.js\";\nimport { handleNotification } from \"./notifications.js\";\nimport { parseCommand } from \"./command/parser.js\";\nimport { CommandThrottle } from \"./throttle.js\";\nimport { splitCommandRows, isAutoNicknameMatch } from \"./helpers.js\";\nimport type { FileUploadInfo, FileDownloadInfo } from \"./types.js\";\nimport { CommandTimeoutError, FileTransferTimeoutError, FileTransferError } from \"./errors.js\";\nimport type { Readable, Writable } from \"node:stream\";\n\nexport { ClientStatus };\n\nexport interface ClientState {\n status: ClientStatus;\n clid: number;\n}\n\ninterface ClientInitOptions {\n readonly serverPassword: string;\n readonly defaultChannel: string;\n readonly defaultChannelPassword: string;\n}\n\nfunction normalizeClientInitOptions(options: ClientOptions): ClientInitOptions {\n return {\n serverPassword: options.serverPassword ?? \"\",\n defaultChannel: options.defaultChannel ?? \"\",\n defaultChannelPassword: options.defaultChannelPassword ?? \"\",\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyHandler = (arg: any) => void;\n\nexport class Client {\n // Internal — accessible from handshake.ts helpers\n /** @internal */ crypt: Crypt;\n /** @internal */ handler: PacketHandler;\n /** @internal */ logger: Logger;\n /** @internal */ nickname: string;\n /** @internal */ clid = 0;\n\n #identity: Identity;\n #addr: string;\n #resolver: AddrResolver;\n #clientInitOptions: ClientInitOptions;\n #status: ClientStatus = ClientStatus.Disconnected;\n #throttle = new CommandThrottle();\n #cmdTrack = new CommandTracker();\n #ftTrack = new FileTransferTracker();\n #clients = new Map<number, ClientInfo>();\n #connectedResolvers: Array<() => void> = [];\n\n // Event handler lists\n #textMsgHandlers: Array<(msg: import(\"./types.js\").TextMessage) => void> = [];\n #clientEnterHandlers: Array<(info: ClientInfo) => void> = [];\n #clientLeaveHandlers: Array<(evt: import(\"./types.js\").ClientLeftViewEvent) => void> = [];\n #clientMoveHandlers: Array<(evt: import(\"./types.js\").ClientMovedEvent) => void> = [];\n #pokedHandlers: Array<(evt: import(\"./types.js\").PokeEvent) => void> = [];\n #voiceDataHandlers: Array<(data: import(\"./types.js\").VoiceData) => void> = [];\n #connectedHandlers: Array<() => void> = [];\n #disconnectedHandlers: Array<(err: Error | undefined) => void> = [];\n #kickedHandlers: Array<(msg: string) => void> = [];\n\n // Middleware\n #cmdMiddlewares: CommandMiddleware[] = [];\n #eventMiddlewares: EventMiddleware[] = [];\n #finalCmdHandler: (cmd: string) => Promise<void>;\n #finalEvtHandler: (evt: EventMap[keyof EventMap]) => void;\n\n constructor(identity: Identity, addr: string, nickname: string, options: ClientOptions = {}) {\n this.#identity = identity;\n this.#addr = addr;\n this.nickname = nickname;\n this.logger = options.logger ?? consoleLogger;\n this.#resolver = options.resolver ?? new Resolver(this.logger);\n this.#clientInitOptions = normalizeClientInitOptions(options);\n\n this.crypt = new Crypt(identity);\n this.handler = new PacketHandler(this.crypt, this.logger);\n this.handler.onPacket = (p) => this.#handlePacket(p);\n this.handler.onClosed = (err) => this.#handleConnectionClosed(err);\n\n if (options.commandMiddleware) {\n this.#cmdMiddlewares.push(...options.commandMiddleware);\n }\n if (options.eventMiddleware) {\n this.#eventMiddlewares.push(...options.eventMiddleware);\n }\n\n this.#finalCmdHandler = this.#buildCmdHandler();\n this.#finalEvtHandler = this.#buildEvtHandler();\n }\n\n get status(): ClientStatus {\n return this.#status;\n }\n\n /** @internal */\n getClientInitOptions(): Readonly<{\n serverPassword: string;\n defaultChannel: string;\n defaultChannelPassword: string;\n }> {\n return this.#clientInitOptions;\n }\n\n // ---- Connection -----------------------------------------------------------\n\n async connect(): Promise<void> {\n if (this.#status !== ClientStatus.Disconnected) {\n throw new AlreadyConnectedError();\n }\n\n this.#resetForConnect();\n this.#status = ClientStatus.Connecting;\n\n const targetAddr = await this.#resolveAddr();\n this.logger.info(\"connecting to server\", { address: targetAddr });\n await this.handler.connect(targetAddr);\n }\n\n async disconnect(): Promise<void> {\n if (this.#status === ClientStatus.Disconnected) return;\n\n const wasConnected = this.#status === ClientStatus.Connected;\n this.#status = ClientStatus.Disconnected;\n\n this.logger.info(\"disconnecting from server\");\n\n if (wasConnected) {\n try {\n await this.execCommand(\"clientdisconnect reasonmsg=Shutdown\", 1000);\n } catch {\n // best-effort\n }\n }\n\n this.handler.close();\n const handlers = this.#disconnectedHandlers.slice();\n for (const h of handlers) setImmediate(() => h(undefined));\n }\n\n waitConnected(signal?: AbortSignal): Promise<void> {\n if (this.#status === ClientStatus.Connected) return Promise.resolve();\n return new Promise<void>((resolve, reject) => {\n this.#connectedResolvers.push(resolve);\n if (signal) {\n signal.addEventListener(\"abort\", () => reject(signal.reason as Error), { once: true });\n }\n });\n }\n\n // ---- Commands ------------------------------------------------------------\n\n async sendCommandNoWait(cmd: string): Promise<void> {\n await this.#throttle.wait();\n await this.#finalCmdHandler(cmd);\n }\n\n async execCommand(cmd: string, timeoutMs = 10_000): Promise<void> {\n await this.execCommandWithResponse(cmd, timeoutMs);\n }\n\n async execCommandWithResponse(\n cmd: string,\n timeoutMs = 10_000,\n ): Promise<Record<string, string>[]> {\n const [rc, promise] = this.#cmdTrack.register();\n const withRc = appendReturnCode(cmd, rc);\n\n try {\n await this.#throttle.wait();\n await this.#finalCmdHandler(withRc);\n } catch (err) {\n this.#cmdTrack.unregister(rc);\n throw err;\n }\n\n const result = await Promise.race([\n promise,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new CommandTimeoutError(cmd)), timeoutMs),\n ),\n ]);\n\n this.#cmdTrack.unregister(rc);\n\n if (result.err) throw result.err;\n return result.data;\n }\n\n // ---- Events --------------------------------------------------------------\n\n on<K extends keyof EventMap>(\n event: K,\n handler: EventMap[K] extends void ? () => void : (payload: EventMap[K]) => void,\n ): this {\n switch (event) {\n case \"textMessage\":\n this.#textMsgHandlers.push(handler as AnyHandler);\n break;\n case \"clientEnter\":\n this.#clientEnterHandlers.push(handler as AnyHandler);\n break;\n case \"clientLeave\":\n this.#clientLeaveHandlers.push(handler as AnyHandler);\n break;\n case \"clientMoved\":\n this.#clientMoveHandlers.push(handler as AnyHandler);\n break;\n case \"poked\":\n this.#pokedHandlers.push(handler as AnyHandler);\n break;\n case \"voiceData\":\n this.#voiceDataHandlers.push(handler as AnyHandler);\n break;\n case \"connected\":\n this.#connectedHandlers.push(handler as () => void);\n break;\n case \"disconnected\":\n this.#disconnectedHandlers.push(handler as AnyHandler);\n break;\n case \"kicked\":\n this.#kickedHandlers.push(handler as AnyHandler);\n break;\n }\n return this;\n }\n\n useCommandMiddleware(...mw: CommandMiddleware[]): this {\n this.#cmdMiddlewares.push(...mw);\n this.#finalCmdHandler = this.#buildCmdHandler();\n return this;\n }\n\n useEventMiddleware(...mw: EventMiddleware[]): this {\n this.#eventMiddlewares.push(...mw);\n this.#finalEvtHandler = this.#buildEvtHandler();\n return this;\n }\n\n // ---- API shorthand -------------------------------------------------------\n\n clientID(): number {\n return this.clid;\n }\n\n channelID(): bigint {\n const info = this.#clients.get(this.clid);\n return info?.channelID ?? 0n;\n }\n\n sendVoice(data: Uint8Array, codec: number): void {\n this.handler.sendVoicePacket(data, codec);\n }\n\n // ---- File Transfer -------------------------------------------------------\n\n async fileTransferInitUpload(\n channelID: bigint,\n path: string,\n password: string,\n size: bigint,\n overwrite = false,\n ): Promise<FileUploadInfo> {\n const [cftid, ftPromise] = this.#ftTrack.register();\n const cmd = buildFtInitUpload(channelID, path, password, size, cftid, overwrite);\n\n try {\n await this.execCommand(cmd, 10_000);\n } catch (err) {\n this.#ftTrack.unregister(cftid);\n throw err;\n }\n\n const result = await Promise.race([\n ftPromise,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new FileTransferTimeoutError()), 10_000),\n ),\n ]);\n this.#ftTrack.unregister(cftid);\n\n if (\"size\" in result) throw new FileTransferError(\"unexpected download response\");\n if (\"status\" in result) {\n const st = result as import(\"./types.js\").FileTransferStatusInfo;\n throw new FileTransferError(`${st.message} (status=${st.status})`);\n }\n return result as FileUploadInfo;\n }\n\n async fileTransferInitDownload(\n channelID: bigint,\n path: string,\n password: string,\n ): Promise<FileDownloadInfo> {\n const [cftid, ftPromise] = this.#ftTrack.register();\n const cmd = buildFtInitDownload(channelID, path, password, cftid);\n\n try {\n await this.execCommand(cmd, 10_000);\n } catch (err) {\n this.#ftTrack.unregister(cftid);\n throw err;\n }\n\n const result = await Promise.race([\n ftPromise,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new FileTransferTimeoutError()), 10_000),\n ),\n ]);\n this.#ftTrack.unregister(cftid);\n\n if (\"seekPosition\" in result) throw new FileTransferError(\"unexpected upload response\");\n if (\"status\" in result) {\n const st = result as import(\"./types.js\").FileTransferStatusInfo;\n throw new FileTransferError(`${st.message} (status=${st.status})`);\n }\n return result as FileDownloadInfo;\n }\n\n uploadFileData(host: string, info: FileUploadInfo, data: Readable): Promise<void> {\n return uploadFileData(host, info, data);\n }\n\n downloadFileData(host: string, info: FileDownloadInfo, dest: Writable): Promise<void> {\n return downloadFileData(host, info, dest);\n }\n\n // ---- Internal (package-visible) ------------------------------------------\n\n /** @internal */\n _markConnected(): void {\n this.#status = ClientStatus.Connected;\n for (const resolve of this.#connectedResolvers) resolve();\n this.#connectedResolvers = [];\n const handlers = this.#connectedHandlers.slice();\n for (const h of handlers) setImmediate(() => h());\n }\n\n // ---- Private -------------------------------------------------------------\n\n #resetForConnect(): void {\n this.handler.close();\n this.crypt = new Crypt(this.#identity);\n this.handler = new PacketHandler(this.crypt, this.logger);\n this.handler.onPacket = (p) => this.#handlePacket(p);\n this.handler.onClosed = (err) => this.#handleConnectionClosed(err);\n this.#cmdTrack.reset();\n this.#ftTrack.reset();\n this.#clients.clear();\n this.clid = 0;\n this.#finalCmdHandler = this.#buildCmdHandler();\n }\n\n async #resolveAddr(): Promise<string> {\n const addrWithPort = this.#addr.includes(\":\") ? this.#addr : `${this.#addr}:9987`;\n try {\n const resolved = await this.#resolver.resolve(this.#addr);\n return resolved[0]?.addr ?? addrWithPort;\n } catch {\n return addrWithPort;\n }\n }\n\n #handlePacket(p: Packet): void {\n this.#handlePacketSync(p);\n }\n\n #handlePacketSync(p: Packet): void {\n const pType = p.typeFlagged & 0x0f;\n if (pType === 8 /* Init1 */) {\n const response = processInit1(this.crypt, p.data);\n if (response) {\n this.handler.sendPacket(PacketType.Init1, response, 0);\n }\n return;\n }\n\n if ((pType === 0 /* Voice */ || pType === 1) /* VoiceWhisper */ && p.data.length > 5) {\n this.#handleVoicePacket(p.data);\n return;\n }\n\n if ((pType === 2 /* Command */ || pType === 3) /* CommandLow */ && p.data.length > 0) {\n this.#handleCommandLines(Buffer.from(p.data).toString(\"utf8\"));\n }\n }\n\n /**\n * Parse an incoming S2C voice packet.\n * Format: [VId: u16] [CId: u16] [Codec: u8] [Data: var]\n */\n #handleVoicePacket(payload: Uint8Array): void {\n if (this.#voiceDataHandlers.length === 0) return;\n\n const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);\n const clientId = view.getUint16(2, false);\n if (clientId === this.clid) return;\n\n const codec = payload[4]!;\n const data = payload.subarray(5);\n\n const voiceData: import(\"./types.js\").VoiceData = { clientId, codec, data };\n for (const h of this.#voiceDataHandlers) setImmediate(() => h(voiceData));\n }\n\n #handleCommandLines(s: string): void {\n if (!s) return;\n const lines = s.split(/[\\n\\0]/);\n for (const line of lines) {\n const trimmed = line.replace(/\\r$/, \"\");\n if (!trimmed) continue;\n for (const row of splitCommandRows(trimmed)) {\n this.#handleCommandStr(row);\n }\n }\n }\n\n #handleCommandStr(s: string): void {\n const cmd = parseCommand(s);\n if (!cmd || !cmd.name) return;\n\n if (cmd.name.startsWith(\"notify\")) {\n const result = handleNotification(cmd, this.clid, this.#clients, this.nickname);\n this.#processNotificationResult(result, cmd.params);\n return;\n }\n\n switch (cmd.name) {\n case \"clientinitiv\":\n handleHandshakeInitIV(this, cmd.params);\n break;\n case \"initivexpand2\":\n handleHandshakeExpand2(this, cmd.params);\n break;\n case \"initserver\":\n handleInitServer(this, cmd.params);\n break;\n case \"error\":\n this.#handleError(cmd.params);\n break;\n default: {\n // TS5/TS6 servers send data rows without a command-name prefix.\n // In that case our parser treats the first key=value pair as the\n // \"command name\" (e.g. name=\"clid=1827\"). Reconstruct full params.\n let params = cmd.params;\n if (cmd.name.includes(\"=\")) {\n const eqIdx = cmd.name.indexOf(\"=\");\n const k = cmd.name.slice(0, eqIdx);\n const v = cmd.name.slice(eqIdx + 1);\n params = { [k]: v, ...cmd.params };\n }\n this.#cmdTrack.buffer(params);\n break;\n }\n }\n }\n\n #handleError(params: Record<string, string>): void {\n const { err, rc } = parseServerError(params);\n if (rc !== null) {\n this.#cmdTrack.resolve(rc, err);\n } else {\n // No return_code: server is acknowledging an unsolicited command\n // (welcome-sequence channellist, no-RC commands like clientupdate, etc.).\n // Discard any rows buffered since the last resolved command.\n this.#cmdTrack.discardBuffer();\n }\n\n const id = params[\"id\"] ?? \"0\";\n if (id === \"3329\") {\n setImmediate(() => this.disconnect().catch(() => {}));\n }\n }\n\n #processNotificationResult(\n result: import(\"./notifications.js\").NotificationResult,\n _params: Record<string, string>,\n ): void {\n switch (result.kind) {\n case \"clientEnter\": {\n const info = result.info;\n if (info.id !== 0 && isAutoNicknameMatch(this.nickname, info.nickname)) {\n this.clid = info.id;\n this.handler.setClientID(info.id);\n // Our own notifycliententerview is the last event in the TS3/TS5\n // welcome sequence. Signal that it's safe to buffer command responses.\n this.#cmdTrack.signalWelcomeComplete();\n }\n this.#dispatchEvent(\"clientEnter\", info);\n break;\n }\n case \"clientLeave\": {\n this.#dispatchEvent(\"clientLeave\", result.event);\n if (result.isSelf && (result.event.reasonID === 4 || result.event.reasonID === 5)) {\n const msg = result.event.reasonMsg;\n for (const h of this.#kickedHandlers) setImmediate(() => h(msg));\n }\n break;\n }\n case \"clientMoved\":\n this.#dispatchEvent(\"clientMoved\", result.event);\n break;\n case \"textMessage\":\n this.#dispatchEvent(\"textMessage\", result.message);\n break;\n case \"poked\":\n this.#dispatchEvent(\"poked\", result.event);\n break;\n case \"startUpload\":\n this.#ftTrack.notify(result.info.clientFileTransferID, result.info);\n break;\n case \"startDownload\":\n this.#ftTrack.notify(result.info.clientFileTransferID, result.info);\n break;\n case \"fileTransferStatus\":\n this.#ftTrack.notify(result.info.clientFileTransferID, result.info);\n break;\n }\n }\n\n #dispatchEvent<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n this.#finalEvtHandler(payload as EventMap[keyof EventMap]);\n }\n\n #dispatchEventDirect<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n switch (event) {\n case \"textMessage\":\n for (const h of this.#textMsgHandlers)\n setImmediate(() => h(payload as import(\"./types.js\").TextMessage));\n break;\n case \"clientEnter\":\n for (const h of this.#clientEnterHandlers) setImmediate(() => h(payload as ClientInfo));\n break;\n case \"clientLeave\":\n for (const h of this.#clientLeaveHandlers)\n setImmediate(() => h(payload as import(\"./types.js\").ClientLeftViewEvent));\n break;\n case \"clientMoved\":\n for (const h of this.#clientMoveHandlers)\n setImmediate(() => h(payload as import(\"./types.js\").ClientMovedEvent));\n break;\n case \"poked\":\n for (const h of this.#pokedHandlers)\n setImmediate(() => h(payload as import(\"./types.js\").PokeEvent));\n break;\n }\n }\n\n #handleConnectionClosed(err: Error | null): void {\n if (this.#status === ClientStatus.Disconnected) return;\n this.#status = ClientStatus.Disconnected;\n const handlers = this.#disconnectedHandlers.slice();\n for (const h of handlers) setImmediate(() => h(err ?? undefined));\n }\n\n #buildCmdHandler(): (cmd: string) => Promise<void> {\n const base = async (cmd: string): Promise<void> => {\n this.handler.sendPacket(PacketType.Command, Buffer.from(cmd), 0);\n };\n return buildCommandChain(this.#cmdMiddlewares, base);\n }\n\n #buildEvtHandler(): (evt: EventMap[keyof EventMap]) => void {\n const base = (evt: EventMap[keyof EventMap]): void => {\n // Determine which event type this is by checking the shape\n if (\n evt !== null &&\n evt !== undefined &&\n typeof evt === \"object\" &&\n \"invokerName\" in evt &&\n \"message\" in evt &&\n \"targetMode\" in evt\n ) {\n this.#dispatchEventDirect(\"textMessage\", evt as EventMap[\"textMessage\"]);\n } else if (\n evt !== null &&\n evt !== undefined &&\n typeof evt === \"object\" &&\n \"invokerName\" in evt &&\n \"message\" in evt &&\n !(\"targetMode\" in evt)\n ) {\n this.#dispatchEventDirect(\"poked\", evt as EventMap[\"poked\"]);\n } else if (\n evt !== null &&\n evt !== undefined &&\n typeof evt === \"object\" &&\n \"id\" in evt &&\n \"uid\" in evt\n ) {\n this.#dispatchEventDirect(\"clientEnter\", evt as EventMap[\"clientEnter\"]);\n } else if (\n evt !== null &&\n evt !== undefined &&\n typeof evt === \"object\" &&\n \"id\" in evt &&\n \"reasonID\" in evt &&\n \"targetChannelID\" in evt\n ) {\n this.#dispatchEventDirect(\"clientMoved\", evt as EventMap[\"clientMoved\"]);\n } else if (\n evt !== null &&\n evt !== undefined &&\n typeof evt === \"object\" &&\n \"id\" in evt &&\n \"reasonID\" in evt\n ) {\n this.#dispatchEventDirect(\"clientLeave\", evt as EventMap[\"clientLeave\"]);\n }\n };\n return buildEventChain(this.#eventMiddlewares, base);\n }\n}\n","import { buildCommandOrdered, buildCommand, unescape } from \"./command/command.js\";\nimport type { ChannelInfo, ClientInfo } from \"./types.js\";\nimport type { Client } from \"./client.js\";\n\n/** Send a text message to a client (targetMode=1), channel (2), or server (3). */\nexport async function sendTextMessage(\n client: Client,\n targetMode: number,\n targetID: bigint,\n message: string,\n): Promise<void> {\n const cmd = buildCommandOrdered(\"sendtextmessage\", [\n [\"targetmode\", String(targetMode)],\n [\"target\", String(targetID)],\n [\"msg\", message],\n ]);\n await client.sendCommandNoWait(cmd);\n}\n\n/** Move a client to a different channel. */\nexport async function clientMove(\n client: Client,\n clid: number,\n channelID: bigint,\n password = \"\",\n): Promise<void> {\n const params: Array<readonly [string, string]> = [\n [\"clid\", String(clid)],\n [\"cid\", String(channelID)],\n ];\n if (password) params.push([\"cpw\", password]);\n const cmd = buildCommandOrdered(\"clientmove\", params);\n await client.execCommand(cmd, 10_000);\n}\n\n/** Send a poke message to a client. */\nexport async function poke(client: Client, clid: number, message: string): Promise<void> {\n const cmd = buildCommandOrdered(\"clientpoke\", [\n [\"clid\", String(clid)],\n [\"msg\", message],\n ]);\n await client.execCommand(cmd, 10_000);\n}\n\n/** Fetch raw clientinfo for a given clid. */\nexport async function getClientInfo(client: Client, clid: number): Promise<Record<string, string>> {\n const data = await client.execCommandWithResponse(`clientinfo clid=${clid}`, 5_000);\n const row = data[0];\n if (!row) throw new Error(`no data returned for client ${clid}`);\n return row;\n}\n\n/** List all channels on the server. */\nexport async function listChannels(client: Client): Promise<ChannelInfo[]> {\n const data = await client.execCommandWithResponse(\"channellist\", 5_000);\n return data.map((item) => ({\n id: BigInt(item[\"cid\"] ?? \"0\"),\n parentID: BigInt(item[\"pid\"] ?? \"0\"),\n name: unescape(item[\"channel_name\"] ?? \"\"),\n description: \"\",\n }));\n}\n\n/** List all clients currently connected to the server. */\nexport async function listClients(client: Client): Promise<ClientInfo[]> {\n const data = await client.execCommandWithResponse(\"clientlist -uid -away -voice -groups\", 5_000);\n return data.map((item) => {\n const groupsStr = item[\"client_servergroups\"] ?? \"\";\n return {\n id: parseInt(item[\"clid\"] ?? \"0\", 10),\n nickname: unescape(item[\"client_nickname\"] ?? \"\"),\n uid: item[\"client_unique_identifier\"] ?? \"\",\n channelID: BigInt(item[\"cid\"] ?? \"0\"),\n type: parseInt(item[\"client_type\"] ?? \"0\", 10),\n serverGroups: groupsStr ? groupsStr.split(\",\") : [],\n };\n });\n}\n\n/** Delete a file on the server. */\nexport async function fileTransferDeleteFile(\n client: Client,\n channelID: bigint,\n paths: string[],\n): Promise<void> {\n if (paths.length === 0) return;\n const pathStr = paths.join(\"|\");\n const cmd = buildCommand(\"ftdeletefile\", {\n cid: String(channelID),\n cpw: \"\",\n name: pathStr,\n });\n await client.execCommand(cmd, 10_000);\n}\n"],"mappings":"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"}