@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,243 @@
1
+ /**
2
+ * File transfer data.
3
+ *
4
+ * Negotiating a transfer is a command (`initFileUpload`, `initFileDownload`);
5
+ * the bytes then go over a separate TCP connection to the server's file
6
+ * transfer port, opened with the key the negotiation returned.
7
+ */
8
+ import { connect } from "node:net";
9
+ import { pipeline } from "node:stream/promises";
10
+ import { Transform } from "node:stream";
11
+ import { FileTransferError } from "./errors.js";
12
+ import { callHook } from "./hooks.js";
13
+ import { joinHostPort } from "./address.js";
14
+ import { abortable } from "./abort.js";
15
+ /** How long dialing may take before it fails, unless a signal says otherwise. */
16
+ const DIAL_TIMEOUT_MS = 10_000;
17
+ /** How long a transfer may go without moving a byte, unless `idleTimeoutMs` says otherwise. */
18
+ const DEFAULT_IDLE_TIMEOUT_MS = 30_000;
19
+ /** How many bytes move between two calls of the `progress` hook, at least. */
20
+ const PROGRESS_STEP_BYTES = 64 * 1024;
21
+ function newIdleGuard(options) {
22
+ const limitMs = options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
23
+ if (!Number.isFinite(limitMs) || limitMs < 0) {
24
+ throw new RangeError("idleTimeoutMs must be a finite number of milliseconds, 0 or more");
25
+ }
26
+ const controller = new AbortController();
27
+ if (limitMs === 0) {
28
+ return { signal: controller.signal, limitMs, touch() { }, stop() { } };
29
+ }
30
+ const timer = setTimeout(() => controller.abort(new DOMException(`no data moved for ${limitMs} ms`, "TimeoutError")), limitMs);
31
+ return {
32
+ signal: controller.signal,
33
+ limitMs,
34
+ touch: () => timer.refresh(),
35
+ stop: () => clearTimeout(timer),
36
+ };
37
+ }
38
+ /** The error a transfer fails with when `idle` expired, else `error` as it is. */
39
+ function idleOr(idle, error) {
40
+ if (!idle.signal.aborted)
41
+ return error;
42
+ return new FileTransferError(`file transfer stalled: no data moved for ${idle.limitMs} ms`, {
43
+ cause: idle.signal.reason,
44
+ });
45
+ }
46
+ function newTransferTrace(options) {
47
+ return {
48
+ trace: options.trace === undefined ? undefined : { ...options.trace },
49
+ startedAt: performance.now(),
50
+ bytes: 0,
51
+ };
52
+ }
53
+ function reportFailed(t, error, stage) {
54
+ callHook(t.trace?.failed, t.trace, () => ({
55
+ error,
56
+ bytes: t.bytes,
57
+ durationMs: performance.now() - t.startedAt,
58
+ stage,
59
+ }));
60
+ }
61
+ /**
62
+ * Open a connection to the file transfer port and send the transfer key.
63
+ * The caller owns the returned stream and must end or destroy it.
64
+ */
65
+ export async function dialFileTransfer(host, port, key, options = {}) {
66
+ const t = newTransferTrace(options);
67
+ const idle = newIdleGuard(options);
68
+ try {
69
+ return await dial(host, port, key, options, t, idle);
70
+ }
71
+ catch (error) {
72
+ const failure = idleOr(idle, error);
73
+ reportFailed(t, failure, "dial");
74
+ throw failure;
75
+ }
76
+ finally {
77
+ idle.stop();
78
+ }
79
+ }
80
+ async function dial(host, port, key, options, t, idle) {
81
+ const { signal, socketFactory } = options;
82
+ // One budget for the connection and the key write: a peer that accepts the
83
+ // connection and never reads would otherwise hold the write forever.
84
+ const timeout = AbortSignal.timeout(DIAL_TIMEOUT_MS);
85
+ const dialSignal = AbortSignal.any(signal ? [signal, timeout, idle.signal] : [timeout, idle.signal]);
86
+ const addr = joinHostPort(host, String(port));
87
+ callHook(t.trace?.dialStart, t.trace, () => ({ addr }));
88
+ signal?.throwIfAborted();
89
+ const socket = socketFactory ? socketFactory(host, port) : connect({ host, port });
90
+ // Until the caller takes the stream over, its errors are this function's to
91
+ // report: a stream's unhandled `error` event takes the process down.
92
+ const swallow = () => { };
93
+ socket.on("error", swallow);
94
+ try {
95
+ await abortable(connected(socket), dialSignal);
96
+ idle.touch();
97
+ await abortable(new Promise((resolve, reject) => {
98
+ socket.write(key, (err) => err
99
+ ? reject(new FileTransferError(`failed to send transfer key: ${err.message}`, {
100
+ cause: err,
101
+ }))
102
+ : resolve());
103
+ }), dialSignal);
104
+ idle.touch();
105
+ }
106
+ catch (error) {
107
+ socket.destroy();
108
+ if (timeout.aborted && error === timeout.reason) {
109
+ throw new FileTransferError("file transfer connection timed out", { cause: error });
110
+ }
111
+ throw error;
112
+ }
113
+ finally {
114
+ socket.off("error", swallow);
115
+ }
116
+ callHook(t.trace?.dialDone, t.trace, () => {
117
+ let localAddr = "";
118
+ const local = socket;
119
+ if (typeof local.localAddress === "string" && typeof local.localPort === "number") {
120
+ localAddr = joinHostPort(local.localAddress, String(local.localPort));
121
+ }
122
+ return { addr, localAddr, durationMs: performance.now() - t.startedAt };
123
+ });
124
+ return socket;
125
+ }
126
+ /**
127
+ * A pass-through that counts what moves and reports it to `progress`. It never
128
+ * fails the pipeline: a hook's error is reported, not thrown.
129
+ */
130
+ function countingStream(t, total, idle) {
131
+ let reported = 0;
132
+ return new Transform({
133
+ transform(chunk, _encoding, callback) {
134
+ t.bytes += typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
135
+ idle.touch();
136
+ if (t.bytes - reported >= PROGRESS_STEP_BYTES) {
137
+ reported = t.bytes;
138
+ const bytes = t.bytes;
139
+ callHook(t.trace?.progress, t.trace, () => ({ bytes, total }));
140
+ }
141
+ callback(null, chunk);
142
+ },
143
+ });
144
+ }
145
+ /**
146
+ * Passes exactly `expected` bytes. One more byte fails the transfer, and is
147
+ * not passed on; a stream that ends before `expected` fails it too.
148
+ */
149
+ function exactSize(expected) {
150
+ let received = 0;
151
+ return new Transform({
152
+ transform(chunk, _encoding, callback) {
153
+ const room = expected - received;
154
+ if (chunk.length > room) {
155
+ this.push(chunk.subarray(0, room));
156
+ received = expected;
157
+ callback(new FileTransferError(`file transfer sent more than the announced ${expected} bytes`));
158
+ return;
159
+ }
160
+ received += chunk.length;
161
+ callback(null, chunk);
162
+ },
163
+ flush(callback) {
164
+ callback(received === expected
165
+ ? null
166
+ : new FileTransferError(`file transfer ended after ${received} of the announced ${expected} bytes`));
167
+ },
168
+ });
169
+ }
170
+ /** Run a transfer's data phase, and report how the whole call ended. */
171
+ async function transfer(host, port, key, total, options, move) {
172
+ const t = newTransferTrace(options);
173
+ const idle = newIdleGuard(options);
174
+ try {
175
+ let socket;
176
+ try {
177
+ socket = await dial(host, port, key, options, t, idle);
178
+ }
179
+ catch (error) {
180
+ const failure = idleOr(idle, error);
181
+ reportFailed(t, failure, "dial");
182
+ throw failure;
183
+ }
184
+ try {
185
+ const signal = options.signal ? AbortSignal.any([options.signal, idle.signal]) : idle.signal;
186
+ await move(socket, countingStream(t, total, idle), { signal });
187
+ }
188
+ catch (error) {
189
+ // A pipeline aborted by the caller's signal rejects as the signal says;
190
+ // one aborted by the idle limit is the transfer's own failure.
191
+ const failure = idleOr(idle, error);
192
+ reportFailed(t, failure, "transfer");
193
+ throw failure;
194
+ }
195
+ }
196
+ finally {
197
+ idle.stop();
198
+ }
199
+ const bytes = t.bytes;
200
+ callHook(t.trace?.progress, t.trace, () => ({ bytes, total }));
201
+ callHook(t.trace?.done, t.trace, () => ({
202
+ bytes,
203
+ durationMs: performance.now() - t.startedAt,
204
+ }));
205
+ }
206
+ /**
207
+ * Wait for a stream to be connected. A `node:net` socket says so with
208
+ * `connect`; a stream from elsewhere that is already writable is taken as
209
+ * connected.
210
+ */
211
+ function connected(socket) {
212
+ const pending = socket.pending;
213
+ if (pending === false || (pending === undefined && socket.writable))
214
+ return Promise.resolve();
215
+ return new Promise((resolve, reject) => {
216
+ const done = (error) => {
217
+ socket.off("connect", onConnect);
218
+ socket.off("ready", onConnect);
219
+ socket.off("error", onError);
220
+ if (error === undefined)
221
+ resolve();
222
+ else
223
+ reject(error);
224
+ };
225
+ const onConnect = () => done();
226
+ const onError = (error) => done(new FileTransferError(`file transfer connection failed: ${error.message}`, {
227
+ cause: error,
228
+ }));
229
+ socket.once("connect", onConnect);
230
+ socket.once("ready", onConnect);
231
+ socket.once("error", onError);
232
+ });
233
+ }
234
+ /** Upload `data` over a negotiated transfer. Resolves once every byte is sent. */
235
+ export function uploadFileData(host, info, data, options = {}) {
236
+ return transfer(host, info.port, info.fileTransferKey, 0, options, (socket, counter, pipeOptions) => pipeline(data, counter, socket, pipeOptions));
237
+ }
238
+ /** Download a negotiated transfer into `dest`. Resolves once the file is written. */
239
+ export function downloadFileData(host, info, dest, options = {}) {
240
+ return transfer(host, info.port, info.fileTransferKey, Number(info.size), options, (socket, counter, pipeOptions) => pipeline(socket, exactSize(Number(info.size)), counter, dest, pipeOptions));
241
+ }
242
+ export { FileTransferError };
243
+ //# sourceMappingURL=transfer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transfer.js","sourceRoot":"","sources":["../../src/client/transfer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ export declare class GenerationWindow {
2
+ #private;
3
+ constructor(mod: number, windowSize: number);
4
+ get generation(): number;
5
+ advance(amount: number): void;
6
+ advanceToExcluded(mappedValue: number): void;
7
+ syncTo(mappedValue: number): void;
8
+ isInWindow(mappedValue: number): boolean;
9
+ /**
10
+ * The offset from the window base: negative means stale, `receiveWindow` or
11
+ * more too far ahead. An id up to `receiveWindow` behind the base across the
12
+ * last wrap, which reads as a high number, is stale too.
13
+ */
14
+ mappedToIndex(mappedValue: number): number;
15
+ /**
16
+ * Whether the id is before the receive window: a packet whose acknowledgement
17
+ * was lost is sent again after the window has moved past it, also when the
18
+ * move wrapped the 16-bit id.
19
+ */
20
+ isOldPacket(mappedValue: number): boolean;
21
+ isFuturePacket(mappedValue: number): boolean;
22
+ /**
23
+ * The generation the id belongs to: one past the current generation if the id
24
+ * has already wrapped, one before it if the id is just behind the base across
25
+ * the last wrap.
26
+ */
27
+ getGeneration(mappedValue: number): number;
28
+ reset(): void;
29
+ }
30
+ //# sourceMappingURL=generation-window.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generation-window.d.ts","sourceRoot":"","sources":["../../../src/client/transport/generation-window.ts"],"names":[],"mappings":"AAAA,qBAAa,gBAAgB;;IAM3B,YAAY,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAG1C;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAQ5B;IAED,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAI3C;IAED,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAIhC;IAED,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAMvC;IAED;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAMzC;IAgBD;;;;OAIG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAExC;IAED,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE3C;IASD;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAIzC;IAED,KAAK,IAAI,IAAI,CAGZ;CACF"}
@@ -0,0 +1,97 @@
1
+ export class GenerationWindow {
2
+ #mappedBaseOffset = 0;
3
+ #generation = 0;
4
+ #mod;
5
+ #receiveWindow;
6
+ constructor(mod, windowSize) {
7
+ this.#mod = mod;
8
+ this.#receiveWindow = windowSize;
9
+ }
10
+ get generation() {
11
+ return this.#generation;
12
+ }
13
+ advance(amount) {
14
+ if (amount <= 0)
15
+ return;
16
+ const newBaseOffset = this.#mappedBaseOffset + amount;
17
+ const genStep = Math.floor(newBaseOffset / this.#mod);
18
+ if (genStep > 0) {
19
+ this.#generation = Math.min(this.#generation + genStep, 0xffff_ffff);
20
+ }
21
+ this.#mappedBaseOffset = newBaseOffset % this.#mod;
22
+ }
23
+ advanceToExcluded(mappedValue) {
24
+ let moveDist = mappedValue - this.#mappedBaseOffset;
25
+ if (moveDist < 0)
26
+ moveDist += this.#mod;
27
+ this.advance(moveDist + 1);
28
+ }
29
+ syncTo(mappedValue) {
30
+ let moveDist = mappedValue - this.#mappedBaseOffset;
31
+ if (moveDist < 0)
32
+ moveDist += this.#mod;
33
+ this.advance(moveDist);
34
+ }
35
+ isInWindow(mappedValue) {
36
+ const maxOffset = this.#mappedBaseOffset + this.#receiveWindow;
37
+ if (maxOffset < this.#mod) {
38
+ return mappedValue >= this.#mappedBaseOffset && mappedValue < maxOffset;
39
+ }
40
+ return mappedValue >= this.#mappedBaseOffset || mappedValue < maxOffset - this.#mod;
41
+ }
42
+ /**
43
+ * The offset from the window base: negative means stale, `receiveWindow` or
44
+ * more too far ahead. An id up to `receiveWindow` behind the base across the
45
+ * last wrap, which reads as a high number, is stale too.
46
+ */
47
+ mappedToIndex(mappedValue) {
48
+ if (this.#isNextGen(mappedValue)) {
49
+ return mappedValue + this.#mod - this.#mappedBaseOffset;
50
+ }
51
+ const index = mappedValue - this.#mappedBaseOffset;
52
+ return this.#isBehindAcrossWrap(index) ? index - this.#mod : index;
53
+ }
54
+ /**
55
+ * Whether an id `index` past the base is really up to `receiveWindow` behind
56
+ * it, in the generation before: the base has wrapped since, so the id reads as
57
+ * nearly a whole generation ahead. Before the first wrap no id lies behind the
58
+ * base across it.
59
+ */
60
+ #isBehindAcrossWrap(index) {
61
+ return (this.#generation > 0 &&
62
+ index >= this.#receiveWindow &&
63
+ index >= this.#mod - this.#receiveWindow);
64
+ }
65
+ /**
66
+ * Whether the id is before the receive window: a packet whose acknowledgement
67
+ * was lost is sent again after the window has moved past it, also when the
68
+ * move wrapped the 16-bit id.
69
+ */
70
+ isOldPacket(mappedValue) {
71
+ return this.mappedToIndex(mappedValue) < 0;
72
+ }
73
+ isFuturePacket(mappedValue) {
74
+ return this.mappedToIndex(mappedValue) >= this.#receiveWindow;
75
+ }
76
+ #isNextGen(mappedValue) {
77
+ return (this.#mappedBaseOffset > this.#mod - this.#receiveWindow &&
78
+ mappedValue < this.#mappedBaseOffset + this.#receiveWindow - this.#mod);
79
+ }
80
+ /**
81
+ * The generation the id belongs to: one past the current generation if the id
82
+ * has already wrapped, one before it if the id is just behind the base across
83
+ * the last wrap.
84
+ */
85
+ getGeneration(mappedValue) {
86
+ if (this.#isNextGen(mappedValue))
87
+ return this.#generation + 1;
88
+ if (this.#isBehindAcrossWrap(mappedValue - this.#mappedBaseOffset))
89
+ return this.#generation - 1;
90
+ return this.#generation;
91
+ }
92
+ reset() {
93
+ this.#mappedBaseOffset = 0;
94
+ this.#generation = 0;
95
+ }
96
+ }
97
+ //# sourceMappingURL=generation-window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generation-window.js","sourceRoot":"","sources":["../../../src/client/transport/generation-window.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import type { Crypt } from "../crypto/crypt.js";
2
+ import type { DatagramSocket, SocketFactory } from "../types.js";
3
+ import type { Logger } from "@honeybbq/teamspeak";
4
+ import { type Packet, PacketType } from "./packet.js";
5
+ /**
6
+ * The largest datagram taken. TeamSpeak's packets are at most 500 bytes; a
7
+ * larger one is no packet of the protocol's, and is dropped before anything
8
+ * is decrypted or held.
9
+ */
10
+ export declare const MAX_DATAGRAM_SIZE: number;
11
+ /**
12
+ * The most command bytes held, across both receive queues, waiting for the
13
+ * packets before them. A server's in-order traffic drains at once and a full
14
+ * window of real packets is under a megabyte; past this, a packet is dropped
15
+ * unacknowledged, so the server sends it again once there is room.
16
+ */
17
+ export declare const MAX_QUEUED_BYTES: number;
18
+ export declare class PacketHandler {
19
+ #private;
20
+ onPacket: ((p: Packet) => void) | null;
21
+ onClosed: ((err: Error | null) => void) | null;
22
+ /**
23
+ * A received datagram could not be handled: it was malformed, or handling it
24
+ * threw. The datagram is dropped either way; the owner decides whether that
25
+ * ends the connection. Without an owner the error is logged.
26
+ */
27
+ onReceiveError: ((error: unknown) => void) | null;
28
+ /** Called with the socket once it is open, before the handshake's first packet is sent. */
29
+ onOpen: ((socket: DatagramSocket) => void) | null;
30
+ constructor(crypt: Crypt, logger?: Logger, socketFactory?: SocketFactory);
31
+ setClientID(id: number): void;
32
+ /**
33
+ * Resolve `addr`, open a socket to it and start the handshake.
34
+ *
35
+ * Aborting `signal`, or closing the handler, while this runs abandons it: the
36
+ * lookup's answer is ignored, and a socket that finishes connecting
37
+ * afterwards is closed rather than started, so no handshake begins after
38
+ * the connection was given up.
39
+ */
40
+ connect(addr: string, signal?: AbortSignal): Promise<void>;
41
+ /** Take over a connected socket and start the handshake on it. A closed handler closes it instead. */
42
+ start(conn: DatagramSocket): void;
43
+ /**
44
+ * Stop resending the last Init1 packet the client sent. Until this is called,
45
+ * the latest step stays pending whatever the server sends in between: a step
46
+ * the client does not answer, an unknown one or a second RSA challenge, must
47
+ * not stop the resending of its own. The server's `initivexpand2` command
48
+ * acknowledges the last step, not an Init1 reply.
49
+ */
50
+ receivedFinalInitAck(): void;
51
+ sendPacket(pType: PacketType, data: Uint8Array, flags: number): void;
52
+ sendVoicePacket(data: Uint8Array, codec: number): void;
53
+ /** Send an unencrypted TeamSpeak voice whisper packet to up to 32 clients. */
54
+ sendWhisperPacket(data: Uint8Array, targetClientIds: number[], codec: number): void;
55
+ /** How many packets have been sent again for want of an acknowledgement. */
56
+ get resends(): number;
57
+ /** Whether there is a live socket to send on. */
58
+ get isOpen(): boolean;
59
+ close(): void;
60
+ }
61
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/client/transport/handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EACL,KAAK,MAAM,EACX,UAAU,EAMX,MAAM,aAAa,CAAC;AA4BrB;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAa,CAAC;AAE9C;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAgB,CAAC;AA4BhD,qBAAa,aAAa;;IACxB,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAC9C,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IACtD;;;;OAIG;IACH,cAAc,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IACzD,2FAA2F;IAC3F,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IA0CzD,YAAY,KAAK,EAAE,KAAK,EAAE,MAAM,GAAE,MAAmB,EAAE,aAAa,CAAC,EAAE,aAAa,EAInF;IAED,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE5B;IAED;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAyD/D;IAOD,sGAAsG;IACtG,KAAK,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CA2ChC;IAED;;;;;;OAMG;IACH,oBAAoB,IAAI,IAAI,CAE3B;IAED,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAOnE;IAED,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CA6BrD;IAED,8EAA8E;IAC9E,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAwClF;IAED,4EAA4E;IAC5E,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,iDAAiD;IACjD,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,KAAK,IAAI,IAAI,CAmBZ;CA6fF"}