@honeybbq/teamspeak-client 0.3.1 → 1.0.0-beta.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 +322 -60
- package/dist/abort.d.ts +5 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/address.d.ts +8 -0
- package/dist/address.d.ts.map +1 -1
- package/dist/api/voice.d.ts +24 -0
- package/dist/api/voice.d.ts.map +1 -0
- package/dist/capabilities.d.ts +62 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/client.d.ts +172 -39
- package/dist/client.d.ts.map +1 -1
- package/dist/commands.d.ts +45 -27
- package/dist/commands.d.ts.map +1 -1
- package/dist/crypto/crypt.d.ts +19 -4
- package/dist/crypto/crypt.d.ts.map +1 -1
- package/dist/crypto/identity.d.ts +87 -8
- package/dist/crypto/identity.d.ts.map +1 -1
- package/dist/crypto/index.d.ts +2 -1
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/diagnostics.d.ts +45 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/discovery/resolver.d.ts +21 -3
- package/dist/discovery/resolver.d.ts.map +1 -1
- package/dist/errors.d.ts +70 -16
- package/dist/errors.d.ts.map +1 -1
- package/dist/events.d.ts +4 -5
- package/dist/events.d.ts.map +1 -1
- package/dist/handshake/crypt-handshake.d.ts +1 -0
- package/dist/handshake/crypt-handshake.d.ts.map +1 -1
- package/dist/handshake/crypt-init2.d.ts.map +1 -1
- package/dist/handshake/license.d.ts +7 -0
- package/dist/handshake/license.d.ts.map +1 -1
- package/dist/handshake.d.ts +14 -5
- package/dist/handshake.d.ts.map +1 -1
- package/dist/helpers.d.ts +0 -8
- package/dist/helpers.d.ts.map +1 -1
- package/dist/index.d.ts +20 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3967 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications.d.ts +7 -15
- package/dist/notifications.d.ts.map +1 -1
- package/dist/reconnect.d.ts +69 -0
- package/dist/reconnect.d.ts.map +1 -0
- package/dist/throttle.d.ts +9 -0
- package/dist/throttle.d.ts.map +1 -1
- package/dist/transfer.d.ts +27 -25
- package/dist/transfer.d.ts.map +1 -1
- package/dist/transport/handler.d.ts +37 -5
- package/dist/transport/handler.d.ts.map +1 -1
- package/dist/transport/quicklz.d.ts +19 -0
- package/dist/transport/quicklz.d.ts.map +1 -1
- package/dist/types.d.ts +277 -97
- package/dist/types.d.ts.map +1 -1
- package/package.json +21 -56
- package/src/abort.ts +24 -0
- package/src/address.ts +74 -0
- package/src/api/voice.ts +61 -0
- package/src/capabilities.ts +92 -0
- package/src/client.ts +1392 -0
- package/src/commands.ts +193 -0
- package/src/crypto/crypt-ops.ts +6 -0
- package/src/crypto/crypt.ts +274 -0
- package/src/crypto/eax.ts +152 -0
- package/src/crypto/identity.ts +484 -0
- package/src/crypto/index.ts +21 -0
- package/src/crypto/primitives.ts +141 -0
- package/src/diagnostics.ts +58 -0
- package/src/discovery/index.ts +1 -0
- package/src/discovery/resolver.ts +272 -0
- package/src/errors.ts +156 -0
- package/src/events.ts +28 -0
- package/src/handshake/crypt-handshake.ts +135 -0
- package/src/handshake/crypt-init2.ts +48 -0
- package/src/handshake/index.ts +3 -0
- package/src/handshake/license.test.ts +49 -0
- package/src/handshake/license.ts +208 -0
- package/src/handshake.ts +136 -0
- package/src/helpers.ts +10 -0
- package/src/index.ts +74 -0
- package/src/notifications.ts +136 -0
- package/src/reconnect.ts +141 -0
- package/src/throttle.ts +92 -0
- package/src/transfer.ts +127 -0
- package/src/transport/generation-window.ts +77 -0
- package/src/transport/handler.ts +914 -0
- package/src/transport/index.ts +14 -0
- package/src/transport/packet.ts +69 -0
- package/src/transport/quicklz.ts +209 -0
- package/src/types.ts +349 -0
- package/dist/address-BR-5unVo.cjs +0 -2
- package/dist/address-BR-5unVo.cjs.map +0 -1
- package/dist/address-BfmovVpp.js +0 -65
- package/dist/address-BfmovVpp.js.map +0 -1
- package/dist/api.d.ts +0 -17
- package/dist/api.d.ts.map +0 -1
- package/dist/command/command.d.ts +0 -12
- package/dist/command/command.d.ts.map +0 -1
- package/dist/command/index.cjs +0 -1
- package/dist/command/index.d.ts +0 -4
- package/dist/command/index.d.ts.map +0 -1
- package/dist/command/index.mjs +0 -3
- package/dist/command/parser.d.ts +0 -3
- package/dist/command/parser.d.ts.map +0 -1
- package/dist/command-BLe-C2L2.js +0 -74
- package/dist/command-BLe-C2L2.js.map +0 -1
- package/dist/command-DAK4pUBP.cjs +0 -4
- package/dist/command-DAK4pUBP.cjs.map +0 -1
- package/dist/crypt-handshake-CQkQreLx.cjs +0 -2
- package/dist/crypt-handshake-CQkQreLx.cjs.map +0 -1
- package/dist/crypt-handshake-DziOY4Lq.js +0 -55
- package/dist/crypt-handshake-DziOY4Lq.js.map +0 -1
- package/dist/crypt-init2-D70ha4LB.js +0 -158
- package/dist/crypt-init2-D70ha4LB.js.map +0 -1
- package/dist/crypt-init2-DparLekm.cjs +0 -2
- package/dist/crypt-init2-DparLekm.cjs.map +0 -1
- package/dist/crypto/index.cjs +0 -1
- package/dist/crypto/index.mjs +0 -3
- package/dist/crypto-Bg02m4ZE.js +0 -165
- package/dist/crypto-Bg02m4ZE.js.map +0 -1
- package/dist/crypto-CDlweUL3.cjs +0 -2
- package/dist/crypto-CDlweUL3.cjs.map +0 -1
- package/dist/discovery/index.cjs +0 -1
- package/dist/discovery/index.mjs +0 -2
- package/dist/handler-DI_abe9c.js +0 -483
- package/dist/handler-DI_abe9c.js.map +0 -1
- package/dist/handler-DuwoO5RC.cjs +0 -2
- package/dist/handler-DuwoO5RC.cjs.map +0 -1
- package/dist/handshake/index.cjs +0 -1
- package/dist/handshake/index.mjs +0 -3
- package/dist/index.cjs +0 -4
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs +0 -827
- package/dist/index.mjs.map +0 -1
- package/dist/parser-CL33R9tr.cjs +0 -2
- package/dist/parser-CL33R9tr.cjs.map +0 -1
- package/dist/parser-DZMv3Jm-.js +0 -33
- package/dist/parser-DZMv3Jm-.js.map +0 -1
- package/dist/primitives-cNNAeFCo.cjs +0 -2
- package/dist/primitives-cNNAeFCo.cjs.map +0 -1
- package/dist/primitives-xIr6Tjk4.js +0 -1457
- package/dist/primitives-xIr6Tjk4.js.map +0 -1
- package/dist/resolver-6B8dI9gr.js +0 -141
- package/dist/resolver-6B8dI9gr.js.map +0 -1
- package/dist/resolver-DCcmyWSK.cjs +0 -4
- package/dist/resolver-DCcmyWSK.cjs.map +0 -1
- package/dist/transport/index.cjs +0 -1
- package/dist/transport/index.mjs +0 -2
package/dist/types.d.ts
CHANGED
|
@@ -1,122 +1,302 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export interface
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import type { ChannelID, ClientEntry, ClientID, CommandMiddleware, Logger, ServerGroupID, UID } from "@honeybbq/teamspeak-core";
|
|
2
|
+
import type { Duplex } from "node:stream";
|
|
3
|
+
import type { ReconnectOptions } from "./reconnect.js";
|
|
4
|
+
/** A text message, sent privately, to a channel, or to the whole server. */
|
|
5
|
+
export interface TextMessageEvent {
|
|
6
|
+
/** The sender's nickname. */
|
|
7
|
+
readonly invokerName: string;
|
|
8
|
+
/** The sender's unique identifier. */
|
|
9
|
+
readonly invokerUID: UID;
|
|
10
|
+
/** The message, unescaped. */
|
|
11
|
+
readonly message: string;
|
|
12
|
+
/** The sender's server groups, as this client last saw them. */
|
|
13
|
+
readonly invokerGroups: readonly ServerGroupID[];
|
|
14
|
+
/**
|
|
15
|
+
* Private, channel or server; compare it with `TextMessageTarget`. A plain
|
|
16
|
+
* number, since a server may send a mode that table does not name.
|
|
17
|
+
*/
|
|
18
|
+
readonly targetMode: number;
|
|
19
|
+
/**
|
|
20
|
+
* The client a private message was sent to. Channel and server messages
|
|
21
|
+
* carry no target, so it is 0 for them.
|
|
22
|
+
*/
|
|
23
|
+
readonly targetID: ClientID;
|
|
24
|
+
/** The sender. */
|
|
25
|
+
readonly invokerID: ClientID;
|
|
13
26
|
}
|
|
27
|
+
/** A client changing channel, of its own accord or moved by someone. */
|
|
14
28
|
export interface ClientMovedEvent {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
export interface ClientInfo {
|
|
29
|
-
nickname: string;
|
|
30
|
-
uid: string;
|
|
31
|
-
serverGroups: string[];
|
|
32
|
-
channelID: bigint;
|
|
33
|
-
type: number;
|
|
34
|
-
id: number;
|
|
35
|
-
}
|
|
36
|
-
export interface ChannelInfo {
|
|
37
|
-
name: string;
|
|
38
|
-
description: string;
|
|
39
|
-
id: bigint;
|
|
40
|
-
parentID: bigint;
|
|
41
|
-
/** ID of the sibling channel this one is sorted after; 0 means first. */
|
|
42
|
-
order: bigint;
|
|
29
|
+
/** Who moved the client; the client itself for a move of its own. */
|
|
30
|
+
readonly invokerName: string;
|
|
31
|
+
/** The mover's unique identifier. */
|
|
32
|
+
readonly invokerUID: UID;
|
|
33
|
+
/** The channel the client is now in. */
|
|
34
|
+
readonly targetChannelID: ChannelID;
|
|
35
|
+
/** Why the client moved; compare it with `Reason`. */
|
|
36
|
+
readonly reason: number;
|
|
37
|
+
/** The client that moved. */
|
|
38
|
+
readonly clientID: ClientID;
|
|
39
|
+
/** The mover. */
|
|
40
|
+
readonly invokerID: ClientID;
|
|
43
41
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
/**
|
|
43
|
+
* A client going out of view: leaving the server, kicked or banned from it, or
|
|
44
|
+
* in a channel that stopped being subscribed.
|
|
45
|
+
*/
|
|
46
|
+
export interface ClientLeaveEvent {
|
|
47
|
+
/** The reason given for a kick or a ban, or the client's own parting message. */
|
|
48
|
+
readonly reasonMessage: string;
|
|
49
|
+
/** Why the client left; compare it with `Reason`. */
|
|
50
|
+
readonly reason: number;
|
|
51
|
+
/** The client that left. */
|
|
52
|
+
readonly clientID: ClientID;
|
|
53
|
+
/** Who kicked or banned the client; empty otherwise. */
|
|
54
|
+
readonly invokerName: string;
|
|
55
|
+
/** The kicker's unique identifier; empty unless kicked or banned. */
|
|
56
|
+
readonly invokerUID: UID;
|
|
57
|
+
/** The kicker; 0 unless kicked or banned. */
|
|
58
|
+
readonly invokerID: ClientID;
|
|
50
59
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
/** This client being kicked from its channel or the server. */
|
|
61
|
+
export interface KickedEvent {
|
|
62
|
+
/** The reason the invoker gave. */
|
|
63
|
+
readonly reasonMessage: string;
|
|
64
|
+
/** `Reason.KickChannel`, `Reason.KickServer` or `Reason.KickServerBan`. */
|
|
65
|
+
readonly reason: number;
|
|
66
|
+
/** Who kicked this client. */
|
|
67
|
+
readonly invokerName: string;
|
|
68
|
+
/** The kicker's unique identifier. */
|
|
69
|
+
readonly invokerUID: UID;
|
|
70
|
+
/** The kicker. */
|
|
71
|
+
readonly invokerID: ClientID;
|
|
62
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* A client coming into view: the same record `listClients` returns, so one
|
|
75
|
+
* type describes a client however it was learned of; its own id is `id`, as
|
|
76
|
+
* in every record. The fields only `clientlist -times` reports are undefined
|
|
77
|
+
* here.
|
|
78
|
+
*/
|
|
79
|
+
export type ClientEnterEvent = ClientEntry;
|
|
80
|
+
/** This client being poked. */
|
|
63
81
|
export interface PokeEvent {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
/** Who poked. */
|
|
83
|
+
readonly invokerName: string;
|
|
84
|
+
/** The poker's unique identifier. */
|
|
85
|
+
readonly invokerUID: UID;
|
|
86
|
+
/** The poker. */
|
|
87
|
+
readonly invokerID: ClientID;
|
|
88
|
+
/** The poke's message, unescaped. */
|
|
89
|
+
readonly message: string;
|
|
90
|
+
}
|
|
91
|
+
/** Audio from another client, in the channel or whispered. */
|
|
92
|
+
export interface VoiceDataEvent {
|
|
93
|
+
/** Who is speaking. */
|
|
94
|
+
readonly clientID: ClientID;
|
|
95
|
+
/**
|
|
96
|
+
* How the audio is encoded; compare it with `Codec`. A plain number, since a
|
|
97
|
+
* server may relay a codec that table does not name.
|
|
98
|
+
*/
|
|
99
|
+
readonly codec: number;
|
|
100
|
+
/** One encoded frame, copied: it stays valid after the listener returns. */
|
|
101
|
+
readonly data: Uint8Array;
|
|
68
102
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
103
|
+
/**
|
|
104
|
+
* A notification from the server, as it arrived: the escape hatch for one the
|
|
105
|
+
* SDK does not model.
|
|
106
|
+
*/
|
|
107
|
+
export interface NotificationEvent {
|
|
108
|
+
/** The notification's name, such as `notifyserveredited`. */
|
|
109
|
+
readonly name: string;
|
|
110
|
+
/** Its parameters, unescaped. */
|
|
111
|
+
readonly params: Readonly<Record<string, string>>;
|
|
73
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* The events `Client.on()` takes, and what each delivers. May gain events in a
|
|
115
|
+
* minor release; code that handles every event generically should expect
|
|
116
|
+
* names it does not know.
|
|
117
|
+
*/
|
|
74
118
|
export interface EventMap {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
119
|
+
/** A text message to this client, its channel or the server. */
|
|
120
|
+
textMessage: TextMessageEvent;
|
|
121
|
+
/** A client coming into view, including every client already there on connecting. */
|
|
122
|
+
clientEnter: ClientEnterEvent;
|
|
123
|
+
/** A client going out of view. */
|
|
124
|
+
clientLeave: ClientLeaveEvent;
|
|
125
|
+
/** A client changing channel. */
|
|
78
126
|
clientMoved: ClientMovedEvent;
|
|
127
|
+
/** This client being poked. */
|
|
79
128
|
poked: PokeEvent;
|
|
80
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Audio from another client. Only decoded with a listener or event
|
|
131
|
+
* middleware. Voice is dropped, counted and reported in a warning at most
|
|
132
|
+
* every ten seconds, while more than 256 deliveries are waiting: a listener
|
|
133
|
+
* that cannot keep up loses audio rather than memory.
|
|
134
|
+
*/
|
|
135
|
+
voiceData: VoiceDataEvent;
|
|
136
|
+
/**
|
|
137
|
+
* Every notification the server sends, modelled or not, after any event it
|
|
138
|
+
* produces.
|
|
139
|
+
*/
|
|
140
|
+
notification: NotificationEvent;
|
|
141
|
+
/** The handshake completing, on `connect()` and on every reconnection. */
|
|
81
142
|
connected: void;
|
|
143
|
+
/**
|
|
144
|
+
* `undefined` after `disconnect()`, and the cause otherwise: a failed
|
|
145
|
+
* handshake, a `ConnectionTimeoutError`, or a `RemovedError` for a kick, a
|
|
146
|
+
* ban or a server stopping.
|
|
147
|
+
*/
|
|
82
148
|
disconnected: Error | undefined;
|
|
83
|
-
|
|
149
|
+
/** A kick from the server also ends the connection, which `disconnected` reports. */
|
|
150
|
+
kicked: KickedEvent;
|
|
84
151
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
152
|
+
/**
|
|
153
|
+
* The events that come from the server, and so pass through event middleware.
|
|
154
|
+
* May gain members in a minor release: a `switch` over an event's name needs
|
|
155
|
+
* a default case.
|
|
156
|
+
*/
|
|
157
|
+
export type ServerEventName = "textMessage" | "clientEnter" | "clientLeave" | "clientMoved" | "poked" | "voiceData" | "notification";
|
|
158
|
+
/** A server event as event middleware sees it. */
|
|
159
|
+
export type ServerEvent = {
|
|
160
|
+
[K in ServerEventName]: {
|
|
161
|
+
readonly name: K;
|
|
162
|
+
readonly payload: EventMap[K];
|
|
163
|
+
};
|
|
164
|
+
}[ServerEventName];
|
|
165
|
+
/** A listener for one event. */
|
|
166
|
+
export type Listener<K extends keyof EventMap> = EventMap[K] extends void ? () => void : (payload: EventMap[K]) => void;
|
|
167
|
+
/** Removes a listener; calling it again does nothing. Also a `Disposable`, for `using`. */
|
|
168
|
+
export type Unsubscribe = (() => void) & Disposable;
|
|
169
|
+
/**
|
|
170
|
+
* The part of a UDP socket the client uses. A `node:dgram` socket is one; so
|
|
171
|
+
* is anything else with these methods, such as a tunnel or a test double.
|
|
172
|
+
*
|
|
173
|
+
* Should a later release use more of a socket, the new members will be
|
|
174
|
+
* optional here, so an implementation of this interface keeps compiling.
|
|
175
|
+
*/
|
|
176
|
+
export interface DatagramSocket {
|
|
177
|
+
/** Fix the peer, then call `callback`; failure is reported as an `error` event. */
|
|
178
|
+
connect(port: number, address: string, callback: () => void): void;
|
|
179
|
+
/** Send one datagram to the peer. */
|
|
180
|
+
send(data: Uint8Array, callback: (error: Error | null) => void): void;
|
|
181
|
+
/** Close the socket; it then emits `close`. */
|
|
182
|
+
close(): void;
|
|
183
|
+
/** Listen for each datagram received. */
|
|
184
|
+
on(event: "message", listener: (message: Uint8Array) => void): unknown;
|
|
185
|
+
/** Listen for a failure, which ends the connection. */
|
|
186
|
+
on(event: "error", listener: (error: Error) => void): unknown;
|
|
187
|
+
/** Listen for the socket closing. */
|
|
188
|
+
on(event: "close", listener: () => void): unknown;
|
|
189
|
+
/** Listen for the next failure only, while connecting. */
|
|
190
|
+
once(event: "error", listener: (error: Error) => void): unknown;
|
|
191
|
+
/** Stop listening for failures. */
|
|
192
|
+
off(event: "error", listener: (error: Error) => void): unknown;
|
|
89
193
|
}
|
|
90
|
-
|
|
91
|
-
export type
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
194
|
+
/** Creates the UDP socket the client talks through, for the given address family. */
|
|
195
|
+
export type SocketFactory = (family: 4 | 6) => DatagramSocket;
|
|
196
|
+
/**
|
|
197
|
+
* Opens the connection a file transfer runs over, to `host:port`. A
|
|
198
|
+
* `node:net` socket is one, as is the socket a SOCKS or HTTP proxy library
|
|
199
|
+
* returns. It may still be connecting when returned: the transfer waits for
|
|
200
|
+
* it.
|
|
201
|
+
*/
|
|
202
|
+
export type FileTransferSocketFactory = (host: string, port: number) => Duplex;
|
|
203
|
+
/** The values of the table below, before freezing. */
|
|
204
|
+
declare const clientStatusValues: {
|
|
205
|
+
/** Not connected: before `connect()`, after `disconnect()`, or after a drop. */
|
|
206
|
+
readonly Disconnected: "disconnected";
|
|
207
|
+
/** Connecting: `connect()` is waiting for the handshake. */
|
|
208
|
+
readonly Connecting: "connecting";
|
|
209
|
+
/** Connected: the handshake completed and commands can be sent. */
|
|
210
|
+
readonly Connected: "connected";
|
|
211
|
+
};
|
|
212
|
+
/** Where a client is in its connection's life. */
|
|
213
|
+
export declare const ClientStatus: typeof clientStatusValues;
|
|
214
|
+
/**
|
|
215
|
+
* One of {@link ClientStatus}. May gain members in a minor release: a
|
|
216
|
+
* `switch` over it needs a default case.
|
|
217
|
+
*/
|
|
218
|
+
export type ClientStatus = (typeof ClientStatus)[keyof typeof ClientStatus];
|
|
219
|
+
/** Wraps the delivery of server events; it may observe, alter or drop them. */
|
|
220
|
+
export type EventMiddleware = (next: (event: ServerEvent) => void) => (event: ServerEvent) => void;
|
|
221
|
+
/**
|
|
222
|
+
* An address a server's name resolved to. Only `addr` is needed to connect;
|
|
223
|
+
* the rest describes the answer.
|
|
224
|
+
*/
|
|
102
225
|
export interface ResolvedAddr {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
226
|
+
/** The endpoint, as `host:port`. */
|
|
227
|
+
readonly addr: string;
|
|
228
|
+
/** How it was found, such as `SRV`, `TSDNS-SRV`, `TSDNS-Direct` or `Direct`. */
|
|
229
|
+
readonly source?: string | undefined;
|
|
230
|
+
/** When the answer stops being valid; unset for no stated lifetime. */
|
|
231
|
+
readonly expiry?: Date | undefined;
|
|
106
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Turns the address a client was given — a host, `host:port`, or a TeamSpeak
|
|
235
|
+
* name — into endpoints to connect to. The default follows SRV records and
|
|
236
|
+
* TSDNS, as the TeamSpeak application does.
|
|
237
|
+
*/
|
|
107
238
|
export interface AddrResolver {
|
|
108
|
-
|
|
239
|
+
/**
|
|
240
|
+
* The endpoints for `addr`, best first. An empty answer falls back to `addr`
|
|
241
|
+
* itself. `signal` aborts when the connection attempt is given up, or once
|
|
242
|
+
* resolution has taken 10 seconds, after which the client connects to
|
|
243
|
+
* `addr` as given; a resolver that ignores it is abandoned all the same.
|
|
244
|
+
*/
|
|
245
|
+
resolve(addr: string, options?: {
|
|
246
|
+
readonly signal?: AbortSignal | undefined;
|
|
247
|
+
}): Promise<readonly ResolvedAddr[]>;
|
|
109
248
|
}
|
|
249
|
+
/** How a `Client` connects, logs and behaves; every field is optional. */
|
|
110
250
|
export interface ClientOptions {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
251
|
+
/** Where the client logs. Silent unless set: a library has no business writing to the console. */
|
|
252
|
+
readonly logger?: Logger | undefined;
|
|
253
|
+
/**
|
|
254
|
+
* Creates the UDP socket the client talks through, given the address family
|
|
255
|
+
* the server's address resolved to.
|
|
256
|
+
*
|
|
257
|
+
* Supplying one lets an application route traffic through a proxy or tunnel,
|
|
258
|
+
* or drive the client from something other than a real socket. It is the only
|
|
259
|
+
* seam into the transport: without it the SDK always creates its own.
|
|
260
|
+
*/
|
|
261
|
+
readonly socketFactory?: SocketFactory | undefined;
|
|
262
|
+
/**
|
|
263
|
+
* Reconnect after a dropped connection.
|
|
264
|
+
*
|
|
265
|
+
* Off by default: a silent reconnect makes an outage look like an ordinary
|
|
266
|
+
* session. An explicit `disconnect()` never reconnects regardless.
|
|
267
|
+
*/
|
|
268
|
+
readonly reconnect?: ReconnectOptions | undefined;
|
|
269
|
+
/**
|
|
270
|
+
* Creates the TCP socket a file transfer runs over.
|
|
271
|
+
*
|
|
272
|
+
* Separate from `socketFactory` because file transfer dials its own
|
|
273
|
+
* connection to a different port, on demand. Set both to route everything
|
|
274
|
+
* through a proxy.
|
|
275
|
+
*/
|
|
276
|
+
readonly fileTransferSocketFactory?: FileTransferSocketFactory | undefined;
|
|
277
|
+
/**
|
|
278
|
+
* Look a dot-less address up as a server nickname at named.myteamspeak.com,
|
|
279
|
+
* as the TeamSpeak application does. Off by default, since it sends the name
|
|
280
|
+
* to a third party; without it a dot-less name is resolved like any host.
|
|
281
|
+
* Ignored with a custom `resolver`.
|
|
282
|
+
*/
|
|
283
|
+
readonly resolveNicknames?: boolean | undefined;
|
|
284
|
+
/** Replaces the SRV and TSDNS resolution `connect()` performs. */
|
|
285
|
+
readonly resolver?: AddrResolver | undefined;
|
|
286
|
+
/**
|
|
287
|
+
* Wraps every typed command, outermost first; see `CommandMiddleware`. Raw
|
|
288
|
+
* lines sent with `exec` and `execNoWait` do not pass through it. Fixed for
|
|
289
|
+
* the client's life.
|
|
290
|
+
*/
|
|
291
|
+
readonly commandMiddleware?: readonly CommandMiddleware[] | undefined;
|
|
292
|
+
/** Wraps the delivery of every server event, outermost first. Fixed for the client's life. */
|
|
293
|
+
readonly eventMiddleware?: readonly EventMiddleware[] | undefined;
|
|
115
294
|
/** Server password sent during the initial `clientinit` handshake. */
|
|
116
|
-
serverPassword?: string;
|
|
295
|
+
readonly serverPassword?: string | undefined;
|
|
117
296
|
/** Default channel name to join during the initial `clientinit` handshake. */
|
|
118
|
-
defaultChannel?: string;
|
|
297
|
+
readonly defaultChannel?: string | undefined;
|
|
119
298
|
/** Password for `defaultChannel`, sent during the initial `clientinit` handshake. */
|
|
120
|
-
defaultChannelPassword?: string;
|
|
299
|
+
readonly defaultChannelPassword?: string | undefined;
|
|
121
300
|
}
|
|
301
|
+
export {};
|
|
122
302
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,86 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@honeybbq/teamspeak-client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "TeamSpeak
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
|
+
"description": "A clean-room TeamSpeak client for Node.js, speaking the voice protocol the way the TeamSpeak application does",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"client",
|
|
7
7
|
"sdk",
|
|
8
8
|
"teamspeak",
|
|
9
9
|
"ts3",
|
|
10
|
+
"ts6",
|
|
10
11
|
"voip"
|
|
11
12
|
],
|
|
12
13
|
"license": "MIT",
|
|
13
14
|
"author": "honeybbq",
|
|
14
15
|
"repository": {
|
|
15
16
|
"type": "git",
|
|
16
|
-
"url": "https://github.com/HoneyBBQ/teamspeak-js"
|
|
17
|
+
"url": "git+https://github.com/HoneyBBQ/teamspeak-js.git",
|
|
18
|
+
"directory": "packages/client"
|
|
17
19
|
},
|
|
18
20
|
"files": [
|
|
19
|
-
"dist"
|
|
21
|
+
"dist",
|
|
22
|
+
"src",
|
|
23
|
+
"!src/**/*.test.ts",
|
|
24
|
+
"!src/testing",
|
|
25
|
+
"LICENSE"
|
|
20
26
|
],
|
|
21
27
|
"type": "module",
|
|
28
|
+
"sideEffects": false,
|
|
22
29
|
"exports": {
|
|
23
30
|
".": {
|
|
24
31
|
"types": "./dist/index.d.ts",
|
|
25
|
-
"
|
|
26
|
-
"require": "./dist/index.cjs"
|
|
27
|
-
},
|
|
28
|
-
"./crypto": {
|
|
29
|
-
"types": "./dist/crypto/index.d.ts",
|
|
30
|
-
"import": "./dist/crypto/index.mjs",
|
|
31
|
-
"require": "./dist/crypto/index.cjs"
|
|
32
|
-
},
|
|
33
|
-
"./transport": {
|
|
34
|
-
"types": "./dist/transport/index.d.ts",
|
|
35
|
-
"import": "./dist/transport/index.mjs",
|
|
36
|
-
"require": "./dist/transport/index.cjs"
|
|
37
|
-
},
|
|
38
|
-
"./discovery": {
|
|
39
|
-
"types": "./dist/discovery/index.d.ts",
|
|
40
|
-
"import": "./dist/discovery/index.mjs",
|
|
41
|
-
"require": "./dist/discovery/index.cjs"
|
|
42
|
-
},
|
|
43
|
-
"./command": {
|
|
44
|
-
"types": "./dist/command/index.d.ts",
|
|
45
|
-
"import": "./dist/command/index.mjs",
|
|
46
|
-
"require": "./dist/command/index.cjs"
|
|
47
|
-
},
|
|
48
|
-
"./handshake": {
|
|
49
|
-
"types": "./dist/handshake/index.d.ts",
|
|
50
|
-
"import": "./dist/handshake/index.mjs",
|
|
51
|
-
"require": "./dist/handshake/index.cjs"
|
|
32
|
+
"default": "./dist/index.js"
|
|
52
33
|
}
|
|
53
34
|
},
|
|
54
35
|
"publishConfig": {
|
|
55
36
|
"access": "public"
|
|
56
37
|
},
|
|
57
|
-
"scripts": {
|
|
58
|
-
"build": "vite build && tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
59
|
-
"test": "vitest run",
|
|
60
|
-
"test:watch": "vitest",
|
|
61
|
-
"lint": "oxlint .",
|
|
62
|
-
"fmt": "oxfmt .",
|
|
63
|
-
"fmt:check": "oxfmt --check .",
|
|
64
|
-
"typecheck": "tsc --noEmit",
|
|
65
|
-
"check": "pnpm typecheck && pnpm lint && pnpm fmt:check",
|
|
66
|
-
"prepublishOnly": "pnpm run build",
|
|
67
|
-
"example": "tsx examples/connect.ts",
|
|
68
|
-
"test:integration": "TEAMSPEAK_ADDR=chenkr.cn vitest run src/integration.test.ts --reporter=verbose"
|
|
69
|
-
},
|
|
70
38
|
"dependencies": {
|
|
71
|
-
"@noble/curves": "^2.0.1"
|
|
72
|
-
|
|
73
|
-
"devDependencies": {
|
|
74
|
-
"@types/node": "^26.1.1",
|
|
75
|
-
"oxfmt": "^0.71.0",
|
|
76
|
-
"oxlint": "^1.59.0",
|
|
77
|
-
"tsx": "^4.21.0",
|
|
78
|
-
"typescript": "^7.0.2",
|
|
79
|
-
"vite": "^8.0.8",
|
|
80
|
-
"vitest": "^5.0.0"
|
|
39
|
+
"@noble/curves": "^2.0.1",
|
|
40
|
+
"@honeybbq/teamspeak-core": "1.0.0-beta.1"
|
|
81
41
|
},
|
|
82
42
|
"engines": {
|
|
83
43
|
"node": ">=20.19"
|
|
84
44
|
},
|
|
85
|
-
"
|
|
86
|
-
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "vite build && tsc -p tsconfig.build.json",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"example": "tsx examples/connect.ts"
|
|
49
|
+
},
|
|
50
|
+
"types": "./dist/index.d.ts"
|
|
51
|
+
}
|
package/src/abort.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** The reason an aborted signal gives, as an error. */
|
|
2
|
+
export function abortReason(signal: AbortSignal): unknown {
|
|
3
|
+
return signal.reason ?? new DOMException("This operation was aborted", "AbortError");
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/** Settle with `promise`, or reject as soon as `signal` aborts, whichever is first. */
|
|
7
|
+
export function abortable<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T> {
|
|
8
|
+
if (!signal) return promise;
|
|
9
|
+
if (signal.aborted) return Promise.reject(abortReason(signal));
|
|
10
|
+
return new Promise<T>((resolve, reject) => {
|
|
11
|
+
const onAbort = (): void => reject(abortReason(signal));
|
|
12
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
13
|
+
promise.then(
|
|
14
|
+
(value) => {
|
|
15
|
+
signal.removeEventListener("abort", onAbort);
|
|
16
|
+
resolve(value);
|
|
17
|
+
},
|
|
18
|
+
(error: unknown) => {
|
|
19
|
+
signal.removeEventListener("abort", onAbort);
|
|
20
|
+
reject(error);
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
}
|
package/src/address.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
import { InvalidAddressError } from "./errors.js";
|
|
3
|
+
|
|
4
|
+
export interface HostPort {
|
|
5
|
+
host: string;
|
|
6
|
+
port: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Parse a TeamSpeak address without confusing an IPv6 colon for a port separator. */
|
|
10
|
+
export function splitHostPort(address: string, defaultPort = "9987"): HostPort {
|
|
11
|
+
const input = address.trim();
|
|
12
|
+
if (input.startsWith("[")) {
|
|
13
|
+
const closingBracket = input.indexOf("]");
|
|
14
|
+
if (closingBracket > 0) {
|
|
15
|
+
const host = input.slice(1, closingBracket);
|
|
16
|
+
const suffix = input.slice(closingBracket + 1);
|
|
17
|
+
if (suffix.startsWith(":") && /^\d+$/.test(suffix.slice(1))) {
|
|
18
|
+
return { host, port: suffix.slice(1) };
|
|
19
|
+
}
|
|
20
|
+
if (!suffix) return { host, port: defaultPort };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// A raw IPv6 literal has no unambiguous port separator. Internal callers
|
|
25
|
+
// normally use bracket notation, but accepting the literal with the default
|
|
26
|
+
// port prevents a final IPv6 segment from being mistaken for a port.
|
|
27
|
+
if (isIP(input) === 6) return { host: input, port: defaultPort };
|
|
28
|
+
|
|
29
|
+
const lastColon = input.lastIndexOf(":");
|
|
30
|
+
if (lastColon < 0) return { host: input, port: defaultPort };
|
|
31
|
+
const candidatePort = input.slice(lastColon + 1);
|
|
32
|
+
if (/^\d+$/.test(candidatePort) && input.indexOf(":") === lastColon) {
|
|
33
|
+
return { host: input.slice(0, lastColon), port: candidatePort };
|
|
34
|
+
}
|
|
35
|
+
return { host: input, port: defaultPort };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Characters no host name or IP address contains, whitespace among them. */
|
|
39
|
+
const NOT_IN_A_HOST = /[\s\p{Cc}/?#@[\]\\]/u;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Parse an address to connect to, and check it can be one: a host, which
|
|
43
|
+
* contains nothing a host name or IP address cannot, and a port from 1 to
|
|
44
|
+
* 65535. Throws an InvalidAddressError otherwise.
|
|
45
|
+
*/
|
|
46
|
+
export function parseConnectAddress(address: string): HostPort & { portNumber: number } {
|
|
47
|
+
const { host, port } = splitHostPort(address);
|
|
48
|
+
if (host === "") throw new InvalidAddressError(address, "no host");
|
|
49
|
+
// A colon is left only in an IPv6 literal; anywhere else it is a port that
|
|
50
|
+
// is not a number, which splitHostPort keeps as part of the host.
|
|
51
|
+
if (NOT_IN_A_HOST.test(host) || (host.includes(":") && isIP(host) !== 6)) {
|
|
52
|
+
throw new InvalidAddressError(address, "not a host name, IP address or host:port");
|
|
53
|
+
}
|
|
54
|
+
const portNumber = Number(port);
|
|
55
|
+
if (!Number.isInteger(portNumber) || portNumber < 1 || portNumber > 65535) {
|
|
56
|
+
throw new InvalidAddressError(address, `port ${port} is not from 1 to 65535`);
|
|
57
|
+
}
|
|
58
|
+
return { host, port, portNumber };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function joinHostPort(host: string, port: string): string {
|
|
62
|
+
const normalizedHost = stripBrackets(host);
|
|
63
|
+
return isIP(normalizedHost) === 6 || normalizedHost.includes(":")
|
|
64
|
+
? `[${normalizedHost}]:${port}`
|
|
65
|
+
: `${normalizedHost}:${port}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function isIpAddress(host: string): boolean {
|
|
69
|
+
return isIP(stripBrackets(host)) !== 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function stripBrackets(host: string): string {
|
|
73
|
+
return host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
74
|
+
}
|