@honeybbq/teamspeak 1.0.0-beta.21 → 1.0.0-beta.22

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 (127) hide show
  1. package/README.md +2 -1
  2. package/dist/client/crypto/identity.d.ts +15 -4
  3. package/dist/client/crypto/identity.d.ts.map +1 -1
  4. package/dist/client/crypto/identity.js +19 -1
  5. package/dist/client/crypto/identity.js.map +1 -1
  6. package/dist/client/crypto/index.d.ts +1 -1
  7. package/dist/client/crypto/index.d.ts.map +1 -1
  8. package/dist/client/crypto/index.js +1 -0
  9. package/dist/client/crypto/index.js.map +1 -1
  10. package/dist/client/discovery/resolver.d.ts.map +1 -1
  11. package/dist/client/discovery/resolver.js +9 -6
  12. package/dist/client/discovery/resolver.js.map +1 -1
  13. package/dist/client/handshake/license.js +1 -0
  14. package/dist/client/handshake/license.js.map +1 -1
  15. package/dist/client/index.d.ts +6 -5
  16. package/dist/client/index.d.ts.map +1 -1
  17. package/dist/client/index.js +4 -2
  18. package/dist/client/index.js.map +1 -1
  19. package/dist/client/trace.d.ts +4 -1
  20. package/dist/client/trace.d.ts.map +1 -1
  21. package/dist/client/transfer.d.ts +10 -1
  22. package/dist/client/transfer.d.ts.map +1 -1
  23. package/dist/client/transfer.js +10 -0
  24. package/dist/client/transfer.js.map +1 -1
  25. package/dist/client/transport/handler.d.ts.map +1 -1
  26. package/dist/client/transport/handler.js +3 -3
  27. package/dist/client/transport/handler.js.map +1 -1
  28. package/dist/client/transport/packet.d.ts +5 -0
  29. package/dist/client/transport/packet.d.ts.map +1 -1
  30. package/dist/client/transport/packet.js +9 -1
  31. package/dist/client/transport/packet.js.map +1 -1
  32. package/dist/client/types.d.ts +28 -1
  33. package/dist/client/types.d.ts.map +1 -1
  34. package/dist/client/types.js +21 -0
  35. package/dist/client/types.js.map +1 -1
  36. package/dist/client/view.d.ts +24 -8
  37. package/dist/client/view.d.ts.map +1 -1
  38. package/dist/client/view.js +24 -1
  39. package/dist/client/view.js.map +1 -1
  40. package/dist/core/api/channels.d.ts +3 -3
  41. package/dist/core/api/channels.d.ts.map +1 -1
  42. package/dist/core/api/clients.d.ts +13 -1
  43. package/dist/core/api/clients.d.ts.map +1 -1
  44. package/dist/core/api/clients.js +12 -0
  45. package/dist/core/api/clients.js.map +1 -1
  46. package/dist/core/api/command.d.ts +11 -3
  47. package/dist/core/api/command.d.ts.map +1 -1
  48. package/dist/core/api/command.js +8 -2
  49. package/dist/core/api/command.js.map +1 -1
  50. package/dist/core/api/groups.d.ts +2 -1
  51. package/dist/core/api/groups.d.ts.map +1 -1
  52. package/dist/core/api/groups.js.map +1 -1
  53. package/dist/core/api/instance.d.ts +5 -3
  54. package/dist/core/api/instance.d.ts.map +1 -1
  55. package/dist/core/api/instance.js.map +1 -1
  56. package/dist/core/api/server.d.ts +40 -10
  57. package/dist/core/api/server.d.ts.map +1 -1
  58. package/dist/core/api/server.js +2 -2
  59. package/dist/core/api/server.js.map +1 -1
  60. package/dist/core/command-name.d.ts +6 -0
  61. package/dist/core/command-name.d.ts.map +1 -1
  62. package/dist/core/command-name.js +6 -0
  63. package/dist/core/command-name.js.map +1 -1
  64. package/dist/core/enums.d.ts +94 -4
  65. package/dist/core/enums.d.ts.map +1 -1
  66. package/dist/core/enums.js +91 -4
  67. package/dist/core/enums.js.map +1 -1
  68. package/dist/core/index.d.ts +3 -3
  69. package/dist/core/index.d.ts.map +1 -1
  70. package/dist/core/index.js +2 -2
  71. package/dist/core/index.js.map +1 -1
  72. package/dist/core/property-name.d.ts +3 -3
  73. package/dist/core/property-name.d.ts.map +1 -1
  74. package/dist/core/property-name.js +3 -3
  75. package/dist/core/property-name.js.map +1 -1
  76. package/dist/core/types.d.ts +14 -4
  77. package/dist/core/types.d.ts.map +1 -1
  78. package/dist/core/types.js +16 -4
  79. package/dist/core/types.js.map +1 -1
  80. package/dist/query/client.d.ts +55 -1
  81. package/dist/query/client.d.ts.map +1 -1
  82. package/dist/query/client.js +53 -0
  83. package/dist/query/client.js.map +1 -1
  84. package/dist/query/index.d.ts +2 -2
  85. package/dist/query/index.d.ts.map +1 -1
  86. package/dist/query/index.js +1 -1
  87. package/dist/query/index.js.map +1 -1
  88. package/dist/query/options.d.ts +21 -1
  89. package/dist/query/options.d.ts.map +1 -1
  90. package/dist/query/options.js +34 -5
  91. package/dist/query/options.js.map +1 -1
  92. package/dist/stream/index.d.ts +2 -1
  93. package/dist/stream/index.d.ts.map +1 -1
  94. package/dist/stream/index.js +1 -0
  95. package/dist/stream/index.js.map +1 -1
  96. package/dist/stream/types.d.ts +243 -25
  97. package/dist/stream/types.d.ts.map +1 -1
  98. package/dist/stream/types.js +235 -1
  99. package/dist/stream/types.js.map +1 -1
  100. package/package.json +12 -10
  101. package/src/client/crypto/identity.ts +16 -5
  102. package/src/client/crypto/index.ts +1 -1
  103. package/src/client/discovery/resolver.ts +9 -6
  104. package/src/client/handshake/license.ts +1 -0
  105. package/src/client/index.ts +10 -5
  106. package/src/client/trace.ts +4 -1
  107. package/src/client/transfer.ts +11 -1
  108. package/src/client/transport/handler.ts +3 -2
  109. package/src/client/transport/packet.ts +10 -1
  110. package/src/client/types.ts +30 -1
  111. package/src/client/view.ts +24 -9
  112. package/src/core/api/channels.ts +3 -3
  113. package/src/core/api/clients.ts +14 -1
  114. package/src/core/api/command.ts +16 -5
  115. package/src/core/api/groups.ts +2 -1
  116. package/src/core/api/instance.ts +5 -3
  117. package/src/core/api/server.ts +39 -10
  118. package/src/core/command-name.ts +6 -0
  119. package/src/core/enums.ts +111 -4
  120. package/src/core/index.ts +12 -2
  121. package/src/core/property-name.ts +3 -3
  122. package/src/core/types.ts +19 -8
  123. package/src/query/client.ts +68 -6
  124. package/src/query/index.ts +1 -2
  125. package/src/query/options.ts +26 -13
  126. package/src/stream/index.ts +14 -8
  127. package/src/stream/types.ts +321 -27
@@ -270,8 +270,21 @@ export async function getClientProperties(
270
270
  return firstRow(rows, "clientinfo");
271
271
  }
272
272
 
273
+ /** The values of the table below, before freezing. */
274
+ const connectionTrafficClassValues = {
275
+ /** Voice and whisper packets. */
276
+ Speech: "speech",
277
+ /** Ping and pong packets. */
278
+ Keepalive: "keepalive",
279
+ /** Every other packet: commands, acknowledgements and the handshake. */
280
+ Control: "control",
281
+ } as const;
273
282
  /** The three classes of traffic the server counts. */
274
- export type ConnectionTrafficClass = "speech" | "keepalive" | "control";
283
+ export const ConnectionTrafficClass: typeof connectionTrafficClassValues =
284
+ /* @__PURE__ */ Object.freeze(connectionTrafficClassValues);
285
+ /** One of {@link ConnectionTrafficClass}. */
286
+ export type ConnectionTrafficClass =
287
+ (typeof ConnectionTrafficClass)[keyof typeof ConnectionTrafficClass];
275
288
 
276
289
  /** One direction of one class of a client's traffic, as the client reported it. */
277
290
  export interface ClientTraffic {
@@ -289,10 +289,17 @@ export function encodeFields<T extends object>(fields: T, names: WireNames<T>):
289
289
  return out;
290
290
  }
291
291
 
292
- /** Raw wire properties, sent as given; a value that is not a string is left out. */
293
- export const rawProperties = (settings: Readonly<Record<string, string>>): Params =>
294
- Object.entries(settings).filter(
295
- (entry): entry is [string, string] => typeof entry[1] === "string",
292
+ /** The kinds of value a raw property is sent as. */
293
+ const propertyKinds: ReadonlySet<string> = new Set(["string", "number", "bigint", "boolean"]);
294
+
295
+ /**
296
+ * Raw wire properties, sent as given: a string as is, a number or bigint in
297
+ * decimal, a boolean as 1 or 0. Any other value, undefined among them, is left
298
+ * out.
299
+ */
300
+ export const rawProperties = (settings: Readonly<Record<string, unknown>>): Params =>
301
+ Object.entries(settings).filter((entry): entry is [string, string | number | bigint | boolean] =>
302
+ propertyKinds.has(typeof entry[1]),
296
303
  );
297
304
 
298
305
  /** An encoder that omits an empty string instead of sending it. */
@@ -668,7 +675,11 @@ export interface Channel {
668
675
  readonly isForcedSilence?: boolean | undefined;
669
676
  /** The URL of the channel's banner image (`channel_banner_gfx_url`). */
670
677
  readonly bannerURL?: string | undefined;
671
- /** How the banner is scaled (`channel_banner_mode`). */
678
+ /**
679
+ * How the banner is fitted to the channel (`channel_banner_mode`); compare it
680
+ * with `BannerMode`. A plain number, since a server may send a mode that
681
+ * table does not name.
682
+ */
672
683
  readonly bannerMode?: number | undefined;
673
684
  /**
674
685
  * How long the channel has had no client, in milliseconds (`seconds_empty`,
@@ -50,6 +50,7 @@ import { parseChannelGroup } from "./group-rows.js";
50
50
  import { PermissionTarget, PrivilegeKeyType } from "../enums.js";
51
51
  import type { GroupType } from "../enums.js";
52
52
  import type { Permission } from "../permission.js";
53
+ import type { PermissionName } from "../permission-name.js";
53
54
  import { escape, unescape } from "../command/command.js";
54
55
  import type { CustomProperty } from "./clients.js";
55
56
 
@@ -396,7 +397,7 @@ export async function listPermissions(
396
397
  */
397
398
  export async function getPermissionIDByName(
398
399
  client: CommandExecutor,
399
- name: string,
400
+ name: PermissionName | (string & {}),
400
401
  options?: CommandOptions,
401
402
  ): Promise<PermissionID | undefined> {
402
403
  const rows = await query(client, "permidgetbyname", [["permsid", name]], options);
@@ -27,6 +27,7 @@ import {
27
27
  SECOND,
28
28
  } from "./command.js";
29
29
  import type { WireNames } from "./command.js";
30
+ import type { ServerSettings } from "./server.js";
30
31
  import type { CommandExecutor, CommandOptions } from "../command/request.js";
31
32
  import type { ChannelID, ServerID } from "../command/ids.js";
32
33
  import { asChannelID, asServerID } from "../command/ids.js";
@@ -40,8 +41,9 @@ export interface VirtualServer {
40
41
  /** The voice port it listens on (`virtualserver_port`). */
41
42
  readonly port: number;
42
43
  /**
43
- * Its state, as the server words it: "online", "offline", "booting up",
44
- * "shutting down", "online virtual" (`virtualserver_status`).
44
+ * Its state, as the server words it (`virtualserver_status`); compare it
45
+ * with `VirtualServerStatus`. A plain string, since a server may send a
46
+ * state that table does not name.
45
47
  */
46
48
  readonly status: string;
47
49
  /** Its name (`virtualserver_name`); "" with `short`. */
@@ -165,7 +167,7 @@ export interface ServerCreated {
165
167
  export async function createServer(
166
168
  client: CommandExecutor,
167
169
  name: string,
168
- settings: Readonly<Record<string, string>> = {},
170
+ settings: ServerSettings = {},
169
171
  options?: CommandOptions,
170
172
  ): Promise<ServerCreated> {
171
173
  const rows = await query(
@@ -55,10 +55,11 @@ import {
55
55
  asServerID,
56
56
  asUID,
57
57
  } from "../command/ids.js";
58
- import type { GroupAutoUpdateType, GroupType } from "../enums.js";
58
+ import type { BindingSubsystem, GroupAutoUpdateType, GroupType } from "../enums.js";
59
59
  import type { GroupDeleteOptions } from "./groups.js";
60
60
  import { parseServerGroup } from "./group-rows.js";
61
61
  import type { Permission } from "../permission.js";
62
+ import type { PropertyName } from "../property-name.js";
62
63
 
63
64
  /** A server group as `servergrouplist` reports it. */
64
65
  export interface ServerGroup {
@@ -107,6 +108,29 @@ export async function getServerInfo(
107
108
  return firstRow(await query(client, "serverinfo", [], options), "serverinfo");
108
109
  }
109
110
 
111
+ /**
112
+ * A raw property's value: a string is sent as is, a number or bigint in
113
+ * decimal and a boolean as 1 or 0. So a value read back as text, or a table's
114
+ * constant such as `BannerMode.AdjustKeepAspect`, is written without
115
+ * converting it.
116
+ */
117
+ export type PropertyValue = string | number | bigint | boolean;
118
+
119
+ /**
120
+ * Raw `virtualserver_*` properties, for {@link editServer} and
121
+ * `createServer`. The keys `PropertyName` names are offered by an editor; any
122
+ * other key is sent as well, since a server may know properties the table does
123
+ * not. A key whose value is undefined is left out.
124
+ */
125
+ export type ServerSettings = {
126
+ readonly [K in Extract<PropertyName, `virtualserver_${string}`>]?: PropertyValue | undefined;
127
+ } & { readonly [key: string]: PropertyValue | undefined };
128
+
129
+ /** Raw `serverinstance_*` properties, for {@link editInstance}, as {@link ServerSettings} are. */
130
+ export type InstanceSettings = {
131
+ readonly [K in Extract<PropertyName, `serverinstance_${string}`>]?: PropertyValue | undefined;
132
+ } & { readonly [key: string]: PropertyValue | undefined };
133
+
110
134
  /**
111
135
  * Change the virtual server's settings. Only the properties you pass are sent.
112
136
  *
@@ -114,12 +138,12 @@ export async function getServerInfo(
114
138
  * wire properties from `serverinfo`, passed through as given rather than
115
139
  * enumerated: there are well over a hundred, they are version-dependent, and a
116
140
  * value read back from {@link getServerInfo} should be writable straight back.
117
- * The values are strings, as `getServerInfo` returns them. The editable keys
118
- * are marked in `PropertyName`.
141
+ * A value may also be a number or a boolean; see {@link PropertyValue}. The
142
+ * editable keys are marked in `PropertyName`.
119
143
  */
120
144
  export async function editServer(
121
145
  client: CommandExecutor,
122
- settings: Readonly<Record<string, string>>,
146
+ settings: ServerSettings,
123
147
  options?: CommandOptions,
124
148
  ): Promise<void> {
125
149
  await exec(client, "serveredit", rawProperties(settings), options);
@@ -162,7 +186,7 @@ export async function getInstanceInfo(
162
186
  */
163
187
  export async function editInstance(
164
188
  client: CommandExecutor,
165
- settings: Readonly<Record<string, string>>,
189
+ settings: InstanceSettings,
166
190
  options?: CommandOptions,
167
191
  ): Promise<void> {
168
192
  await exec(client, "instanceedit", rawProperties(settings), options);
@@ -171,9 +195,10 @@ export async function editInstance(
171
195
  /** An address the instance listens on. */
172
196
  export interface Binding {
173
197
  /**
174
- * What listens there: `voice`, `query` or `filetransfer`. The server does not
198
+ * What listens there; compare it with `BindingSubsystem`. The server does not
175
199
  * name it in each row, so it is the subsystem asked for, or `voice` when none
176
- * was.
200
+ * was. A plain string, since a server may send a subsystem that table does
201
+ * not name.
177
202
  */
178
203
  readonly subsystem: string;
179
204
  /** The address. */
@@ -184,8 +209,8 @@ export interface Binding {
184
209
 
185
210
  /** Which bindings {@link listBindings} reports. */
186
211
  export interface BindingListOptions extends CommandOptions {
187
- /** Only this subsystem's: `voice`, `query` or `filetransfer`; unset for all (`subsystem`). */
188
- readonly subsystem?: string | undefined;
212
+ /** Only this subsystem's; unset for all (`subsystem`). */
213
+ readonly subsystem?: BindingSubsystem | undefined;
189
214
  }
190
215
 
191
216
  /**
@@ -234,7 +259,11 @@ export async function getVersion(
234
259
 
235
260
  /** Which server and client a connection is, as `whoami` reports it. */
236
261
  export interface WhoAmI {
237
- /** The virtual server's state, such as "online" (`virtualserver_status`). */
262
+ /**
263
+ * The virtual server's state (`virtualserver_status`); compare it with
264
+ * `VirtualServerStatus`. A plain string, since a server may send a state that
265
+ * table does not name.
266
+ */
238
267
  readonly serverStatus: string;
239
268
  /** The virtual server's id, 0 when none is selected (`virtualserver_id`). */
240
269
  readonly serverID: ServerID;
@@ -96,6 +96,10 @@ const commandNameValues = {
96
96
  ClientAddPerm: "clientaddperm",
97
97
  /** `clientaddservergroup`: Adds a client to one or more server groups specified with sgid. */
98
98
  ClientAddServerGroup: "clientaddservergroup",
99
+ /** `clientchatclosed`: Tells a client this client has closed its private chat window with it. Voice protocol only. */
100
+ ClientChatClosed: "clientchatclosed",
101
+ /** `clientchatcomposing`: Tells a client this client is typing a private message to it. Voice protocol only. */
102
+ ClientChatComposing: "clientchatcomposing",
99
103
  /** `clientdbdelete`: Deletes a client's properties from the database. */
100
104
  ClientDBDelete: "clientdbdelete",
101
105
  /** `clientdbedit`: Changes a client's settings using given properties. */
@@ -238,6 +242,8 @@ const commandNameValues = {
238
242
  PermOverview: "permoverview",
239
243
  /** `permreset`: Restores the default permission settings on the selected virtual server and creates a new initial administrator token. */
240
244
  PermReset: "permreset",
245
+ /** `plugincmd`: Sends a plugin-defined message to the clients of a channel, the server or chosen clients, for plugins to read. Voice protocol only. */
246
+ PluginCmd: "plugincmd",
241
247
  /** `privilegekeyadd`: Creates a new privilege key, a token that grants a server or channel group. */
242
248
  PrivilegeKeyAdd: "privilegekeyadd",
243
249
  /** `privilegekeydelete`: Deletes an existing token matching the token key specified with token. */
package/src/core/enums.ts CHANGED
@@ -1,13 +1,19 @@
1
1
  /**
2
- * Enumerations the server reports and accepts as small integers.
2
+ * Enumerations the server reports and accepts as small integers or fixed
3
+ * strings.
3
4
  *
4
5
  * Each is an object of named values plus a type of the same name, the way
5
6
  * `Reason` is: the object names the values (`GroupType.Regular`), the type
6
7
  * restricts a parameter to them.
7
8
  *
8
- * Parameters take the type; parsed results carry a plain `number`, since a
9
- * server may send a value newer than this table — compare it against the
10
- * names (`group.type === GroupType.Query`).
9
+ * Parameters take the type; parsed results carry a plain `number` or `string`,
10
+ * since a server may send a value newer than this table — compare it against
11
+ * the names (`group.type === GroupType.Query`).
12
+ *
13
+ * The values are the server's own, plain numbers and strings, so they are what
14
+ * to store: one written to JSON or a database reads back unchanged. A value read
15
+ * back is a `number` or `string` to TypeScript; {@link isValueOf} narrows it to
16
+ * the table's type before it is passed as a parameter.
11
17
  *
12
18
  * Every table, and `ErrorCode` and `Reason` with them, may gain members in a
13
19
  * minor release: a `switch` over one needs a default case.
@@ -213,3 +219,104 @@ export const LogLevel: typeof logLevelValues = /* @__PURE__ */ Object.freeze(log
213
219
 
214
220
  /** A log level. */
215
221
  export type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];
222
+
223
+ /** The values of the table below, before freezing. */
224
+ const bannerModeValues = {
225
+ /** Show the image at its own size. */
226
+ NoAdjust: 0,
227
+ /** Scale the image to fill its space, ignoring its aspect ratio. */
228
+ AdjustIgnoreAspect: 1,
229
+ /** Scale the image to fit its space, keeping its aspect ratio. */
230
+ AdjustKeepAspect: 2,
231
+ } as const;
232
+ /**
233
+ * How a banner image is fitted to its space: a channel's (`channel_banner_mode`)
234
+ * and the server's host banner (`virtualserver_hostbanner_mode`).
235
+ */
236
+ export const BannerMode: typeof bannerModeValues = /* @__PURE__ */ Object.freeze(bannerModeValues);
237
+
238
+ /** A banner mode. */
239
+ export type BannerMode = (typeof BannerMode)[keyof typeof BannerMode];
240
+
241
+ /** The values of the table below, before freezing. */
242
+ const codecEncryptionModeValues = {
243
+ /** Each channel decides, by its `channel_codec_is_unencrypted`. */
244
+ PerChannel: 0,
245
+ /** Voice is never encrypted, whatever the channel says. */
246
+ ForcedOff: 1,
247
+ /** Voice is always encrypted, whatever the channel says. */
248
+ ForcedOn: 2,
249
+ } as const;
250
+ /** Whether the virtual server encrypts voice (`virtualserver_codec_encryption_mode`). */
251
+ export const CodecEncryptionMode: typeof codecEncryptionModeValues =
252
+ /* @__PURE__ */ Object.freeze(codecEncryptionModeValues);
253
+
254
+ /** A codec encryption mode. */
255
+ export type CodecEncryptionMode = (typeof CodecEncryptionMode)[keyof typeof CodecEncryptionMode];
256
+
257
+ /** The values of the table below, before freezing. */
258
+ const virtualServerStatusValues = {
259
+ /** Running, and voice clients can connect. */
260
+ Online: "online",
261
+ /** Stopped. */
262
+ Offline: "offline",
263
+ /** Starting up. */
264
+ BootingUp: "booting up",
265
+ /** Stopping. */
266
+ ShuttingDown: "shutting down",
267
+ /**
268
+ * Stopped, but selected by a ServerQuery client with `-virtual` so it can be
269
+ * configured. Voice clients cannot connect, and it returns to offline when
270
+ * the last query client deselects it.
271
+ */
272
+ OnlineVirtual: "online virtual",
273
+ } as const;
274
+ /**
275
+ * The state of a virtual server (`virtualserver_status`), as `serverlist` and
276
+ * `whoami` report it.
277
+ */
278
+ export const VirtualServerStatus: typeof virtualServerStatusValues =
279
+ /* @__PURE__ */ Object.freeze(virtualServerStatusValues);
280
+
281
+ /** A virtual server status. */
282
+ export type VirtualServerStatus = (typeof VirtualServerStatus)[keyof typeof VirtualServerStatus];
283
+
284
+ /** The values of the table below, before freezing. */
285
+ const bindingSubsystemValues = {
286
+ /** The voice port. */
287
+ Voice: "voice",
288
+ /** The ServerQuery port. */
289
+ Query: "query",
290
+ /** The file transfer port. */
291
+ FileTransfer: "filetransfer",
292
+ } as const;
293
+ /**
294
+ * What listens on an instance binding (`subsystem`), as `bindinglist` takes
295
+ * and reports it.
296
+ */
297
+ export const BindingSubsystem: typeof bindingSubsystemValues =
298
+ /* @__PURE__ */ Object.freeze(bindingSubsystemValues);
299
+
300
+ /** A binding subsystem. */
301
+ export type BindingSubsystem = (typeof BindingSubsystem)[keyof typeof BindingSubsystem];
302
+
303
+ /**
304
+ * Whether `value` is one of `table`'s values, narrowing it to the table's type.
305
+ * For a value from outside the program, such as one read back from storage or
306
+ * a configuration file, before it is passed where the table's type is taken:
307
+ *
308
+ * ```ts
309
+ * if (!isValueOf(BannerMode, row.bannerMode)) throw new Error(`bad banner mode ${row.bannerMode}`);
310
+ * await editChannel(client, cid, { bannerMode: row.bannerMode });
311
+ * ```
312
+ *
313
+ * It takes any of the SDK's tables, of any entry point, and compares with
314
+ * `===`: a number kept as text, `"2"`, is not the number `2`, so a value stored
315
+ * in another form is converted first.
316
+ */
317
+ export function isValueOf<T extends Readonly<Record<string, string | number>>>(
318
+ table: T,
319
+ value: unknown,
320
+ ): value is T[keyof T] {
321
+ return (Object.values(table) as unknown[]).includes(value);
322
+ }
package/src/core/index.ts CHANGED
@@ -68,8 +68,12 @@ export { Reason } from "./reason.js";
68
68
  // Small-integer enumerations, as named values and types.
69
69
  export {
70
70
  APIKeyScope,
71
+ BannerMode,
72
+ BindingSubsystem,
71
73
  ClientType,
72
74
  Codec,
75
+ CodecEncryptionMode,
76
+ isValueOf,
73
77
  GroupAutoUpdateType,
74
78
  GroupNameMode,
75
79
  GroupType,
@@ -78,6 +82,7 @@ export {
78
82
  PermissionTarget,
79
83
  TextMessageTarget,
80
84
  PrivilegeKeyType,
85
+ VirtualServerStatus,
81
86
  } from "./enums.js";
82
87
 
83
88
  // Permissions, by id or by name.
@@ -88,11 +93,16 @@ export { NotificationName } from "./notification-name.js";
88
93
  export { PropertyName } from "./property-name.js";
89
94
  export type { Permission } from "./permission.js";
90
95
 
91
- export { noopLogger, consoleLogger, ClientStatus, serverFamilyForVersion } from "./types.js";
96
+ export {
97
+ noopLogger,
98
+ consoleLogger,
99
+ ClientStatus,
100
+ ServerFamily,
101
+ serverFamilyForVersion,
102
+ } from "./types.js";
92
103
  export type {
93
104
  ClientVersion,
94
105
  Listener,
95
- ServerFamily,
96
106
  Unsubscribe,
97
107
  CommandMiddleware,
98
108
  FileDownloadInfo,
@@ -37,7 +37,7 @@ const propertyNameValues = {
37
37
  VirtualServerCreated: "virtualserver_created",
38
38
  /** `virtualserver_uptime`: Seconds since the virtual server started. */
39
39
  VirtualServerUptime: "virtualserver_uptime",
40
- /** `virtualserver_codec_encryption_mode`: The global codec encryption mode of the virtual server. Editable. */
40
+ /** `virtualserver_codec_encryption_mode`: The global codec encryption mode of the virtual server; see `CodecEncryptionMode`. Editable. */
41
41
  VirtualServerCodecEncryptionMode: "virtualserver_codec_encryption_mode",
42
42
  /** `virtualserver_hostmessage`: The host message of the server. Editable. */
43
43
  VirtualServerHostMessage: "virtualserver_hostmessage",
@@ -151,7 +151,7 @@ const propertyNameValues = {
151
151
  VirtualServerWebListEnabled: "virtualserver_weblist_enabled",
152
152
  /** `virtualserver_ask_for_privilegekey`: 1 if clients are asked for a privilege key on their first connection to an unclaimed server, 0 if not. */
153
153
  VirtualServerAskForPrivilegeKey: "virtualserver_ask_for_privilegekey",
154
- /** `virtualserver_hostbanner_mode`: The display mode for the virtual servers hostbanner. Editable. */
154
+ /** `virtualserver_hostbanner_mode`: The display mode for the virtual servers hostbanner; see `BannerMode`. Editable. */
155
155
  VirtualServerHostBannerMode: "virtualserver_hostbanner_mode",
156
156
  /** `virtualserver_channel_temp_delete_delay_default`: Default delay, in seconds, before an empty temporary channel is deleted. */
157
157
  VirtualServerChannelTempDeleteDelayDefault: "virtualserver_channel_temp_delete_delay_default",
@@ -168,7 +168,7 @@ const propertyNameValues = {
168
168
  VirtualServerCapabilityExtensions: "virtualserver_capability_extensions",
169
169
  /** `virtualserver_file_storage_class`: Storage backend of the server's files; empty for the local disk. TeamSpeak 3 only. */
170
170
  VirtualServerFileStorageClass: "virtualserver_file_storage_class",
171
- /** `virtualserver_status`: Status of the virtual server (online | virtual online | offline | booting up | shutting down). Editable. */
171
+ /** `virtualserver_status`: Status of the virtual server (online | online virtual | offline | booting up | shutting down); see `VirtualServerStatus`. Editable. */
172
172
  VirtualServerStatus: "virtualserver_status",
173
173
  /** `connection_filetransfer_bandwidth_sent`: Current file transfer upload speed, in bytes per second. Also in hostinfo and clientinfo. */
174
174
  ConnectionFileTransferBandwidthSent: "connection_filetransfer_bandwidth_sent",
package/src/core/types.ts CHANGED
@@ -141,12 +141,23 @@ export const ClientStatus: typeof clientStatusValues =
141
141
  */
142
142
  export type ClientStatus = (typeof ClientStatus)[keyof typeof ClientStatus];
143
143
 
144
+ /** The values of the table below, before freezing. */
145
+ const serverFamilyValues = {
146
+ /** TeamSpeak 3: major version 3. */
147
+ TS3: "ts3",
148
+ /** TeamSpeak 6: major version 6 or later. */
149
+ TS6: "ts6",
150
+ /** A version string that names neither generation, or has no number. */
151
+ Unknown: "unknown",
152
+ } as const;
153
+ /** The server generation a version string belongs to. */
154
+ export const ServerFamily: typeof serverFamilyValues =
155
+ /* @__PURE__ */ Object.freeze(serverFamilyValues);
144
156
  /**
145
- * The server generation a version string belongs to. May gain members in a
146
- * minor release, as server generations appear: a `switch` over it needs a
147
- * default case.
157
+ * One of {@link ServerFamily}. May gain members in a minor release, as server
158
+ * generations appear: a `switch` over it needs a default case.
148
159
  */
149
- export type ServerFamily = "ts3" | "ts6" | "unknown";
160
+ export type ServerFamily = (typeof ServerFamily)[keyof typeof ServerFamily];
150
161
 
151
162
  /**
152
163
  * Pick the server generation from a `virtualserver_version` string such as
@@ -156,8 +167,8 @@ export type ServerFamily = "ts3" | "ts6" | "unknown";
156
167
  */
157
168
  export function serverFamilyForVersion(version: string): ServerFamily {
158
169
  const major = Number.parseInt(version, 10);
159
- if (Number.isNaN(major)) return "unknown";
160
- if (major === 3) return "ts3";
161
- if (major >= 6) return "ts6";
162
- return "unknown";
170
+ if (Number.isNaN(major)) return ServerFamily.Unknown;
171
+ if (major === 3) return ServerFamily.TS3;
172
+ if (major >= 6) return ServerFamily.TS6;
173
+ return ServerFamily.Unknown;
163
174
  }
@@ -52,12 +52,8 @@ import {
52
52
  import type { ResolvedQueryOptions, ResolvedTransport } from "./options.js";
53
53
  import { defaultShouldRetry, noteConnectFailure } from "./reconnect.js";
54
54
 
55
- export type {
56
- QueryClientOptions,
57
- QueryEventsOption,
58
- QueryEventCategory,
59
- QueryTransportOptions,
60
- } from "./options.js";
55
+ export type { QueryClientOptions, QueryEventsOption, QueryTransportOptions } from "./options.js";
56
+ export { QueryEventCategory } from "./options.js";
61
57
 
62
58
  /**
63
59
  * The events `QueryClient.on()` takes, and what each delivers.
@@ -82,6 +78,72 @@ export type {
82
78
  */
83
79
  export interface QueryEventMap extends ServerEventMap, SessionEventMap {}
84
80
 
81
+ /** The values of the table below, before freezing. */
82
+ const queryEventNameValues = {
83
+ /** A text message to this client, its channel or the server. */
84
+ TextMessage: "textMessage",
85
+ /** A client coming into view, including every client already there on connecting. */
86
+ ClientEnter: "clientEnter",
87
+ /** A client going out of view. */
88
+ ClientLeave: "clientLeave",
89
+ /** A client changing channel. */
90
+ ClientMoved: "clientMoved",
91
+ /** A channel being created. */
92
+ ChannelCreated: "channelCreated",
93
+ /** A channel's properties being edited. */
94
+ ChannelEdited: "channelEdited",
95
+ /** A channel being moved or reordered. */
96
+ ChannelMoved: "channelMoved",
97
+ /** A channel being deleted. */
98
+ ChannelDeleted: "channelDeleted",
99
+ /** A channel's description changing; the text is not in it. */
100
+ ChannelDescriptionChanged: "channelDescriptionChanged",
101
+ /** A channel's password being set, changed or removed. */
102
+ ChannelPasswordChanged: "channelPasswordChanged",
103
+ /** The server's settings being edited. */
104
+ ServerEdited: "serverEdited",
105
+ /**
106
+ * Every notification the server sends, modelled or not, after any event it
107
+ * produces; one with a typed event arrives here as well, not only there.
108
+ */
109
+ Notification: "notification",
110
+ /** The handshake completing, on `connect()` and on every reconnection. */
111
+ Connected: "connected",
112
+ /** The connection ending, with its cause and whether a reconnection follows. */
113
+ Disconnected: "disconnected",
114
+ /** A kick from the server or from its channel; a kick from the server also ends the connection. */
115
+ Kicked: "kicked",
116
+ } as const;
117
+ /**
118
+ * The names of the events `QueryClient.on()` takes, as constants.
119
+ * `on(QueryEventName.TextMessage, ...)` and `on("textMessage", ...)` are the
120
+ * same call, and both give the listener the same payload type.
121
+ *
122
+ * @experimental Part of the `@honeybbq/teamspeak/query` entry, which may
123
+ * change in a minor release.
124
+ */
125
+ export const QueryEventName: typeof queryEventNameValues =
126
+ /* @__PURE__ */ Object.freeze(queryEventNameValues);
127
+ /**
128
+ * One of {@link QueryEventName}, and so a key of {@link QueryEventMap}. May
129
+ * gain members in a minor release: a `switch` over it needs a default case.
130
+ *
131
+ * @experimental Part of the `@honeybbq/teamspeak/query` entry, which may
132
+ * change in a minor release.
133
+ */
134
+ export type QueryEventName = (typeof QueryEventName)[keyof typeof QueryEventName];
135
+
136
+ // Each direction fails to compile when `QueryEventMap` and `QueryEventName`
137
+ // drift: an event without a name, and a name that is not an event.
138
+ const eventNamesCoverEventMap: [Exclude<keyof QueryEventMap, QueryEventName>] extends [never]
139
+ ? true
140
+ : never = true;
141
+ const eventMapCoversEventNames: [Exclude<QueryEventName, keyof QueryEventMap>] extends [never]
142
+ ? true
143
+ : never = true;
144
+ void eventNamesCoverEventMap;
145
+ void eventMapCoversEventNames;
146
+
85
147
  /** How long a command waits for its answer unless told otherwise. */
86
148
  const DEFAULT_COMMAND_TIMEOUT_MS = 10_000;
87
149
 
@@ -22,10 +22,9 @@
22
22
  * @packageDocumentation
23
23
  */
24
24
 
25
- export { QueryClient } from "./client.js";
25
+ export { QueryClient, QueryEventCategory, QueryEventName } from "./client.js";
26
26
  export type {
27
27
  QueryClientOptions,
28
- QueryEventCategory,
29
28
  QueryEventMap,
30
29
  QueryEventsOption,
31
30
  QueryTransportOptions,
@@ -70,6 +70,23 @@ export type QueryTransportOptions =
70
70
  readonly open: (signal?: AbortSignal) => Promise<QueryTransport>;
71
71
  };
72
72
 
73
+ /** The values of the table below, before freezing. */
74
+ const queryEventCategoryValues = {
75
+ /** Server-wide events, such as clients joining and leaving. */
76
+ Server: "server",
77
+ /** Events of the channels, such as one being created or edited. */
78
+ Channel: "channel",
79
+ /** Text messages to the server. */
80
+ TextServer: "textserver",
81
+ /** Text messages to a channel. */
82
+ TextChannel: "textchannel",
83
+ /** Private text messages to this client. */
84
+ TextPrivate: "textprivate",
85
+ /** Ban list changes. */
86
+ Bans: "bans",
87
+ /** A privilege key being used. */
88
+ TokenUsed: "tokenused",
89
+ } as const;
73
90
  /**
74
91
  * One category of notifications to register for: the `event` parameter of
75
92
  * `servernotifyregister`.
@@ -80,14 +97,10 @@ export type QueryTransportOptions =
80
97
  * then send `notifytokenused`, which carries a privilege key and has no typed
81
98
  * event, so it reaches `notification` only.
82
99
  */
83
- export type QueryEventCategory =
84
- | "server"
85
- | "channel"
86
- | "textserver"
87
- | "textchannel"
88
- | "textprivate"
89
- | "bans"
90
- | "tokenused";
100
+ export const QueryEventCategory: typeof queryEventCategoryValues =
101
+ /* @__PURE__ */ Object.freeze(queryEventCategoryValues);
102
+ /** One of {@link QueryEventCategory}. */
103
+ export type QueryEventCategory = (typeof QueryEventCategory)[keyof typeof QueryEventCategory];
91
104
 
92
105
  /**
93
106
  * Which notification categories to register for.
@@ -184,11 +197,11 @@ export interface QueryClientOptions {
184
197
 
185
198
  /** The five categories both raw TCP on TS3 and SSH on TS6 accept. */
186
199
  export const DEFAULT_EVENT_CATEGORIES: readonly QueryEventCategory[] = Object.freeze([
187
- "server",
188
- "channel",
189
- "textserver",
190
- "textchannel",
191
- "textprivate",
200
+ QueryEventCategory.Server,
201
+ QueryEventCategory.Channel,
202
+ QueryEventCategory.TextServer,
203
+ QueryEventCategory.TextChannel,
204
+ QueryEventCategory.TextPrivate,
192
205
  ]);
193
206
 
194
207
  const CATEGORIES: ReadonlySet<string> = new Set([