├── .editorconfig
├── .github
├── FUNDING.yml
├── dependabot.yml
└── workflows
│ ├── CD.yml
│ └── CI.yml
├── .gitignore
├── .npmignore
├── .vscode
├── extensions.json
├── settings.json
└── tasks.json
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── src
├── index.ts
├── node-ts.ts
└── queryStrings.ts
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 | [*]
3 | end_of_line = lf
4 | insert_final_newline = true
5 |
6 | [*.{ts,json,js}]
7 | charset = utf-8
8 |
9 | [*.{ts,js}]
10 | indent_style = space
11 | indent_size = 4
12 |
13 | [*.json]
14 | indent_style = tab
15 | tab_width = 4
16 |
17 | [package.json]
18 | indent_style = space
19 | indent_size = 2
20 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: nikeee
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "npm"
4 | directory: "/"
5 | schedule:
6 | interval: "monthly"
7 |
8 | - package-ecosystem: "github-actions"
9 | directory: "/"
10 | schedule:
11 | interval: "monthly"
12 |
--------------------------------------------------------------------------------
/.github/workflows/CD.yml:
--------------------------------------------------------------------------------
1 | name: CD
2 |
3 | on:
4 | push:
5 | branches:
6 | - "!*"
7 | tags:
8 | - "v*"
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 |
14 | permissions:
15 | contents: read
16 | id-token: write
17 |
18 | steps:
19 | - uses: actions/checkout@v4
20 |
21 | - uses: actions/setup-node@v4
22 | with:
23 | node-version: 24
24 | cache: npm
25 | registry-url: https://registry.npmjs.org
26 |
27 | - run: npm ci
28 | - run: npm run compile
29 | - run: npm test
30 | env:
31 | CI: true
32 | - run: npm publish --provenance --access public
33 | env:
34 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
35 |
--------------------------------------------------------------------------------
/.github/workflows/CI.yml:
--------------------------------------------------------------------------------
1 | name: Node.js CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | strategy:
11 | matrix:
12 | node-version: [20.x, 22.x, 24.x]
13 |
14 | steps:
15 | - uses: actions/checkout@v4
16 |
17 | - name: Use Node.js ${{ matrix.node-version }}
18 | uses: actions/setup-node@v4
19 | with:
20 | node-version: ${{ matrix.node-version }}
21 | cache: npm
22 |
23 | - run: npm ci
24 | - run: npm run compile
25 | - run: npm test
26 | env:
27 | CI: true
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # js files will only be relevant for the released npm package, so don't inclode them
2 | *.js
3 |
4 | # d.ts files can be generated, so don't include them
5 | *.d.ts
6 |
7 | # exclude VS-generated files/folders
8 | bin/
9 | obj/
10 | *.user
11 | *.js.map
12 | *.suo
13 |
14 | npm-debug.log
15 |
16 | # nodejs tools dat files
17 | *.dat
18 |
19 | # exclude node modules, they will be installed using npm
20 | node_modules/
21 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # No log files/DBs
2 | *.log
3 | *.db*
4 |
5 | *.ts
6 | !*.d.ts
7 | *.js.map
8 |
9 | # No ts files are shipped, so we don't need any config
10 | tsconfig.json
11 |
12 | # Make sure js files always get included
13 | !*.js
14 |
15 | # No CI/Editor-Specific files
16 | .editorconfig
17 | .vscode/
18 | .travis.yml
19 |
20 | # No raw ts source + tests
21 | src/
22 | tests/
23 |
24 | # License is stated/linked to in package.json
25 | LICENSE
26 | *.md
27 |
28 | .github/
29 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "EditorConfig.EditorConfig",
4 | "eg2.tslint"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "editor.formatOnSave": false,
4 | "editor.formatOnType": true
5 | }
6 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "command": "tsc",
4 | "args": [],
5 | "problemMatcher": "$tsc",
6 | "tasks": [
7 | {
8 | "label": "tsc",
9 | "type": "shell",
10 | "command": "tsc",
11 | "problemMatcher": "$tsc",
12 | "group": {
13 | "_id": "build",
14 | "isDefault": false
15 | }
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # node-ts [](https://travis-ci.com/nikeee/node-ts) [](http://badge.fury.io/js/node-ts)   
2 |
3 | This is a CommonJS module which allows you to connect to any TeamSpeak® 3 server which has the Server Query API enabled. Using the Server Query API, you can do everything a normal TeamSpeak user can do (except sending and receiving voice data) automatically via JavaScript/TypeScript (e. g. listing clients logged in on the server).
4 |
5 | The Server Query specification is available [here](http://media.teamspeak.com/ts3_literature/TeamSpeak%203%20Server%20Query%20Manual.pdf). I also created a script to import the complete query API from a TeamSpeak 3 server using the help command. This (json) dump will later be used to auto genrate some stuff. It is available as Gist [here](https://gist.github.com/nikeee/71e71439dd91999a3692).
6 |
7 | This is a fork of [gwTumm's node-teamspeak](https://github.com/gwTumm/node-teamspeak) which has been ported from JS to TS.
8 |
9 | ## Install
10 | ```bash
11 | npm install -S node-ts # install package
12 | ```
13 |
14 | ## Example Usage
15 | After registering a Server Query account using your TeamSpeak Client, you can login using node-ts (Alternatively, you can login as the root account "`ServerAdmin`" which is created during the installation of the server). The following code prints out a JSON-array containing all clients that are currently connected to the first virtual server:
16 |
17 | ```TypeScript
18 | import { TeamSpeakClient } from "node-ts";
19 | // Node.js without ES Modules:
20 | // const { TeamSpeakClient } = require("node-ts");
21 |
22 | async function main() {
23 | const client = new TeamSpeakClient("server.example.com");
24 |
25 | try {
26 | await client.connect();
27 |
28 | await client.send("use", { sid: 1 });
29 |
30 | const me = await client.send("whoami");
31 | console.log(me);
32 |
33 | // Log in to use more features
34 | await client.send("login", {
35 | client_login_name: "##USERNAME##",
36 | client_login_password: "##PASSWORD##"
37 | });
38 |
39 | const clientList = await client.send("clientlist");
40 | console.log(clientList);
41 |
42 | await client.subscribePrivateTextEvents(); // Tell the server we want to receive private text events
43 |
44 | // Register a callback for these events
45 | client.on("textmessage", data => {
46 | console.log(`Message received: ${data.msg}`);
47 | });
48 |
49 | } catch (err) {
50 | console.error("An error occurred:")
51 | console.error(err);
52 | }
53 | }
54 | main();
55 | ```
56 |
57 | ## Usage information
58 |
59 | * TeamSpeakClient.send is the main method that executes a command. An array with options and an object with parameters can be passed to the send-function. The function returns a `Promise`. See the TypeScript file for more information.
60 | * Every TeamSpeakClient instance is an `EventEmitter`. You can install listeners to the `"close"` and `"error"` event. The error-event will only be fired if there was socket-error, not if a sent command failed.
61 | * If you want to register to notifications sent by the TeamSpeak-Server, you can send a normal command `servernotifyregister` (consider specification). Any event sent by the server that starts with `"notify"` is then fired as an event (e. g. as soon as a `notifyclientmove` notification is sent by the server, the TeamSpeakClient-instance fires the `"clientmove"` event with only one parameter which is an object containing the given parameters).
62 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-ts",
3 | "version": "8.0.5",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "node-ts",
9 | "version": "8.0.5",
10 | "license": "LGPL-3.0",
11 | "dependencies": {
12 | "@rauschma/stringio": "^1.4.0",
13 | "@types/node": "^22.15.29"
14 | },
15 | "devDependencies": {
16 | "rimraf": "^6.0.1",
17 | "typescript": "^5.8.3"
18 | },
19 | "engines": {
20 | "node": ">=22.0.0"
21 | }
22 | },
23 | "node_modules/@isaacs/cliui": {
24 | "version": "8.0.2",
25 | "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
26 | "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
27 | "dev": true,
28 | "license": "ISC",
29 | "dependencies": {
30 | "string-width": "^5.1.2",
31 | "string-width-cjs": "npm:string-width@^4.2.0",
32 | "strip-ansi": "^7.0.1",
33 | "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
34 | "wrap-ansi": "^8.1.0",
35 | "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
36 | },
37 | "engines": {
38 | "node": ">=12"
39 | }
40 | },
41 | "node_modules/@rauschma/stringio": {
42 | "version": "1.4.0",
43 | "resolved": "https://registry.npmjs.org/@rauschma/stringio/-/stringio-1.4.0.tgz",
44 | "integrity": "sha512-3uor2f/MXZkmX5RJf8r+OC3WvZVzpSme0yyL0rQDPEnatE02qRcqwEwnsgpgriEck0S/n4vWtUd6tTtrJwk45Q==",
45 | "dependencies": {
46 | "@types/node": "^10.0.3"
47 | }
48 | },
49 | "node_modules/@rauschma/stringio/node_modules/@types/node": {
50 | "version": "10.17.60",
51 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
52 | "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==",
53 | "license": "MIT"
54 | },
55 | "node_modules/@types/node": {
56 | "version": "22.15.29",
57 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.29.tgz",
58 | "integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==",
59 | "license": "MIT",
60 | "dependencies": {
61 | "undici-types": "~6.21.0"
62 | }
63 | },
64 | "node_modules/ansi-regex": {
65 | "version": "6.1.0",
66 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
67 | "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
68 | "dev": true,
69 | "license": "MIT",
70 | "engines": {
71 | "node": ">=12"
72 | },
73 | "funding": {
74 | "url": "https://github.com/chalk/ansi-regex?sponsor=1"
75 | }
76 | },
77 | "node_modules/ansi-styles": {
78 | "version": "6.2.1",
79 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
80 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
81 | "dev": true,
82 | "license": "MIT",
83 | "engines": {
84 | "node": ">=12"
85 | },
86 | "funding": {
87 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
88 | }
89 | },
90 | "node_modules/balanced-match": {
91 | "version": "1.0.2",
92 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
93 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
94 | "dev": true,
95 | "license": "MIT"
96 | },
97 | "node_modules/brace-expansion": {
98 | "version": "2.0.1",
99 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
100 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
101 | "dev": true,
102 | "license": "MIT",
103 | "dependencies": {
104 | "balanced-match": "^1.0.0"
105 | }
106 | },
107 | "node_modules/color-convert": {
108 | "version": "2.0.1",
109 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
110 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
111 | "dev": true,
112 | "license": "MIT",
113 | "dependencies": {
114 | "color-name": "~1.1.4"
115 | },
116 | "engines": {
117 | "node": ">=7.0.0"
118 | }
119 | },
120 | "node_modules/color-name": {
121 | "version": "1.1.4",
122 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
123 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
124 | "dev": true,
125 | "license": "MIT"
126 | },
127 | "node_modules/cross-spawn": {
128 | "version": "7.0.6",
129 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
130 | "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
131 | "dev": true,
132 | "license": "MIT",
133 | "dependencies": {
134 | "path-key": "^3.1.0",
135 | "shebang-command": "^2.0.0",
136 | "which": "^2.0.1"
137 | },
138 | "engines": {
139 | "node": ">= 8"
140 | }
141 | },
142 | "node_modules/eastasianwidth": {
143 | "version": "0.2.0",
144 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
145 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
146 | "dev": true,
147 | "license": "MIT"
148 | },
149 | "node_modules/emoji-regex": {
150 | "version": "9.2.2",
151 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
152 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
153 | "dev": true,
154 | "license": "MIT"
155 | },
156 | "node_modules/foreground-child": {
157 | "version": "3.3.1",
158 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
159 | "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
160 | "dev": true,
161 | "license": "ISC",
162 | "dependencies": {
163 | "cross-spawn": "^7.0.6",
164 | "signal-exit": "^4.0.1"
165 | },
166 | "engines": {
167 | "node": ">=14"
168 | },
169 | "funding": {
170 | "url": "https://github.com/sponsors/isaacs"
171 | }
172 | },
173 | "node_modules/glob": {
174 | "version": "11.0.2",
175 | "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz",
176 | "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==",
177 | "dev": true,
178 | "license": "ISC",
179 | "dependencies": {
180 | "foreground-child": "^3.1.0",
181 | "jackspeak": "^4.0.1",
182 | "minimatch": "^10.0.0",
183 | "minipass": "^7.1.2",
184 | "package-json-from-dist": "^1.0.0",
185 | "path-scurry": "^2.0.0"
186 | },
187 | "bin": {
188 | "glob": "dist/esm/bin.mjs"
189 | },
190 | "engines": {
191 | "node": "20 || >=22"
192 | },
193 | "funding": {
194 | "url": "https://github.com/sponsors/isaacs"
195 | }
196 | },
197 | "node_modules/is-fullwidth-code-point": {
198 | "version": "3.0.0",
199 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
200 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
201 | "dev": true,
202 | "license": "MIT",
203 | "engines": {
204 | "node": ">=8"
205 | }
206 | },
207 | "node_modules/isexe": {
208 | "version": "2.0.0",
209 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
210 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
211 | "dev": true,
212 | "license": "ISC"
213 | },
214 | "node_modules/jackspeak": {
215 | "version": "4.1.0",
216 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz",
217 | "integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==",
218 | "dev": true,
219 | "license": "BlueOak-1.0.0",
220 | "dependencies": {
221 | "@isaacs/cliui": "^8.0.2"
222 | },
223 | "engines": {
224 | "node": "20 || >=22"
225 | },
226 | "funding": {
227 | "url": "https://github.com/sponsors/isaacs"
228 | }
229 | },
230 | "node_modules/lru-cache": {
231 | "version": "11.1.0",
232 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz",
233 | "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==",
234 | "dev": true,
235 | "license": "ISC",
236 | "engines": {
237 | "node": "20 || >=22"
238 | }
239 | },
240 | "node_modules/minimatch": {
241 | "version": "10.0.1",
242 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
243 | "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
244 | "dev": true,
245 | "license": "ISC",
246 | "dependencies": {
247 | "brace-expansion": "^2.0.1"
248 | },
249 | "engines": {
250 | "node": "20 || >=22"
251 | },
252 | "funding": {
253 | "url": "https://github.com/sponsors/isaacs"
254 | }
255 | },
256 | "node_modules/minipass": {
257 | "version": "7.1.2",
258 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
259 | "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
260 | "dev": true,
261 | "license": "ISC",
262 | "engines": {
263 | "node": ">=16 || 14 >=14.17"
264 | }
265 | },
266 | "node_modules/package-json-from-dist": {
267 | "version": "1.0.1",
268 | "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
269 | "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
270 | "dev": true,
271 | "license": "BlueOak-1.0.0"
272 | },
273 | "node_modules/path-key": {
274 | "version": "3.1.1",
275 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
276 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
277 | "dev": true,
278 | "license": "MIT",
279 | "engines": {
280 | "node": ">=8"
281 | }
282 | },
283 | "node_modules/path-scurry": {
284 | "version": "2.0.0",
285 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
286 | "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
287 | "dev": true,
288 | "license": "BlueOak-1.0.0",
289 | "dependencies": {
290 | "lru-cache": "^11.0.0",
291 | "minipass": "^7.1.2"
292 | },
293 | "engines": {
294 | "node": "20 || >=22"
295 | },
296 | "funding": {
297 | "url": "https://github.com/sponsors/isaacs"
298 | }
299 | },
300 | "node_modules/rimraf": {
301 | "version": "6.0.1",
302 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz",
303 | "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==",
304 | "dev": true,
305 | "license": "ISC",
306 | "dependencies": {
307 | "glob": "^11.0.0",
308 | "package-json-from-dist": "^1.0.0"
309 | },
310 | "bin": {
311 | "rimraf": "dist/esm/bin.mjs"
312 | },
313 | "engines": {
314 | "node": "20 || >=22"
315 | },
316 | "funding": {
317 | "url": "https://github.com/sponsors/isaacs"
318 | }
319 | },
320 | "node_modules/shebang-command": {
321 | "version": "2.0.0",
322 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
323 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
324 | "dev": true,
325 | "license": "MIT",
326 | "dependencies": {
327 | "shebang-regex": "^3.0.0"
328 | },
329 | "engines": {
330 | "node": ">=8"
331 | }
332 | },
333 | "node_modules/shebang-regex": {
334 | "version": "3.0.0",
335 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
336 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
337 | "dev": true,
338 | "license": "MIT",
339 | "engines": {
340 | "node": ">=8"
341 | }
342 | },
343 | "node_modules/signal-exit": {
344 | "version": "4.1.0",
345 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
346 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
347 | "dev": true,
348 | "license": "ISC",
349 | "engines": {
350 | "node": ">=14"
351 | },
352 | "funding": {
353 | "url": "https://github.com/sponsors/isaacs"
354 | }
355 | },
356 | "node_modules/string-width": {
357 | "version": "5.1.2",
358 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
359 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
360 | "dev": true,
361 | "license": "MIT",
362 | "dependencies": {
363 | "eastasianwidth": "^0.2.0",
364 | "emoji-regex": "^9.2.2",
365 | "strip-ansi": "^7.0.1"
366 | },
367 | "engines": {
368 | "node": ">=12"
369 | },
370 | "funding": {
371 | "url": "https://github.com/sponsors/sindresorhus"
372 | }
373 | },
374 | "node_modules/string-width-cjs": {
375 | "name": "string-width",
376 | "version": "4.2.3",
377 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
378 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
379 | "dev": true,
380 | "license": "MIT",
381 | "dependencies": {
382 | "emoji-regex": "^8.0.0",
383 | "is-fullwidth-code-point": "^3.0.0",
384 | "strip-ansi": "^6.0.1"
385 | },
386 | "engines": {
387 | "node": ">=8"
388 | }
389 | },
390 | "node_modules/string-width-cjs/node_modules/ansi-regex": {
391 | "version": "5.0.1",
392 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
393 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
394 | "dev": true,
395 | "license": "MIT",
396 | "engines": {
397 | "node": ">=8"
398 | }
399 | },
400 | "node_modules/string-width-cjs/node_modules/emoji-regex": {
401 | "version": "8.0.0",
402 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
403 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
404 | "dev": true,
405 | "license": "MIT"
406 | },
407 | "node_modules/string-width-cjs/node_modules/strip-ansi": {
408 | "version": "6.0.1",
409 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
410 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
411 | "dev": true,
412 | "license": "MIT",
413 | "dependencies": {
414 | "ansi-regex": "^5.0.1"
415 | },
416 | "engines": {
417 | "node": ">=8"
418 | }
419 | },
420 | "node_modules/strip-ansi": {
421 | "version": "7.1.0",
422 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
423 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
424 | "dev": true,
425 | "license": "MIT",
426 | "dependencies": {
427 | "ansi-regex": "^6.0.1"
428 | },
429 | "engines": {
430 | "node": ">=12"
431 | },
432 | "funding": {
433 | "url": "https://github.com/chalk/strip-ansi?sponsor=1"
434 | }
435 | },
436 | "node_modules/strip-ansi-cjs": {
437 | "name": "strip-ansi",
438 | "version": "6.0.1",
439 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
440 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
441 | "dev": true,
442 | "license": "MIT",
443 | "dependencies": {
444 | "ansi-regex": "^5.0.1"
445 | },
446 | "engines": {
447 | "node": ">=8"
448 | }
449 | },
450 | "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
451 | "version": "5.0.1",
452 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
453 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
454 | "dev": true,
455 | "license": "MIT",
456 | "engines": {
457 | "node": ">=8"
458 | }
459 | },
460 | "node_modules/typescript": {
461 | "version": "5.8.3",
462 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
463 | "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
464 | "dev": true,
465 | "license": "Apache-2.0",
466 | "bin": {
467 | "tsc": "bin/tsc",
468 | "tsserver": "bin/tsserver"
469 | },
470 | "engines": {
471 | "node": ">=14.17"
472 | }
473 | },
474 | "node_modules/undici-types": {
475 | "version": "6.21.0",
476 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
477 | "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
478 | "license": "MIT"
479 | },
480 | "node_modules/which": {
481 | "version": "2.0.2",
482 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
483 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
484 | "dev": true,
485 | "license": "ISC",
486 | "dependencies": {
487 | "isexe": "^2.0.0"
488 | },
489 | "bin": {
490 | "node-which": "bin/node-which"
491 | },
492 | "engines": {
493 | "node": ">= 8"
494 | }
495 | },
496 | "node_modules/wrap-ansi": {
497 | "version": "8.1.0",
498 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
499 | "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
500 | "dev": true,
501 | "license": "MIT",
502 | "dependencies": {
503 | "ansi-styles": "^6.1.0",
504 | "string-width": "^5.0.1",
505 | "strip-ansi": "^7.0.1"
506 | },
507 | "engines": {
508 | "node": ">=12"
509 | },
510 | "funding": {
511 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
512 | }
513 | },
514 | "node_modules/wrap-ansi-cjs": {
515 | "name": "wrap-ansi",
516 | "version": "7.0.0",
517 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
518 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
519 | "dev": true,
520 | "license": "MIT",
521 | "dependencies": {
522 | "ansi-styles": "^4.0.0",
523 | "string-width": "^4.1.0",
524 | "strip-ansi": "^6.0.0"
525 | },
526 | "engines": {
527 | "node": ">=10"
528 | },
529 | "funding": {
530 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
531 | }
532 | },
533 | "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
534 | "version": "5.0.1",
535 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
536 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
537 | "dev": true,
538 | "license": "MIT",
539 | "engines": {
540 | "node": ">=8"
541 | }
542 | },
543 | "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
544 | "version": "4.3.0",
545 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
546 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
547 | "dev": true,
548 | "license": "MIT",
549 | "dependencies": {
550 | "color-convert": "^2.0.1"
551 | },
552 | "engines": {
553 | "node": ">=8"
554 | },
555 | "funding": {
556 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
557 | }
558 | },
559 | "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
560 | "version": "8.0.0",
561 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
562 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
563 | "dev": true,
564 | "license": "MIT"
565 | },
566 | "node_modules/wrap-ansi-cjs/node_modules/string-width": {
567 | "version": "4.2.3",
568 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
569 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
570 | "dev": true,
571 | "license": "MIT",
572 | "dependencies": {
573 | "emoji-regex": "^8.0.0",
574 | "is-fullwidth-code-point": "^3.0.0",
575 | "strip-ansi": "^6.0.1"
576 | },
577 | "engines": {
578 | "node": ">=8"
579 | }
580 | },
581 | "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
582 | "version": "6.0.1",
583 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
584 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
585 | "dev": true,
586 | "license": "MIT",
587 | "dependencies": {
588 | "ansi-regex": "^5.0.1"
589 | },
590 | "engines": {
591 | "node": ">=8"
592 | }
593 | }
594 | }
595 | }
596 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Niklas Mollenhauer ",
3 | "name": "node-ts",
4 | "description": "TeamSpeak® 3 Server Query client for node.js implemented using TypeScript",
5 | "version": "8.0.5",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/nikeee/node-ts.git"
9 | },
10 | "main": "lib/index.js",
11 | "type": "module",
12 | "types": "lib/index.d.ts",
13 | "dependencies": {
14 | "@rauschma/stringio": "^1.4.0",
15 | "@types/node": "^22.15.29"
16 | },
17 | "devDependencies": {
18 | "rimraf": "^6.0.1",
19 | "typescript": "^5.8.3"
20 | },
21 | "scripts": {
22 | "test": "tsc --noEmit",
23 | "clean": "rimraf lib",
24 | "compile": "tsc",
25 | "prepare": "npm run clean && npm run compile"
26 | },
27 | "keywords": [
28 | "teamspeak",
29 | "serverquery",
30 | "ts3",
31 | "ts",
32 | "typescript"
33 | ],
34 | "optionalDependencies": {},
35 | "engines": {
36 | "node": ">=22.0.0"
37 | },
38 | "license": "LGPL-3.0"
39 | }
40 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./node-ts";
2 |
--------------------------------------------------------------------------------
/src/node-ts.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @autor Niklas Mollenhauer
3 | * @autor Tim Kluge
4 | */
5 |
6 | import * as net from "node:net";
7 | import { EventEmitter } from "node:events";
8 | import { chunksToLinesAsync, chomp } from "@rauschma/stringio";
9 |
10 | import { escapeQueryString, unescapeQueryString } from "./queryStrings.js"
11 |
12 | /** Represents a Key-Value object. */
13 | type MapLike = Record;
14 |
15 | /**
16 | * Client that can be used to connect to a TeamSpeak server query API.
17 | */
18 | export class TeamSpeakClient extends EventEmitter {
19 | private queue: QueryCommand[] = [];
20 | private _executing: QueryCommand | undefined;
21 |
22 | private socket!: net.Socket;
23 |
24 | private isConnected = false;
25 |
26 | private static readonly DefaultHost = "localhost";
27 | private static readonly DefaultPort = 10011;
28 |
29 | private readonly host: string;
30 | private readonly port: number;
31 |
32 | /**
33 | * Creates a new instance of TeamSpeakClient for a specific remote host:port.
34 | * @param {string = TeamSpeakClient.DefaultHost} host Remote host of the TeamSpeak server. Can be an IP address or a host name.
35 | * @param {number = TeamSpeakClient.DefaultPort} port TCP port of the server query instance of the remote host.
36 | * @constructor
37 | */
38 | constructor(
39 | host = TeamSpeakClient.DefaultHost,
40 | port = TeamSpeakClient.DefaultPort,
41 | ) {
42 | super();
43 | this.host = host;
44 | this.port = port;
45 | }
46 |
47 | public connect(): Promise {
48 | this.isConnected = false;
49 | return new Promise((resolve, reject) => {
50 | this.socket = net.connect(this.port, this.host);
51 | this.socket.on("error", err => this.emit("error", err));
52 | // We'll try to reject the promise if the connection closes, to make sure
53 | // the promise gets rejected if we get an error while connecting.
54 | // (This will just do nothing if the promise is already fulfilled)
55 | this.socket.once("close", err => reject(err));
56 | this.socket.on("close", () => this.emit("close", this.queue));
57 | this.socket.on("connect", () => this.onConnect(resolve, reject));
58 | });
59 | }
60 |
61 | /**
62 | * Gets called on an opened connection
63 | */
64 | private async onConnect(connectionEstablished: () => void, error: (e: Error) => void): Promise {
65 | const lineGenerator = chunksToLinesAsync(this.socket);
66 |
67 | let lineCounter = 0;
68 |
69 | for await (const lineWithNewLine of lineGenerator) {
70 | const line = chomp(lineWithNewLine).trim();
71 | if (line === "")
72 | continue;
73 | ++lineCounter;
74 |
75 | switch (lineCounter) {
76 | case 1: {
77 | if (line !== "TS3") {
78 | this.isConnected = false;
79 | error(new Error("Remove server is not a TS3 Query Server endpoint."));
80 | return;
81 | }
82 | continue;
83 | }
84 |
85 | case 2:
86 | // We have read a second non-empty line, so we are ready to take commands
87 | this.isConnected = true;
88 | connectionEstablished();
89 | continue; // Welcome message, followed by empty line (which is skipped)
90 |
91 | default: {
92 | this.handleSingleLine(line);
93 | this.checkQueue();
94 | }
95 | }
96 | }
97 | }
98 |
99 | private handleSingleLine(line: string): void {
100 | // Server answers with:
101 | // [- One line containing the answer ]
102 | // - "error id=XX msg=YY". ID is zero if command was executed successfully.
103 | if (line.startsWith("error")) {
104 |
105 | const errorResponse = line.substr("error ".length);
106 |
107 | const response = this.parseResponse(errorResponse);
108 | const executing = this._executing;
109 |
110 | if (response !== undefined && executing !== undefined) {
111 | const res = response.shift();
112 |
113 | if (res !== undefined) {
114 | const currentError: QueryError = {
115 | id: res["id"] || 0,
116 | msg: res["msg"] || ""
117 | };
118 |
119 | if (currentError.id !== 0)
120 | executing.error = currentError;
121 |
122 | if (executing.rejectFunction && executing.resolveFunction) {
123 | //item: executing || null,
124 | const e = executing;
125 | const data = {
126 | cmd: e.cmd,
127 | options: e.options || [],
128 | text: e.text || null,
129 | parameters: e.parameters || {},
130 | error: e.error || null,
131 | response: e.response || null,
132 | rawResponse: e.rawResponse || null
133 | };
134 | if (data.error && data.error.id !== 0)
135 | executing.rejectFunction(data as CallbackData);
136 | else
137 | executing.resolveFunction(data as CallbackData);
138 | }
139 | }
140 | }
141 |
142 | this._executing = undefined;
143 | this.checkQueue();
144 |
145 | } else if (line.startsWith("notify")) {
146 | const notificationResponse = line.substr("notify".length);
147 | const response = this.parseResponse(notificationResponse);
148 |
149 | const notificationName = notificationResponse.substr(0, notificationResponse.indexOf(" "));
150 | this.emit(notificationName, response);
151 | } else if (this._executing) {
152 | this._executing.rawResponse = line;
153 | this._executing.response = this.parseResponse(line);
154 | }
155 | }
156 |
157 | /**
158 | * Sends a command to the server
159 | */
160 | // TODO: Only include constant overloads to force corrent parameterization
161 |
162 | // TODO: help
163 | // TODO: quit
164 | public send(cmd: "login", params: LoginParams): Promise>;
165 | public send(cmd: "logout"): Promise>;
166 | public send(cmd: "version"): Promise>;
167 | public send(cmd: "hostinfo"): Promise>;
168 | public send(cmd: "instanceinfo"): Promise>;
169 | public send(cmd: "instanceedit", params: InstanceEditParams): Promise>;
170 | public send(cmd: "bindinglist"): Promise>;
171 | public send(cmd: "use", params: UseParams): Promise>;
172 | public send(cmd: "serverlist", params: MapLike, options: string[]): Promise>;
173 | // TODO: serveridgetbyport
174 | public send(cmd: "serverdelete", params: ServerDeleteParams): Promise>;
175 | // TODO: servercreate
176 | public send(cmd: "serverstart", params: ServerStartStopParams): Promise>;
177 | public send(cmd: "serverstop", params: ServerStartStopParams): Promise>;
178 | public send(cmd: "serverprocessstop"): Promise>;
179 | public send(cmd: "serverinfo"): Promise>;
180 | public send(cmd: "serverrequestconnectioninfo"): Promise>;
181 | public send(cmd: "serveredit", params: ServerEditParams): Promise>;
182 | // TODO: servergrouplist
183 | // TODO: servergroupadd
184 | // TODO: servergroupdel
185 | // TODO: servergroupcopy
186 | // TODO: servergrouprename
187 | // TODO: servergrouppermlist
188 | // TODO: servergroupaddperm
189 | // TODO: servergroupdelperm
190 | // TODO: servergroupaddclient
191 | // TODO: servergroupdelclient
192 | // TODO: servergroupclientlist
193 | // TODO: servergroupsbyclientid
194 | // TODO: servergroupautoaddperm
195 | // TODO: servergroupautodelperm
196 | // TODO: serversnapshotcreate
197 | // TODO: serversnapshotdeploy
198 | public send(cmd: "servernotifyregister", params: RegisterNotificationsParams): Promise>;
199 | // TODO: servernotifyunregister
200 | public send(cmd: "sendtextmessage", params: SendTextMessageParams): Promise>;
201 | // TODO: logview
202 | public send(cmd: "logadd", params: LogAddParams): Promise>;
203 | public send(cmd: "gm", params: GmParams): Promise>;
204 | public send(cmd: "channellist", params: MapLike, options: string[]): Promise>; //@todo find anything to make signature better typed
205 | public send(cmd: "channelinfo", params: ChannelInfoParams): Promise>
206 | // TODO: channelfind
207 | // TODO: channelmove
208 | // TODO: channelcreate
209 | public send(cmd: "channeldelete", params: ChannelDeleteParams): Promise>;
210 | // TODO: channeledit
211 | // TODO: channelgrouplist
212 | // TODO: channelgroupadd
213 | // TODO: channelgroupdel
214 | // TODO: channelgroupcopy
215 | // TODO: channelgrouprename
216 | // TODO: channelgroupaddperm
217 | // TODO: channelgrouppermlist
218 | // TODO: channelgroupdelperm
219 | // TODO: channelgroupclientlist
220 | // TODO: setclientchannelgroup
221 | // TODO: channelpermlist
222 | // TODO: channeladdperm
223 | // TODO: channeldelperm
224 | public send(cmd: "clientlist", params: ClientListParams): Promise>;
225 | public send(cmd: "clientinfo", params: ClientInfoParams): Promise>;
226 | // TODO: clientfind
227 | // TODO: clientedit
228 | // TODO: clientdblist
229 | // TODO: clientdbinfo
230 | // TODO: clientdbfind
231 | // TODO: clientdbedit
232 | public send(cmd: "clientdbdelete", params: ClientDBDeleteParams): Promise>;
233 | // TODO: clientgetids
234 | // TODO: clientgetdbidfromuid
235 | // TODO: clientgetnamefromuid
236 | // TODO: clientgetnamefromdbid
237 | // TODO: clientsetserverquerylogin
238 | // TODO: clientupdate
239 | public send(cmd: "clientmove", params: ClientMoveParams): Promise>;
240 | public send(cmd: "clientkick", params: ClientKickParams): Promise>;
241 | public send(cmd: "clientpoke", params: ClientPokeParams): Promise>;
242 | public send(cmd: "clientpermlist", params: ClientPermListParams, options: string[]): Promise>;
243 | public send(cmd: "clientaddperm", params: ClientAddPermParams): Promise>;
244 | public send(cmd: "clientdelperm", param: ClientDeleteParams): Promise>;
245 | // TODO: channelclientpermlist
246 | // TODO: channelclientaddperm
247 | // TODO: channelclientdelperm
248 | // TODO: permissionlist
249 | // TODO: permidgetbyname
250 | // TODO: permoverview
251 | // TODO: permget
252 | // TODO: permfind
253 | // TODO: permrest
254 | // TODO: privilegekeylist
255 | // TODO: privilegekeyadd
256 | // TODO: privilegekeydelete
257 | // TODO: privilegekeyuse
258 | // TODO: messageadd
259 | public send(cmd: "messagedel", params: MessageDeleteParams): Promise>;
260 | // TODO: messageget
261 | // TODO: messageupdateflag
262 | // TODO: complainlist
263 | // TODO: complainadd
264 | public send(cmd: "complaindelall", params: ComplainDeleteAllParams): Promise>;
265 | public send(cmd: "complaindel", params: ComplainDeleteParams): Promise>;
266 | public send(cmd: "banclient", params: BanClientParams): Promise>; //@todo test
267 | public send(cmd: "banlist"): Promise>;
268 | public send(cmd: "banadd", params: BanAddParams): Promise>;
269 | public send(cmd: "bandel", params: BanDeleteParams): Promise>;
270 | public send(cmd: "bandelall"): Promise>;
271 | // TODO: ftinitupload
272 | // TODO: ftinitdownload
273 | // TODO: ftlist
274 | // TODO: ftgetfileinfo
275 | public send(cmd: "ftstop", params: FtStopParams): Promise>;
276 | // TODO: ftdeletefile
277 | // TODO: ftrenamefile
278 | // TODO: customsearch
279 | // TODO: custominfo
280 | // TODO: whoami
281 |
282 | //public send(cmd: string): Promise>;
283 | //public send(cmd: string, params: IAssoc