@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
@@ -0,0 +1,125 @@
1
+ const ESCAPE_MAP: Array<[string, string]> = [
2
+ ["\\", "\\\\"],
3
+ ["/", "\\/"],
4
+ [" ", "\\s"],
5
+ ["|", "\\p"],
6
+ ["\x07", "\\a"],
7
+ ["\x08", "\\b"],
8
+ ["\x0C", "\\f"],
9
+ ["\n", "\\n"],
10
+ ["\r", "\\r"],
11
+ ["\t", "\\t"],
12
+ ["\x0B", "\\v"],
13
+ ];
14
+
15
+ /**
16
+ * Escape a value for the command line: the characters that delimit a command
17
+ * (space, `|`, `/`, the backslash itself, control characters) become their
18
+ * two-character escapes.
19
+ */
20
+ export function escape(s: string): string {
21
+ let result = s;
22
+ for (const [from, to] of ESCAPE_MAP) {
23
+ result = result.split(from).join(to);
24
+ }
25
+ return result;
26
+ }
27
+
28
+ /** Undo {@link escape}, in one pass so that `\\s` comes back as `\s`, not a space. */
29
+ export function unescape(s: string): string {
30
+ // Process escape sequences in a single pass to avoid double-substitution
31
+ let result = "";
32
+ let i = 0;
33
+ while (i < s.length) {
34
+ if (s[i] === "\\" && i + 1 < s.length) {
35
+ const next = s[i + 1];
36
+ switch (next) {
37
+ case "\\":
38
+ result += "\\";
39
+ i += 2;
40
+ break;
41
+ case "/":
42
+ result += "/";
43
+ i += 2;
44
+ break;
45
+ case "s":
46
+ result += " ";
47
+ i += 2;
48
+ break;
49
+ case "p":
50
+ result += "|";
51
+ i += 2;
52
+ break;
53
+ case "a":
54
+ result += "\x07";
55
+ i += 2;
56
+ break;
57
+ case "b":
58
+ result += "\x08";
59
+ i += 2;
60
+ break;
61
+ case "f":
62
+ result += "\x0C";
63
+ i += 2;
64
+ break;
65
+ case "n":
66
+ result += "\n";
67
+ i += 2;
68
+ break;
69
+ case "r":
70
+ result += "\r";
71
+ i += 2;
72
+ break;
73
+ case "t":
74
+ result += "\t";
75
+ i += 2;
76
+ break;
77
+ case "v":
78
+ result += "\x0B";
79
+ i += 2;
80
+ break;
81
+ case undefined:
82
+ default:
83
+ result += s[i] ?? "";
84
+ i++;
85
+ break;
86
+ }
87
+ } else {
88
+ result += s[i] ?? "";
89
+ i++;
90
+ }
91
+ }
92
+ return result;
93
+ }
94
+
95
+ /** A command line, parsed. */
96
+ export interface Command {
97
+ /** The command's name, or `""` for a data row, which carries no name. */
98
+ readonly name: string;
99
+ /** Its parameters, unescaped. A flag such as `-uid` maps to `""`. */
100
+ readonly params: Readonly<Record<string, string>>;
101
+ }
102
+
103
+ /** Build a command line from a parameter map; keys and values are escaped alike. */
104
+ export function buildCommand(cmd: string, params: Readonly<Record<string, string>>): string {
105
+ const parts: string[] = [escape(cmd)];
106
+ for (const [k, v] of Object.entries(params)) {
107
+ parts.push(`${escape(k)}=${escape(v)}`);
108
+ }
109
+ return parts.join(" ");
110
+ }
111
+
112
+ /** Build a TS3 command string preserving parameter order. */
113
+ export function buildCommandOrdered(
114
+ cmd: string,
115
+ params: ReadonlyArray<readonly [string, string]>,
116
+ ): string {
117
+ const parts: string[] = [escape(cmd)];
118
+ for (const [k, v] of params) {
119
+ // A flag such as `-uid` is a bare switch. `-uid=1` happens to be accepted
120
+ // over the voice protocol, but it is not the documented form and nothing
121
+ // promises another transport tolerates it.
122
+ parts.push(k.startsWith("-") && v === "" ? escape(k) : `${escape(k)}=${escape(v)}`);
123
+ }
124
+ return parts.join(" ");
125
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Branded identifiers.
3
+ *
4
+ * TeamSpeak uses one 64-bit integer space for several unrelated kinds of id, so
5
+ * a `bigint` alone cannot tell a channel from a client. Branding makes the
6
+ * mistake a compile error instead of a silent move-to-the-wrong-place, and the
7
+ * brands cost nothing at runtime.
8
+ *
9
+ * The ids the protocol defines as 32 bits or narrower — a clid, a permission,
10
+ * an icon — are `number` brands; the 64-bit ones are `bigint` brands.
11
+ */
12
+
13
+ /** A channel (`cid`). */
14
+ export type ChannelID = bigint & { readonly __brand: "ChannelID" };
15
+ /**
16
+ * A connected client (`clid`): an id for this connection only, assigned anew
17
+ * every time the client connects.
18
+ */
19
+ export type ClientID = number & { readonly __brand: "ClientID" };
20
+ /**
21
+ * A client's database record (`cldbid`): stable across connections, unlike its
22
+ * ClientID.
23
+ */
24
+ export type ClientDBID = bigint & { readonly __brand: "ClientDBID" };
25
+ /** A server group (`sgid`). */
26
+ export type ServerGroupID = bigint & { readonly __brand: "ServerGroupID" };
27
+ /** A channel group (`cgid`). */
28
+ export type ChannelGroupID = bigint & { readonly __brand: "ChannelGroupID" };
29
+ /** A permission's numeric id (`permid`), a 32-bit value assigned by the server build. */
30
+ export type PermissionID = number & { readonly __brand: "PermissionID" };
31
+ /**
32
+ * An icon: the unsigned CRC32 of the icon file, which also names the file
33
+ * (`/icon_<id>`) in the server's file area.
34
+ */
35
+ export type IconID = number & { readonly __brand: "IconID" };
36
+
37
+ /** A ban (`banid`). */
38
+ export type BanID = bigint & { readonly __brand: "BanID" };
39
+ /** An offline message (`msgid`). */
40
+ export type MessageID = bigint & { readonly __brand: "MessageID" };
41
+ /** A virtual server on an instance (`sid`, `virtualserver_id`). */
42
+ export type ServerID = bigint & { readonly __brand: "ServerID" };
43
+ /** The client's id for a file transfer (`clientftfid`), a 16-bit value it chooses. */
44
+ export type ClientFileTransferID = number & { readonly __brand: "ClientFileTransferID" };
45
+ /** The server's id for a file transfer (`serverftfid`), a 16-bit value. */
46
+ export type ServerFileTransferID = number & { readonly __brand: "ServerFileTransferID" };
47
+
48
+ const MAX_UINT16 = 0xffff;
49
+ const MAX_UINT32 = 0xffff_ffff;
50
+ const MAX_UINT64 = (1n << 64n) - 1n;
51
+
52
+ /** `v` if it is an integer from 0 to `max`; a RangeError otherwise. */
53
+ function uintInRange(v: number, max: number, what: string): number {
54
+ if (typeof v !== "number" || !Number.isInteger(v) || v < 0 || v > max) {
55
+ throw new RangeError(`${what} is an integer from 0 to ${max}, not ${String(v)}`);
56
+ }
57
+ return v;
58
+ }
59
+
60
+ /** `v` as a bigint if it is an integer from 0 to 2^64-1; a RangeError otherwise. */
61
+ function uint64(v: bigint | number, what: string): bigint {
62
+ const integer = typeof v === "bigint" || (typeof v === "number" && Number.isInteger(v));
63
+ const value = integer ? BigInt(v) : -1n;
64
+ if (value < 0n || value > MAX_UINT64) {
65
+ throw new RangeError(`${what} is an integer from 0 to 2^64-1, not ${String(v)}`);
66
+ }
67
+ return value;
68
+ }
69
+
70
+ // Every constructor checks its value against the id's wire width and throws a
71
+ // RangeError for anything else — a fraction, a negative, a value too wide —
72
+ // rather than brand a value no server could mean.
73
+
74
+ /** Brand a ban id, an integer from 0 to 2^64-1, from a number or a bigint. */
75
+ export const asBanID = (v: bigint | number): BanID => uint64(v, "a ban id") as BanID;
76
+ /** Brand an offline message id, an integer from 0 to 2^64-1. */
77
+ export const asMessageID = (v: bigint | number): MessageID =>
78
+ uint64(v, "a message id") as MessageID;
79
+ /** Brand a virtual server id, an integer from 0 to 2^64-1. */
80
+ export const asServerID = (v: bigint | number): ServerID => uint64(v, "a server id") as ServerID;
81
+ /** Brand the client's id for a file transfer, an integer from 0 to 65535. */
82
+ export const asClientFileTransferID = (v: number): ClientFileTransferID =>
83
+ uintInRange(v, MAX_UINT16, "a client file transfer id") as ClientFileTransferID;
84
+ /** Brand the server's id for a file transfer, an integer from 0 to 65535. */
85
+ export const asServerFileTransferID = (v: number): ServerFileTransferID =>
86
+ uintInRange(v, MAX_UINT16, "a server file transfer id") as ServerFileTransferID;
87
+
88
+ /** Brand a channel id, an integer from 0 to 2^64-1, from a number or a bigint. */
89
+ export const asChannelID = (v: bigint | number): ChannelID =>
90
+ uint64(v, "a channel id") as ChannelID;
91
+ /** Brand a client id, an integer from 0 to 65535: the voice protocol's width. */
92
+ export const asClientID = (v: number): ClientID =>
93
+ uintInRange(v, MAX_UINT16, "a client id") as ClientID;
94
+ /** Brand a client database id, an integer from 0 to 2^64-1. */
95
+ export const asClientDBID = (v: bigint | number): ClientDBID =>
96
+ uint64(v, "a client database id") as ClientDBID;
97
+ /** Brand a server group id, an integer from 0 to 2^64-1. */
98
+ export const asServerGroupID = (v: bigint | number): ServerGroupID =>
99
+ uint64(v, "a server group id") as ServerGroupID;
100
+ /** Brand a channel group id, an integer from 0 to 2^64-1. */
101
+ export const asChannelGroupID = (v: bigint | number): ChannelGroupID =>
102
+ uint64(v, "a channel group id") as ChannelGroupID;
103
+ /** Brand a permission id, an integer from 0 to 2^32-1. */
104
+ export const asPermissionID = (v: number): PermissionID =>
105
+ uintInRange(v, MAX_UINT32, "a permission id") as PermissionID;
106
+ /**
107
+ * Brand an icon id, an integer from -2^31 to 2^32-1. A negative value is taken
108
+ * as the signed form of the same CRC32, which is how the server sometimes
109
+ * sends one, and stored unsigned.
110
+ */
111
+ export const asIconID = (v: number): IconID => {
112
+ if (typeof v !== "number" || !Number.isInteger(v) || v < -(2 ** 31) || v > MAX_UINT32) {
113
+ throw new RangeError(`an icon id is an integer from -2^31 to 2^32-1, not ${String(v)}`);
114
+ }
115
+ return (v >>> 0) as IconID;
116
+ };
117
+
118
+ /**
119
+ * Read an icon id as the server sends it: the CRC32, sometimes as a negative
120
+ * 32-bit number, sometimes unsigned. Both name the same icon, so both come back
121
+ * as the unsigned value; 0, garbage and out-of-range values mean no icon.
122
+ */
123
+ export function parseIconID(raw: string | undefined): IconID | undefined {
124
+ const text = raw?.trim() ?? "";
125
+ if (!/^-?\d{1,10}$/.test(text)) return undefined;
126
+ const value = Number(text);
127
+ if (value < -(2 ** 31) || value >= 2 ** 32 || value === 0) return undefined;
128
+ return asIconID(value);
129
+ }
130
+
131
+ /**
132
+ * A unique identifier: `base64(SHA-1(publicKey))` on TeamSpeak 3 and
133
+ * `base64(SHA-256(publicKey))` on TeamSpeak 6.
134
+ *
135
+ * The length differs between versions, so treat it as opaque bytes rather than
136
+ * assuming either width.
137
+ */
138
+ export type UID = string & { readonly __brand: "UID" };
139
+ /** Brand a unique identifier. */
140
+ export const asUID = (v: string): UID => v as UID;
141
+
142
+ /**
143
+ * A channel's unique identifier (`channel_unique_identifier`), which TS6
144
+ * gives every channel and TS3 does not send. Opaque text, and not a client's
145
+ * {@link UID}.
146
+ */
147
+ export type ChannelUID = string & { readonly __brand: "ChannelUID" };
148
+ /** Brand a channel's unique identifier. */
149
+ export const asChannelUID = (v: string): ChannelUID => v as ChannelUID;
@@ -0,0 +1,68 @@
1
+ import { unescape } from "./command.js";
2
+ import type { Command } from "./command.js";
3
+
4
+ /**
5
+ * Whether a token is a command name.
6
+ *
7
+ * A command name is a run of ASCII alphanumerics — the rule tsproto-packets
8
+ * uses (CommandParser::new). Everything that splits or parses a line asks this
9
+ * one function, so the parser and the row splitter cannot disagree about where
10
+ * a command's data begins.
11
+ */
12
+ export function isCommandName(token: string): boolean {
13
+ return /^[A-Za-z0-9]+$/.test(token);
14
+ }
15
+
16
+ /**
17
+ * Parse one command line, or one row of it. Returns null for an empty line.
18
+ * A line whose first token is not a command name is a data row, with `name`
19
+ * `""`.
20
+ */
21
+ export function parseCommand(s: string): Command | null {
22
+ if (s === "") return null;
23
+
24
+ // Skip leading non-printable bytes (< 0x20 or > 0x7E)
25
+ let startIndex = 0;
26
+ for (let i = 0; i < s.length; i++) {
27
+ const code = s.charCodeAt(i);
28
+ if (code >= 32 && code <= 126) {
29
+ startIndex = i;
30
+ break;
31
+ }
32
+ }
33
+ if (startIndex > 0) {
34
+ s = s.slice(startIndex);
35
+ }
36
+
37
+ const parts = s.split(" ");
38
+ if (parts.length === 0) return null;
39
+
40
+ // A command name is a run of alphanumerics followed by a space — the rule
41
+ // tsproto-packets uses (CommandParser::new). Anything else means the line is
42
+ // not a command at all: response rows carry no name ("clid=6 cid=2 ..."),
43
+ // and negative feedback is "-1 id=2 ...", naming the *rejected* command id
44
+ // rather than a command of its own. Returning those as a nameless row keeps
45
+ // the data intact instead of folding the first field into a name, which is
46
+ // how a clientlist row used to arrive as name="clid=6" and lose its clid.
47
+ const first = parts[0] ?? "";
48
+ if (first === "") return null;
49
+
50
+ // No prototype: a key is whatever the line says, and one named __proto__
51
+ // must be stored, not swallowed by Object.prototype's setter.
52
+ const params: Record<string, string> = Object.create(null) as Record<string, string>;
53
+ const name = isCommandName(first) ? first : "";
54
+ const start = name === "" ? 0 : 1;
55
+
56
+ for (let i = start; i < parts.length; i++) {
57
+ const p = parts[i];
58
+ if (p === undefined || p === "") continue;
59
+ const eqIdx = p.indexOf("=");
60
+ if (eqIdx >= 0) {
61
+ params[unescape(p.slice(0, eqIdx))] = unescape(p.slice(eqIdx + 1));
62
+ } else {
63
+ params[unescape(p)] = "";
64
+ }
65
+ }
66
+
67
+ return { name, params };
68
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * A command as the typed layer describes it, before a transport encodes it.
3
+ *
4
+ * The typed commands run on any connection that can execute a command — the
5
+ * voice client today, ServerQuery later — and the two disagree about how some
6
+ * values go on the wire. A channel password is the case that matters: the
7
+ * voice protocol expects `base64(sha1(password))`, while ServerQuery takes the
8
+ * password itself and hashes it server-side. So a request says *which*
9
+ * parameters are passwords and leaves their encoding to the transport.
10
+ */
11
+
12
+ import type { CommandName } from "../command-name.js";
13
+ import { buildCommandOrdered } from "./command.js";
14
+
15
+ /** A parameter value as a caller may supply it. */
16
+ export type ParamValue = string | number | bigint | boolean | undefined;
17
+
18
+ /** A command and its parameters, in the order they are sent. */
19
+ export interface CommandRequest {
20
+ /** The command's name, such as `clientlist`; {@link CommandName} lists the known ones. */
21
+ readonly command: CommandName | (string & {});
22
+ /**
23
+ * Its parameters, as wire name and value pairs, in the order they are sent;
24
+ * an undefined value is omitted.
25
+ */
26
+ readonly params?: ReadonlyArray<readonly [string, ParamValue]> | undefined;
27
+ /**
28
+ * Further rows, for a command that takes a list: each is a group of
29
+ * parameters sent after a `|`, as `ftdeletefile cid=1 cpw= name=/a|name=/b`
30
+ * sends two names. The first row's parameters follow `params`.
31
+ */
32
+ readonly rows?: ReadonlyArray<ReadonlyArray<readonly [string, ParamValue]>> | undefined;
33
+ /** Names of the parameters that carry a channel password. */
34
+ readonly passwords?: readonly string[] | undefined;
35
+ }
36
+
37
+ /** How long a command may take, and how to abandon it. */
38
+ export interface CommandOptions {
39
+ /** Abandons the command; it then rejects with the signal's reason. */
40
+ readonly signal?: AbortSignal | undefined;
41
+ /** Milliseconds to wait for the answer before failing with a CommandTimeoutError. */
42
+ readonly timeoutMs?: number | undefined;
43
+ }
44
+
45
+ /**
46
+ * A connection the typed commands can run on.
47
+ *
48
+ * It is deliberately this narrow. A caller implements it to run the typed
49
+ * commands over a transport of their own, and `CommandMiddleware` wraps its
50
+ * `send`, so a method added here would break every implementation and every
51
+ * middleware along with it: this interface gains no methods in a minor
52
+ * release. A new capability arrives as an interface, a function or an option
53
+ * of its own instead, and an implementer or a middleware author may rely on
54
+ * that.
55
+ */
56
+ export interface CommandExecutor {
57
+ /** Send a command and return the rows that answer it. */
58
+ // oxlint-disable-next-line typescript/array-type -- the public API report spells this `[]`; respelling it changes the report
59
+ send(request: CommandRequest, options?: CommandOptions): Promise<Record<string, string>[]>;
60
+ }
61
+
62
+ /**
63
+ * Turn a value into its wire form.
64
+ *
65
+ * Returns undefined for values that should be omitted entirely — an unset
66
+ * optional field — because sending `foo=` is not the same as not sending it:
67
+ * for `channel_password` the first clears the password and the second leaves it
68
+ * alone. Callers distinguish "unset" from "empty string" by passing undefined
69
+ * versus "".
70
+ */
71
+ function encodeValue(value: ParamValue): string | undefined {
72
+ if (value === undefined) return undefined;
73
+ if (typeof value === "boolean") return value ? "1" : "0";
74
+ return String(value);
75
+ }
76
+
77
+ /**
78
+ * Render a request as a command line.
79
+ *
80
+ * `encodePassword` is the transport's rule for password parameters. An empty
81
+ * password is sent as is: it means "no password", in every encoding.
82
+ */
83
+ export function encodeRequest(
84
+ request: CommandRequest,
85
+ encodePassword: (password: string) => string,
86
+ ): string {
87
+ const passwords = request.passwords ?? [];
88
+ const encode = (params: ReadonlyArray<readonly [string, ParamValue]>) =>
89
+ encodeParams(params, passwords, encodePassword);
90
+ const [first = [], ...rest] = request.rows ?? [];
91
+ const line = buildCommandOrdered(request.command, [
92
+ ...encode(request.params ?? []),
93
+ ...encode(first),
94
+ ]);
95
+ // A row is the parameters alone, with no command name before them.
96
+ return [line, ...rest.map((row) => buildCommandOrdered("", encode(row)).slice(1))].join("|");
97
+ }
98
+
99
+ function encodeParams(
100
+ params: ReadonlyArray<readonly [string, ParamValue]>,
101
+ passwords: readonly string[],
102
+ encodePassword: (password: string) => string,
103
+ ): Array<readonly [string, string]> {
104
+ const out: Array<readonly [string, string]> = [];
105
+ for (const [key, value] of params) {
106
+ // Flags (`-uid`) are switches: present when true, absent otherwise.
107
+ if (key.startsWith("-")) {
108
+ if (value === true) out.push([key, ""]);
109
+ continue;
110
+ }
111
+ if (passwords.includes(key) && typeof value === "string" && value !== "") {
112
+ out.push([key, encodePassword(value)]);
113
+ continue;
114
+ }
115
+ const encoded = encodeValue(value);
116
+ if (encoded !== undefined) out.push([key, encoded]);
117
+ }
118
+ return out;
119
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Where each command's answer actually arrives.
3
+ *
4
+ * ServerQuery answers a query with nameless rows followed by `error`. The voice
5
+ * protocol often does not: it answers `servergrouplist` with a named
6
+ * `notifyservergrouplist` command, `clientgetuidfromclid` with
7
+ * `notifyclientuidfromclid`, and so on. A client that only collects nameless
8
+ * rows reports an empty success for every one of those — which this SDK did,
9
+ * and documented as a property of the protocol.
10
+ *
11
+ * Notifications carry no return_code, so nothing on the wire ties one to the
12
+ * command that caused it. The pairing is a property of the command, and this
13
+ * table is where it lives. It was measured command by command
14
+ * against TS3 3.13.8 and TS6 6.0.0-beta13.1, which answer identically — see
15
+ * scripts/probe-response-shapes.mts to re-run that measurement.
16
+ *
17
+ * Commands not listed answer with nameless rows, or with nothing.
18
+ */
19
+
20
+ /** How the voice protocol delivers one command's data. */
21
+ export interface ResponseSpec {
22
+ /**
23
+ * Notifications carrying the data, sent before the command's `error`.
24
+ *
25
+ * Rows of these are attributed to the command whose `error` follows them.
26
+ * The same notification can also arrive unprompted — `notifyservergrouplist`
27
+ * after someone else edits a group — so they are still dispatched as events.
28
+ */
29
+ readonly notifications?: readonly string[];
30
+ /**
31
+ * Keep only rows whose `invokerid` is the client itself.
32
+ *
33
+ * `notifychannelcreated` is broadcast for every channel anyone creates; the
34
+ * one answering our `channelcreate` is the one we invoked.
35
+ */
36
+ readonly ownRowsOnly?: boolean;
37
+ /**
38
+ * Notifications that answer after the `error`, matched on a request field.
39
+ *
40
+ * File transfer negotiation reports its key once the command has already
41
+ * succeeded, echoing the `clientftfid` the request carried; that echo is the
42
+ * only link between the two.
43
+ */
44
+ readonly correlated?: {
45
+ readonly notifications: readonly string[];
46
+ /** Request parameter the answer echoes back. */
47
+ readonly key: string;
48
+ /**
49
+ * A notification that reports failure rather than data. Its `status` is an
50
+ * ordinary server error id: an `ftinitupload` refused for permissions
51
+ * answers `error id=0` and then this with `status=2568`.
52
+ */
53
+ readonly failure?: string;
54
+ };
55
+ }
56
+
57
+ const inline = (...notifications: string[]): ResponseSpec => ({ notifications });
58
+
59
+ const fileTransfer = (answer: string): ResponseSpec => ({
60
+ correlated: {
61
+ notifications: [answer, "notifystatusfiletransfer"],
62
+ key: "clientftfid",
63
+ failure: "notifystatusfiletransfer",
64
+ },
65
+ });
66
+
67
+ /** The table behind {@link responseSpec}, by command name; exported for the tests that check it against the name tables. */
68
+ export const RESPONSES: Readonly<Record<string, ResponseSpec>> = {
69
+ banlist: inline("notifybanlist"),
70
+ channelclientpermlist: inline("notifychannelclientpermlist"),
71
+ channelcreate: { notifications: ["notifychannelcreated"], ownRowsOnly: true },
72
+ channelgetdescription: inline("notifychanneledited"),
73
+ channelgroupadd: inline("notifychannelgrouplist"),
74
+ channelgroupclientlist: inline("notifychannelgroupclientlist"),
75
+ channelgroupcopy: inline("notifychannelgrouplist"),
76
+ channelgrouplist: inline("notifychannelgrouplist"),
77
+ channelgrouppermlist: inline("notifychannelgrouppermlist"),
78
+ channelpermlist: inline("notifychannelpermlist"),
79
+ clientdbfind: inline("notifyclientdbfind"),
80
+ clientdblist: inline("notifyclientdblist"),
81
+ clientgetdbidfromuid: inline("notifyclientdbidfromuid"),
82
+ clientgetids: inline("notifyclientids"),
83
+ clientgetnamefromdbid: inline("notifyclientnamefromdbid"),
84
+ clientgetnamefromuid: inline("notifyclientnamefromuid"),
85
+ clientgetuidfromclid: inline("notifyclientuidfromclid"),
86
+ clientpermlist: inline("notifyclientpermlist"),
87
+ complainlist: inline("notifycomplainlist"),
88
+ ftgetfileinfo: inline("notifyfileinfo"),
89
+ ftgetfilelist: inline("notifyfilelist"),
90
+ ftinitdownload: fileTransfer("notifystartdownload"),
91
+ ftinitupload: fileTransfer("notifystartupload"),
92
+ ftlist: inline("notifyfiletransferlist"),
93
+ logview: inline("notifyserverlog"),
94
+ messageget: inline("notifymessage"),
95
+ messagelist: inline("notifymessagelist"),
96
+ permfind: inline("notifypermfind"),
97
+ permissionlist: inline("notifypermissionlist"),
98
+ permoverview: inline("notifypermoverview"),
99
+ privilegekeyadd: inline("notifytokenadd"),
100
+ privilegekeylist: inline("notifytokenlist"),
101
+ servergroupadd: inline("notifyservergrouplist"),
102
+ servergroupclientlist: inline("notifyservergroupclientlist"),
103
+ servergroupcopy: inline("notifyservergrouplist"),
104
+ servergrouplist: inline("notifyservergrouplist"),
105
+ servergrouppermlist: inline("notifyservergrouppermlist"),
106
+ servergroupsbyclientid: inline("notifyservergroupsbyclientid"),
107
+ serverrequestconnectioninfo: inline("notifyserverconnectioninfo"),
108
+ servertemppasswordlist: inline("notifyservertemppasswordlist"),
109
+ };
110
+
111
+ /** The response shape of a command, or undefined for plain rows. */
112
+ export function responseSpec(command: string): ResponseSpec | undefined {
113
+ return Object.hasOwn(RESPONSES, command) ? RESPONSES[command] : undefined;
114
+ }