@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.
- package/LICENSE +21 -0
- package/README.md +726 -2
- package/dist/client/abort.d.ts +5 -0
- package/dist/client/abort.d.ts.map +1 -0
- package/dist/client/abort.js +23 -0
- package/dist/client/abort.js.map +1 -0
- package/dist/client/address.d.ts +17 -0
- package/dist/client/address.d.ts.map +1 -0
- package/dist/client/address.js +66 -0
- package/dist/client/address.js.map +1 -0
- package/dist/client/api/voice.d.ts +24 -0
- package/dist/client/api/voice.d.ts.map +1 -0
- package/dist/client/api/voice.js +33 -0
- package/dist/client/api/voice.js.map +1 -0
- package/dist/client/capabilities.d.ts +68 -0
- package/dist/client/capabilities.d.ts.map +1 -0
- package/dist/client/capabilities.js +59 -0
- package/dist/client/capabilities.js.map +1 -0
- package/dist/client/client.d.ts +196 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +1523 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/commands.d.ts +66 -0
- package/dist/client/commands.d.ts.map +1 -0
- package/dist/client/commands.js +162 -0
- package/dist/client/commands.js.map +1 -0
- package/dist/client/crypto/crypt-ops.d.ts +7 -0
- package/dist/client/crypto/crypt-ops.d.ts.map +1 -0
- package/dist/client/crypto/crypt-ops.js +2 -0
- package/dist/client/crypto/crypt-ops.js.map +1 -0
- package/dist/client/crypto/crypt.d.ts +37 -0
- package/dist/client/crypto/crypt.d.ts.map +1 -0
- package/dist/client/crypto/crypt.js +203 -0
- package/dist/client/crypto/crypt.js.map +1 -0
- package/dist/client/crypto/eax.d.ts +12 -0
- package/dist/client/crypto/eax.d.ts.map +1 -0
- package/dist/client/crypto/eax.js +118 -0
- package/dist/client/crypto/eax.js.map +1 -0
- package/dist/client/crypto/identity.d.ts +97 -0
- package/dist/client/crypto/identity.d.ts.map +1 -0
- package/dist/client/crypto/identity.js +412 -0
- package/dist/client/crypto/identity.js.map +1 -0
- package/dist/client/crypto/index.d.ts +7 -0
- package/dist/client/crypto/index.d.ts.map +1 -0
- package/dist/client/crypto/index.js +5 -0
- package/dist/client/crypto/index.js.map +1 -0
- package/dist/client/crypto/primitives.d.ts +43 -0
- package/dist/client/crypto/primitives.d.ts.map +1 -0
- package/dist/client/crypto/primitives.js +116 -0
- package/dist/client/crypto/primitives.js.map +1 -0
- package/dist/client/diagnostics.d.ts +45 -0
- package/dist/client/diagnostics.d.ts.map +1 -0
- package/dist/client/diagnostics.js +30 -0
- package/dist/client/diagnostics.js.map +1 -0
- package/dist/client/discovery/index.d.ts +2 -0
- package/dist/client/discovery/index.d.ts.map +1 -0
- package/dist/client/discovery/index.js +2 -0
- package/dist/client/discovery/index.js.map +1 -0
- package/dist/client/discovery/resolver.d.ts +26 -0
- package/dist/client/discovery/resolver.d.ts.map +1 -0
- package/dist/client/discovery/resolver.js +275 -0
- package/dist/client/discovery/resolver.js.map +1 -0
- package/dist/client/errors.d.ts +82 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +201 -0
- package/dist/client/errors.js.map +1 -0
- package/dist/client/events.d.ts +3 -0
- package/dist/client/events.d.ts.map +1 -0
- package/dist/client/events.js +8 -0
- package/dist/client/events.js.map +1 -0
- package/dist/client/handshake/crypt-handshake.d.ts +17 -0
- package/dist/client/handshake/crypt-handshake.d.ts.map +1 -0
- package/dist/client/handshake/crypt-handshake.js +128 -0
- package/dist/client/handshake/crypt-handshake.js.map +1 -0
- package/dist/client/handshake/crypt-init2.d.ts +7 -0
- package/dist/client/handshake/crypt-init2.d.ts.map +1 -0
- package/dist/client/handshake/crypt-init2.js +37 -0
- package/dist/client/handshake/crypt-init2.js.map +1 -0
- package/dist/client/handshake/index.d.ts +4 -0
- package/dist/client/handshake/index.d.ts.map +1 -0
- package/dist/client/handshake/index.js +4 -0
- package/dist/client/handshake/index.js.map +1 -0
- package/dist/client/handshake/license.d.ts +35 -0
- package/dist/client/handshake/license.d.ts.map +1 -0
- package/dist/client/handshake/license.js +169 -0
- package/dist/client/handshake/license.js.map +1 -0
- package/dist/client/handshake.d.ts +27 -0
- package/dist/client/handshake.d.ts.map +1 -0
- package/dist/client/handshake.js +126 -0
- package/dist/client/handshake.js.map +1 -0
- package/dist/client/helpers.d.ts +6 -0
- package/dist/client/helpers.d.ts.map +1 -0
- package/dist/client/helpers.js +13 -0
- package/dist/client/helpers.js.map +1 -0
- package/dist/client/hooks.d.ts +7 -0
- package/dist/client/hooks.d.ts.map +1 -0
- package/dist/client/hooks.js +28 -0
- package/dist/client/hooks.js.map +1 -0
- package/dist/client/index.d.ts +26 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +28 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/reconnect.d.ts +12 -0
- package/dist/client/reconnect.d.ts.map +1 -0
- package/dist/client/reconnect.js +44 -0
- package/dist/client/reconnect.js.map +1 -0
- package/dist/client/throttle.d.ts +20 -0
- package/dist/client/throttle.d.ts.map +1 -0
- package/dist/client/throttle.js +83 -0
- package/dist/client/throttle.js.map +1 -0
- package/dist/client/trace.d.ts +223 -0
- package/dist/client/trace.d.ts.map +1 -0
- package/dist/client/trace.js +13 -0
- package/dist/client/trace.js.map +1 -0
- package/dist/client/transfer.d.ts +111 -0
- package/dist/client/transfer.d.ts.map +1 -0
- package/dist/client/transfer.js +243 -0
- package/dist/client/transfer.js.map +1 -0
- package/dist/client/transport/generation-window.d.ts +30 -0
- package/dist/client/transport/generation-window.d.ts.map +1 -0
- package/dist/client/transport/generation-window.js +97 -0
- package/dist/client/transport/generation-window.js.map +1 -0
- package/dist/client/transport/handler.d.ts +61 -0
- package/dist/client/transport/handler.d.ts.map +1 -0
- package/dist/client/transport/handler.js +793 -0
- package/dist/client/transport/handler.js.map +1 -0
- package/dist/client/transport/index.d.ts +6 -0
- package/dist/client/transport/index.d.ts.map +1 -0
- package/dist/client/transport/index.js +5 -0
- package/dist/client/transport/index.js.map +1 -0
- package/dist/client/transport/packet.d.ts +36 -0
- package/dist/client/transport/packet.d.ts.map +1 -0
- package/dist/client/transport/packet.js +55 -0
- package/dist/client/transport/packet.js.map +1 -0
- package/dist/client/transport/quicklz.d.ts +24 -0
- package/dist/client/transport/quicklz.d.ts.map +1 -0
- package/dist/client/transport/quicklz.js +179 -0
- package/dist/client/transport/quicklz.js.map +1 -0
- package/dist/client/types.d.ts +226 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +39 -0
- package/dist/client/types.js.map +1 -0
- package/dist/core/api/channels.d.ts +182 -0
- package/dist/core/api/channels.d.ts.map +1 -0
- package/dist/core/api/channels.js +155 -0
- package/dist/core/api/channels.js.map +1 -0
- package/dist/core/api/clients.d.ts +304 -0
- package/dist/core/api/clients.d.ts.map +1 -0
- package/dist/core/api/clients.js +260 -0
- package/dist/core/api/clients.js.map +1 -0
- package/dist/core/api/command.d.ts +305 -0
- package/dist/core/api/command.d.ts.map +1 -0
- package/dist/core/api/command.js +363 -0
- package/dist/core/api/command.js.map +1 -0
- package/dist/core/api/files.d.ts +153 -0
- package/dist/core/api/files.d.ts.map +1 -0
- package/dist/core/api/files.js +181 -0
- package/dist/core/api/files.js.map +1 -0
- package/dist/core/api/groups.d.ts +248 -0
- package/dist/core/api/groups.d.ts.map +1 -0
- package/dist/core/api/groups.js +271 -0
- package/dist/core/api/groups.js.map +1 -0
- package/dist/core/api/moderation.d.ts +205 -0
- package/dist/core/api/moderation.d.ts.map +1 -0
- package/dist/core/api/moderation.js +209 -0
- package/dist/core/api/moderation.js.map +1 -0
- package/dist/core/api/parse.d.ts +16 -0
- package/dist/core/api/parse.d.ts.map +1 -0
- package/dist/core/api/parse.js +40 -0
- package/dist/core/api/parse.js.map +1 -0
- package/dist/core/api/server.d.ts +310 -0
- package/dist/core/api/server.d.ts.map +1 -0
- package/dist/core/api/server.js +290 -0
- package/dist/core/api/server.js.map +1 -0
- package/dist/core/command/command.d.ts +20 -0
- package/dist/core/command/command.d.ts.map +1 -0
- package/dist/core/command/command.js +112 -0
- package/dist/core/command/command.js.map +1 -0
- package/dist/core/command/ids.d.ts +125 -0
- package/dist/core/command/ids.d.ts.map +1 -0
- package/dist/core/command/ids.js +85 -0
- package/dist/core/command/ids.js.map +1 -0
- package/dist/core/command/parser.d.ts +17 -0
- package/dist/core/command/parser.d.ts.map +1 -0
- package/dist/core/command/parser.js +65 -0
- package/dist/core/command/parser.js.map +1 -0
- package/dist/core/command/request.d.ts +61 -0
- package/dist/core/command/request.d.ts.map +1 -0
- package/dist/core/command/request.js +64 -0
- package/dist/core/command/request.js.map +1 -0
- package/dist/core/command/responses.d.ts +59 -0
- package/dist/core/command/responses.d.ts.map +1 -0
- package/dist/core/command/responses.js +74 -0
- package/dist/core/command/responses.js.map +1 -0
- package/dist/core/command-name.d.ts +333 -0
- package/dist/core/command-name.d.ts.map +1 -0
- package/dist/core/command-name.js +331 -0
- package/dist/core/command-name.js.map +1 -0
- package/dist/core/enums.d.ts +146 -0
- package/dist/core/enums.d.ts.map +1 -0
- package/dist/core/enums.js +132 -0
- package/dist/core/enums.js.map +1 -0
- package/dist/core/errorcode.d.ts +413 -0
- package/dist/core/errorcode.d.ts.map +1 -0
- package/dist/core/errorcode.js +410 -0
- package/dist/core/errorcode.js.map +1 -0
- package/dist/core/errors.d.ts +111 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +233 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/events.d.ts +207 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +6 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/helpers.d.ts +42 -0
- package/dist/core/helpers.d.ts.map +1 -0
- package/dist/core/helpers.js +156 -0
- package/dist/core/helpers.js.map +1 -0
- package/dist/core/index.d.ts +35 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +34 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/internal.d.ts +23 -0
- package/dist/core/internal.d.ts.map +1 -0
- package/dist/core/internal.js +20 -0
- package/dist/core/internal.js.map +1 -0
- package/dist/core/middleware.d.ts +14 -0
- package/dist/core/middleware.d.ts.map +1 -0
- package/dist/core/middleware.js +18 -0
- package/dist/core/middleware.js.map +1 -0
- package/dist/core/notification-name.d.ts +154 -0
- package/dist/core/notification-name.d.ts.map +1 -0
- package/dist/core/notification-name.js +152 -0
- package/dist/core/notification-name.js.map +1 -0
- package/dist/core/notifications.d.ts +43 -0
- package/dist/core/notifications.d.ts.map +1 -0
- package/dist/core/notifications.js +116 -0
- package/dist/core/notifications.js.map +1 -0
- package/dist/core/permission-name.d.ts +533 -0
- package/dist/core/permission-name.d.ts.map +1 -0
- package/dist/core/permission-name.js +531 -0
- package/dist/core/permission-name.js.map +1 -0
- package/dist/core/permission.d.ts +31 -0
- package/dist/core/permission.d.ts.map +1 -0
- package/dist/core/permission.js +20 -0
- package/dist/core/permission.js.map +1 -0
- package/dist/core/property-name.d.ts +403 -0
- package/dist/core/property-name.d.ts.map +1 -0
- package/dist/core/property-name.js +405 -0
- package/dist/core/property-name.js.map +1 -0
- package/dist/core/reason.d.ts +39 -0
- package/dist/core/reason.d.ts.map +1 -0
- package/dist/core/reason.js +36 -0
- package/dist/core/reason.js.map +1 -0
- package/dist/core/reconnect.d.ts +59 -0
- package/dist/core/reconnect.d.ts.map +1 -0
- package/dist/core/reconnect.js +55 -0
- package/dist/core/reconnect.js.map +1 -0
- package/dist/core/types.d.ts +110 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +27 -0
- package/dist/core/types.js.map +1 -0
- package/dist/query/client.d.ts +194 -0
- package/dist/query/client.d.ts.map +1 -0
- package/dist/query/client.js +967 -0
- package/dist/query/client.js.map +1 -0
- package/dist/query/errors.d.ts +61 -0
- package/dist/query/errors.d.ts.map +1 -0
- package/dist/query/errors.js +100 -0
- package/dist/query/errors.js.map +1 -0
- package/dist/query/index.d.ts +36 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +34 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/knownhosts.d.ts +61 -0
- package/dist/query/knownhosts.d.ts.map +1 -0
- package/dist/query/knownhosts.js +223 -0
- package/dist/query/knownhosts.js.map +1 -0
- package/dist/query/lines.d.ts +14 -0
- package/dist/query/lines.d.ts.map +1 -0
- package/dist/query/lines.js +29 -0
- package/dist/query/lines.js.map +1 -0
- package/dist/query/options.d.ts +187 -0
- package/dist/query/options.d.ts.map +1 -0
- package/dist/query/options.js +213 -0
- package/dist/query/options.js.map +1 -0
- package/dist/query/reconnect.d.ts +29 -0
- package/dist/query/reconnect.d.ts.map +1 -0
- package/dist/query/reconnect.js +87 -0
- package/dist/query/reconnect.js.map +1 -0
- package/dist/query/ssh.d.ts +345 -0
- package/dist/query/ssh.d.ts.map +1 -0
- package/dist/query/ssh.js +241 -0
- package/dist/query/ssh.js.map +1 -0
- package/dist/query/stream.d.ts +38 -0
- package/dist/query/stream.d.ts.map +1 -0
- package/dist/query/stream.js +70 -0
- package/dist/query/stream.js.map +1 -0
- package/dist/query/tcp.d.ts +38 -0
- package/dist/query/tcp.d.ts.map +1 -0
- package/dist/query/tcp.js +53 -0
- package/dist/query/tcp.js.map +1 -0
- package/dist/query/transport.d.ts +36 -0
- package/dist/query/transport.d.ts.map +1 -0
- package/dist/query/transport.js +2 -0
- package/dist/query/transport.js.map +1 -0
- package/dist/query/web.d.ts +54 -0
- package/dist/query/web.d.ts.map +1 -0
- package/dist/query/web.js +146 -0
- package/dist/query/web.js.map +1 -0
- package/dist/versions/index.d.ts +3094 -0
- package/dist/versions/index.d.ts.map +1 -0
- package/dist/versions/index.js +9237 -0
- package/dist/versions/index.js.map +1 -0
- package/package.json +118 -4
- package/src/client/abort.ts +24 -0
- package/src/client/address.ts +74 -0
- package/src/client/api/voice.ts +61 -0
- package/src/client/capabilities.ts +106 -0
- package/src/client/client.ts +1809 -0
- package/src/client/commands.ts +193 -0
- package/src/client/crypto/crypt-ops.ts +6 -0
- package/src/client/crypto/crypt.ts +275 -0
- package/src/client/crypto/eax.ts +152 -0
- package/src/client/crypto/identity.ts +484 -0
- package/src/client/crypto/index.ts +21 -0
- package/src/client/crypto/primitives.ts +141 -0
- package/src/client/diagnostics.ts +58 -0
- package/src/client/discovery/index.ts +1 -0
- package/src/client/discovery/resolver.ts +325 -0
- package/src/client/errors.ts +217 -0
- package/src/client/events.ts +12 -0
- package/src/client/handshake/crypt-handshake.ts +157 -0
- package/src/client/handshake/crypt-init2.ts +48 -0
- package/src/client/handshake/index.ts +3 -0
- package/src/client/handshake/license.ts +208 -0
- package/src/client/handshake.ts +150 -0
- package/src/client/helpers.ts +10 -0
- package/src/client/hooks.ts +30 -0
- package/src/client/index.ts +93 -0
- package/src/client/reconnect.ts +43 -0
- package/src/client/throttle.ts +92 -0
- package/src/client/trace.ts +237 -0
- package/src/client/transfer.ts +436 -0
- package/src/client/transport/generation-window.ts +108 -0
- package/src/client/transport/handler.ts +926 -0
- package/src/client/transport/index.ts +14 -0
- package/src/client/transport/packet.ts +69 -0
- package/src/client/transport/quicklz.ts +209 -0
- package/src/client/types.ts +268 -0
- package/src/core/api/channels.ts +396 -0
- package/src/core/api/clients.ts +654 -0
- package/src/core/api/command.ts +563 -0
- package/src/core/api/files.ts +405 -0
- package/src/core/api/groups.ts +622 -0
- package/src/core/api/moderation.ts +525 -0
- package/src/core/api/parse.ts +52 -0
- package/src/core/api/server.ts +709 -0
- package/src/core/command/command.ts +125 -0
- package/src/core/command/ids.ts +149 -0
- package/src/core/command/parser.ts +68 -0
- package/src/core/command/request.ts +119 -0
- package/src/core/command/responses.ts +114 -0
- package/src/core/command-name.ts +334 -0
- package/src/core/enums.ts +167 -0
- package/src/core/errorcode.ts +412 -0
- package/src/core/errors.ts +258 -0
- package/src/core/events.ts +219 -0
- package/src/core/helpers.ts +161 -0
- package/src/core/index.ts +126 -0
- package/src/core/internal.ts +23 -0
- package/src/core/middleware.ts +24 -0
- package/src/core/notification-name.ts +155 -0
- package/src/core/notifications.ts +157 -0
- package/src/core/permission-name.ts +538 -0
- package/src/core/permission.ts +34 -0
- package/src/core/property-name.ts +411 -0
- package/src/core/reason.ts +38 -0
- package/src/core/reconnect.ts +98 -0
- package/src/core/types.ts +138 -0
- package/src/query/client.ts +1132 -0
- package/src/query/errors.ts +108 -0
- package/src/query/index.ts +65 -0
- package/src/query/knownhosts.ts +257 -0
- package/src/query/lines.ts +28 -0
- package/src/query/options.ts +388 -0
- package/src/query/reconnect.ts +84 -0
- package/src/query/ssh.ts +614 -0
- package/src/query/stream.ts +91 -0
- package/src/query/tcp.ts +85 -0
- package/src/query/transport.ts +35 -0
- package/src/query/web.ts +195 -0
- package/src/versions/index.ts +10774 -0
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client commands.
|
|
3
|
+
*
|
|
4
|
+
* A "client" is someone connected right now, identified by `clid`; a "client
|
|
5
|
+
* database entry" is the persistent record, identified by `cldbid`. Both exist
|
|
6
|
+
* and both appear below, so the two are named apart in the types rather than
|
|
7
|
+
* relying on the reader to tell `ClientID` from `ClientDBID`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
uint,
|
|
12
|
+
U16,
|
|
13
|
+
firstRow,
|
|
14
|
+
exec,
|
|
15
|
+
query,
|
|
16
|
+
list,
|
|
17
|
+
pages,
|
|
18
|
+
encodeFields,
|
|
19
|
+
nonEmpty,
|
|
20
|
+
parsePermission,
|
|
21
|
+
permissionParam,
|
|
22
|
+
str,
|
|
23
|
+
big,
|
|
24
|
+
num,
|
|
25
|
+
date,
|
|
26
|
+
} from "./command.js";
|
|
27
|
+
import type { PagingOptions, PermissionEntry, WireNames } from "./command.js";
|
|
28
|
+
import type { CommandExecutor, CommandOptions } from "../command/request.js";
|
|
29
|
+
import type {
|
|
30
|
+
ChannelGroupID,
|
|
31
|
+
ChannelID,
|
|
32
|
+
ClientDBID,
|
|
33
|
+
ClientID,
|
|
34
|
+
ServerGroupID,
|
|
35
|
+
UID,
|
|
36
|
+
} from "../command/ids.js";
|
|
37
|
+
import { asClientDBID, asClientID, asUID } from "../command/ids.js";
|
|
38
|
+
import type { Permission } from "../permission.js";
|
|
39
|
+
import { Reason } from "../reason.js";
|
|
40
|
+
import { ErrorCode } from "../errorcode.js";
|
|
41
|
+
import { parseClient } from "./parse.js";
|
|
42
|
+
|
|
43
|
+
/** A connected client, as `clientlist` reports one. */
|
|
44
|
+
export interface ClientEntry {
|
|
45
|
+
/** The client's id for this connection. It changes every time the client connects. */
|
|
46
|
+
readonly id: ClientID;
|
|
47
|
+
/** The client's nickname. */
|
|
48
|
+
readonly nickname: string;
|
|
49
|
+
/** The client's unique identifier, stable across connections. Empty if `uid` was turned off. */
|
|
50
|
+
readonly uid: UID;
|
|
51
|
+
/** The channel the client is in. */
|
|
52
|
+
readonly channelID: ChannelID;
|
|
53
|
+
/** What kind of connection this is, one of {@link ClientType}. */
|
|
54
|
+
readonly type: number;
|
|
55
|
+
/**
|
|
56
|
+
* The server groups the client holds, with `groups`. Ids rather than names:
|
|
57
|
+
* the server sends ids, and resolving them costs a separate call.
|
|
58
|
+
*/
|
|
59
|
+
readonly serverGroups: readonly ServerGroupID[];
|
|
60
|
+
/** Whether the client is away, with `away`. */
|
|
61
|
+
readonly isAway: boolean;
|
|
62
|
+
/** Whether the client is recording, with `voice`. */
|
|
63
|
+
readonly isRecording: boolean;
|
|
64
|
+
/** Whether the client may talk despite the channel's needed talk power, with `voice`. */
|
|
65
|
+
readonly isTalker: boolean;
|
|
66
|
+
/** The channel group the client holds in its channel, with `groups`. */
|
|
67
|
+
readonly channelGroupID: ChannelGroupID;
|
|
68
|
+
/** When the client first connected to this server, with `times`. */
|
|
69
|
+
readonly createdAt: Date | undefined;
|
|
70
|
+
/** When the client last connected before this session, with `times`. */
|
|
71
|
+
readonly lastConnectedAt: Date | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* How long since the client last did anything, in milliseconds
|
|
74
|
+
* (`client_idle_time`), with `times`; undefined without it.
|
|
75
|
+
*/
|
|
76
|
+
readonly idleTimeMs: number | undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Which optional fields `clientlist` should include. Each asks the server for
|
|
81
|
+
* more per client; turn them off for a narrower response when watching a busy
|
|
82
|
+
* server.
|
|
83
|
+
*/
|
|
84
|
+
export interface ClientListOptions extends CommandOptions {
|
|
85
|
+
/** The unique identifier (`-uid`). On unless set to false: almost every caller needs it. */
|
|
86
|
+
readonly uid?: boolean | undefined;
|
|
87
|
+
/** Away state and message (`-away`). */
|
|
88
|
+
readonly away?: boolean | undefined;
|
|
89
|
+
/** Voice state: muted, talking, recording, talker (`-voice`). */
|
|
90
|
+
readonly voice?: boolean | undefined;
|
|
91
|
+
/** Server and channel groups (`-groups`). */
|
|
92
|
+
readonly groups?: boolean | undefined;
|
|
93
|
+
/** Creation, last connection and idle times (`-times`). */
|
|
94
|
+
readonly times?: boolean | undefined;
|
|
95
|
+
/** Client version and platform (`-info`). */
|
|
96
|
+
readonly info?: boolean | undefined;
|
|
97
|
+
/** The client's country (`-country`). */
|
|
98
|
+
readonly country?: boolean | undefined;
|
|
99
|
+
/** The client's address (`-ip`). */
|
|
100
|
+
readonly ip?: boolean | undefined;
|
|
101
|
+
/** The client's badges (`-badges`). */
|
|
102
|
+
readonly badges?: boolean | undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const listFlags: WireNames<ClientListOptions> = {
|
|
106
|
+
uid: "-uid",
|
|
107
|
+
away: "-away",
|
|
108
|
+
voice: "-voice",
|
|
109
|
+
groups: "-groups",
|
|
110
|
+
times: "-times",
|
|
111
|
+
info: "-info",
|
|
112
|
+
country: "-country",
|
|
113
|
+
ip: "-ip",
|
|
114
|
+
badges: "-badges",
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/** Every client currently connected. */
|
|
118
|
+
export async function listClients(
|
|
119
|
+
client: CommandExecutor,
|
|
120
|
+
options: ClientListOptions = {},
|
|
121
|
+
): Promise<ClientEntry[]> {
|
|
122
|
+
const flags = encodeFields({ ...options, uid: options.uid !== false }, listFlags);
|
|
123
|
+
return (await list(client, "clientlist", flags, options)).map(parseClient);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* One connected client's full detail, as the server sent it.
|
|
128
|
+
*
|
|
129
|
+
* Raw rather than parsed: `clientinfo` carries some eighty fields, which ones
|
|
130
|
+
* appear depends on the server version and on the caller's permissions, and a
|
|
131
|
+
* typed subset would drop the rest. Durations here are in the server's units —
|
|
132
|
+
* `client_idle_time` and `connection_connected_time` in milliseconds. The keys
|
|
133
|
+
* are named in `PropertyName`.
|
|
134
|
+
*/
|
|
135
|
+
export async function getClientProperties(
|
|
136
|
+
client: CommandExecutor,
|
|
137
|
+
clid: ClientID,
|
|
138
|
+
options?: CommandOptions,
|
|
139
|
+
): Promise<Readonly<Record<string, string>>> {
|
|
140
|
+
const rows = await query(client, "clientinfo", [["clid", clid]], options);
|
|
141
|
+
return firstRow(rows, "clientinfo");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** How {@link moveClient} enters the channel. */
|
|
145
|
+
export interface ClientMoveOptions extends CommandOptions {
|
|
146
|
+
/**
|
|
147
|
+
* The channel's password, in cleartext; the voice client hashes it on the
|
|
148
|
+
* wire. Unset sends none (`cpw`).
|
|
149
|
+
*/
|
|
150
|
+
readonly password?: string | undefined;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Move a client to another channel. */
|
|
154
|
+
export async function moveClient(
|
|
155
|
+
client: CommandExecutor,
|
|
156
|
+
clid: ClientID,
|
|
157
|
+
channelID: ChannelID,
|
|
158
|
+
options: ClientMoveOptions = {},
|
|
159
|
+
): Promise<void> {
|
|
160
|
+
await exec(
|
|
161
|
+
client,
|
|
162
|
+
"clientmove",
|
|
163
|
+
[
|
|
164
|
+
["clid", clid],
|
|
165
|
+
["cid", channelID],
|
|
166
|
+
["cpw", options.password],
|
|
167
|
+
],
|
|
168
|
+
options,
|
|
169
|
+
["cpw"],
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** The reasons a client can be kicked for. */
|
|
174
|
+
export type KickReason = typeof Reason.KickChannel | typeof Reason.KickServer;
|
|
175
|
+
|
|
176
|
+
/** What {@link kickClient} tells the kicked client. */
|
|
177
|
+
export interface ClientKickOptions extends CommandOptions {
|
|
178
|
+
/** Shown to the client; unset or `""` sends none (`reasonmsg`). */
|
|
179
|
+
readonly reasonMessage?: string | undefined;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Kick a client from its channel (`Reason.KickChannel`), which moves it to the
|
|
184
|
+
* default channel, or from the server (`Reason.KickServer`), which disconnects
|
|
185
|
+
* it. Any other reason is refused before anything is sent.
|
|
186
|
+
*/
|
|
187
|
+
export async function kickClient(
|
|
188
|
+
client: CommandExecutor,
|
|
189
|
+
clid: ClientID,
|
|
190
|
+
reason: KickReason,
|
|
191
|
+
options: ClientKickOptions = {},
|
|
192
|
+
): Promise<void> {
|
|
193
|
+
if (reason !== Reason.KickChannel && reason !== Reason.KickServer) {
|
|
194
|
+
throw new RangeError(
|
|
195
|
+
`a kick's reason is Reason.KickChannel or Reason.KickServer, not ${String(reason)}`,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
await exec(
|
|
199
|
+
client,
|
|
200
|
+
"clientkick",
|
|
201
|
+
[
|
|
202
|
+
["clid", clid],
|
|
203
|
+
["reasonid", reason],
|
|
204
|
+
["reasonmsg", nonEmpty(options.reasonMessage ?? "")],
|
|
205
|
+
],
|
|
206
|
+
options,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Send a poke to a client. */
|
|
211
|
+
export async function pokeClient(
|
|
212
|
+
client: CommandExecutor,
|
|
213
|
+
clid: ClientID,
|
|
214
|
+
message: string,
|
|
215
|
+
options?: CommandOptions,
|
|
216
|
+
): Promise<void> {
|
|
217
|
+
await exec(
|
|
218
|
+
client,
|
|
219
|
+
"clientpoke",
|
|
220
|
+
[
|
|
221
|
+
["clid", clid],
|
|
222
|
+
["msg", message],
|
|
223
|
+
],
|
|
224
|
+
options,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Our own client state, as `clientupdate` takes it.
|
|
230
|
+
*
|
|
231
|
+
* Only the fields you set are sent. An unset (undefined) field is omitted and
|
|
232
|
+
* leaves the setting alone; any other value is sent, so `""` sends an empty
|
|
233
|
+
* value — `awayMessage: ""` clears the away message.
|
|
234
|
+
*/
|
|
235
|
+
export interface ClientUpdateOptions {
|
|
236
|
+
/** Our nickname (`client_nickname`). */
|
|
237
|
+
readonly nickname?: string | undefined;
|
|
238
|
+
/** How the nickname is pronounced, for text-to-speech (`client_nickname_phonetic`). */
|
|
239
|
+
readonly nicknamePhonetic?: string | undefined;
|
|
240
|
+
/** Whether our microphone is muted (`client_input_muted`). */
|
|
241
|
+
readonly isInputMuted?: boolean | undefined;
|
|
242
|
+
/** Whether our speakers are muted (`client_output_muted`). */
|
|
243
|
+
readonly isOutputMuted?: boolean | undefined;
|
|
244
|
+
/** Whether we have a working microphone (`client_input_hardware`). */
|
|
245
|
+
readonly hasInputHardware?: boolean | undefined;
|
|
246
|
+
/** Whether we have working speakers (`client_output_hardware`). */
|
|
247
|
+
readonly hasOutputHardware?: boolean | undefined;
|
|
248
|
+
/** Whether we are away (`client_away`). */
|
|
249
|
+
readonly isAway?: boolean | undefined;
|
|
250
|
+
/** The away message (`client_away_message`). */
|
|
251
|
+
readonly awayMessage?: string | undefined;
|
|
252
|
+
/** Whether we speak as channel commander (`client_is_channel_commander`). */
|
|
253
|
+
readonly isChannelCommander?: boolean | undefined;
|
|
254
|
+
/** Whether we are recording (`client_is_recording`). */
|
|
255
|
+
readonly isRecording?: boolean | undefined;
|
|
256
|
+
/** Whether we are requesting to talk (`client_talk_request`). */
|
|
257
|
+
readonly isRequestingTalk?: boolean | undefined;
|
|
258
|
+
/** The message sent with a talk request (`client_talk_request_msg`). */
|
|
259
|
+
readonly talkRequestMessage?: string | undefined;
|
|
260
|
+
/** Our avatar's MD5, as uploaded to the file area; "" removes it (`client_flag_avatar`). */
|
|
261
|
+
readonly avatar?: string | undefined;
|
|
262
|
+
/** Our badges, in the client's own format (`client_badges`). */
|
|
263
|
+
readonly badges?: string | undefined;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const updateNames: WireNames<ClientUpdateOptions> = {
|
|
267
|
+
nickname: "client_nickname",
|
|
268
|
+
nicknamePhonetic: "client_nickname_phonetic",
|
|
269
|
+
isInputMuted: "client_input_muted",
|
|
270
|
+
isOutputMuted: "client_output_muted",
|
|
271
|
+
hasInputHardware: "client_input_hardware",
|
|
272
|
+
hasOutputHardware: "client_output_hardware",
|
|
273
|
+
isAway: "client_away",
|
|
274
|
+
awayMessage: "client_away_message",
|
|
275
|
+
isChannelCommander: "client_is_channel_commander",
|
|
276
|
+
isRecording: "client_is_recording",
|
|
277
|
+
isRequestingTalk: "client_talk_request",
|
|
278
|
+
talkRequestMessage: "client_talk_request_msg",
|
|
279
|
+
avatar: "client_flag_avatar",
|
|
280
|
+
badges: "client_badges",
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Change our own client state (nickname, mute, away, …). Only the fields you
|
|
285
|
+
* set are sent.
|
|
286
|
+
*
|
|
287
|
+
* `clientupdate` addresses the calling client implicitly — there is no clid
|
|
288
|
+
* parameter on the wire, which is why this takes no id.
|
|
289
|
+
*
|
|
290
|
+
* `update` is what to send; the command's `signal` and `timeoutMs` go in
|
|
291
|
+
* `options`, a separate last argument — set among the fields, they are not
|
|
292
|
+
* read.
|
|
293
|
+
*/
|
|
294
|
+
export async function updateClient(
|
|
295
|
+
client: CommandExecutor,
|
|
296
|
+
update: ClientUpdateOptions,
|
|
297
|
+
options?: CommandOptions,
|
|
298
|
+
): Promise<void> {
|
|
299
|
+
await exec(client, "clientupdate", encodeFields(update, updateNames), options);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Another client's editable attributes, as `clientedit` takes them. Unset
|
|
304
|
+
* fields are omitted; `""` is sent empty.
|
|
305
|
+
*/
|
|
306
|
+
export interface ClientEditOptions {
|
|
307
|
+
/** The client's description (`client_description`). */
|
|
308
|
+
readonly description?: string | undefined;
|
|
309
|
+
/** Whether the client may talk despite a channel's needed talk power (`client_is_talker`). */
|
|
310
|
+
readonly isTalker?: boolean | undefined;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const editNames: WireNames<ClientEditOptions> = {
|
|
314
|
+
description: "client_description",
|
|
315
|
+
isTalker: "client_is_talker",
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Change another client's editable attributes. Only the fields you set are
|
|
320
|
+
* sent.
|
|
321
|
+
*
|
|
322
|
+
* `edit` is what to send; the command's `signal` and `timeoutMs` go in
|
|
323
|
+
* `options`, a separate last argument — set among the fields, they are not
|
|
324
|
+
* read.
|
|
325
|
+
*/
|
|
326
|
+
export async function editClient(
|
|
327
|
+
client: CommandExecutor,
|
|
328
|
+
clid: ClientID,
|
|
329
|
+
edit: ClientEditOptions,
|
|
330
|
+
options?: CommandOptions,
|
|
331
|
+
): Promise<void> {
|
|
332
|
+
await exec(client, "clientedit", [["clid", clid], ...encodeFields(edit, editNames)], options);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** A connected client whose nickname matched a search. */
|
|
336
|
+
export interface ClientMatch {
|
|
337
|
+
/** The client's id. */
|
|
338
|
+
readonly id: ClientID;
|
|
339
|
+
/** The client's nickname. */
|
|
340
|
+
readonly nickname: string;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Clients whose nickname contains `pattern`; none is an empty list. The server
|
|
345
|
+
* reports finding no one as error 512 (invalid clientID), which this answers
|
|
346
|
+
* as `[]`.
|
|
347
|
+
*/
|
|
348
|
+
export async function findClients(
|
|
349
|
+
client: CommandExecutor,
|
|
350
|
+
pattern: string,
|
|
351
|
+
options?: CommandOptions,
|
|
352
|
+
): Promise<ClientMatch[]> {
|
|
353
|
+
const rows = await list(client, "clientfind", [["pattern", pattern]], options, {
|
|
354
|
+
noMatch: ErrorCode.ClientInvalidID,
|
|
355
|
+
});
|
|
356
|
+
return rows.map((row) => ({
|
|
357
|
+
id: asClientID(uint(row, "clid", U16)),
|
|
358
|
+
nickname: str(row, "client_nickname"),
|
|
359
|
+
}));
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Every client currently using a given unique identifier, with the nickname
|
|
364
|
+
* each uses; none is an empty list.
|
|
365
|
+
*/
|
|
366
|
+
export async function getClientIDs(
|
|
367
|
+
client: CommandExecutor,
|
|
368
|
+
uid: UID,
|
|
369
|
+
options?: CommandOptions,
|
|
370
|
+
): Promise<ClientMatch[]> {
|
|
371
|
+
const rows = await list(client, "clientgetids", [["cluid", uid]], options);
|
|
372
|
+
return rows.map((row) => ({
|
|
373
|
+
id: asClientID(uint(row, "clid", U16)),
|
|
374
|
+
nickname: str(row, "name"),
|
|
375
|
+
}));
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/** The uid of a connected client. */
|
|
379
|
+
export async function getClientUIDByID(
|
|
380
|
+
client: CommandExecutor,
|
|
381
|
+
clid: ClientID,
|
|
382
|
+
options?: CommandOptions,
|
|
383
|
+
): Promise<UID> {
|
|
384
|
+
const rows = await query(client, "clientgetuidfromclid", [["clid", clid]], options);
|
|
385
|
+
return asUID(str(firstRow(rows, "clientgetuidfromclid", "cluid"), "cluid"));
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** The persistent database id behind a uid. */
|
|
389
|
+
export async function getClientDBIDByUID(
|
|
390
|
+
client: CommandExecutor,
|
|
391
|
+
uid: UID,
|
|
392
|
+
options?: CommandOptions,
|
|
393
|
+
): Promise<ClientDBID> {
|
|
394
|
+
const rows = await query(client, "clientgetdbidfromuid", [["cluid", uid]], options);
|
|
395
|
+
return asClientDBID(big(firstRow(rows, "clientgetdbidfromuid", "cldbid"), "cldbid"));
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/** The database record a uid or database id names. */
|
|
399
|
+
export interface ClientDatabaseName {
|
|
400
|
+
/** The client's database id. */
|
|
401
|
+
readonly databaseID: ClientDBID;
|
|
402
|
+
/** The nickname the client last used. */
|
|
403
|
+
readonly name: string;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function parseDatabaseName(row: Record<string, string>): ClientDatabaseName {
|
|
407
|
+
return { databaseID: asClientDBID(big(row, "cldbid")), name: str(row, "name") };
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/** The database id and nickname recorded for a database id. */
|
|
411
|
+
export async function getClientNameByDBID(
|
|
412
|
+
client: CommandExecutor,
|
|
413
|
+
cldbid: ClientDBID,
|
|
414
|
+
options?: CommandOptions,
|
|
415
|
+
): Promise<ClientDatabaseName> {
|
|
416
|
+
const rows = await query(client, "clientgetnamefromdbid", [["cldbid", cldbid]], options);
|
|
417
|
+
return parseDatabaseName(firstRow(rows, "clientgetnamefromdbid", "cldbid"));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/** The database id and nickname recorded for a uid. */
|
|
421
|
+
export async function getClientNameByUID(
|
|
422
|
+
client: CommandExecutor,
|
|
423
|
+
uid: UID,
|
|
424
|
+
options?: CommandOptions,
|
|
425
|
+
): Promise<ClientDatabaseName> {
|
|
426
|
+
const rows = await query(client, "clientgetnamefromuid", [["cluid", uid]], options);
|
|
427
|
+
return parseDatabaseName(firstRow(rows, "clientgetnamefromuid", "cldbid"));
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/** Give a client a channel group in one channel. */
|
|
431
|
+
export async function setClientChannelGroup(
|
|
432
|
+
client: CommandExecutor,
|
|
433
|
+
cgid: ChannelGroupID,
|
|
434
|
+
cid: ChannelID,
|
|
435
|
+
cldbid: ClientDBID,
|
|
436
|
+
options?: CommandOptions,
|
|
437
|
+
): Promise<void> {
|
|
438
|
+
await exec(
|
|
439
|
+
client,
|
|
440
|
+
"setclientchannelgroup",
|
|
441
|
+
[
|
|
442
|
+
["cgid", cgid],
|
|
443
|
+
["cid", cid],
|
|
444
|
+
["cldbid", cldbid],
|
|
445
|
+
],
|
|
446
|
+
options,
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// ---- Client database --------------------------------------------------------
|
|
451
|
+
|
|
452
|
+
/** A persistent client record, as `clientdblist` and `clientdbinfo` report it. */
|
|
453
|
+
export interface ClientDatabaseEntry {
|
|
454
|
+
/** The record's id. */
|
|
455
|
+
readonly databaseID: ClientDBID;
|
|
456
|
+
/** The client's unique identifier. */
|
|
457
|
+
readonly uid: UID;
|
|
458
|
+
/** The nickname the client last used. */
|
|
459
|
+
readonly nickname: string;
|
|
460
|
+
/** When the client first connected. */
|
|
461
|
+
readonly createdAt: Date | undefined;
|
|
462
|
+
/** When the client last connected. */
|
|
463
|
+
readonly lastConnectedAt: Date | undefined;
|
|
464
|
+
/** How many times the client has connected. */
|
|
465
|
+
readonly totalConnections: number;
|
|
466
|
+
/** The client's description. */
|
|
467
|
+
readonly description: string;
|
|
468
|
+
/** The address the client last connected from. */
|
|
469
|
+
readonly lastIP: string;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const parseDatabaseEntry = (row: Record<string, string>): ClientDatabaseEntry => ({
|
|
473
|
+
databaseID: asClientDBID(big(row, "cldbid")),
|
|
474
|
+
uid: asUID(str(row, "client_unique_identifier")),
|
|
475
|
+
nickname: str(row, "client_nickname"),
|
|
476
|
+
createdAt: date(row, "client_created"),
|
|
477
|
+
lastConnectedAt: date(row, "client_lastconnected"),
|
|
478
|
+
totalConnections: num(row, "client_totalconnections"),
|
|
479
|
+
description: str(row, "client_description"),
|
|
480
|
+
lastIP: str(row, "client_lastip"),
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
/** Which slice of the client database {@link listClientDatabase} reads. */
|
|
484
|
+
export interface ClientDatabasePageOptions extends CommandOptions {
|
|
485
|
+
/** The offset of the first record, 0 by default (`start`). */
|
|
486
|
+
readonly start?: number | undefined;
|
|
487
|
+
/** How many records to read at most; the server caps it (`duration`). */
|
|
488
|
+
readonly limit?: number | undefined;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const pageNames: WireNames<ClientDatabasePageOptions> = { start: "start", limit: "duration" };
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* One page of persistent client records.
|
|
495
|
+
*
|
|
496
|
+
* The database is paged, and the server caps a page; {@link iterateClientDatabase}
|
|
497
|
+
* walks all of it. A `start` past the last record is an empty page.
|
|
498
|
+
*/
|
|
499
|
+
export async function listClientDatabase(
|
|
500
|
+
client: CommandExecutor,
|
|
501
|
+
options: ClientDatabasePageOptions = {},
|
|
502
|
+
): Promise<ClientDatabaseEntry[]> {
|
|
503
|
+
return (await list(client, "clientdblist", encodeFields(options, pageNames), options)).map(
|
|
504
|
+
parseDatabaseEntry,
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Every persistent client record, fetched a page at a time as the loop asks
|
|
510
|
+
* for more:
|
|
511
|
+
*
|
|
512
|
+
* ```ts
|
|
513
|
+
* for await (const entry of iterateClientDatabase(client, { signal })) { ... }
|
|
514
|
+
* ```
|
|
515
|
+
*
|
|
516
|
+
* The walk ends when the server answers a page past the last record with
|
|
517
|
+
* error 1281, or with a page shorter than an earlier one; any other error is
|
|
518
|
+
* thrown from the loop. Each page is a separate `clientdblist`, given the
|
|
519
|
+
* options' signal and timeoutMs, so records added or removed meanwhile can be
|
|
520
|
+
* skipped or seen twice.
|
|
521
|
+
*/
|
|
522
|
+
export function iterateClientDatabase(
|
|
523
|
+
client: CommandExecutor,
|
|
524
|
+
options?: PagingOptions,
|
|
525
|
+
): AsyncIterable<ClientDatabaseEntry> {
|
|
526
|
+
return pages(
|
|
527
|
+
client,
|
|
528
|
+
"clientdblist",
|
|
529
|
+
parseDatabaseEntry,
|
|
530
|
+
(previous, next) => next.databaseID > previous.databaseID,
|
|
531
|
+
options,
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Database ids of the records whose nickname matches `pattern`, which may use
|
|
537
|
+
* `%` as a wildcard. No match is an empty list.
|
|
538
|
+
*/
|
|
539
|
+
export async function findClientDatabase(
|
|
540
|
+
client: CommandExecutor,
|
|
541
|
+
pattern: string,
|
|
542
|
+
options?: CommandOptions,
|
|
543
|
+
): Promise<ClientDBID[]> {
|
|
544
|
+
const rows = await list(client, "clientdbfind", [["pattern", pattern]], options);
|
|
545
|
+
return rows.map((row) => asClientDBID(big(row, "cldbid")));
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/** One database record. */
|
|
549
|
+
export async function getClientDatabaseInfo(
|
|
550
|
+
client: CommandExecutor,
|
|
551
|
+
cldbid: ClientDBID,
|
|
552
|
+
options?: CommandOptions,
|
|
553
|
+
): Promise<ClientDatabaseEntry> {
|
|
554
|
+
const rows = await query(client, "clientdbinfo", [["cldbid", cldbid]], options);
|
|
555
|
+
return { ...parseDatabaseEntry(firstRow(rows, "clientdbinfo")), databaseID: cldbid };
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* A database record's editable attributes, as `clientdbedit` takes them.
|
|
560
|
+
* Unset fields are omitted; `""` is sent empty.
|
|
561
|
+
*/
|
|
562
|
+
export interface ClientDatabaseEditOptions {
|
|
563
|
+
/** The client's description (`client_description`). */
|
|
564
|
+
readonly description?: string | undefined;
|
|
565
|
+
/** The nickname on record (`client_nickname`). */
|
|
566
|
+
readonly nickname?: string | undefined;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const databaseEditNames: WireNames<ClientDatabaseEditOptions> = {
|
|
570
|
+
description: "client_description",
|
|
571
|
+
nickname: "client_nickname",
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Change a database record. Only the fields you set are sent.
|
|
576
|
+
*
|
|
577
|
+
* `edit` is what to send; the command's `signal` and `timeoutMs` go in
|
|
578
|
+
* `options`, a separate last argument — set among the fields, they are not
|
|
579
|
+
* read.
|
|
580
|
+
*/
|
|
581
|
+
export async function editClientDatabase(
|
|
582
|
+
client: CommandExecutor,
|
|
583
|
+
cldbid: ClientDBID,
|
|
584
|
+
edit: ClientDatabaseEditOptions,
|
|
585
|
+
options?: CommandOptions,
|
|
586
|
+
): Promise<void> {
|
|
587
|
+
await exec(
|
|
588
|
+
client,
|
|
589
|
+
"clientdbedit",
|
|
590
|
+
[["cldbid", cldbid], ...encodeFields(edit, databaseEditNames)],
|
|
591
|
+
options,
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/** Delete a client from the database entirely. */
|
|
596
|
+
export async function deleteClientDatabase(
|
|
597
|
+
client: CommandExecutor,
|
|
598
|
+
cldbid: ClientDBID,
|
|
599
|
+
options?: CommandOptions,
|
|
600
|
+
): Promise<void> {
|
|
601
|
+
await exec(client, "clientdbdelete", [["cldbid", cldbid]], options);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// ---- Client permissions -----------------------------------------------------
|
|
605
|
+
|
|
606
|
+
/** Permissions set on a client, server-wide. */
|
|
607
|
+
export async function listClientPermissions(
|
|
608
|
+
client: CommandExecutor,
|
|
609
|
+
cldbid: ClientDBID,
|
|
610
|
+
options?: CommandOptions,
|
|
611
|
+
): Promise<PermissionEntry[]> {
|
|
612
|
+
return (await list(client, "clientpermlist", [["cldbid", cldbid]], options)).map(parsePermission);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/** How {@link addClientPermission} sets the permission. */
|
|
616
|
+
export interface ClientPermissionOptions extends CommandOptions {
|
|
617
|
+
/**
|
|
618
|
+
* Whether it skips channel and client overrides; false by default. Always
|
|
619
|
+
* sent: the server requires it here, unlike the channel equivalent
|
|
620
|
+
* (`permskip`).
|
|
621
|
+
*/
|
|
622
|
+
readonly skip?: boolean | undefined;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/** Set a permission on a client, server-wide. */
|
|
626
|
+
export async function addClientPermission(
|
|
627
|
+
client: CommandExecutor,
|
|
628
|
+
cldbid: ClientDBID,
|
|
629
|
+
permission: Permission,
|
|
630
|
+
value: number,
|
|
631
|
+
options: ClientPermissionOptions = {},
|
|
632
|
+
): Promise<void> {
|
|
633
|
+
await exec(
|
|
634
|
+
client,
|
|
635
|
+
"clientaddperm",
|
|
636
|
+
[
|
|
637
|
+
["cldbid", cldbid],
|
|
638
|
+
permissionParam(permission),
|
|
639
|
+
["permvalue", value],
|
|
640
|
+
["permskip", options.skip ?? false],
|
|
641
|
+
],
|
|
642
|
+
options,
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/** Remove a permission from a client. */
|
|
647
|
+
export async function deleteClientPermission(
|
|
648
|
+
client: CommandExecutor,
|
|
649
|
+
cldbid: ClientDBID,
|
|
650
|
+
permission: Permission,
|
|
651
|
+
options?: CommandOptions,
|
|
652
|
+
): Promise<void> {
|
|
653
|
+
await exec(client, "clientdelperm", [["cldbid", cldbid], permissionParam(permission)], options);
|
|
654
|
+
}
|