@honeybbq/teamspeak 1.0.0-beta.11 → 1.0.0-beta.13

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 (187) hide show
  1. package/README.md +52 -7
  2. package/dist/client/api/voice.d.ts +13 -0
  3. package/dist/client/api/voice.d.ts.map +1 -1
  4. package/dist/client/api/voice.js +20 -1
  5. package/dist/client/api/voice.js.map +1 -1
  6. package/dist/client/capabilities.d.ts +4 -4
  7. package/dist/client/capabilities.d.ts.map +1 -1
  8. package/dist/client/capabilities.js +3 -8
  9. package/dist/client/capabilities.js.map +1 -1
  10. package/dist/client/client.d.ts.map +1 -1
  11. package/dist/client/client.js +120 -18
  12. package/dist/client/client.js.map +1 -1
  13. package/dist/client/crypto/crypt.d.ts +25 -4
  14. package/dist/client/crypto/crypt.d.ts.map +1 -1
  15. package/dist/client/crypto/crypt.js +41 -9
  16. package/dist/client/crypto/crypt.js.map +1 -1
  17. package/dist/client/crypto/identity.d.ts +2 -0
  18. package/dist/client/crypto/identity.d.ts.map +1 -1
  19. package/dist/client/crypto/identity.js +2 -2
  20. package/dist/client/crypto/identity.js.map +1 -1
  21. package/dist/client/crypto/index.d.ts +1 -1
  22. package/dist/client/crypto/index.d.ts.map +1 -1
  23. package/dist/client/crypto/index.js +1 -1
  24. package/dist/client/crypto/index.js.map +1 -1
  25. package/dist/client/errors.d.ts +14 -0
  26. package/dist/client/errors.d.ts.map +1 -1
  27. package/dist/client/errors.js +28 -0
  28. package/dist/client/errors.js.map +1 -1
  29. package/dist/client/handshake/crypt-handshake.d.ts +8 -2
  30. package/dist/client/handshake/crypt-handshake.d.ts.map +1 -1
  31. package/dist/client/handshake/crypt-handshake.js +26 -20
  32. package/dist/client/handshake/crypt-handshake.js.map +1 -1
  33. package/dist/client/index.d.ts +3 -3
  34. package/dist/client/index.d.ts.map +1 -1
  35. package/dist/client/index.js +2 -2
  36. package/dist/client/index.js.map +1 -1
  37. package/dist/client/trace.d.ts +7 -0
  38. package/dist/client/trace.d.ts.map +1 -1
  39. package/dist/client/transport/handler.d.ts +2 -0
  40. package/dist/client/transport/handler.d.ts.map +1 -1
  41. package/dist/client/transport/handler.js +4 -0
  42. package/dist/client/transport/handler.js.map +1 -1
  43. package/dist/client/types.d.ts +25 -3
  44. package/dist/client/types.d.ts.map +1 -1
  45. package/dist/client/types.js +4 -0
  46. package/dist/client/types.js.map +1 -1
  47. package/dist/client/view.d.ts +71 -4
  48. package/dist/client/view.d.ts.map +1 -1
  49. package/dist/client/view.js +165 -5
  50. package/dist/client/view.js.map +1 -1
  51. package/dist/core/api/channels.d.ts +7 -3
  52. package/dist/core/api/channels.d.ts.map +1 -1
  53. package/dist/core/api/channels.js +5 -3
  54. package/dist/core/api/channels.js.map +1 -1
  55. package/dist/core/api/clients.d.ts +38 -1
  56. package/dist/core/api/clients.d.ts.map +1 -1
  57. package/dist/core/api/clients.js +33 -2
  58. package/dist/core/api/clients.js.map +1 -1
  59. package/dist/core/api/command.d.ts +18 -1
  60. package/dist/core/api/command.d.ts.map +1 -1
  61. package/dist/core/api/command.js +7 -1
  62. package/dist/core/api/command.js.map +1 -1
  63. package/dist/core/api/group-rows.d.ts +12 -0
  64. package/dist/core/api/group-rows.d.ts.map +1 -0
  65. package/dist/core/api/group-rows.js +34 -0
  66. package/dist/core/api/group-rows.js.map +1 -0
  67. package/dist/core/api/groups.d.ts.map +1 -1
  68. package/dist/core/api/groups.js +2 -13
  69. package/dist/core/api/groups.js.map +1 -1
  70. package/dist/core/api/instance.d.ts +10 -2
  71. package/dist/core/api/instance.d.ts.map +1 -1
  72. package/dist/core/api/instance.js +6 -2
  73. package/dist/core/api/instance.js.map +1 -1
  74. package/dist/core/api/moderation.d.ts +7 -0
  75. package/dist/core/api/moderation.d.ts.map +1 -1
  76. package/dist/core/api/moderation.js +7 -0
  77. package/dist/core/api/moderation.js.map +1 -1
  78. package/dist/core/api/parse.d.ts.map +1 -1
  79. package/dist/core/api/parse.js +1 -0
  80. package/dist/core/api/parse.js.map +1 -1
  81. package/dist/core/api/server.d.ts +9 -0
  82. package/dist/core/api/server.d.ts.map +1 -1
  83. package/dist/core/api/server.js +5 -13
  84. package/dist/core/api/server.js.map +1 -1
  85. package/dist/core/command/responses.d.ts.map +1 -1
  86. package/dist/core/command/responses.js +1 -0
  87. package/dist/core/command/responses.js.map +1 -1
  88. package/dist/core/errorcode.d.ts +16 -0
  89. package/dist/core/errorcode.d.ts.map +1 -1
  90. package/dist/core/errorcode.js +16 -0
  91. package/dist/core/errorcode.js.map +1 -1
  92. package/dist/core/events.d.ts +67 -6
  93. package/dist/core/events.d.ts.map +1 -1
  94. package/dist/core/index.d.ts +2 -2
  95. package/dist/core/index.d.ts.map +1 -1
  96. package/dist/core/index.js +1 -1
  97. package/dist/core/index.js.map +1 -1
  98. package/dist/core/internal.d.ts +1 -0
  99. package/dist/core/internal.d.ts.map +1 -1
  100. package/dist/core/internal.js +1 -0
  101. package/dist/core/internal.js.map +1 -1
  102. package/dist/core/notification-name.d.ts +4 -0
  103. package/dist/core/notification-name.d.ts.map +1 -1
  104. package/dist/core/notification-name.js +4 -0
  105. package/dist/core/notification-name.js.map +1 -1
  106. package/dist/core/notifications.d.ts +6 -2
  107. package/dist/core/notifications.d.ts.map +1 -1
  108. package/dist/core/notifications.js +32 -1
  109. package/dist/core/notifications.js.map +1 -1
  110. package/dist/core/types.d.ts +7 -0
  111. package/dist/core/types.d.ts.map +1 -1
  112. package/dist/core/types.js +16 -0
  113. package/dist/core/types.js.map +1 -1
  114. package/dist/query/client.d.ts +16 -7
  115. package/dist/query/client.d.ts.map +1 -1
  116. package/dist/query/client.js +55 -20
  117. package/dist/query/client.js.map +1 -1
  118. package/dist/query/errors.d.ts +21 -0
  119. package/dist/query/errors.d.ts.map +1 -1
  120. package/dist/query/errors.js +34 -0
  121. package/dist/query/errors.js.map +1 -1
  122. package/dist/query/index.d.ts +4 -3
  123. package/dist/query/index.d.ts.map +1 -1
  124. package/dist/query/index.js +3 -2
  125. package/dist/query/index.js.map +1 -1
  126. package/dist/query/options.d.ts +32 -19
  127. package/dist/query/options.d.ts.map +1 -1
  128. package/dist/query/options.js +21 -16
  129. package/dist/query/options.js.map +1 -1
  130. package/dist/query/ssh.d.ts +3 -1
  131. package/dist/query/ssh.d.ts.map +1 -1
  132. package/dist/query/ssh.js +4 -1
  133. package/dist/query/ssh.js.map +1 -1
  134. package/dist/query/stream.d.ts +16 -3
  135. package/dist/query/stream.d.ts.map +1 -1
  136. package/dist/query/stream.js +57 -6
  137. package/dist/query/stream.js.map +1 -1
  138. package/dist/query/tcp.js +1 -1
  139. package/dist/query/tcp.js.map +1 -1
  140. package/dist/query/transport.d.ts +39 -3
  141. package/dist/query/transport.d.ts.map +1 -1
  142. package/dist/query/web.d.ts +25 -7
  143. package/dist/query/web.d.ts.map +1 -1
  144. package/dist/query/web.js +40 -10
  145. package/dist/query/web.js.map +1 -1
  146. package/package.json +6 -5
  147. package/src/client/api/voice.ts +25 -1
  148. package/src/client/capabilities.ts +14 -11
  149. package/src/client/client.ts +128 -14
  150. package/src/client/crypto/crypt.ts +46 -9
  151. package/src/client/crypto/identity.ts +2 -2
  152. package/src/client/crypto/index.ts +1 -0
  153. package/src/client/errors.ts +31 -0
  154. package/src/client/handshake/crypt-handshake.ts +51 -16
  155. package/src/client/index.ts +4 -1
  156. package/src/client/trace.ts +7 -0
  157. package/src/client/transport/handler.ts +5 -0
  158. package/src/client/types.ts +25 -1
  159. package/src/client/view.ts +227 -8
  160. package/src/core/api/channels.ts +9 -3
  161. package/src/core/api/clients.ts +73 -2
  162. package/src/core/api/command.ts +22 -1
  163. package/src/core/api/group-rows.ts +38 -0
  164. package/src/core/api/groups.ts +1 -14
  165. package/src/core/api/instance.ts +20 -2
  166. package/src/core/api/moderation.ts +7 -0
  167. package/src/core/api/parse.ts +1 -0
  168. package/src/core/api/server.ts +13 -15
  169. package/src/core/command/responses.ts +1 -0
  170. package/src/core/errorcode.ts +16 -0
  171. package/src/core/events.ts +68 -6
  172. package/src/core/index.ts +2 -1
  173. package/src/core/internal.ts +1 -0
  174. package/src/core/notification-name.ts +4 -0
  175. package/src/core/notifications.ts +48 -17
  176. package/src/core/types.ts +14 -0
  177. package/src/query/client.ts +63 -20
  178. package/src/query/errors.ts +37 -0
  179. package/src/query/index.ts +9 -3
  180. package/src/query/options.ts +53 -33
  181. package/src/query/ssh.ts +9 -2
  182. package/src/query/stream.ts +65 -7
  183. package/src/query/tcp.ts +1 -1
  184. package/src/query/testing/live.ts +311 -0
  185. package/src/query/testing/ssh-keys.ts +67 -0
  186. package/src/query/transport.ts +40 -3
  187. package/src/query/web.ts +65 -16
package/README.md CHANGED
@@ -537,11 +537,53 @@ the way the voice protocol cannot: the same typed commands the core exports,
537
537
  plus the ones only an administrator may run, over the three transports a
538
538
  ServerQuery speaks.
539
539
 
540
- | Transport | Where | Server | Login | Notifications |
541
- | --------- | ------------ | ---------------- | ------------------- | ------------- |
542
- | `tcp` | 10011 | TeamSpeak 3 only | the `login` command | yes |
543
- | `ssh` | 10022 | both | the SSH login | yes |
544
- | `web` | 10080 (HTTP) | TeamSpeak 6 | the api key | **no** |
540
+ | Transport | Where | Server | Login | Notifications |
541
+ | --------- | --------------------------- | ---------------- | ----------------- | ------------- |
542
+ | `tcp` | 10011 | TeamSpeak 3 only | `transport.login` | yes |
543
+ | `ssh` | 10022 | both | the SSH login | yes |
544
+ | `web` | 10080 (HTTP), 10443 (HTTPS) | both | the api key | **no** |
545
+
546
+ TeamSpeak 3 (3.12 and later for WebQuery, 3.3 and later for SSH) serves SSH and
547
+ WebQuery as well as raw TCP, but only the raw port is on until
548
+ `query_protocols` lists the others; the official Docker image takes it as
549
+ `TS3SERVER_QUERY_PROTOCOLS=raw,ssh,http`. TeamSpeak 6 has no raw port. Its
550
+ WebQuery also answers a request with no api key as a guest; TeamSpeak 3 refuses
551
+ one.
552
+
553
+ WebQuery is reached over `http:` or `https:`, by the scheme of `url`. TeamSpeak 3
554
+ serves HTTPS on 10443 once `query_protocols` lists `https` and
555
+ `query_https_certificate_file` and `query_https_private_key_file` are set. The
556
+ built-in `fetch` verifies the certificate against the trust store Node uses and
557
+ never skips that. A certificate from a private CA, or a self-signed one, is
558
+ trusted by starting Node with `NODE_EXTRA_CA_CERTS=ca.pem`, or by a `fetch`
559
+ that trusts the CA:
560
+
561
+ ```typescript
562
+ import { readFileSync } from "node:fs";
563
+ import { Agent, request } from "node:https";
564
+
565
+ const agent = new Agent({ ca: readFileSync("ca.pem") });
566
+ const trusting = ((url: string, init: RequestInit) =>
567
+ new Promise<Response>((resolve, reject) => {
568
+ const req = request(
569
+ url,
570
+ { method: init.method, headers: init.headers as never, agent },
571
+ (res) => {
572
+ const chunks: Buffer[] = [];
573
+ res.on("data", (chunk: Buffer) => chunks.push(chunk));
574
+ res.on("end", () =>
575
+ resolve(new Response(Buffer.concat(chunks), { status: res.statusCode })),
576
+ );
577
+ },
578
+ );
579
+ req.on("error", reject);
580
+ req.end(init.body as string);
581
+ })) as typeof fetch;
582
+
583
+ new QueryClient({
584
+ transport: { kind: "web", url: "https://ts.example.com:10443", apiKey, fetch: trusting },
585
+ });
586
+ ```
545
587
 
546
588
  Only raw TCP and SSH carry notifications: the server pushes them down the same
547
589
  connection. WebQuery has no session to push to and refuses to register, so the
@@ -554,8 +596,11 @@ import { QueryClient } from "@honeybbq/teamspeak/query";
554
596
  import { listChannels } from "@honeybbq/teamspeak";
555
597
 
556
598
  const client = new QueryClient({
557
- transport: { kind: "tcp", host: "ts.example.com" }, // 10011
558
- login: { name: "serveradmin", password: process.env.QUERY_PASSWORD! },
599
+ transport: {
600
+ kind: "tcp", // 10011
601
+ host: "ts.example.com",
602
+ login: { name: "serveradmin", password: process.env.QUERY_PASSWORD! },
603
+ },
559
604
  server: { id: 1 },
560
605
  nickname: "bot",
561
606
  events: { categories: ["textserver", "textprivate"] },
@@ -14,6 +14,19 @@ import type { ChannelID, ClientID, CommandOptions } from "@honeybbq/teamspeak";
14
14
  * a `channelEdited` event, since it is no edit.
15
15
  */
16
16
  export declare function getChannelDescription(client: Client, cid: ChannelID, options?: CommandOptions): Promise<string>;
17
+ /**
18
+ * The virtual server's properties as the server sends them on request, which
19
+ * is a different set from `getServerInfo`'s: it has the settings, limits and
20
+ * counters (clients online, uptime, traffic) and lacks the identity ones such as
21
+ * the unique identifier. It is the whole row, counters included.
22
+ *
23
+ * The client's `view.server` takes every answer in, whoever asked, less the
24
+ * counters, so this is also how to bring it up to date after an edit the
25
+ * server did not spell out. The answer goes to the asker alone.
26
+ *
27
+ * @experimental New in 1.x and may change in a minor release.
28
+ */
29
+ export declare function getServerVariables(client: Client, options?: CommandOptions): Promise<Readonly<Record<string, string>>>;
17
30
  /**
18
31
  * Subscribe to a channel: receive its clients' events and voice without
19
32
  * joining it.
@@ -1 +1 @@
1
- {"version":3,"file":"voice.d.ts","sourceRoot":"","sources":["../../../src/client/api/voice.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE/E;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,8DAA8D;AAC9D,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,gDAAgD;AAChD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,oDAAoD;AACpD,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf;AAaD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAaD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf"}
1
+ {"version":3,"file":"voice.d.ts","sourceRoot":"","sources":["../../../src/client/api/voice.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE/E;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAO3C;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,8DAA8D;AAC9D,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,gDAAgD;AAChD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,oDAAoD;AACpD,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf;AAaD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAaD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAEf"}
@@ -6,7 +6,7 @@
6
6
  * `channelinfo` already carries the description. These run on the voice
7
7
  * client alone, which is why they take one rather than any CommandExecutor.
8
8
  */
9
- import { ErrorCode, ServerError } from "@honeybbq/teamspeak";
9
+ import { ErrorCode, NoDataError, ServerError } from "@honeybbq/teamspeak";
10
10
  /**
11
11
  * The channel's description, which `listChannels` omits for bandwidth. The
12
12
  * server answers with a `notifychanneledited` that the client does not report as
@@ -20,6 +20,25 @@ export async function getChannelDescription(client, cid, options) {
20
20
  const answer = rows.find((row) => row["cid"] === String(cid) && "channel_description" in row);
21
21
  return answer?.["channel_description"] ?? "";
22
22
  }
23
+ /**
24
+ * The virtual server's properties as the server sends them on request, which
25
+ * is a different set from `getServerInfo`'s: it has the settings, limits and
26
+ * counters (clients online, uptime, traffic) and lacks the identity ones such as
27
+ * the unique identifier. It is the whole row, counters included.
28
+ *
29
+ * The client's `view.server` takes every answer in, whoever asked, less the
30
+ * counters, so this is also how to bring it up to date after an edit the
31
+ * server did not spell out. The answer goes to the asker alone.
32
+ *
33
+ * @experimental New in 1.x and may change in a minor release.
34
+ */
35
+ export async function getServerVariables(client, options) {
36
+ const rows = await client.send({ command: "servergetvariables" }, options);
37
+ const answer = rows.find((row) => Object.keys(row).some((key) => key.startsWith("virtualserver_")));
38
+ if (answer === undefined)
39
+ throw new NoDataError("servergetvariables");
40
+ return answer;
41
+ }
23
42
  /**
24
43
  * Subscribe to a channel: receive its clients' events and voice without
25
44
  * joining it.
@@ -1 +1 @@
1
- {"version":3,"file":"voice.js","sourceRoot":"","sources":["../../../src/client/api/voice.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"voice.js","sourceRoot":"","sources":["../../../src/client/api/voice.ts"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@
11
11
  * its name, icon, banner and welcome message — so reading it costs no extra
12
12
  * round trip.
13
13
  */
14
- import { type IconID, type ServerFamily, type ServerID } from "@honeybbq/teamspeak";
14
+ import { HostMessageMode, type IconID, type ServerFamily, type ServerID } from "@honeybbq/teamspeak";
15
15
  import { type UIDAlgorithm } from "./crypto/identity.js";
16
16
  /** What a server said about itself in the handshake. */
17
17
  export interface ServerCapabilities {
@@ -48,10 +48,10 @@ export interface ServerCapabilities {
48
48
  readonly hostMessage: string;
49
49
  /**
50
50
  * How the host message is to be shown (`virtualserver_hostmessage_mode`).
51
- * Compare it with `HostMessageMode`; a server may send a value the table
52
- * does not name.
51
+ * A value the `HostMessageMode` table does not name is passed through as the
52
+ * server sent it.
53
53
  */
54
- readonly hostMessageMode: number;
54
+ readonly hostMessageMode: HostMessageMode;
55
55
  }
56
56
  /**
57
57
  * Read what a server says about itself in `initserver`, or a version string
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/client/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAc,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEhG,OAAO,EAA0B,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEjF,wDAAwD;AACxD,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,uFAAuF;IACvF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,gFAAgF;IAChF,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,uFAAuF;IACvF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,uGAAuG;IACvG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2FAA2F;IAC3F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACpD,kBAAkB,CAyBpB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,IAAI,kBAAkB,CAE9D"}
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/client/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAEL,eAAe,EAEf,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAA0B,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEjF,wDAAwD;AACxD,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,uFAAuF;IACvF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,gFAAgF;IAChF,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,uFAAuF;IACvF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,uGAAuG;IACvG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2FAA2F;IAC3F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC3C;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACpD,kBAAkB,CAqBpB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,IAAI,kBAAkB,CAE9D"}
@@ -11,7 +11,7 @@
11
11
  * its name, icon, banner and welcome message — so reading it costs no extra
12
12
  * round trip.
13
13
  */
14
- import { asServerID } from "@honeybbq/teamspeak";
14
+ import { asServerID, HostMessageMode, serverFamilyForVersion, } from "@honeybbq/teamspeak";
15
15
  import { parseIconID, parseUint64 } from "../core/internal.js";
16
16
  import { uidAlgorithmForVersion } from "./crypto/identity.js";
17
17
  /**
@@ -23,15 +23,10 @@ export function parseServerCapabilities(initserver) {
23
23
  const version = params["virtualserver_version"] ?? "";
24
24
  const parsed = Number.parseInt(version, 10);
25
25
  const major = Number.isNaN(parsed) ? 0 : parsed;
26
- let family = "unknown";
27
- if (major === 3)
28
- family = "ts3";
29
- else if (major >= 6)
30
- family = "ts6";
31
26
  return {
32
27
  version,
33
28
  major,
34
- family,
29
+ family: serverFamilyForVersion(version),
35
30
  uidAlgorithm: uidAlgorithmForVersion(version),
36
31
  name: params["virtualserver_name"] ?? "",
37
32
  iconID: parseIconID(params["virtualserver_icon_id"]),
@@ -54,6 +49,6 @@ export function unknownServerCapabilities() {
54
49
  }
55
50
  function hostMessageMode(value) {
56
51
  const parsed = Number.parseInt(value ?? "", 10);
57
- return Number.isNaN(parsed) ? 0 : parsed;
52
+ return (Number.isNaN(parsed) ? HostMessageMode.None : parsed);
58
53
  }
59
54
  //# sourceMappingURL=capabilities.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/client/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAiD,MAAM,qBAAqB,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAqB,MAAM,sBAAsB,CAAC;AA2CjF;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAqD;IAErD,MAAM,MAAM,GACV,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;IACtF,MAAM,OAAO,GAAG,MAAM,CAAC,uBAAuB,CAAC,IAAI,EAAE,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAEhD,IAAI,MAAM,GAAiB,SAAS,CAAC;IACrC,IAAI,KAAK,KAAK,CAAC;QAAE,MAAM,GAAG,KAAK,CAAC;SAC3B,IAAI,KAAK,IAAI,CAAC;QAAE,MAAM,GAAG,KAAK,CAAC;IAEpC,OAAO;QACL,OAAO;QACP,KAAK;QACL,MAAM;QACN,YAAY,EAAE,sBAAsB,CAAC,OAAO,CAAC;QAC7C,IAAI,EAAE,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE;QACxC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC;QACpD,kBAAkB,EAAE,MAAM,CAAC,kCAAkC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS;QACnF,cAAc,EAAE,MAAM,CAAC,8BAA8B,CAAC,IAAI,EAAE;QAC5D,QAAQ,EAAE,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC;QACnE,SAAS,EAAE,MAAM,CAAC,iCAAiC,CAAC,IAAI,EAAE;QAC1D,WAAW,EAAE,MAAM,CAAC,2BAA2B,CAAC,IAAI,EAAE;QACtD,eAAe,EAAE,eAAe,CAAC,MAAM,CAAC,gCAAgC,CAAC,CAAC;KAC3E,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO,uBAAuB,CAAC,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,eAAe,CAAC,KAAyB;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/client/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,UAAU,EACV,eAAe,EACf,sBAAsB,GAIvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAqB,MAAM,sBAAsB,CAAC;AA2CjF;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAqD;IAErD,MAAM,MAAM,GACV,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;IACtF,MAAM,OAAO,GAAG,MAAM,CAAC,uBAAuB,CAAC,IAAI,EAAE,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAEhD,OAAO;QACL,OAAO;QACP,KAAK;QACL,MAAM,EAAE,sBAAsB,CAAC,OAAO,CAAC;QACvC,YAAY,EAAE,sBAAsB,CAAC,OAAO,CAAC;QAC7C,IAAI,EAAE,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE;QACxC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC;QACpD,kBAAkB,EAAE,MAAM,CAAC,kCAAkC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS;QACnF,cAAc,EAAE,MAAM,CAAC,8BAA8B,CAAC,IAAI,EAAE;QAC5D,QAAQ,EAAE,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC;QACnE,SAAS,EAAE,MAAM,CAAC,iCAAiC,CAAC,IAAI,EAAE;QAC1D,WAAW,EAAE,MAAM,CAAC,2BAA2B,CAAC,IAAI,EAAE;QACtD,eAAe,EAAE,eAAe,CAAC,MAAM,CAAC,gCAAgC,CAAC,CAAC;KAC3E,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO,uBAAuB,CAAC,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,eAAe,CAAC,KAAyB;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAChD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAoB,CAAC;AACnF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,7 @@ import { buildEventChain } from "./events.js";
17
17
  import { processInit1 } from "./handshake/crypt-handshake.js";
18
18
  import { handleHandshakeInitIV, handleHandshakeExpand2, defaultClientVersion, handleInitServer, prepareClientPassword, } from "./handshake.js";
19
19
  import { handleNotification } from "../core/internal.js";
20
- import { parseChannel, parseCommand } from "../core/internal.js";
20
+ import { parseChannel, parseChannelGroup, parseCommand, parseServerGroup, parseUint16, } from "../core/internal.js";
21
21
  import { CommandThrottle } from "./throttle.js";
22
22
  import { splitCommandRows, sleep } from "../core/internal.js";
23
23
  import { isAutoNicknameMatch } from "./helpers.js";
@@ -83,6 +83,24 @@ const DEFAULT_COMMAND_TIMEOUT_MS = 10_000;
83
83
  const DISCONNECT_TIMEOUT_MS = 1_000;
84
84
  /** How long each reconnection attempt may take. */
85
85
  const RECONNECT_ATTEMPT_TIMEOUT_MS = 30_000;
86
+ /** What an attempt is waiting for now, for the report of an attempt that ended. */
87
+ function describeWaiting(trace, clientEkPending) {
88
+ if (trace.phase === ConnectPhase.Open) {
89
+ return trace.target === "" ? "the server address to resolve" : "the connection to open";
90
+ }
91
+ if (trace.phase === ConnectPhase.Join) {
92
+ return clientEkPending
93
+ ? "the server's answer to clientek"
94
+ : "the server's answer to clientinit";
95
+ }
96
+ if (trace.stage === "puzzleSolving")
97
+ return "the RSA puzzle to be solved";
98
+ if (trace.stage === "puzzleAnswered")
99
+ return "the server's answer to the RSA puzzle";
100
+ return trace.init1Step < 0
101
+ ? "the server's first answer to init1"
102
+ : `the server's init1 step after step ${trace.init1Step}`;
103
+ }
86
104
  /** The `initserver` parameters a trace never sees, because they could carry a secret. */
87
105
  const SECRET_INITSERVER_PARAMS = new Set([
88
106
  "client_server_password",
@@ -221,6 +239,8 @@ export class Client {
221
239
  /** Deliveries waiting for their turn; see #emit. */
222
240
  #queue = [];
223
241
  #draining = false;
242
+ /** The group list rows of the command line being handled, by the name of the line. */
243
+ #groupLine;
224
244
  #voiceDropped = 0;
225
245
  #voiceDropWarnedAt = -Infinity;
226
246
  #eventMiddlewares;
@@ -237,7 +257,7 @@ export class Client {
237
257
  this.#fileTransferSocketFactory = options.fileTransferSocketFactory;
238
258
  this.#reconnectOptions = options.reconnect;
239
259
  this.#trace = options.trace === undefined ? undefined : { ...options.trace };
240
- this.#viewStore = new ViewStore(this.#logger, () => this.#clid);
260
+ this.#viewStore = new ViewStore(this.#logger, () => this.#clid, () => this.#scheduleDrain());
241
261
  this.#clients = this.#viewStore.roster;
242
262
  this.#crypt = new Crypt(identity);
243
263
  this.#handler = this.#newHandler();
@@ -362,16 +382,27 @@ export class Client {
362
382
  sessionStarted: false,
363
383
  welcomeDone: false,
364
384
  channels: 0,
385
+ stage: "init1",
386
+ init1Step: -1,
365
387
  };
366
388
  attempt.trace = trace;
367
- attempt.onFail = (error) => this.#callHook(this.#trace?.attemptFailed, () => ({
368
- attempt: trace.attempt,
369
- reconnect: trace.reconnect,
370
- phase: trace.phase,
371
- error,
372
- target: trace.target,
373
- durationMs: performance.now() - trace.startedAt,
374
- }));
389
+ attempt.onFail = (error) => {
390
+ const waitingFor = describeWaiting(trace, this.#handler.clientEkPending);
391
+ this.#logger.info("connection attempt ended", {
392
+ phase: trace.phase,
393
+ waitingFor,
394
+ error: String(error),
395
+ });
396
+ this.#callHook(this.#trace?.attemptFailed, () => ({
397
+ attempt: trace.attempt,
398
+ reconnect: trace.reconnect,
399
+ phase: trace.phase,
400
+ error,
401
+ target: trace.target,
402
+ waitingFor,
403
+ durationMs: performance.now() - trace.startedAt,
404
+ }));
405
+ };
375
406
  // The handshake may complete just as the signal fires, in which case
376
407
  // #failConnection leaves the session alone and the caller gets the
377
408
  // connection it made rather than one it would believe had failed.
@@ -1076,9 +1107,32 @@ export class Client {
1076
1107
  if (pType === 8 /* Init1 */) {
1077
1108
  if (this.#crypt.cryptoInitComplete)
1078
1109
  return;
1079
- const response = processInit1(this.#crypt, p.data);
1080
- if (response) {
1081
- this.#handler.sendPacket(PacketType.Init1, response, 0);
1110
+ const signal = this.#attempt.signal;
1111
+ const handler = this.#handler;
1112
+ const trace = this.#attempt.trace;
1113
+ const step = p.data[0] ?? 0x7f;
1114
+ const response = processInit1(this.#crypt, p.data, signal);
1115
+ if (response instanceof Promise) {
1116
+ // The puzzle: solved in slices, so the loop keeps running meanwhile.
1117
+ if (trace !== undefined)
1118
+ trace.stage = "puzzleSolving";
1119
+ response.then((answer) => {
1120
+ if (answer && !signal.aborted) {
1121
+ handler.sendPacket(PacketType.Init1, answer, 0);
1122
+ if (trace !== undefined)
1123
+ trace.stage = "puzzleAnswered";
1124
+ }
1125
+ }, (error) => {
1126
+ // An attempt that ended did so for its own reason; the abandoned
1127
+ // solve has nothing more to report.
1128
+ if (!signal.aborted)
1129
+ this.#handleReceiveError(error);
1130
+ });
1131
+ }
1132
+ else if (response) {
1133
+ handler.sendPacket(PacketType.Init1, response, 0);
1134
+ if (trace !== undefined)
1135
+ trace.init1Step = step === 0x7f ? -1 : step;
1082
1136
  }
1083
1137
  return;
1084
1138
  }
@@ -1126,6 +1180,23 @@ export class Client {
1126
1180
  for (const row of splitCommandRows(trimmed)) {
1127
1181
  this.#handleCommandStr(row);
1128
1182
  }
1183
+ this.#applyGroupLine();
1184
+ }
1185
+ }
1186
+ /**
1187
+ * A group list is a whole set, and the server sends it as one command line,
1188
+ * so it is applied once its last row has been handled.
1189
+ */
1190
+ #applyGroupLine() {
1191
+ const line = this.#groupLine;
1192
+ if (line === undefined)
1193
+ return;
1194
+ this.#groupLine = undefined;
1195
+ if (line.name === "notifyservergrouplist") {
1196
+ this.#viewStore.setServerGroups(line.rows.map(parseServerGroup).filter((group) => group.id !== 0n));
1197
+ }
1198
+ else {
1199
+ this.#viewStore.setChannelGroups(line.rows.map(parseChannelGroup).filter((group) => group.id !== 0n));
1129
1200
  }
1130
1201
  }
1131
1202
  #handleCommandStr(s) {
@@ -1194,8 +1265,21 @@ export class Client {
1194
1265
  }
1195
1266
  if (cmd.name === "notifyconnectioninforequest")
1196
1267
  this.#answerConnectionInfoRequest();
1268
+ if (cmd.name === "notifyservergrouplist" || cmd.name === "notifychannelgrouplist") {
1269
+ if (this.#groupLine?.name !== cmd.name)
1270
+ this.#applyGroupLine();
1271
+ this.#groupLine ??= { name: cmd.name, rows: [] };
1272
+ this.#groupLine.rows.push(cmd.params);
1273
+ }
1274
+ else if (cmd.name === "notifyserverupdated") {
1275
+ this.#viewStore.mergeServer(cmd.params);
1276
+ }
1277
+ // The roster entry goes with the notification, so it is read first.
1278
+ const leaving = cmd.name === "notifyclientleftview"
1279
+ ? this.#clients.get(parseUint16(cmd.params["clid"] ?? ""))
1280
+ : undefined;
1197
1281
  const result = handleNotification(cmd, this.#clid, this.#clients);
1198
- this.#processNotificationResult(result);
1282
+ this.#processNotificationResult(result, leaving);
1199
1283
  if (this.#listeners.get("notification")?.length || this.#eventMiddlewares.length > 0) {
1200
1284
  this.#emitServerEvent({
1201
1285
  name: "notification",
@@ -1221,6 +1305,7 @@ export class Client {
1221
1305
  // report a connection whose next command — clientinit with its password
1222
1306
  // hashes among them — goes out under that dummy key.
1223
1307
  if (this.#status === ClientStatus.Connecting && this.#crypt.cryptoInitComplete) {
1308
+ this.#viewStore.seedServer(cmd.params);
1224
1309
  handleInitServer(this.#internals, cmd.params);
1225
1310
  }
1226
1311
  break;
@@ -1273,7 +1358,7 @@ export class Client {
1273
1358
  });
1274
1359
  }
1275
1360
  }
1276
- #processNotificationResult(result) {
1361
+ #processNotificationResult(result, leaving) {
1277
1362
  switch (result.kind) {
1278
1363
  case "clientEnter": {
1279
1364
  const info = result.info;
@@ -1303,7 +1388,7 @@ export class Client {
1303
1388
  break;
1304
1389
  }
1305
1390
  case "clientLeave": {
1306
- const event = result.event;
1391
+ const event = leaving === undefined ? result.event : { ...result.event, previous: leaving };
1307
1392
  this.#emitServerEvent({ name: "clientLeave", payload: event });
1308
1393
  if (!result.isSelf)
1309
1394
  break;
@@ -1353,10 +1438,15 @@ export class Client {
1353
1438
  this.#viewStore.applyMoved(result.event);
1354
1439
  this.#emitServerEvent({ name: "channelMoved", payload: result.event });
1355
1440
  break;
1356
- case "channelDeleted":
1441
+ case "channelDeleted": {
1442
+ const previous = this.#viewStore.channelBeforeDeletion(result.event.channelID);
1357
1443
  this.#viewStore.applyDeleted(result.event);
1358
- this.#emitServerEvent({ name: "channelDeleted", payload: result.event });
1444
+ this.#emitServerEvent({
1445
+ name: "channelDeleted",
1446
+ payload: previous === undefined ? result.event : { ...result.event, previous },
1447
+ });
1359
1448
  break;
1449
+ }
1360
1450
  case "channelDescriptionChanged":
1361
1451
  this.#emitServerEvent({ name: "channelDescriptionChanged", payload: result.event });
1362
1452
  break;
@@ -1364,6 +1454,7 @@ export class Client {
1364
1454
  this.#emitServerEvent({ name: "channelPasswordChanged", payload: result.event });
1365
1455
  break;
1366
1456
  case "serverEdited":
1457
+ this.#viewStore.patchServer(result.event.changes);
1367
1458
  this.#emitServerEvent({ name: "serverEdited", payload: result.event });
1368
1459
  break;
1369
1460
  case "channelSubscribed":
@@ -1380,6 +1471,9 @@ export class Client {
1380
1471
  case "clientChatComposing":
1381
1472
  this.#emitServerEvent({ name: "clientChatComposing", payload: result.event });
1382
1473
  break;
1474
+ case "clientChatClosed":
1475
+ this.#emitServerEvent({ name: "clientChatClosed", payload: result.event });
1476
+ break;
1383
1477
  case "poked":
1384
1478
  this.#emitServerEvent({ name: "poked", payload: result.event });
1385
1479
  break;
@@ -1468,6 +1562,9 @@ export class Client {
1468
1562
  */
1469
1563
  #enqueue(delivery) {
1470
1564
  this.#queue.push(delivery);
1565
+ this.#scheduleDrain();
1566
+ }
1567
+ #scheduleDrain() {
1471
1568
  if (this.#draining)
1472
1569
  return;
1473
1570
  this.#draining = true;
@@ -1477,6 +1574,11 @@ export class Client {
1477
1574
  try {
1478
1575
  while (this.#queue.length > 0)
1479
1576
  this.#queue.shift()();
1577
+ // Everything handled so far is delivered: say once that the view moved.
1578
+ // Listeners cannot change the view, so this is the last word of the run.
1579
+ const revision = this.#viewStore.announce();
1580
+ if (revision !== undefined)
1581
+ this.#deliver("viewChanged", { revision });
1480
1582
  }
1481
1583
  finally {
1482
1584
  if (this.#queue.length > 0)