@honeybbq/teamspeak 0.0.1 → 1.0.0-beta.7

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.
Files changed (393) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +726 -2
  3. package/dist/client/abort.d.ts +5 -0
  4. package/dist/client/abort.d.ts.map +1 -0
  5. package/dist/client/abort.js +23 -0
  6. package/dist/client/abort.js.map +1 -0
  7. package/dist/client/address.d.ts +17 -0
  8. package/dist/client/address.d.ts.map +1 -0
  9. package/dist/client/address.js +66 -0
  10. package/dist/client/address.js.map +1 -0
  11. package/dist/client/api/voice.d.ts +24 -0
  12. package/dist/client/api/voice.d.ts.map +1 -0
  13. package/dist/client/api/voice.js +33 -0
  14. package/dist/client/api/voice.js.map +1 -0
  15. package/dist/client/capabilities.d.ts +68 -0
  16. package/dist/client/capabilities.d.ts.map +1 -0
  17. package/dist/client/capabilities.js +59 -0
  18. package/dist/client/capabilities.js.map +1 -0
  19. package/dist/client/client.d.ts +196 -0
  20. package/dist/client/client.d.ts.map +1 -0
  21. package/dist/client/client.js +1523 -0
  22. package/dist/client/client.js.map +1 -0
  23. package/dist/client/commands.d.ts +66 -0
  24. package/dist/client/commands.d.ts.map +1 -0
  25. package/dist/client/commands.js +162 -0
  26. package/dist/client/commands.js.map +1 -0
  27. package/dist/client/crypto/crypt-ops.d.ts +7 -0
  28. package/dist/client/crypto/crypt-ops.d.ts.map +1 -0
  29. package/dist/client/crypto/crypt-ops.js +2 -0
  30. package/dist/client/crypto/crypt-ops.js.map +1 -0
  31. package/dist/client/crypto/crypt.d.ts +37 -0
  32. package/dist/client/crypto/crypt.d.ts.map +1 -0
  33. package/dist/client/crypto/crypt.js +203 -0
  34. package/dist/client/crypto/crypt.js.map +1 -0
  35. package/dist/client/crypto/eax.d.ts +12 -0
  36. package/dist/client/crypto/eax.d.ts.map +1 -0
  37. package/dist/client/crypto/eax.js +118 -0
  38. package/dist/client/crypto/eax.js.map +1 -0
  39. package/dist/client/crypto/identity.d.ts +97 -0
  40. package/dist/client/crypto/identity.d.ts.map +1 -0
  41. package/dist/client/crypto/identity.js +412 -0
  42. package/dist/client/crypto/identity.js.map +1 -0
  43. package/dist/client/crypto/index.d.ts +7 -0
  44. package/dist/client/crypto/index.d.ts.map +1 -0
  45. package/dist/client/crypto/index.js +5 -0
  46. package/dist/client/crypto/index.js.map +1 -0
  47. package/dist/client/crypto/primitives.d.ts +43 -0
  48. package/dist/client/crypto/primitives.d.ts.map +1 -0
  49. package/dist/client/crypto/primitives.js +116 -0
  50. package/dist/client/crypto/primitives.js.map +1 -0
  51. package/dist/client/diagnostics.d.ts +45 -0
  52. package/dist/client/diagnostics.d.ts.map +1 -0
  53. package/dist/client/diagnostics.js +30 -0
  54. package/dist/client/diagnostics.js.map +1 -0
  55. package/dist/client/discovery/index.d.ts +2 -0
  56. package/dist/client/discovery/index.d.ts.map +1 -0
  57. package/dist/client/discovery/index.js +2 -0
  58. package/dist/client/discovery/index.js.map +1 -0
  59. package/dist/client/discovery/resolver.d.ts +26 -0
  60. package/dist/client/discovery/resolver.d.ts.map +1 -0
  61. package/dist/client/discovery/resolver.js +275 -0
  62. package/dist/client/discovery/resolver.js.map +1 -0
  63. package/dist/client/errors.d.ts +82 -0
  64. package/dist/client/errors.d.ts.map +1 -0
  65. package/dist/client/errors.js +201 -0
  66. package/dist/client/errors.js.map +1 -0
  67. package/dist/client/events.d.ts +3 -0
  68. package/dist/client/events.d.ts.map +1 -0
  69. package/dist/client/events.js +8 -0
  70. package/dist/client/events.js.map +1 -0
  71. package/dist/client/handshake/crypt-handshake.d.ts +17 -0
  72. package/dist/client/handshake/crypt-handshake.d.ts.map +1 -0
  73. package/dist/client/handshake/crypt-handshake.js +128 -0
  74. package/dist/client/handshake/crypt-handshake.js.map +1 -0
  75. package/dist/client/handshake/crypt-init2.d.ts +7 -0
  76. package/dist/client/handshake/crypt-init2.d.ts.map +1 -0
  77. package/dist/client/handshake/crypt-init2.js +37 -0
  78. package/dist/client/handshake/crypt-init2.js.map +1 -0
  79. package/dist/client/handshake/index.d.ts +4 -0
  80. package/dist/client/handshake/index.d.ts.map +1 -0
  81. package/dist/client/handshake/index.js +4 -0
  82. package/dist/client/handshake/index.js.map +1 -0
  83. package/dist/client/handshake/license.d.ts +35 -0
  84. package/dist/client/handshake/license.d.ts.map +1 -0
  85. package/dist/client/handshake/license.js +169 -0
  86. package/dist/client/handshake/license.js.map +1 -0
  87. package/dist/client/handshake.d.ts +27 -0
  88. package/dist/client/handshake.d.ts.map +1 -0
  89. package/dist/client/handshake.js +126 -0
  90. package/dist/client/handshake.js.map +1 -0
  91. package/dist/client/helpers.d.ts +6 -0
  92. package/dist/client/helpers.d.ts.map +1 -0
  93. package/dist/client/helpers.js +13 -0
  94. package/dist/client/helpers.js.map +1 -0
  95. package/dist/client/hooks.d.ts +7 -0
  96. package/dist/client/hooks.d.ts.map +1 -0
  97. package/dist/client/hooks.js +28 -0
  98. package/dist/client/hooks.js.map +1 -0
  99. package/dist/client/index.d.ts +26 -0
  100. package/dist/client/index.d.ts.map +1 -0
  101. package/dist/client/index.js +28 -0
  102. package/dist/client/index.js.map +1 -0
  103. package/dist/client/reconnect.d.ts +12 -0
  104. package/dist/client/reconnect.d.ts.map +1 -0
  105. package/dist/client/reconnect.js +44 -0
  106. package/dist/client/reconnect.js.map +1 -0
  107. package/dist/client/throttle.d.ts +20 -0
  108. package/dist/client/throttle.d.ts.map +1 -0
  109. package/dist/client/throttle.js +83 -0
  110. package/dist/client/throttle.js.map +1 -0
  111. package/dist/client/trace.d.ts +223 -0
  112. package/dist/client/trace.d.ts.map +1 -0
  113. package/dist/client/trace.js +13 -0
  114. package/dist/client/trace.js.map +1 -0
  115. package/dist/client/transfer.d.ts +111 -0
  116. package/dist/client/transfer.d.ts.map +1 -0
  117. package/dist/client/transfer.js +243 -0
  118. package/dist/client/transfer.js.map +1 -0
  119. package/dist/client/transport/generation-window.d.ts +30 -0
  120. package/dist/client/transport/generation-window.d.ts.map +1 -0
  121. package/dist/client/transport/generation-window.js +97 -0
  122. package/dist/client/transport/generation-window.js.map +1 -0
  123. package/dist/client/transport/handler.d.ts +61 -0
  124. package/dist/client/transport/handler.d.ts.map +1 -0
  125. package/dist/client/transport/handler.js +793 -0
  126. package/dist/client/transport/handler.js.map +1 -0
  127. package/dist/client/transport/index.d.ts +6 -0
  128. package/dist/client/transport/index.d.ts.map +1 -0
  129. package/dist/client/transport/index.js +5 -0
  130. package/dist/client/transport/index.js.map +1 -0
  131. package/dist/client/transport/packet.d.ts +36 -0
  132. package/dist/client/transport/packet.d.ts.map +1 -0
  133. package/dist/client/transport/packet.js +55 -0
  134. package/dist/client/transport/packet.js.map +1 -0
  135. package/dist/client/transport/quicklz.d.ts +24 -0
  136. package/dist/client/transport/quicklz.d.ts.map +1 -0
  137. package/dist/client/transport/quicklz.js +179 -0
  138. package/dist/client/transport/quicklz.js.map +1 -0
  139. package/dist/client/types.d.ts +226 -0
  140. package/dist/client/types.d.ts.map +1 -0
  141. package/dist/client/types.js +39 -0
  142. package/dist/client/types.js.map +1 -0
  143. package/dist/core/api/channels.d.ts +182 -0
  144. package/dist/core/api/channels.d.ts.map +1 -0
  145. package/dist/core/api/channels.js +155 -0
  146. package/dist/core/api/channels.js.map +1 -0
  147. package/dist/core/api/clients.d.ts +304 -0
  148. package/dist/core/api/clients.d.ts.map +1 -0
  149. package/dist/core/api/clients.js +260 -0
  150. package/dist/core/api/clients.js.map +1 -0
  151. package/dist/core/api/command.d.ts +305 -0
  152. package/dist/core/api/command.d.ts.map +1 -0
  153. package/dist/core/api/command.js +363 -0
  154. package/dist/core/api/command.js.map +1 -0
  155. package/dist/core/api/files.d.ts +153 -0
  156. package/dist/core/api/files.d.ts.map +1 -0
  157. package/dist/core/api/files.js +181 -0
  158. package/dist/core/api/files.js.map +1 -0
  159. package/dist/core/api/groups.d.ts +248 -0
  160. package/dist/core/api/groups.d.ts.map +1 -0
  161. package/dist/core/api/groups.js +271 -0
  162. package/dist/core/api/groups.js.map +1 -0
  163. package/dist/core/api/moderation.d.ts +205 -0
  164. package/dist/core/api/moderation.d.ts.map +1 -0
  165. package/dist/core/api/moderation.js +209 -0
  166. package/dist/core/api/moderation.js.map +1 -0
  167. package/dist/core/api/parse.d.ts +16 -0
  168. package/dist/core/api/parse.d.ts.map +1 -0
  169. package/dist/core/api/parse.js +40 -0
  170. package/dist/core/api/parse.js.map +1 -0
  171. package/dist/core/api/server.d.ts +310 -0
  172. package/dist/core/api/server.d.ts.map +1 -0
  173. package/dist/core/api/server.js +290 -0
  174. package/dist/core/api/server.js.map +1 -0
  175. package/dist/core/command/command.d.ts +20 -0
  176. package/dist/core/command/command.d.ts.map +1 -0
  177. package/dist/core/command/command.js +112 -0
  178. package/dist/core/command/command.js.map +1 -0
  179. package/dist/core/command/ids.d.ts +125 -0
  180. package/dist/core/command/ids.d.ts.map +1 -0
  181. package/dist/core/command/ids.js +85 -0
  182. package/dist/core/command/ids.js.map +1 -0
  183. package/dist/core/command/parser.d.ts +17 -0
  184. package/dist/core/command/parser.d.ts.map +1 -0
  185. package/dist/core/command/parser.js +65 -0
  186. package/dist/core/command/parser.js.map +1 -0
  187. package/dist/core/command/request.d.ts +61 -0
  188. package/dist/core/command/request.d.ts.map +1 -0
  189. package/dist/core/command/request.js +64 -0
  190. package/dist/core/command/request.js.map +1 -0
  191. package/dist/core/command/responses.d.ts +59 -0
  192. package/dist/core/command/responses.d.ts.map +1 -0
  193. package/dist/core/command/responses.js +74 -0
  194. package/dist/core/command/responses.js.map +1 -0
  195. package/dist/core/command-name.d.ts +333 -0
  196. package/dist/core/command-name.d.ts.map +1 -0
  197. package/dist/core/command-name.js +331 -0
  198. package/dist/core/command-name.js.map +1 -0
  199. package/dist/core/enums.d.ts +146 -0
  200. package/dist/core/enums.d.ts.map +1 -0
  201. package/dist/core/enums.js +132 -0
  202. package/dist/core/enums.js.map +1 -0
  203. package/dist/core/errorcode.d.ts +413 -0
  204. package/dist/core/errorcode.d.ts.map +1 -0
  205. package/dist/core/errorcode.js +410 -0
  206. package/dist/core/errorcode.js.map +1 -0
  207. package/dist/core/errors.d.ts +111 -0
  208. package/dist/core/errors.d.ts.map +1 -0
  209. package/dist/core/errors.js +233 -0
  210. package/dist/core/errors.js.map +1 -0
  211. package/dist/core/events.d.ts +207 -0
  212. package/dist/core/events.d.ts.map +1 -0
  213. package/dist/core/events.js +6 -0
  214. package/dist/core/events.js.map +1 -0
  215. package/dist/core/helpers.d.ts +42 -0
  216. package/dist/core/helpers.d.ts.map +1 -0
  217. package/dist/core/helpers.js +156 -0
  218. package/dist/core/helpers.js.map +1 -0
  219. package/dist/core/index.d.ts +35 -0
  220. package/dist/core/index.d.ts.map +1 -0
  221. package/dist/core/index.js +34 -0
  222. package/dist/core/index.js.map +1 -0
  223. package/dist/core/internal.d.ts +23 -0
  224. package/dist/core/internal.d.ts.map +1 -0
  225. package/dist/core/internal.js +20 -0
  226. package/dist/core/internal.js.map +1 -0
  227. package/dist/core/middleware.d.ts +14 -0
  228. package/dist/core/middleware.d.ts.map +1 -0
  229. package/dist/core/middleware.js +18 -0
  230. package/dist/core/middleware.js.map +1 -0
  231. package/dist/core/notification-name.d.ts +154 -0
  232. package/dist/core/notification-name.d.ts.map +1 -0
  233. package/dist/core/notification-name.js +152 -0
  234. package/dist/core/notification-name.js.map +1 -0
  235. package/dist/core/notifications.d.ts +43 -0
  236. package/dist/core/notifications.d.ts.map +1 -0
  237. package/dist/core/notifications.js +116 -0
  238. package/dist/core/notifications.js.map +1 -0
  239. package/dist/core/permission-name.d.ts +533 -0
  240. package/dist/core/permission-name.d.ts.map +1 -0
  241. package/dist/core/permission-name.js +531 -0
  242. package/dist/core/permission-name.js.map +1 -0
  243. package/dist/core/permission.d.ts +31 -0
  244. package/dist/core/permission.d.ts.map +1 -0
  245. package/dist/core/permission.js +20 -0
  246. package/dist/core/permission.js.map +1 -0
  247. package/dist/core/property-name.d.ts +403 -0
  248. package/dist/core/property-name.d.ts.map +1 -0
  249. package/dist/core/property-name.js +405 -0
  250. package/dist/core/property-name.js.map +1 -0
  251. package/dist/core/reason.d.ts +39 -0
  252. package/dist/core/reason.d.ts.map +1 -0
  253. package/dist/core/reason.js +36 -0
  254. package/dist/core/reason.js.map +1 -0
  255. package/dist/core/reconnect.d.ts +59 -0
  256. package/dist/core/reconnect.d.ts.map +1 -0
  257. package/dist/core/reconnect.js +55 -0
  258. package/dist/core/reconnect.js.map +1 -0
  259. package/dist/core/types.d.ts +110 -0
  260. package/dist/core/types.d.ts.map +1 -0
  261. package/dist/core/types.js +27 -0
  262. package/dist/core/types.js.map +1 -0
  263. package/dist/query/client.d.ts +194 -0
  264. package/dist/query/client.d.ts.map +1 -0
  265. package/dist/query/client.js +967 -0
  266. package/dist/query/client.js.map +1 -0
  267. package/dist/query/errors.d.ts +61 -0
  268. package/dist/query/errors.d.ts.map +1 -0
  269. package/dist/query/errors.js +100 -0
  270. package/dist/query/errors.js.map +1 -0
  271. package/dist/query/index.d.ts +36 -0
  272. package/dist/query/index.d.ts.map +1 -0
  273. package/dist/query/index.js +34 -0
  274. package/dist/query/index.js.map +1 -0
  275. package/dist/query/knownhosts.d.ts +61 -0
  276. package/dist/query/knownhosts.d.ts.map +1 -0
  277. package/dist/query/knownhosts.js +223 -0
  278. package/dist/query/knownhosts.js.map +1 -0
  279. package/dist/query/lines.d.ts +14 -0
  280. package/dist/query/lines.d.ts.map +1 -0
  281. package/dist/query/lines.js +29 -0
  282. package/dist/query/lines.js.map +1 -0
  283. package/dist/query/options.d.ts +187 -0
  284. package/dist/query/options.d.ts.map +1 -0
  285. package/dist/query/options.js +213 -0
  286. package/dist/query/options.js.map +1 -0
  287. package/dist/query/reconnect.d.ts +29 -0
  288. package/dist/query/reconnect.d.ts.map +1 -0
  289. package/dist/query/reconnect.js +87 -0
  290. package/dist/query/reconnect.js.map +1 -0
  291. package/dist/query/ssh.d.ts +345 -0
  292. package/dist/query/ssh.d.ts.map +1 -0
  293. package/dist/query/ssh.js +241 -0
  294. package/dist/query/ssh.js.map +1 -0
  295. package/dist/query/stream.d.ts +38 -0
  296. package/dist/query/stream.d.ts.map +1 -0
  297. package/dist/query/stream.js +70 -0
  298. package/dist/query/stream.js.map +1 -0
  299. package/dist/query/tcp.d.ts +38 -0
  300. package/dist/query/tcp.d.ts.map +1 -0
  301. package/dist/query/tcp.js +53 -0
  302. package/dist/query/tcp.js.map +1 -0
  303. package/dist/query/transport.d.ts +36 -0
  304. package/dist/query/transport.d.ts.map +1 -0
  305. package/dist/query/transport.js +2 -0
  306. package/dist/query/transport.js.map +1 -0
  307. package/dist/query/web.d.ts +54 -0
  308. package/dist/query/web.d.ts.map +1 -0
  309. package/dist/query/web.js +146 -0
  310. package/dist/query/web.js.map +1 -0
  311. package/dist/versions/index.d.ts +3094 -0
  312. package/dist/versions/index.d.ts.map +1 -0
  313. package/dist/versions/index.js +9237 -0
  314. package/dist/versions/index.js.map +1 -0
  315. package/package.json +118 -4
  316. package/src/client/abort.ts +24 -0
  317. package/src/client/address.ts +74 -0
  318. package/src/client/api/voice.ts +61 -0
  319. package/src/client/capabilities.ts +106 -0
  320. package/src/client/client.ts +1809 -0
  321. package/src/client/commands.ts +193 -0
  322. package/src/client/crypto/crypt-ops.ts +6 -0
  323. package/src/client/crypto/crypt.ts +275 -0
  324. package/src/client/crypto/eax.ts +152 -0
  325. package/src/client/crypto/identity.ts +484 -0
  326. package/src/client/crypto/index.ts +21 -0
  327. package/src/client/crypto/primitives.ts +141 -0
  328. package/src/client/diagnostics.ts +58 -0
  329. package/src/client/discovery/index.ts +1 -0
  330. package/src/client/discovery/resolver.ts +325 -0
  331. package/src/client/errors.ts +217 -0
  332. package/src/client/events.ts +12 -0
  333. package/src/client/handshake/crypt-handshake.ts +157 -0
  334. package/src/client/handshake/crypt-init2.ts +48 -0
  335. package/src/client/handshake/index.ts +3 -0
  336. package/src/client/handshake/license.ts +208 -0
  337. package/src/client/handshake.ts +150 -0
  338. package/src/client/helpers.ts +10 -0
  339. package/src/client/hooks.ts +30 -0
  340. package/src/client/index.ts +93 -0
  341. package/src/client/reconnect.ts +43 -0
  342. package/src/client/throttle.ts +92 -0
  343. package/src/client/trace.ts +237 -0
  344. package/src/client/transfer.ts +436 -0
  345. package/src/client/transport/generation-window.ts +108 -0
  346. package/src/client/transport/handler.ts +926 -0
  347. package/src/client/transport/index.ts +14 -0
  348. package/src/client/transport/packet.ts +69 -0
  349. package/src/client/transport/quicklz.ts +209 -0
  350. package/src/client/types.ts +268 -0
  351. package/src/core/api/channels.ts +396 -0
  352. package/src/core/api/clients.ts +654 -0
  353. package/src/core/api/command.ts +563 -0
  354. package/src/core/api/files.ts +405 -0
  355. package/src/core/api/groups.ts +622 -0
  356. package/src/core/api/moderation.ts +525 -0
  357. package/src/core/api/parse.ts +52 -0
  358. package/src/core/api/server.ts +709 -0
  359. package/src/core/command/command.ts +125 -0
  360. package/src/core/command/ids.ts +149 -0
  361. package/src/core/command/parser.ts +68 -0
  362. package/src/core/command/request.ts +119 -0
  363. package/src/core/command/responses.ts +114 -0
  364. package/src/core/command-name.ts +334 -0
  365. package/src/core/enums.ts +167 -0
  366. package/src/core/errorcode.ts +412 -0
  367. package/src/core/errors.ts +258 -0
  368. package/src/core/events.ts +219 -0
  369. package/src/core/helpers.ts +161 -0
  370. package/src/core/index.ts +126 -0
  371. package/src/core/internal.ts +23 -0
  372. package/src/core/middleware.ts +24 -0
  373. package/src/core/notification-name.ts +155 -0
  374. package/src/core/notifications.ts +157 -0
  375. package/src/core/permission-name.ts +538 -0
  376. package/src/core/permission.ts +34 -0
  377. package/src/core/property-name.ts +411 -0
  378. package/src/core/reason.ts +38 -0
  379. package/src/core/reconnect.ts +98 -0
  380. package/src/core/types.ts +138 -0
  381. package/src/query/client.ts +1132 -0
  382. package/src/query/errors.ts +108 -0
  383. package/src/query/index.ts +65 -0
  384. package/src/query/knownhosts.ts +257 -0
  385. package/src/query/lines.ts +28 -0
  386. package/src/query/options.ts +388 -0
  387. package/src/query/reconnect.ts +84 -0
  388. package/src/query/ssh.ts +614 -0
  389. package/src/query/stream.ts +91 -0
  390. package/src/query/tcp.ts +85 -0
  391. package/src/query/transport.ts +35 -0
  392. package/src/query/web.ts +195 -0
  393. package/src/versions/index.ts +10774 -0
package/README.md CHANGED
@@ -1,3 +1,727 @@
1
- # Temporary Holding Version
1
+ <div align="center">
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # @honeybbq/teamspeak
4
+
5
+ **A clean-room TeamSpeak client protocol library written in pure TypeScript.**
6
+
7
+ Works with TeamSpeak 3 and TeamSpeak 6 servers. No proprietary SDK, no copied code.
8
+
9
+ [![CI](https://github.com/honeybbq/teamspeak-js/actions/workflows/ci.yml/badge.svg)](https://github.com/honeybbq/teamspeak-js/actions/workflows/ci.yml)
10
+ [![npm](https://img.shields.io/npm/v/@honeybbq/teamspeak)](https://www.npmjs.com/package/@honeybbq/teamspeak)
11
+ [![npm beta](https://img.shields.io/npm/v/@honeybbq/teamspeak/beta?label=beta)](https://www.npmjs.com/package/@honeybbq/teamspeak?activeTab=versions)
12
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/HoneyBBQ/teamspeak-js/badge)](https://scorecard.dev/viewer/?uri=github.com/HoneyBBQ/teamspeak-js)
13
+ [![Node Version](https://img.shields.io/node/v/@honeybbq/teamspeak)](https://github.com/HoneyBBQ/teamspeak-js/blob/main/package.json)
14
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/HoneyBBQ/teamspeak-js/blob/main/LICENSE)
15
+
16
+ </div>
17
+
18
+ **[API reference](https://honeybbq.github.io/teamspeak-js/)**
19
+
20
+ Upgrading from 0.x? The package was renamed; see the [migration guide](https://github.com/HoneyBBQ/teamspeak-js/blob/main/docs/migrating-to-1.0.md).
21
+
22
+ ## Features
23
+
24
+ - **Full protocol handshake** — ECDH key exchange, RSA puzzle, EAX-encrypted transport
25
+ - **Command & notification system** — Send commands, receive server events
26
+ - **Event-driven API** — Register handlers for text messages, client enter/leave, channel moves, kicks, etc.
27
+ - **Voice data** — Send Opus voice packets (codec 4 & 5)
28
+ - **File transfers** — Upload, download, and delete files on the server
29
+ - **Address resolution** — SRV records, TSDNS, and direct addresses; server nicknames on request (`nicknameLookup: true`), since that lookup goes to named.myteamspeak.com
30
+ - **Middleware** — Pluggable command and event middleware chains
31
+ - **Built-in rate limiter** — Token-bucket throttling to prevent server-side flood kicks
32
+ - **Identity management** — Generate, import/export, and upgrade security level of identities
33
+ - **Full command set** — 111 typed functions covering every command the voice protocol answers
34
+ - **Reconnection** — Opt-in retry with backoff, tuned for TeamSpeak's antiflood ban
35
+ - **Server capabilities** — Reports the server version and the uid hash it uses (SHA-1 on TS3, SHA-256 on TS6), and the server's name, icon, banner and welcome message
36
+ - **Custom transports** — Supply your own socket, for proxies, tunnels or tests
37
+ - **ESM with types** — Ships ES modules with full TypeScript declarations
38
+ - **Zero native deps** — Pure TypeScript, no native addons required
39
+
40
+ ## Installation
41
+
42
+ 1.0 is in beta, published under the `beta` tag. A plain `npm install` still
43
+ gets 0.3, so ask for the beta:
44
+
45
+ ```bash
46
+ npm install @honeybbq/teamspeak@beta
47
+ # or
48
+ pnpm add @honeybbq/teamspeak@beta
49
+ ```
50
+
51
+ Everything in this README is the 1.0 API. You need Node.js 22.12 or newer.
52
+
53
+ ## Quick Start
54
+
55
+ ```typescript
56
+ import { Client, generateIdentity } from "@honeybbq/teamspeak/client";
57
+
58
+ // Generate a new identity (or load an existing one)
59
+ const identity = await generateIdentity(8);
60
+
61
+ // Create the client
62
+ const client = new Client(identity, "localhost", "TSBot", {
63
+ serverPassword: process.env.TEAMSPEAK_SERVER_PASSWORD,
64
+ defaultChannel: "Lobby",
65
+ defaultChannelPassword: process.env.TEAMSPEAK_DEFAULT_CHANNEL_PASSWORD,
66
+ });
67
+
68
+ // Register event handlers
69
+ client.on("connected", ({ reconnected }) => {
70
+ console.log(reconnected ? "Reconnected to server!" : "Connected to server!");
71
+ });
72
+
73
+ client.on("textMessage", (msg) => {
74
+ console.log(`[${msg.invokerName}]: ${msg.message}`);
75
+ });
76
+
77
+ client.on("disconnected", ({ error, willReconnect }) => {
78
+ console.log("Disconnected:", error?.message ?? "clean", willReconnect ? "(reconnecting)" : "");
79
+ });
80
+
81
+ // Connect; resolves once the handshake completes.
82
+ await client.connect({ signal: AbortSignal.timeout(15_000) });
83
+
84
+ // Stay connected until interrupted
85
+ process.on("SIGINT", async () => {
86
+ await client.disconnect();
87
+ });
88
+ ```
89
+
90
+ ## API Overview
91
+
92
+ ### Client Lifecycle
93
+
94
+ | Method | Description |
95
+ | --------------------------------------------- | ------------------------------------------------- |
96
+ | `new Client(identity, addr, nickname, opts?)` | Create a new client |
97
+ | `connect({ signal? })` | Connect; resolves once the handshake completes |
98
+ | `disconnect({ signal? })` | Leave the server and close the connection |
99
+ | `status` | `"disconnected"`, `"connecting"` or `"connected"` |
100
+ | `clientID` | Our clid, assigned by the server |
101
+ | `channelID` | The channel we are in |
102
+ | `serverCapabilities` | Server version, family and uid hash |
103
+ | `uid` | Our own uid, hashed as the server does |
104
+
105
+ `connect()` rejects with an `InvalidAddressError` for an address that cannot be
106
+ one — no host, or a port outside 1–65535 — before anything starts; a host name
107
+ that does not resolve fails with a `TeamspeakError` whose `cause` is the lookup's
108
+ error. A `connect()` called while `disconnect()` is still saying goodbye waits
109
+ for it to finish, then connects.
110
+
111
+ Commands, raw `exec`/`execNoWait`, voice and whispers need a connected client:
112
+ until `connect()` resolves, and from the moment `disconnect()` begins, they fail
113
+ with a `NotConnectedError` and send nothing.
114
+
115
+ ### Events
116
+
117
+ Name an event with an `EventName` constant, or with its string: the two are the
118
+ same, and the listener's payload type follows either.
119
+
120
+ ```typescript
121
+ import { EventName } from "@honeybbq/teamspeak/client";
122
+
123
+ client.on(EventName.TextMessage, (message) => console.log(message.message));
124
+ client.on("textMessage", (message) => console.log(message.message)); // the same
125
+ ```
126
+
127
+ | Method | Description |
128
+ | ----------------------------- | --------------------------------------------- |
129
+ | `on("connected", handler)` | Fires when fully connected (`ConnectedEvent`) |
130
+ | `on("disconnected", handler)` | Fires on disconnect (`DisconnectedEvent`) |
131
+ | `on("textMessage", handler)` | Fires on text messages |
132
+ | `on("clientEnter", handler)` | Fires when a client joins |
133
+ | `on("clientLeave", handler)` | Fires when a client leaves |
134
+ | `on("clientMoved", handler)` | Fires when a client moves channels |
135
+ | `on("kicked", handler)` | Fires when the bot is kicked |
136
+ | `on("poked", handler)` | Fires when poked by a client |
137
+ | `on("voiceData", handler)` | Fires on incoming voice data |
138
+
139
+ `on()` and `once()` return a function that removes the listener, which is also
140
+ a `Disposable` (`using listener = client.on(...)`). Listeners run one at a
141
+ time, in the order their events arrived, so a listener may call the client and
142
+ await an answer. `disconnected` delivers `undefined` after `disconnect()`, and
143
+ the cause otherwise — a `ConnectionTimeoutError`, or a `RemovedError` for a kick, a ban
144
+ or a server stopping. `await using client = new Client(...)` disconnects when
145
+ the scope ends.
146
+
147
+ `connected` is delivered after `connect()` resolves, so a listener added right
148
+ after `await client.connect()` still hears it. `disconnect()` waits a second at
149
+ most for the server to acknowledge its goodbye, less if its `signal` aborts
150
+ sooner, and resolves once `disconnected` has been delivered. A `connect()` waits
151
+ for an earlier session's `disconnected` to be delivered before it starts, so no
152
+ listener or `events()` iterator of the new session hears the old one end.
153
+
154
+ A listener that throws does not stop the others: the event still reaches the
155
+ listeners after it, and the exception surfaces as an `uncaughtException`, as an
156
+ EventEmitter listener's would.
157
+
158
+ Voice is the exception to "every event in order": while more than 256
159
+ deliveries are waiting, voice frames are dropped (and counted in a warning at
160
+ most every ten seconds) rather than queued without bound.
161
+
162
+ `events(name, { signal })` is the same as an async iterator, buffering events
163
+ that arrive while the loop body runs. The buffer is unbounded (voice excepted,
164
+ as above), so stop iterating when you stop reading. Aborting `signal` stops
165
+ listening and makes the pending and later `next()` calls reject with the
166
+ signal's reason, as Node's `events.on` does; `break`ing out of the loop, or a
167
+ disconnect, ends it normally:
168
+
169
+ ```typescript
170
+ for await (const msg of client.events("textMessage", { signal })) {
171
+ await reply(msg);
172
+ }
173
+ ```
174
+
175
+ `notification` is the catch-all: it delivers every notification the server
176
+ sends, as it arrived, the ones that also have a typed event among them, after
177
+ that event. It is how to reach one the SDK does not model; `NotificationName`
178
+ names the known ones:
179
+
180
+ ```typescript
181
+ import { NotificationName } from "@honeybbq/teamspeak";
182
+
183
+ client.on("notification", (n) => {
184
+ if (n.name === NotificationName.ChannelEdited) console.log(n.params);
185
+ });
186
+ ```
187
+
188
+ ### Commands
189
+
190
+ Every command the voice protocol answers is a typed function, grouped by area.
191
+ Each is addressed by branded ids, so a `ChannelID` cannot be passed where a
192
+ `ClientID` is meant. The constructors — `asChannelID(5)`, `asClientID(3)` and
193
+ the rest — throw a `RangeError` for anything but an integer in the id's wire
194
+ range: 0–65535 for a `ClientID` and the file transfer ids, 0–2^32−1 for a
195
+ `PermissionID` (an `IconID` also takes the signed form), 0–2^64−1 for the
196
+ `bigint` ids. Required arguments are positional; everything optional
197
+ goes in one options object, always the last argument, which also carries
198
+ `signal` and `timeoutMs` to abandon the command or bound how long it waits.
199
+
200
+ ```typescript
201
+ import {
202
+ listChannels,
203
+ createChannel,
204
+ moveClient,
205
+ kickClient,
206
+ sendChannelMessage,
207
+ addServerGroupPermission,
208
+ iterateClientDatabase,
209
+ permissionByName,
210
+ PermissionName,
211
+ asClientID,
212
+ Codec,
213
+ Reason,
214
+ } from "@honeybbq/teamspeak";
215
+
216
+ const channels = await listChannels(client, { signal: AbortSignal.timeout(5_000) });
217
+
218
+ const cid = await createChannel(client, {
219
+ name: "Lounge",
220
+ topic: "the quiet one",
221
+ codec: Codec.OpusVoice,
222
+ isPermanent: true,
223
+ });
224
+
225
+ await moveClient(client, client.clientID, cid, { password: "channel-password" });
226
+ await sendChannelMessage(client, "hello");
227
+ await kickClient(client, someone, Reason.KickChannel, { reasonMessage: "take a break" });
228
+
229
+ await addServerGroupPermission(client, sgid, permissionByName(PermissionName.ClientTalkPower), 50, {
230
+ skip: true,
231
+ });
232
+
233
+ for await (const entry of iterateClientDatabase(client)) {
234
+ console.log(entry.nickname, entry.lastConnectedAt);
235
+ }
236
+ ```
237
+
238
+ A command that sends content — `createChannel`'s channel, `editChannel`'s
239
+ settings, `updateClient`, `editClient`, `editClientDatabase`,
240
+ `addBan`'s `BanFields` — takes it as its own
241
+ argument, and `{ signal, timeoutMs }` as a separate one after it: set among the
242
+ content, they are not read.
243
+
244
+ Options objects use camelCase names (`maxClients` for `channel_maxclients`),
245
+ and only the fields you set are sent: an unset field leaves the setting alone,
246
+ while `""` sends it empty — `editChannel(client, cid, { password: "" })` clears
247
+ a password. A key an options type does not name is never sent. The exceptions
248
+ are `editServer` and `editInstance`, which take the raw `virtualserver_*` and
249
+ `serverinstance_*` properties as `getServerInfo` reports them; `PropertyName` names
250
+ the keys.
251
+
252
+ Results are camelCase too. Timestamps are `Date`s (`undefined` where the server
253
+ sends 0 for "never"), durations are milliseconds with an `Ms` suffix
254
+ (`idleTimeMs`, `durationMs`), and a permission is a `Permission`, built with
255
+ `permissionByID` or `permissionByName`. Small enumerations — `GroupType`,
256
+ `Codec`, `PrivilegeKeyType`, `LogLevel` and the rest — are objects of named values with
257
+ a type of the same name.
258
+
259
+ | Module | Covers |
260
+ | ------------ | -------------------------------------------------------------- |
261
+ | `channels` | Create, edit, move, delete, subscribe, channel permissions |
262
+ | `clients` | List, move, kick, poke, edit, the client database, permissions |
263
+ | `server` | Server and instance settings, groups, temp passwords, bindings |
264
+ | `groups` | Channel groups, the permission catalogue, privilege keys |
265
+ | `moderation` | Bans, complaints, offline messages, text messages, the log |
266
+ | `files` | List, delete, rename, create directories, transfer negotiation |
267
+
268
+ Many of these commands are answered over the voice protocol with a
269
+ notification rather than data rows — `servergrouplist` with
270
+ `notifyservergrouplist`, `ftinitupload` with `notifystartupload` after the
271
+ command has already succeeded. The client pairs each answer with its command,
272
+ so this is invisible to callers; [docs/voice-protocol-responses.md](https://github.com/HoneyBBQ/teamspeak-js/blob/main/docs/voice-protocol-responses.md)
273
+ has the measured table. A refusal is always thrown, never returned as an empty
274
+ result. A list or find with nothing to report answers `[]`. A command that
275
+ exists to return something — `createChannel`'s id, `initFileUpload`'s key,
276
+ `getClientProperties`'s fields — throws a `NoDataError` when the server answers
277
+ without it, rather than returning an id of 0 or an empty object.
278
+
279
+ For anything outside the typed set, `client.exec(line, { signal?, timeoutMs? })`
280
+ sends a raw command line and resolves to the rows that answer it.
281
+
282
+ ### File Transfers
283
+
284
+ Negotiate with the `files` module, then move the bytes over TCP:
285
+
286
+ ```typescript
287
+ import { Readable } from "node:stream";
288
+ import { initFileUpload } from "@honeybbq/teamspeak";
289
+
290
+ const info = await initFileUpload(client, cid, "/notes.txt", BigInt(data.length));
291
+ await client.uploadFileData(host, info, Readable.from([data]));
292
+ ```
293
+
294
+ An upload does not replace a file already at the path unless passed
295
+ `{ overwrite: true }`.
296
+
297
+ | Function | Description |
298
+ | ---------------------------------------------------- | --------------------------------- |
299
+ | `initFileUpload(client, ...)` | Negotiate an upload |
300
+ | `initFileDownload(client, ...)` | Negotiate a download |
301
+ | `client.uploadFileData(host, info, data, options?)` | Transfer file data to the server |
302
+ | `client.downloadFileData(host, info, out, options?)` | Receive file data from the server |
303
+
304
+ The transfer functions take `FileTransferOptions`:
305
+
306
+ | Option | Description |
307
+ | --------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
308
+ | `signal` | An `AbortSignal` that abandons the transfer; it rejects with the signal's reason |
309
+ | `socketFactory` | Opens the connection instead of a direct TCP dial, to route it through a proxy or tunnel |
310
+ | `trace` | Hooks called at each milestone of the transfer (`dialStart`, `dialDone`, `progress`, `done`, `failed`); none sees the transfer key |
311
+ | `idleTimeoutMs` | The longest, in milliseconds, a transfer may go without moving a byte, the key write included. Default 30 000; `0` disables it |
312
+
313
+ A transfer that goes idle for `idleTimeoutMs` fails with a `FileTransferError`
314
+ whose `cause` is a `TimeoutError`, and its connection is destroyed. A download
315
+ that sends more bytes than the negotiated size, or ends short of it, fails with
316
+ a `FileTransferError` too; bytes past the announced size are never written.
317
+
318
+ ### Identity
319
+
320
+ ```typescript
321
+ import { generateIdentity, parseIdentity } from "@honeybbq/teamspeak/client";
322
+
323
+ // Generate a new identity with security level 8
324
+ const identity = await generateIdentity(8);
325
+
326
+ // Export to string for persistent storage
327
+ const exported = identity.export();
328
+
329
+ // Import from a previously exported string
330
+ const restored = parseIdentity(exported);
331
+
332
+ // Raise the security level (CPU-intensive). Identities are immutable: this
333
+ // returns a new one with the same key.
334
+ const stronger = await identity.upgradeToLevel(10, { signal });
335
+
336
+ // The unique identifier, hashed as a TS3 (sha1) or TS6 (sha256) server does
337
+ const uid = identity.uid("sha1");
338
+ ```
339
+
340
+ The private key never leaves the identity except through `export()`:
341
+ `toString()`, `toJSON()` and `util.inspect()` describe it without the key.
342
+ `parseIdentity` takes exactly what `export()` writes — the key as canonical
343
+ base64 of at most 32 bytes, a colon, and a decimal offset that fits in 64 bits
344
+ — and throws an `InvalidIdentityError` for anything else.
345
+
346
+ ### Options
347
+
348
+ ```typescript
349
+ import { Client } from "@honeybbq/teamspeak/client";
350
+ import { consoleLogger } from "@honeybbq/teamspeak";
351
+
352
+ const client = new Client(identity, "ts.example.com", "Bot", {
353
+ logger: consoleLogger, // silent unless set
354
+ resolver: customResolver,
355
+ commandMiddleware: [timing],
356
+ eventMiddleware: [filterMiddleware],
357
+ serverPassword: process.env.TEAMSPEAK_SERVER_PASSWORD,
358
+ defaultChannel: "Lobby",
359
+ defaultChannelPassword: process.env.TEAMSPEAK_DEFAULT_CHANNEL_PASSWORD,
360
+ });
361
+ ```
362
+
363
+ Address resolution — the built-in one or a custom `resolver` — has ten seconds
364
+ in all: the `signal` a resolver is given aborts then, and the client connects
365
+ to the address as given.
366
+
367
+ `commandMiddleware` wraps the typed commands: each middleware receives the
368
+ request (its command name and parameters) with its options and returns the
369
+ answering rows, so it can time, retry or answer a command itself. Raw `exec`
370
+ and `execNoWait` lines do not pass through it.
371
+
372
+ ```typescript
373
+ import type { CommandMiddleware } from "@honeybbq/teamspeak";
374
+
375
+ const timing: CommandMiddleware = (next) => async (request, options) => {
376
+ const started = Date.now();
377
+ try {
378
+ return await next(request, options);
379
+ } finally {
380
+ console.log(request.command, Date.now() - started, "ms");
381
+ }
382
+ };
383
+ ```
384
+
385
+ Connection auth options:
386
+
387
+ - `serverPassword`: plain-text server password; sent as the TeamSpeak protocol hash during `clientinit`
388
+ - `defaultChannel`: default channel name requested during `clientinit`
389
+ - `defaultChannelPassword`: plain-text password for `defaultChannel`; sent as the TeamSpeak protocol hash
390
+
391
+ ### Client version
392
+
393
+ By default `clientinit` sends a recent Windows version. The `version` option
394
+ sends another, and `@honeybbq/teamspeak/versions` has one export for each
395
+ version that is known to work, named `<Platform>_<version>_<build>`:
396
+
397
+ ```typescript
398
+ import { Client } from "@honeybbq/teamspeak/client";
399
+ import { Windows_3_6_2_1695203293 } from "@honeybbq/teamspeak/versions";
400
+
401
+ const client = new Client(identity, "ts.example.com", "Bot", {
402
+ version: Windows_3_6_2_1695203293,
403
+ });
404
+ ```
405
+
406
+ A `ClientVersion` is a platform, a version string and a signature, and only
407
+ the ones in that entry carry a signature a server accepts. A server refuses a
408
+ build below its configured minimum, so an old version fails to connect on a
409
+ server that has raised it. `new Client` throws when a field is empty or the
410
+ signature is not the base64 of 64 bytes. Importing `@honeybbq/teamspeak/client`
411
+ does not load the table; only the entry you import it from does.
412
+
413
+ ### Tracing
414
+
415
+ `trace` takes hooks that are called at each milestone of the client's life, for timing, metrics, logs or a progress display. For each connection attempt, the one `connect()` starts and each one the reconnect loop makes, the milestones come in this order: `resolveStart`, `resolveDone`, `connectStart`, `connectDone`, `handshakeDone`, `sessionStart`, `welcomeDone`. An attempt that never gets a session ends with `attemptFailed` instead, which says in which phase (`"open"`, `"handshake"` or `"join"`) and why. When a session ends, `sessionEnd` is called with the cause (`undefined` after `disconnect()`), preceded on a `disconnect()` by `disconnectStart` and `disconnectDone`, which says whether the server acknowledged the goodbye. `reconnectScheduled` fires when the reconnect loop is about to wait for its next attempt, and `reconnectStopped` when it ends without a session. Every attempt ends with exactly one of `sessionStart` and `attemptFailed`, and every session with exactly one `sessionEnd`.
416
+
417
+ The infos carry what each milestone knows: the resolver's candidates, the local address, the RSA puzzle's level and how long it took, how many packets were sent again, the server's public key (to pin a server's identity), the nickname the server accepted, the server's `initserver` parameters without any secret, and where the client landed with how many channels and clients the welcome delivered. Durations are in milliseconds.
418
+
419
+ ```ts
420
+ const client = new Client(identity, "ts.example.com", "Bot", {
421
+ trace: {
422
+ resolveDone: (i) => console.log(`resolved to ${i.target} in ${i.durationMs.toFixed(0)} ms`),
423
+ handshakeDone: (i) =>
424
+ console.log(`encrypted after ${i.durationMs.toFixed(0)} ms, ${i.resends} resends`),
425
+ sessionStart: (i) => console.log(`joined as ${i.nickname} after ${i.durationMs.toFixed(0)} ms`),
426
+ welcomeDone: (i) => console.log(`${i.channels} channels, ${i.clients} clients in view`),
427
+ attemptFailed: (i) => console.log(`attempt ${i.attempt} failed while ${i.phase}:`, i.error),
428
+ sessionEnd: (i) => console.log(`session over after ${(i.durationMs / 1000).toFixed(0)} s`),
429
+ reconnectScheduled: (i) => console.log(`retry ${i.attempt} in ${i.delayMs} ms`),
430
+ },
431
+ });
432
+ ```
433
+
434
+ A file transfer has a trace of its own, given in the options of `uploadFileData`, `downloadFileData` and `dialFileTransfer` (and of the client's methods that forward to them): `dialStart`, `dialDone`, `progress` (at most once per 64 KiB, and once more at the end with the final count), then exactly one of `done` and `failed`, which names the stage (`"dial"` or `"transfer"`). The transfer key never appears in any of it.
435
+
436
+ The rules for a hook, in both traces:
437
+
438
+ - It runs synchronously, at the moment of the milestone, and the client waits for it. Keep it quick and hand slow work to your own task.
439
+ - What it returns is ignored. A promise it returns is not awaited.
440
+ - It must not call `connect()` or `disconnect()`. To give up on an attempt, abort the signal you passed to `connect()`; to leave once connected, call `disconnect()` from a `connected` listener.
441
+ - It may read `client.status`, `client.clientID` and the like. `sessionStart` runs before `connect()` resolves and before `connected` is delivered, and `sessionEnd` before `disconnected`.
442
+ - If it throws, or the promise it returns rejects, the error is reported the way a throwing event listener's is, as an uncaught exception, and the client carries on as if nothing happened.
443
+
444
+ The object is copied when the client is made (or the transfer call starts), so changing it afterwards has no effect.
445
+
446
+ ### Diagnostics
447
+
448
+ The client logs nothing unless given a `logger`. For tracing, it publishes on
449
+ two [`diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html)
450
+ channels, which cost nothing without a subscriber:
451
+
452
+ - `honeybbq:teamspeak:command` (`commandChannel`), a tracing channel: `start`
453
+ when a command is sent, `asyncEnd` when its answer arrives, `error` when it
454
+ fails.
455
+ - `honeybbq:teamspeak:incoming` (`incomingChannel`): every command the server sends.
456
+
457
+ Both carry the command's name, never its parameters, which hold password hashes
458
+ and privilege keys.
459
+
460
+ ### Reconnection
461
+
462
+ Off by default: a silent reconnect makes an outage look like a healthy session.
463
+ An explicit `disconnect()` never reconnects, whatever the policy says.
464
+
465
+ ```typescript
466
+ const client = new Client(identity, "ts.example.com", "Bot", {
467
+ reconnect: {
468
+ backoff: { initialDelayMs: 1_000, maxDelayMs: 60_000, factor: 2, jitter: 0.2 },
469
+ // Optional: decide for yourself which failures are worth retrying.
470
+ shouldRetry: (err, attempt) => attempt < 10,
471
+ },
472
+ });
473
+ ```
474
+
475
+ The defaults are conservative because TeamSpeak **bans an IP after roughly
476
+ three rapid connects** — a retry loop without a delay bans itself, and the ban
477
+ outlasts the outage it was recovering from. Recovery is also not instant even
478
+ when it succeeds: the server holds the dropped session for a while and refuses a
479
+ reconnect with `521 too many clones already connected` until it reaps it, so the
480
+ loop keeps trying rather than giving up on the first refusal. It stops once a
481
+ `connect()` of your own has connected the client, and it does not retry an
482
+ address that cannot be one (`InvalidAddressError`).
483
+
484
+ ### Custom transports
485
+
486
+ `fileTransferSocketFactory` and `socketFactory` are the only seams into the
487
+ network layer. Without them the SDK always creates its own sockets, so an
488
+ application running behind a proxy has no way through. `socketFactory` returns
489
+ a `DatagramSocket` — a `node:dgram` socket, or anything with the few methods
490
+ it names — and `fileTransferSocketFactory` any `Duplex` stream, such as the
491
+ socket a SOCKS library returns.
492
+
493
+ ```typescript
494
+ const client = new Client(identity, "ts.example.com", "Bot", {
495
+ // UDP, for the voice and command channel.
496
+ socketFactory: (family) => createSocket(family === 6 ? "udp6" : "udp4"),
497
+ // TCP, dialled separately by each file transfer.
498
+ fileTransferSocketFactory: (host, port) => createConnection({ host, port }),
499
+ });
500
+ ```
501
+
502
+ ### Server capabilities
503
+
504
+ ```typescript
505
+ const caps = client.serverCapabilities;
506
+ // {
507
+ // version: "6.0.0-beta13.1 [Build: 1790080330]", major: 6, family: "ts6",
508
+ // uidAlgorithm: "sha256", name: "TeamSpeak 6 Server", iconID: undefined,
509
+ // hostBannerImageURL: undefined, welcomeMessage: "…"
510
+ // }
511
+ ```
512
+
513
+ Read from `initserver` during the handshake, so it costs no extra round trip.
514
+ The uid hash matters because TS3 hashes a client's public key with SHA-1 and TS6
515
+ with SHA-256 — a client that assumes either one computes an identifier the other
516
+ server never sends.
517
+
518
+ ## ServerQuery
519
+
520
+ The `@experimental` subpath `@honeybbq/teamspeak/query` administers a server
521
+ the way the voice protocol cannot: the same typed commands the core exports,
522
+ plus the ones only an administrator may run, over the three transports a
523
+ ServerQuery speaks.
524
+
525
+ | Transport | Where | Server | Login | Notifications |
526
+ | --------- | ------------ | ---------------- | ------------------- | ------------- |
527
+ | `tcp` | 10011 | TeamSpeak 3 only | the `login` command | yes |
528
+ | `ssh` | 10022 | both | the SSH login | yes |
529
+ | `web` | 10080 (HTTP) | TeamSpeak 6 | the api key | **no** |
530
+
531
+ Only raw TCP and SSH carry notifications: the server pushes them down the same
532
+ connection. WebQuery has no session to push to and refuses to register, so the
533
+ client never tries, and a listener for a server event there throws rather than
534
+ sitting silent. `connected` and `disconnected` work on every transport, since
535
+ they come from the client itself.
536
+
537
+ ```typescript
538
+ import { QueryClient } from "@honeybbq/teamspeak/query";
539
+ import { listChannels } from "@honeybbq/teamspeak";
540
+
541
+ const client = new QueryClient({
542
+ transport: { kind: "tcp", host: "ts.example.com" }, // 10011
543
+ login: { name: "serveradmin", password: process.env.QUERY_PASSWORD! },
544
+ server: { id: 1 },
545
+ nickname: "bot",
546
+ events: { categories: ["textserver", "textprivate"] },
547
+ reconnect: { backoff: { initialDelayMs: 1_000 } },
548
+ });
549
+
550
+ client.on("textMessage", (message) => console.log(message.invokerName, message.message));
551
+
552
+ await client.connect();
553
+
554
+ for (const channel of await listChannels(client)) console.log(channel.name);
555
+
556
+ await client.disconnect();
557
+ ```
558
+
559
+ The three transports are figures of speech the client rebuilds on every
560
+ connection, which is what makes reconnecting possible; `custom` opens one
561
+ itself, for a proxy, a tunnel or a test. Each built-in transport also offers
562
+ the seam into its own connection — `connect` for `tcp`, returning a `Duplex`,
563
+ and `connection` for `ssh`, taking a client or a factory for one — so an
564
+ application behind a TLS terminator or a SOCKS proxy, or one that already
565
+ holds an SSH client, can supply it. `ssh2` is an optional peer dependency:
566
+ without it the other two transports still work, and an `ssh` transport throws
567
+ a `MissingDependencyError` naming the package.
568
+
569
+ `serverFamily` reports which generation the server is, read from its own
570
+ `version` answer, and `transport` reads back the live connection for metrics.
571
+
572
+ ### SSH host keys
573
+
574
+ The `ssh` transport checks the server's host key before it sends the login, and
575
+ there is no default for how: the login is a credential, normally
576
+ `serveradmin`'s, and a client that accepts any key hands it to whatever answers
577
+ the port. Give exactly one of these, or the client refuses to be built, naming
578
+ all three:
579
+
580
+ ```typescript
581
+ const client = new QueryClient({
582
+ transport: {
583
+ kind: "ssh",
584
+ host: "ts.example.com",
585
+ username: "serveradmin",
586
+ password: process.env.QUERY_PASSWORD!,
587
+ knownHosts: "/etc/ssh/ssh_known_hosts",
588
+ },
589
+ });
590
+ ```
591
+
592
+ - `knownHosts`: the path of an OpenSSH `known_hosts` file, read each time a
593
+ connection is attempted and never found on its own: `~/.ssh/known_hosts` is
594
+ used only if you name it. The check is `StrictHostKeyChecking=yes`: a host the
595
+ file does not mention is refused, so is one recorded with another key, and so
596
+ is a key a `@revoked` line names. Plain, `[host]:port` and hashed
597
+ (`ssh-keygen -H`) entries are read. The query port is not 22, so record it as
598
+ `ssh-keyscan -p 10022 ts.example.com`, which writes `[ts.example.com]:10022`;
599
+ an entry for port 22 does not vouch for 10022.
600
+ - `hostKey`: your own check, `(key) => void`, that throws to refuse. `key` has
601
+ the host, port, `keyType`, the key's bytes and its `fingerprint`, the
602
+ `SHA256:…` that `ssh-keygen -lf` prints. It has to be synchronous and return
603
+ nothing: a returned value, a `false` included, or a promise is refused rather
604
+ than guessed at.
605
+ - `insecureIgnoreHostKey: true`: accept any key. It gives up what the host key
606
+ is for, and is for a test or a throwaway server.
607
+
608
+ A key that is refused fails the connection with an `SshHostKeyError`, whose
609
+ `cause` says why, and nothing was sent: the password has not left the process.
610
+ Reconnection does not retry it. A connection you supply yourself through
611
+ `connection` is checked by whoever made it, so these options are refused there.
612
+
613
+ **`@experimental`**: this entry point is new, and its API may change in a
614
+ minor release — the options, the transport union and the event map are all
615
+ still settling. Pin a version and read the changelog if you depend on it.
616
+
617
+ ## Compatibility
618
+
619
+ The package follows semver from 1.0. A few sets are open by nature and may
620
+ gain members in a minor release: the events (`EventMap`, `ServerEventName`),
621
+ `ClientStatus`, `ServerFamily`, `UIDAlgorithm`, `ErrorCode`, `Reason` and the
622
+ enumeration tables. Write a `switch` over any of them with a default case. A
623
+ field the server sends as a number that one of those tables names — a codec, a
624
+ text message's target mode, a group type — is a plain `number`, since a server
625
+ may send a value newer than the table.
626
+
627
+ `DatagramSocket` describes the part of a socket the client uses; should a
628
+ later release use more, the new members will be optional.
629
+
630
+ ### Supported environments
631
+
632
+ | Environment | Supported |
633
+ | ----------- | ------------------------------------------------------------------------------ |
634
+ | Node.js | The active and maintenance LTS releases, from 22.12; CI tests 22.12, 24 and 26 |
635
+ | TypeScript | 5.2 and newer, for the published types |
636
+ | Modules | ESM only |
637
+
638
+ When a Node.js release reaches end of life, a minor release may raise
639
+ `engines.node` past it; that is not a breaking change. The published types use
640
+ `Disposable`, so the `lib` option must include `esnext.disposable` (or `es2026`
641
+ or `esnext`), and the subpath exports need `moduleResolution` set to `node16`,
642
+ `nodenext` or `bundler`. CI type-checks a consumer of the packed package with
643
+ TypeScript 5.2. Raising that minimum follows TypeScript's own support window,
644
+ happens in a minor release, and comes with a changelog note.
645
+
646
+ ### Differences from the Go SDK
647
+
648
+ The [Go SDK](https://github.com/honeybbq/teamspeak-go) makes the same calls
649
+ with the same semantics, apart from what the languages make differ:
650
+
651
+ - Backoff fields: JavaScript takes `undefined` as "the default" and `0` as 0.
652
+ Go cannot tell an unset field from 0, so there a zero field takes the default
653
+ and a negative jitter disables it.
654
+ - A listener that throws: here the exception is rethrown from a microtask, an
655
+ uncaught exception as an EventEmitter listener's would be, and the other
656
+ listeners still get the event. Go recovers a panicking handler, logs it at
657
+ Error, and keeps delivering.
658
+ - Durations are milliseconds with an `Ms` suffix here, `time.Duration` in Go;
659
+ `listClients`' `uid` flag (on by default) is Go's `OmitUID`.
660
+
661
+ ## Entry points
662
+
663
+ | Import from | What it is |
664
+ | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
665
+ | `@honeybbq/teamspeak` | What every TeamSpeak connection shares: the command language, ids, errors, the typed commands, the event types and the status and reconnection types |
666
+ | `@honeybbq/teamspeak/client` | The voice client, identities, file transfers, diagnostics and its retry policy |
667
+ | `@honeybbq/teamspeak/versions` | Client versions a server accepts, for the client's `version` option; data only, one export each |
668
+ | `@honeybbq/teamspeak/query` | The ServerQuery client, running the same typed commands over raw TCP, SSH or WebQuery; `@experimental` |
669
+
670
+ Each entry exports only its own symbols. The client entry does not re-export
671
+ the core, so a program imports the `Client` from `@honeybbq/teamspeak/client`
672
+ and the typed commands, ids and errors from `@honeybbq/teamspeak`.
673
+
674
+ The protocol internals (crypto, handshake, transport) are not exported. They
675
+ change with the protocol, and exporting them would have made every change a
676
+ breaking one.
677
+
678
+ `@honeybbq/teamspeak-client` and `@honeybbq/teamspeak-core` are deprecated and
679
+ get no further releases. Coming from 0.x? The
680
+ [migration guide](https://github.com/HoneyBBQ/teamspeak-js/blob/main/docs/migrating-to-1.0.md) lists every change.
681
+
682
+ ## Architecture
683
+
684
+ ```
685
+ src/
686
+ ├── core/ # Shared: command language, ids, errors, typed commands
687
+ ├── client/ # The voice client (@honeybbq/teamspeak/client)
688
+ │ ├── client.ts # Client lifecycle, connection management
689
+ │ ├── commands.ts # Command sending and response tracking
690
+ │ ├── api/voice.ts # Commands only the voice protocol has
691
+ │ ├── capabilities.ts # Server version and uid hash detection
692
+ │ ├── reconnect.ts # Backoff policy and permanent-failure detection
693
+ │ ├── events.ts # Event handler registration and middleware
694
+ │ ├── notifications.ts # Server notification parsing and dispatch
695
+ │ ├── handshake.ts # Protocol handshake orchestration
696
+ │ ├── transfer.ts # File transfer data connections
697
+ │ ├── throttle.ts # Token-bucket rate limiter
698
+ │ ├── crypto/ # ECDH, EAX encryption, identity management
699
+ │ ├── handshake/ # Crypto handshake and license verification
700
+ │ ├── transport/ # UDP packet framing, ACK, compression
701
+ │ └── discovery/ # SRV / TSDNS / direct address resolution
702
+ └── query/ # ServerQuery client (not exported yet)
703
+ examples/
704
+ └── connect.ts # Minimal connection example
705
+ ```
706
+
707
+ ## Related
708
+
709
+ - **[teamspeak-go](https://github.com/honeybbq/teamspeak-go)** — The original Go implementation this library is ported from
710
+
711
+ ## Acknowledgments
712
+
713
+ Protocol knowledge was primarily informed by the [TSLib](https://github.com/Splamy/TS3AudioBot) implementation in [TS3AudioBot](https://github.com/Splamy/TS3AudioBot) by Splamy. Huge thanks to the TS3AudioBot project and its contributors.
714
+
715
+ ## Disclaimer
716
+
717
+ TeamSpeak is a registered trademark of [TeamSpeak Systems GmbH](https://teamspeak.com/). This project is not affiliated with, endorsed by, or associated with TeamSpeak Systems GmbH in any way.
718
+
719
+ This library is a **clean-room implementation** developed from publicly available documentation, protocol analysis of network traffic, and independent research. No proprietary TeamSpeak SDK code, headers, or libraries were used in its creation.
720
+
721
+ ## Contributing
722
+
723
+ See [CONTRIBUTING.md](https://github.com/HoneyBBQ/teamspeak-js/blob/main/.github/CONTRIBUTING.md) for setup, checks and the integration suite.
724
+
725
+ ## License
726
+
727
+ [MIT](https://github.com/HoneyBBQ/teamspeak-js/blob/main/LICENSE)