@honeybbq/teamspeak-client 1.0.0-beta.2 → 1.0.0-beta.3

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["base64UrlToBytes"],"sources":["../src/types.ts","../src/errors.ts","../src/abort.ts","../src/crypto/identity.ts","../src/crypto/eax.ts","../src/crypto/crypt.ts","../src/crypto/primitives.ts","../src/address.ts","../src/discovery/resolver.ts","../src/transport/packet.ts","../src/transport/generation-window.ts","../src/transport/quicklz.ts","../src/handshake/crypt-handshake.ts","../src/transport/handler.ts","../src/commands.ts","../src/transfer.ts","../src/events.ts","../src/capabilities.ts","../src/handshake/license.ts","../src/handshake/crypt-init2.ts","../src/handshake.ts","../src/notifications.ts","../src/throttle.ts","../src/helpers.ts","../src/diagnostics.ts","../src/reconnect.ts","../src/client.ts","../src/api/voice.ts"],"sourcesContent":["import type {\n ChannelID,\n ClientEntry,\n ClientID,\n CommandMiddleware,\n Logger,\n NotificationName,\n ServerGroupID,\n UID,\n} from \"@honeybbq/teamspeak-core\";\nimport type { Duplex } from \"node:stream\";\nimport type { ReconnectOptions } from \"./reconnect.js\";\n\n// ---- Events ---------------------------------------------------------------\n\n/** A text message, sent privately, to a channel, or to the whole server. */\nexport interface TextMessageEvent {\n /** The sender's nickname. */\n readonly invokerName: string;\n /** The sender's unique identifier. */\n readonly invokerUID: UID;\n /** The message, unescaped. */\n readonly message: string;\n /** The sender's server groups, as this client last saw them. */\n readonly invokerGroups: readonly ServerGroupID[];\n /**\n * Private, channel or server; compare it with `TextMessageTarget`. A plain\n * number, since a server may send a mode that table does not name.\n */\n readonly targetMode: number;\n /**\n * The client a private message was sent to. Channel and server messages\n * carry no target, so it is 0 for them.\n */\n readonly targetID: ClientID;\n /** The sender. */\n readonly invokerID: ClientID;\n}\n\n/** A client changing channel, of its own accord or moved by someone. */\nexport interface ClientMovedEvent {\n /** Who moved the client; the client itself for a move of its own. */\n readonly invokerName: string;\n /** The mover's unique identifier. */\n readonly invokerUID: UID;\n /** The channel the client is now in. */\n readonly targetChannelID: ChannelID;\n /** Why the client moved; compare it with `Reason`. */\n readonly reason: number;\n /** The client that moved. */\n readonly clientID: ClientID;\n /** The mover. */\n readonly invokerID: ClientID;\n}\n\n/**\n * A client going out of view: leaving the server, kicked or banned from it, or\n * in a channel that stopped being subscribed.\n */\nexport interface ClientLeaveEvent {\n /** The reason given for a kick or a ban, or the client's own parting message. */\n readonly reasonMessage: string;\n /** Why the client left; compare it with `Reason`. */\n readonly reason: number;\n /** The client that left. */\n readonly clientID: ClientID;\n /** Who kicked or banned the client; empty otherwise. */\n readonly invokerName: string;\n /** The kicker's unique identifier; empty unless kicked or banned. */\n readonly invokerUID: UID;\n /** The kicker; 0 unless kicked or banned. */\n readonly invokerID: ClientID;\n}\n\n/** This client being kicked from its channel or the server. */\nexport interface KickedEvent {\n /** The reason the invoker gave. */\n readonly reasonMessage: string;\n /** `Reason.KickChannel`, `Reason.KickServer` or `Reason.KickServerBan`. */\n readonly reason: number;\n /** Who kicked this client. */\n readonly invokerName: string;\n /** The kicker's unique identifier. */\n readonly invokerUID: UID;\n /** The kicker. */\n readonly invokerID: ClientID;\n}\n\n/**\n * A client coming into view: the same record `listClients` returns, so one\n * type describes a client however it was learned of; its own id is `id`, as\n * in every record. The fields only `clientlist -times` reports are undefined\n * here.\n */\nexport type ClientEnterEvent = ClientEntry;\n\n/** This client being poked. */\nexport interface PokeEvent {\n /** Who poked. */\n readonly invokerName: string;\n /** The poker's unique identifier. */\n readonly invokerUID: UID;\n /** The poker. */\n readonly invokerID: ClientID;\n /** The poke's message, unescaped. */\n readonly message: string;\n}\n\n/** Audio from another client, in the channel or whispered. */\nexport interface VoiceDataEvent {\n /** Who is speaking. */\n readonly clientID: ClientID;\n /**\n * How the audio is encoded; compare it with `Codec`. A plain number, since a\n * server may relay a codec that table does not name.\n */\n readonly codec: number;\n /** One encoded frame, copied: it stays valid after the listener returns. */\n readonly data: Uint8Array;\n}\n\n/**\n * A notification from the server, as it arrived: the escape hatch for one the\n * SDK does not model. Match its `name` against `NotificationName`.\n */\nexport interface NotificationEvent {\n /** The notification's name, such as `notifyserveredited`; `NotificationName` lists the known ones. */\n readonly name: NotificationName | (string & {});\n /** Its parameters, unescaped. */\n readonly params: Readonly<Record<string, string>>;\n}\n\n/**\n * The events `Client.on()` takes, and what each delivers. May gain events in a\n * minor release; code that handles every event generically should expect\n * names it does not know.\n */\nexport interface EventMap {\n /** A text message to this client, its channel or the server. */\n textMessage: TextMessageEvent;\n /** A client coming into view, including every client already there on connecting. */\n clientEnter: ClientEnterEvent;\n /** A client going out of view. */\n clientLeave: ClientLeaveEvent;\n /** A client changing channel. */\n clientMoved: ClientMovedEvent;\n /** This client being poked. */\n poked: PokeEvent;\n /**\n * Audio from another client. Only decoded with a listener or event\n * middleware. Voice is dropped, counted and reported in a warning at most\n * every ten seconds, while more than 256 deliveries are waiting: a listener\n * that cannot keep up loses audio rather than memory.\n */\n voiceData: VoiceDataEvent;\n /**\n * Every notification the server sends, modelled or not, after any event it\n * produces.\n */\n notification: NotificationEvent;\n /** The handshake completing, on `connect()` and on every reconnection. */\n connected: void;\n /**\n * `undefined` after `disconnect()`, and the cause otherwise: a failed\n * handshake, a `ConnectionTimeoutError`, or a `RemovedError` for a kick, a\n * ban or a server stopping.\n */\n disconnected: Error | undefined;\n /** A kick from the server also ends the connection, which `disconnected` reports. */\n kicked: KickedEvent;\n}\n\n/**\n * The events that come from the server, and so pass through event middleware.\n * May gain members in a minor release: a `switch` over an event's name needs\n * a default case.\n */\nexport type ServerEventName =\n | \"textMessage\"\n | \"clientEnter\"\n | \"clientLeave\"\n | \"clientMoved\"\n | \"poked\"\n | \"voiceData\"\n | \"notification\";\n\n/** A server event as event middleware sees it. */\nexport type ServerEvent = {\n [K in ServerEventName]: { readonly name: K; readonly payload: EventMap[K] };\n}[ServerEventName];\n\n/** A listener for one event. */\nexport type Listener<K extends keyof EventMap> = EventMap[K] extends void\n ? () => void\n : (payload: EventMap[K]) => void;\n\n/** Removes a listener; calling it again does nothing. Also a `Disposable`, for `using`. */\nexport type Unsubscribe = (() => void) & Disposable;\n\n// ---- Transport seam ---------------------------------------------------------\n\n/**\n * The part of a UDP socket the client uses. A `node:dgram` socket is one; so\n * is anything else with these methods, such as a tunnel or a test double.\n *\n * Should a later release use more of a socket, the new members will be\n * optional here, so an implementation of this interface keeps compiling.\n */\nexport interface DatagramSocket {\n /** Fix the peer, then call `callback`; failure is reported as an `error` event. */\n connect(port: number, address: string, callback: () => void): void;\n /** Send one datagram to the peer. */\n send(data: Uint8Array, callback: (error: Error | null) => void): void;\n /** Close the socket; it then emits `close`. */\n close(): void;\n /** Listen for each datagram received. */\n on(event: \"message\", listener: (message: Uint8Array) => void): unknown;\n /** Listen for a failure, which ends the connection. */\n on(event: \"error\", listener: (error: Error) => void): unknown;\n /** Listen for the socket closing. */\n on(event: \"close\", listener: () => void): unknown;\n /** Listen for the next failure only, while connecting. */\n once(event: \"error\", listener: (error: Error) => void): unknown;\n /** Stop listening for failures. */\n off(event: \"error\", listener: (error: Error) => void): unknown;\n}\n\n/** Creates the UDP socket the client talks through, for the given address family. */\nexport type SocketFactory = (family: 4 | 6) => DatagramSocket;\n\n/**\n * Opens the connection a file transfer runs over, to `host:port`. A\n * `node:net` socket is one, as is the socket a SOCKS or HTTP proxy library\n * returns. It may still be connecting when returned: the transfer waits for\n * it.\n */\nexport type FileTransferSocketFactory = (host: string, port: number) => Duplex;\n\n// ---- Client status ----------------------------------------------------------\n\n/** The values of the table below, before freezing. */\nconst clientStatusValues = {\n /** Not connected: before `connect()`, after `disconnect()`, or after a drop. */\n Disconnected: \"disconnected\",\n /** Connecting: `connect()` is waiting for the handshake. */\n Connecting: \"connecting\",\n /** Connected: the handshake completed and commands can be sent. */\n Connected: \"connected\",\n} as const;\n/** Where a client is in its connection's life. */\nexport const ClientStatus: typeof clientStatusValues =\n /* @__PURE__ */ Object.freeze(clientStatusValues);\n/**\n * One of {@link ClientStatus}. May gain members in a minor release: a\n * `switch` over it needs a default case.\n */\nexport type ClientStatus = (typeof ClientStatus)[keyof typeof ClientStatus];\n\n/** Wraps the delivery of server events; it may observe, alter or drop them. */\nexport type EventMiddleware = (next: (event: ServerEvent) => void) => (event: ServerEvent) => void;\n\n// ---- Resolved address (from discovery) --------------------------------------\n\n/**\n * An address a server's name resolved to. Only `addr` is needed to connect;\n * the rest describes the answer.\n */\nexport interface ResolvedAddr {\n /** The endpoint, as `host:port`. */\n readonly addr: string;\n /** How it was found, such as `SRV`, `TSDNS-SRV`, `TSDNS-Direct` or `Direct`. */\n readonly source?: string | undefined;\n /** When the answer stops being valid; unset for no stated lifetime. */\n readonly expiry?: Date | undefined;\n}\n\n// ---- AddrResolver interface -------------------------------------------------\n\n/**\n * Turns the address a client was given — a host, `host:port`, or a TeamSpeak\n * name — into endpoints to connect to. The default follows SRV records and\n * TSDNS, as the TeamSpeak application does.\n */\nexport interface AddrResolver {\n /**\n * The endpoints for `addr`, best first. An empty answer falls back to `addr`\n * itself. `signal` aborts when the connection attempt is given up, or once\n * resolution has taken 10 seconds, after which the client connects to\n * `addr` as given; a resolver that ignores it is abandoned all the same.\n */\n resolve(\n addr: string,\n options?: { readonly signal?: AbortSignal | undefined },\n ): Promise<readonly ResolvedAddr[]>;\n}\n\n// ---- ClientOptions ----------------------------------------------------------\n\n/** How a `Client` connects, logs and behaves; every field is optional. */\nexport interface ClientOptions {\n /** Where the client logs. Silent unless set: a library has no business writing to the console. */\n readonly logger?: Logger | undefined;\n /**\n * Creates the UDP socket the client talks through, given the address family\n * the server's address resolved to.\n *\n * Supplying one lets an application route traffic through a proxy or tunnel,\n * or drive the client from something other than a real socket. It is the only\n * seam into the transport: without it the SDK always creates its own.\n */\n readonly socketFactory?: SocketFactory | undefined;\n /**\n * Reconnect after a dropped connection.\n *\n * Off by default: a silent reconnect makes an outage look like an ordinary\n * session. An explicit `disconnect()` never reconnects regardless.\n */\n readonly reconnect?: ReconnectOptions | undefined;\n /**\n * Creates the TCP socket a file transfer runs over.\n *\n * Separate from `socketFactory` because file transfer dials its own\n * connection to a different port, on demand. Set both to route everything\n * through a proxy.\n */\n readonly fileTransferSocketFactory?: FileTransferSocketFactory | undefined;\n /**\n * Look a dot-less address up as a server nickname at named.myteamspeak.com,\n * as the TeamSpeak application does. Off by default, since it sends the name\n * to a third party; without it a dot-less name is resolved like any host.\n * Ignored with a custom `resolver`.\n */\n readonly resolveNicknames?: boolean | undefined;\n /** Replaces the SRV and TSDNS resolution `connect()` performs. */\n readonly resolver?: AddrResolver | undefined;\n /**\n * Wraps every typed command, outermost first; see `CommandMiddleware`. Raw\n * lines sent with `exec` and `execNoWait` do not pass through it. Fixed for\n * the client's life.\n */\n readonly commandMiddleware?: readonly CommandMiddleware[] | undefined;\n /** Wraps the delivery of every server event, outermost first. Fixed for the client's life. */\n readonly eventMiddleware?: readonly EventMiddleware[] | undefined;\n /** Server password sent during the initial `clientinit` handshake. */\n readonly serverPassword?: string | undefined;\n /** Default channel name to join during the initial `clientinit` handshake. */\n readonly defaultChannel?: string | undefined;\n /** Password for `defaultChannel`, sent during the initial `clientinit` handshake. */\n readonly defaultChannelPassword?: string | undefined;\n}\n","import { Reason, TeamspeakError } from \"@honeybbq/teamspeak-core\";\n\n/** `connect()` was called on a client that is connecting or connected. */\nexport class AlreadyConnectedError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"AlreadyConnectedError\";\n\n constructor() {\n super(\"already connecting or connected\");\n this.name = \"AlreadyConnectedError\";\n }\n}\n\n/**\n * The address a client was given cannot be connected to: no host, a host with\n * characters no host name or IP address has, or a port outside 1–65535.\n * `connect()` rejects with it before it starts, and the client stays\n * disconnected. A name that does not resolve is not this: that fails with a\n * TeamspeakError whose `cause` is the lookup's error, since DNS failures are\n * often transient.\n */\nexport class InvalidAddressError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"InvalidAddressError\";\n\n /** The address as given. */\n readonly address: string;\n\n constructor(address: string, reason: string) {\n super(`invalid address ${JSON.stringify(address)}: ${reason}`);\n this.name = \"InvalidAddressError\";\n this.address = address;\n }\n}\n\n/**\n * A packet failed authentication: it was corrupted, or not from the server.\n * Internal: the packet is dropped, and this never reaches a caller.\n */\nexport class EAXTagMismatchError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"EAXTagMismatchError\";\n\n constructor() {\n super(\"EAX tag mismatch\");\n this.name = \"EAXTagMismatchError\";\n }\n}\n\n/**\n * An unencrypted packet failed its integrity check. Internal: the packet is\n * dropped, and this never reaches a caller.\n */\nexport class FakeSignatureMismatchError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"FakeSignatureMismatchError\";\n\n constructor() {\n super(\"fake signature mismatch\");\n this.name = \"FakeSignatureMismatchError\";\n }\n}\n\n/** A file transfer connection failed: it could not be opened, or broke during the transfer. */\nexport class FileTransferError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"FileTransferError\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"FileTransferError\";\n }\n}\n\n/**\n * The handshake failed on what the server sent: a malformed or out-of-range\n * Init1 step, public key, license or proof. `connect()` rejects with it, the\n * underlying failure as its `cause`.\n */\nexport class CryptoInitError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"CryptoInitError\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"CryptoInitError\";\n }\n}\n\n/** An identity string `parseIdentity()` cannot read. */\nexport class InvalidIdentityError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"InvalidIdentityError\";\n\n constructor(message = \"invalid identity format\", options?: ErrorOptions) {\n super(message, options);\n this.name = \"InvalidIdentityError\";\n }\n}\n\n/**\n * The server stopped answering: nothing arrived, or a packet went\n * unacknowledged, for a minute.\n */\nexport class ConnectionTimeoutError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"ConnectionTimeoutError\";\n\n constructor() {\n super(\"connection timed out: the server stopped answering\");\n this.name = \"ConnectionTimeoutError\";\n }\n}\n\n/**\n * The server ended this client's session: a kick, a ban, or the server\n * stopping. The default reconnect policy retries a server that stopped, but\n * not a kick or a ban.\n */\nexport class RemovedError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"RemovedError\";\n\n /** Why: `Reason.KickServer`, `KickServerBan`, `ServerStop` or `ServerShutdown`. */\n readonly reason: number;\n /** The reason the server or the invoker gave, if any. */\n readonly reasonMessage: string;\n /** Who removed the client, for a kick or a ban. */\n readonly invokerName: string;\n\n constructor(reason: number, reasonMessage: string, invokerName: string) {\n let message = `removed from the server: ${reasonName(reason)}`;\n if (invokerName) message += ` by ${invokerName}`;\n if (reasonMessage) message += `: ${reasonMessage}`;\n super(message);\n this.name = \"RemovedError\";\n this.reason = reason;\n this.reasonMessage = reasonMessage;\n this.invokerName = invokerName;\n }\n}\n\nfunction reasonName(reason: number): string {\n switch (reason) {\n case Reason.KickServer:\n return \"kicked from server\";\n case Reason.KickServerBan:\n return \"banned from server\";\n case Reason.ServerStop:\n return \"server stopped\";\n case Reason.ServerShutdown:\n return \"server shut down\";\n default:\n return `reason ${reason}`;\n }\n}\n","/** The reason an aborted signal gives, as an error. */\nexport function abortReason(signal: AbortSignal): unknown {\n return signal.reason ?? new DOMException(\"This operation was aborted\", \"AbortError\");\n}\n\n/** Settle with `promise`, or reject as soon as `signal` aborts, whichever is first. */\nexport function abortable<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return promise;\n if (signal.aborted) return Promise.reject(abortReason(signal));\n return new Promise<T>((resolve, reject) => {\n const onAbort = (): void => reject(abortReason(signal));\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error);\n },\n );\n });\n}\n","import {\n createHash,\n createECDH,\n generateKeyPairSync,\n createPrivateKey,\n createPublicKey,\n type KeyObject,\n} from \"node:crypto\";\nimport { InvalidIdentityError } from \"../errors.js\";\nimport { asUID, type UID } from \"@honeybbq/teamspeak-core\";\n\nconst P256_SCALAR_SIZE = 32;\nconst P256_UNCOMPRESSED_KEY_SIZE = 65;\nconst P256_POINT_PREFIX = 0x04;\n\n/** The most a security level can be: SHA-1 is 160 bits wide. */\nconst MAX_SECURITY_LEVEL = 160;\n\nlet createIdentity: (privateKey: KeyObject, offset: bigint) => Identity;\nlet privateKeyOf: (identity: Identity) => KeyObject;\n\n/**\n * A TeamSpeak client identity: a P-256 key pair plus a counter, the offset,\n * whose hash with the public key sets the identity's security level.\n *\n * Immutable: raising the level returns a new identity. Opaque: the private\n * key is never exposed, and `toString()`, `toJSON()` and `util.inspect()`\n * describe the identity without it, so an identity that reaches a log or an\n * error message does not leak; `export()` is the one way to get the secret\n * form, for storing it. Make one with `generateIdentity()` or\n * `parseIdentity()`.\n */\nexport class Identity {\n static {\n createIdentity = (privateKey, offset) => new Identity(privateKey, offset);\n privateKeyOf = (identity) => identity.#privateKey;\n }\n\n readonly #privateKey: KeyObject;\n readonly #offset: bigint;\n #publicKey: string | undefined;\n\n private constructor(privateKey: KeyObject, offset: bigint) {\n this.#privateKey = privateKey;\n this.#offset = offset;\n }\n\n /** The counter whose hash with the public key sets the security level. */\n get offset(): bigint {\n return this.#offset;\n }\n\n /** The public key in TeamSpeak's encoding: base64 of its DER form. */\n publicKey(): string {\n if (this.#publicKey !== undefined) return this.#publicKey;\n const rawJwk = this.#privateKey.export({ format: \"jwk\" });\n if (typeof rawJwk.x !== \"string\" || typeof rawJwk.y !== \"string\") return \"\";\n\n const xBytes = base64UrlToBytes(rawJwk.x, P256_SCALAR_SIZE);\n const yBytes = base64UrlToBytes(rawJwk.y, P256_SCALAR_SIZE);\n // Encode as TS3 canonical ASN.1: SEQUENCE { BIT STRING, INTEGER(32), INTEGER(x), INTEGER(y) }\n this.#publicKey = encodeTsPublicKey(xBytes, yBytes);\n return this.#publicKey;\n }\n\n /**\n * The identity's unique identifier, hashed with `algorithm`: SHA-1 for a\n * TeamSpeak 3 server, SHA-256 for TeamSpeak 6. A connected client's `uid`\n * already uses the one its server does.\n */\n uid(algorithm: UIDAlgorithm): UID {\n return uidFromPublicKey(this.publicKey(), algorithm);\n }\n\n /**\n * The identity in the form `parseIdentity()` reads, private key included.\n * Store it as you would a password.\n */\n export(): string {\n const jwk = this.#privateKey.export({ format: \"jwk\" }) as { d?: string };\n if (!jwk.d) return `:${this.#offset}`;\n const dBytes = base64UrlToBytes(jwk.d, P256_SCALAR_SIZE);\n return `${Buffer.from(dBytes).toString(\"base64\")}:${this.#offset}`;\n }\n\n /** Describes the identity, by its SHA-1 unique identifier, without its private key. */\n toString(): string {\n return `identity ${this.uid(\"sha1\")} (private key redacted)`;\n }\n\n /** The same as `toString()`, so serialising an identity cannot leak its key. */\n toJSON(): string {\n return this.toString();\n }\n\n /** The security level: trailing zero bits in SHA-1 of the public key and offset. */\n securityLevel(): number {\n return levelAt(this.publicKey(), this.#offset);\n }\n\n /**\n * The same key at an offset whose security level reaches `targetLevel`, as\n * a new identity; this one is unchanged, and returned as it is when it\n * already reaches the level.\n *\n * Each level doubles the expected work, so a high level can take a long\n * time; `signal` bounds it, and the event loop keeps running meanwhile. A\n * level above 160, the width of SHA-1, can never be reached and is refused\n * with a RangeError.\n */\n async upgradeToLevel(\n targetLevel: number,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): Promise<Identity> {\n checkLevel(targetLevel);\n const { signal } = options;\n const prefix = this.publicKey();\n let offset = this.#offset;\n while (true) {\n signal?.throwIfAborted();\n if (levelAt(prefix, offset) >= targetLevel) {\n return offset === this.#offset ? this : new Identity(this.#privateKey, offset);\n }\n offset++;\n // Yield to the event loop now and then rather than blocking it.\n if (offset % 10000n === 0n) {\n await new Promise<void>((resolve) => setImmediate(resolve));\n }\n }\n }\n}\n\n// Defined outside the class body: a computed key there would have to be\n// inferred, which isolatedDeclarations rules out. By its registered name, so\n// this module needs no node:util.\nObject.defineProperty(Identity.prototype, Symbol.for(\"nodejs.util.inspect.custom\"), {\n value(this: Identity): string {\n return `Identity <${this.toString()}>`;\n },\n});\n\n/**\n * The private key of an identity, for the handshake. Not exported from the\n * package.\n *\n * @internal\n */\nexport function identityPrivateKey(identity: Identity): KeyObject {\n return privateKeyOf(identity);\n}\n\nfunction checkLevel(level: number): void {\n if (!Number.isInteger(level) || level < 0 || level > MAX_SECURITY_LEVEL) {\n throw new RangeError(`a security level is an integer from 0 to 160, not ${level}`);\n }\n}\n\nfunction levelAt(publicKey: string, offset: bigint): number {\n const h = createHash(\"sha1\");\n h.update(publicKey);\n h.update(offset.toString(10));\n return countLeadingZeros(h.digest());\n}\n\n/** The largest offset, an unsigned 64-bit counter. */\nconst MAX_UINT64 = (1n << 64n) - 1n;\n\n/**\n * Read an identity from the form `Identity.export()` writes: the private key\n * as canonical base64 of at most 32 bytes, a colon, and the offset as a\n * decimal unsigned 64-bit integer. Anything else throws an\n * InvalidIdentityError, with the underlying failure as its cause.\n */\nexport function parseIdentity(s: string): Identity {\n const colonIdx = s.lastIndexOf(\":\");\n if (colonIdx < 0) throw new InvalidIdentityError();\n\n const dBase64 = s.slice(0, colonIdx);\n const offsetStr = s.slice(colonIdx + 1);\n if (!/^\\d+$/.test(offsetStr) || BigInt(offsetStr) > MAX_UINT64) {\n throw new InvalidIdentityError(\"invalid identity offset\");\n }\n const offset = BigInt(offsetStr);\n\n // Node's base64 decoder skips what it cannot read, so the key is checked by\n // a round trip: anything but canonical base64 would otherwise decode to some\n // other key, silently.\n const dBytes = Buffer.from(dBase64, \"base64\");\n if (dBytes.length === 0 || dBytes.toString(\"base64\") !== dBase64) {\n throw new InvalidIdentityError(\"the private key is not canonical base64\");\n }\n if (dBytes.length > P256_SCALAR_SIZE) {\n throw new InvalidIdentityError(\"private key scalar too large\");\n }\n\n // Pad to P256_SCALAR_SIZE\n const padded = Buffer.alloc(P256_SCALAR_SIZE);\n dBytes.copy(padded, P256_SCALAR_SIZE - dBytes.length);\n\n try {\n // node:crypto JWK import requires x and y to be present.\n // Derive the public key from the private scalar via ECDH.\n const ecdh = createECDH(\"prime256v1\");\n ecdh.setPrivateKey(padded);\n const pub = ecdh.getPublicKey(null, \"uncompressed\"); // 65 bytes: 0x04 || x(32) || y(32)\n\n const x = Buffer.from(pub.slice(1, 33)).toString(\"base64url\");\n const y = Buffer.from(pub.slice(33, 65)).toString(\"base64url\");\n const d = padded.toString(\"base64url\");\n\n const jwk = { kty: \"EC\", crv: \"P-256\", d, x, y };\n return createIdentity(createPrivateKey({ key: jwk, format: \"jwk\" }), offset);\n } catch (error) {\n throw new InvalidIdentityError(\"invalid private key\", { cause: error });\n }\n}\n\n/**\n * Create an identity at the given security level, at most 160. Each level\n * doubles the expected work; `signal` bounds it, and the event loop keeps\n * running meanwhile.\n */\nexport async function generateIdentity(\n targetLevel: number,\n options: { readonly signal?: AbortSignal | undefined } = {},\n): Promise<Identity> {\n checkLevel(targetLevel);\n return createIdentity(generateKey(), 0n).upgradeToLevel(targetLevel, options);\n}\n\n/**\n * Create an identity at the given security level, at most 160, blocking until\n * done. Fine for a low level; a high one can block the event loop for minutes,\n * so prefer `generateIdentity()` there.\n */\nexport function generateIdentitySync(targetLevel: number): Identity {\n checkLevel(targetLevel);\n const key = generateKey();\n const prefix = createIdentity(key, 0n).publicKey();\n let offset = 0n;\n while (levelAt(prefix, offset) < targetLevel) offset++;\n return createIdentity(key, offset);\n}\n\nfunction generateKey(): KeyObject {\n return generateKeyPairSync(\"ec\", { namedCurve: \"prime256v1\" }).privateKey;\n}\n\n/**\n * The hash a server uses for `client_unique_identifier`, keyed by the server's\n * major version.\n *\n * TeamSpeak 3 hashes the canonical public key with SHA-1 (20 bytes); TeamSpeak\n * 6 switched to SHA-256 (32 bytes). The algorithm is not negotiable on the\n * wire, so a client that guesses wrong computes a UID that matches nothing the\n * server ever sends — self-identification by UID silently fails.\n *\n * May gain members in a minor release, should a server generation change the\n * hash again: a `switch` over it needs a default case.\n */\nexport type UIDAlgorithm = \"sha1\" | \"sha256\";\n\n/** Pick the UID hash from a `virtualserver_version` string, e.g. \"6.0.0-beta13.1\". */\nexport function uidAlgorithmForVersion(version: string): UIDAlgorithm {\n const major = Number.parseInt(version, 10);\n return Number.isNaN(major) || major < 6 ? \"sha1\" : \"sha256\";\n}\n\n/**\n * The unique identifier of a public key in TeamSpeak's encoding, hashed with\n * `algorithm`: SHA-1 for a TeamSpeak 3 server, SHA-256 for TeamSpeak 6.\n */\nexport function uidFromPublicKey(publicKey: string, algorithm: UIDAlgorithm): UID {\n return asUID(createHash(algorithm).update(publicKey).digest(\"base64\"));\n}\n\nexport function hash512(data: Uint8Array): Uint8Array {\n return createHash(\"sha512\").update(data).digest();\n}\n\n// ---- Internal ASN.1 DER helpers for TS3 canonical P-256 public key ----------\n\n/**\n * Encode a P-256 public key as the TS3 canonical ASN.1 SEQUENCE and return\n * its base64 representation.\n *\n * TS3 canonical format (v3+):\n * SEQUENCE {\n * BIT STRING { unused=7, value=0x00 } — DER: 03 02 07 00\n * INTEGER 32\n * INTEGER x\n * INTEGER y\n * }\n */\nfunction encodeTsPublicKey(x: Uint8Array, y: Uint8Array): string {\n // BIT STRING with 7 unused bits + value byte 0x00 — matches C# DerBitString(0x00, 7)\n const bitStringBody = Buffer.from([0x07, 0x00]);\n const bitStringDer = encodeDerTlv(0x03, bitStringBody);\n\n const integerSize = encodeDerTlv(0x02, encodePositiveInt(32));\n const integerX = encodeDerTlv(0x02, encodePositiveInt(x));\n const integerY = encodeDerTlv(0x02, encodePositiveInt(y));\n\n const seqBody = Buffer.concat([bitStringDer, integerSize, integerX, integerY]);\n const seqDer = encodeDerTlv(0x30, seqBody);\n\n return seqDer.toString(\"base64\");\n}\n\n/** Import a TS3 public key (canonical or legacy ASN.1 DER) and return the\n * uncompressed 65-byte point [0x04 || x || y]. */\nexport function importPublicKey(data: Uint8Array): KeyObject {\n const point = parseTsPublicKeyDer(data);\n const jwk = {\n kty: \"EC\",\n crv: \"P-256\",\n x: Buffer.from(point.slice(1, 33)).toString(\"base64url\"),\n y: Buffer.from(point.slice(33, 65)).toString(\"base64url\"),\n };\n return createPublicKey({ key: jwk, format: \"jwk\" });\n}\n\n/**\n * Parse both TS3 canonical and legacy ASN.1 formats and return the\n * uncompressed 65-byte point [0x04 || x || y].\n */\nfunction parseTsPublicKeyDer(data: Uint8Array): Uint8Array {\n // Try canonical: SEQUENCE { BIT_STRING, INTEGER(32), INTEGER(x), INTEGER(y) }\n try {\n return parseTsCanonicalPublicKey(data);\n } catch {\n // fall through to legacy\n }\n // Try legacy: SEQUENCE { INTEGER(x), INTEGER(y), BIT_STRING, INTEGER }\n return parseTsLegacyPublicKey(data);\n}\n\nfunction parseTsCanonicalPublicKey(data: Uint8Array): Uint8Array {\n const seqTlv = parseDerTlv(data, 0x30);\n const seq = seqTlv.value;\n let offset = 0;\n // BIT_STRING\n const bs = parseDerTlv(seq, 0x03, offset);\n offset += bs.consumed;\n // INTEGER (32)\n const sizeInt = parseDerTlv(seq, 0x02, offset);\n offset += sizeInt.consumed;\n // INTEGER x\n const xInt = parseDerTlv(seq, 0x02, offset);\n offset += xInt.consumed;\n // INTEGER y\n const yInt = parseDerTlv(seq, 0x02, offset);\n\n return buildUncompressedPoint(\n positiveIntToBytes(xInt.value, P256_SCALAR_SIZE),\n positiveIntToBytes(yInt.value, P256_SCALAR_SIZE),\n );\n}\n\nfunction parseTsLegacyPublicKey(data: Uint8Array): Uint8Array {\n const seqTlv = parseDerTlv(data, 0x30);\n const seq = seqTlv.value;\n let offset = 0;\n const xInt = parseDerTlv(seq, 0x02, offset);\n offset += xInt.consumed;\n const yInt = parseDerTlv(seq, 0x02, offset);\n\n return buildUncompressedPoint(\n positiveIntToBytes(xInt.value, P256_SCALAR_SIZE),\n positiveIntToBytes(yInt.value, P256_SCALAR_SIZE),\n );\n}\n\nfunction buildUncompressedPoint(x: Uint8Array, y: Uint8Array): Uint8Array {\n if (x.length > P256_SCALAR_SIZE || y.length > P256_SCALAR_SIZE) {\n throw new Error(\"invalid public key point encoding\");\n }\n const point = new Uint8Array(P256_UNCOMPRESSED_KEY_SIZE);\n point[0] = P256_POINT_PREFIX;\n point.set(x, 1 + P256_SCALAR_SIZE - x.length);\n point.set(y, 1 + 2 * P256_SCALAR_SIZE - y.length);\n return point;\n}\n\n// ---- DER encoding helpers ---------------------------------------------------\n\nfunction encodeDerTlv(tag: number, value: Uint8Array): Buffer {\n const lenBytes = encodeDerLength(value.length);\n return Buffer.concat([Buffer.from([tag]), lenBytes, value]);\n}\n\nfunction encodeDerLength(len: number): Buffer {\n if (len < 128) return Buffer.from([len]);\n if (len < 256) return Buffer.from([0x81, len]);\n return Buffer.from([0x82, (len >> 8) & 0xff, len & 0xff]);\n}\n\n/** Encode a non-negative value as a DER INTEGER (with 0x00 prefix if high bit set). */\nfunction encodePositiveInt(v: number | Uint8Array): Buffer {\n if (typeof v === \"number\") {\n const bytes: number[] = [];\n let n = v;\n do {\n bytes.unshift(n & 0xff);\n n >>= 8;\n } while (n > 0);\n if ((bytes[0]! & 0x80) !== 0) bytes.unshift(0x00);\n return Buffer.from(bytes);\n }\n // Uint8Array — strip leading zeros, add 0x00 if high bit set\n let start = 0;\n while (start < v.length - 1 && v[start] === 0) start++;\n const trimmed = v.slice(start);\n if ((trimmed[0]! & 0x80) !== 0) {\n return Buffer.concat([Buffer.from([0x00]), trimmed]);\n }\n return Buffer.from(trimmed);\n}\n\ninterface ParsedTlv {\n value: Uint8Array;\n consumed: number; // bytes consumed including tag+length\n}\n\nfunction parseDerTlv(data: Uint8Array, expectedTag: number, offset = 0): ParsedTlv {\n if (data[offset] !== expectedTag) {\n throw new Error(\n `expected DER tag 0x${expectedTag.toString(16)}, got 0x${(data[offset] ?? 0).toString(16)}`,\n );\n }\n let pos = offset + 1;\n let len: number;\n const firstLenByte = data[pos++]!;\n if (firstLenByte < 0x80) {\n len = firstLenByte;\n } else if (firstLenByte === 0x81) {\n len = data[pos++]!;\n } else if (firstLenByte === 0x82) {\n len = ((data[pos]! << 8) | data[pos + 1]!) >>> 0;\n pos += 2;\n } else {\n throw new Error(\"unsupported DER length encoding\");\n }\n const value = data.slice(pos, pos + len);\n return { value, consumed: pos - offset + len };\n}\n\n/** Convert a DER INTEGER value (may have leading 0x00) to fixed-length bytes. */\nfunction positiveIntToBytes(int: Uint8Array, size: number): Uint8Array {\n // Strip leading 0x00 sign byte\n let start = 0;\n while (start < int.length - 1 && int[start] === 0x00) start++;\n const stripped = int.slice(start);\n if (stripped.length > size) throw new Error(\"integer too large\");\n if (stripped.length === size) return stripped;\n const padded = new Uint8Array(size);\n padded.set(stripped, size - stripped.length);\n return padded;\n}\n\n// ---- Misc helpers -----------------------------------------------------------\n\nfunction base64UrlToBytes(b64url: string, size: number): Uint8Array {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n\nfunction countLeadingZeros(data: Buffer): number {\n let zeros = 0;\n for (const b of data) {\n if (b === 0) {\n zeros += 8;\n } else {\n for (let i = 0; i < 8; i++) {\n if ((b & (1 << i)) === 0) zeros++;\n else return zeros;\n }\n }\n }\n return zeros;\n}\n","import { createCipheriv, timingSafeEqual } from \"node:crypto\";\nimport { EAXTagMismatchError } from \"../errors.js\";\n\nconst EAX_TAG_SIZE = 8;\nconst EAX_BLOCK_SIZE = 16;\n\n/**\n * AES-EAX AEAD implementation for TS3 (64-bit tag, AES-128).\n * Uses AES-CMAC for authentication and AES-CTR for encryption.\n */\nexport class EAX {\n readonly #key: Uint8Array;\n\n constructor(key: Uint8Array) {\n if (key.length !== 16) throw new Error(\"EAX requires a 16-byte key\");\n this.#key = key;\n }\n\n encrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n plaintext: Uint8Array,\n ): [ciphertext: Uint8Array, tag: Uint8Array] {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n\n const ciphertext = aesCtr(this.#key, nStar, plaintext);\n\n const cStar = this.#cmac(2, ciphertext);\n\n const tag = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n tag[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n return [ciphertext, tag];\n }\n\n decrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): Uint8Array {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n const cStar = this.#cmac(2, ciphertext);\n\n const expected = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n expected[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n if (!timingSafeEqual(Buffer.from(expected), Buffer.from(tag.slice(0, EAX_TAG_SIZE)))) {\n throw new EAXTagMismatchError();\n }\n\n return aesCtr(this.#key, nStar, ciphertext);\n }\n\n /**\n * AES-CMAC per RFC 4493:\n * input = [0…0 tag] ++ data (one block prefix)\n */\n #cmac(tagByte: number, data: Uint8Array): Uint8Array {\n const input = new Uint8Array(EAX_BLOCK_SIZE + data.length);\n // first block: zeros then tag byte at the last position\n input[EAX_BLOCK_SIZE - 1] = tagByte;\n input.set(data, EAX_BLOCK_SIZE);\n\n return aesCmac(this.#key, input);\n }\n}\n\n// ---- AES-CTR ----------------------------------------------------------------\n\nfunction aesCtr(key: Uint8Array, iv: Uint8Array, data: Uint8Array): Uint8Array {\n const cipher = createCipheriv(\"aes-128-ctr\", Buffer.from(key), Buffer.from(iv));\n return Buffer.concat([cipher.update(Buffer.from(data)), cipher.final()]);\n}\n\n// ---- AES-CMAC (RFC 4493) ----------------------------------------------------\n\nfunction aesEcb(key: Uint8Array, block: Uint8Array): Uint8Array {\n // Node.js does not expose ECB directly; simulate via CTR with zero IV and\n // a zero-input (CTR of 0-block XOR with input = ECB)\n const cipher = createCipheriv(\"aes-128-ecb\", Buffer.from(key), null);\n cipher.setAutoPadding(false);\n return Buffer.concat([cipher.update(Buffer.from(block)), cipher.final()]);\n}\n\nfunction xorBlock(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n for (let i = 0; i < EAX_BLOCK_SIZE; i++) out[i] = a[i]! ^ b[i]!;\n return out;\n}\n\nfunction shiftLeft1(b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n let carry = 0;\n for (let i = EAX_BLOCK_SIZE - 1; i >= 0; i--) {\n const shifted = ((b[i]! << 1) | carry) & 0xff;\n carry = b[i]! >> 7;\n out[i] = shifted;\n }\n return out;\n}\n\nconst RB = new Uint8Array(EAX_BLOCK_SIZE);\nRB[EAX_BLOCK_SIZE - 1] = 0x87;\n\nfunction generateSubkeys(key: Uint8Array): [Uint8Array, Uint8Array] {\n const zero = new Uint8Array(EAX_BLOCK_SIZE);\n const L = aesEcb(key, zero);\n\n let K1 = shiftLeft1(L);\n if ((L[0]! & 0x80) !== 0) K1 = xorBlock(K1, RB);\n\n let K2 = shiftLeft1(K1);\n if ((K1[0]! & 0x80) !== 0) K2 = xorBlock(K2, RB);\n\n return [K1, K2];\n}\n\nexport function aesCmac(key: Uint8Array, message: Uint8Array): Uint8Array {\n const [K1, K2] = generateSubkeys(key);\n\n const n = Math.max(1, Math.ceil(message.length / EAX_BLOCK_SIZE));\n const lastBlockComplete = message.length > 0 && message.length % EAX_BLOCK_SIZE === 0;\n\n let X: Uint8Array = new Uint8Array(EAX_BLOCK_SIZE);\n\n for (let i = 0; i < n - 1; i++) {\n const block = message.slice(i * EAX_BLOCK_SIZE, (i + 1) * EAX_BLOCK_SIZE);\n X = Uint8Array.from(aesEcb(key, xorBlock(X, block)));\n }\n\n const lastBlock = new Uint8Array(EAX_BLOCK_SIZE);\n const lastStart = (n - 1) * EAX_BLOCK_SIZE;\n const lastSlice = message.slice(lastStart);\n lastBlock.set(lastSlice);\n\n let Mn: Uint8Array;\n if (lastBlockComplete) {\n Mn = xorBlock(lastBlock, K1);\n } else {\n if (lastSlice.length < EAX_BLOCK_SIZE) lastBlock[lastSlice.length] = 0x80;\n Mn = xorBlock(lastBlock, K2);\n }\n\n return Uint8Array.from(aesEcb(key, xorBlock(X, Mn)));\n}\n","import { createHash, createECDH, randomBytes } from \"node:crypto\";\nimport { CryptoInitError, FakeSignatureMismatchError } from \"../errors.js\";\nimport type { Identity } from \"./identity.js\";\nimport { identityPrivateKey, importPublicKey } from \"./identity.js\";\nimport { EAX } from \"./eax.js\";\n\nconst FAKE_SIGNATURE_SIZE = 8;\nconst IV_ALPHA_SIZE = 10;\nconst INIT1_PACKET_TYPE = 8;\nconst PACKET_TYPE_MASK = 0x0f;\n\nconst INIT1_MAC = Buffer.from(\"TS3INIT1\");\n\n/**\n * The most squarings the Init1 puzzle may ask for. TS3 3.13 and TS6 6.0 both\n * ask for 10000; a level far beyond that is a server trying to pin the event\n * loop, since the squarings run synchronously.\n */\nexport const MAX_RSA_CHALLENGE_LEVEL: number = 100_000;\n\nexport interface KeyNonce {\n key: Uint8Array;\n nonce: Uint8Array;\n gen: number;\n}\n\n/** Precomputed dummy key/nonce matching the TS3 client pre-crypto placeholder. */\nconst DUMMY_KEY = Buffer.from(\"c:\\\\windows\\\\syste\");\nconst DUMMY_NONCE = Buffer.from(\"m\\\\firewall32.cpl\");\n\n/**\n * A connection's encryption state. The session material — the IV the keys\n * derive from — lives in private fields, so it shows in no `util.inspect()`\n * or `JSON.stringify()` of anything holding a Crypt.\n */\nexport class Crypt {\n readonly identity: Identity;\n\n #ivStruct: Uint8Array = new Uint8Array(0);\n #fakeSignature: Uint8Array = new Uint8Array(FAKE_SIGNATURE_SIZE);\n #alpha: Uint8Array = new Uint8Array(0);\n #cryptoInitComplete = false;\n\n readonly #cachedKeys = new Map<bigint, KeyNonce>();\n\n constructor(identity: Identity) {\n this.identity = identity;\n }\n\n /** Whether the session keys are set up; until then packets use the dummy key. */\n get cryptoInitComplete(): boolean {\n return this.#cryptoInitComplete;\n }\n\n /** The signature unencrypted packets carry: zeros until crypto init completes. */\n get fakeSignature(): Uint8Array {\n return this.#fakeSignature;\n }\n\n /** The client's random contribution to the IV, sent in clientinitiv; empty before. */\n get alpha(): Uint8Array {\n return this.#alpha;\n }\n\n /** Choose the client's random contribution to the IV, and return it. */\n newAlpha(): Uint8Array {\n this.#alpha = new Uint8Array(randomBytes(IV_ALPHA_SIZE));\n return this.#alpha;\n }\n\n solveRsaChallenge(data: Uint8Array, offset: number, level: number): Uint8Array {\n if (!Number.isInteger(level) || level < 0 || level > MAX_RSA_CHALLENGE_LEVEL) {\n throw new CryptoInitError(`RSA challenge level ${level} out of range`);\n }\n\n const xBytes = data.slice(offset, offset + 64);\n const nBytes = data.slice(offset + 64, offset + 128);\n\n let y = bytesToBigInt(xBytes);\n const n = bytesToBigInt(nBytes);\n if (n === 0n) throw new CryptoInitError(\"RSA challenge modulus is zero\");\n\n for (let i = 0; i < level; i++) {\n y = (y * y) % n;\n }\n\n return bigIntToBytes(y, 64);\n }\n\n initCrypto(alpha: string, beta: string, omega: string): void {\n const alphaBytes = Buffer.from(alpha, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n\n let sharedSecret: Uint8Array;\n try {\n sharedSecret = this.#getSharedSecret(importPublicKey(omegaBytes));\n } catch (error) {\n throw new CryptoInitError(\"the server's public key is invalid\", { cause: error });\n }\n\n this.setSharedSecret(alphaBytes, betaBytes, sharedSecret);\n }\n\n setSharedSecret(alpha: Uint8Array, beta: Uint8Array, sharedKey: Uint8Array): void {\n this.#ivStruct = new Uint8Array(IV_ALPHA_SIZE + beta.length);\n for (let i = 0; i < IV_ALPHA_SIZE; i++) {\n const a = sharedKey[i];\n const b = alpha[i];\n this.#ivStruct[i] = ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n for (let i = 0; i < beta.length; i++) {\n const a = sharedKey[IV_ALPHA_SIZE + i];\n const b = beta[i];\n this.#ivStruct[IV_ALPHA_SIZE + i] =\n ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n\n // Keys derive from the IV: any cached before it changed belong to another\n // IV, the empty one before crypto init in particular, which is public.\n this.#cachedKeys.clear();\n\n const digest = createHash(\"sha1\").update(this.#ivStruct).digest();\n this.#fakeSignature = new Uint8Array(digest.buffer, digest.byteOffset, FAKE_SIGNATURE_SIZE);\n this.#cryptoInitComplete = true;\n }\n\n getKeyNonce(\n fromServer: boolean,\n packetID: number,\n generationID: number,\n packetType: number,\n dummy: boolean,\n ): [key: Uint8Array, nonce: Uint8Array] {\n if (dummy) {\n return [Uint8Array.from(DUMMY_KEY), Uint8Array.from(DUMMY_NONCE)];\n }\n // Before crypto init there is no IV, and a key derived from the empty one\n // is a key anyone can compute.\n if (!this.#cryptoInitComplete) {\n throw new CryptoInitError(\"no session key before crypto init completes\");\n }\n\n const cacheKey = makeCacheKey(fromServer, packetType, generationID);\n let kn = this.#cachedKeys.get(cacheKey);\n\n if (kn === undefined) {\n const tmpToHash = new Uint8Array(6 + this.#ivStruct.length);\n tmpToHash[0] = fromServer ? 0x30 : 0x31;\n tmpToHash[1] = packetType & PACKET_TYPE_MASK;\n new DataView(tmpToHash.buffer).setUint32(2, generationID, false);\n tmpToHash.set(this.#ivStruct, 6);\n\n const hash = createHash(\"sha256\").update(tmpToHash).digest();\n kn = {\n key: Uint8Array.from(hash.slice(0, 16)),\n nonce: Uint8Array.from(hash.slice(16, 32)),\n gen: generationID,\n };\n this.#cachedKeys.set(cacheKey, kn);\n }\n\n const key = Uint8Array.from(kn.key);\n key[0] = (key[0] !== undefined ? key[0] : 0) ^ ((packetID >> 8) & 0xff);\n key[1] = (key[1] !== undefined ? key[1] : 0) ^ (packetID & 0xff);\n\n return [key, kn.nonce];\n }\n\n encrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n plaintext: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): [ciphertext: Uint8Array, mac: Uint8Array] {\n if (packetType === INIT1_PACKET_TYPE) {\n return [plaintext, INIT1_MAC];\n }\n if (unencrypted) {\n return [plaintext, this.#fakeSignature];\n }\n\n const [key, nonce] = this.getKeyNonce(false, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.encrypt(nonce, header, plaintext);\n }\n\n decrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): Uint8Array {\n if (packetType === INIT1_PACKET_TYPE) {\n return ciphertext;\n }\n if (unencrypted) {\n const fsSub = tag.slice(0, FAKE_SIGNATURE_SIZE);\n if (!Buffer.from(fsSub).equals(Buffer.from(this.#fakeSignature))) {\n throw new FakeSignatureMismatchError();\n }\n return ciphertext;\n }\n\n const [key, nonce] = this.getKeyNonce(true, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.decrypt(nonce, header, ciphertext, tag);\n }\n\n #getSharedSecret(serverPubKey: import(\"node:crypto\").KeyObject): Uint8Array {\n const privJwk = identityPrivateKey(this.identity).export({ format: \"jwk\" }) as {\n d: string;\n };\n const pubJwk = serverPubKey.export({ format: \"jwk\" }) as {\n x: string;\n y: string;\n };\n\n const ecdh = createECDH(\"prime256v1\");\n const dBytes = Buffer.from(privJwk.d, \"base64url\");\n ecdh.setPrivateKey(dBytes);\n\n const xBytes = base64UrlToBytes(pubJwk.x, 32);\n const yBytes = base64UrlToBytes(pubJwk.y, 32);\n const uncompressed = Buffer.alloc(65);\n uncompressed[0] = 0x04;\n xBytes.copy(uncompressed, 1);\n yBytes.copy(uncompressed, 33);\n\n const rawSecret = ecdh.computeSecret(uncompressed);\n return createHash(\"sha1\").update(rawSecret).digest();\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction makeCacheKey(fromServer: boolean, packetType: number, generationID: number): bigint {\n let key = 0n;\n if (fromServer) key |= 1n << 40n;\n key |= BigInt(packetType & PACKET_TYPE_MASK) << 32n;\n key |= BigInt(generationID);\n return key;\n}\n\nfunction bytesToBigInt(bytes: Uint8Array): bigint {\n let result = 0n;\n for (const b of bytes) result = (result << 8n) | BigInt(b);\n return result;\n}\n\nfunction bigIntToBytes(value: bigint, size: number): Uint8Array {\n const result = new Uint8Array(size);\n let v = value;\n for (let i = size - 1; i >= 0; i--) {\n result[i] = Number(v & 0xffn);\n v >>= 8n;\n }\n return result;\n}\n\nfunction base64UrlToBytes(b64url: string, size: number): Buffer {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n","import { createSign, createVerify, createHash, randomBytes, type KeyObject } from \"node:crypto\";\nimport { ed25519 } from \"@noble/curves/ed25519.js\";\n\nconst CURVE25519_KEY_SIZE = 32;\nconst CLAMP_MASK_LOW = 248;\nconst CLAMP_MASK_HIGH = 127;\nconst CLAMP_HIGH_BIT = 64;\nconst SHARED_SIGN_BIT = 0x80;\nconst PRIVATE_KEY_TOP_MASK = 0x7f;\n\n/** Clamp a Curve25519 scalar in-place (required before scalar multiplication). */\nexport function clampScalar(key: Uint8Array): void {\n if (key.length < CURVE25519_KEY_SIZE) return;\n key[0] = (key[0] ?? 0) & CLAMP_MASK_LOW;\n key[CURVE25519_KEY_SIZE - 1] =\n ((key[CURVE25519_KEY_SIZE - 1] ?? 0) & CLAMP_MASK_HIGH) | CLAMP_HIGH_BIT;\n}\n\n/**\n * Generate an ephemeral Ed25519 key pair for the TS3 handshake.\n * Returns [publicKey (32 bytes, RFC-8032 encoded), privateKey (32 bytes)].\n */\nexport function generateTemporaryKey(): [Uint8Array, Uint8Array] {\n const privateKey = new Uint8Array(randomBytes(CURVE25519_KEY_SIZE));\n clampScalar(privateKey);\n\n // Base point G is in the prime-order subgroup, so G*s = G*(s mod n).\n // Safe to reduce here since G has no small-order component.\n const scalar = bytesToBigIntLE(privateKey) % ed25519.Point.CURVE().n;\n const publicKey = ed25519.Point.BASE.multiply(scalar).toBytes();\n\n return [publicKey, Uint8Array.from(privateKey)];\n}\n\n/**\n * Sign data with a P-256 private key (SHA-256 hash, ASN.1 DER encoded).\n */\nexport function sign(privateKey: KeyObject, data: Uint8Array): Uint8Array {\n const signer = createSign(\"SHA256\");\n signer.update(data);\n return signer.sign(privateKey);\n}\n\n/**\n * Verify a P-256 ECDSA signature (SHA-256 hash, ASN.1 DER encoded).\n */\nexport function verifySign(publicKey: KeyObject, data: Uint8Array, sig: Uint8Array): boolean {\n try {\n const verifier = createVerify(\"SHA256\");\n verifier.update(data);\n return verifier.verify(publicKey, Buffer.from(sig));\n } catch {\n return false;\n }\n}\n\n/**\n * TS3-specific shared secret derivation using Ed25519 point arithmetic.\n * Mirrors NaCl's ge_scalarmult_vartime:\n * 1. Negate the public point\n * 2. Scalar-multiply by clamped private key bytes (NOT reduced mod n)\n * 3. Flip sign bit of result\n * 4. SHA-512 the resulting point bytes\n *\n * The scalar must NOT be reduced mod n: Ed25519 has cofactor 8, so the server's\n * public key may have a small-order component, and P*s ≠ P*(s mod n) in that case.\n * We use scalarMultFull to handle scalars >= n without losing the cofactor term.\n */\nexport function getSharedSecret2(\n publicKeyBytes: Uint8Array,\n privateKeyBytes: Uint8Array,\n): Uint8Array {\n if (\n publicKeyBytes.length !== CURVE25519_KEY_SIZE ||\n privateKeyBytes.length !== CURVE25519_KEY_SIZE\n ) {\n throw new Error(\"invalid key length\");\n }\n\n const privCopy = Uint8Array.from(privateKeyBytes);\n privCopy[CURVE25519_KEY_SIZE - 1] =\n (privCopy[CURVE25519_KEY_SIZE - 1] ?? 0) & PRIVATE_KEY_TOP_MASK;\n\n // Use raw scalar WITHOUT reducing mod n — matches NaCl's ge_scalarmult_vartime.\n // Ed25519 has cofactor 8, so P*s ≠ P*(s mod n) when P has a small-order component.\n // Since @noble/curves rejects scalars >= n, we decompose: P*s = P*(s%n) + (P*n)*q\n const rawScalar = bytesToBigIntLE(privCopy);\n\n const pub = ed25519.Point.fromBytes(publicKeyBytes);\n const negPub = pub.negate();\n\n const sharedPoint = scalarMultFull(negPub, rawScalar);\n const sharedBytes = sharedPoint.toBytes();\n\n // Flip sign bit (mirrors Go: shared[31] ^= 0x80)\n sharedBytes[CURVE25519_KEY_SIZE - 1] =\n (sharedBytes[CURVE25519_KEY_SIZE - 1] ?? 0) ^ SHARED_SIGN_BIT;\n\n return createHash(\"sha512\").update(sharedBytes).digest();\n}\n\n// ---- Internal ---------------------------------------------------------------\n\n/**\n * Multiply an Ed25519 point by a scalar that may be >= curve order n.\n * Decomposes as: P*s = P*(s mod n) + (P*n)*q where q = floor(s/n).\n * This preserves the small-order component (cofactor 8) that would be\n * lost by reducing mod n first.\n *\n * For a clamped 255-bit scalar, q is at most 7 (since maxScalar / n < 8),\n * so the second term is computed with at most one extra scalar multiplication.\n */\nexport function scalarMultFull(\n point: InstanceType<typeof ed25519.Point>,\n scalar: bigint,\n): InstanceType<typeof ed25519.Point> {\n const n = ed25519.Point.CURVE().n;\n if (scalar < n) {\n return scalar === 0n ? ed25519.Point.ZERO : point.multiply(scalar);\n }\n const remainder = scalar % n;\n const quotient = scalar / n; // integer division, 1 <= quotient <= 7 for clamped scalars\n\n // P * (s mod n)\n const mainPart = remainder === 0n ? ed25519.Point.ZERO : point.multiply(remainder);\n\n // (P * n) * q — compute P*n via P*(n-1)+P since multiply() rejects scalar == n\n const pointTimesN = point.multiply(n - 1n).add(point);\n const cofactorPart = pointTimesN.multiply(quotient);\n\n return mainPart.add(cofactorPart);\n}\n\n/** Interpret a little-endian byte array as an unsigned BigInt. */\nexport function bytesToBigIntLE(bytes: Uint8Array): bigint {\n let result = 0n;\n for (let i = bytes.length - 1; i >= 0; i--) {\n result = (result << 8n) | BigInt(bytes[i]!);\n }\n return result;\n}\n","import { isIP } from \"node:net\";\nimport { InvalidAddressError } from \"./errors.js\";\n\nexport interface HostPort {\n host: string;\n port: string;\n}\n\n/** Parse a TeamSpeak address without confusing an IPv6 colon for a port separator. */\nexport function splitHostPort(address: string, defaultPort = \"9987\"): HostPort {\n const input = address.trim();\n if (input.startsWith(\"[\")) {\n const closingBracket = input.indexOf(\"]\");\n if (closingBracket > 0) {\n const host = input.slice(1, closingBracket);\n const suffix = input.slice(closingBracket + 1);\n if (suffix.startsWith(\":\") && /^\\d+$/.test(suffix.slice(1))) {\n return { host, port: suffix.slice(1) };\n }\n if (!suffix) return { host, port: defaultPort };\n }\n }\n\n // A raw IPv6 literal has no unambiguous port separator. Internal callers\n // normally use bracket notation, but accepting the literal with the default\n // port prevents a final IPv6 segment from being mistaken for a port.\n if (isIP(input) === 6) return { host: input, port: defaultPort };\n\n const lastColon = input.lastIndexOf(\":\");\n if (lastColon < 0) return { host: input, port: defaultPort };\n const candidatePort = input.slice(lastColon + 1);\n if (/^\\d+$/.test(candidatePort) && input.indexOf(\":\") === lastColon) {\n return { host: input.slice(0, lastColon), port: candidatePort };\n }\n return { host: input, port: defaultPort };\n}\n\n/** Characters no host name or IP address contains, whitespace among them. */\nconst NOT_IN_A_HOST = /[\\s\\p{Cc}/?#@[\\]\\\\]/u;\n\n/**\n * Parse an address to connect to, and check it can be one: a host, which\n * contains nothing a host name or IP address cannot, and a port from 1 to\n * 65535. Throws an InvalidAddressError otherwise.\n */\nexport function parseConnectAddress(address: string): HostPort & { portNumber: number } {\n const { host, port } = splitHostPort(address);\n if (host === \"\") throw new InvalidAddressError(address, \"no host\");\n // A colon is left only in an IPv6 literal; anywhere else it is a port that\n // is not a number, which splitHostPort keeps as part of the host.\n if (NOT_IN_A_HOST.test(host) || (host.includes(\":\") && isIP(host) !== 6)) {\n throw new InvalidAddressError(address, \"not a host name, IP address or host:port\");\n }\n const portNumber = Number(port);\n if (!Number.isInteger(portNumber) || portNumber < 1 || portNumber > 65535) {\n throw new InvalidAddressError(address, `port ${port} is not from 1 to 65535`);\n }\n return { host, port, portNumber };\n}\n\nexport function joinHostPort(host: string, port: string): string {\n const normalizedHost = stripBrackets(host);\n return isIP(normalizedHost) === 6 || normalizedHost.includes(\":\")\n ? `[${normalizedHost}]:${port}`\n : `${normalizedHost}:${port}`;\n}\n\nexport function isIpAddress(host: string): boolean {\n return isIP(stripBrackets(host)) !== 0;\n}\n\nfunction stripBrackets(host: string): string {\n return host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n}\n","import { resolveSrv } from \"node:dns/promises\";\nimport { createConnection } from \"node:net\";\nimport type { ResolvedAddr } from \"../types.js\";\nimport { isIpAddress, joinHostPort, splitHostPort } from \"../address.js\";\nimport { abortable } from \"../abort.js\";\n\nconst TS_DNS_DEFAULT_PORT = 41144;\nconst NICKNAME_LOOKUP_URL = \"https://named.myteamspeak.com/lookup\";\nconst CACHE_TTL_MS = 10 * 60 * 1000;\n/**\n * How long resolution may take in all; past it, the address is used as given.\n * A Client holds any resolver, its own or a custom one, to the same budget.\n *\n * @internal\n */\nexport const RESOLVE_BUDGET_MS = 10_000;\n/** How long one TSDNS server may take to answer. */\nconst TSDNS_TIMEOUT_MS = 3_000;\n\n/**\n * The most a TSDNS server or the nickname service is read for. Either answers\n * with one short line; without a bound, one that kept sending would be held in\n * memory until the resolution budget ran out.\n */\nexport const MAX_DISCOVERY_RESPONSE: number = 8 * 1024;\n\n/** How the default resolver resolves. */\nexport interface ResolverOptions {\n /** Look dot-less names up at named.myteamspeak.com; off by default. */\n readonly resolveNicknames?: boolean | undefined;\n}\n\nexport class Resolver {\n readonly #cache = new Map<string, ResolvedAddr[]>();\n readonly #resolveNicknames: boolean;\n\n constructor(options: ResolverOptions = {}) {\n this.#resolveNicknames = options.resolveNicknames ?? false;\n }\n\n /**\n * Resolve as the TeamSpeak application does: a server nickname (only with\n * `resolveNicknames`), then SRV, then TSDNS, then the address as given. The\n * whole resolution is bounded: past the budget, or when a step fails, the\n * address as given is the answer.\n */\n async resolve(\n inputAddr: string,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): Promise<ResolvedAddr[]> {\n if (!inputAddr) throw new Error(\"empty address\");\n const budget = AbortSignal.timeout(RESOLVE_BUDGET_MS);\n const signal = options.signal ? AbortSignal.any([options.signal, budget]) : budget;\n try {\n return await this.#resolve(inputAddr, signal, true);\n } catch (error) {\n options.signal?.throwIfAborted();\n if (!budget.aborted) throw error;\n const { host, port } = splitHostPort(inputAddr);\n return [{ addr: joinHostPort(host, port), source: \"Direct\" }];\n }\n }\n\n async #resolve(\n inputAddr: string,\n signal: AbortSignal,\n nicknames: boolean,\n ): Promise<ResolvedAddr[]> {\n const cached = this.#getValidCache(inputAddr);\n if (cached) return cached;\n\n const { host, port } = splitHostPort(inputAddr);\n\n if (isIpAddress(host)) {\n return [{ addr: joinHostPort(host, port), source: \"Direct\" }];\n }\n\n // A dot-less name may be a server nickname, which only the TeamSpeak\n // service can answer: asking it sends the name to a third party, so it is\n // opt-in. Otherwise the name is resolved like any host.\n if (nicknames && this.#resolveNicknames && !host.includes(\".\") && host !== \"localhost\") {\n const nickAddr = await resolveNickname(host, signal);\n signal.throwIfAborted();\n if (nickAddr) return this.#resolve(nickAddr, signal, false);\n }\n\n // SRV _ts3._udp.<host>\n const srvResults = await this.#resolveSRV(host, signal);\n if (srvResults) return this.#setCache(inputAddr, srvResults);\n\n const domainList = getDomainList(host);\n\n // TSDNS via SRV _tsdns._tcp.<domain>\n const tsdnsSrv = await this.#resolveTSDNSSRV(domainList, host, signal);\n if (tsdnsSrv) {\n return this.#setCache(inputAddr, [{ addr: tsdnsSrv, source: \"TSDNS-SRV\" }]);\n }\n\n // TSDNS direct :41144\n const tsdnsDirect = await this.#resolveTSDNSDirect(domainList, host, signal);\n if (tsdnsDirect) {\n return this.#setCache(inputAddr, [{ addr: tsdnsDirect, source: \"TSDNS-Direct\" }]);\n }\n\n signal.throwIfAborted();\n // Plain DNS fallback\n const fallback: ResolvedAddr[] = [{ addr: joinHostPort(host, port), source: \"Direct\" }];\n return this.#setCache(inputAddr, fallback);\n }\n\n #getValidCache(inputAddr: string): ResolvedAddr[] | null {\n const cached = this.#cache.get(inputAddr);\n if (!cached || cached.length === 0) return null;\n const first = cached[0]!;\n if (first.expiry !== undefined && Date.now() > first.expiry.getTime()) return null;\n return cached;\n }\n\n #setCache(key: string, results: ResolvedAddr[]): ResolvedAddr[] {\n const expiry = new Date(Date.now() + CACHE_TTL_MS);\n const withExpiry = results.map((r) => ({ ...r, expiry }));\n this.#cache.set(key, withExpiry);\n return withExpiry;\n }\n\n async #resolveSRV(host: string, signal?: AbortSignal): Promise<ResolvedAddr[] | null> {\n try {\n const srvs = await abortable(resolveSrv(`_ts3._udp.${host}`), signal);\n if (!srvs || srvs.length === 0) return null;\n return srvs.map((srv) => ({\n addr: joinHostPort(srv.name.replace(/\\.$/, \"\"), String(srv.port)),\n source: \"SRV\",\n }));\n } catch {\n return null;\n }\n }\n\n async #resolveTSDNSSRV(\n domains: string[],\n queryHost: string,\n signal?: AbortSignal,\n ): Promise<string | null> {\n for (const domain of domains) {\n try {\n const srvs = await abortable(resolveSrv(`_tsdns._tcp.${domain}`), signal);\n if (!srvs || srvs.length === 0) continue;\n for (const srv of srvs) {\n const tsdnsAddr = joinHostPort(srv.name.replace(/\\.$/, \"\"), String(srv.port));\n const result = await queryTSDNS(tsdnsAddr, queryHost, signal);\n if (result) return result;\n }\n } catch {\n continue;\n }\n }\n return null;\n }\n\n async #resolveTSDNSDirect(\n domains: string[],\n queryHost: string,\n signal?: AbortSignal,\n ): Promise<string | null> {\n // Asked at once rather than in turn, so the probes cost one timeout in\n // all; the most specific domain's answer wins.\n const answers = await Promise.all(\n domains.map((domain) =>\n queryTSDNS(joinHostPort(domain, String(TS_DNS_DEFAULT_PORT)), queryHost, signal),\n ),\n );\n return answers.find((answer) => answer !== null) ?? null;\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\n/** @internal Ask the nickname service for `nickname`'s address. */\nexport async function resolveNickname(\n nickname: string,\n signal?: AbortSignal,\n): Promise<string | null> {\n try {\n const url = new URL(NICKNAME_LOOKUP_URL);\n url.searchParams.set(\"name\", nickname);\n const init: RequestInit = signal ? { signal } : {};\n const resp = await fetch(url.toString(), init);\n if (!resp.ok) return null;\n const text = await readLimited(resp, MAX_DISCOVERY_RESPONSE);\n const line = text.split(\"\\n\")[0]?.trim();\n return line || null;\n } catch {\n return null;\n }\n}\n\n/** A response body's first `limit` bytes, as text; the rest is not read. */\nasync function readLimited(resp: Response, limit: number): Promise<string> {\n if (resp.body === null) return \"\";\n const reader = resp.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n try {\n while (size < limit) {\n const { done, value } = await reader.read();\n if (done) break;\n const part = value.subarray(0, limit - size);\n chunks.push(part);\n size += part.length;\n }\n } finally {\n reader.cancel().catch(() => {});\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\n/** @internal Ask the TSDNS server at `tsdnsAddr` for `queryHost`'s address. */\nexport function queryTSDNS(\n tsdnsAddr: string,\n queryHost: string,\n signal?: AbortSignal,\n): Promise<string | null> {\n const [host, portStr] = splitHostPortParts(tsdnsAddr);\n const port = parseInt(portStr, 10);\n\n return new Promise((resolve) => {\n if (signal?.aborted) return resolve(null);\n const finish = (answer: string | null): void => {\n clearTimeout(timeout);\n signal?.removeEventListener(\"abort\", onAbort);\n socket.destroy();\n resolve(answer);\n };\n const onAbort = (): void => finish(null);\n const timeout = setTimeout(() => finish(null), TSDNS_TIMEOUT_MS);\n\n const socket = createConnection({ host, port, timeout: 2_000 }, () => {\n socket.write(`${queryHost}\\n`);\n });\n\n let buf = \"\";\n socket.on(\"data\", (chunk: Buffer) => {\n buf += chunk.toString(\"latin1\");\n const idx = buf.indexOf(\"\\n\");\n if (idx >= 0 && idx < MAX_DISCOVERY_RESPONSE) {\n const line = Buffer.from(buf.slice(0, idx), \"latin1\").toString(\"utf8\").trim();\n finish(!line || line === \"404\" || line === \"errors\" ? null : line);\n } else if (buf.length >= MAX_DISCOVERY_RESPONSE) {\n // No answer is that long.\n finish(null);\n }\n });\n\n socket.on(\"error\", () => finish(null));\n socket.on(\"timeout\", () => finish(null));\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction splitHostPortParts(addr: string): [string, string] {\n const { host, port } = splitHostPort(addr);\n return [host, port];\n}\n\nfunction getDomainList(host: string): string[] {\n const parts = host.split(\".\");\n const list: string[] = [];\n for (let i = 0; i < parts.length - 1; i++) {\n list.push(parts.slice(i).join(\".\"));\n }\n return list.slice(0, 3);\n}\n","export const enum PacketType {\n Voice = 0,\n VoiceWhisper = 1,\n Command = 2,\n CommandLow = 3,\n Ping = 4,\n Pong = 5,\n Ack = 6,\n AckLow = 7,\n Init1 = 8,\n}\n\nexport const enum PacketFlags {\n Fragmented = 0x10,\n NewProtocol = 0x20,\n Compressed = 0x40,\n Unencrypted = 0x80,\n}\n\nexport interface Packet {\n /** Type byte combined with flags (low nibble = type, high nibble = flags). */\n typeFlagged: number;\n id: number;\n clientID: number;\n generationID: number;\n data: Uint8Array;\n receivedAt: number; // Date.now()\n}\n\nexport function packetType(p: Packet): PacketType {\n return (p.typeFlagged & 0x0f) as PacketType;\n}\n\nexport function packetFlags(p: Packet): number {\n return p.typeFlagged & 0xf0;\n}\n\nexport function isUnencrypted(p: Packet): boolean {\n return (packetFlags(p) & PacketFlags.Unencrypted) !== 0;\n}\n\n/** Build the 5-byte client-to-server header: [packetID(2), clientID(2), typeFlagged(1)]. */\nexport function buildC2SHeader(p: Packet): Uint8Array {\n const header = new Uint8Array(5);\n const view = new DataView(header.buffer);\n view.setUint16(0, p.id, false);\n view.setUint16(2, p.clientID, false);\n header[4] = p.typeFlagged;\n return header;\n}\n\n/** Parse a 3-byte server-to-client header. */\nexport function parseS2CHeader(raw: Uint8Array): Pick<Packet, \"id\" | \"typeFlagged\"> {\n const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);\n return {\n id: view.getUint16(0, false),\n typeFlagged: raw[2]!,\n };\n}\n\n/** Parse a 5-byte client-to-server header. */\nexport function parseC2SHeader(raw: Uint8Array): Pick<Packet, \"id\" | \"clientID\" | \"typeFlagged\"> {\n const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);\n return {\n id: view.getUint16(0, false),\n clientID: view.getUint16(2, false),\n typeFlagged: raw[4]!,\n };\n}\n","export class GenerationWindow {\n #mappedBaseOffset = 0;\n #generation = 0;\n readonly #mod: number;\n readonly #receiveWindow: number;\n\n constructor(mod: number, windowSize: number) {\n this.#mod = mod;\n this.#receiveWindow = windowSize;\n }\n\n get generation(): number {\n return this.#generation;\n }\n\n advance(amount: number): void {\n if (amount <= 0) return;\n const newBaseOffset = this.#mappedBaseOffset + amount;\n const genStep = Math.floor(newBaseOffset / this.#mod);\n if (genStep > 0) {\n this.#generation = Math.min(this.#generation + genStep, 0xffff_ffff);\n }\n this.#mappedBaseOffset = newBaseOffset % this.#mod;\n }\n\n advanceToExcluded(mappedValue: number): void {\n let moveDist = mappedValue - this.#mappedBaseOffset;\n if (moveDist < 0) moveDist += this.#mod;\n this.advance(moveDist + 1);\n }\n\n syncTo(mappedValue: number): void {\n let moveDist = mappedValue - this.#mappedBaseOffset;\n if (moveDist < 0) moveDist += this.#mod;\n this.advance(moveDist);\n }\n\n isInWindow(mappedValue: number): boolean {\n const maxOffset = this.#mappedBaseOffset + this.#receiveWindow;\n if (maxOffset < this.#mod) {\n return mappedValue >= this.#mappedBaseOffset && mappedValue < maxOffset;\n }\n return mappedValue >= this.#mappedBaseOffset || mappedValue < maxOffset - this.#mod;\n }\n\n /**\n * The offset from the window base: negative means stale, `receiveWindow` or\n * more too far ahead. An id up to `receiveWindow` behind the base across the\n * last wrap, which reads as a high number, is stale too.\n */\n mappedToIndex(mappedValue: number): number {\n if (this.#isNextGen(mappedValue)) {\n return mappedValue + this.#mod - this.#mappedBaseOffset;\n }\n const index = mappedValue - this.#mappedBaseOffset;\n return this.#isBehindAcrossWrap(index) ? index - this.#mod : index;\n }\n\n /**\n * Whether an id `index` past the base is really up to `receiveWindow` behind\n * it, in the generation before: the base has wrapped since, so the id reads as\n * nearly a whole generation ahead. Before the first wrap no id lies behind the\n * base across it.\n */\n #isBehindAcrossWrap(index: number): boolean {\n return (\n this.#generation > 0 &&\n index >= this.#receiveWindow &&\n index >= this.#mod - this.#receiveWindow\n );\n }\n\n /**\n * Whether the id is before the receive window: a packet whose acknowledgement\n * was lost is sent again after the window has moved past it, also when the\n * move wrapped the 16-bit id.\n */\n isOldPacket(mappedValue: number): boolean {\n return this.mappedToIndex(mappedValue) < 0;\n }\n\n isFuturePacket(mappedValue: number): boolean {\n return this.mappedToIndex(mappedValue) >= this.#receiveWindow;\n }\n\n #isNextGen(mappedValue: number): boolean {\n return (\n this.#mappedBaseOffset > this.#mod - this.#receiveWindow &&\n mappedValue < this.#mappedBaseOffset + this.#receiveWindow - this.#mod\n );\n }\n\n /**\n * The generation the id belongs to: one past the current generation if the id\n * has already wrapped, one before it if the id is just behind the base across\n * the last wrap.\n */\n getGeneration(mappedValue: number): number {\n if (this.#isNextGen(mappedValue)) return this.#generation + 1;\n if (this.#isBehindAcrossWrap(mappedValue - this.#mappedBaseOffset)) return this.#generation - 1;\n return this.#generation;\n }\n\n reset(): void {\n this.#mappedBaseOffset = 0;\n this.#generation = 0;\n }\n}\n","const TABLE_SIZE = 4096;\n\n/**\n * The largest decompressed command accepted. A command is reassembled from at\n * most a receive window of fragments, and the largest real answers (a full\n * permission list, the welcome channel list of a big server) are a few\n * hundred kilobytes; a header declaring more is refused before anything is\n * allocated.\n */\nexport const MAX_DECOMPRESSED_SIZE: number = 1 << 20;\n\n/**\n * How much larger than its compressed bytes a level-1 block can be. The most\n * a 3-byte back-reference yields is 255 bytes, and every 32 entries also cost\n * a 4-byte control word, which bounds the ratio at about 82; a block declaring\n * more cannot be honest, and is refused before its output is allocated.\n */\nconst MAX_EXPANSION = 128;\n\ninterface QlzState {\n control: number;\n sourcePos: number;\n destPos: number;\n nextHashed: number;\n}\n\n/** A QuickLZ block that cannot be decompressed: truncated, oversized or inconsistent. */\nexport class QuickLZError extends Error {\n constructor(message: string) {\n super(`QuickLZ: ${message}`);\n this.name = \"QuickLZError\";\n }\n}\n\n/**\n * QuickLZ level 1 decompression, as the server compresses large commands.\n *\n * The input comes from the network, so every read and every back-reference is\n * checked, and malformed input throws a QuickLZError rather than reading out\n * of range or producing a partly filled buffer.\n */\nexport class Qlz {\n #hashtable = new Int32Array(TABLE_SIZE);\n\n decompress(data: Uint8Array): Uint8Array {\n const { headerLen, decompressedSize, flags } = parseQlzHeader(data);\n\n if ((flags & 0x01) === 0) {\n if (headerLen + decompressedSize > data.length) {\n throw new QuickLZError(\"stored block is shorter than its declared size\");\n }\n return data.slice(headerLen, headerLen + decompressedSize);\n }\n\n if (decompressedSize > (data.length - headerLen) * MAX_EXPANSION) {\n throw new QuickLZError(\n `declared size ${decompressedSize} is more than ${data.length - headerLen} bytes can expand to`,\n );\n }\n const dest = new Uint8Array(decompressedSize);\n this.#hashtable.fill(0);\n\n const state: QlzState = {\n control: 1,\n sourcePos: headerLen,\n destPos: 0,\n nextHashed: 0,\n };\n\n while (state.destPos < decompressedSize) {\n this.#ensureControl(data, state);\n if ((state.control & 1) !== 0) {\n this.#processReference(data, dest, state);\n } else if (this.#processLiteral(data, dest, decompressedSize, state)) {\n break;\n }\n }\n\n if (state.destPos !== decompressedSize) throw new QuickLZError(\"block ends early\");\n return dest;\n }\n\n #ensureControl(data: Uint8Array, st: QlzState): void {\n if (st.control !== 1) return;\n if (st.sourcePos + 4 > data.length) throw new QuickLZError(\"block ends early\");\n st.control =\n (data[st.sourcePos]! |\n (data[st.sourcePos + 1]! << 8) |\n (data[st.sourcePos + 2]! << 16) |\n (data[st.sourcePos + 3]! << 24)) >>>\n 0;\n st.sourcePos += 4;\n }\n\n #processReference(data: Uint8Array, dest: Uint8Array, st: QlzState): void {\n st.control = (st.control >>> 1) >>> 0;\n if (st.sourcePos + 2 > data.length) throw new QuickLZError(\"block ends early\");\n\n const b1 = data[st.sourcePos]!;\n const b2 = data[st.sourcePos + 1]!;\n st.sourcePos += 2;\n\n const hash = (b1 >> 4) | (b2 << 4);\n let matchlen = b1 & 0x0f;\n if (matchlen !== 0) {\n matchlen += 2;\n } else {\n if (st.sourcePos >= data.length) throw new QuickLZError(\"block ends early\");\n matchlen = data[st.sourcePos]!;\n st.sourcePos++;\n }\n\n const offset = this.#hashtable[hash]!;\n // The copy may overlap its own output, so only its start must precede it.\n if (offset >= st.destPos) throw new QuickLZError(\"back-reference points ahead of the output\");\n if (st.destPos + matchlen > dest.length) {\n throw new QuickLZError(\"back-reference overruns the declared size\");\n }\n for (let i = 0; i < matchlen; i++) {\n dest[st.destPos] = dest[offset + i]!;\n st.destPos++;\n }\n\n const end = st.destPos + 1 - matchlen;\n this.#updateHashtable(dest, st, end);\n st.nextHashed = st.destPos;\n }\n\n /** Copy literals; returns true once the tail of the block has been copied. */\n #processLiteral(\n data: Uint8Array,\n dest: Uint8Array,\n decompressedSize: number,\n st: QlzState,\n ): boolean {\n const threshold = Math.max(decompressedSize, 10) - 10;\n if (st.destPos >= threshold) {\n while (st.destPos < decompressedSize) {\n if (st.control === 1) {\n if (st.sourcePos + 4 > data.length) throw new QuickLZError(\"block ends early\");\n st.control =\n (data[st.sourcePos]! |\n (data[st.sourcePos + 1]! << 8) |\n (data[st.sourcePos + 2]! << 16) |\n (data[st.sourcePos + 3]! << 24)) >>>\n 0;\n st.sourcePos += 4;\n }\n if (st.sourcePos >= data.length) throw new QuickLZError(\"block ends early\");\n dest[st.destPos++] = data[st.sourcePos++]!;\n st.control = (st.control >>> 1) >>> 0;\n }\n return true;\n }\n\n if (st.sourcePos >= data.length) throw new QuickLZError(\"block ends early\");\n\n dest[st.destPos++] = data[st.sourcePos++]!;\n st.control = (st.control >>> 1) >>> 0;\n\n const end = Math.max(st.destPos - 2, 0);\n this.#updateHashtable(dest, st, end);\n if (st.nextHashed < end) st.nextHashed = end;\n\n return false;\n }\n\n #updateHashtable(dest: Uint8Array, st: QlzState, end: number): void {\n while (st.nextHashed < end) {\n if (st.nextHashed + 3 > dest.length) break;\n const v =\n (dest[st.nextHashed]! |\n (dest[st.nextHashed + 1]! << 8) |\n (dest[st.nextHashed + 2]! << 16)) >>>\n 0;\n const hash = ((v >> 12) ^ v) & 0xfff;\n this.#hashtable[hash] = st.nextHashed;\n st.nextHashed++;\n }\n }\n}\n\nfunction parseQlzHeader(data: Uint8Array): {\n headerLen: number;\n decompressedSize: number;\n flags: number;\n} {\n if (data.length < 3) throw new QuickLZError(\"data too short\");\n\n const flags = data[0]!;\n const level = (flags >> 2) & 0x03;\n if (level !== 1) throw new QuickLZError(\"only level 1 is supported\");\n\n const long = (flags & 0x02) !== 0;\n const headerLen = long ? 9 : 3;\n if (data.length < headerLen) throw new QuickLZError(\"data too short for header\");\n\n // The header also carries the compressed size, which the reads below make\n // redundant: each one is checked against the data itself.\n const decompressedSize = long\n ? (data[5]! | (data[6]! << 8) | (data[7]! << 16) | (data[8]! << 24)) >>> 0\n : data[2]!;\n\n if (decompressedSize > MAX_DECOMPRESSED_SIZE) {\n throw new QuickLZError(`declared size ${decompressedSize} exceeds ${MAX_DECOMPRESSED_SIZE}`);\n }\n\n return { headerLen, decompressedSize, flags };\n}\n","import { randomBytes } from \"node:crypto\";\nimport { buildCommandOrdered } from \"@honeybbq/teamspeak-core/internal\";\nimport type { Crypt } from \"../crypto/crypt.js\";\nimport { CryptoInitError } from \"../errors.js\";\n\nexport const INIT_VERSION = 1566914096; // 3.5.0 [Stable]\n\nconst INIT_VERSION_LEN = 4;\nconst INIT_TYPE_LEN = 1;\nconst INIT_STEP_LEN = 21;\n\n/** The RSA challenge each connection attempt, by its Crypt, has answered. */\nconst answeredChallenges = new WeakMap<\n Crypt,\n { readonly challenge: Uint8Array; readonly answer: Uint8Array }\n>();\n\n/**\n * Handle the TS3INIT1 handshake steps.\n * Returns the response bytes to send, or null if nothing should be sent.\n * Throws a CryptoInitError for a step that cannot be answered.\n */\nexport function processInit1(crypt: Crypt, data: Uint8Array | null): Uint8Array | null {\n if (data === null || (data.length >= 1 && data[0] === 0x7f)) {\n return buildInit1StartPacket();\n }\n if (data.length === 0) throw new CryptoInitError(\"empty Init1 packet\");\n\n switch (data[0]) {\n case 0:\n return buildInit1Step1Packet(data);\n case 1:\n return buildInit1Step2Packet(data);\n case 2:\n return buildInit1Step3Packet(data);\n case 3:\n return buildInit1Step4Packet(crypt, data);\n default:\n return null;\n }\n}\n\nfunction buildInit1StartPacket(): Uint8Array {\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 4 + 4 + 8);\n const view = new DataView(sendData.buffer);\n\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x00;\n\n const nowSec = Math.floor(Date.now() / 1000);\n const clampedNow = Math.max(0, Math.min(nowSec, 0xffff_ffff));\n view.setUint32(5, clampedNow, false);\n\n const rng = randomBytes(4);\n sendData.set(rng, 9);\n\n return sendData;\n}\n\nfunction buildInit1Step1Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 16 + 4);\n sendData[0] = 0x01;\n\n // TS rand: little-endian uint32 at offset [INIT_VERSION_LEN + INIT_TYPE_LEN + 4]\n const tsRandOffset = INIT_VERSION_LEN + INIT_TYPE_LEN + 4;\n const tsRand =\n data[tsRandOffset]! |\n (data[tsRandOffset + 1]! << 8) |\n (data[tsRandOffset + 2]! << 16) |\n (data[tsRandOffset + 3]! << 24);\n\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 16, tsRand >>> 0, false);\n return sendData;\n}\n\nfunction buildInit1Step2Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4);\n new DataView(sendData.buffer).setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x02;\n sendData.set(data.slice(1, 21), 5);\n return sendData;\n}\n\nfunction buildInit1Step3Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 64 + 64 + 4 + 100);\n sendData[0] = 0x03;\n sendData[INIT_TYPE_LEN + 64 - 1] = 1;\n sendData[INIT_TYPE_LEN + 64 + 64 - 1] = 1;\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 64 + 64, 1, false);\n return sendData;\n}\n\nfunction buildInit1Step4Packet(crypt: Crypt, data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_TYPE_LEN + 64 + 64 + 4 + 100) return null;\n // One challenge per connection attempt, whose Crypt is its own. Each answer\n // costs up to a second of synchronous squarings, and a second would choose a\n // new alpha behind the clientinitiv already sent. The same challenge again\n // means the server did not get our answer, so it gets the same answer,\n // without solving anything; a different one gets none.\n const answered = answeredChallenges.get(crypt);\n if (answered !== undefined) {\n return Buffer.from(answered.challenge).equals(Buffer.from(data)) ? answered.answer : null;\n }\n\n const level = new DataView(data.buffer, data.byteOffset).getUint32(1 + 128, false);\n const y = crypt.solveRsaChallenge(data, 1, level);\n\n const alphaB64 = Buffer.from(crypt.newAlpha()).toString(\"base64\");\n const omegaB64 = crypt.identity.publicKey();\n\n const cmd = buildCommandOrdered(\"clientinitiv\", [\n [\"alpha\", alphaB64],\n [\"omega\", omegaB64],\n [\"ot\", \"1\"],\n [\"ip\", \"\"],\n ]);\n const cmdBytes = Buffer.from(cmd);\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 232 + 64 + cmdBytes.length);\n const view = new DataView(sendData.buffer);\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x04;\n sendData.set(data.slice(1, 233), 5);\n sendData.set(y.slice(0, 64), 5 + 232);\n sendData.set(cmdBytes, 5 + 232 + 64);\n\n answeredChallenges.set(crypt, { challenge: Uint8Array.from(data), answer: sendData });\n return sendData;\n}\n","import { createSocket } from \"node:dgram\";\nimport { lookup } from \"node:dns/promises\";\nimport { parseConnectAddress } from \"../address.js\";\nimport type { Crypt } from \"../crypto/crypt.js\";\nimport type { DatagramSocket, SocketFactory } from \"../types.js\";\nimport type { Logger } from \"@honeybbq/teamspeak-core\";\nimport { noopLogger } from \"@honeybbq/teamspeak-core\";\nimport {\n type Packet,\n PacketType,\n PacketFlags,\n packetType,\n packetFlags,\n buildC2SHeader,\n parseS2CHeader,\n} from \"./packet.js\";\nimport { ConnectionTimeoutError } from \"../errors.js\";\nimport { abortable, abortReason } from \"../abort.js\";\nimport { NotConnectedError, TeamspeakError } from \"@honeybbq/teamspeak-core\";\nimport { GenerationWindow } from \"./generation-window.js\";\nimport { Qlz } from \"./quicklz.js\";\nimport { processInit1 } from \"../handshake/crypt-handshake.js\";\n\nconst MAX_OUT_PACKET_SIZE = 500;\nconst RECEIVE_PACKET_WINDOW_SIZE = 1024;\nconst PING_INTERVAL_MS = 5_000;\nconst PACKET_TIMEOUT_MS = 60_000;\nconst MAX_RETRY_INTERVAL_MS = 1_000;\nconst HEADER_SIZE = 5;\nconst TAG_SIZE = 8;\nconst VOICE_HEADER_SIZE = 3;\nconst WHISPER_HEADER_SIZE = 5;\nconst RESEND_BASE_INTERVAL_MS = 500;\nconst RESEND_LOOP_INTERVAL_MS = 100;\n\n/**\n * The largest command reassembled from fragments. The receive window already\n * bounds how many fragments one command can span; this bounds their total\n * size, which a datagram's own size limit would otherwise let reach tens of\n * megabytes.\n */\nconst MAX_REASSEMBLED_SIZE = 1 << 20;\n\n/**\n * The largest datagram taken. TeamSpeak's packets are at most 500 bytes; a\n * larger one is no packet of the protocol's, and is dropped before anything\n * is decrypted or held.\n */\nexport const MAX_DATAGRAM_SIZE: number = 4096;\n\n/**\n * The most command bytes held, across both receive queues, waiting for the\n * packets before them. A server's in-order traffic drains at once and a full\n * window of real packets is under a megabyte; past this, a packet is dropped\n * unacknowledged, so the server sends it again once there is room.\n */\nexport const MAX_QUEUED_BYTES: number = 1 << 20;\n\n/**\n * The packet types the server may send unencrypted: voice, which TeamSpeak\n * never encrypts, ping and pong, and acknowledgements — TS3 3.13 and TS6 6.0\n * both acknowledge commands with plaintext Acks once crypto init has\n * completed. An Ack carries nothing but the id it acknowledges, so a forged\n * one can at worst stop a resend, which dropping the packet would do too.\n * Init1 is handled before decryption.\n */\nconst UNENCRYPTED_TYPES: ReadonlySet<number> = new Set<number>([\n PacketType.Voice,\n PacketType.VoiceWhisper,\n PacketType.Ping,\n PacketType.Pong,\n PacketType.Ack,\n PacketType.AckLow,\n PacketType.Init1,\n]);\n\ninterface ResendPacket {\n packet: Packet;\n firstSend: number;\n lastSend: number;\n retryCount: number;\n nextInterval: number;\n}\n\nexport class PacketHandler {\n onPacket: ((p: Packet) => void) | null = null;\n onClosed: ((err: Error | null) => void) | null = null;\n /**\n * A received datagram could not be handled: it was malformed, or handling it\n * threw. The datagram is dropped either way; the owner decides whether that\n * ends the connection. Without an owner the error is logged.\n */\n onReceiveError: ((error: unknown) => void) | null = null;\n\n readonly #crypt: Crypt;\n readonly #logger: Logger;\n readonly #socketFactory: SocketFactory | undefined;\n\n #conn: DatagramSocket | null = null;\n #clientID = 0;\n #closed = false;\n #stopPing: (() => void) | null = null;\n #stopResend: (() => void) | null = null;\n #lastMessageReceived = Date.now();\n\n #packetCounter = new Uint16Array(9);\n #generationCounter = new Uint32Array(9);\n\n #recvWindowCommand = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #recvWindowCommandLow = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #sendWindowCommand = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #sendWindowCommandLow = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n\n #commandQueue = new Map<number, Packet>();\n #commandLowQueue = new Map<number, Packet>();\n /** The bytes held in both command queues; see MAX_QUEUED_BYTES. */\n #queuedBytes = 0;\n #ackManager = new Map<number, ResendPacket>();\n /**\n * The last Init1 packet the client sent, resent until the handshake's final\n * acknowledgement. Init1 packets are not acknowledged one by one: each step\n * the client sends replaces it, and only `receivedFinalInitAck` clears it.\n * Receiving an Init1 does not, as the client may have nothing to answer with.\n */\n #initPacketCheck: ResendPacket | null = null;\n /**\n * Command packets sent under the dummy key, before crypto init completed:\n * clientek, in practice. Both TS3 and TS6 acknowledge clientek under the\n * dummy key even though it completes crypto init, so the dummy key stays\n * acceptable for exactly those acknowledgements, and for nothing else.\n */\n #dummyCommandIDs = new Set<number>();\n #resends = 0;\n\n constructor(crypt: Crypt, logger: Logger = noopLogger, socketFactory?: SocketFactory) {\n this.#crypt = crypt;\n this.#logger = logger;\n this.#socketFactory = socketFactory;\n }\n\n setClientID(id: number): void {\n this.#clientID = id;\n }\n\n /**\n * Resolve `addr`, open a socket to it and start the handshake.\n *\n * Aborting `signal`, or closing the handler, while this runs abandons it: the\n * lookup's answer is ignored, and a socket that finishes connecting\n * afterwards is closed rather than started, so no handshake begins after\n * the connection was given up.\n */\n async connect(addr: string, signal?: AbortSignal): Promise<void> {\n const { host, portNumber } = parseConnectAddress(addr);\n this.#throwIfAbandoned(signal);\n\n // Resolve before choosing a socket family. `isIP()` only recognises literal\n // addresses and returns 0 for every hostname, so picking the family from it\n // sent every hostname to a udp4 socket — and a udp4 socket handed a name\n // that resolves to IPv6 drops the datagrams with no error at all. On a\n // stock macOS/Linux box `localhost` resolves to ::1 first, so that path\n // silently never connected. Let DNS decide, then match the family.\n let resolved: { address: string; family: number };\n try {\n resolved = await abortable(lookup(host), signal);\n } catch (error) {\n if (signal?.aborted) throw error;\n // Wrapped, not classed as an invalid address: a lookup can fail for a\n // while (EAI_AGAIN) and then succeed, which a reconnect should retry.\n throw new TeamspeakError(`could not resolve ${host}`, { cause: error });\n }\n const { address, family } = resolved;\n this.#throwIfAbandoned(signal);\n\n const family6 = family === 6;\n const socket: DatagramSocket = this.#socketFactory\n ? this.#socketFactory(family6 ? 6 : 4)\n : createSocket(family6 ? \"udp6\" : \"udp4\");\n\n await new Promise<void>((resolve, reject) => {\n let done = false;\n const fail = (error: unknown): void => {\n if (done) return;\n done = true;\n socket.off(\"error\", onError);\n signal?.removeEventListener(\"abort\", onAbort);\n closeQuietly(socket);\n reject(error);\n };\n const onError = (error: Error): void => fail(error);\n const onAbort = (): void => fail(abortReason(signal!));\n socket.once(\"error\", onError);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n // Connect to the resolved address, not the original host, so the socket\n // cannot end up talking to a different family than it was created for.\n socket.connect(portNumber, address, () => {\n if (done) return;\n if (this.#closed || signal?.aborted) {\n fail(signal?.aborted ? abortReason(signal) : new NotConnectedError());\n return;\n }\n done = true;\n socket.off(\"error\", onError);\n signal?.removeEventListener(\"abort\", onAbort);\n this.start(socket);\n resolve();\n });\n });\n }\n\n #throwIfAbandoned(signal: AbortSignal | undefined): void {\n signal?.throwIfAborted();\n if (this.#closed) throw new NotConnectedError();\n }\n\n /** Take over a connected socket and start the handshake on it. A closed handler closes it instead. */\n start(conn: DatagramSocket): void {\n if (this.#closed) {\n closeQuietly(conn);\n return;\n }\n this.#conn = conn;\n this.#lastMessageReceived = Date.now();\n\n conn.on(\"message\", (msg) => {\n if (this.#closed) return;\n // Everything here parses what the network sent. Nothing it throws may\n // escape: from a socket callback it would be an uncaught exception, and\n // a malformed datagram from the server would take the process down.\n try {\n this.#handleRawPacket(new Uint8Array(msg.buffer, msg.byteOffset, msg.byteLength));\n } catch (error: unknown) {\n if (this.onReceiveError) this.onReceiveError(error);\n else this.#logger.debug(\"dropped a malformed packet\", { error: String(error) });\n }\n });\n conn.on(\"error\", (err) => {\n this.#logger.error(\"udp error\", err);\n this.#triggerClose(err);\n });\n conn.on(\"close\", () => this.#triggerClose(null));\n\n this.#packetCounter[PacketType.Command] = 1;\n this.#packetCounter[PacketType.Init1] = 101;\n\n const init1Data = processInit1(this.#crypt, null);\n if (init1Data) this.#sendPacketRaw(PacketType.Init1, init1Data, 0);\n\n // Ping loop\n const pingTimer = setInterval(() => {\n if (this.#crypt.cryptoInitComplete) {\n this.sendPacket(PacketType.Ping, new Uint8Array(0), PacketFlags.Unencrypted);\n }\n }, PING_INTERVAL_MS);\n this.#stopPing = () => clearInterval(pingTimer);\n\n // Resend loop\n const resendTimer = setInterval(() => this.#checkResends(), RESEND_LOOP_INTERVAL_MS);\n this.#stopResend = () => clearInterval(resendTimer);\n }\n\n /**\n * Stop resending the last Init1 packet the client sent. Until this is called,\n * the latest step stays pending whatever the server sends in between: a step\n * the client does not answer, an unknown one or a second RSA challenge, must\n * not stop the resending of its own. The server's `initivexpand2` command\n * acknowledges the last step, not an Init1 reply.\n */\n receivedFinalInitAck(): void {\n this.#initPacketCheck = null;\n }\n\n sendPacket(pType: PacketType, data: Uint8Array, flags: number): void {\n const dummy = !this.#crypt.cryptoInitComplete;\n if (data.length > 487 && pType !== PacketType.Voice && pType !== PacketType.VoiceWhisper) {\n this.#sendSplitPacket(pType, data, flags, dummy);\n return;\n }\n this.#sendPacketRaw(pType, data, flags, dummy);\n }\n\n sendVoicePacket(data: Uint8Array, codec: number): void {\n const pID = this.#packetCounter[PacketType.Voice]!;\n const pGen = this.#generationCounter[PacketType.Voice]!;\n this.#packetCounter[PacketType.Voice] = (pID + 1) & 0xffff;\n if (this.#packetCounter[PacketType.Voice] === 0) {\n this.#generationCounter[PacketType.Voice]!++;\n }\n\n const payloadLen = VOICE_HEADER_SIZE + data.length;\n const voicePayload = new Uint8Array(payloadLen);\n new DataView(voicePayload.buffer).setUint16(0, pID, false);\n voicePayload[2] = codec;\n voicePayload.set(data, VOICE_HEADER_SIZE);\n\n const p: Packet = {\n typeFlagged: PacketType.Voice | PacketFlags.Unencrypted,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data: voicePayload,\n receivedAt: 0,\n };\n\n const header = buildC2SHeader(p);\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + payloadLen);\n final.set(this.#crypt.fakeSignature, 0);\n final.set(header, TAG_SIZE);\n final.set(voicePayload, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n /** Send an unencrypted TeamSpeak voice whisper packet to up to 32 clients. */\n sendWhisperPacket(data: Uint8Array, targetClientIds: number[], codec: number): void {\n if (targetClientIds.length === 0) throw new RangeError(\"a whisper needs at least one target\");\n if (targetClientIds.length > 32) throw new RangeError(\"a whisper has at most 32 targets\");\n if (targetClientIds.some((id) => !Number.isInteger(id) || id < 0 || id > 0xffff)) {\n throw new RangeError(\"invalid whisper target\");\n }\n\n const pID = this.#packetCounter[PacketType.VoiceWhisper]!;\n const pGen = this.#generationCounter[PacketType.VoiceWhisper]!;\n this.#packetCounter[PacketType.VoiceWhisper] = (pID + 1) & 0xffff;\n if (this.#packetCounter[PacketType.VoiceWhisper] === 0) {\n this.#generationCounter[PacketType.VoiceWhisper] = (pGen + 1) >>> 0;\n }\n\n const payloadLen = WHISPER_HEADER_SIZE + targetClientIds.length * 2 + data.length;\n const whisperPayload = new Uint8Array(payloadLen);\n const view = new DataView(whisperPayload.buffer);\n view.setUint16(0, pID, false);\n whisperPayload[2] = codec;\n whisperPayload[3] = 0;\n whisperPayload[4] = targetClientIds.length;\n for (let index = 0; index < targetClientIds.length; index++) {\n view.setUint16(WHISPER_HEADER_SIZE + index * 2, targetClientIds[index]!, false);\n }\n whisperPayload.set(data, WHISPER_HEADER_SIZE + targetClientIds.length * 2);\n\n const packet: Packet = {\n typeFlagged: PacketType.VoiceWhisper | PacketFlags.Unencrypted,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data: whisperPayload,\n receivedAt: 0,\n };\n const header = buildC2SHeader(packet);\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + payloadLen);\n final.set(this.#crypt.fakeSignature, 0);\n final.set(header, TAG_SIZE);\n final.set(whisperPayload, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n /** How many packets have been sent again for want of an acknowledgement. */\n get resends(): number {\n return this.#resends;\n }\n\n /** Whether there is a live socket to send on. */\n get isOpen(): boolean {\n return this.#conn !== null && !this.#closed;\n }\n\n close(): void {\n if (this.#closed) return;\n this.#closed = true;\n this.#stopPing?.();\n this.#stopResend?.();\n\n // The socket may already be closed — this runs from its own \"close\" event\n // when a connection drops — and dgram throws ERR_SOCKET_DGRAM_NOT_RUNNING\n // on a second close. Letting that escape would surface as an uncaught\n // exception inside an event callback, taking the process with it instead of\n // reporting a dropped connection.\n const conn = this.#conn;\n this.#conn = null;\n if (conn === null) return;\n try {\n conn.close();\n } catch (error: unknown) {\n this.#logger.debug(\"socket already closed\", { error: String(error) });\n }\n }\n\n // ---- Private ---------------------------------------------------------------\n\n #sendSplitPacket(pType: PacketType, data: Uint8Array, flags: number, dummy: boolean): void {\n const maxSize = MAX_OUT_PACKET_SIZE - HEADER_SIZE - TAG_SIZE; // 487\n let pos = 0;\n let first = true;\n\n while (pos < data.length) {\n const blockSize = Math.min(data.length - pos, maxSize);\n const last = pos + blockSize === data.length;\n\n let pFlags = flags;\n if (first !== last) pFlags |= PacketFlags.Fragmented;\n\n this.#sendPacketRaw(pType, data.slice(pos, pos + blockSize), pFlags, dummy);\n pos += blockSize;\n first = false;\n }\n }\n\n #sendPacketRaw(\n pType: PacketType,\n data: Uint8Array,\n flags: number,\n dummy = !this.#crypt.cryptoInitComplete,\n ): void {\n flags = applyProtocolFlags(pType, flags);\n const [pID, pGen] = this.#nextPacketIdentity(pType);\n const p: Packet = {\n typeFlagged: pType | flags,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data,\n receivedAt: 0,\n };\n\n const unencrypted = (flags & PacketFlags.Unencrypted) !== 0;\n const header = buildC2SHeader(p);\n const [ciphertext, tag] = this.#crypt.encrypt(\n pType,\n pID,\n pGen,\n header,\n data,\n dummy,\n unencrypted,\n );\n\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + ciphertext.length);\n final.set(tag.slice(0, TAG_SIZE), 0);\n final.set(header, TAG_SIZE);\n final.set(ciphertext, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n if (dummy && pType === PacketType.Command) this.#dummyCommandIDs.add(pID);\n\n const rp: ResendPacket = {\n packet: p,\n firstSend: Date.now(),\n lastSend: Date.now(),\n retryCount: 0,\n nextInterval: RESEND_BASE_INTERVAL_MS,\n };\n this.#trackResend(pType, p, rp);\n }\n\n #write(data: Uint8Array): void {\n if (!this.#conn) return;\n try {\n this.#conn.send(data, (err) => {\n if (err) this.#logger.warn(\"udp send error\", err);\n });\n } catch (error: unknown) {\n const normalized = error instanceof Error ? error : new Error(String(error));\n // dgram can throw synchronously for an invalid family/address pair. A\n // malformed remote target must close this session, never escape from an\n // async socket callback and terminate the gateway process.\n this.#logger.error(\"udp send failed\", normalized);\n this.#triggerClose(normalized);\n }\n }\n\n #handleRawPacket(raw: Uint8Array): void {\n if (raw.length < 11) return;\n if (raw.length > MAX_DATAGRAM_SIZE) {\n this.#logger.debug(\"dropped an oversized datagram\", { size: raw.length });\n return;\n }\n\n const tag = raw.slice(0, TAG_SIZE);\n const header = raw.slice(TAG_SIZE, TAG_SIZE + 3);\n const ciphertext = raw.slice(TAG_SIZE + 3);\n\n const parsed = parseS2CHeader(header);\n // Init1 belongs to the start of the handshake; once crypto init has\n // completed, another one can only restart a session that is already set up.\n if ((parsed.typeFlagged & 0x0f) === PacketType.Init1 && this.#crypt.cryptoInitComplete) return;\n\n const p: Packet = {\n ...parsed,\n clientID: 0,\n generationID: this.#resolveGeneration(parsed.id, parsed.typeFlagged & 0x0f),\n data: new Uint8Array(0),\n receivedAt: Date.now(),\n };\n\n const decrypted = this.#decryptPacketData(p, header, ciphertext, tag);\n if (decrypted === null) return;\n p.data = decrypted.plaintext;\n // Only a packet that decrypted shows the server is there: anyone can send\n // datagrams that do not, and they must not keep a dead session alive.\n this.#lastMessageReceived = Date.now();\n\n const pType = packetType(p);\n\n if (pType === PacketType.Ping) {\n this.#sendPong(p.id, decrypted.dummyUsed);\n return;\n }\n\n if (!this.#handleCommandWindowAndAck(p, decrypted.dummyUsed)) return;\n\n this.#handlePacketQueue(p);\n this.#updatePostReceiveState(p);\n }\n\n #resolveGeneration(id: number, pType: number): number {\n switch (pType as PacketType) {\n case PacketType.Command:\n return this.#recvWindowCommand.getGeneration(id);\n case PacketType.CommandLow:\n return this.#recvWindowCommandLow.getGeneration(id);\n case PacketType.Ack:\n return this.#sendWindowCommand.getGeneration(id);\n case PacketType.AckLow:\n return this.#sendWindowCommandLow.getGeneration(id);\n default:\n return 0;\n }\n }\n\n #decryptPacketData(\n p: Packet,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): { plaintext: Uint8Array; dummyUsed: boolean } | null {\n const unencrypted = (packetFlags(p) & PacketFlags.Unencrypted) !== 0;\n const dummy = !this.#crypt.cryptoInitComplete;\n let dummyUsed = dummy;\n const pType = packetType(p);\n const gen = p.generationID;\n\n // An unencrypted packet is checked against the fake signature only, and\n // that signature is no secret: every plaintext ping, pong and voice packet\n // carries it. A command must therefore never be taken unencrypted, or\n // anyone on the path could forge text messages, kicks and command answers.\n if (unencrypted && !UNENCRYPTED_TYPES.has(pType)) {\n this.#logger.debug(\"dropped an unencrypted packet of a type that must be encrypted\", {\n type: pType,\n id: p.id,\n });\n return null;\n }\n\n try {\n const plaintext = this.#crypt.decrypt(\n pType,\n p.id,\n gen,\n header,\n ciphertext,\n tag,\n dummy,\n unencrypted,\n );\n return { plaintext, dummyUsed };\n } catch {\n // Before crypto init only the dummy key exists: there is no other key\n // to try.\n if (dummy) return null;\n // No other generation is tried: the receive window already places the\n // id in its generation, and a packet that decrypts only under the one\n // before is an old packet replayed after the 16-bit id wrapped. Neither\n // TS3 nor TS6 ever needed a guess at the next one.\n\n // The acknowledgement of a command sent under the dummy key may itself\n // use the dummy key, and is the one packet that may once crypto init has\n // completed (see #dummyCommandIDs). A dummy-keyed command after that is\n // dropped: the dummy key is public.\n if (!dummy && pType === PacketType.Ack && !unencrypted) {\n try {\n const plaintext = this.#crypt.decrypt(\n pType,\n p.id,\n gen,\n header,\n ciphertext,\n tag,\n true,\n false,\n );\n const acked = plaintext.length >= 2 ? (plaintext[0]! << 8) | plaintext[1]! : Number.NaN;\n if (this.#dummyCommandIDs.delete(acked)) return { plaintext, dummyUsed: true };\n } catch {\n // fall through\n }\n }\n\n return null;\n }\n }\n\n #handleCommandWindowAndAck(p: Packet, dummyUsed: boolean): boolean {\n const pType = packetType(p);\n if (pType !== PacketType.Command && pType !== PacketType.CommandLow) return true;\n\n const win = pType === PacketType.Command ? this.#recvWindowCommand : this.#recvWindowCommandLow;\n const ackType = pType === PacketType.Command ? PacketType.Ack : PacketType.AckLow;\n\n if (!win.isInWindow(p.id)) {\n if (win.isOldPacket(p.id)) {\n this.#sendAck(p.id, ackType, dummyUsed);\n }\n return false;\n }\n const queue = pType === PacketType.Command ? this.#commandQueue : this.#commandLowQueue;\n const held = queue.get(p.id)?.data.length ?? 0;\n // The packet the queue waits for is always taken: it is what drains it.\n const next = pType === PacketType.Command ? this.#_nextCommandID : this.#_nextCommandLowID;\n if (p.id !== next && this.#queuedBytes - held + p.data.length > MAX_QUEUED_BYTES) {\n // Not acknowledged: the server sends it again.\n this.#logger.debug(\"dropped a command packet: the receive queues are full\", { id: p.id });\n return false;\n }\n this.#sendAck(p.id, ackType, dummyUsed);\n return true;\n }\n\n #sendAck(packetID: number, ackType: PacketType, dummyUsed: boolean): void {\n const ackData = new Uint8Array(2);\n new DataView(ackData.buffer).setUint16(0, packetID, false);\n this.#sendPacketRaw(ackType, ackData, 0, dummyUsed);\n }\n\n #sendPong(pID: number, dummyUsed: boolean): void {\n const pongData = new Uint8Array(2);\n new DataView(pongData.buffer).setUint16(0, pID, false);\n this.#sendPacketRaw(PacketType.Pong, pongData, PacketFlags.Unencrypted, dummyUsed);\n }\n\n #handlePacketQueue(p: Packet): void {\n const pType = packetType(p);\n if (pType !== PacketType.Command && pType !== PacketType.CommandLow) {\n this.onPacket?.(p);\n return;\n }\n\n const isCommand = pType === PacketType.Command;\n const queue = isCommand ? this.#commandQueue : this.#commandLowQueue;\n const win = isCommand ? this.#recvWindowCommand : this.#recvWindowCommandLow;\n\n this.#hold(queue, p);\n\n if (isCommand) {\n this.#fastForwardMissingPackets(queue, win, true);\n } else {\n this.#fastForwardMissingPackets(queue, win, false);\n }\n\n while (true) {\n const current = isCommand ? this.#_nextCommandID : this.#_nextCommandLowID;\n const packet = queue.get(current);\n if (packet === undefined) break;\n\n const result = this.#tryReassemble(packet, queue, current, win);\n if (!result) break;\n\n const [reassembled, newNext] = result;\n if (isCommand) this.#_nextCommandID = newNext;\n else this.#_nextCommandLowID = newNext;\n\n if (reassembled === null) {\n this.#logger.debug(\"dropped a command over the reassembly limit\", { id: current });\n continue;\n }\n if (!this.#tryDecompress(reassembled)) continue;\n this.onPacket?.(reassembled);\n }\n }\n\n /** Put a packet in its queue, counting its bytes; one with the same id is replaced. */\n #hold(queue: Map<number, Packet>, p: Packet): void {\n this.#release(queue, p.id);\n queue.set(p.id, p);\n this.#queuedBytes += p.data.length;\n }\n\n #release(queue: Map<number, Packet>, id: number): void {\n const held = queue.get(id);\n if (held === undefined) return;\n queue.delete(id);\n this.#queuedBytes -= held.data.length;\n }\n\n #_nextCommandID = 0;\n #_nextCommandLowID = 0;\n\n #fastForwardMissingPackets(\n queue: Map<number, Packet>,\n win: GenerationWindow,\n isCommand: boolean,\n ): void {\n let nextID = isCommand ? this.#_nextCommandID : this.#_nextCommandLowID;\n while (!queue.has(nextID) && hasOldNewerPacket(queue, nextID)) {\n nextID = (nextID + 1) & 0xffff;\n win.advance(1);\n }\n if (isCommand) this.#_nextCommandID = nextID;\n else this.#_nextCommandLowID = nextID;\n }\n\n #tryReassemble(\n startPacket: Packet,\n queue: Map<number, Packet>,\n nextID: number,\n win: GenerationWindow,\n ): [reassembled: Packet | null, newNextID: number] | null {\n if ((packetFlags(startPacket) & PacketFlags.Fragmented) === 0) {\n this.#release(queue, nextID);\n win.advance(1);\n return [startPacket, (nextID + 1) & 0xffff];\n }\n\n const fragments: Packet[] = [];\n let totalSize = 0;\n let currID = nextID;\n let startSeen = false;\n\n // Ends at the fragment that closes the command, or returns while one is\n // still missing.\n while (true) {\n const frag = queue.get(currID);\n if (!frag) return null;\n fragments.push(frag);\n totalSize += frag.data.length;\n if (totalSize > MAX_REASSEMBLED_SIZE) {\n // Dropped whole, so the window moves past it rather than waiting on\n // the rest of a command that will never be accepted.\n for (let i = 0; i < fragments.length; i++) {\n this.#release(queue, nextID);\n win.advance(1);\n nextID = (nextID + 1) & 0xffff;\n }\n return [null, nextID];\n }\n\n const fragmented = (packetFlags(frag) & PacketFlags.Fragmented) !== 0;\n if (!startSeen) {\n startSeen = true;\n if (!fragmented) break;\n } else if (fragmented) {\n break;\n }\n currID = (currID + 1) & 0xffff;\n }\n\n const combined = new Uint8Array(totalSize);\n let pos = 0;\n for (const frag of fragments) {\n combined.set(frag.data, pos);\n pos += frag.data.length;\n this.#release(queue, nextID);\n win.advance(1);\n nextID = (nextID + 1) & 0xffff;\n }\n\n startPacket.data = combined;\n startPacket.typeFlagged &= ~PacketFlags.Fragmented;\n return [startPacket, nextID];\n }\n\n /** Decompress a command in place; false when it cannot be, and is to be dropped. */\n #tryDecompress(packet: Packet): boolean {\n if ((packetFlags(packet) & PacketFlags.Compressed) === 0) return true;\n try {\n const qlz = new Qlz();\n packet.data = qlz.decompress(packet.data);\n packet.typeFlagged &= ~PacketFlags.Compressed;\n return true;\n } catch (err) {\n // Passing the compressed bytes on as if they were the command would\n // hand the parser garbage.\n this.#logger.debug(\"dropped a command that failed to decompress\", {\n id: packet.id,\n error: String(err),\n });\n return false;\n }\n }\n\n #updatePostReceiveState(p: Packet): void {\n const pType = packetType(p);\n\n if ((pType === PacketType.Ack || pType === PacketType.AckLow) && p.data.length >= 2) {\n const ackID = new DataView(p.data.buffer, p.data.byteOffset).getUint16(0, false);\n const targetType = pType === PacketType.Ack ? PacketType.Command : PacketType.CommandLow;\n const key = (targetType << 16) | ackID;\n this.#ackManager.delete(key);\n }\n }\n\n #nextPacketIdentity(pType: PacketType): [id: number, gen: number] {\n const pID = this.#packetCounter[pType]!;\n const pGen = this.#generationCounter[pType]!;\n\n if (pType === PacketType.Init1) return [pID, pGen];\n\n this.#packetCounter[pType] = (pID + 1) & 0xffff;\n if (this.#packetCounter[pType] === 0) {\n this.#generationCounter[pType] = (pGen + 1) >>> 0;\n }\n\n if (pType === PacketType.Command) {\n this.#sendWindowCommand.advanceToExcluded(pID);\n } else if (pType === PacketType.CommandLow) {\n this.#sendWindowCommandLow.advanceToExcluded(pID);\n }\n\n return [pID, pGen];\n }\n\n #trackResend(pType: PacketType, p: Packet, rp: ResendPacket): void {\n if (pType === PacketType.Init1) {\n this.#initPacketCheck = rp;\n return;\n }\n if (pType === PacketType.Command || pType === PacketType.CommandLow) {\n const key = (pType << 16) | p.id;\n this.#ackManager.set(key, rp);\n }\n }\n\n #checkResends(): void {\n const now = Date.now();\n\n if (now - this.#lastMessageReceived > PACKET_TIMEOUT_MS) {\n this.#logger.warn(\"idle timeout\");\n this.#triggerClose(new ConnectionTimeoutError());\n return;\n }\n\n if (this.#initPacketCheck) {\n this.#doResend(this.#initPacketCheck, now);\n }\n\n for (const [key, rp] of this.#ackManager) {\n if (now - rp.firstSend > PACKET_TIMEOUT_MS) {\n this.#ackManager.delete(key);\n this.#triggerClose(new ConnectionTimeoutError());\n return;\n }\n this.#doResend(rp, now);\n }\n }\n\n #doResend(rp: ResendPacket, now: number): void {\n if (now - rp.lastSend < rp.nextInterval) return;\n\n rp.lastSend = now;\n rp.retryCount++;\n this.#resends++;\n rp.nextInterval = Math.min(rp.nextInterval * 2, MAX_RETRY_INTERVAL_MS);\n\n const dummy = !this.#crypt.cryptoInitComplete;\n const unencrypted = (packetFlags(rp.packet) & PacketFlags.Unencrypted) !== 0;\n const header = buildC2SHeader(rp.packet);\n const pType = packetType(rp.packet);\n\n const [ciphertext, tag] = this.#crypt.encrypt(\n pType,\n rp.packet.id,\n rp.packet.generationID,\n header,\n rp.packet.data,\n dummy,\n unencrypted,\n );\n\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + ciphertext.length);\n final.set(tag.slice(0, TAG_SIZE), 0);\n final.set(header, TAG_SIZE);\n final.set(ciphertext, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n #triggerClose(err: Error | null): void {\n if (this.#closed) return;\n this.close();\n this.onClosed?.(err);\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\n/** Close a socket that may already be closed; dgram throws on a second close. */\nfunction closeQuietly(socket: DatagramSocket): void {\n try {\n socket.close();\n } catch {\n // Already closed.\n }\n}\n\nfunction applyProtocolFlags(pType: PacketType, flags: number): number {\n if (pType === PacketType.Command || pType === PacketType.CommandLow) {\n return flags | PacketFlags.NewProtocol;\n }\n return flags;\n}\n\nfunction hasOldNewerPacket(queue: Map<number, Packet>, nextID: number): boolean {\n const now = Date.now();\n for (const [id, pkg] of queue) {\n const diff = (id - nextID + 0x10000) & 0xffff;\n if (diff < 0x8000 && now - pkg.receivedAt > 5_000) {\n return true;\n }\n }\n return false;\n}\n","import { parseCommand } from \"@honeybbq/teamspeak-core/internal\";\nimport { ServerError } from \"@honeybbq/teamspeak-core\";\nimport { parseErrorCode } from \"@honeybbq/teamspeak-core/internal\";\n\nimport type { ResponseSpec } from \"@honeybbq/teamspeak-core/internal\";\n\nexport interface CommandResult {\n err: Error | null;\n data: Record<string, string>[];\n}\n\n/** A row waiting for the `error` that says which command it answered. */\ninterface BufferedRow {\n /** The notification that carried it, or \"\" for a nameless data row. */\n readonly source: string;\n readonly params: Record<string, string>;\n}\n\ninterface PendingCommand {\n readonly resolve: (result: CommandResult) => void;\n readonly spec: ResponseSpec | undefined;\n /** The request's value for `spec.correlated.key`, when there is one. */\n readonly correlation: string | undefined;\n /** Correlated answers that arrived before the command's own `error`. */\n readonly correlated: Record<string, string>[];\n /** The command's `error` result, held while its correlated answer is due. */\n settled?: CommandResult;\n}\n\n/**\n * Matches the server's answers to the commands that asked for them.\n *\n * The server handles one client's commands in order and closes each answer\n * with `error … return_code=N`, so every row seen since the previous `error`\n * belongs to command N. Rows are therefore held, tagged with where they came\n * from, until that `error` says whose they are — attributing them on arrival\n * would mean guessing which in-flight command the server is answering, and a\n * command can be registered here well before it is sent (it first waits on the\n * throttle and the middleware chain).\n *\n * A nameless row always belongs to the command. A notification row belongs to\n * it only if the command declared that notification as its answer (see\n * command/responses.ts): the same `notifyclientmoved` that answers nothing can\n * arrive between any two commands.\n *\n * The welcome sequence is the exception. The server pushes channellist,\n * channelgrouplist and the rest unprompted right after the handshake, before\n * `channellistfinished`; without the gate they would land in the first\n * command's answer as duplicate rows and a phantom cid=0.\n */\nexport class CommandTracker {\n readonly #pending = new Map<number, PendingCommand>();\n readonly #ownClientID: () => number;\n #nextRC = 0;\n #buffer: BufferedRow[] = [];\n #welcomeComplete = false;\n\n /** @param ownClientID the client's clid, for answers filtered by invoker. */\n constructor(ownClientID: () => number = () => 0) {\n this.#ownClientID = ownClientID;\n }\n\n register(\n spec?: ResponseSpec,\n correlation?: string,\n ): [rc: number, promise: Promise<CommandResult>] {\n this.#nextRC++;\n const rc = this.#nextRC;\n const promise = new Promise<CommandResult>((resolve) => {\n this.#pending.set(rc, { resolve, spec, correlation, correlated: [] });\n });\n return [rc, promise];\n }\n\n unregister(rc: number): void {\n this.#pending.delete(rc);\n }\n\n /** Marks the end of the welcome sequence and drops what it left behind. */\n signalWelcomeComplete(): void {\n this.#welcomeComplete = true;\n this.#buffer = [];\n }\n\n /** Whether some in-flight command declared `name` as its answer. */\n expects(name: string): boolean {\n for (const p of this.#pending.values()) {\n if (p.spec?.notifications?.includes(name)) return true;\n if (p.spec?.correlated?.notifications.includes(name)) return true;\n }\n return false;\n }\n\n /** Hold a row until the next `error` says which command it answered. */\n buffer(params: Record<string, string>, source = \"\"): void {\n if (!this.#welcomeComplete) return;\n if (this.#pending.size === 0) return;\n this.#buffer.push({ source, params });\n }\n\n /**\n * Offer a notification to commands answered after their `error`.\n *\n * Matching is on the echoed request field, so it does not matter whether the\n * notification beats the `error` or follows it.\n */\n offerCorrelated(name: string, params: Record<string, string>): void {\n for (const [rc, p] of this.#pending) {\n const c = p.spec?.correlated;\n if (!c || p.correlation === undefined || !c.notifications.includes(name)) continue;\n if (params[c.key] !== p.correlation) continue;\n\n if (name === c.failure && (params[\"status\"] ?? \"0\") !== \"0\") {\n const err = new ServerError(parseErrorCode(params[\"status\"]), params[\"msg\"] ?? \"\", {\n extraMessage: params[\"extra_msg\"] || undefined,\n });\n this.#settle(rc, p, { err, data: [] });\n return;\n }\n p.correlated.push(params);\n if (p.settled) this.#settle(rc, p, { err: null, data: [...p.settled.data, ...p.correlated] });\n return;\n }\n }\n\n resolve(rc: number, err: Error | null): void {\n const rows = this.#buffer;\n this.#buffer = [];\n const p = this.#pending.get(rc);\n if (!p) return;\n\n const data = rows.filter((row) => this.#answers(p, row)).map((row) => row.params);\n if (err) {\n this.#settle(rc, p, { err, data });\n return;\n }\n // Answered after the error: hold the result until the answer arrives, or\n // the caller's timeout gives up on it.\n if (p.spec?.correlated && p.correlation !== undefined && p.correlated.length === 0) {\n p.settled = { err: null, data };\n return;\n }\n this.#settle(rc, p, { err: null, data: [...data, ...p.correlated] });\n }\n\n discardBuffer(): void {\n this.#buffer = [];\n }\n\n /**\n * Forget every command and fail it with `err`.\n *\n * Dropping them silently would leave each caller waiting out its full\n * timeout for an answer that can no longer come.\n */\n reset(err: Error): void {\n const pending = [...this.#pending.values()];\n this.#pending.clear();\n for (const p of pending) p.resolve({ err, data: [] });\n this.#buffer = [];\n this.#welcomeComplete = false;\n this.#nextRC = 0;\n }\n\n #answers(p: PendingCommand, row: BufferedRow): boolean {\n if (row.source === \"\") return true;\n if (!p.spec?.notifications?.includes(row.source)) return false;\n if (!p.spec.ownRowsOnly) return true;\n return row.params[\"invokerid\"] === String(this.#ownClientID());\n }\n\n #settle(rc: number, p: PendingCommand, result: CommandResult): void {\n this.#pending.delete(rc);\n p.resolve(result);\n }\n}\n\n/**\n * Append the tracker's return_code to a command.\n *\n * The return_code belongs to the tracker: it is how an answer finds its\n * command, so a caller-supplied one would detach the command from its answer.\n * Checked as a parameter rather than as text, because a message body that\n * merely contains \"return_code=\" used to suppress the real one and time the\n * command out.\n */\nexport function appendReturnCode(cmd: string, rc: number): string {\n const params = parseCommand(cmd)?.params ?? {};\n if (Object.hasOwn(params, \"return_code\")) {\n throw new TypeError(\"commands must not carry their own return_code; the client assigns it\");\n }\n return `${cmd} return_code=${rc}`;\n}\n","/**\n * File transfer data.\n *\n * Negotiating a transfer is a command (`initFileUpload`, `initFileDownload`);\n * the bytes then go over a separate TCP connection to the server's file\n * transfer port, opened with the key the negotiation returned.\n */\n\nimport { connect } from \"node:net\";\nimport { pipeline } from \"node:stream/promises\";\nimport type { Duplex, Readable, Writable } from \"node:stream\";\nimport type { FileUploadInfo, FileDownloadInfo } from \"@honeybbq/teamspeak-core\";\nimport type { FileTransferSocketFactory } from \"./types.js\";\nimport { FileTransferError } from \"./errors.js\";\n\n/** How long dialing may take before it fails, unless a signal says otherwise. */\nconst DIAL_TIMEOUT_MS = 10_000;\n\n/** Options for a file transfer. */\nexport interface FileTransferOptions {\n /** Abandons the transfer; it then rejects with the signal's reason. */\n readonly signal?: AbortSignal | undefined;\n /**\n * Opens the connection instead of a direct TCP dial, to route the transfer\n * through a proxy or tunnel.\n */\n readonly socketFactory?: FileTransferSocketFactory | undefined;\n}\n\n/**\n * Open a connection to the file transfer port and send the transfer key.\n * The caller owns the returned stream and must end or destroy it.\n */\nexport async function dialFileTransfer(\n host: string,\n port: number,\n key: string,\n options: FileTransferOptions = {},\n): Promise<Duplex> {\n const { signal, socketFactory } = options;\n signal?.throwIfAborted();\n const socket: Duplex = socketFactory ? socketFactory(host, port) : connect({ host, port });\n\n // Until the caller takes the stream over, its errors are this function's to\n // report: a stream's unhandled `error` event takes the process down.\n const swallow = (): void => {};\n socket.on(\"error\", swallow);\n try {\n await connected(socket, signal);\n await new Promise<void>((resolve, reject) => {\n socket.write(key, (err) =>\n err\n ? reject(\n new FileTransferError(`failed to send transfer key: ${err.message}`, { cause: err }),\n )\n : resolve(),\n );\n });\n } catch (error) {\n socket.destroy();\n throw error;\n } finally {\n socket.off(\"error\", swallow);\n }\n return socket;\n}\n\n/**\n * Wait for a stream to be connected. A `node:net` socket says so with\n * `connect`; a stream from elsewhere that is already writable is taken as\n * connected.\n */\nfunction connected(socket: Duplex, signal: AbortSignal | undefined): Promise<void> {\n const pending = (socket as { pending?: boolean }).pending;\n if (pending === false || (pending === undefined && socket.writable)) return Promise.resolve();\n\n return new Promise<void>((resolve, reject) => {\n const timeout = AbortSignal.timeout(DIAL_TIMEOUT_MS);\n const done = (error?: unknown): void => {\n socket.off(\"connect\", onConnect);\n socket.off(\"ready\", onConnect);\n socket.off(\"error\", onError);\n signal?.removeEventListener(\"abort\", onAbort);\n timeout.removeEventListener(\"abort\", onTimeout);\n if (error === undefined) resolve();\n else reject(error);\n };\n const onConnect = (): void => done();\n const onError = (error: Error): void =>\n done(\n new FileTransferError(`file transfer connection failed: ${error.message}`, {\n cause: error,\n }),\n );\n const onAbort = (): void => done(signal!.reason);\n const onTimeout = (): void => done(new FileTransferError(\"file transfer connection timed out\"));\n socket.once(\"connect\", onConnect);\n socket.once(\"ready\", onConnect);\n socket.once(\"error\", onError);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n timeout.addEventListener(\"abort\", onTimeout, { once: true });\n });\n}\n\n/** Upload `data` over a negotiated transfer. Resolves once every byte is sent. */\nexport async function uploadFileData(\n host: string,\n info: FileUploadInfo,\n data: Readable,\n options: FileTransferOptions = {},\n): Promise<void> {\n const socket = await dialFileTransfer(host, info.port, info.fileTransferKey, options);\n await pipeline(data, socket, options.signal ? { signal: options.signal } : {});\n}\n\n/** Download a negotiated transfer into `dest`. Resolves once the file is written. */\nexport async function downloadFileData(\n host: string,\n info: FileDownloadInfo,\n dest: Writable,\n options: FileTransferOptions = {},\n): Promise<void> {\n const socket = await dialFileTransfer(host, info.port, info.fileTransferKey, options);\n await pipeline(socket, dest, options.signal ? { signal: options.signal } : {});\n}\n\nexport { FileTransferError };\n","import type { EventMiddleware, ServerEvent } from \"./types.js\";\nimport type { CommandExecutor, CommandMiddleware } from \"@honeybbq/teamspeak-core\";\n\n/**\n * Compose a chain of middlewares around a base handler.\n * Rightmost middleware wraps the base first.\n */\nexport function buildCommandChain(\n middlewares: readonly CommandMiddleware[],\n base: CommandExecutor[\"send\"],\n): CommandExecutor[\"send\"] {\n let handler = base;\n for (let i = middlewares.length - 1; i >= 0; i--) {\n handler = middlewares[i]!(handler);\n }\n return handler;\n}\n\nexport function buildEventChain(\n middlewares: EventMiddleware[],\n base: (event: ServerEvent) => void,\n): (event: ServerEvent) => void {\n let handler = base;\n for (let i = middlewares.length - 1; i >= 0; i--) {\n handler = middlewares[i]!(handler);\n }\n return handler;\n}\n","/**\n * What the connected server is, and what that means for the caller.\n *\n * TS3 and TS6 differ in ways that stay invisible until something breaks. The\n * clearest: the server hashes a client's public key with SHA-1 on TS3 and\n * SHA-256 on TS6, so a client that assumes either one computes a\n * `client_unique_identifier` the other server never sends.\n *\n * Everything below comes from the handshake — `initserver` carries\n * `virtualserver_version`, the one place the server names itself, along with\n * its name, icon, banner and welcome message — so reading it costs no extra\n * round trip.\n */\n\nimport type { IconID } from \"@honeybbq/teamspeak-core\";\nimport { parseIconID } from \"@honeybbq/teamspeak-core/internal\";\nimport { uidAlgorithmForVersion, type UIDAlgorithm } from \"./crypto/identity.js\";\n\n/**\n * The server generation a version string belongs to. May gain members in a\n * minor release, as server generations appear: a `switch` over it needs a\n * default case.\n */\nexport type ServerFamily = \"ts3\" | \"ts6\" | \"unknown\";\n\n/** What a server said about itself in the handshake. */\nexport interface ServerCapabilities {\n /** The `virtualserver_version` string, exactly as the server sent it. */\n readonly version: string;\n /** Major version number, or 0 when it could not be parsed. */\n readonly major: number;\n /** Which server generation this is. */\n readonly family: ServerFamily;\n /**\n * The hash the server uses for `client_unique_identifier`.\n *\n * Read from the family rather than offered as a setting: the server decides\n * this, and a client that picks differently never matches.\n */\n readonly uidAlgorithm: UIDAlgorithm;\n /** The virtual server's name (`virtualserver_name`). */\n readonly name: string;\n /**\n * The server's icon (`virtualserver_icon_id`), or `undefined` for none. The\n * server sends the icon's CRC32, sometimes as a negative 32-bit number; this\n * is the unsigned value, which names the icon file.\n */\n readonly iconID: IconID | undefined;\n /** The host banner image's URL (`virtualserver_hostbanner_gfx_url`), if one is set. */\n readonly hostBannerImageURL: string | undefined;\n /** The welcome message shown on connecting (`virtualserver_welcomemessage`). */\n readonly welcomeMessage: string;\n}\n\n/**\n * Read what a server says about itself in `initserver`, or a version string\n * alone, such as \"6.0.0-beta13.1 [Build: 1]\".\n */\nexport function parseServerCapabilities(\n initserver: string | Readonly<Record<string, string>>,\n): ServerCapabilities {\n const params =\n typeof initserver === \"string\" ? { virtualserver_version: initserver } : initserver;\n const version = params[\"virtualserver_version\"] ?? \"\";\n const parsed = Number.parseInt(version, 10);\n const major = Number.isNaN(parsed) ? 0 : parsed;\n\n let family: ServerFamily = \"unknown\";\n if (major === 3) family = \"ts3\";\n else if (major >= 6) family = \"ts6\";\n\n return {\n version,\n major,\n family,\n uidAlgorithm: uidAlgorithmForVersion(version),\n name: params[\"virtualserver_name\"] ?? \"\",\n iconID: parseIconID(params[\"virtualserver_icon_id\"]),\n hostBannerImageURL: params[\"virtualserver_hostbanner_gfx_url\"]?.trim() || undefined,\n welcomeMessage: params[\"virtualserver_welcomemessage\"] ?? \"\",\n };\n}\n\n/**\n * Capabilities of a server that has not been connected to yet.\n *\n * The family is `unknown` — nothing has said which server this is — and\n * `uidAlgorithm` is SHA-1, the TS3 hash.\n */\nexport function unknownServerCapabilities(): ServerCapabilities {\n return parseServerCapabilities(\"\");\n}\n","import { hash512 } from \"../crypto/identity.js\";\nimport { clampScalar, scalarMultFull, bytesToBigIntLE } from \"../crypto/primitives.js\";\nimport { ed25519 } from \"@noble/curves/ed25519.js\";\n\n// The root key is a 33-byte Ed25519 point\nconst LICENSE_ROOT_KEY = new Uint8Array([\n 0xcd, 0x0d, 0xe2, 0xae, 0xd4, 0x63, 0x45, 0x50, 0x9a, 0x7e, 0x3c, 0xfd, 0x8f, 0x68, 0xb3, 0xdc,\n 0x75, 0x55, 0xb2, 0x9d, 0xcc, 0xec, 0x73, 0xcd, 0x18, 0x75, 0x0f, 0x99, 0x38, 0x12, 0x40, 0x8a,\n]);\n\nconst enum LicenseBlockType {\n Intermediate = 0,\n Server = 2,\n Ts5Server = 8,\n Ephemeral = 32,\n}\n\ninterface LicenseBlock {\n readonly key: Uint8Array; // 32-byte Ed25519 point\n readonly hash: Uint8Array; // SHA-512 truncated to 32 bytes\n properties: Uint8Array[];\n issuer: string;\n notValidBefore: Date;\n notValidAfter: Date;\n blockType: LicenseBlockType;\n serverType: number;\n}\n\nexport class LicenseChain {\n readonly blocks: LicenseBlock[];\n\n constructor(blocks: LicenseBlock[]) {\n this.blocks = blocks;\n }\n\n /**\n * Derive the session key by chaining Ed25519 point arithmetic starting from\n * the root key through each license block.\n */\n deriveKey(): Uint8Array<ArrayBuffer> {\n let round: Uint8Array<ArrayBuffer> = Uint8Array.from(LICENSE_ROOT_KEY);\n for (const block of this.blocks) {\n round = deriveKeyFromBlock(block, round);\n }\n return round;\n }\n}\n\n/**\n * The most blocks a license chain may have. Real chains have two or three —\n * root-issued intermediate, server, ephemeral — and every block costs a\n * point multiplication to derive, so a server's chain of thousands would hold\n * the event loop for seconds.\n */\nexport const MAX_LICENSE_BLOCKS = 8;\n\nexport function parseLicenses(data: Uint8Array): LicenseChain {\n if (data.length < 1) throw new Error(\"license too short\");\n if (data[0] !== 1) throw new Error(\"unsupported license version\");\n\n let remaining = data.slice(1);\n const blocks: LicenseBlock[] = [];\n\n while (remaining.length > 0) {\n if (blocks.length === MAX_LICENSE_BLOCKS) {\n throw new Error(`license chain longer than ${MAX_LICENSE_BLOCKS} blocks`);\n }\n const { block, consumed } = parseLicenseBlock(remaining);\n blocks.push(block);\n remaining = remaining.slice(consumed);\n }\n\n return new LicenseChain(blocks);\n}\n\nfunction parseLicenseBlock(data: Uint8Array): { block: LicenseBlock; consumed: number } {\n const MIN_BLOCK_LEN = 42;\n if (data.length < MIN_BLOCK_LEN) throw new Error(\"license too short\");\n if (data[0] !== 0) throw new Error(`wrong key kind in license: ${data[0]}`);\n\n const blockType = data[33] as LicenseBlockType;\n\n // Timestamps are seconds since Unix epoch offset by 0x50e22700\n const UNIX_OFFSET = 0x50e22700;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const notValidBefore = new Date((view.getUint32(34, false) + UNIX_OFFSET) * 1000);\n const notValidAfter = new Date((view.getUint32(38, false) + UNIX_OFFSET) * 1000);\n\n if (notValidAfter < notValidBefore) {\n throw new Error(\"license times are invalid\");\n }\n\n const key = Uint8Array.from(data.slice(1, 33));\n\n const { payload, payloadRead } = parseBlockPayload(blockType, data, MIN_BLOCK_LEN);\n\n const allLen = MIN_BLOCK_LEN + payloadRead;\n if (allLen > data.length) throw new Error(\"license block longer than the license\");\n const hashInput = data.slice(1, allLen);\n const hashFull = hash512(Uint8Array.from(hashInput));\n const hash = Uint8Array.from(hashFull.slice(0, 32));\n\n return {\n block: {\n key,\n hash,\n properties: payload.properties,\n issuer: payload.issuer,\n notValidBefore,\n notValidAfter,\n blockType,\n serverType: payload.serverType,\n },\n consumed: allLen,\n };\n}\n\ninterface BlockPayload {\n issuer: string;\n serverType: number;\n properties: Uint8Array[];\n read: number;\n}\n\nfunction parseBlockPayload(\n blockType: LicenseBlockType,\n data: Uint8Array,\n minBlockLen: number,\n): { payload: BlockPayload; payloadRead: number } {\n switch (blockType) {\n case LicenseBlockType.Intermediate: {\n const { str, read } = readNullString(data.slice(46));\n return {\n payload: { issuer: str, serverType: 0, properties: [], read: 5 + read },\n payloadRead: 5 + read,\n };\n }\n case LicenseBlockType.Server: {\n const { str, read } = readNullString(data.slice(47));\n return {\n payload: { issuer: str, serverType: data[42] ?? 0, properties: [], read: 6 + read },\n payloadRead: 6 + read,\n };\n }\n case LicenseBlockType.Ts5Server: {\n const propCount = data[43] !== undefined ? data[43] : 0;\n let pos = 44;\n const properties: Uint8Array[] = [];\n for (let i = 0; i < propCount; i++) {\n if (pos >= data.length) throw new Error(\"license too short\");\n const propLen = data[pos++]!;\n if (pos + propLen > data.length) throw new Error(\"license too short\");\n properties.push(Uint8Array.from(data.slice(pos, pos + propLen)));\n pos += propLen;\n }\n return {\n payload: { issuer: \"\", serverType: data[42] ?? 0, properties, read: pos - minBlockLen },\n payloadRead: pos - minBlockLen,\n };\n }\n case LicenseBlockType.Ephemeral:\n return { payload: { issuer: \"\", serverType: 0, properties: [], read: 0 }, payloadRead: 0 };\n default:\n throw new Error(`invalid license block type: ${blockType}`);\n }\n}\n\n/**\n * Scan for a null-terminated string and return its content and the index\n * of the null byte (NOT including it in the count, matching Go behaviour).\n * The parent formulas (`5 + read`, `6 + read`) already add 1 for the null.\n */\nfunction readNullString(data: Uint8Array): { str: string; read: number } {\n for (let i = 0; i < data.length; i++) {\n if (data[i] === 0) {\n return { str: new TextDecoder().decode(data.slice(0, i)), read: i };\n }\n }\n throw new Error(\"non-null-terminated issuer string\");\n}\n\n/**\n * Derive the next key given a parent key and a license block.\n * Mirrors Go's licenseBlock.deriveKey.\n */\nfunction deriveKeyFromBlock(block: LicenseBlock, parent: Uint8Array): Uint8Array<ArrayBuffer> {\n const scalarBytes = Uint8Array.from(block.hash);\n clampScalar(scalarBytes);\n\n // Use raw scalar WITHOUT reducing mod n — NaCl's ge_scalarmult_vartime\n // uses the raw 256-bit scalar. Reducing mod n changes the result when\n // the point has a small-order component (Ed25519 cofactor = 8).\n const scalar = bytesToBigIntLE(scalarBytes);\n\n const pub = ed25519.Point.fromBytes(block.key);\n const negPub = pub.negate();\n\n const par = ed25519.Point.fromBytes(parent);\n const negPar = par.negate();\n\n const res = scalarMultFull(negPub, scalar).add(negPar);\n const raw = res.toBytes();\n const final = new Uint8Array(raw.length) as Uint8Array<ArrayBuffer>;\n final.set(raw);\n final[31] = (final[31] !== undefined ? final[31] : 0) ^ 0x80;\n\n return final;\n}\n","import type { KeyObject } from \"node:crypto\";\nimport type { Crypt } from \"../crypto/crypt.js\";\nimport { importPublicKey } from \"../crypto/identity.js\";\nimport { verifySign, getSharedSecret2 } from \"../crypto/primitives.js\";\nimport { parseLicenses } from \"./license.js\";\nimport { CryptoInitError } from \"../errors.js\";\n\n/**\n * CryptoInit2 performs the second stage of crypto initialization (Ed25519 ECDH).\n * Mirrors Go's handshake.CryptoInit2.\n */\nexport function cryptoInit2(\n crypt: Crypt,\n license: string,\n omega: string,\n proof: string,\n beta: string,\n privateKey: Uint8Array,\n): void {\n if (crypt.alpha.length === 0) {\n throw new CryptoInitError(\"initivexpand2 arrived before clientinitiv was sent\");\n }\n\n const licenseBytes = Buffer.from(license, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n const proofBytes = Buffer.from(proof, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n\n let serverPubKey: KeyObject;\n try {\n serverPubKey = importPublicKey(omegaBytes);\n } catch (error) {\n throw new CryptoInitError(\"the server's public key is invalid\", { cause: error });\n }\n if (!verifySign(serverPubKey, licenseBytes, proofBytes)) {\n throw new CryptoInitError(\"the server's license proof is not valid\");\n }\n\n let sharedSecret: Uint8Array;\n try {\n const key = parseLicenses(licenseBytes).deriveKey();\n sharedSecret = getSharedSecret2(key, privateKey);\n } catch (error) {\n throw new CryptoInitError(\"the server's license is invalid\", { cause: error });\n }\n\n crypt.setSharedSecret(crypt.alpha, betaBytes, sharedSecret);\n}\n","import { createHash } from \"node:crypto\";\nimport { buildCommandOrdered, buildCommand } from \"@honeybbq/teamspeak-core/internal\";\nimport { sign, generateTemporaryKey } from \"./crypto/primitives.js\";\nimport { identityPrivateKey } from \"./crypto/identity.js\";\nimport { parseServerCapabilities } from \"./capabilities.js\";\nimport { cryptoInit2 } from \"./handshake/crypt-init2.js\";\nimport { PacketType } from \"./transport/packet.js\";\nimport type { ClientInternals } from \"./client.js\";\n\n/** Handle the `clientinitiv` message (P-256 based crypto path). */\nexport function handleHandshakeInitIV(\n client: ClientInternals,\n params: Record<string, string>,\n): void {\n const alpha = params[\"alpha\"] ?? \"\";\n const beta = params[\"beta\"] ?? \"\";\n const omega = params[\"omega\"] ?? \"\";\n\n client.handler.receivedFinalInitAck();\n client.crypt.initCrypto(alpha, beta, omega);\n client.logger.info(\"crypto initialized (P-256 path), sending clientinit\");\n sendClientInit(client);\n}\n\n/** Handle the `initivexpand2` message (Ed25519 / TS3 crypto path). */\nexport function handleHandshakeExpand2(\n client: ClientInternals,\n params: Record<string, string>,\n): void {\n client.logger.info(\"received initivexpand2\");\n client.handler.receivedFinalInitAck();\n\n const license = params[\"l\"] ?? \"\";\n const omega = params[\"omega\"] ?? \"\";\n const proof = params[\"proof\"] ?? \"\";\n const beta = params[\"beta\"] ?? \"\";\n\n const privateKey = sendClientEkPacket(client, beta);\n cryptoInit2(client.crypt, license, omega, proof, beta, privateKey);\n sendClientInit(client);\n}\n\n/** Handle `initserver` — marks the client as connected. */\nexport function handleInitServer(client: ClientInternals, params: Record<string, string>): void {\n const idStr = params[\"aclid\"] ?? params[\"clid\"] ?? \"\";\n const clid = idStr ? parseInt(idStr, 10) : 0;\n\n if (clid > 0) {\n client.clid = clid;\n client.handler.setClientID(clid);\n }\n\n // initserver is the only place the server names itself, and it determines how\n // the server hashes our public key into client_unique_identifier: SHA-1 on\n // TS3, SHA-256 on TS6. Recording the whole capability set here keeps callers\n // from re-deriving it, or assuming one server generation.\n client.capabilities = parseServerCapabilities(params);\n\n client.logger.info(\"connected to server\", { selfId: client.clid });\n client.markConnected();\n\n // Inform the server about mute state\n setImmediate(() => {\n const updateCmd = buildCommand(\"clientupdate\", {\n client_input_muted: \"0\",\n client_output_muted: \"0\",\n });\n client.execNoWait(updateCmd).catch(() => {});\n });\n}\n\nfunction sendClientEkPacket(client: ClientInternals, beta: string): Uint8Array {\n const [publicKey, privateKey] = generateTemporaryKey();\n const ekBase64 = Buffer.from(publicKey).toString(\"base64\");\n const clientProof = buildClientEkProof(client, publicKey, beta);\n\n const clientEk = buildCommandOrdered(\"clientek\", [\n [\"ek\", ekBase64],\n [\"proof\", clientProof],\n ]);\n client.handler.sendPacket(PacketType.Command, Buffer.from(clientEk), 0);\n return privateKey;\n}\n\nfunction buildClientEkProof(client: ClientInternals, publicKey: Uint8Array, beta: string): string {\n const betaBytes = Buffer.from(beta, \"base64\");\n const toSign = new Uint8Array(86);\n toSign.set(publicKey.slice(0, 32));\n toSign.set(betaBytes.slice(0, Math.min(54, betaBytes.length)), 32);\n const sig = sign(identityPrivateKey(client.crypt.identity), toSign);\n return Buffer.from(sig).toString(\"base64\");\n}\n\n/**\n * Encode a password field for the command protocol.\n *\n * TeamSpeak expects password fields as base64(sha1(password)) — server and\n * channel passwords during the handshake, the `clientmove` channel password,\n * and the `cpw` field of the file transfer commands. Sending the plain text\n * instead makes the server reject correct passwords with error 781.\n */\nexport function prepareClientPassword(password: string): string {\n if (password === \"\") return \"\";\n return createHash(\"sha1\").update(password).digest().toString(\"base64\");\n}\n\nexport function sendClientInit(client: ClientInternals): void {\n const cmd = buildClientInitCommand(client);\n client.handler.sendPacket(PacketType.Command, Buffer.from(cmd), 0);\n}\n\nfunction buildClientInitCommand(client: ClientInternals): string {\n const pubKeyBase64 = client.crypt.identity.publicKey();\n const initOptions = client.initOptions;\n // HWID should match TS3 client UID format: base64(SHA1(publicKey()))\n const hwid = createHash(\"sha1\").update(pubKeyBase64).digest().toString(\"base64\");\n\n return buildCommandOrdered(\"clientinit\", [\n [\"client_nickname\", client.nickname],\n [\"client_version\", \"3.?.? [Build: 5680278000]\"],\n [\"client_platform\", \"Windows\"],\n [\"client_input_hardware\", \"1\"],\n [\"client_output_hardware\", \"1\"],\n [\"client_default_channel\", initOptions.defaultChannel],\n [\"client_default_channel_password\", initOptions.defaultChannelPasswordHash],\n [\"client_server_password\", initOptions.serverPasswordHash],\n [\"client_meta_data\", \"\"],\n [\n \"client_version_sign\",\n \"DX5NIYLvfJEUjuIbCidnoeozxIDRRkpq3I9vVMBmE9L2qnekOoBzSenkzsg2lC9CMv8K5hkEzhr2TYUYSwUXCg==\",\n ],\n [\"client_key_offset\", String(client.crypt.identity.offset)],\n [\"client_nickname_phonetic\", \"\"],\n [\"client_default_token\", \"\"],\n [\"hwid\", hwid],\n ]);\n}\n","import type { Command } from \"@honeybbq/teamspeak-core/internal\";\nimport type {\n ClientEnterEvent,\n ClientLeaveEvent,\n ClientMovedEvent,\n TextMessageEvent,\n PokeEvent,\n} from \"./types.js\";\nimport {\n parseClient,\n parseUint64,\n parseUint16,\n parseInt10,\n} from \"@honeybbq/teamspeak-core/internal\";\nimport { asChannelID, asClientID, asUID } from \"@honeybbq/teamspeak-core\";\n\nexport type NotificationResult =\n | { kind: \"clientEnter\"; info: ClientEnterEvent }\n | { kind: \"clientLeave\"; event: ClientLeaveEvent; isSelf: boolean }\n | { kind: \"clientMoved\"; event: ClientMovedEvent; reasonMessage: string }\n | { kind: \"textMessage\"; message: TextMessageEvent }\n | { kind: \"poked\"; event: PokeEvent }\n | { kind: \"unknown\" };\n\nexport function handleNotification(\n cmd: Command,\n selfCLID: number,\n clients: Map<number, ClientEnterEvent>,\n _nickname: string,\n): NotificationResult {\n switch (cmd.name) {\n case \"notifycliententerview\":\n return handleClientEnterView(cmd, clients);\n case \"notifyclientleftview\":\n return handleClientLeftView(cmd, selfCLID, clients);\n case \"notifyclientmoved\":\n return handleClientMoved(cmd, clients);\n case \"notifytextmessage\":\n return handleTextMessage(cmd, clients);\n case \"notifyclientpoke\":\n return handleClientPoked(cmd);\n default:\n return { kind: \"unknown\" };\n }\n}\n\nfunction handleClientEnterView(\n cmd: Command,\n clients: Map<number, ClientEnterEvent>,\n): NotificationResult {\n const info = parseClient(cmd.params);\n // No client has id 0: a row without one describes nobody.\n if (info.id === 0) return { kind: \"unknown\" };\n clients.set(info.id, info);\n return { kind: \"clientEnter\", info };\n}\n\nfunction handleClientLeftView(\n cmd: Command,\n selfCLID: number,\n clients: Map<number, ClientEnterEvent>,\n): NotificationResult {\n const clid = asClientID(parseUint16(cmd.params[\"clid\"] ?? \"\"));\n if (clid === 0) return { kind: \"unknown\" };\n const isSelf = clid === selfCLID;\n clients.delete(clid);\n return {\n kind: \"clientLeave\",\n event: {\n clientID: clid,\n reason: parseInt10(cmd.params[\"reasonid\"] ?? \"\"),\n reasonMessage: cmd.params[\"reasonmsg\"] ?? \"\",\n invokerID: asClientID(parseUint16(cmd.params[\"invokerid\"] ?? \"\")),\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: asUID(cmd.params[\"invokeruid\"] ?? \"\"),\n },\n isSelf,\n };\n}\n\nfunction handleClientMoved(\n cmd: Command,\n clients: Map<number, ClientEnterEvent>,\n): NotificationResult {\n const clid = asClientID(parseUint16(cmd.params[\"clid\"] ?? \"\"));\n const ctid = asChannelID(parseUint64(cmd.params[\"ctid\"] ?? \"\"));\n if (clid === 0) return { kind: \"unknown\" };\n\n const existing = clients.get(clid);\n if (existing) clients.set(clid, { ...existing, channelID: ctid });\n\n return {\n kind: \"clientMoved\",\n event: {\n clientID: clid,\n targetChannelID: ctid,\n reason: parseInt10(cmd.params[\"reasonid\"] ?? \"\"),\n invokerID: asClientID(parseUint16(cmd.params[\"invokerid\"] ?? \"\")),\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: asUID(cmd.params[\"invokeruid\"] ?? \"\"),\n },\n reasonMessage: cmd.params[\"reasonmsg\"] ?? \"\",\n };\n}\n\nfunction handleTextMessage(\n cmd: Command,\n clients: Map<number, ClientEnterEvent>,\n): NotificationResult {\n const invokerID = asClientID(parseUint16(cmd.params[\"invokerid\"] ?? \"\"));\n const invokerInfo = clients.get(invokerID);\n\n const message: TextMessageEvent = {\n targetMode: parseInt10(cmd.params[\"targetmode\"] ?? \"\"),\n targetID: asClientID(parseUint16(cmd.params[\"target\"] ?? \"\")),\n invokerID,\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: asUID(cmd.params[\"invokeruid\"] ?? invokerInfo?.uid ?? \"\"),\n message: cmd.params[\"msg\"] ?? \"\",\n invokerGroups: invokerInfo?.serverGroups ?? [],\n };\n\n return { kind: \"textMessage\", message };\n}\n\nfunction handleClientPoked(cmd: Command): NotificationResult {\n return {\n kind: \"poked\",\n event: {\n invokerID: asClientID(parseUint16(cmd.params[\"invokerid\"] ?? \"\")),\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: asUID(cmd.params[\"invokeruid\"] ?? \"\"),\n message: cmd.params[\"msg\"] ?? \"\",\n },\n };\n}\n","interface Waiter {\n readonly resolve: () => void;\n readonly signal: AbortSignal | undefined;\n readonly onAbort: () => void;\n}\n\n/**\n * Token-bucket limiter for outbound TS3 commands.\n * Mirrors Go's commandThrottle.\n *\n * Waiters are released in the order they arrived: each used to poll for a\n * token on its own timer, so a command that came later could take the turn of\n * one that had waited longer, and the commands went out of order.\n */\nexport class CommandThrottle {\n static readonly TOKEN_RATE = 4.0; // tokens per second\n static readonly TOKEN_MAX = 8.0; // bucket capacity\n\n #tokens = 5.0;\n #lastUpdate = Date.now();\n readonly #waiters: Waiter[] = [];\n #timer: ReturnType<typeof setTimeout> | undefined;\n\n /**\n * Wait for a token, behind every earlier waiter. Aborting `signal` rejects\n * with its reason and gives the place in line up; the abort listener is\n * removed however the wait ends.\n */\n wait(signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) return Promise.reject(signal.reason);\n this.#refill();\n if (this.#waiters.length === 0 && this.#tokens >= 1.0) {\n this.#tokens -= 1.0;\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n const waiter: Waiter = {\n resolve,\n signal,\n onAbort: () => {\n const index = this.#waiters.indexOf(waiter);\n if (index >= 0) this.#waiters.splice(index, 1);\n if (this.#waiters.length === 0) this.#stopTimer();\n reject(signal!.reason);\n },\n };\n signal?.addEventListener(\"abort\", waiter.onAbort, { once: true });\n this.#waiters.push(waiter);\n this.#schedule();\n });\n }\n\n #refill(): void {\n const now = Date.now();\n const elapsed = (now - this.#lastUpdate) / 1000;\n this.#tokens = Math.min(\n this.#tokens + elapsed * CommandThrottle.TOKEN_RATE,\n CommandThrottle.TOKEN_MAX,\n );\n this.#lastUpdate = now;\n }\n\n /** Arm the timer for when the next token is due, unless it already is. */\n #schedule(): void {\n if (this.#timer !== undefined || this.#waiters.length === 0) return;\n const waitMs =\n this.#tokens >= 1.0\n ? 0\n : Math.ceil(((1.0 - this.#tokens) / CommandThrottle.TOKEN_RATE) * 1000) + 10;\n this.#timer = setTimeout(() => {\n this.#timer = undefined;\n this.#release();\n }, waitMs);\n }\n\n #stopTimer(): void {\n clearTimeout(this.#timer);\n this.#timer = undefined;\n }\n\n /** Hand the tokens there are to the waiters at the head of the line. */\n #release(): void {\n this.#refill();\n while (this.#waiters.length > 0 && this.#tokens >= 1.0) {\n this.#tokens -= 1.0;\n const waiter = this.#waiters.shift()!;\n waiter.signal?.removeEventListener(\"abort\", waiter.onAbort);\n waiter.resolve();\n }\n this.#schedule();\n }\n}\n","/**\n * Reports whether `actual` equals `expected` or equals `expected` followed by\n * only digits — the pattern TeamSpeak uses when a nickname is already taken.\n */\nexport function isAutoNicknameMatch(expected: string, actual: string): boolean {\n if (actual === expected) return true;\n if (!actual.startsWith(expected)) return false;\n const suffix = actual.slice(expected.length);\n return /^\\d+$/.test(suffix);\n}\n","/**\n * Diagnostics channels: the SDK's tracing points, for an application or an\n * APM agent (OpenTelemetry instruments `diagnostics_channel` directly) to\n * subscribe to.\n *\n * A library does not decide where its traces go, so the SDK publishes them\n * here, and with no subscriber a channel costs a property read.\n *\n * Messages carry the command's name, never its parameters: those hold\n * password hashes, which the server accepts as passwords, and privilege keys.\n *\n * ```ts\n * import { tracingChannel } from \"node:diagnostics_channel\";\n *\n * tracingChannel(\"honeybbq:teamspeak:command\").subscribe({\n * start: ({ command }) => console.time(command),\n * asyncEnd: ({ command }) => console.timeEnd(command),\n * error: ({ command, error }) => console.error(command, error),\n * });\n * ```\n */\n\nimport {\n channel,\n tracingChannel,\n type Channel,\n type TracingChannel,\n} from \"node:diagnostics_channel\";\nimport type { Client } from \"./client.js\";\n\n/** What `honeybbq:teamspeak:command` reports about a command. */\nexport interface CommandTrace {\n /** The command's name, such as `clientlist`. */\n readonly command: string;\n /** The client sending it. Its fields are private, so it carries no secret. */\n readonly client: Client;\n}\n\n/** What `honeybbq:teamspeak:packet` reports about a command arriving from the server. */\nexport interface PacketTrace {\n /** The command's name, such as `notifytextmessage`, or `\"\"` for a data row. */\n readonly command: string;\n /** The client receiving it. */\n readonly client: Client;\n}\n\n/**\n * Traces every command with an answer: `start` when it is sent, `asyncEnd`\n * when its answer arrives, `error` when it fails.\n */\nexport const commandChannel: TracingChannel<CommandTrace> = tracingChannel<CommandTrace>(\n \"honeybbq:teamspeak:command\",\n);\n\n/** Publishes every command the server sends. */\nexport const packetChannel: Channel<PacketTrace> = channel<PacketTrace>(\n \"honeybbq:teamspeak:packet\",\n);\n","/**\n * Reconnection policy.\n *\n * A dropped connection is normal on a UDP voice session, so a bot that cannot\n * recover is not usable unattended. Reconnecting is opt-in rather than\n * automatic: a silent reconnect makes a dropped session look like a healthy\n * one, and a caller that wanted to know about the drop never finds out.\n *\n * Backoff is not a nicety here. TeamSpeak bans an IP that opens several\n * connections in quick succession — measured at roughly three, after which the\n * server answers `error id=3329` and refuses everything. A reconnect loop\n * without a delay therefore bans itself, and the ban outlasts the outage it was\n * recovering from.\n */\n\nimport { ErrorCode, Reason, ServerError } from \"@honeybbq/teamspeak-core\";\nimport { AlreadyConnectedError, InvalidAddressError, RemovedError } from \"./errors.js\";\n\n/** How long to wait before each attempt. */\nexport interface BackoffPolicy {\n /** Delay before the first retry, in milliseconds. */\n readonly initialDelayMs: number;\n /** Ceiling for the delay; it never grows past this. */\n readonly maxDelayMs: number;\n /** Multiplier applied after each failed attempt. */\n readonly factor: number;\n /**\n * Fraction of the delay to randomise, 0 to 1.\n *\n * A fleet of bots that drop together would otherwise retry in lockstep and\n * hit the server in a burst. Jitter spreads them out.\n */\n readonly jitter: number;\n /** Give up after this many consecutive failures. 0 means never give up. */\n readonly maxAttempts: number;\n}\n\n/** One second, doubling, capped at a minute, with 20% jitter, never giving up. */\nexport const defaultBackoffPolicy: Readonly<BackoffPolicy> = Object.freeze({\n initialDelayMs: 1_000,\n maxDelayMs: 60_000,\n factor: 2,\n jitter: 0.2,\n maxAttempts: 0,\n});\n\n/**\n * How a client reconnects after its connection drops. Supplying it, even as\n * `{}`, turns reconnecting on; a deliberate `disconnect()` never reconnects.\n */\nexport interface ReconnectOptions {\n /** Tuning for the retry delays; unset fields keep {@link defaultBackoffPolicy}'s. */\n readonly backoff?:\n | { readonly [K in keyof BackoffPolicy]?: BackoffPolicy[K] | undefined }\n | undefined;\n /**\n * Decide whether a given failure is worth retrying. Returning false stops the\n * loop. Defaults to {@link defaultShouldRetry}.\n */\n readonly shouldRetry?: ((error: Error | undefined, attempt: number) => boolean) | undefined;\n}\n\n/**\n * Compute the delay before an attempt.\n *\n * `attempt` is 1-based: the delay before the first retry is `initialDelayMs`,\n * give or take the jitter, and the delay never grows past `maxDelayMs`.\n */\nexport function backoffDelay(policy: Readonly<BackoffPolicy>, attempt: number): number {\n return jitteredDelay(policy, attempt, Math.random);\n}\n\n/** @internal The delay, with `random` supplying the jitter. */\nexport function jitteredDelay(\n policy: Readonly<BackoffPolicy>,\n attempt: number,\n random: () => number,\n): number {\n const exponent = Math.max(0, attempt - 1);\n const raw = policy.initialDelayMs * policy.factor ** exponent;\n const capped = Math.min(raw, policy.maxDelayMs);\n\n if (policy.jitter <= 0) return Math.round(capped);\n\n // Full jitter would ignore the computed delay; this keeps the trend while\n // spreading peers, so a whole fleet does not retry on the same millisecond.\n // Kept under the ceiling, which a caller reasonably reads as a promise.\n const spread = capped * Math.min(policy.jitter, 1);\n const delay = capped + (random() * 2 - 1) * spread;\n return Math.round(Math.max(0, Math.min(delay, policy.maxDelayMs)));\n}\n\n/**\n * Server errors where retrying cannot help.\n *\n * Deliberately a short list of codes known to be refusals, rather than \"any\n * ServerError\". The server also answers transiently: after a dropped\n * connection it still holds the old session, and a reconnect with the same\n * identity is refused with 521 \"too many clones already connected\" until it\n * reaps the zombie — a condition that clears itself and is worth retrying.\n *\n * The asymmetry is deliberate. Retrying a permanent failure costs a few bounded\n * attempts; not retrying a transient one means never recovering.\n */\nconst PERMANENT_SERVER_ERRORS: ReadonlySet<number> = new Set([\n ErrorCode.ConnectFailedBanned,\n ErrorCode.BanFlooding,\n ErrorCode.ServerInvalidPassword,\n ErrorCode.ChannelInvalidPassword,\n ErrorCode.PermissionsClientInsufficient,\n]);\n\n/**\n * Whether a failure is worth another attempt.\n *\n * Transport failures are retried; so is a server that stopped, and a server\n * error other than the known refusals — a ban, flooding, a wrong server or\n * channel password, missing permissions — since some, such as 521 \"too many\n * clones\" right after a drop, clear by themselves. A kick or a ban is not:\n * someone removed the client on purpose. Nor is an AlreadyConnectedError: the\n * client was connected by other means; nor an InvalidAddressError.\n */\nexport function defaultShouldRetry(error: Error | undefined): boolean {\n // The client is connected, or connecting, already: there is nothing to retry.\n if (error instanceof AlreadyConnectedError) return false;\n // An address that cannot be one stays that way.\n if (error instanceof InvalidAddressError) return false;\n if (error instanceof RemovedError) {\n return error.reason !== Reason.KickServer && error.reason !== Reason.KickServerBan;\n }\n return !(error instanceof ServerError && PERMANENT_SERVER_ERRORS.has(error.code));\n}\n\nexport function resolveBackoffPolicy(options: ReconnectOptions): BackoffPolicy {\n const policy: Record<string, number> = { ...defaultBackoffPolicy };\n // An explicit undefined keeps the default, as an unset field does.\n for (const [key, value] of Object.entries(options.backoff ?? {})) {\n if (value !== undefined) policy[key] = value;\n }\n return policy as unknown as BackoffPolicy;\n}\n","import {\n type EventMap,\n type ClientOptions,\n type EventMiddleware,\n type AddrResolver,\n type ClientEnterEvent,\n type KickedEvent,\n type Listener,\n type ServerEvent,\n type ServerEventName,\n type Unsubscribe,\n ClientStatus,\n} from \"./types.js\";\nimport {\n type ChannelID,\n type ClientID,\n type Codec,\n type CommandMiddleware,\n type CommandOptions,\n type UID,\n asChannelID,\n asClientID,\n type Logger,\n ErrorCode,\n Reason,\n TeamspeakError,\n noopLogger,\n} from \"@honeybbq/teamspeak-core\";\nimport { AlreadyConnectedError, CryptoInitError, RemovedError } from \"./errors.js\";\nimport { abortable, abortReason } from \"./abort.js\";\nimport { Identity, Crypt } from \"./crypto/index.js\";\nimport { RESOLVE_BUDGET_MS, Resolver } from \"./discovery/resolver.js\";\nimport { PacketHandler } from \"./transport/handler.js\";\nimport { PacketType } from \"./transport/packet.js\";\nimport type { Packet } from \"./transport/packet.js\";\nimport { CommandTracker, appendReturnCode } from \"./commands.js\";\nimport { encodeRequest, parseServerError } from \"@honeybbq/teamspeak-core/internal\";\nimport { uploadFileData, downloadFileData } from \"./transfer.js\";\nimport { buildCommandChain, buildEventChain } from \"./events.js\";\nimport { processInit1 } from \"./handshake/crypt-handshake.js\";\nimport {\n handleHandshakeInitIV,\n handleHandshakeExpand2,\n handleInitServer,\n prepareClientPassword,\n} from \"./handshake.js\";\nimport type { CommandExecutor, CommandRequest } from \"@honeybbq/teamspeak-core\";\nimport { handleNotification } from \"./notifications.js\";\nimport { parseCommand } from \"@honeybbq/teamspeak-core/internal\";\nimport { CommandThrottle } from \"./throttle.js\";\nimport { splitCommandRows, sleep } from \"@honeybbq/teamspeak-core/internal\";\nimport { isAutoNicknameMatch } from \"./helpers.js\";\nimport type { FileUploadInfo, FileDownloadInfo } from \"@honeybbq/teamspeak-core\";\nimport { CommandTimeoutError, NotConnectedError } from \"@honeybbq/teamspeak-core\";\nimport { responseSpec } from \"@honeybbq/teamspeak-core/internal\";\nimport type { Readable, Writable } from \"node:stream\";\nimport type { SocketFactory, FileTransferSocketFactory } from \"./types.js\";\nimport { unknownServerCapabilities, type ServerCapabilities } from \"./capabilities.js\";\nimport { joinHostPort, parseConnectAddress, splitHostPort } from \"./address.js\";\nimport { commandChannel, packetChannel, type CommandTrace } from \"./diagnostics.js\";\nimport {\n backoffDelay,\n defaultShouldRetry,\n resolveBackoffPolicy,\n type ReconnectOptions,\n} from \"./reconnect.js\";\n\nexport { ClientStatus };\n\n/**\n * What clientinit sends about the connection, with the passwords already in\n * their wire form, `base64(sha1(password))`: hashed once, when the client is\n * made, so the plain text is never held.\n */\nexport interface ClientInitOptions {\n readonly serverPasswordHash: string;\n readonly defaultChannel: string;\n readonly defaultChannelPasswordHash: string;\n}\n\nfunction normalizeClientInitOptions(options: ClientOptions): ClientInitOptions {\n return {\n serverPasswordHash: prepareClientPassword(options.serverPassword ?? \"\"),\n defaultChannel: options.defaultChannel ?? \"\",\n defaultChannelPasswordHash: prepareClientPassword(options.defaultChannelPassword ?? \"\"),\n };\n}\n\n/**\n * What the handshake, and the package's own tests, reach inside a Client.\n * Not exported from the package: a Client keeps all of it in private fields,\n * so none of it shows in `util.inspect()`, `JSON.stringify()` or a debugger's\n * property list.\n *\n * @internal\n */\nexport interface ClientInternals {\n readonly crypt: Crypt;\n readonly handler: PacketHandler;\n readonly logger: Logger;\n readonly initOptions: ClientInitOptions;\n nickname: string;\n clid: number;\n capabilities: ServerCapabilities;\n /** Mark the attempt in progress connected. */\n markConnected(): void;\n /**\n * Send a command line without waiting for an answer, on the handshake's\n * own path: it needs an open socket, not a connected session.\n */\n execNoWait(command: string): Promise<void>;\n /** Handle a packet as if the current handler had received it. */\n handlePacket(packet: Packet): void;\n}\n\nlet internalsOf: (client: Client) => ClientInternals;\n\nlet sentLineHook: ((client: Client, line: string) => void) | undefined;\n\n/**\n * Observe every command line the client sends, as encoded. A seam for the\n * package's own tests; not exported from the package.\n *\n * @internal\n */\nexport function onSentLine(hook: ((client: Client, line: string) => void) | undefined): void {\n sentLineHook = hook;\n}\n\n/** @internal The internals of `client`. */\nexport function clientInternals(client: Client): ClientInternals {\n return internalsOf(client);\n}\n\n/** How long a command waits for its answer unless told otherwise. */\nconst DEFAULT_COMMAND_TIMEOUT_MS = 10_000;\n\n/**\n * How long `disconnect()` waits for the server to acknowledge its goodbye\n * unless told otherwise: the acknowledgement is a courtesy, and a connection\n * that has already died would otherwise hold it for a full command timeout.\n */\nconst DISCONNECT_TIMEOUT_MS = 1_000;\n\n/** How long each reconnection attempt may take. */\nconst RECONNECT_ATTEMPT_TIMEOUT_MS = 30_000;\n\n/** One connection attempt, settled once by the handshake or its failure. */\ninterface ConnectAttempt {\n readonly promise: Promise<void>;\n /**\n * Aborted when the attempt fails, is abandoned, or is interrupted by\n * disconnect(), so the address lookup and the socket being opened for it\n * stop too instead of finishing a connection nobody wants.\n */\n readonly signal: AbortSignal;\n settled: boolean;\n resolve(): void;\n reject(error: unknown): void;\n /**\n * Settle the attempt as failed now, which stops its lookup and socket, but\n * reject its promise only once `until` settles: disconnect() holds it until\n * `disconnected` has been delivered, so a caller that awaits disconnect()\n * before the connect() it interrupted still hears that reject in time.\n */\n rejectAfter(error: unknown, until: Promise<unknown>): void;\n}\n\nfunction newConnectAttempt(): ConnectAttempt {\n let resolve!: () => void;\n let reject!: (error: unknown) => void;\n const promise = new Promise<void>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n // The failure is reported to whoever awaits connect(); an attempt nobody\n // awaits any more must not surface as an unhandled rejection.\n promise.catch(() => {});\n const controller = new AbortController();\n const attempt: ConnectAttempt = {\n promise,\n signal: controller.signal,\n settled: false,\n resolve() {\n if (attempt.settled) return;\n attempt.settled = true;\n resolve();\n },\n reject(error) {\n if (attempt.settled) return;\n attempt.settled = true;\n controller.abort(error);\n reject(error);\n },\n rejectAfter(error, until) {\n if (attempt.settled) return;\n attempt.settled = true;\n controller.abort(error);\n void until.finally(() => reject(error));\n },\n };\n return attempt;\n}\n\n/**\n * Voice deliveries are dropped while more than this many deliveries of any\n * kind are waiting: audio is fifty packets a second per speaker, and a\n * listener that cannot keep up would otherwise queue it without bound.\n */\nconst MAX_PENDING_DELIVERIES = 256;\n\n/** How often dropped voice is reported, at most. */\nconst VOICE_DROP_WARN_INTERVAL_MS = 10_000;\n\n/** The only commands handled before crypto init completes. */\nconst PRE_INIT_COMMANDS: ReadonlySet<string> = new Set([\"clientinitiv\", \"initivexpand2\", \"error\"]);\n\ninterface Subscription {\n readonly listener: (payload: unknown) => void;\n removed: boolean;\n}\n\n/**\n * A TeamSpeak client over the voice protocol.\n *\n * Listeners run one at a time, in the order their events arrived, after the\n * packet that carried them has been handled, so a listener may call the client\n * and await an answer.\n */\nexport class Client implements CommandExecutor, AsyncDisposable {\n static {\n internalsOf = (client) => client.#internals;\n }\n\n #crypt: Crypt;\n #handler: PacketHandler;\n #logger: Logger;\n #nickname: string;\n #clid = 0;\n /**\n * What the server reported about itself in initserver, including the UID\n * hash it uses: TS3 hashes the public key with SHA-1 and TS6 with SHA-256.\n */\n #capabilities: ServerCapabilities = unknownServerCapabilities();\n #internals: ClientInternals;\n\n #identity: Identity;\n #addr: string;\n #resolver: AddrResolver;\n #clientInitOptions: ClientInitOptions;\n #socketFactory: SocketFactory | undefined;\n #fileTransferSocketFactory: FileTransferSocketFactory | undefined;\n /** Undefined when the client does not reconnect. */\n #reconnectOptions: ReconnectOptions | undefined;\n /**\n * Set while a reconnect attempt is in flight, so overlapping failures do not\n * start competing loops.\n */\n #reconnecting = false;\n /**\n * Why the last established session dropped: a reconnect loop whose own\n * attempt connected and then dropped before the loop resumed retries for it.\n */\n #lastDrop: Error | undefined;\n /** Set by an explicit disconnect(), which must never be undone by a retry. */\n #stopped = false;\n /**\n * The goodbye of a disconnect() still in progress, which a connect() waits\n * for: tearing the old session down after a new one has started would end\n * the new one instead.\n */\n #leaving: Promise<void> | undefined;\n /** How many times disconnect() was called, so a waiting connect() sees one. */\n #disconnects = 0;\n /**\n * Settles once the last queued `disconnected` has been delivered. A\n * connect() waits for it, so the end of one session is never heard during\n * the next: not by a listener added for the new session, and not by an\n * events() iterator started for it.\n */\n #disconnectedDelivered: Promise<void> | undefined;\n /** Cuts short the reconnect loop's wait, on disconnect(). */\n #stopReconnecting: AbortController | undefined;\n #status: ClientStatus = ClientStatus.Disconnected;\n #throttle = new CommandThrottle();\n #cmdTrack = new CommandTracker(() => this.#clid);\n #clients = new Map<number, ClientEnterEvent>();\n #attempt: ConnectAttempt = newConnectAttempt();\n\n #listeners = new Map<keyof EventMap, Subscription[]>();\n /** Deliveries waiting for their turn; see #emit. */\n #queue: Array<() => void> = [];\n #draining = false;\n #voiceDropped = 0;\n #voiceDropWarnedAt = -Infinity;\n\n #eventMiddlewares: readonly EventMiddleware[];\n #send: CommandExecutor[\"send\"];\n #eventChain: (event: ServerEvent) => void;\n\n constructor(identity: Identity, addr: string, nickname: string, options: ClientOptions = {}) {\n this.#identity = identity;\n this.#addr = addr;\n this.#nickname = nickname;\n this.#logger = options.logger ?? noopLogger;\n this.#resolver =\n options.resolver ?? new Resolver({ resolveNicknames: options.resolveNicknames });\n this.#clientInitOptions = normalizeClientInitOptions(options);\n this.#socketFactory = options.socketFactory;\n this.#fileTransferSocketFactory = options.fileTransferSocketFactory;\n this.#reconnectOptions = options.reconnect;\n\n this.#crypt = new Crypt(identity);\n this.#handler = this.#newHandler();\n\n // oxlint-disable-next-line no-this-alias -- accessors cannot be arrow functions\n const self = this;\n this.#internals = {\n get crypt() {\n return self.#crypt;\n },\n get handler() {\n return self.#handler;\n },\n get logger() {\n return self.#logger;\n },\n get initOptions() {\n return self.#clientInitOptions;\n },\n get nickname() {\n return self.#nickname;\n },\n set nickname(value) {\n self.#nickname = value;\n },\n get clid() {\n return self.#clid;\n },\n set clid(value) {\n self.#clid = value;\n },\n get capabilities() {\n return self.#capabilities;\n },\n set capabilities(value) {\n self.#capabilities = value;\n },\n markConnected: () => this.#markConnected(),\n execNoWait: (command) => this.#execNoWait(command, undefined, true),\n handlePacket: (packet) => this.#handlePacket(packet),\n };\n\n // Built once: the chains are read on every command and event, and\n // changing them while those run would make the behaviour depend on timing.\n const cmdMiddlewares: readonly CommandMiddleware[] = options.commandMiddleware ?? [];\n this.#eventMiddlewares = options.eventMiddleware ?? [];\n this.#send = buildCommandChain(cmdMiddlewares, (request, commandOptions = {}) =>\n this.#exec(encodeRequest(request, prepareClientPassword), commandOptions, false),\n );\n this.#eventChain = buildEventChain([...this.#eventMiddlewares], (event) =>\n this.#deliver(event.name, event.payload),\n );\n }\n\n /** Where the client is in its connection's life. */\n get status(): ClientStatus {\n return this.#status;\n }\n\n // ---- Connection -----------------------------------------------------------\n\n /**\n * Connect to the server. Resolves once the handshake completes.\n *\n * An address that cannot be one — no host, a port outside 1–65535 — rejects\n * with an InvalidAddressError at once, before anything starts. A host name\n * that does not resolve fails the attempt with a TeamspeakError whose\n * `cause` is the lookup's error.\n *\n * A failed attempt rejects with its cause, such as the server's error for a\n * rejected password. Aborting `signal` abandons the attempt and rejects with\n * the signal's reason. The signal bounds only the connecting: once this\n * resolves, the connection lasts until `disconnect()` or a drop.\n * `connect()` does not retry; the `reconnect` option only retries a\n * connection that drops after it was established.\n *\n * Called while a `disconnect()` is still saying goodbye, or while an earlier\n * session's `disconnected` is still waiting to be delivered, this waits for\n * that first, so the old session is closed, and its `disconnected`\n * delivered, before the new one starts: no listener or `events()` iterator\n * of the new session hears the old one end. A `disconnect()` called during\n * that wait wins: this then rejects with a NotConnectedError.\n *\n * `connected` is delivered after this resolves, so a listener added right\n * after `await client.connect()` still hears it.\n */\n async connect(options: { readonly signal?: AbortSignal | undefined } = {}): Promise<void> {\n const { signal } = options;\n signal?.throwIfAborted();\n const disconnects = this.#disconnects;\n if (this.#leaving !== undefined) await abortable(this.#leaving, signal);\n while (this.#disconnectedDelivered !== undefined) {\n await abortable(this.#disconnectedDelivered, signal);\n }\n if (this.#disconnects !== disconnects) throw new NotConnectedError();\n if (this.#status !== ClientStatus.Disconnected) throw new AlreadyConnectedError();\n // Checked before anything changes: an address that can never work leaves\n // the client as it was, with no attempt to announce the end of.\n parseConnectAddress(this.#addr);\n this.#stopped = false;\n\n this.#resetForConnect();\n this.#status = ClientStatus.Connecting;\n const attempt = this.#attempt;\n\n // The handshake may complete just as the signal fires, in which case\n // #failConnection leaves the session alone and the caller gets the\n // connection it made rather than one it would believe had failed.\n const onAbort = (): void => this.#failConnection(abortReason(signal!));\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n try {\n try {\n const targetAddr = await this.#resolveAddr(attempt.signal);\n if (!attempt.settled) {\n this.#logger.info(\"connecting to server\", { address: targetAddr });\n await this.#handler.connect(targetAddr, attempt.signal);\n }\n } catch (error) {\n // Without this the client stays Connecting and every later connect()\n // fails with AlreadyConnectedError.\n this.#failConnection(error);\n }\n await attempt.promise;\n } finally {\n signal?.removeEventListener(\"abort\", onAbort);\n }\n }\n\n /**\n * Leave the server and close the connection.\n *\n * Says goodbye first, waiting for the server's acknowledgement for a second\n * at most, or less if `signal` aborts sooner. The connection is closed\n * either way. A `connect()` still waiting for its handshake rejects with a\n * NotConnectedError, and so do the commands still waiting for an answer.\n * Resolves once `disconnected` has been delivered to the listeners, so one\n * added after `await client.disconnect()` does not hear it. Does nothing on\n * a client that is not connected; called again while an earlier call is\n * still saying goodbye, it waits for that one.\n */\n async disconnect(options: { readonly signal?: AbortSignal | undefined } = {}): Promise<void> {\n // Recorded before anything else: a dropped socket during the goodbye below\n // must not be mistaken for an outage worth retrying.\n this.#stopped = true;\n this.#disconnects++;\n this.#stopReconnecting?.abort();\n\n if (this.#leaving !== undefined) return this.#leaving;\n // Already ended, by a drop or a failed attempt: its `disconnected` may\n // still be on its way.\n if (this.#status === ClientStatus.Disconnected) return this.#disconnectedDelivered;\n\n const wasConnected = this.#status === ClientStatus.Connected;\n this.#status = ClientStatus.Disconnected;\n let left!: () => void;\n this.#attempt.rejectAfter(new NotConnectedError(), new Promise<void>((r) => (left = r)));\n\n const leaving = this.#leave(wasConnected, options.signal).finally(left);\n this.#leaving = leaving;\n try {\n await leaving;\n } finally {\n this.#leaving = undefined;\n }\n }\n\n async #leave(wasConnected: boolean, signal: AbortSignal | undefined): Promise<void> {\n this.#logger.info(\"disconnecting from server\");\n\n if (wasConnected) {\n try {\n // On the internal path: the status already says Disconnected.\n await this.#exec(\n \"clientdisconnect reasonmsg=Shutdown\",\n { signal, timeout: DISCONNECT_TIMEOUT_MS },\n true,\n );\n } catch {\n // A courtesy; the connection closes regardless.\n }\n }\n\n this.#handler.close();\n this.#cmdTrack.reset(new NotConnectedError());\n // Announced here; #handleConnectionClosed stays quiet once the status is\n // already Disconnected, so listeners hear about it once.\n await this.#announceDisconnected(undefined);\n }\n\n /** `await using client = …` disconnects when the scope ends. */\n [Symbol.asyncDispose](): Promise<void> {\n return this.disconnect();\n }\n\n // ---- Commands ------------------------------------------------------------\n\n /**\n * Send a raw command line and return the rows that answer it: the escape\n * hatch for a command the typed functions do not cover. The line is sent as\n * given, so its values must already be escaped and any channel password\n * already hashed. `CommandName` lists the command names.\n *\n * Rejects with a NotConnectedError unless the client is connected: while it\n * is still connecting, the session's keys may not exist yet.\n */\n exec(command: string, options: CommandOptions = {}): Promise<Record<string, string>[]> {\n return this.#exec(command, options, false);\n }\n\n /**\n * Send a raw command line without waiting for an answer, for the few\n * commands the server answers with nothing at all. `CommandName` lists\n * the command names.\n *\n * Commands are paced by a flood throttle; aborting `signal` while this waits\n * for its turn rejects with the signal's reason and sends nothing. Rejects\n * with a NotConnectedError unless the client is connected.\n */\n execNoWait(\n command: string,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): Promise<void> {\n return this.#execNoWait(command, options.signal, false);\n }\n\n /**\n * Whether a command may go out now. The handshake's own commands (`internal`)\n * need only an open socket; everything else needs a connected session, so\n * nothing a caller sends can go out under the public dummy key, or after\n * disconnect() has begun saying goodbye.\n */\n #canSend(internal: boolean): boolean {\n return this.#handler.isOpen && (internal || this.#status === ClientStatus.Connected);\n }\n\n async #execNoWait(\n command: string,\n signal: AbortSignal | undefined,\n internal: boolean,\n ): Promise<void> {\n signal?.throwIfAborted();\n if (!this.#canSend(internal)) throw new NotConnectedError();\n await this.#throttle.wait(signal);\n if (!this.#canSend(internal)) throw new NotConnectedError();\n this.#sendLine(command);\n }\n\n /**\n * Send a typed command; this is the CommandExecutor the typed commands run on.\n *\n * The request passes through the `commandMiddleware` first. Channel\n * passwords are then hashed, because that is this protocol's rule: the voice\n * protocol expects `base64(sha1(password))`, where ServerQuery takes the\n * password itself.\n */\n send(request: CommandRequest, options: CommandOptions = {}): Promise<Record<string, string>[]> {\n return this.#send(request, options);\n }\n\n #sendLine(line: string): void {\n const hook = sentLineHook;\n if (hook) hook(this, line);\n this.#handler.sendPacket(PacketType.Command, Buffer.from(line), 0);\n }\n\n #exec(\n command: string,\n options: CommandOptions,\n internal: boolean,\n ): Promise<Record<string, string>[]> {\n if (!commandChannel.hasSubscribers) return this.#execUntraced(command, options, internal);\n const trace: CommandTrace = { command: parseCommand(command)?.name ?? \"\", client: this };\n return commandChannel.tracePromise(() => this.#execUntraced(command, options, internal), trace);\n }\n\n async #execUntraced(\n command: string,\n options: CommandOptions,\n internal: boolean,\n ): Promise<Record<string, string>[]> {\n const { signal, timeout = DEFAULT_COMMAND_TIMEOUT_MS } = options;\n signal?.throwIfAborted();\n // A command sent on no socket used to vanish and surface 10 seconds later\n // as a timeout, which reads like a slow server rather than a usage error.\n if (!this.#canSend(internal)) throw new NotConnectedError();\n\n // Which notifications answer this command, and — for answers that arrive\n // after the `error` — the request field they echo back.\n const parsed = parseCommand(command);\n const spec = responseSpec(parsed?.name ?? \"\");\n const key = spec?.correlated?.key;\n const correlation = key === undefined ? undefined : parsed?.params[key];\n\n const [rc, answered] = this.#cmdTrack.register(spec, correlation);\n let timer: ReturnType<typeof setTimeout> | undefined;\n let onAbort: (() => void) | undefined;\n // Started before the throttle: the timeout bounds the whole command, its\n // wait for a turn included, and so does the signal.\n const givenUp = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new CommandTimeoutError(parsed?.name ?? \"\")), timeout);\n onAbort = () => reject(abortReason(signal!));\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n givenUp.catch(() => {});\n const throttleAbort = new AbortController();\n try {\n const withRc = appendReturnCode(command, rc);\n await Promise.race([this.#throttle.wait(throttleAbort.signal), givenUp]);\n if (!this.#canSend(internal)) throw new NotConnectedError();\n this.#sendLine(withRc);\n\n const result = await Promise.race([answered, givenUp]);\n if (result.err) throw result.err;\n return result.data;\n } finally {\n // A command given up while it waited for its turn gives the turn back.\n throttleAbort.abort();\n // Cleared, not left to fire: a pending timer keeps the process alive for\n // the full timeout after the last command has long been answered.\n clearTimeout(timer);\n if (onAbort) signal?.removeEventListener(\"abort\", onAbort);\n this.#cmdTrack.unregister(rc);\n }\n }\n\n // ---- Events --------------------------------------------------------------\n\n /**\n * Listen for an event. Returns a function that removes the listener.\n *\n * A listener that throws does not stop the others: the rest of the event's\n * listeners, and the events after it, are still delivered, and the exception\n * is rethrown on its own, from a microtask, so it surfaces as an\n * `uncaughtException` just as an EventEmitter listener's would. An async\n * listener's rejection is not caught, and surfaces as an unhandled\n * rejection.\n */\n on<K extends keyof EventMap>(event: K, listener: Listener<K>): Unsubscribe {\n const subscription: Subscription = {\n listener: listener as (payload: unknown) => void,\n removed: false,\n };\n // A new array rather than an edit in place: a delivery may be iterating\n // over the old one.\n this.#listeners.set(event, [...(this.#listeners.get(event) ?? []), subscription]);\n\n const unsubscribe = (): void => {\n if (subscription.removed) return;\n subscription.removed = true;\n const list = this.#listeners.get(event) ?? [];\n this.#listeners.set(\n event,\n list.filter((s) => s !== subscription),\n );\n };\n return Object.assign(unsubscribe, { [Symbol.dispose]: unsubscribe });\n }\n\n /** Listen for the next occurrence of an event only. */\n once<K extends keyof EventMap>(event: K, listener: Listener<K>): Unsubscribe {\n const unsubscribe = this.on(event, ((payload: EventMap[K]) => {\n unsubscribe();\n (listener as (payload: EventMap[K]) => void)(payload);\n }) as Listener<K>);\n return unsubscribe;\n }\n\n /**\n * An event as an async iterator, for `for await`:\n *\n * ```ts\n * for await (const message of client.events(\"textMessage\", { signal })) { … }\n * ```\n *\n * Events that arrive while the loop body runs are buffered, so none is\n * missed — except voice, of which at most 256 frames are buffered; the rest\n * are dropped, as for a listener that falls behind. Iteration ends when\n * `signal` aborts, when the loop exits early (`break`, `return`, a throw),\n * and — for every event but `disconnected` — when the client disconnects.\n * An abort stops listening at once and discards whatever is buffered.\n */\n events<K extends keyof EventMap>(\n event: K,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): AsyncIterableIterator<EventMap[K]> {\n const { signal } = options;\n const buffered: Array<EventMap[K]> = [];\n let wake: (() => void) | undefined;\n let ended = false;\n\n const stopListening = this.on(event, ((payload: EventMap[K]) => {\n if (ended) return;\n if (event === \"voiceData\" && buffered.length >= MAX_PENDING_DELIVERIES) {\n this.#dropVoice();\n return;\n }\n buffered.push(payload);\n wake?.();\n }) as Listener<K>);\n // Ends after what is already buffered, which arrived before the disconnect.\n const stopOnDisconnect =\n event === \"disconnected\"\n ? undefined\n : this.on(\"disconnected\", () => {\n ended = true;\n stopListening();\n wake?.();\n });\n const cleanup = (): void => {\n ended = true;\n stopListening();\n stopOnDisconnect?.();\n signal?.removeEventListener(\"abort\", abort);\n wake?.();\n };\n const abort = (): void => {\n buffered.length = 0;\n cleanup();\n };\n if (signal?.aborted) abort();\n else signal?.addEventListener(\"abort\", abort, { once: true });\n\n const iterator: AsyncIterableIterator<EventMap[K]> = {\n async next(): Promise<IteratorResult<EventMap[K]>> {\n while (buffered.length === 0 && !ended) {\n await new Promise<void>((resolve) => (wake = resolve));\n wake = undefined;\n }\n if (buffered.length > 0) return { value: buffered.shift()!, done: false };\n cleanup();\n return { value: undefined, done: true };\n },\n async return(): Promise<IteratorResult<EventMap[K]>> {\n buffered.length = 0;\n cleanup();\n return { value: undefined, done: true };\n },\n [Symbol.asyncIterator]() {\n return iterator;\n },\n };\n return iterator;\n }\n\n // ---- API shorthand -------------------------------------------------------\n\n /** This client's id on the server, assigned in the handshake; 0 before it. */\n get clientID(): ClientID {\n return asClientID(this.#clid);\n }\n\n /**\n * What the connected server is: version, generation, and the uid hash it\n * uses. Read from `initserver`; before connecting the family is `unknown`\n * and the uid hash SHA-1.\n */\n get serverCapabilities(): ServerCapabilities {\n return this.#capabilities;\n }\n\n /**\n * Our own `client_unique_identifier`, hashed with the algorithm the connected\n * server uses.\n *\n * TS3 uses SHA-1 and TS6 SHA-256, so this reads the algorithm learned during\n * initserver rather than assuming one. Comparing a hard-coded SHA-1 UID to a\n * TS6 server silently never matches.\n */\n get uid(): UID {\n return this.#identity.uid(this.#capabilities.uidAlgorithm);\n }\n\n /** The channel this client is in, as it last learned; 0 before connecting. */\n get channelID(): ChannelID {\n return this.#clients.get(this.#clid)?.channelID ?? asChannelID(0n);\n }\n\n /**\n * Send Opus voice directly to specific clients, bypassing channel routing.\n * Throws a NotConnectedError unless the client is connected.\n */\n sendWhisper(data: Uint8Array, targetClientIDs: readonly ClientID[], codec: Codec): void {\n if (!this.#canSend(false)) throw new NotConnectedError();\n this.#handler.sendWhisperPacket(data, [...targetClientIDs], codec);\n }\n\n /**\n * Send one encoded audio frame to the channel this client is in. Throws a\n * NotConnectedError unless the client is connected.\n */\n sendVoice(data: Uint8Array, codec: Codec): void {\n if (!this.#canSend(false)) throw new NotConnectedError();\n this.#handler.sendVoicePacket(data, codec);\n }\n\n // ---- File Transfer -------------------------------------------------------\n\n /**\n * Upload `data` over a negotiated transfer, through the client's\n * `fileTransferSocketFactory` if it has one.\n */\n uploadFileData(\n host: string,\n info: FileUploadInfo,\n data: Readable,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): Promise<void> {\n return uploadFileData(host, info, data, {\n ...options,\n socketFactory: this.#fileTransferSocketFactory,\n });\n }\n\n /**\n * Download a negotiated transfer into `dest`, through the client's\n * `fileTransferSocketFactory` if it has one.\n */\n downloadFileData(\n host: string,\n info: FileDownloadInfo,\n dest: Writable,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): Promise<void> {\n return downloadFileData(host, info, dest, {\n ...options,\n socketFactory: this.#fileTransferSocketFactory,\n });\n }\n\n // ---- Internal (package-visible) ------------------------------------------\n\n #markConnected(): void {\n // Only the attempt in progress can complete: never one that disconnect()\n // or a failure has already ended.\n if (this.#status !== ClientStatus.Connecting || this.#attempt.settled) return;\n this.#status = ClientStatus.Connected;\n this.#attempt.resolve();\n this.#emit(\"connected\", undefined);\n }\n\n // ---- Private -------------------------------------------------------------\n\n #newHandler(): PacketHandler {\n const handler = new PacketHandler(this.#crypt, this.#logger, this.#socketFactory);\n // Each callback checks that its handler is still the current one: a\n // packet or close reported late by one a later connect() already replaced\n // must not reach, or tear down, the new connection.\n handler.onPacket = (p) => {\n if (handler === this.#handler) this.#handlePacket(p);\n };\n handler.onClosed = (err) => {\n if (handler === this.#handler) this.#handleConnectionClosed(err);\n };\n handler.onReceiveError = (error) => {\n if (handler === this.#handler) this.#handleReceiveError(error);\n };\n return handler;\n }\n\n #resetForConnect(): void {\n this.#handler.close();\n this.#crypt = new Crypt(this.#identity);\n this.#handler = this.#newHandler();\n this.#attempt = newConnectAttempt();\n this.#cmdTrack.reset(new NotConnectedError());\n this.#clients.clear();\n this.#clid = 0;\n this.#capabilities = unknownServerCapabilities();\n }\n\n async #resolveAddr(signal: AbortSignal): Promise<string> {\n // Parsed, not tested for a colon: an IPv6 literal has colons and no port.\n const { host, port } = splitHostPort(this.#addr);\n const fallback = joinHostPort(host, port);\n // Every resolver, a custom one too, gets the same budget: past it the\n // address is used as given. A timer the tests can control, not\n // AbortSignal.timeout().\n const budget = new AbortController();\n const timer = setTimeout(\n () => budget.abort(new TeamspeakError(\"address resolution took too long\")),\n RESOLVE_BUDGET_MS,\n );\n const lookup = AbortSignal.any([signal, budget.signal]);\n try {\n // Raced against the signal: a resolver that ignores it must still not\n // hold up an attempt that has been given up.\n const resolved = await abortable(\n this.#resolver.resolve(this.#addr, { signal: lookup }),\n lookup,\n );\n return resolved[0]?.addr ?? fallback;\n } catch (error) {\n signal.throwIfAborted();\n this.#logger.warn(\"address resolution failed, falling back to direct\", {\n error: String(budget.signal.aborted ? budget.signal.reason : error),\n });\n return fallback;\n } finally {\n clearTimeout(timer);\n }\n }\n\n /**\n * A datagram from the server could not be handled. During the handshake that\n * is the connection failing, reported as a CryptoInitError with the cause;\n * once connected, one bad packet is not worth the session, so it is dropped.\n */\n #handleReceiveError(error: unknown): void {\n if (this.#status !== ClientStatus.Connected) {\n this.#failConnection(\n error instanceof CryptoInitError\n ? error\n : new CryptoInitError(\"the handshake failed on a malformed packet\", { cause: error }),\n );\n return;\n }\n this.#logger.debug(\"dropped a malformed packet\", { error: String(error) });\n }\n\n #handlePacket(p: Packet): void {\n const pType = p.typeFlagged & 0x0f;\n if (pType === 8 /* Init1 */) {\n if (this.#crypt.cryptoInitComplete) return;\n const response = processInit1(this.#crypt, p.data);\n if (response) {\n this.#handler.sendPacket(PacketType.Init1, response, 0);\n }\n return;\n }\n\n if ((pType === 0 /* Voice */ || pType === 1) /* VoiceWhisper */ && p.data.length > 5) {\n this.#handleVoicePacket(p.data);\n return;\n }\n\n if ((pType === 2 /* Command */ || pType === 3) /* CommandLow */ && p.data.length > 0) {\n this.#handleCommandLines(Buffer.from(p.data).toString(\"utf8\"));\n }\n }\n\n /**\n * Parse an incoming S2C voice packet.\n * Format: [VId: u16] [CId: u16] [Codec: u8] [Data: var]\n */\n #handleVoicePacket(payload: Uint8Array): void {\n // Audio arrives fifty times a second per speaker; build no event nobody\n // will see.\n if (!this.#listeners.get(\"voiceData\")?.length && this.#eventMiddlewares.length === 0) return;\n if (this.#queue.length > MAX_PENDING_DELIVERIES) {\n this.#dropVoice();\n return;\n }\n\n const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);\n const clientId = view.getUint16(2, false);\n if (clientId === this.#clid) return;\n\n // Copied: the packet's buffer is reused once this returns, and a listener\n // runs later.\n const data = payload.slice(5);\n this.#emitServerEvent({\n name: \"voiceData\",\n payload: { clientID: asClientID(clientId), codec: payload[4]!, data },\n });\n }\n\n #handleCommandLines(s: string): void {\n if (!s) return;\n const lines = s.split(\"\\0\").join(\"\\n\").split(\"\\n\");\n for (const line of lines) {\n const trimmed = line.replace(/\\r$/, \"\");\n if (!trimmed) continue;\n for (const row of splitCommandRows(trimmed)) {\n this.#handleCommandStr(row);\n }\n }\n }\n\n #handleCommandStr(s: string): void {\n const cmd = parseCommand(s);\n if (!cmd) return;\n // Before crypto init a packet needs only the public dummy key, so anyone\n // on the path could have sent it: nothing but the handshake's own steps,\n // and an error that may end the attempt, is taken then. A notification\n // would be a forged event, a row a forged answer.\n if (!this.#crypt.cryptoInitComplete && !PRE_INIT_COMMANDS.has(cmd.name)) {\n this.#logger.debug(\"dropped a command that arrived before crypto init\", {\n command: cmd.name,\n });\n return;\n }\n if (packetChannel.hasSubscribers) packetChannel.publish({ command: cmd.name, client: this });\n\n // No name means a response row: the server sends data without echoing the\n // command, so the row belongs to whichever command is awaiting a result.\n if (cmd.name === \"\") {\n if (Object.keys(cmd.params).length > 0) this.#cmdTrack.buffer(cmd.params);\n return;\n }\n\n // `channellistfinished` ends the server's welcome sequence. It carries no\n // data of its own, so it is the only reliable marker: the guard used to\n // trip on our own notifycliententerview, which the server sends *in the\n // middle* of the sequence — the channellist rows after it were then\n // buffered as if they were the response to the caller's first command,\n // which is how a channellist could come back with duplicate and empty rows.\n if (cmd.name === \"channellistfinished\") {\n this.#cmdTrack.signalWelcomeComplete();\n return;\n }\n\n if (cmd.name.startsWith(\"notify\")) {\n // Some commands are answered by a notification instead of data rows;\n // it still goes on to be dispatched as an event, since the same\n // notification also arrives unprompted.\n if (this.#cmdTrack.expects(cmd.name)) {\n this.#cmdTrack.buffer(cmd.params, cmd.name);\n this.#cmdTrack.offerCorrelated(cmd.name, cmd.params);\n }\n const result = handleNotification(cmd, this.#clid, this.#clients, this.#nickname);\n this.#processNotificationResult(result);\n if (this.#listeners.get(\"notification\")?.length || this.#eventMiddlewares.length > 0) {\n this.#emitServerEvent({\n name: \"notification\",\n payload: { name: cmd.name, params: { ...cmd.params } },\n });\n }\n return;\n }\n\n switch (cmd.name) {\n // The handshake's steps happen once: repeated after crypto init, they\n // could only re-key or re-announce a session that is already set up.\n case \"clientinitiv\":\n if (!this.#crypt.cryptoInitComplete) handleHandshakeInitIV(this.#internals, cmd.params);\n break;\n case \"initivexpand2\":\n if (!this.#crypt.cryptoInitComplete) handleHandshakeExpand2(this.#internals, cmd.params);\n break;\n case \"initserver\":\n // Only on a session with its keys: before crypto init a packet needs\n // nothing but the public dummy key, and an initserver taken then would\n // report a connection whose next command — clientinit with its password\n // hashes among them — goes out under that dummy key.\n if (this.#status === ClientStatus.Connecting && this.#crypt.cryptoInitComplete) {\n handleInitServer(this.#internals, cmd.params);\n }\n break;\n case \"error\":\n this.#handleError(cmd.params);\n break;\n default:\n // A named command the SDK does not model. Held under its own name, so\n // it answers a command only if that command declared it — not merely by\n // arriving while one is in flight.\n this.#cmdTrack.buffer(cmd.params, cmd.name);\n break;\n }\n }\n\n #handleError(params: Record<string, string>): void {\n const { err, rc } = parseServerError(params);\n if (rc !== null) {\n this.#cmdTrack.resolve(rc, err);\n } else {\n // No return_code: server is acknowledging an unsolicited command\n // (welcome-sequence channellist, no-RC commands like clientupdate, etc.).\n // Discard any rows buffered since the last resolved command.\n this.#cmdTrack.discardBuffer();\n }\n\n // A server error before the welcome sequence finished is the connection\n // failure itself — a rejected password, or an invalid clientinit parameter.\n // Report it as the cause instead of leaving the caller with a bare timeout.\n if (err && this.#status !== ClientStatus.Connected) {\n this.#failConnection(err);\n return;\n }\n\n // Only a connected session gets here, so only after crypto init: an error\n // under the public dummy key can fail an attempt, never stop the client.\n if (err?.code === ErrorCode.ConnectFailedBanned) {\n this.#logger.warn(\"banned by the server, closing the connection\");\n setImmediate(() => this.disconnect().catch(() => {}));\n }\n }\n\n #processNotificationResult(result: import(\"./notifications.js\").NotificationResult): void {\n switch (result.kind) {\n case \"clientEnter\": {\n const info = result.info;\n // Identify self by the clid initserver already assigned rather than by\n // nickname: any other client whose nickname happens to be \"<our\n // nick><digits>\" — which is how the server renames a client whose\n // nickname was taken — would otherwise be mistaken for us, poisoning\n // every outgoing packet header with a foreign clientID until the server\n // drops the connection for command-resend timeout.\n //\n // This no longer marks the end of the welcome sequence: the server\n // sends more welcome data after it, and `channellistfinished` is the\n // real terminator.\n if (info.id === this.#clid) {\n // Carries the rename the server applied if our nickname was taken.\n this.#nickname = info.nickname;\n } else if (this.#clid === 0 && isAutoNicknameMatch(this.#nickname, info.nickname)) {\n // initserver carried no aclid, so the welcome enter is the only way\n // to learn our clid. Gated on clid still being unknown so a later\n // lookalike can never hijack an established session.\n this.#clid = info.id;\n this.#handler.setClientID(info.id);\n this.#nickname = info.nickname;\n }\n this.#emitServerEvent({ name: \"clientEnter\", payload: info });\n break;\n }\n case \"clientLeave\": {\n const event = result.event;\n this.#emitServerEvent({ name: \"clientLeave\", payload: event });\n if (!result.isSelf) break;\n if (event.reason === Reason.KickServer || event.reason === Reason.KickServerBan) {\n this.#emit(\"kicked\", kickedEvent(event));\n }\n this.#removedByServer(\n new RemovedError(event.reason, event.reasonMessage, event.invokerName),\n );\n break;\n }\n case \"clientMoved\":\n this.#emitServerEvent({ name: \"clientMoved\", payload: result.event });\n // A channel kick moves the client to the default channel; it arrives\n // as a move, not as leaving view, which is where it used to be looked\n // for.\n if (result.event.clientID === this.#clid && result.event.reason === Reason.KickChannel) {\n this.#emit(\n \"kicked\",\n kickedEvent({ ...result.event, reasonMessage: result.reasonMessage }),\n );\n }\n break;\n case \"textMessage\":\n this.#emitServerEvent({ name: \"textMessage\", payload: result.message });\n break;\n case \"poked\":\n this.#emitServerEvent({ name: \"poked\", payload: result.event });\n break;\n }\n }\n\n /**\n * End a session the server has ended. The server stops answering a client it\n * has removed, so waiting for the transport to notice reported the end a\n * minute late, without its cause, and with the client claiming to be\n * connected meanwhile.\n */\n #removedByServer(cause: Error): void {\n this.#handleConnectionClosed(cause);\n this.#handler.close();\n }\n\n /**\n * Count a dropped voice delivery, and report the drops now and then: at most\n * once every ten seconds, with how many were dropped since the last report.\n */\n #dropVoice(): void {\n this.#voiceDropped++;\n const now = Date.now();\n if (now - this.#voiceDropWarnedAt < VOICE_DROP_WARN_INTERVAL_MS) return;\n this.#voiceDropWarnedAt = now;\n // The count since the last warning, so each one says how bad it is now.\n this.#logger.warn(\"voice dropped: listeners are not keeping up\", {\n dropped: this.#voiceDropped,\n });\n this.#voiceDropped = 0;\n }\n\n /** Queue a server event, through the event middleware. */\n #emitServerEvent(event: ServerEvent): void {\n this.#enqueue(() => this.#eventChain(event));\n }\n\n /**\n * Queue `disconnected`; the promise settles once it has been delivered, and\n * a connect() waits for it until then.\n */\n #announceDisconnected(cause: Error | undefined): Promise<void> {\n const delivered = new Promise<void>((resolve) =>\n this.#enqueue(() => {\n try {\n this.#deliver(\"disconnected\", cause);\n } finally {\n resolve();\n }\n }),\n );\n this.#disconnectedDelivered = delivered;\n void delivered.then(() => {\n if (this.#disconnectedDelivered === delivered) this.#disconnectedDelivered = undefined;\n });\n return delivered;\n }\n\n /** Queue a lifecycle event, which middleware does not see. */\n #emit<K extends Exclude<keyof EventMap, ServerEventName>>(event: K, payload: EventMap[K]): void {\n this.#enqueue(() => this.#deliver(event, payload));\n }\n\n #deliver<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n for (const subscription of this.#listeners.get(event) ?? []) {\n // Checked at delivery: a listener removed while its event was queued\n // does not get it.\n if (subscription.removed) continue;\n try {\n subscription.listener(payload);\n } catch (error) {\n // Rethrown on its own, as an uncaught exception, so it surfaces as one\n // from an EventEmitter listener would, and the listeners after it\n // still get the event.\n queueMicrotask(() => {\n throw error;\n });\n }\n }\n }\n\n /**\n * Run deliveries one at a time, in order, once the packet being handled is\n * done with. A listener that throws does so as an uncaught exception, as it\n * would from an EventEmitter, and the listeners and deliveries behind it\n * still run.\n */\n #enqueue(delivery: () => void): void {\n this.#queue.push(delivery);\n if (this.#draining) return;\n this.#draining = true;\n setImmediate(this.#drain);\n }\n\n #drain = (): void => {\n try {\n while (this.#queue.length > 0) this.#queue.shift()!();\n } finally {\n if (this.#queue.length > 0) setImmediate(this.#drain);\n else this.#draining = false;\n }\n };\n\n #handleConnectionClosed(err: Error | null): void {\n if (this.#status === ClientStatus.Disconnected) return;\n // Nothing in flight can be answered any more; failing it now, with the\n // reason, beats every caller timing out one by one.\n this.#cmdTrack.reset(new NotConnectedError(err ? { cause: err } : undefined));\n if (this.#status !== ClientStatus.Connected) {\n // The socket closed before the handshake finished, so this is a failed\n // connection attempt rather than a disconnect of a live session.\n this.#failConnection(\n err ?? new TeamspeakError(\"connection closed before the TeamSpeak handshake completed\"),\n );\n return;\n }\n this.#status = ClientStatus.Disconnected;\n // Never undefined for a drop: undefined means disconnect() only.\n const cause = err ?? new TeamspeakError(\"connection closed\");\n this.#lastDrop = cause;\n\n // Announced first, then retried: a caller watching `disconnected` should\n // hear about the drop even when a reconnect is already on its way, because\n // a silent recovery hides an outage.\n void this.#announceDisconnected(cause);\n this.#scheduleReconnect(cause).catch((error: unknown) => {\n this.#logger.error(\"reconnecting failed\", { error: String(error) });\n });\n }\n\n /**\n * Retry a dropped connection according to the reconnect policy.\n *\n * Never runs after an explicit disconnect, and never more than one at a time:\n * two failures in quick succession would otherwise start competing loops, and\n * a loop shorter than the server's antiflood window bans the IP rather than\n * reconnecting it. A drop while the loop runs is the loop's to retry: it\n * ends only once its attempt is still connected when it resumes.\n */\n async #scheduleReconnect(err: Error): Promise<void> {\n const options = this.#reconnectOptions;\n if (options === undefined || this.#stopped || this.#reconnecting) return;\n\n const policy = resolveBackoffPolicy(options);\n const shouldRetry = options.shouldRetry ?? defaultShouldRetry;\n\n this.#reconnecting = true;\n\n const stop = new AbortController();\n this.#stopReconnecting = stop;\n try {\n for (let attempt = 1; policy.maxAttempts === 0 || attempt <= policy.maxAttempts; attempt++) {\n if (this.#stopped) return;\n let retry: boolean;\n try {\n retry = shouldRetry(err, attempt);\n } catch (error) {\n this.#logger.error(\"shouldRetry threw; not reconnecting\", { error: String(error) });\n return;\n }\n if (!retry) {\n this.#logger.info(\"not retrying\", { attempt, reason: err.message });\n return;\n }\n\n const delay = backoffDelay(policy, attempt);\n this.#logger.info(\"reconnecting\", { attempt, delayMs: delay });\n // A timer that keeps the process alive: an application that does\n // nothing but stay connected would otherwise exit during the wait.\n await sleep(delay, stop.signal);\n if (this.#stopped) return;\n // Connected, or connecting, by hand during the wait: nothing is left to\n // retry, and an attempt now would only fail with AlreadyConnectedError.\n if (this.#status !== ClientStatus.Disconnected) {\n this.#logger.info(\"reconnect loop ended: connected by other means\", { attempt });\n return;\n }\n\n try {\n await this.connect({ signal: AbortSignal.timeout(RECONNECT_ATTEMPT_TIMEOUT_MS) });\n // Read afresh: the status may have changed while connect() resolved.\n if (this.status === ClientStatus.Connected) {\n this.#logger.info(\"reconnected\", { attempt });\n return;\n }\n // The new session dropped before this loop resumed — initserver and\n // the server's goodbye in one datagram, say. That drop found this\n // loop running and left the retrying to it.\n err = this.#lastDrop ?? new TeamspeakError(\"connection closed\");\n } catch (retryErr) {\n if (retryErr instanceof AlreadyConnectedError) return;\n err = retryErr instanceof Error ? retryErr : new TeamspeakError(String(retryErr));\n }\n }\n this.#logger.warn(\"reconnect attempts exhausted\", { attempts: policy.maxAttempts });\n } finally {\n this.#reconnecting = false;\n if (this.#stopReconnecting === stop) this.#stopReconnecting = undefined;\n }\n }\n\n /**\n * A connection attempt has failed for good: settle it with the cause, and\n * tear the connection down. Does nothing once the handshake has completed,\n * so it cannot end a live session.\n *\n * Without this, a handshake the server rejects (a wrong password, say, which\n * the server answers with an error instead of closing the socket) surfaces\n * only as the caller's own timeout, and the client stays in `Connecting`\n * forever without ever emitting `disconnected`.\n */\n #failConnection(error: unknown): void {\n if (this.#status === ClientStatus.Connected) return;\n this.#attempt.reject(error);\n\n if (this.#status === ClientStatus.Disconnected) return;\n this.#status = ClientStatus.Disconnected;\n this.#handler.close();\n void this.#announceDisconnected(\n error instanceof Error ? error : new TeamspeakError(String(error)),\n );\n }\n}\n\nfunction kickedEvent(event: {\n readonly reason: number;\n readonly reasonMessage: string;\n readonly invokerName: string;\n readonly invokerUID: UID;\n readonly invokerID: ClientID;\n}): KickedEvent {\n return {\n reason: event.reason,\n reasonMessage: event.reasonMessage,\n invokerName: event.invokerName,\n invokerUID: event.invokerUID,\n invokerID: event.invokerID,\n };\n}\n","/**\n * Commands only the voice protocol has.\n *\n * ServerQuery has no subscriptions — a query client hears every channel's\n * events once it registers for them — and no `channelgetdescription`, since its\n * `channelinfo` already carries the description. These run on the voice\n * client alone, which is why they take one rather than any CommandExecutor.\n */\n\nimport type { Client } from \"../client.js\";\nimport type { ChannelID, CommandOptions } from \"@honeybbq/teamspeak-core\";\n\n/** The channel's description, which `listChannels` omits for bandwidth. */\nexport async function getChannelDescription(\n client: Client,\n cid: ChannelID,\n options?: CommandOptions,\n): Promise<string> {\n const rows = await client.send(\n { command: \"channelgetdescription\", params: [[\"cid\", cid]] },\n options,\n );\n return rows[0]?.[\"channel_description\"] ?? \"\";\n}\n\n/**\n * Subscribe to a channel: receive its clients' events and voice without\n * joining it.\n */\nexport async function subscribeChannel(\n client: Client,\n cid: ChannelID,\n options?: CommandOptions,\n): Promise<void> {\n await client.send({ command: \"channelsubscribe\", params: [[\"cid\", cid]] }, options);\n}\n\n/** Stop receiving a subscribed channel's events and voice. */\nexport async function unsubscribeChannel(\n client: Client,\n cid: ChannelID,\n options?: CommandOptions,\n): Promise<void> {\n await client.send({ command: \"channelunsubscribe\", params: [[\"cid\", cid]] }, options);\n}\n\n/** Subscribe to every channel on the server. */\nexport async function subscribeAllChannels(\n client: Client,\n options?: CommandOptions,\n): Promise<void> {\n await client.send({ command: \"channelsubscribeall\" }, options);\n}\n\n/** Unsubscribe from every channel on the server. */\nexport async function unsubscribeAllChannels(\n client: Client,\n options?: CommandOptions,\n): Promise<void> {\n await client.send({ command: \"channelunsubscribeall\" }, options);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["base64UrlToBytes"],"sources":["../src/types.ts","../src/errors.ts","../src/abort.ts","../src/crypto/identity.ts","../src/crypto/eax.ts","../src/crypto/crypt.ts","../src/crypto/primitives.ts","../src/address.ts","../src/discovery/resolver.ts","../src/transport/packet.ts","../src/transport/generation-window.ts","../src/transport/quicklz.ts","../src/handshake/crypt-handshake.ts","../src/transport/handler.ts","../src/commands.ts","../src/transfer.ts","../src/events.ts","../src/capabilities.ts","../src/handshake/license.ts","../src/handshake/crypt-init2.ts","../src/handshake.ts","../src/notifications.ts","../src/throttle.ts","../src/helpers.ts","../src/diagnostics.ts","../src/reconnect.ts","../src/client.ts","../src/api/voice.ts"],"sourcesContent":["import type {\n ClientEnterEvent,\n ClientLeaveEvent,\n ClientMovedEvent,\n CommandMiddleware,\n KickedEvent,\n Logger,\n NotificationEvent,\n PokeEvent,\n TextMessageEvent,\n VoiceDataEvent,\n} from \"@honeybbq/teamspeak-core\";\nimport type { Duplex } from \"node:stream\";\nimport type { ReconnectOptions } from \"./reconnect.js\";\n\n// ---- Events ---------------------------------------------------------------\n\n/**\n * The events `Client.on()` takes, and what each delivers. May gain events in a\n * minor release; code that handles every event generically should expect\n * names it does not know.\n */\nexport interface EventMap {\n /** A text message to this client, its channel or the server. */\n textMessage: TextMessageEvent;\n /** A client coming into view, including every client already there on connecting. */\n clientEnter: ClientEnterEvent;\n /** A client going out of view. */\n clientLeave: ClientLeaveEvent;\n /** A client changing channel. */\n clientMoved: ClientMovedEvent;\n /** This client being poked. */\n poked: PokeEvent;\n /**\n * Audio from another client. Only decoded with a listener or event\n * middleware. Voice is dropped, counted and reported in a warning at most\n * every ten seconds, while more than 256 deliveries are waiting: a listener\n * that cannot keep up loses audio rather than memory.\n */\n voiceData: VoiceDataEvent;\n /**\n * Every notification the server sends, modelled or not, after any event it\n * produces.\n */\n notification: NotificationEvent;\n /** The handshake completing, on `connect()` and on every reconnection. */\n connected: void;\n /**\n * `undefined` after `disconnect()`, and the cause otherwise: a failed\n * handshake, a `ConnectionTimeoutError`, or a `RemovedError` for a kick, a\n * ban or a server stopping.\n */\n disconnected: Error | undefined;\n /** A kick from the server also ends the connection, which `disconnected` reports. */\n kicked: KickedEvent;\n}\n\n/**\n * The events that come from the server, and so pass through event middleware.\n * May gain members in a minor release: a `switch` over an event's name needs\n * a default case.\n */\nexport type ServerEventName =\n | \"textMessage\"\n | \"clientEnter\"\n | \"clientLeave\"\n | \"clientMoved\"\n | \"poked\"\n | \"voiceData\"\n | \"notification\";\n\n/** A server event as event middleware sees it. */\nexport type ServerEvent = {\n [K in ServerEventName]: { readonly name: K; readonly payload: EventMap[K] };\n}[ServerEventName];\n\n/** A listener for one event. */\nexport type Listener<K extends keyof EventMap> = EventMap[K] extends void\n ? () => void\n : (payload: EventMap[K]) => void;\n\n/** Removes a listener; calling it again does nothing. Also a `Disposable`, for `using`. */\nexport type Unsubscribe = (() => void) & Disposable;\n\n// ---- Transport seam ---------------------------------------------------------\n\n/**\n * The part of a UDP socket the client uses. A `node:dgram` socket is one; so\n * is anything else with these methods, such as a tunnel or a test double.\n *\n * Should a later release use more of a socket, the new members will be\n * optional here, so an implementation of this interface keeps compiling.\n */\nexport interface DatagramSocket {\n /** Fix the peer, then call `callback`; failure is reported as an `error` event. */\n connect(port: number, address: string, callback: () => void): void;\n /** Send one datagram to the peer. */\n send(data: Uint8Array, callback: (error: Error | null) => void): void;\n /** Close the socket; it then emits `close`. */\n close(): void;\n /** Listen for each datagram received. */\n on(event: \"message\", listener: (message: Uint8Array) => void): unknown;\n /** Listen for a failure, which ends the connection. */\n on(event: \"error\", listener: (error: Error) => void): unknown;\n /** Listen for the socket closing. */\n on(event: \"close\", listener: () => void): unknown;\n /** Listen for the next failure only, while connecting. */\n once(event: \"error\", listener: (error: Error) => void): unknown;\n /** Stop listening for failures. */\n off(event: \"error\", listener: (error: Error) => void): unknown;\n}\n\n/** Creates the UDP socket the client talks through, for the given address family. */\nexport type SocketFactory = (family: 4 | 6) => DatagramSocket;\n\n/**\n * Opens the connection a file transfer runs over, to `host:port`. A\n * `node:net` socket is one, as is the socket a SOCKS or HTTP proxy library\n * returns. It may still be connecting when returned: the transfer waits for\n * it.\n */\nexport type FileTransferSocketFactory = (host: string, port: number) => Duplex;\n\n// ---- Client status ----------------------------------------------------------\n\n/** The values of the table below, before freezing. */\nconst clientStatusValues = {\n /** Not connected: before `connect()`, after `disconnect()`, or after a drop. */\n Disconnected: \"disconnected\",\n /** Connecting: `connect()` is waiting for the handshake. */\n Connecting: \"connecting\",\n /** Connected: the handshake completed and commands can be sent. */\n Connected: \"connected\",\n} as const;\n/** Where a client is in its connection's life. */\nexport const ClientStatus: typeof clientStatusValues =\n /* @__PURE__ */ Object.freeze(clientStatusValues);\n/**\n * One of {@link ClientStatus}. May gain members in a minor release: a\n * `switch` over it needs a default case.\n */\nexport type ClientStatus = (typeof ClientStatus)[keyof typeof ClientStatus];\n\n/** Wraps the delivery of server events; it may observe, alter or drop them. */\nexport type EventMiddleware = (next: (event: ServerEvent) => void) => (event: ServerEvent) => void;\n\n// ---- Resolved address (from discovery) --------------------------------------\n\n/**\n * An address a server's name resolved to. Only `addr` is needed to connect;\n * the rest describes the answer.\n */\nexport interface ResolvedAddr {\n /** The endpoint, as `host:port`. */\n readonly addr: string;\n /** How it was found, such as `SRV`, `TSDNS-SRV`, `TSDNS-Direct` or `Direct`. */\n readonly source?: string | undefined;\n /** When the answer stops being valid; unset for no stated lifetime. */\n readonly expiry?: Date | undefined;\n}\n\n// ---- AddrResolver interface -------------------------------------------------\n\n/**\n * Turns the address a client was given — a host, `host:port`, or a TeamSpeak\n * name — into endpoints to connect to. The default follows SRV records and\n * TSDNS, as the TeamSpeak application does.\n */\nexport interface AddrResolver {\n /**\n * The endpoints for `addr`, best first. An empty answer falls back to `addr`\n * itself. `signal` aborts when the connection attempt is given up, or once\n * resolution has taken 10 seconds, after which the client connects to\n * `addr` as given; a resolver that ignores it is abandoned all the same.\n */\n resolve(\n addr: string,\n options?: { readonly signal?: AbortSignal | undefined },\n ): Promise<readonly ResolvedAddr[]>;\n}\n\n// ---- ClientOptions ----------------------------------------------------------\n\n/** How a `Client` connects, logs and behaves; every field is optional. */\nexport interface ClientOptions {\n /** Where the client logs. Silent unless set: a library has no business writing to the console. */\n readonly logger?: Logger | undefined;\n /**\n * Creates the UDP socket the client talks through, given the address family\n * the server's address resolved to.\n *\n * Supplying one lets an application route traffic through a proxy or tunnel,\n * or drive the client from something other than a real socket. It is the only\n * seam into the transport: without it the SDK always creates its own.\n */\n readonly socketFactory?: SocketFactory | undefined;\n /**\n * Reconnect after a dropped connection.\n *\n * Off by default: a silent reconnect makes an outage look like an ordinary\n * session. An explicit `disconnect()` never reconnects regardless.\n */\n readonly reconnect?: ReconnectOptions | undefined;\n /**\n * Creates the TCP socket a file transfer runs over.\n *\n * Separate from `socketFactory` because file transfer dials its own\n * connection to a different port, on demand. Set both to route everything\n * through a proxy.\n */\n readonly fileTransferSocketFactory?: FileTransferSocketFactory | undefined;\n /**\n * Look a dot-less address up as a server nickname at named.myteamspeak.com,\n * as the TeamSpeak application does. Off by default, since it sends the name\n * to a third party; without it a dot-less name is resolved like any host.\n * Ignored with a custom `resolver`.\n */\n readonly resolveNicknames?: boolean | undefined;\n /** Replaces the SRV and TSDNS resolution `connect()` performs. */\n readonly resolver?: AddrResolver | undefined;\n /**\n * Wraps every typed command, outermost first; see `CommandMiddleware`. Raw\n * lines sent with `exec` and `execNoWait` do not pass through it. Fixed for\n * the client's life.\n */\n readonly commandMiddleware?: readonly CommandMiddleware[] | undefined;\n /** Wraps the delivery of every server event, outermost first. Fixed for the client's life. */\n readonly eventMiddleware?: readonly EventMiddleware[] | undefined;\n /** Server password sent during the initial `clientinit` handshake. */\n readonly serverPassword?: string | undefined;\n /** Default channel name to join during the initial `clientinit` handshake. */\n readonly defaultChannel?: string | undefined;\n /** Password for `defaultChannel`, sent during the initial `clientinit` handshake. */\n readonly defaultChannelPassword?: string | undefined;\n}\n","import { Reason, TeamspeakError } from \"@honeybbq/teamspeak-core\";\n\n/** `connect()` was called on a client that is connecting or connected. */\nexport class AlreadyConnectedError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"AlreadyConnectedError\";\n\n constructor() {\n super(\"already connecting or connected\");\n this.name = \"AlreadyConnectedError\";\n }\n}\n\n/**\n * The address a client was given cannot be connected to: no host, a host with\n * characters no host name or IP address has, or a port outside 1–65535.\n * `connect()` rejects with it before it starts, and the client stays\n * disconnected. A name that does not resolve is not this: that fails with a\n * TeamspeakError whose `cause` is the lookup's error, since DNS failures are\n * often transient.\n */\nexport class InvalidAddressError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"InvalidAddressError\";\n\n /** The address as given. */\n readonly address: string;\n\n constructor(address: string, reason: string) {\n super(`invalid address ${JSON.stringify(address)}: ${reason}`);\n this.name = \"InvalidAddressError\";\n this.address = address;\n }\n}\n\n/**\n * A packet failed authentication: it was corrupted, or not from the server.\n * Internal: the packet is dropped, and this never reaches a caller.\n */\nexport class EAXTagMismatchError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"EAXTagMismatchError\";\n\n constructor() {\n super(\"EAX tag mismatch\");\n this.name = \"EAXTagMismatchError\";\n }\n}\n\n/**\n * An unencrypted packet failed its integrity check. Internal: the packet is\n * dropped, and this never reaches a caller.\n */\nexport class FakeSignatureMismatchError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"FakeSignatureMismatchError\";\n\n constructor() {\n super(\"fake signature mismatch\");\n this.name = \"FakeSignatureMismatchError\";\n }\n}\n\n/** A file transfer connection failed: it could not be opened, or broke during the transfer. */\nexport class FileTransferError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"FileTransferError\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"FileTransferError\";\n }\n}\n\n/**\n * The handshake failed on what the server sent: a malformed or out-of-range\n * Init1 step, public key, license or proof. `connect()` rejects with it, the\n * underlying failure as its `cause`.\n */\nexport class CryptoInitError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"CryptoInitError\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"CryptoInitError\";\n }\n}\n\n/** An identity string `parseIdentity()` cannot read. */\nexport class InvalidIdentityError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"InvalidIdentityError\";\n\n constructor(message = \"invalid identity format\", options?: ErrorOptions) {\n super(message, options);\n this.name = \"InvalidIdentityError\";\n }\n}\n\n/**\n * The server stopped answering: nothing arrived, or a packet went\n * unacknowledged, for a minute.\n */\nexport class ConnectionTimeoutError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"ConnectionTimeoutError\";\n\n constructor() {\n super(\"connection timed out: the server stopped answering\");\n this.name = \"ConnectionTimeoutError\";\n }\n}\n\n/**\n * The server ended this client's session: a kick, a ban, or the server\n * stopping. The default reconnect policy retries a server that stopped, but\n * not a kick or a ban.\n */\nexport class RemovedError extends TeamspeakError {\n /** {@inheritDoc TeamspeakError.kind} */\n static override readonly kind: string = \"RemovedError\";\n\n /** Why: `Reason.KickServer`, `KickServerBan`, `ServerStop` or `ServerShutdown`. */\n readonly reason: number;\n /** The reason the server or the invoker gave, if any. */\n readonly reasonMessage: string;\n /** Who removed the client, for a kick or a ban. */\n readonly invokerName: string;\n\n constructor(reason: number, reasonMessage: string, invokerName: string) {\n let message = `removed from the server: ${reasonName(reason)}`;\n if (invokerName) message += ` by ${invokerName}`;\n if (reasonMessage) message += `: ${reasonMessage}`;\n super(message);\n this.name = \"RemovedError\";\n this.reason = reason;\n this.reasonMessage = reasonMessage;\n this.invokerName = invokerName;\n }\n}\n\nfunction reasonName(reason: number): string {\n switch (reason) {\n case Reason.KickServer:\n return \"kicked from server\";\n case Reason.KickServerBan:\n return \"banned from server\";\n case Reason.ServerStop:\n return \"server stopped\";\n case Reason.ServerShutdown:\n return \"server shut down\";\n default:\n return `reason ${reason}`;\n }\n}\n","/** The reason an aborted signal gives, as an error. */\nexport function abortReason(signal: AbortSignal): unknown {\n return signal.reason ?? new DOMException(\"This operation was aborted\", \"AbortError\");\n}\n\n/** Settle with `promise`, or reject as soon as `signal` aborts, whichever is first. */\nexport function abortable<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return promise;\n if (signal.aborted) return Promise.reject(abortReason(signal));\n return new Promise<T>((resolve, reject) => {\n const onAbort = (): void => reject(abortReason(signal));\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error);\n },\n );\n });\n}\n","import {\n createHash,\n createECDH,\n generateKeyPairSync,\n createPrivateKey,\n createPublicKey,\n type KeyObject,\n} from \"node:crypto\";\nimport { InvalidIdentityError } from \"../errors.js\";\nimport { asUID, type UID } from \"@honeybbq/teamspeak-core\";\n\nconst P256_SCALAR_SIZE = 32;\nconst P256_UNCOMPRESSED_KEY_SIZE = 65;\nconst P256_POINT_PREFIX = 0x04;\n\n/** The most a security level can be: SHA-1 is 160 bits wide. */\nconst MAX_SECURITY_LEVEL = 160;\n\nlet createIdentity: (privateKey: KeyObject, offset: bigint) => Identity;\nlet privateKeyOf: (identity: Identity) => KeyObject;\n\n/**\n * A TeamSpeak client identity: a P-256 key pair plus a counter, the offset,\n * whose hash with the public key sets the identity's security level.\n *\n * Immutable: raising the level returns a new identity. Opaque: the private\n * key is never exposed, and `toString()`, `toJSON()` and `util.inspect()`\n * describe the identity without it, so an identity that reaches a log or an\n * error message does not leak; `export()` is the one way to get the secret\n * form, for storing it. Make one with `generateIdentity()` or\n * `parseIdentity()`.\n */\nexport class Identity {\n static {\n createIdentity = (privateKey, offset) => new Identity(privateKey, offset);\n privateKeyOf = (identity) => identity.#privateKey;\n }\n\n readonly #privateKey: KeyObject;\n readonly #offset: bigint;\n #publicKey: string | undefined;\n\n private constructor(privateKey: KeyObject, offset: bigint) {\n this.#privateKey = privateKey;\n this.#offset = offset;\n }\n\n /** The counter whose hash with the public key sets the security level. */\n get offset(): bigint {\n return this.#offset;\n }\n\n /** The public key in TeamSpeak's encoding: base64 of its DER form. */\n publicKey(): string {\n if (this.#publicKey !== undefined) return this.#publicKey;\n const rawJwk = this.#privateKey.export({ format: \"jwk\" });\n if (typeof rawJwk.x !== \"string\" || typeof rawJwk.y !== \"string\") return \"\";\n\n const xBytes = base64UrlToBytes(rawJwk.x, P256_SCALAR_SIZE);\n const yBytes = base64UrlToBytes(rawJwk.y, P256_SCALAR_SIZE);\n // Encode as TS3 canonical ASN.1: SEQUENCE { BIT STRING, INTEGER(32), INTEGER(x), INTEGER(y) }\n this.#publicKey = encodeTsPublicKey(xBytes, yBytes);\n return this.#publicKey;\n }\n\n /**\n * The identity's unique identifier, hashed with `algorithm`: SHA-1 for a\n * TeamSpeak 3 server, SHA-256 for TeamSpeak 6. A connected client's `uid`\n * already uses the one its server does.\n */\n uid(algorithm: UIDAlgorithm): UID {\n return uidFromPublicKey(this.publicKey(), algorithm);\n }\n\n /**\n * The identity in the form `parseIdentity()` reads, private key included.\n * Store it as you would a password.\n */\n export(): string {\n const jwk = this.#privateKey.export({ format: \"jwk\" }) as { d?: string };\n if (!jwk.d) return `:${this.#offset}`;\n const dBytes = base64UrlToBytes(jwk.d, P256_SCALAR_SIZE);\n return `${Buffer.from(dBytes).toString(\"base64\")}:${this.#offset}`;\n }\n\n /** Describes the identity, by its SHA-1 unique identifier, without its private key. */\n toString(): string {\n return `identity ${this.uid(\"sha1\")} (private key redacted)`;\n }\n\n /** The same as `toString()`, so serialising an identity cannot leak its key. */\n toJSON(): string {\n return this.toString();\n }\n\n /** The security level: trailing zero bits in SHA-1 of the public key and offset. */\n securityLevel(): number {\n return levelAt(this.publicKey(), this.#offset);\n }\n\n /**\n * The same key at an offset whose security level reaches `targetLevel`, as\n * a new identity; this one is unchanged, and returned as it is when it\n * already reaches the level.\n *\n * Each level doubles the expected work, so a high level can take a long\n * time; `signal` bounds it, and the event loop keeps running meanwhile. A\n * level above 160, the width of SHA-1, can never be reached and is refused\n * with a RangeError.\n */\n async upgradeToLevel(\n targetLevel: number,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): Promise<Identity> {\n checkLevel(targetLevel);\n const { signal } = options;\n const prefix = this.publicKey();\n let offset = this.#offset;\n while (true) {\n signal?.throwIfAborted();\n if (levelAt(prefix, offset) >= targetLevel) {\n return offset === this.#offset ? this : new Identity(this.#privateKey, offset);\n }\n offset++;\n // Yield to the event loop now and then rather than blocking it.\n if (offset % 10000n === 0n) {\n await new Promise<void>((resolve) => setImmediate(resolve));\n }\n }\n }\n}\n\n// Defined outside the class body: a computed key there would have to be\n// inferred, which isolatedDeclarations rules out. By its registered name, so\n// this module needs no node:util.\nObject.defineProperty(Identity.prototype, Symbol.for(\"nodejs.util.inspect.custom\"), {\n value(this: Identity): string {\n return `Identity <${this.toString()}>`;\n },\n});\n\n/**\n * The private key of an identity, for the handshake. Not exported from the\n * package.\n *\n * @internal\n */\nexport function identityPrivateKey(identity: Identity): KeyObject {\n return privateKeyOf(identity);\n}\n\nfunction checkLevel(level: number): void {\n if (!Number.isInteger(level) || level < 0 || level > MAX_SECURITY_LEVEL) {\n throw new RangeError(`a security level is an integer from 0 to 160, not ${level}`);\n }\n}\n\nfunction levelAt(publicKey: string, offset: bigint): number {\n const h = createHash(\"sha1\");\n h.update(publicKey);\n h.update(offset.toString(10));\n return countLeadingZeros(h.digest());\n}\n\n/** The largest offset, an unsigned 64-bit counter. */\nconst MAX_UINT64 = (1n << 64n) - 1n;\n\n/**\n * Read an identity from the form `Identity.export()` writes: the private key\n * as canonical base64 of at most 32 bytes, a colon, and the offset as a\n * decimal unsigned 64-bit integer. Anything else throws an\n * InvalidIdentityError, with the underlying failure as its cause.\n */\nexport function parseIdentity(s: string): Identity {\n const colonIdx = s.lastIndexOf(\":\");\n if (colonIdx < 0) throw new InvalidIdentityError();\n\n const dBase64 = s.slice(0, colonIdx);\n const offsetStr = s.slice(colonIdx + 1);\n if (!/^\\d+$/.test(offsetStr) || BigInt(offsetStr) > MAX_UINT64) {\n throw new InvalidIdentityError(\"invalid identity offset\");\n }\n const offset = BigInt(offsetStr);\n\n // Node's base64 decoder skips what it cannot read, so the key is checked by\n // a round trip: anything but canonical base64 would otherwise decode to some\n // other key, silently.\n const dBytes = Buffer.from(dBase64, \"base64\");\n if (dBytes.length === 0 || dBytes.toString(\"base64\") !== dBase64) {\n throw new InvalidIdentityError(\"the private key is not canonical base64\");\n }\n if (dBytes.length > P256_SCALAR_SIZE) {\n throw new InvalidIdentityError(\"private key scalar too large\");\n }\n\n // Pad to P256_SCALAR_SIZE\n const padded = Buffer.alloc(P256_SCALAR_SIZE);\n dBytes.copy(padded, P256_SCALAR_SIZE - dBytes.length);\n\n try {\n // node:crypto JWK import requires x and y to be present.\n // Derive the public key from the private scalar via ECDH.\n const ecdh = createECDH(\"prime256v1\");\n ecdh.setPrivateKey(padded);\n const pub = ecdh.getPublicKey(null, \"uncompressed\"); // 65 bytes: 0x04 || x(32) || y(32)\n\n const x = Buffer.from(pub.slice(1, 33)).toString(\"base64url\");\n const y = Buffer.from(pub.slice(33, 65)).toString(\"base64url\");\n const d = padded.toString(\"base64url\");\n\n const jwk = { kty: \"EC\", crv: \"P-256\", d, x, y };\n return createIdentity(createPrivateKey({ key: jwk, format: \"jwk\" }), offset);\n } catch (error) {\n throw new InvalidIdentityError(\"invalid private key\", { cause: error });\n }\n}\n\n/**\n * Create an identity at the given security level, at most 160. Each level\n * doubles the expected work; `signal` bounds it, and the event loop keeps\n * running meanwhile.\n */\nexport async function generateIdentity(\n targetLevel: number,\n options: { readonly signal?: AbortSignal | undefined } = {},\n): Promise<Identity> {\n checkLevel(targetLevel);\n return createIdentity(generateKey(), 0n).upgradeToLevel(targetLevel, options);\n}\n\n/**\n * Create an identity at the given security level, at most 160, blocking until\n * done. Fine for a low level; a high one can block the event loop for minutes,\n * so prefer `generateIdentity()` there.\n */\nexport function generateIdentitySync(targetLevel: number): Identity {\n checkLevel(targetLevel);\n const key = generateKey();\n const prefix = createIdentity(key, 0n).publicKey();\n let offset = 0n;\n while (levelAt(prefix, offset) < targetLevel) offset++;\n return createIdentity(key, offset);\n}\n\nfunction generateKey(): KeyObject {\n return generateKeyPairSync(\"ec\", { namedCurve: \"prime256v1\" }).privateKey;\n}\n\n/**\n * The hash a server uses for `client_unique_identifier`, keyed by the server's\n * major version.\n *\n * TeamSpeak 3 hashes the canonical public key with SHA-1 (20 bytes); TeamSpeak\n * 6 switched to SHA-256 (32 bytes). The algorithm is not negotiable on the\n * wire, so a client that guesses wrong computes a UID that matches nothing the\n * server ever sends — self-identification by UID silently fails.\n *\n * May gain members in a minor release, should a server generation change the\n * hash again: a `switch` over it needs a default case.\n */\nexport type UIDAlgorithm = \"sha1\" | \"sha256\";\n\n/** Pick the UID hash from a `virtualserver_version` string, e.g. \"6.0.0-beta13.1\". */\nexport function uidAlgorithmForVersion(version: string): UIDAlgorithm {\n const major = Number.parseInt(version, 10);\n return Number.isNaN(major) || major < 6 ? \"sha1\" : \"sha256\";\n}\n\n/**\n * The unique identifier of a public key in TeamSpeak's encoding, hashed with\n * `algorithm`: SHA-1 for a TeamSpeak 3 server, SHA-256 for TeamSpeak 6.\n */\nexport function uidFromPublicKey(publicKey: string, algorithm: UIDAlgorithm): UID {\n return asUID(createHash(algorithm).update(publicKey).digest(\"base64\"));\n}\n\nexport function hash512(data: Uint8Array): Uint8Array {\n return createHash(\"sha512\").update(data).digest();\n}\n\n// ---- Internal ASN.1 DER helpers for TS3 canonical P-256 public key ----------\n\n/**\n * Encode a P-256 public key as the TS3 canonical ASN.1 SEQUENCE and return\n * its base64 representation.\n *\n * TS3 canonical format (v3+):\n * SEQUENCE {\n * BIT STRING { unused=7, value=0x00 } — DER: 03 02 07 00\n * INTEGER 32\n * INTEGER x\n * INTEGER y\n * }\n */\nfunction encodeTsPublicKey(x: Uint8Array, y: Uint8Array): string {\n // BIT STRING with 7 unused bits + value byte 0x00 — matches C# DerBitString(0x00, 7)\n const bitStringBody = Buffer.from([0x07, 0x00]);\n const bitStringDer = encodeDerTlv(0x03, bitStringBody);\n\n const integerSize = encodeDerTlv(0x02, encodePositiveInt(32));\n const integerX = encodeDerTlv(0x02, encodePositiveInt(x));\n const integerY = encodeDerTlv(0x02, encodePositiveInt(y));\n\n const seqBody = Buffer.concat([bitStringDer, integerSize, integerX, integerY]);\n const seqDer = encodeDerTlv(0x30, seqBody);\n\n return seqDer.toString(\"base64\");\n}\n\n/** Import a TS3 public key (canonical or legacy ASN.1 DER) and return the\n * uncompressed 65-byte point [0x04 || x || y]. */\nexport function importPublicKey(data: Uint8Array): KeyObject {\n const point = parseTsPublicKeyDer(data);\n const jwk = {\n kty: \"EC\",\n crv: \"P-256\",\n x: Buffer.from(point.slice(1, 33)).toString(\"base64url\"),\n y: Buffer.from(point.slice(33, 65)).toString(\"base64url\"),\n };\n return createPublicKey({ key: jwk, format: \"jwk\" });\n}\n\n/**\n * Parse both TS3 canonical and legacy ASN.1 formats and return the\n * uncompressed 65-byte point [0x04 || x || y].\n */\nfunction parseTsPublicKeyDer(data: Uint8Array): Uint8Array {\n // Try canonical: SEQUENCE { BIT_STRING, INTEGER(32), INTEGER(x), INTEGER(y) }\n try {\n return parseTsCanonicalPublicKey(data);\n } catch {\n // fall through to legacy\n }\n // Try legacy: SEQUENCE { INTEGER(x), INTEGER(y), BIT_STRING, INTEGER }\n return parseTsLegacyPublicKey(data);\n}\n\nfunction parseTsCanonicalPublicKey(data: Uint8Array): Uint8Array {\n const seqTlv = parseDerTlv(data, 0x30);\n const seq = seqTlv.value;\n let offset = 0;\n // BIT_STRING\n const bs = parseDerTlv(seq, 0x03, offset);\n offset += bs.consumed;\n // INTEGER (32)\n const sizeInt = parseDerTlv(seq, 0x02, offset);\n offset += sizeInt.consumed;\n // INTEGER x\n const xInt = parseDerTlv(seq, 0x02, offset);\n offset += xInt.consumed;\n // INTEGER y\n const yInt = parseDerTlv(seq, 0x02, offset);\n\n return buildUncompressedPoint(\n positiveIntToBytes(xInt.value, P256_SCALAR_SIZE),\n positiveIntToBytes(yInt.value, P256_SCALAR_SIZE),\n );\n}\n\nfunction parseTsLegacyPublicKey(data: Uint8Array): Uint8Array {\n const seqTlv = parseDerTlv(data, 0x30);\n const seq = seqTlv.value;\n let offset = 0;\n const xInt = parseDerTlv(seq, 0x02, offset);\n offset += xInt.consumed;\n const yInt = parseDerTlv(seq, 0x02, offset);\n\n return buildUncompressedPoint(\n positiveIntToBytes(xInt.value, P256_SCALAR_SIZE),\n positiveIntToBytes(yInt.value, P256_SCALAR_SIZE),\n );\n}\n\nfunction buildUncompressedPoint(x: Uint8Array, y: Uint8Array): Uint8Array {\n if (x.length > P256_SCALAR_SIZE || y.length > P256_SCALAR_SIZE) {\n throw new Error(\"invalid public key point encoding\");\n }\n const point = new Uint8Array(P256_UNCOMPRESSED_KEY_SIZE);\n point[0] = P256_POINT_PREFIX;\n point.set(x, 1 + P256_SCALAR_SIZE - x.length);\n point.set(y, 1 + 2 * P256_SCALAR_SIZE - y.length);\n return point;\n}\n\n// ---- DER encoding helpers ---------------------------------------------------\n\nfunction encodeDerTlv(tag: number, value: Uint8Array): Buffer {\n const lenBytes = encodeDerLength(value.length);\n return Buffer.concat([Buffer.from([tag]), lenBytes, value]);\n}\n\nfunction encodeDerLength(len: number): Buffer {\n if (len < 128) return Buffer.from([len]);\n if (len < 256) return Buffer.from([0x81, len]);\n return Buffer.from([0x82, (len >> 8) & 0xff, len & 0xff]);\n}\n\n/** Encode a non-negative value as a DER INTEGER (with 0x00 prefix if high bit set). */\nfunction encodePositiveInt(v: number | Uint8Array): Buffer {\n if (typeof v === \"number\") {\n const bytes: number[] = [];\n let n = v;\n do {\n bytes.unshift(n & 0xff);\n n >>= 8;\n } while (n > 0);\n if ((bytes[0]! & 0x80) !== 0) bytes.unshift(0x00);\n return Buffer.from(bytes);\n }\n // Uint8Array — strip leading zeros, add 0x00 if high bit set\n let start = 0;\n while (start < v.length - 1 && v[start] === 0) start++;\n const trimmed = v.slice(start);\n if ((trimmed[0]! & 0x80) !== 0) {\n return Buffer.concat([Buffer.from([0x00]), trimmed]);\n }\n return Buffer.from(trimmed);\n}\n\ninterface ParsedTlv {\n value: Uint8Array;\n consumed: number; // bytes consumed including tag+length\n}\n\nfunction parseDerTlv(data: Uint8Array, expectedTag: number, offset = 0): ParsedTlv {\n if (data[offset] !== expectedTag) {\n throw new Error(\n `expected DER tag 0x${expectedTag.toString(16)}, got 0x${(data[offset] ?? 0).toString(16)}`,\n );\n }\n let pos = offset + 1;\n let len: number;\n const firstLenByte = data[pos++]!;\n if (firstLenByte < 0x80) {\n len = firstLenByte;\n } else if (firstLenByte === 0x81) {\n len = data[pos++]!;\n } else if (firstLenByte === 0x82) {\n len = ((data[pos]! << 8) | data[pos + 1]!) >>> 0;\n pos += 2;\n } else {\n throw new Error(\"unsupported DER length encoding\");\n }\n const value = data.slice(pos, pos + len);\n return { value, consumed: pos - offset + len };\n}\n\n/** Convert a DER INTEGER value (may have leading 0x00) to fixed-length bytes. */\nfunction positiveIntToBytes(int: Uint8Array, size: number): Uint8Array {\n // Strip leading 0x00 sign byte\n let start = 0;\n while (start < int.length - 1 && int[start] === 0x00) start++;\n const stripped = int.slice(start);\n if (stripped.length > size) throw new Error(\"integer too large\");\n if (stripped.length === size) return stripped;\n const padded = new Uint8Array(size);\n padded.set(stripped, size - stripped.length);\n return padded;\n}\n\n// ---- Misc helpers -----------------------------------------------------------\n\nfunction base64UrlToBytes(b64url: string, size: number): Uint8Array {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n\nfunction countLeadingZeros(data: Buffer): number {\n let zeros = 0;\n for (const b of data) {\n if (b === 0) {\n zeros += 8;\n } else {\n for (let i = 0; i < 8; i++) {\n if ((b & (1 << i)) === 0) zeros++;\n else return zeros;\n }\n }\n }\n return zeros;\n}\n","import { createCipheriv, timingSafeEqual } from \"node:crypto\";\nimport { EAXTagMismatchError } from \"../errors.js\";\n\nconst EAX_TAG_SIZE = 8;\nconst EAX_BLOCK_SIZE = 16;\n\n/**\n * AES-EAX AEAD implementation for TS3 (64-bit tag, AES-128).\n * Uses AES-CMAC for authentication and AES-CTR for encryption.\n */\nexport class EAX {\n readonly #key: Uint8Array;\n\n constructor(key: Uint8Array) {\n if (key.length !== 16) throw new Error(\"EAX requires a 16-byte key\");\n this.#key = key;\n }\n\n encrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n plaintext: Uint8Array,\n ): [ciphertext: Uint8Array, tag: Uint8Array] {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n\n const ciphertext = aesCtr(this.#key, nStar, plaintext);\n\n const cStar = this.#cmac(2, ciphertext);\n\n const tag = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n tag[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n return [ciphertext, tag];\n }\n\n decrypt(\n nonce: Uint8Array,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): Uint8Array {\n const nStar = this.#cmac(0, nonce);\n const hStar = this.#cmac(1, header);\n const cStar = this.#cmac(2, ciphertext);\n\n const expected = new Uint8Array(EAX_TAG_SIZE);\n for (let i = 0; i < EAX_TAG_SIZE; i++) {\n expected[i] = nStar[i]! ^ hStar[i]! ^ cStar[i]!;\n }\n\n if (!timingSafeEqual(Buffer.from(expected), Buffer.from(tag.slice(0, EAX_TAG_SIZE)))) {\n throw new EAXTagMismatchError();\n }\n\n return aesCtr(this.#key, nStar, ciphertext);\n }\n\n /**\n * AES-CMAC per RFC 4493:\n * input = [0…0 tag] ++ data (one block prefix)\n */\n #cmac(tagByte: number, data: Uint8Array): Uint8Array {\n const input = new Uint8Array(EAX_BLOCK_SIZE + data.length);\n // first block: zeros then tag byte at the last position\n input[EAX_BLOCK_SIZE - 1] = tagByte;\n input.set(data, EAX_BLOCK_SIZE);\n\n return aesCmac(this.#key, input);\n }\n}\n\n// ---- AES-CTR ----------------------------------------------------------------\n\nfunction aesCtr(key: Uint8Array, iv: Uint8Array, data: Uint8Array): Uint8Array {\n const cipher = createCipheriv(\"aes-128-ctr\", Buffer.from(key), Buffer.from(iv));\n return Buffer.concat([cipher.update(Buffer.from(data)), cipher.final()]);\n}\n\n// ---- AES-CMAC (RFC 4493) ----------------------------------------------------\n\nfunction aesEcb(key: Uint8Array, block: Uint8Array): Uint8Array {\n // Node.js does not expose ECB directly; simulate via CTR with zero IV and\n // a zero-input (CTR of 0-block XOR with input = ECB)\n const cipher = createCipheriv(\"aes-128-ecb\", Buffer.from(key), null);\n cipher.setAutoPadding(false);\n return Buffer.concat([cipher.update(Buffer.from(block)), cipher.final()]);\n}\n\nfunction xorBlock(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n for (let i = 0; i < EAX_BLOCK_SIZE; i++) out[i] = a[i]! ^ b[i]!;\n return out;\n}\n\nfunction shiftLeft1(b: Uint8Array): Uint8Array {\n const out = new Uint8Array(EAX_BLOCK_SIZE);\n let carry = 0;\n for (let i = EAX_BLOCK_SIZE - 1; i >= 0; i--) {\n const shifted = ((b[i]! << 1) | carry) & 0xff;\n carry = b[i]! >> 7;\n out[i] = shifted;\n }\n return out;\n}\n\nconst RB = new Uint8Array(EAX_BLOCK_SIZE);\nRB[EAX_BLOCK_SIZE - 1] = 0x87;\n\nfunction generateSubkeys(key: Uint8Array): [Uint8Array, Uint8Array] {\n const zero = new Uint8Array(EAX_BLOCK_SIZE);\n const L = aesEcb(key, zero);\n\n let K1 = shiftLeft1(L);\n if ((L[0]! & 0x80) !== 0) K1 = xorBlock(K1, RB);\n\n let K2 = shiftLeft1(K1);\n if ((K1[0]! & 0x80) !== 0) K2 = xorBlock(K2, RB);\n\n return [K1, K2];\n}\n\nexport function aesCmac(key: Uint8Array, message: Uint8Array): Uint8Array {\n const [K1, K2] = generateSubkeys(key);\n\n const n = Math.max(1, Math.ceil(message.length / EAX_BLOCK_SIZE));\n const lastBlockComplete = message.length > 0 && message.length % EAX_BLOCK_SIZE === 0;\n\n let X: Uint8Array = new Uint8Array(EAX_BLOCK_SIZE);\n\n for (let i = 0; i < n - 1; i++) {\n const block = message.slice(i * EAX_BLOCK_SIZE, (i + 1) * EAX_BLOCK_SIZE);\n X = Uint8Array.from(aesEcb(key, xorBlock(X, block)));\n }\n\n const lastBlock = new Uint8Array(EAX_BLOCK_SIZE);\n const lastStart = (n - 1) * EAX_BLOCK_SIZE;\n const lastSlice = message.slice(lastStart);\n lastBlock.set(lastSlice);\n\n let Mn: Uint8Array;\n if (lastBlockComplete) {\n Mn = xorBlock(lastBlock, K1);\n } else {\n if (lastSlice.length < EAX_BLOCK_SIZE) lastBlock[lastSlice.length] = 0x80;\n Mn = xorBlock(lastBlock, K2);\n }\n\n return Uint8Array.from(aesEcb(key, xorBlock(X, Mn)));\n}\n","import { createHash, createECDH, randomBytes } from \"node:crypto\";\nimport { CryptoInitError, FakeSignatureMismatchError } from \"../errors.js\";\nimport type { Identity } from \"./identity.js\";\nimport { identityPrivateKey, importPublicKey } from \"./identity.js\";\nimport { EAX } from \"./eax.js\";\n\nconst FAKE_SIGNATURE_SIZE = 8;\nconst IV_ALPHA_SIZE = 10;\nconst INIT1_PACKET_TYPE = 8;\nconst PACKET_TYPE_MASK = 0x0f;\n\nconst INIT1_MAC = Buffer.from(\"TS3INIT1\");\n\n/**\n * The most squarings the Init1 puzzle may ask for. TS3 3.13 and TS6 6.0 both\n * ask for 10000; a level far beyond that is a server trying to pin the event\n * loop, since the squarings run synchronously.\n */\nexport const MAX_RSA_CHALLENGE_LEVEL: number = 100_000;\n\nexport interface KeyNonce {\n key: Uint8Array;\n nonce: Uint8Array;\n gen: number;\n}\n\n/** Precomputed dummy key/nonce matching the TS3 client pre-crypto placeholder. */\nconst DUMMY_KEY = Buffer.from(\"c:\\\\windows\\\\syste\");\nconst DUMMY_NONCE = Buffer.from(\"m\\\\firewall32.cpl\");\n\n/**\n * A connection's encryption state. The session material — the IV the keys\n * derive from — lives in private fields, so it shows in no `util.inspect()`\n * or `JSON.stringify()` of anything holding a Crypt.\n */\nexport class Crypt {\n readonly identity: Identity;\n\n #ivStruct: Uint8Array = new Uint8Array(0);\n #fakeSignature: Uint8Array = new Uint8Array(FAKE_SIGNATURE_SIZE);\n #alpha: Uint8Array = new Uint8Array(0);\n #cryptoInitComplete = false;\n\n readonly #cachedKeys = new Map<bigint, KeyNonce>();\n\n constructor(identity: Identity) {\n this.identity = identity;\n }\n\n /** Whether the session keys are set up; until then packets use the dummy key. */\n get cryptoInitComplete(): boolean {\n return this.#cryptoInitComplete;\n }\n\n /** The signature unencrypted packets carry: zeros until crypto init completes. */\n get fakeSignature(): Uint8Array {\n return this.#fakeSignature;\n }\n\n /** The client's random contribution to the IV, sent in clientinitiv; empty before. */\n get alpha(): Uint8Array {\n return this.#alpha;\n }\n\n /** Choose the client's random contribution to the IV, and return it. */\n newAlpha(): Uint8Array {\n this.#alpha = new Uint8Array(randomBytes(IV_ALPHA_SIZE));\n return this.#alpha;\n }\n\n solveRsaChallenge(data: Uint8Array, offset: number, level: number): Uint8Array {\n if (!Number.isInteger(level) || level < 0 || level > MAX_RSA_CHALLENGE_LEVEL) {\n throw new CryptoInitError(`RSA challenge level ${level} out of range`);\n }\n\n const xBytes = data.slice(offset, offset + 64);\n const nBytes = data.slice(offset + 64, offset + 128);\n\n let y = bytesToBigInt(xBytes);\n const n = bytesToBigInt(nBytes);\n if (n === 0n) throw new CryptoInitError(\"RSA challenge modulus is zero\");\n\n for (let i = 0; i < level; i++) {\n y = (y * y) % n;\n }\n\n return bigIntToBytes(y, 64);\n }\n\n initCrypto(alpha: string, beta: string, omega: string): void {\n const alphaBytes = Buffer.from(alpha, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n\n let sharedSecret: Uint8Array;\n try {\n sharedSecret = this.#getSharedSecret(importPublicKey(omegaBytes));\n } catch (error) {\n throw new CryptoInitError(\"the server's public key is invalid\", { cause: error });\n }\n\n this.setSharedSecret(alphaBytes, betaBytes, sharedSecret);\n }\n\n setSharedSecret(alpha: Uint8Array, beta: Uint8Array, sharedKey: Uint8Array): void {\n this.#ivStruct = new Uint8Array(IV_ALPHA_SIZE + beta.length);\n for (let i = 0; i < IV_ALPHA_SIZE; i++) {\n const a = sharedKey[i];\n const b = alpha[i];\n this.#ivStruct[i] = ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n for (let i = 0; i < beta.length; i++) {\n const a = sharedKey[IV_ALPHA_SIZE + i];\n const b = beta[i];\n this.#ivStruct[IV_ALPHA_SIZE + i] =\n ((a !== undefined ? a : 0) ^ (b !== undefined ? b : 0)) & 0xff;\n }\n\n // Keys derive from the IV: any cached before it changed belong to another\n // IV, the empty one before crypto init in particular, which is public.\n this.#cachedKeys.clear();\n\n const digest = createHash(\"sha1\").update(this.#ivStruct).digest();\n this.#fakeSignature = new Uint8Array(digest.buffer, digest.byteOffset, FAKE_SIGNATURE_SIZE);\n this.#cryptoInitComplete = true;\n }\n\n getKeyNonce(\n fromServer: boolean,\n packetID: number,\n generationID: number,\n packetType: number,\n dummy: boolean,\n ): [key: Uint8Array, nonce: Uint8Array] {\n if (dummy) {\n return [Uint8Array.from(DUMMY_KEY), Uint8Array.from(DUMMY_NONCE)];\n }\n // Before crypto init there is no IV, and a key derived from the empty one\n // is a key anyone can compute.\n if (!this.#cryptoInitComplete) {\n throw new CryptoInitError(\"no session key before crypto init completes\");\n }\n\n const cacheKey = makeCacheKey(fromServer, packetType, generationID);\n let kn = this.#cachedKeys.get(cacheKey);\n\n if (kn === undefined) {\n const tmpToHash = new Uint8Array(6 + this.#ivStruct.length);\n tmpToHash[0] = fromServer ? 0x30 : 0x31;\n tmpToHash[1] = packetType & PACKET_TYPE_MASK;\n new DataView(tmpToHash.buffer).setUint32(2, generationID, false);\n tmpToHash.set(this.#ivStruct, 6);\n\n const hash = createHash(\"sha256\").update(tmpToHash).digest();\n kn = {\n key: Uint8Array.from(hash.slice(0, 16)),\n nonce: Uint8Array.from(hash.slice(16, 32)),\n gen: generationID,\n };\n this.#cachedKeys.set(cacheKey, kn);\n }\n\n const key = Uint8Array.from(kn.key);\n key[0] = (key[0] !== undefined ? key[0] : 0) ^ ((packetID >> 8) & 0xff);\n key[1] = (key[1] !== undefined ? key[1] : 0) ^ (packetID & 0xff);\n\n return [key, kn.nonce];\n }\n\n encrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n plaintext: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): [ciphertext: Uint8Array, mac: Uint8Array] {\n if (packetType === INIT1_PACKET_TYPE) {\n return [plaintext, INIT1_MAC];\n }\n if (unencrypted) {\n return [plaintext, this.#fakeSignature];\n }\n\n const [key, nonce] = this.getKeyNonce(false, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.encrypt(nonce, header, plaintext);\n }\n\n decrypt(\n packetType: number,\n packetID: number,\n generationID: number,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n dummy: boolean,\n unencrypted: boolean,\n ): Uint8Array {\n if (packetType === INIT1_PACKET_TYPE) {\n return ciphertext;\n }\n if (unencrypted) {\n const fsSub = tag.slice(0, FAKE_SIGNATURE_SIZE);\n if (!Buffer.from(fsSub).equals(Buffer.from(this.#fakeSignature))) {\n throw new FakeSignatureMismatchError();\n }\n return ciphertext;\n }\n\n const [key, nonce] = this.getKeyNonce(true, packetID, generationID, packetType, dummy);\n const eax = new EAX(key);\n return eax.decrypt(nonce, header, ciphertext, tag);\n }\n\n #getSharedSecret(serverPubKey: import(\"node:crypto\").KeyObject): Uint8Array {\n const privJwk = identityPrivateKey(this.identity).export({ format: \"jwk\" }) as {\n d: string;\n };\n const pubJwk = serverPubKey.export({ format: \"jwk\" }) as {\n x: string;\n y: string;\n };\n\n const ecdh = createECDH(\"prime256v1\");\n const dBytes = Buffer.from(privJwk.d, \"base64url\");\n ecdh.setPrivateKey(dBytes);\n\n const xBytes = base64UrlToBytes(pubJwk.x, 32);\n const yBytes = base64UrlToBytes(pubJwk.y, 32);\n const uncompressed = Buffer.alloc(65);\n uncompressed[0] = 0x04;\n xBytes.copy(uncompressed, 1);\n yBytes.copy(uncompressed, 33);\n\n const rawSecret = ecdh.computeSecret(uncompressed);\n return createHash(\"sha1\").update(rawSecret).digest();\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\nfunction makeCacheKey(fromServer: boolean, packetType: number, generationID: number): bigint {\n let key = 0n;\n if (fromServer) key |= 1n << 40n;\n key |= BigInt(packetType & PACKET_TYPE_MASK) << 32n;\n key |= BigInt(generationID);\n return key;\n}\n\nfunction bytesToBigInt(bytes: Uint8Array): bigint {\n let result = 0n;\n for (const b of bytes) result = (result << 8n) | BigInt(b);\n return result;\n}\n\nfunction bigIntToBytes(value: bigint, size: number): Uint8Array {\n const result = new Uint8Array(size);\n let v = value;\n for (let i = size - 1; i >= 0; i--) {\n result[i] = Number(v & 0xffn);\n v >>= 8n;\n }\n return result;\n}\n\nfunction base64UrlToBytes(b64url: string, size: number): Buffer {\n const buf = Buffer.from(b64url, \"base64url\");\n if (buf.length === size) return buf;\n const padded = Buffer.alloc(size);\n buf.copy(padded, size - buf.length);\n return padded;\n}\n","import { createSign, createVerify, createHash, randomBytes, type KeyObject } from \"node:crypto\";\nimport { ed25519 } from \"@noble/curves/ed25519.js\";\n\nconst CURVE25519_KEY_SIZE = 32;\nconst CLAMP_MASK_LOW = 248;\nconst CLAMP_MASK_HIGH = 127;\nconst CLAMP_HIGH_BIT = 64;\nconst SHARED_SIGN_BIT = 0x80;\nconst PRIVATE_KEY_TOP_MASK = 0x7f;\n\n/** Clamp a Curve25519 scalar in-place (required before scalar multiplication). */\nexport function clampScalar(key: Uint8Array): void {\n if (key.length < CURVE25519_KEY_SIZE) return;\n key[0] = (key[0] ?? 0) & CLAMP_MASK_LOW;\n key[CURVE25519_KEY_SIZE - 1] =\n ((key[CURVE25519_KEY_SIZE - 1] ?? 0) & CLAMP_MASK_HIGH) | CLAMP_HIGH_BIT;\n}\n\n/**\n * Generate an ephemeral Ed25519 key pair for the TS3 handshake.\n * Returns [publicKey (32 bytes, RFC-8032 encoded), privateKey (32 bytes)].\n */\nexport function generateTemporaryKey(): [Uint8Array, Uint8Array] {\n const privateKey = new Uint8Array(randomBytes(CURVE25519_KEY_SIZE));\n clampScalar(privateKey);\n\n // Base point G is in the prime-order subgroup, so G*s = G*(s mod n).\n // Safe to reduce here since G has no small-order component.\n const scalar = bytesToBigIntLE(privateKey) % ed25519.Point.CURVE().n;\n const publicKey = ed25519.Point.BASE.multiply(scalar).toBytes();\n\n return [publicKey, Uint8Array.from(privateKey)];\n}\n\n/**\n * Sign data with a P-256 private key (SHA-256 hash, ASN.1 DER encoded).\n */\nexport function sign(privateKey: KeyObject, data: Uint8Array): Uint8Array {\n const signer = createSign(\"SHA256\");\n signer.update(data);\n return signer.sign(privateKey);\n}\n\n/**\n * Verify a P-256 ECDSA signature (SHA-256 hash, ASN.1 DER encoded).\n */\nexport function verifySign(publicKey: KeyObject, data: Uint8Array, sig: Uint8Array): boolean {\n try {\n const verifier = createVerify(\"SHA256\");\n verifier.update(data);\n return verifier.verify(publicKey, Buffer.from(sig));\n } catch {\n return false;\n }\n}\n\n/**\n * TS3-specific shared secret derivation using Ed25519 point arithmetic.\n * Mirrors NaCl's ge_scalarmult_vartime:\n * 1. Negate the public point\n * 2. Scalar-multiply by clamped private key bytes (NOT reduced mod n)\n * 3. Flip sign bit of result\n * 4. SHA-512 the resulting point bytes\n *\n * The scalar must NOT be reduced mod n: Ed25519 has cofactor 8, so the server's\n * public key may have a small-order component, and P*s ≠ P*(s mod n) in that case.\n * We use scalarMultFull to handle scalars >= n without losing the cofactor term.\n */\nexport function getSharedSecret2(\n publicKeyBytes: Uint8Array,\n privateKeyBytes: Uint8Array,\n): Uint8Array {\n if (\n publicKeyBytes.length !== CURVE25519_KEY_SIZE ||\n privateKeyBytes.length !== CURVE25519_KEY_SIZE\n ) {\n throw new Error(\"invalid key length\");\n }\n\n const privCopy = Uint8Array.from(privateKeyBytes);\n privCopy[CURVE25519_KEY_SIZE - 1] =\n (privCopy[CURVE25519_KEY_SIZE - 1] ?? 0) & PRIVATE_KEY_TOP_MASK;\n\n // Use raw scalar WITHOUT reducing mod n — matches NaCl's ge_scalarmult_vartime.\n // Ed25519 has cofactor 8, so P*s ≠ P*(s mod n) when P has a small-order component.\n // Since @noble/curves rejects scalars >= n, we decompose: P*s = P*(s%n) + (P*n)*q\n const rawScalar = bytesToBigIntLE(privCopy);\n\n const pub = ed25519.Point.fromBytes(publicKeyBytes);\n const negPub = pub.negate();\n\n const sharedPoint = scalarMultFull(negPub, rawScalar);\n const sharedBytes = sharedPoint.toBytes();\n\n // Flip sign bit (mirrors Go: shared[31] ^= 0x80)\n sharedBytes[CURVE25519_KEY_SIZE - 1] =\n (sharedBytes[CURVE25519_KEY_SIZE - 1] ?? 0) ^ SHARED_SIGN_BIT;\n\n return createHash(\"sha512\").update(sharedBytes).digest();\n}\n\n// ---- Internal ---------------------------------------------------------------\n\n/**\n * Multiply an Ed25519 point by a scalar that may be >= curve order n.\n * Decomposes as: P*s = P*(s mod n) + (P*n)*q where q = floor(s/n).\n * This preserves the small-order component (cofactor 8) that would be\n * lost by reducing mod n first.\n *\n * For a clamped 255-bit scalar, q is at most 7 (since maxScalar / n < 8),\n * so the second term is computed with at most one extra scalar multiplication.\n */\nexport function scalarMultFull(\n point: InstanceType<typeof ed25519.Point>,\n scalar: bigint,\n): InstanceType<typeof ed25519.Point> {\n const n = ed25519.Point.CURVE().n;\n if (scalar < n) {\n return scalar === 0n ? ed25519.Point.ZERO : point.multiply(scalar);\n }\n const remainder = scalar % n;\n const quotient = scalar / n; // integer division, 1 <= quotient <= 7 for clamped scalars\n\n // P * (s mod n)\n const mainPart = remainder === 0n ? ed25519.Point.ZERO : point.multiply(remainder);\n\n // (P * n) * q — compute P*n via P*(n-1)+P since multiply() rejects scalar == n\n const pointTimesN = point.multiply(n - 1n).add(point);\n const cofactorPart = pointTimesN.multiply(quotient);\n\n return mainPart.add(cofactorPart);\n}\n\n/** Interpret a little-endian byte array as an unsigned BigInt. */\nexport function bytesToBigIntLE(bytes: Uint8Array): bigint {\n let result = 0n;\n for (let i = bytes.length - 1; i >= 0; i--) {\n result = (result << 8n) | BigInt(bytes[i]!);\n }\n return result;\n}\n","import { isIP } from \"node:net\";\nimport { InvalidAddressError } from \"./errors.js\";\n\nexport interface HostPort {\n host: string;\n port: string;\n}\n\n/** Parse a TeamSpeak address without confusing an IPv6 colon for a port separator. */\nexport function splitHostPort(address: string, defaultPort = \"9987\"): HostPort {\n const input = address.trim();\n if (input.startsWith(\"[\")) {\n const closingBracket = input.indexOf(\"]\");\n if (closingBracket > 0) {\n const host = input.slice(1, closingBracket);\n const suffix = input.slice(closingBracket + 1);\n if (suffix.startsWith(\":\") && /^\\d+$/.test(suffix.slice(1))) {\n return { host, port: suffix.slice(1) };\n }\n if (!suffix) return { host, port: defaultPort };\n }\n }\n\n // A raw IPv6 literal has no unambiguous port separator. Internal callers\n // normally use bracket notation, but accepting the literal with the default\n // port prevents a final IPv6 segment from being mistaken for a port.\n if (isIP(input) === 6) return { host: input, port: defaultPort };\n\n const lastColon = input.lastIndexOf(\":\");\n if (lastColon < 0) return { host: input, port: defaultPort };\n const candidatePort = input.slice(lastColon + 1);\n if (/^\\d+$/.test(candidatePort) && input.indexOf(\":\") === lastColon) {\n return { host: input.slice(0, lastColon), port: candidatePort };\n }\n return { host: input, port: defaultPort };\n}\n\n/** Characters no host name or IP address contains, whitespace among them. */\nconst NOT_IN_A_HOST = /[\\s\\p{Cc}/?#@[\\]\\\\]/u;\n\n/**\n * Parse an address to connect to, and check it can be one: a host, which\n * contains nothing a host name or IP address cannot, and a port from 1 to\n * 65535. Throws an InvalidAddressError otherwise.\n */\nexport function parseConnectAddress(address: string): HostPort & { portNumber: number } {\n const { host, port } = splitHostPort(address);\n if (host === \"\") throw new InvalidAddressError(address, \"no host\");\n // A colon is left only in an IPv6 literal; anywhere else it is a port that\n // is not a number, which splitHostPort keeps as part of the host.\n if (NOT_IN_A_HOST.test(host) || (host.includes(\":\") && isIP(host) !== 6)) {\n throw new InvalidAddressError(address, \"not a host name, IP address or host:port\");\n }\n const portNumber = Number(port);\n if (!Number.isInteger(portNumber) || portNumber < 1 || portNumber > 65535) {\n throw new InvalidAddressError(address, `port ${port} is not from 1 to 65535`);\n }\n return { host, port, portNumber };\n}\n\nexport function joinHostPort(host: string, port: string): string {\n const normalizedHost = stripBrackets(host);\n return isIP(normalizedHost) === 6 || normalizedHost.includes(\":\")\n ? `[${normalizedHost}]:${port}`\n : `${normalizedHost}:${port}`;\n}\n\nexport function isIpAddress(host: string): boolean {\n return isIP(stripBrackets(host)) !== 0;\n}\n\nfunction stripBrackets(host: string): string {\n return host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n}\n","import { resolveSrv } from \"node:dns/promises\";\nimport { createConnection } from \"node:net\";\nimport type { ResolvedAddr } from \"../types.js\";\nimport { isIpAddress, joinHostPort, splitHostPort } from \"../address.js\";\nimport { abortable } from \"../abort.js\";\n\nconst TS_DNS_DEFAULT_PORT = 41144;\nconst NICKNAME_LOOKUP_URL = \"https://named.myteamspeak.com/lookup\";\nconst CACHE_TTL_MS = 10 * 60 * 1000;\n/**\n * How long resolution may take in all; past it, the address is used as given.\n * A Client holds any resolver, its own or a custom one, to the same budget.\n *\n * @internal\n */\nexport const RESOLVE_BUDGET_MS = 10_000;\n/** How long one TSDNS server may take to answer. */\nconst TSDNS_TIMEOUT_MS = 3_000;\n\n/**\n * The most a TSDNS server or the nickname service is read for. Either answers\n * with one short line; without a bound, one that kept sending would be held in\n * memory until the resolution budget ran out.\n */\nexport const MAX_DISCOVERY_RESPONSE: number = 8 * 1024;\n\n/** How the default resolver resolves. */\nexport interface ResolverOptions {\n /** Look dot-less names up at named.myteamspeak.com; off by default. */\n readonly resolveNicknames?: boolean | undefined;\n}\n\nexport class Resolver {\n readonly #cache = new Map<string, ResolvedAddr[]>();\n readonly #resolveNicknames: boolean;\n\n constructor(options: ResolverOptions = {}) {\n this.#resolveNicknames = options.resolveNicknames ?? false;\n }\n\n /**\n * Resolve as the TeamSpeak application does: a server nickname (only with\n * `resolveNicknames`), then SRV, then TSDNS, then the address as given. The\n * whole resolution is bounded: past the budget, or when a step fails, the\n * address as given is the answer.\n */\n async resolve(\n inputAddr: string,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): Promise<ResolvedAddr[]> {\n if (!inputAddr) throw new Error(\"empty address\");\n const budget = AbortSignal.timeout(RESOLVE_BUDGET_MS);\n const signal = options.signal ? AbortSignal.any([options.signal, budget]) : budget;\n try {\n return await this.#resolve(inputAddr, signal, true);\n } catch (error) {\n options.signal?.throwIfAborted();\n if (!budget.aborted) throw error;\n const { host, port } = splitHostPort(inputAddr);\n return [{ addr: joinHostPort(host, port), source: \"Direct\" }];\n }\n }\n\n async #resolve(\n inputAddr: string,\n signal: AbortSignal,\n nicknames: boolean,\n ): Promise<ResolvedAddr[]> {\n const cached = this.#getValidCache(inputAddr);\n if (cached) return cached;\n\n const { host, port } = splitHostPort(inputAddr);\n\n if (isIpAddress(host)) {\n return [{ addr: joinHostPort(host, port), source: \"Direct\" }];\n }\n\n // A dot-less name may be a server nickname, which only the TeamSpeak\n // service can answer: asking it sends the name to a third party, so it is\n // opt-in. Otherwise the name is resolved like any host.\n if (nicknames && this.#resolveNicknames && !host.includes(\".\") && host !== \"localhost\") {\n const nickAddr = await resolveNickname(host, signal);\n signal.throwIfAborted();\n if (nickAddr) return this.#resolve(nickAddr, signal, false);\n }\n\n // SRV _ts3._udp.<host>\n const srvResults = await this.#resolveSRV(host, signal);\n if (srvResults) return this.#setCache(inputAddr, srvResults);\n\n const domainList = getDomainList(host);\n\n // TSDNS via SRV _tsdns._tcp.<domain>\n const tsdnsSrv = await this.#resolveTSDNSSRV(domainList, host, signal);\n if (tsdnsSrv) {\n return this.#setCache(inputAddr, [{ addr: tsdnsSrv, source: \"TSDNS-SRV\" }]);\n }\n\n // TSDNS direct :41144\n const tsdnsDirect = await this.#resolveTSDNSDirect(domainList, host, signal);\n if (tsdnsDirect) {\n return this.#setCache(inputAddr, [{ addr: tsdnsDirect, source: \"TSDNS-Direct\" }]);\n }\n\n signal.throwIfAborted();\n // Plain DNS fallback\n const fallback: ResolvedAddr[] = [{ addr: joinHostPort(host, port), source: \"Direct\" }];\n return this.#setCache(inputAddr, fallback);\n }\n\n #getValidCache(inputAddr: string): ResolvedAddr[] | null {\n const cached = this.#cache.get(inputAddr);\n if (!cached || cached.length === 0) return null;\n const first = cached[0]!;\n if (first.expiry !== undefined && Date.now() > first.expiry.getTime()) return null;\n return cached;\n }\n\n #setCache(key: string, results: ResolvedAddr[]): ResolvedAddr[] {\n const expiry = new Date(Date.now() + CACHE_TTL_MS);\n const withExpiry = results.map((r) => ({ ...r, expiry }));\n this.#cache.set(key, withExpiry);\n return withExpiry;\n }\n\n async #resolveSRV(host: string, signal?: AbortSignal): Promise<ResolvedAddr[] | null> {\n try {\n const srvs = await abortable(resolveSrv(`_ts3._udp.${host}`), signal);\n if (!srvs || srvs.length === 0) return null;\n return srvs.map((srv) => ({\n addr: joinHostPort(srv.name.replace(/\\.$/, \"\"), String(srv.port)),\n source: \"SRV\",\n }));\n } catch {\n return null;\n }\n }\n\n async #resolveTSDNSSRV(\n domains: string[],\n queryHost: string,\n signal?: AbortSignal,\n ): Promise<string | null> {\n for (const domain of domains) {\n try {\n const srvs = await abortable(resolveSrv(`_tsdns._tcp.${domain}`), signal);\n if (!srvs || srvs.length === 0) continue;\n for (const srv of srvs) {\n const tsdnsAddr = joinHostPort(srv.name.replace(/\\.$/, \"\"), String(srv.port));\n const result = await queryTSDNS(tsdnsAddr, queryHost, signal);\n if (result) return result;\n }\n } catch {\n continue;\n }\n }\n return null;\n }\n\n async #resolveTSDNSDirect(\n domains: string[],\n queryHost: string,\n signal?: AbortSignal,\n ): Promise<string | null> {\n // Asked at once rather than in turn, so the probes cost one timeout in\n // all; the most specific domain's answer wins.\n const answers = await Promise.all(\n domains.map((domain) =>\n queryTSDNS(joinHostPort(domain, String(TS_DNS_DEFAULT_PORT)), queryHost, signal),\n ),\n );\n return answers.find((answer) => answer !== null) ?? null;\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\n/** @internal Ask the nickname service for `nickname`'s address. */\nexport async function resolveNickname(\n nickname: string,\n signal?: AbortSignal,\n): Promise<string | null> {\n try {\n const url = new URL(NICKNAME_LOOKUP_URL);\n url.searchParams.set(\"name\", nickname);\n const init: RequestInit = signal ? { signal } : {};\n const resp = await fetch(url.toString(), init);\n if (!resp.ok) return null;\n const text = await readLimited(resp, MAX_DISCOVERY_RESPONSE);\n const line = text.split(\"\\n\")[0]?.trim();\n return line || null;\n } catch {\n return null;\n }\n}\n\n/** A response body's first `limit` bytes, as text; the rest is not read. */\nasync function readLimited(resp: Response, limit: number): Promise<string> {\n if (resp.body === null) return \"\";\n const reader = resp.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n try {\n while (size < limit) {\n const { done, value } = await reader.read();\n if (done) break;\n const part = value.subarray(0, limit - size);\n chunks.push(part);\n size += part.length;\n }\n } finally {\n reader.cancel().catch(() => {});\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\n/** @internal Ask the TSDNS server at `tsdnsAddr` for `queryHost`'s address. */\nexport function queryTSDNS(\n tsdnsAddr: string,\n queryHost: string,\n signal?: AbortSignal,\n): Promise<string | null> {\n const [host, portStr] = splitHostPortParts(tsdnsAddr);\n const port = parseInt(portStr, 10);\n\n return new Promise((resolve) => {\n if (signal?.aborted) return resolve(null);\n const finish = (answer: string | null): void => {\n clearTimeout(timeout);\n signal?.removeEventListener(\"abort\", onAbort);\n socket.destroy();\n resolve(answer);\n };\n const onAbort = (): void => finish(null);\n const timeout = setTimeout(() => finish(null), TSDNS_TIMEOUT_MS);\n\n const socket = createConnection({ host, port, timeout: 2_000 }, () => {\n socket.write(`${queryHost}\\n`);\n });\n\n let buf = \"\";\n socket.on(\"data\", (chunk: Buffer) => {\n buf += chunk.toString(\"latin1\");\n const idx = buf.indexOf(\"\\n\");\n if (idx >= 0 && idx < MAX_DISCOVERY_RESPONSE) {\n const line = Buffer.from(buf.slice(0, idx), \"latin1\").toString(\"utf8\").trim();\n finish(!line || line === \"404\" || line === \"errors\" ? null : line);\n } else if (buf.length >= MAX_DISCOVERY_RESPONSE) {\n // No answer is that long.\n finish(null);\n }\n });\n\n socket.on(\"error\", () => finish(null));\n socket.on(\"timeout\", () => finish(null));\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction splitHostPortParts(addr: string): [string, string] {\n const { host, port } = splitHostPort(addr);\n return [host, port];\n}\n\nfunction getDomainList(host: string): string[] {\n const parts = host.split(\".\");\n const list: string[] = [];\n for (let i = 0; i < parts.length - 1; i++) {\n list.push(parts.slice(i).join(\".\"));\n }\n return list.slice(0, 3);\n}\n","export const enum PacketType {\n Voice = 0,\n VoiceWhisper = 1,\n Command = 2,\n CommandLow = 3,\n Ping = 4,\n Pong = 5,\n Ack = 6,\n AckLow = 7,\n Init1 = 8,\n}\n\nexport const enum PacketFlags {\n Fragmented = 0x10,\n NewProtocol = 0x20,\n Compressed = 0x40,\n Unencrypted = 0x80,\n}\n\nexport interface Packet {\n /** Type byte combined with flags (low nibble = type, high nibble = flags). */\n typeFlagged: number;\n id: number;\n clientID: number;\n generationID: number;\n data: Uint8Array;\n receivedAt: number; // Date.now()\n}\n\nexport function packetType(p: Packet): PacketType {\n return (p.typeFlagged & 0x0f) as PacketType;\n}\n\nexport function packetFlags(p: Packet): number {\n return p.typeFlagged & 0xf0;\n}\n\nexport function isUnencrypted(p: Packet): boolean {\n return (packetFlags(p) & PacketFlags.Unencrypted) !== 0;\n}\n\n/** Build the 5-byte client-to-server header: [packetID(2), clientID(2), typeFlagged(1)]. */\nexport function buildC2SHeader(p: Packet): Uint8Array {\n const header = new Uint8Array(5);\n const view = new DataView(header.buffer);\n view.setUint16(0, p.id, false);\n view.setUint16(2, p.clientID, false);\n header[4] = p.typeFlagged;\n return header;\n}\n\n/** Parse a 3-byte server-to-client header. */\nexport function parseS2CHeader(raw: Uint8Array): Pick<Packet, \"id\" | \"typeFlagged\"> {\n const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);\n return {\n id: view.getUint16(0, false),\n typeFlagged: raw[2]!,\n };\n}\n\n/** Parse a 5-byte client-to-server header. */\nexport function parseC2SHeader(raw: Uint8Array): Pick<Packet, \"id\" | \"clientID\" | \"typeFlagged\"> {\n const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);\n return {\n id: view.getUint16(0, false),\n clientID: view.getUint16(2, false),\n typeFlagged: raw[4]!,\n };\n}\n","export class GenerationWindow {\n #mappedBaseOffset = 0;\n #generation = 0;\n readonly #mod: number;\n readonly #receiveWindow: number;\n\n constructor(mod: number, windowSize: number) {\n this.#mod = mod;\n this.#receiveWindow = windowSize;\n }\n\n get generation(): number {\n return this.#generation;\n }\n\n advance(amount: number): void {\n if (amount <= 0) return;\n const newBaseOffset = this.#mappedBaseOffset + amount;\n const genStep = Math.floor(newBaseOffset / this.#mod);\n if (genStep > 0) {\n this.#generation = Math.min(this.#generation + genStep, 0xffff_ffff);\n }\n this.#mappedBaseOffset = newBaseOffset % this.#mod;\n }\n\n advanceToExcluded(mappedValue: number): void {\n let moveDist = mappedValue - this.#mappedBaseOffset;\n if (moveDist < 0) moveDist += this.#mod;\n this.advance(moveDist + 1);\n }\n\n syncTo(mappedValue: number): void {\n let moveDist = mappedValue - this.#mappedBaseOffset;\n if (moveDist < 0) moveDist += this.#mod;\n this.advance(moveDist);\n }\n\n isInWindow(mappedValue: number): boolean {\n const maxOffset = this.#mappedBaseOffset + this.#receiveWindow;\n if (maxOffset < this.#mod) {\n return mappedValue >= this.#mappedBaseOffset && mappedValue < maxOffset;\n }\n return mappedValue >= this.#mappedBaseOffset || mappedValue < maxOffset - this.#mod;\n }\n\n /**\n * The offset from the window base: negative means stale, `receiveWindow` or\n * more too far ahead. An id up to `receiveWindow` behind the base across the\n * last wrap, which reads as a high number, is stale too.\n */\n mappedToIndex(mappedValue: number): number {\n if (this.#isNextGen(mappedValue)) {\n return mappedValue + this.#mod - this.#mappedBaseOffset;\n }\n const index = mappedValue - this.#mappedBaseOffset;\n return this.#isBehindAcrossWrap(index) ? index - this.#mod : index;\n }\n\n /**\n * Whether an id `index` past the base is really up to `receiveWindow` behind\n * it, in the generation before: the base has wrapped since, so the id reads as\n * nearly a whole generation ahead. Before the first wrap no id lies behind the\n * base across it.\n */\n #isBehindAcrossWrap(index: number): boolean {\n return (\n this.#generation > 0 &&\n index >= this.#receiveWindow &&\n index >= this.#mod - this.#receiveWindow\n );\n }\n\n /**\n * Whether the id is before the receive window: a packet whose acknowledgement\n * was lost is sent again after the window has moved past it, also when the\n * move wrapped the 16-bit id.\n */\n isOldPacket(mappedValue: number): boolean {\n return this.mappedToIndex(mappedValue) < 0;\n }\n\n isFuturePacket(mappedValue: number): boolean {\n return this.mappedToIndex(mappedValue) >= this.#receiveWindow;\n }\n\n #isNextGen(mappedValue: number): boolean {\n return (\n this.#mappedBaseOffset > this.#mod - this.#receiveWindow &&\n mappedValue < this.#mappedBaseOffset + this.#receiveWindow - this.#mod\n );\n }\n\n /**\n * The generation the id belongs to: one past the current generation if the id\n * has already wrapped, one before it if the id is just behind the base across\n * the last wrap.\n */\n getGeneration(mappedValue: number): number {\n if (this.#isNextGen(mappedValue)) return this.#generation + 1;\n if (this.#isBehindAcrossWrap(mappedValue - this.#mappedBaseOffset)) return this.#generation - 1;\n return this.#generation;\n }\n\n reset(): void {\n this.#mappedBaseOffset = 0;\n this.#generation = 0;\n }\n}\n","const TABLE_SIZE = 4096;\n\n/**\n * The largest decompressed command accepted. A command is reassembled from at\n * most a receive window of fragments, and the largest real answers (a full\n * permission list, the welcome channel list of a big server) are a few\n * hundred kilobytes; a header declaring more is refused before anything is\n * allocated.\n */\nexport const MAX_DECOMPRESSED_SIZE: number = 1 << 20;\n\n/**\n * How much larger than its compressed bytes a level-1 block can be. The most\n * a 3-byte back-reference yields is 255 bytes, and every 32 entries also cost\n * a 4-byte control word, which bounds the ratio at about 82; a block declaring\n * more cannot be honest, and is refused before its output is allocated.\n */\nconst MAX_EXPANSION = 128;\n\ninterface QlzState {\n control: number;\n sourcePos: number;\n destPos: number;\n nextHashed: number;\n}\n\n/** A QuickLZ block that cannot be decompressed: truncated, oversized or inconsistent. */\nexport class QuickLZError extends Error {\n constructor(message: string) {\n super(`QuickLZ: ${message}`);\n this.name = \"QuickLZError\";\n }\n}\n\n/**\n * QuickLZ level 1 decompression, as the server compresses large commands.\n *\n * The input comes from the network, so every read and every back-reference is\n * checked, and malformed input throws a QuickLZError rather than reading out\n * of range or producing a partly filled buffer.\n */\nexport class Qlz {\n #hashtable = new Int32Array(TABLE_SIZE);\n\n decompress(data: Uint8Array): Uint8Array {\n const { headerLen, decompressedSize, flags } = parseQlzHeader(data);\n\n if ((flags & 0x01) === 0) {\n if (headerLen + decompressedSize > data.length) {\n throw new QuickLZError(\"stored block is shorter than its declared size\");\n }\n return data.slice(headerLen, headerLen + decompressedSize);\n }\n\n if (decompressedSize > (data.length - headerLen) * MAX_EXPANSION) {\n throw new QuickLZError(\n `declared size ${decompressedSize} is more than ${data.length - headerLen} bytes can expand to`,\n );\n }\n const dest = new Uint8Array(decompressedSize);\n this.#hashtable.fill(0);\n\n const state: QlzState = {\n control: 1,\n sourcePos: headerLen,\n destPos: 0,\n nextHashed: 0,\n };\n\n while (state.destPos < decompressedSize) {\n this.#ensureControl(data, state);\n if ((state.control & 1) !== 0) {\n this.#processReference(data, dest, state);\n } else if (this.#processLiteral(data, dest, decompressedSize, state)) {\n break;\n }\n }\n\n if (state.destPos !== decompressedSize) throw new QuickLZError(\"block ends early\");\n return dest;\n }\n\n #ensureControl(data: Uint8Array, st: QlzState): void {\n if (st.control !== 1) return;\n if (st.sourcePos + 4 > data.length) throw new QuickLZError(\"block ends early\");\n st.control =\n (data[st.sourcePos]! |\n (data[st.sourcePos + 1]! << 8) |\n (data[st.sourcePos + 2]! << 16) |\n (data[st.sourcePos + 3]! << 24)) >>>\n 0;\n st.sourcePos += 4;\n }\n\n #processReference(data: Uint8Array, dest: Uint8Array, st: QlzState): void {\n st.control = (st.control >>> 1) >>> 0;\n if (st.sourcePos + 2 > data.length) throw new QuickLZError(\"block ends early\");\n\n const b1 = data[st.sourcePos]!;\n const b2 = data[st.sourcePos + 1]!;\n st.sourcePos += 2;\n\n const hash = (b1 >> 4) | (b2 << 4);\n let matchlen = b1 & 0x0f;\n if (matchlen !== 0) {\n matchlen += 2;\n } else {\n if (st.sourcePos >= data.length) throw new QuickLZError(\"block ends early\");\n matchlen = data[st.sourcePos]!;\n st.sourcePos++;\n }\n\n const offset = this.#hashtable[hash]!;\n // The copy may overlap its own output, so only its start must precede it.\n if (offset >= st.destPos) throw new QuickLZError(\"back-reference points ahead of the output\");\n if (st.destPos + matchlen > dest.length) {\n throw new QuickLZError(\"back-reference overruns the declared size\");\n }\n for (let i = 0; i < matchlen; i++) {\n dest[st.destPos] = dest[offset + i]!;\n st.destPos++;\n }\n\n const end = st.destPos + 1 - matchlen;\n this.#updateHashtable(dest, st, end);\n st.nextHashed = st.destPos;\n }\n\n /** Copy literals; returns true once the tail of the block has been copied. */\n #processLiteral(\n data: Uint8Array,\n dest: Uint8Array,\n decompressedSize: number,\n st: QlzState,\n ): boolean {\n const threshold = Math.max(decompressedSize, 10) - 10;\n if (st.destPos >= threshold) {\n while (st.destPos < decompressedSize) {\n if (st.control === 1) {\n if (st.sourcePos + 4 > data.length) throw new QuickLZError(\"block ends early\");\n st.control =\n (data[st.sourcePos]! |\n (data[st.sourcePos + 1]! << 8) |\n (data[st.sourcePos + 2]! << 16) |\n (data[st.sourcePos + 3]! << 24)) >>>\n 0;\n st.sourcePos += 4;\n }\n if (st.sourcePos >= data.length) throw new QuickLZError(\"block ends early\");\n dest[st.destPos++] = data[st.sourcePos++]!;\n st.control = (st.control >>> 1) >>> 0;\n }\n return true;\n }\n\n if (st.sourcePos >= data.length) throw new QuickLZError(\"block ends early\");\n\n dest[st.destPos++] = data[st.sourcePos++]!;\n st.control = (st.control >>> 1) >>> 0;\n\n const end = Math.max(st.destPos - 2, 0);\n this.#updateHashtable(dest, st, end);\n if (st.nextHashed < end) st.nextHashed = end;\n\n return false;\n }\n\n #updateHashtable(dest: Uint8Array, st: QlzState, end: number): void {\n while (st.nextHashed < end) {\n if (st.nextHashed + 3 > dest.length) break;\n const v =\n (dest[st.nextHashed]! |\n (dest[st.nextHashed + 1]! << 8) |\n (dest[st.nextHashed + 2]! << 16)) >>>\n 0;\n const hash = ((v >> 12) ^ v) & 0xfff;\n this.#hashtable[hash] = st.nextHashed;\n st.nextHashed++;\n }\n }\n}\n\nfunction parseQlzHeader(data: Uint8Array): {\n headerLen: number;\n decompressedSize: number;\n flags: number;\n} {\n if (data.length < 3) throw new QuickLZError(\"data too short\");\n\n const flags = data[0]!;\n const level = (flags >> 2) & 0x03;\n if (level !== 1) throw new QuickLZError(\"only level 1 is supported\");\n\n const long = (flags & 0x02) !== 0;\n const headerLen = long ? 9 : 3;\n if (data.length < headerLen) throw new QuickLZError(\"data too short for header\");\n\n // The header also carries the compressed size, which the reads below make\n // redundant: each one is checked against the data itself.\n const decompressedSize = long\n ? (data[5]! | (data[6]! << 8) | (data[7]! << 16) | (data[8]! << 24)) >>> 0\n : data[2]!;\n\n if (decompressedSize > MAX_DECOMPRESSED_SIZE) {\n throw new QuickLZError(`declared size ${decompressedSize} exceeds ${MAX_DECOMPRESSED_SIZE}`);\n }\n\n return { headerLen, decompressedSize, flags };\n}\n","import { randomBytes } from \"node:crypto\";\nimport { buildCommandOrdered } from \"@honeybbq/teamspeak-core/internal\";\nimport type { Crypt } from \"../crypto/crypt.js\";\nimport { CryptoInitError } from \"../errors.js\";\n\nexport const INIT_VERSION = 1566914096; // 3.5.0 [Stable]\n\nconst INIT_VERSION_LEN = 4;\nconst INIT_TYPE_LEN = 1;\nconst INIT_STEP_LEN = 21;\n\n/** The RSA challenge each connection attempt, by its Crypt, has answered. */\nconst answeredChallenges = new WeakMap<\n Crypt,\n { readonly challenge: Uint8Array; readonly answer: Uint8Array }\n>();\n\n/**\n * Handle the TS3INIT1 handshake steps.\n * Returns the response bytes to send, or null if nothing should be sent.\n * Throws a CryptoInitError for a step that cannot be answered.\n */\nexport function processInit1(crypt: Crypt, data: Uint8Array | null): Uint8Array | null {\n if (data === null || (data.length >= 1 && data[0] === 0x7f)) {\n return buildInit1StartPacket();\n }\n if (data.length === 0) throw new CryptoInitError(\"empty Init1 packet\");\n\n switch (data[0]) {\n case 0:\n return buildInit1Step1Packet(data);\n case 1:\n return buildInit1Step2Packet(data);\n case 2:\n return buildInit1Step3Packet(data);\n case 3:\n return buildInit1Step4Packet(crypt, data);\n default:\n return null;\n }\n}\n\nfunction buildInit1StartPacket(): Uint8Array {\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 4 + 4 + 8);\n const view = new DataView(sendData.buffer);\n\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x00;\n\n const nowSec = Math.floor(Date.now() / 1000);\n const clampedNow = Math.max(0, Math.min(nowSec, 0xffff_ffff));\n view.setUint32(5, clampedNow, false);\n\n const rng = randomBytes(4);\n sendData.set(rng, 9);\n\n return sendData;\n}\n\nfunction buildInit1Step1Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 16 + 4);\n sendData[0] = 0x01;\n\n // TS rand: little-endian uint32 at offset [INIT_VERSION_LEN + INIT_TYPE_LEN + 4]\n const tsRandOffset = INIT_VERSION_LEN + INIT_TYPE_LEN + 4;\n const tsRand =\n data[tsRandOffset]! |\n (data[tsRandOffset + 1]! << 8) |\n (data[tsRandOffset + 2]! << 16) |\n (data[tsRandOffset + 3]! << 24);\n\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 16, tsRand >>> 0, false);\n return sendData;\n}\n\nfunction buildInit1Step2Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_STEP_LEN) return null;\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4);\n new DataView(sendData.buffer).setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x02;\n sendData.set(data.slice(1, 21), 5);\n return sendData;\n}\n\nfunction buildInit1Step3Packet(data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_VERSION_LEN + INIT_TYPE_LEN + 16 + 4) return null;\n\n const sendData = new Uint8Array(INIT_TYPE_LEN + 64 + 64 + 4 + 100);\n sendData[0] = 0x03;\n sendData[INIT_TYPE_LEN + 64 - 1] = 1;\n sendData[INIT_TYPE_LEN + 64 + 64 - 1] = 1;\n new DataView(sendData.buffer).setUint32(INIT_TYPE_LEN + 64 + 64, 1, false);\n return sendData;\n}\n\nfunction buildInit1Step4Packet(crypt: Crypt, data: Uint8Array): Uint8Array | null {\n if (data.length !== INIT_TYPE_LEN + 64 + 64 + 4 + 100) return null;\n // One challenge per connection attempt, whose Crypt is its own. Each answer\n // costs up to a second of synchronous squarings, and a second would choose a\n // new alpha behind the clientinitiv already sent. The same challenge again\n // means the server did not get our answer, so it gets the same answer,\n // without solving anything; a different one gets none.\n const answered = answeredChallenges.get(crypt);\n if (answered !== undefined) {\n return Buffer.from(answered.challenge).equals(Buffer.from(data)) ? answered.answer : null;\n }\n\n const level = new DataView(data.buffer, data.byteOffset).getUint32(1 + 128, false);\n const y = crypt.solveRsaChallenge(data, 1, level);\n\n const alphaB64 = Buffer.from(crypt.newAlpha()).toString(\"base64\");\n const omegaB64 = crypt.identity.publicKey();\n\n const cmd = buildCommandOrdered(\"clientinitiv\", [\n [\"alpha\", alphaB64],\n [\"omega\", omegaB64],\n [\"ot\", \"1\"],\n [\"ip\", \"\"],\n ]);\n const cmdBytes = Buffer.from(cmd);\n\n const sendData = new Uint8Array(INIT_VERSION_LEN + INIT_TYPE_LEN + 232 + 64 + cmdBytes.length);\n const view = new DataView(sendData.buffer);\n view.setUint32(0, INIT_VERSION, false);\n sendData[4] = 0x04;\n sendData.set(data.slice(1, 233), 5);\n sendData.set(y.slice(0, 64), 5 + 232);\n sendData.set(cmdBytes, 5 + 232 + 64);\n\n answeredChallenges.set(crypt, { challenge: Uint8Array.from(data), answer: sendData });\n return sendData;\n}\n","import { createSocket } from \"node:dgram\";\nimport { lookup } from \"node:dns/promises\";\nimport { parseConnectAddress } from \"../address.js\";\nimport type { Crypt } from \"../crypto/crypt.js\";\nimport type { DatagramSocket, SocketFactory } from \"../types.js\";\nimport type { Logger } from \"@honeybbq/teamspeak-core\";\nimport { noopLogger } from \"@honeybbq/teamspeak-core\";\nimport {\n type Packet,\n PacketType,\n PacketFlags,\n packetType,\n packetFlags,\n buildC2SHeader,\n parseS2CHeader,\n} from \"./packet.js\";\nimport { ConnectionTimeoutError } from \"../errors.js\";\nimport { abortable, abortReason } from \"../abort.js\";\nimport { NotConnectedError, TeamspeakError } from \"@honeybbq/teamspeak-core\";\nimport { GenerationWindow } from \"./generation-window.js\";\nimport { Qlz } from \"./quicklz.js\";\nimport { processInit1 } from \"../handshake/crypt-handshake.js\";\n\nconst MAX_OUT_PACKET_SIZE = 500;\nconst RECEIVE_PACKET_WINDOW_SIZE = 1024;\nconst PING_INTERVAL_MS = 5_000;\nconst PACKET_TIMEOUT_MS = 60_000;\nconst MAX_RETRY_INTERVAL_MS = 1_000;\nconst HEADER_SIZE = 5;\nconst TAG_SIZE = 8;\nconst VOICE_HEADER_SIZE = 3;\nconst WHISPER_HEADER_SIZE = 5;\nconst RESEND_BASE_INTERVAL_MS = 500;\nconst RESEND_LOOP_INTERVAL_MS = 100;\n\n/**\n * The largest command reassembled from fragments. The receive window already\n * bounds how many fragments one command can span; this bounds their total\n * size, which a datagram's own size limit would otherwise let reach tens of\n * megabytes.\n */\nconst MAX_REASSEMBLED_SIZE = 1 << 20;\n\n/**\n * The largest datagram taken. TeamSpeak's packets are at most 500 bytes; a\n * larger one is no packet of the protocol's, and is dropped before anything\n * is decrypted or held.\n */\nexport const MAX_DATAGRAM_SIZE: number = 4096;\n\n/**\n * The most command bytes held, across both receive queues, waiting for the\n * packets before them. A server's in-order traffic drains at once and a full\n * window of real packets is under a megabyte; past this, a packet is dropped\n * unacknowledged, so the server sends it again once there is room.\n */\nexport const MAX_QUEUED_BYTES: number = 1 << 20;\n\n/**\n * The packet types the server may send unencrypted: voice, which TeamSpeak\n * never encrypts, ping and pong, and acknowledgements — TS3 3.13 and TS6 6.0\n * both acknowledge commands with plaintext Acks once crypto init has\n * completed. An Ack carries nothing but the id it acknowledges, so a forged\n * one can at worst stop a resend, which dropping the packet would do too.\n * Init1 is handled before decryption.\n */\nconst UNENCRYPTED_TYPES: ReadonlySet<number> = new Set<number>([\n PacketType.Voice,\n PacketType.VoiceWhisper,\n PacketType.Ping,\n PacketType.Pong,\n PacketType.Ack,\n PacketType.AckLow,\n PacketType.Init1,\n]);\n\ninterface ResendPacket {\n packet: Packet;\n firstSend: number;\n lastSend: number;\n retryCount: number;\n nextInterval: number;\n}\n\nexport class PacketHandler {\n onPacket: ((p: Packet) => void) | null = null;\n onClosed: ((err: Error | null) => void) | null = null;\n /**\n * A received datagram could not be handled: it was malformed, or handling it\n * threw. The datagram is dropped either way; the owner decides whether that\n * ends the connection. Without an owner the error is logged.\n */\n onReceiveError: ((error: unknown) => void) | null = null;\n\n readonly #crypt: Crypt;\n readonly #logger: Logger;\n readonly #socketFactory: SocketFactory | undefined;\n\n #conn: DatagramSocket | null = null;\n #clientID = 0;\n #closed = false;\n #stopPing: (() => void) | null = null;\n #stopResend: (() => void) | null = null;\n #lastMessageReceived = Date.now();\n\n #packetCounter = new Uint16Array(9);\n #generationCounter = new Uint32Array(9);\n\n #recvWindowCommand = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #recvWindowCommandLow = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #sendWindowCommand = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n #sendWindowCommandLow = new GenerationWindow(1 << 16, RECEIVE_PACKET_WINDOW_SIZE);\n\n #commandQueue = new Map<number, Packet>();\n #commandLowQueue = new Map<number, Packet>();\n /** The bytes held in both command queues; see MAX_QUEUED_BYTES. */\n #queuedBytes = 0;\n #ackManager = new Map<number, ResendPacket>();\n /**\n * The last Init1 packet the client sent, resent until the handshake's final\n * acknowledgement. Init1 packets are not acknowledged one by one: each step\n * the client sends replaces it, and only `receivedFinalInitAck` clears it.\n * Receiving an Init1 does not, as the client may have nothing to answer with.\n */\n #initPacketCheck: ResendPacket | null = null;\n /**\n * Command packets sent under the dummy key, before crypto init completed:\n * clientek, in practice. Both TS3 and TS6 acknowledge clientek under the\n * dummy key even though it completes crypto init, so the dummy key stays\n * acceptable for exactly those acknowledgements, and for nothing else.\n */\n #dummyCommandIDs = new Set<number>();\n #resends = 0;\n\n constructor(crypt: Crypt, logger: Logger = noopLogger, socketFactory?: SocketFactory) {\n this.#crypt = crypt;\n this.#logger = logger;\n this.#socketFactory = socketFactory;\n }\n\n setClientID(id: number): void {\n this.#clientID = id;\n }\n\n /**\n * Resolve `addr`, open a socket to it and start the handshake.\n *\n * Aborting `signal`, or closing the handler, while this runs abandons it: the\n * lookup's answer is ignored, and a socket that finishes connecting\n * afterwards is closed rather than started, so no handshake begins after\n * the connection was given up.\n */\n async connect(addr: string, signal?: AbortSignal): Promise<void> {\n const { host, portNumber } = parseConnectAddress(addr);\n this.#throwIfAbandoned(signal);\n\n // Resolve before choosing a socket family. `isIP()` only recognises literal\n // addresses and returns 0 for every hostname, so picking the family from it\n // sent every hostname to a udp4 socket — and a udp4 socket handed a name\n // that resolves to IPv6 drops the datagrams with no error at all. On a\n // stock macOS/Linux box `localhost` resolves to ::1 first, so that path\n // silently never connected. Let DNS decide, then match the family.\n let resolved: { address: string; family: number };\n try {\n resolved = await abortable(lookup(host), signal);\n } catch (error) {\n if (signal?.aborted) throw error;\n // Wrapped, not classed as an invalid address: a lookup can fail for a\n // while (EAI_AGAIN) and then succeed, which a reconnect should retry.\n throw new TeamspeakError(`could not resolve ${host}`, { cause: error });\n }\n const { address, family } = resolved;\n this.#throwIfAbandoned(signal);\n\n const family6 = family === 6;\n const socket: DatagramSocket = this.#socketFactory\n ? this.#socketFactory(family6 ? 6 : 4)\n : createSocket(family6 ? \"udp6\" : \"udp4\");\n\n await new Promise<void>((resolve, reject) => {\n let done = false;\n const fail = (error: unknown): void => {\n if (done) return;\n done = true;\n socket.off(\"error\", onError);\n signal?.removeEventListener(\"abort\", onAbort);\n closeQuietly(socket);\n reject(error);\n };\n const onError = (error: Error): void => fail(error);\n const onAbort = (): void => fail(abortReason(signal!));\n socket.once(\"error\", onError);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n // Connect to the resolved address, not the original host, so the socket\n // cannot end up talking to a different family than it was created for.\n socket.connect(portNumber, address, () => {\n if (done) return;\n if (this.#closed || signal?.aborted) {\n fail(signal?.aborted ? abortReason(signal) : new NotConnectedError());\n return;\n }\n done = true;\n socket.off(\"error\", onError);\n signal?.removeEventListener(\"abort\", onAbort);\n this.start(socket);\n resolve();\n });\n });\n }\n\n #throwIfAbandoned(signal: AbortSignal | undefined): void {\n signal?.throwIfAborted();\n if (this.#closed) throw new NotConnectedError();\n }\n\n /** Take over a connected socket and start the handshake on it. A closed handler closes it instead. */\n start(conn: DatagramSocket): void {\n if (this.#closed) {\n closeQuietly(conn);\n return;\n }\n this.#conn = conn;\n this.#lastMessageReceived = Date.now();\n\n conn.on(\"message\", (msg) => {\n if (this.#closed) return;\n // Everything here parses what the network sent. Nothing it throws may\n // escape: from a socket callback it would be an uncaught exception, and\n // a malformed datagram from the server would take the process down.\n try {\n this.#handleRawPacket(new Uint8Array(msg.buffer, msg.byteOffset, msg.byteLength));\n } catch (error: unknown) {\n if (this.onReceiveError) this.onReceiveError(error);\n else this.#logger.debug(\"dropped a malformed packet\", { error: String(error) });\n }\n });\n conn.on(\"error\", (err) => {\n this.#logger.error(\"udp error\", err);\n this.#triggerClose(err);\n });\n conn.on(\"close\", () => this.#triggerClose(null));\n\n this.#packetCounter[PacketType.Command] = 1;\n this.#packetCounter[PacketType.Init1] = 101;\n\n const init1Data = processInit1(this.#crypt, null);\n if (init1Data) this.#sendPacketRaw(PacketType.Init1, init1Data, 0);\n\n // Ping loop\n const pingTimer = setInterval(() => {\n if (this.#crypt.cryptoInitComplete) {\n this.sendPacket(PacketType.Ping, new Uint8Array(0), PacketFlags.Unencrypted);\n }\n }, PING_INTERVAL_MS);\n this.#stopPing = () => clearInterval(pingTimer);\n\n // Resend loop\n const resendTimer = setInterval(() => this.#checkResends(), RESEND_LOOP_INTERVAL_MS);\n this.#stopResend = () => clearInterval(resendTimer);\n }\n\n /**\n * Stop resending the last Init1 packet the client sent. Until this is called,\n * the latest step stays pending whatever the server sends in between: a step\n * the client does not answer, an unknown one or a second RSA challenge, must\n * not stop the resending of its own. The server's `initivexpand2` command\n * acknowledges the last step, not an Init1 reply.\n */\n receivedFinalInitAck(): void {\n this.#initPacketCheck = null;\n }\n\n sendPacket(pType: PacketType, data: Uint8Array, flags: number): void {\n const dummy = !this.#crypt.cryptoInitComplete;\n if (data.length > 487 && pType !== PacketType.Voice && pType !== PacketType.VoiceWhisper) {\n this.#sendSplitPacket(pType, data, flags, dummy);\n return;\n }\n this.#sendPacketRaw(pType, data, flags, dummy);\n }\n\n sendVoicePacket(data: Uint8Array, codec: number): void {\n const pID = this.#packetCounter[PacketType.Voice]!;\n const pGen = this.#generationCounter[PacketType.Voice]!;\n this.#packetCounter[PacketType.Voice] = (pID + 1) & 0xffff;\n if (this.#packetCounter[PacketType.Voice] === 0) {\n this.#generationCounter[PacketType.Voice]!++;\n }\n\n const payloadLen = VOICE_HEADER_SIZE + data.length;\n const voicePayload = new Uint8Array(payloadLen);\n new DataView(voicePayload.buffer).setUint16(0, pID, false);\n voicePayload[2] = codec;\n voicePayload.set(data, VOICE_HEADER_SIZE);\n\n const p: Packet = {\n typeFlagged: PacketType.Voice | PacketFlags.Unencrypted,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data: voicePayload,\n receivedAt: 0,\n };\n\n const header = buildC2SHeader(p);\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + payloadLen);\n final.set(this.#crypt.fakeSignature, 0);\n final.set(header, TAG_SIZE);\n final.set(voicePayload, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n /** Send an unencrypted TeamSpeak voice whisper packet to up to 32 clients. */\n sendWhisperPacket(data: Uint8Array, targetClientIds: number[], codec: number): void {\n if (targetClientIds.length === 0) throw new RangeError(\"a whisper needs at least one target\");\n if (targetClientIds.length > 32) throw new RangeError(\"a whisper has at most 32 targets\");\n if (targetClientIds.some((id) => !Number.isInteger(id) || id < 0 || id > 0xffff)) {\n throw new RangeError(\"invalid whisper target\");\n }\n\n const pID = this.#packetCounter[PacketType.VoiceWhisper]!;\n const pGen = this.#generationCounter[PacketType.VoiceWhisper]!;\n this.#packetCounter[PacketType.VoiceWhisper] = (pID + 1) & 0xffff;\n if (this.#packetCounter[PacketType.VoiceWhisper] === 0) {\n this.#generationCounter[PacketType.VoiceWhisper] = (pGen + 1) >>> 0;\n }\n\n const payloadLen = WHISPER_HEADER_SIZE + targetClientIds.length * 2 + data.length;\n const whisperPayload = new Uint8Array(payloadLen);\n const view = new DataView(whisperPayload.buffer);\n view.setUint16(0, pID, false);\n whisperPayload[2] = codec;\n whisperPayload[3] = 0;\n whisperPayload[4] = targetClientIds.length;\n for (let index = 0; index < targetClientIds.length; index++) {\n view.setUint16(WHISPER_HEADER_SIZE + index * 2, targetClientIds[index]!, false);\n }\n whisperPayload.set(data, WHISPER_HEADER_SIZE + targetClientIds.length * 2);\n\n const packet: Packet = {\n typeFlagged: PacketType.VoiceWhisper | PacketFlags.Unencrypted,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data: whisperPayload,\n receivedAt: 0,\n };\n const header = buildC2SHeader(packet);\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + payloadLen);\n final.set(this.#crypt.fakeSignature, 0);\n final.set(header, TAG_SIZE);\n final.set(whisperPayload, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n /** How many packets have been sent again for want of an acknowledgement. */\n get resends(): number {\n return this.#resends;\n }\n\n /** Whether there is a live socket to send on. */\n get isOpen(): boolean {\n return this.#conn !== null && !this.#closed;\n }\n\n close(): void {\n if (this.#closed) return;\n this.#closed = true;\n this.#stopPing?.();\n this.#stopResend?.();\n\n // The socket may already be closed — this runs from its own \"close\" event\n // when a connection drops — and dgram throws ERR_SOCKET_DGRAM_NOT_RUNNING\n // on a second close. Letting that escape would surface as an uncaught\n // exception inside an event callback, taking the process with it instead of\n // reporting a dropped connection.\n const conn = this.#conn;\n this.#conn = null;\n if (conn === null) return;\n try {\n conn.close();\n } catch (error: unknown) {\n this.#logger.debug(\"socket already closed\", { error: String(error) });\n }\n }\n\n // ---- Private ---------------------------------------------------------------\n\n #sendSplitPacket(pType: PacketType, data: Uint8Array, flags: number, dummy: boolean): void {\n const maxSize = MAX_OUT_PACKET_SIZE - HEADER_SIZE - TAG_SIZE; // 487\n let pos = 0;\n let first = true;\n\n while (pos < data.length) {\n const blockSize = Math.min(data.length - pos, maxSize);\n const last = pos + blockSize === data.length;\n\n let pFlags = flags;\n if (first !== last) pFlags |= PacketFlags.Fragmented;\n\n this.#sendPacketRaw(pType, data.slice(pos, pos + blockSize), pFlags, dummy);\n pos += blockSize;\n first = false;\n }\n }\n\n #sendPacketRaw(\n pType: PacketType,\n data: Uint8Array,\n flags: number,\n dummy = !this.#crypt.cryptoInitComplete,\n ): void {\n flags = applyProtocolFlags(pType, flags);\n const [pID, pGen] = this.#nextPacketIdentity(pType);\n const p: Packet = {\n typeFlagged: pType | flags,\n id: pID,\n clientID: this.#clientID,\n generationID: pGen,\n data,\n receivedAt: 0,\n };\n\n const unencrypted = (flags & PacketFlags.Unencrypted) !== 0;\n const header = buildC2SHeader(p);\n const [ciphertext, tag] = this.#crypt.encrypt(\n pType,\n pID,\n pGen,\n header,\n data,\n dummy,\n unencrypted,\n );\n\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + ciphertext.length);\n final.set(tag.slice(0, TAG_SIZE), 0);\n final.set(header, TAG_SIZE);\n final.set(ciphertext, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n if (dummy && pType === PacketType.Command) this.#dummyCommandIDs.add(pID);\n\n const rp: ResendPacket = {\n packet: p,\n firstSend: Date.now(),\n lastSend: Date.now(),\n retryCount: 0,\n nextInterval: RESEND_BASE_INTERVAL_MS,\n };\n this.#trackResend(pType, p, rp);\n }\n\n #write(data: Uint8Array): void {\n if (!this.#conn) return;\n try {\n this.#conn.send(data, (err) => {\n if (err) this.#logger.warn(\"udp send error\", err);\n });\n } catch (error: unknown) {\n const normalized = error instanceof Error ? error : new Error(String(error));\n // dgram can throw synchronously for an invalid family/address pair. A\n // malformed remote target must close this session, never escape from an\n // async socket callback and terminate the gateway process.\n this.#logger.error(\"udp send failed\", normalized);\n this.#triggerClose(normalized);\n }\n }\n\n #handleRawPacket(raw: Uint8Array): void {\n if (raw.length < 11) return;\n if (raw.length > MAX_DATAGRAM_SIZE) {\n this.#logger.debug(\"dropped an oversized datagram\", { size: raw.length });\n return;\n }\n\n const tag = raw.slice(0, TAG_SIZE);\n const header = raw.slice(TAG_SIZE, TAG_SIZE + 3);\n const ciphertext = raw.slice(TAG_SIZE + 3);\n\n const parsed = parseS2CHeader(header);\n // Init1 belongs to the start of the handshake; once crypto init has\n // completed, another one can only restart a session that is already set up.\n if ((parsed.typeFlagged & 0x0f) === PacketType.Init1 && this.#crypt.cryptoInitComplete) return;\n\n const p: Packet = {\n ...parsed,\n clientID: 0,\n generationID: this.#resolveGeneration(parsed.id, parsed.typeFlagged & 0x0f),\n data: new Uint8Array(0),\n receivedAt: Date.now(),\n };\n\n const decrypted = this.#decryptPacketData(p, header, ciphertext, tag);\n if (decrypted === null) return;\n p.data = decrypted.plaintext;\n // Only a packet that decrypted shows the server is there: anyone can send\n // datagrams that do not, and they must not keep a dead session alive.\n this.#lastMessageReceived = Date.now();\n\n const pType = packetType(p);\n\n if (pType === PacketType.Ping) {\n this.#sendPong(p.id, decrypted.dummyUsed);\n return;\n }\n\n if (!this.#handleCommandWindowAndAck(p, decrypted.dummyUsed)) return;\n\n this.#handlePacketQueue(p);\n this.#updatePostReceiveState(p);\n }\n\n #resolveGeneration(id: number, pType: number): number {\n switch (pType as PacketType) {\n case PacketType.Command:\n return this.#recvWindowCommand.getGeneration(id);\n case PacketType.CommandLow:\n return this.#recvWindowCommandLow.getGeneration(id);\n case PacketType.Ack:\n return this.#sendWindowCommand.getGeneration(id);\n case PacketType.AckLow:\n return this.#sendWindowCommandLow.getGeneration(id);\n default:\n return 0;\n }\n }\n\n #decryptPacketData(\n p: Packet,\n header: Uint8Array,\n ciphertext: Uint8Array,\n tag: Uint8Array,\n ): { plaintext: Uint8Array; dummyUsed: boolean } | null {\n const unencrypted = (packetFlags(p) & PacketFlags.Unencrypted) !== 0;\n const dummy = !this.#crypt.cryptoInitComplete;\n let dummyUsed = dummy;\n const pType = packetType(p);\n const gen = p.generationID;\n\n // An unencrypted packet is checked against the fake signature only, and\n // that signature is no secret: every plaintext ping, pong and voice packet\n // carries it. A command must therefore never be taken unencrypted, or\n // anyone on the path could forge text messages, kicks and command answers.\n if (unencrypted && !UNENCRYPTED_TYPES.has(pType)) {\n this.#logger.debug(\"dropped an unencrypted packet of a type that must be encrypted\", {\n type: pType,\n id: p.id,\n });\n return null;\n }\n\n try {\n const plaintext = this.#crypt.decrypt(\n pType,\n p.id,\n gen,\n header,\n ciphertext,\n tag,\n dummy,\n unencrypted,\n );\n return { plaintext, dummyUsed };\n } catch {\n // Before crypto init only the dummy key exists: there is no other key\n // to try.\n if (dummy) return null;\n // No other generation is tried: the receive window already places the\n // id in its generation, and a packet that decrypts only under the one\n // before is an old packet replayed after the 16-bit id wrapped. Neither\n // TS3 nor TS6 ever needed a guess at the next one.\n\n // The acknowledgement of a command sent under the dummy key may itself\n // use the dummy key, and is the one packet that may once crypto init has\n // completed (see #dummyCommandIDs). A dummy-keyed command after that is\n // dropped: the dummy key is public.\n if (!dummy && pType === PacketType.Ack && !unencrypted) {\n try {\n const plaintext = this.#crypt.decrypt(\n pType,\n p.id,\n gen,\n header,\n ciphertext,\n tag,\n true,\n false,\n );\n const acked = plaintext.length >= 2 ? (plaintext[0]! << 8) | plaintext[1]! : Number.NaN;\n if (this.#dummyCommandIDs.delete(acked)) return { plaintext, dummyUsed: true };\n } catch {\n // fall through\n }\n }\n\n return null;\n }\n }\n\n #handleCommandWindowAndAck(p: Packet, dummyUsed: boolean): boolean {\n const pType = packetType(p);\n if (pType !== PacketType.Command && pType !== PacketType.CommandLow) return true;\n\n const win = pType === PacketType.Command ? this.#recvWindowCommand : this.#recvWindowCommandLow;\n const ackType = pType === PacketType.Command ? PacketType.Ack : PacketType.AckLow;\n\n if (!win.isInWindow(p.id)) {\n if (win.isOldPacket(p.id)) {\n this.#sendAck(p.id, ackType, dummyUsed);\n }\n return false;\n }\n const queue = pType === PacketType.Command ? this.#commandQueue : this.#commandLowQueue;\n const held = queue.get(p.id)?.data.length ?? 0;\n // The packet the queue waits for is always taken: it is what drains it.\n const next = pType === PacketType.Command ? this.#_nextCommandID : this.#_nextCommandLowID;\n if (p.id !== next && this.#queuedBytes - held + p.data.length > MAX_QUEUED_BYTES) {\n // Not acknowledged: the server sends it again.\n this.#logger.debug(\"dropped a command packet: the receive queues are full\", { id: p.id });\n return false;\n }\n this.#sendAck(p.id, ackType, dummyUsed);\n return true;\n }\n\n #sendAck(packetID: number, ackType: PacketType, dummyUsed: boolean): void {\n const ackData = new Uint8Array(2);\n new DataView(ackData.buffer).setUint16(0, packetID, false);\n this.#sendPacketRaw(ackType, ackData, 0, dummyUsed);\n }\n\n #sendPong(pID: number, dummyUsed: boolean): void {\n const pongData = new Uint8Array(2);\n new DataView(pongData.buffer).setUint16(0, pID, false);\n this.#sendPacketRaw(PacketType.Pong, pongData, PacketFlags.Unencrypted, dummyUsed);\n }\n\n #handlePacketQueue(p: Packet): void {\n const pType = packetType(p);\n if (pType !== PacketType.Command && pType !== PacketType.CommandLow) {\n this.onPacket?.(p);\n return;\n }\n\n const isCommand = pType === PacketType.Command;\n const queue = isCommand ? this.#commandQueue : this.#commandLowQueue;\n const win = isCommand ? this.#recvWindowCommand : this.#recvWindowCommandLow;\n\n this.#hold(queue, p);\n\n if (isCommand) {\n this.#fastForwardMissingPackets(queue, win, true);\n } else {\n this.#fastForwardMissingPackets(queue, win, false);\n }\n\n while (true) {\n const current = isCommand ? this.#_nextCommandID : this.#_nextCommandLowID;\n const packet = queue.get(current);\n if (packet === undefined) break;\n\n const result = this.#tryReassemble(packet, queue, current, win);\n if (!result) break;\n\n const [reassembled, newNext] = result;\n if (isCommand) this.#_nextCommandID = newNext;\n else this.#_nextCommandLowID = newNext;\n\n if (reassembled === null) {\n this.#logger.debug(\"dropped a command over the reassembly limit\", { id: current });\n continue;\n }\n if (!this.#tryDecompress(reassembled)) continue;\n this.onPacket?.(reassembled);\n }\n }\n\n /** Put a packet in its queue, counting its bytes; one with the same id is replaced. */\n #hold(queue: Map<number, Packet>, p: Packet): void {\n this.#release(queue, p.id);\n queue.set(p.id, p);\n this.#queuedBytes += p.data.length;\n }\n\n #release(queue: Map<number, Packet>, id: number): void {\n const held = queue.get(id);\n if (held === undefined) return;\n queue.delete(id);\n this.#queuedBytes -= held.data.length;\n }\n\n #_nextCommandID = 0;\n #_nextCommandLowID = 0;\n\n #fastForwardMissingPackets(\n queue: Map<number, Packet>,\n win: GenerationWindow,\n isCommand: boolean,\n ): void {\n let nextID = isCommand ? this.#_nextCommandID : this.#_nextCommandLowID;\n while (!queue.has(nextID) && hasOldNewerPacket(queue, nextID)) {\n nextID = (nextID + 1) & 0xffff;\n win.advance(1);\n }\n if (isCommand) this.#_nextCommandID = nextID;\n else this.#_nextCommandLowID = nextID;\n }\n\n #tryReassemble(\n startPacket: Packet,\n queue: Map<number, Packet>,\n nextID: number,\n win: GenerationWindow,\n ): [reassembled: Packet | null, newNextID: number] | null {\n if ((packetFlags(startPacket) & PacketFlags.Fragmented) === 0) {\n this.#release(queue, nextID);\n win.advance(1);\n return [startPacket, (nextID + 1) & 0xffff];\n }\n\n const fragments: Packet[] = [];\n let totalSize = 0;\n let currID = nextID;\n let startSeen = false;\n\n // Ends at the fragment that closes the command, or returns while one is\n // still missing.\n while (true) {\n const frag = queue.get(currID);\n if (!frag) return null;\n fragments.push(frag);\n totalSize += frag.data.length;\n if (totalSize > MAX_REASSEMBLED_SIZE) {\n // Dropped whole, so the window moves past it rather than waiting on\n // the rest of a command that will never be accepted.\n for (let i = 0; i < fragments.length; i++) {\n this.#release(queue, nextID);\n win.advance(1);\n nextID = (nextID + 1) & 0xffff;\n }\n return [null, nextID];\n }\n\n const fragmented = (packetFlags(frag) & PacketFlags.Fragmented) !== 0;\n if (!startSeen) {\n startSeen = true;\n if (!fragmented) break;\n } else if (fragmented) {\n break;\n }\n currID = (currID + 1) & 0xffff;\n }\n\n const combined = new Uint8Array(totalSize);\n let pos = 0;\n for (const frag of fragments) {\n combined.set(frag.data, pos);\n pos += frag.data.length;\n this.#release(queue, nextID);\n win.advance(1);\n nextID = (nextID + 1) & 0xffff;\n }\n\n startPacket.data = combined;\n startPacket.typeFlagged &= ~PacketFlags.Fragmented;\n return [startPacket, nextID];\n }\n\n /** Decompress a command in place; false when it cannot be, and is to be dropped. */\n #tryDecompress(packet: Packet): boolean {\n if ((packetFlags(packet) & PacketFlags.Compressed) === 0) return true;\n try {\n const qlz = new Qlz();\n packet.data = qlz.decompress(packet.data);\n packet.typeFlagged &= ~PacketFlags.Compressed;\n return true;\n } catch (err) {\n // Passing the compressed bytes on as if they were the command would\n // hand the parser garbage.\n this.#logger.debug(\"dropped a command that failed to decompress\", {\n id: packet.id,\n error: String(err),\n });\n return false;\n }\n }\n\n #updatePostReceiveState(p: Packet): void {\n const pType = packetType(p);\n\n if ((pType === PacketType.Ack || pType === PacketType.AckLow) && p.data.length >= 2) {\n const ackID = new DataView(p.data.buffer, p.data.byteOffset).getUint16(0, false);\n const targetType = pType === PacketType.Ack ? PacketType.Command : PacketType.CommandLow;\n const key = (targetType << 16) | ackID;\n this.#ackManager.delete(key);\n }\n }\n\n #nextPacketIdentity(pType: PacketType): [id: number, gen: number] {\n const pID = this.#packetCounter[pType]!;\n const pGen = this.#generationCounter[pType]!;\n\n if (pType === PacketType.Init1) return [pID, pGen];\n\n this.#packetCounter[pType] = (pID + 1) & 0xffff;\n if (this.#packetCounter[pType] === 0) {\n this.#generationCounter[pType] = (pGen + 1) >>> 0;\n }\n\n if (pType === PacketType.Command) {\n this.#sendWindowCommand.advanceToExcluded(pID);\n } else if (pType === PacketType.CommandLow) {\n this.#sendWindowCommandLow.advanceToExcluded(pID);\n }\n\n return [pID, pGen];\n }\n\n #trackResend(pType: PacketType, p: Packet, rp: ResendPacket): void {\n if (pType === PacketType.Init1) {\n this.#initPacketCheck = rp;\n return;\n }\n if (pType === PacketType.Command || pType === PacketType.CommandLow) {\n const key = (pType << 16) | p.id;\n this.#ackManager.set(key, rp);\n }\n }\n\n #checkResends(): void {\n const now = Date.now();\n\n if (now - this.#lastMessageReceived > PACKET_TIMEOUT_MS) {\n this.#logger.warn(\"idle timeout\");\n this.#triggerClose(new ConnectionTimeoutError());\n return;\n }\n\n if (this.#initPacketCheck) {\n this.#doResend(this.#initPacketCheck, now);\n }\n\n for (const [key, rp] of this.#ackManager) {\n if (now - rp.firstSend > PACKET_TIMEOUT_MS) {\n this.#ackManager.delete(key);\n this.#triggerClose(new ConnectionTimeoutError());\n return;\n }\n this.#doResend(rp, now);\n }\n }\n\n #doResend(rp: ResendPacket, now: number): void {\n if (now - rp.lastSend < rp.nextInterval) return;\n\n rp.lastSend = now;\n rp.retryCount++;\n this.#resends++;\n rp.nextInterval = Math.min(rp.nextInterval * 2, MAX_RETRY_INTERVAL_MS);\n\n const dummy = !this.#crypt.cryptoInitComplete;\n const unencrypted = (packetFlags(rp.packet) & PacketFlags.Unencrypted) !== 0;\n const header = buildC2SHeader(rp.packet);\n const pType = packetType(rp.packet);\n\n const [ciphertext, tag] = this.#crypt.encrypt(\n pType,\n rp.packet.id,\n rp.packet.generationID,\n header,\n rp.packet.data,\n dummy,\n unencrypted,\n );\n\n const final = new Uint8Array(TAG_SIZE + HEADER_SIZE + ciphertext.length);\n final.set(tag.slice(0, TAG_SIZE), 0);\n final.set(header, TAG_SIZE);\n final.set(ciphertext, TAG_SIZE + HEADER_SIZE);\n this.#write(final);\n }\n\n #triggerClose(err: Error | null): void {\n if (this.#closed) return;\n this.close();\n this.onClosed?.(err);\n }\n}\n\n// ---- Helpers ----------------------------------------------------------------\n\n/** Close a socket that may already be closed; dgram throws on a second close. */\nfunction closeQuietly(socket: DatagramSocket): void {\n try {\n socket.close();\n } catch {\n // Already closed.\n }\n}\n\nfunction applyProtocolFlags(pType: PacketType, flags: number): number {\n if (pType === PacketType.Command || pType === PacketType.CommandLow) {\n return flags | PacketFlags.NewProtocol;\n }\n return flags;\n}\n\nfunction hasOldNewerPacket(queue: Map<number, Packet>, nextID: number): boolean {\n const now = Date.now();\n for (const [id, pkg] of queue) {\n const diff = (id - nextID + 0x10000) & 0xffff;\n if (diff < 0x8000 && now - pkg.receivedAt > 5_000) {\n return true;\n }\n }\n return false;\n}\n","import { parseCommand } from \"@honeybbq/teamspeak-core/internal\";\nimport { ServerError } from \"@honeybbq/teamspeak-core\";\nimport { parseErrorCode } from \"@honeybbq/teamspeak-core/internal\";\n\nimport type { ResponseSpec } from \"@honeybbq/teamspeak-core/internal\";\n\nexport interface CommandResult {\n err: Error | null;\n data: Record<string, string>[];\n}\n\n/** A row waiting for the `error` that says which command it answered. */\ninterface BufferedRow {\n /** The notification that carried it, or \"\" for a nameless data row. */\n readonly source: string;\n readonly params: Record<string, string>;\n}\n\ninterface PendingCommand {\n readonly resolve: (result: CommandResult) => void;\n readonly spec: ResponseSpec | undefined;\n /** The request's value for `spec.correlated.key`, when there is one. */\n readonly correlation: string | undefined;\n /** Correlated answers that arrived before the command's own `error`. */\n readonly correlated: Record<string, string>[];\n /** The command's `error` result, held while its correlated answer is due. */\n settled?: CommandResult;\n}\n\n/**\n * Matches the server's answers to the commands that asked for them.\n *\n * The server handles one client's commands in order and closes each answer\n * with `error … return_code=N`, so every row seen since the previous `error`\n * belongs to command N. Rows are therefore held, tagged with where they came\n * from, until that `error` says whose they are — attributing them on arrival\n * would mean guessing which in-flight command the server is answering, and a\n * command can be registered here well before it is sent (it first waits on the\n * throttle and the middleware chain).\n *\n * A nameless row always belongs to the command. A notification row belongs to\n * it only if the command declared that notification as its answer (see\n * command/responses.ts): the same `notifyclientmoved` that answers nothing can\n * arrive between any two commands.\n *\n * The welcome sequence is the exception. The server pushes channellist,\n * channelgrouplist and the rest unprompted right after the handshake, before\n * `channellistfinished`; without the gate they would land in the first\n * command's answer as duplicate rows and a phantom cid=0.\n */\nexport class CommandTracker {\n readonly #pending = new Map<number, PendingCommand>();\n readonly #ownClientID: () => number;\n #nextRC = 0;\n #buffer: BufferedRow[] = [];\n #welcomeComplete = false;\n\n /** @param ownClientID the client's clid, for answers filtered by invoker. */\n constructor(ownClientID: () => number = () => 0) {\n this.#ownClientID = ownClientID;\n }\n\n register(\n spec?: ResponseSpec,\n correlation?: string,\n ): [rc: number, promise: Promise<CommandResult>] {\n this.#nextRC++;\n const rc = this.#nextRC;\n const promise = new Promise<CommandResult>((resolve) => {\n this.#pending.set(rc, { resolve, spec, correlation, correlated: [] });\n });\n return [rc, promise];\n }\n\n unregister(rc: number): void {\n this.#pending.delete(rc);\n }\n\n /** Marks the end of the welcome sequence and drops what it left behind. */\n signalWelcomeComplete(): void {\n this.#welcomeComplete = true;\n this.#buffer = [];\n }\n\n /** Whether some in-flight command declared `name` as its answer. */\n expects(name: string): boolean {\n for (const p of this.#pending.values()) {\n if (p.spec?.notifications?.includes(name)) return true;\n if (p.spec?.correlated?.notifications.includes(name)) return true;\n }\n return false;\n }\n\n /** Hold a row until the next `error` says which command it answered. */\n buffer(params: Record<string, string>, source = \"\"): void {\n if (!this.#welcomeComplete) return;\n if (this.#pending.size === 0) return;\n this.#buffer.push({ source, params });\n }\n\n /**\n * Offer a notification to commands answered after their `error`.\n *\n * Matching is on the echoed request field, so it does not matter whether the\n * notification beats the `error` or follows it.\n */\n offerCorrelated(name: string, params: Record<string, string>): void {\n for (const [rc, p] of this.#pending) {\n const c = p.spec?.correlated;\n if (!c || p.correlation === undefined || !c.notifications.includes(name)) continue;\n if (params[c.key] !== p.correlation) continue;\n\n if (name === c.failure && (params[\"status\"] ?? \"0\") !== \"0\") {\n const err = new ServerError(parseErrorCode(params[\"status\"]), params[\"msg\"] ?? \"\", {\n extraMessage: params[\"extra_msg\"] || undefined,\n });\n this.#settle(rc, p, { err, data: [] });\n return;\n }\n p.correlated.push(params);\n if (p.settled) this.#settle(rc, p, { err: null, data: [...p.settled.data, ...p.correlated] });\n return;\n }\n }\n\n resolve(rc: number, err: Error | null): void {\n const rows = this.#buffer;\n this.#buffer = [];\n const p = this.#pending.get(rc);\n if (!p) return;\n\n const data = rows.filter((row) => this.#answers(p, row)).map((row) => row.params);\n if (err) {\n this.#settle(rc, p, { err, data });\n return;\n }\n // Answered after the error: hold the result until the answer arrives, or\n // the caller's timeout gives up on it.\n if (p.spec?.correlated && p.correlation !== undefined && p.correlated.length === 0) {\n p.settled = { err: null, data };\n return;\n }\n this.#settle(rc, p, { err: null, data: [...data, ...p.correlated] });\n }\n\n discardBuffer(): void {\n this.#buffer = [];\n }\n\n /**\n * Forget every command and fail it with `err`.\n *\n * Dropping them silently would leave each caller waiting out its full\n * timeout for an answer that can no longer come.\n */\n reset(err: Error): void {\n const pending = [...this.#pending.values()];\n this.#pending.clear();\n for (const p of pending) p.resolve({ err, data: [] });\n this.#buffer = [];\n this.#welcomeComplete = false;\n this.#nextRC = 0;\n }\n\n #answers(p: PendingCommand, row: BufferedRow): boolean {\n if (row.source === \"\") return true;\n if (!p.spec?.notifications?.includes(row.source)) return false;\n if (!p.spec.ownRowsOnly) return true;\n return row.params[\"invokerid\"] === String(this.#ownClientID());\n }\n\n #settle(rc: number, p: PendingCommand, result: CommandResult): void {\n this.#pending.delete(rc);\n p.resolve(result);\n }\n}\n\n/**\n * Append the tracker's return_code to a command.\n *\n * The return_code belongs to the tracker: it is how an answer finds its\n * command, so a caller-supplied one would detach the command from its answer.\n * Checked as a parameter rather than as text, because a message body that\n * merely contains \"return_code=\" used to suppress the real one and time the\n * command out.\n */\nexport function appendReturnCode(cmd: string, rc: number): string {\n const params = parseCommand(cmd)?.params ?? {};\n if (Object.hasOwn(params, \"return_code\")) {\n throw new TypeError(\"commands must not carry their own return_code; the client assigns it\");\n }\n return `${cmd} return_code=${rc}`;\n}\n","/**\n * File transfer data.\n *\n * Negotiating a transfer is a command (`initFileUpload`, `initFileDownload`);\n * the bytes then go over a separate TCP connection to the server's file\n * transfer port, opened with the key the negotiation returned.\n */\n\nimport { connect } from \"node:net\";\nimport { pipeline } from \"node:stream/promises\";\nimport type { Duplex, Readable, Writable } from \"node:stream\";\nimport type { FileUploadInfo, FileDownloadInfo } from \"@honeybbq/teamspeak-core\";\nimport type { FileTransferSocketFactory } from \"./types.js\";\nimport { FileTransferError } from \"./errors.js\";\n\n/** How long dialing may take before it fails, unless a signal says otherwise. */\nconst DIAL_TIMEOUT_MS = 10_000;\n\n/** Options for a file transfer. */\nexport interface FileTransferOptions {\n /** Abandons the transfer; it then rejects with the signal's reason. */\n readonly signal?: AbortSignal | undefined;\n /**\n * Opens the connection instead of a direct TCP dial, to route the transfer\n * through a proxy or tunnel.\n */\n readonly socketFactory?: FileTransferSocketFactory | undefined;\n}\n\n/**\n * Open a connection to the file transfer port and send the transfer key.\n * The caller owns the returned stream and must end or destroy it.\n */\nexport async function dialFileTransfer(\n host: string,\n port: number,\n key: string,\n options: FileTransferOptions = {},\n): Promise<Duplex> {\n const { signal, socketFactory } = options;\n signal?.throwIfAborted();\n const socket: Duplex = socketFactory ? socketFactory(host, port) : connect({ host, port });\n\n // Until the caller takes the stream over, its errors are this function's to\n // report: a stream's unhandled `error` event takes the process down.\n const swallow = (): void => {};\n socket.on(\"error\", swallow);\n try {\n await connected(socket, signal);\n await new Promise<void>((resolve, reject) => {\n socket.write(key, (err) =>\n err\n ? reject(\n new FileTransferError(`failed to send transfer key: ${err.message}`, { cause: err }),\n )\n : resolve(),\n );\n });\n } catch (error) {\n socket.destroy();\n throw error;\n } finally {\n socket.off(\"error\", swallow);\n }\n return socket;\n}\n\n/**\n * Wait for a stream to be connected. A `node:net` socket says so with\n * `connect`; a stream from elsewhere that is already writable is taken as\n * connected.\n */\nfunction connected(socket: Duplex, signal: AbortSignal | undefined): Promise<void> {\n const pending = (socket as { pending?: boolean }).pending;\n if (pending === false || (pending === undefined && socket.writable)) return Promise.resolve();\n\n return new Promise<void>((resolve, reject) => {\n const timeout = AbortSignal.timeout(DIAL_TIMEOUT_MS);\n const done = (error?: unknown): void => {\n socket.off(\"connect\", onConnect);\n socket.off(\"ready\", onConnect);\n socket.off(\"error\", onError);\n signal?.removeEventListener(\"abort\", onAbort);\n timeout.removeEventListener(\"abort\", onTimeout);\n if (error === undefined) resolve();\n else reject(error);\n };\n const onConnect = (): void => done();\n const onError = (error: Error): void =>\n done(\n new FileTransferError(`file transfer connection failed: ${error.message}`, {\n cause: error,\n }),\n );\n const onAbort = (): void => done(signal!.reason);\n const onTimeout = (): void => done(new FileTransferError(\"file transfer connection timed out\"));\n socket.once(\"connect\", onConnect);\n socket.once(\"ready\", onConnect);\n socket.once(\"error\", onError);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n timeout.addEventListener(\"abort\", onTimeout, { once: true });\n });\n}\n\n/** Upload `data` over a negotiated transfer. Resolves once every byte is sent. */\nexport async function uploadFileData(\n host: string,\n info: FileUploadInfo,\n data: Readable,\n options: FileTransferOptions = {},\n): Promise<void> {\n const socket = await dialFileTransfer(host, info.port, info.fileTransferKey, options);\n await pipeline(data, socket, options.signal ? { signal: options.signal } : {});\n}\n\n/** Download a negotiated transfer into `dest`. Resolves once the file is written. */\nexport async function downloadFileData(\n host: string,\n info: FileDownloadInfo,\n dest: Writable,\n options: FileTransferOptions = {},\n): Promise<void> {\n const socket = await dialFileTransfer(host, info.port, info.fileTransferKey, options);\n await pipeline(socket, dest, options.signal ? { signal: options.signal } : {});\n}\n\nexport { FileTransferError };\n","import type { EventMiddleware, ServerEvent } from \"./types.js\";\nimport type { CommandExecutor, CommandMiddleware } from \"@honeybbq/teamspeak-core\";\n\n/**\n * Compose a chain of middlewares around a base handler.\n * Rightmost middleware wraps the base first.\n */\nexport function buildCommandChain(\n middlewares: readonly CommandMiddleware[],\n base: CommandExecutor[\"send\"],\n): CommandExecutor[\"send\"] {\n let handler = base;\n for (let i = middlewares.length - 1; i >= 0; i--) {\n handler = middlewares[i]!(handler);\n }\n return handler;\n}\n\nexport function buildEventChain(\n middlewares: EventMiddleware[],\n base: (event: ServerEvent) => void,\n): (event: ServerEvent) => void {\n let handler = base;\n for (let i = middlewares.length - 1; i >= 0; i--) {\n handler = middlewares[i]!(handler);\n }\n return handler;\n}\n","/**\n * What the connected server is, and what that means for the caller.\n *\n * TS3 and TS6 differ in ways that stay invisible until something breaks. The\n * clearest: the server hashes a client's public key with SHA-1 on TS3 and\n * SHA-256 on TS6, so a client that assumes either one computes a\n * `client_unique_identifier` the other server never sends.\n *\n * Everything below comes from the handshake — `initserver` carries\n * `virtualserver_version`, the one place the server names itself, along with\n * its name, icon, banner and welcome message — so reading it costs no extra\n * round trip.\n */\n\nimport type { IconID } from \"@honeybbq/teamspeak-core\";\nimport { parseIconID } from \"@honeybbq/teamspeak-core/internal\";\nimport { uidAlgorithmForVersion, type UIDAlgorithm } from \"./crypto/identity.js\";\n\n/**\n * The server generation a version string belongs to. May gain members in a\n * minor release, as server generations appear: a `switch` over it needs a\n * default case.\n */\nexport type ServerFamily = \"ts3\" | \"ts6\" | \"unknown\";\n\n/** What a server said about itself in the handshake. */\nexport interface ServerCapabilities {\n /** The `virtualserver_version` string, exactly as the server sent it. */\n readonly version: string;\n /** Major version number, or 0 when it could not be parsed. */\n readonly major: number;\n /** Which server generation this is. */\n readonly family: ServerFamily;\n /**\n * The hash the server uses for `client_unique_identifier`.\n *\n * Read from the family rather than offered as a setting: the server decides\n * this, and a client that picks differently never matches.\n */\n readonly uidAlgorithm: UIDAlgorithm;\n /** The virtual server's name (`virtualserver_name`). */\n readonly name: string;\n /**\n * The server's icon (`virtualserver_icon_id`), or `undefined` for none. The\n * server sends the icon's CRC32, sometimes as a negative 32-bit number; this\n * is the unsigned value, which names the icon file.\n */\n readonly iconID: IconID | undefined;\n /** The host banner image's URL (`virtualserver_hostbanner_gfx_url`), if one is set. */\n readonly hostBannerImageURL: string | undefined;\n /** The welcome message shown on connecting (`virtualserver_welcomemessage`). */\n readonly welcomeMessage: string;\n}\n\n/**\n * Read what a server says about itself in `initserver`, or a version string\n * alone, such as \"6.0.0-beta13.1 [Build: 1]\".\n */\nexport function parseServerCapabilities(\n initserver: string | Readonly<Record<string, string>>,\n): ServerCapabilities {\n const params =\n typeof initserver === \"string\" ? { virtualserver_version: initserver } : initserver;\n const version = params[\"virtualserver_version\"] ?? \"\";\n const parsed = Number.parseInt(version, 10);\n const major = Number.isNaN(parsed) ? 0 : parsed;\n\n let family: ServerFamily = \"unknown\";\n if (major === 3) family = \"ts3\";\n else if (major >= 6) family = \"ts6\";\n\n return {\n version,\n major,\n family,\n uidAlgorithm: uidAlgorithmForVersion(version),\n name: params[\"virtualserver_name\"] ?? \"\",\n iconID: parseIconID(params[\"virtualserver_icon_id\"]),\n hostBannerImageURL: params[\"virtualserver_hostbanner_gfx_url\"]?.trim() || undefined,\n welcomeMessage: params[\"virtualserver_welcomemessage\"] ?? \"\",\n };\n}\n\n/**\n * Capabilities of a server that has not been connected to yet.\n *\n * The family is `unknown` — nothing has said which server this is — and\n * `uidAlgorithm` is SHA-1, the TS3 hash.\n */\nexport function unknownServerCapabilities(): ServerCapabilities {\n return parseServerCapabilities(\"\");\n}\n","import { hash512 } from \"../crypto/identity.js\";\nimport { clampScalar, scalarMultFull, bytesToBigIntLE } from \"../crypto/primitives.js\";\nimport { ed25519 } from \"@noble/curves/ed25519.js\";\n\n// The root key is a 33-byte Ed25519 point\nconst LICENSE_ROOT_KEY = new Uint8Array([\n 0xcd, 0x0d, 0xe2, 0xae, 0xd4, 0x63, 0x45, 0x50, 0x9a, 0x7e, 0x3c, 0xfd, 0x8f, 0x68, 0xb3, 0xdc,\n 0x75, 0x55, 0xb2, 0x9d, 0xcc, 0xec, 0x73, 0xcd, 0x18, 0x75, 0x0f, 0x99, 0x38, 0x12, 0x40, 0x8a,\n]);\n\nconst enum LicenseBlockType {\n Intermediate = 0,\n Server = 2,\n Ts5Server = 8,\n Ephemeral = 32,\n}\n\ninterface LicenseBlock {\n readonly key: Uint8Array; // 32-byte Ed25519 point\n readonly hash: Uint8Array; // SHA-512 truncated to 32 bytes\n properties: Uint8Array[];\n issuer: string;\n notValidBefore: Date;\n notValidAfter: Date;\n blockType: LicenseBlockType;\n serverType: number;\n}\n\nexport class LicenseChain {\n readonly blocks: LicenseBlock[];\n\n constructor(blocks: LicenseBlock[]) {\n this.blocks = blocks;\n }\n\n /**\n * Derive the session key by chaining Ed25519 point arithmetic starting from\n * the root key through each license block.\n */\n deriveKey(): Uint8Array<ArrayBuffer> {\n let round: Uint8Array<ArrayBuffer> = Uint8Array.from(LICENSE_ROOT_KEY);\n for (const block of this.blocks) {\n round = deriveKeyFromBlock(block, round);\n }\n return round;\n }\n}\n\n/**\n * The most blocks a license chain may have. Real chains have two or three —\n * root-issued intermediate, server, ephemeral — and every block costs a\n * point multiplication to derive, so a server's chain of thousands would hold\n * the event loop for seconds.\n */\nexport const MAX_LICENSE_BLOCKS = 8;\n\nexport function parseLicenses(data: Uint8Array): LicenseChain {\n if (data.length < 1) throw new Error(\"license too short\");\n if (data[0] !== 1) throw new Error(\"unsupported license version\");\n\n let remaining = data.slice(1);\n const blocks: LicenseBlock[] = [];\n\n while (remaining.length > 0) {\n if (blocks.length === MAX_LICENSE_BLOCKS) {\n throw new Error(`license chain longer than ${MAX_LICENSE_BLOCKS} blocks`);\n }\n const { block, consumed } = parseLicenseBlock(remaining);\n blocks.push(block);\n remaining = remaining.slice(consumed);\n }\n\n return new LicenseChain(blocks);\n}\n\nfunction parseLicenseBlock(data: Uint8Array): { block: LicenseBlock; consumed: number } {\n const MIN_BLOCK_LEN = 42;\n if (data.length < MIN_BLOCK_LEN) throw new Error(\"license too short\");\n if (data[0] !== 0) throw new Error(`wrong key kind in license: ${data[0]}`);\n\n const blockType = data[33] as LicenseBlockType;\n\n // Timestamps are seconds since Unix epoch offset by 0x50e22700\n const UNIX_OFFSET = 0x50e22700;\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const notValidBefore = new Date((view.getUint32(34, false) + UNIX_OFFSET) * 1000);\n const notValidAfter = new Date((view.getUint32(38, false) + UNIX_OFFSET) * 1000);\n\n if (notValidAfter < notValidBefore) {\n throw new Error(\"license times are invalid\");\n }\n\n const key = Uint8Array.from(data.slice(1, 33));\n\n const { payload, payloadRead } = parseBlockPayload(blockType, data, MIN_BLOCK_LEN);\n\n const allLen = MIN_BLOCK_LEN + payloadRead;\n if (allLen > data.length) throw new Error(\"license block longer than the license\");\n const hashInput = data.slice(1, allLen);\n const hashFull = hash512(Uint8Array.from(hashInput));\n const hash = Uint8Array.from(hashFull.slice(0, 32));\n\n return {\n block: {\n key,\n hash,\n properties: payload.properties,\n issuer: payload.issuer,\n notValidBefore,\n notValidAfter,\n blockType,\n serverType: payload.serverType,\n },\n consumed: allLen,\n };\n}\n\ninterface BlockPayload {\n issuer: string;\n serverType: number;\n properties: Uint8Array[];\n read: number;\n}\n\nfunction parseBlockPayload(\n blockType: LicenseBlockType,\n data: Uint8Array,\n minBlockLen: number,\n): { payload: BlockPayload; payloadRead: number } {\n switch (blockType) {\n case LicenseBlockType.Intermediate: {\n const { str, read } = readNullString(data.slice(46));\n return {\n payload: { issuer: str, serverType: 0, properties: [], read: 5 + read },\n payloadRead: 5 + read,\n };\n }\n case LicenseBlockType.Server: {\n const { str, read } = readNullString(data.slice(47));\n return {\n payload: { issuer: str, serverType: data[42] ?? 0, properties: [], read: 6 + read },\n payloadRead: 6 + read,\n };\n }\n case LicenseBlockType.Ts5Server: {\n const propCount = data[43] !== undefined ? data[43] : 0;\n let pos = 44;\n const properties: Uint8Array[] = [];\n for (let i = 0; i < propCount; i++) {\n if (pos >= data.length) throw new Error(\"license too short\");\n const propLen = data[pos++]!;\n if (pos + propLen > data.length) throw new Error(\"license too short\");\n properties.push(Uint8Array.from(data.slice(pos, pos + propLen)));\n pos += propLen;\n }\n return {\n payload: { issuer: \"\", serverType: data[42] ?? 0, properties, read: pos - minBlockLen },\n payloadRead: pos - minBlockLen,\n };\n }\n case LicenseBlockType.Ephemeral:\n return { payload: { issuer: \"\", serverType: 0, properties: [], read: 0 }, payloadRead: 0 };\n default:\n throw new Error(`invalid license block type: ${blockType}`);\n }\n}\n\n/**\n * Scan for a null-terminated string and return its content and the index\n * of the null byte (NOT including it in the count, matching Go behaviour).\n * The parent formulas (`5 + read`, `6 + read`) already add 1 for the null.\n */\nfunction readNullString(data: Uint8Array): { str: string; read: number } {\n for (let i = 0; i < data.length; i++) {\n if (data[i] === 0) {\n return { str: new TextDecoder().decode(data.slice(0, i)), read: i };\n }\n }\n throw new Error(\"non-null-terminated issuer string\");\n}\n\n/**\n * Derive the next key given a parent key and a license block.\n * Mirrors Go's licenseBlock.deriveKey.\n */\nfunction deriveKeyFromBlock(block: LicenseBlock, parent: Uint8Array): Uint8Array<ArrayBuffer> {\n const scalarBytes = Uint8Array.from(block.hash);\n clampScalar(scalarBytes);\n\n // Use raw scalar WITHOUT reducing mod n — NaCl's ge_scalarmult_vartime\n // uses the raw 256-bit scalar. Reducing mod n changes the result when\n // the point has a small-order component (Ed25519 cofactor = 8).\n const scalar = bytesToBigIntLE(scalarBytes);\n\n const pub = ed25519.Point.fromBytes(block.key);\n const negPub = pub.negate();\n\n const par = ed25519.Point.fromBytes(parent);\n const negPar = par.negate();\n\n const res = scalarMultFull(negPub, scalar).add(negPar);\n const raw = res.toBytes();\n const final = new Uint8Array(raw.length) as Uint8Array<ArrayBuffer>;\n final.set(raw);\n final[31] = (final[31] !== undefined ? final[31] : 0) ^ 0x80;\n\n return final;\n}\n","import type { KeyObject } from \"node:crypto\";\nimport type { Crypt } from \"../crypto/crypt.js\";\nimport { importPublicKey } from \"../crypto/identity.js\";\nimport { verifySign, getSharedSecret2 } from \"../crypto/primitives.js\";\nimport { parseLicenses } from \"./license.js\";\nimport { CryptoInitError } from \"../errors.js\";\n\n/**\n * CryptoInit2 performs the second stage of crypto initialization (Ed25519 ECDH).\n * Mirrors Go's handshake.CryptoInit2.\n */\nexport function cryptoInit2(\n crypt: Crypt,\n license: string,\n omega: string,\n proof: string,\n beta: string,\n privateKey: Uint8Array,\n): void {\n if (crypt.alpha.length === 0) {\n throw new CryptoInitError(\"initivexpand2 arrived before clientinitiv was sent\");\n }\n\n const licenseBytes = Buffer.from(license, \"base64\");\n const omegaBytes = Buffer.from(omega, \"base64\");\n const proofBytes = Buffer.from(proof, \"base64\");\n const betaBytes = Buffer.from(beta, \"base64\");\n\n let serverPubKey: KeyObject;\n try {\n serverPubKey = importPublicKey(omegaBytes);\n } catch (error) {\n throw new CryptoInitError(\"the server's public key is invalid\", { cause: error });\n }\n if (!verifySign(serverPubKey, licenseBytes, proofBytes)) {\n throw new CryptoInitError(\"the server's license proof is not valid\");\n }\n\n let sharedSecret: Uint8Array;\n try {\n const key = parseLicenses(licenseBytes).deriveKey();\n sharedSecret = getSharedSecret2(key, privateKey);\n } catch (error) {\n throw new CryptoInitError(\"the server's license is invalid\", { cause: error });\n }\n\n crypt.setSharedSecret(crypt.alpha, betaBytes, sharedSecret);\n}\n","import { createHash } from \"node:crypto\";\nimport { buildCommandOrdered, buildCommand } from \"@honeybbq/teamspeak-core/internal\";\nimport { sign, generateTemporaryKey } from \"./crypto/primitives.js\";\nimport { identityPrivateKey } from \"./crypto/identity.js\";\nimport { parseServerCapabilities } from \"./capabilities.js\";\nimport { cryptoInit2 } from \"./handshake/crypt-init2.js\";\nimport { PacketType } from \"./transport/packet.js\";\nimport type { ClientInternals } from \"./client.js\";\n\n/** Handle the `clientinitiv` message (P-256 based crypto path). */\nexport function handleHandshakeInitIV(\n client: ClientInternals,\n params: Record<string, string>,\n): void {\n const alpha = params[\"alpha\"] ?? \"\";\n const beta = params[\"beta\"] ?? \"\";\n const omega = params[\"omega\"] ?? \"\";\n\n client.handler.receivedFinalInitAck();\n client.crypt.initCrypto(alpha, beta, omega);\n client.logger.info(\"crypto initialized (P-256 path), sending clientinit\");\n sendClientInit(client);\n}\n\n/** Handle the `initivexpand2` message (Ed25519 / TS3 crypto path). */\nexport function handleHandshakeExpand2(\n client: ClientInternals,\n params: Record<string, string>,\n): void {\n client.logger.info(\"received initivexpand2\");\n client.handler.receivedFinalInitAck();\n\n const license = params[\"l\"] ?? \"\";\n const omega = params[\"omega\"] ?? \"\";\n const proof = params[\"proof\"] ?? \"\";\n const beta = params[\"beta\"] ?? \"\";\n\n const privateKey = sendClientEkPacket(client, beta);\n cryptoInit2(client.crypt, license, omega, proof, beta, privateKey);\n sendClientInit(client);\n}\n\n/** Handle `initserver` — marks the client as connected. */\nexport function handleInitServer(client: ClientInternals, params: Record<string, string>): void {\n const idStr = params[\"aclid\"] ?? params[\"clid\"] ?? \"\";\n const clid = idStr ? parseInt(idStr, 10) : 0;\n\n if (clid > 0) {\n client.clid = clid;\n client.handler.setClientID(clid);\n }\n\n // initserver is the only place the server names itself, and it determines how\n // the server hashes our public key into client_unique_identifier: SHA-1 on\n // TS3, SHA-256 on TS6. Recording the whole capability set here keeps callers\n // from re-deriving it, or assuming one server generation.\n client.capabilities = parseServerCapabilities(params);\n\n client.logger.info(\"connected to server\", { selfId: client.clid });\n client.markConnected();\n\n // Inform the server about mute state\n setImmediate(() => {\n const updateCmd = buildCommand(\"clientupdate\", {\n client_input_muted: \"0\",\n client_output_muted: \"0\",\n });\n client.execNoWait(updateCmd).catch(() => {});\n });\n}\n\nfunction sendClientEkPacket(client: ClientInternals, beta: string): Uint8Array {\n const [publicKey, privateKey] = generateTemporaryKey();\n const ekBase64 = Buffer.from(publicKey).toString(\"base64\");\n const clientProof = buildClientEkProof(client, publicKey, beta);\n\n const clientEk = buildCommandOrdered(\"clientek\", [\n [\"ek\", ekBase64],\n [\"proof\", clientProof],\n ]);\n client.handler.sendPacket(PacketType.Command, Buffer.from(clientEk), 0);\n return privateKey;\n}\n\nfunction buildClientEkProof(client: ClientInternals, publicKey: Uint8Array, beta: string): string {\n const betaBytes = Buffer.from(beta, \"base64\");\n const toSign = new Uint8Array(86);\n toSign.set(publicKey.slice(0, 32));\n toSign.set(betaBytes.slice(0, Math.min(54, betaBytes.length)), 32);\n const sig = sign(identityPrivateKey(client.crypt.identity), toSign);\n return Buffer.from(sig).toString(\"base64\");\n}\n\n/**\n * Encode a password field for the command protocol.\n *\n * TeamSpeak expects password fields as base64(sha1(password)) — server and\n * channel passwords during the handshake, the `clientmove` channel password,\n * and the `cpw` field of the file transfer commands. Sending the plain text\n * instead makes the server reject correct passwords with error 781.\n */\nexport function prepareClientPassword(password: string): string {\n if (password === \"\") return \"\";\n return createHash(\"sha1\").update(password).digest().toString(\"base64\");\n}\n\nexport function sendClientInit(client: ClientInternals): void {\n const cmd = buildClientInitCommand(client);\n client.handler.sendPacket(PacketType.Command, Buffer.from(cmd), 0);\n}\n\nfunction buildClientInitCommand(client: ClientInternals): string {\n const pubKeyBase64 = client.crypt.identity.publicKey();\n const initOptions = client.initOptions;\n // HWID should match TS3 client UID format: base64(SHA1(publicKey()))\n const hwid = createHash(\"sha1\").update(pubKeyBase64).digest().toString(\"base64\");\n\n return buildCommandOrdered(\"clientinit\", [\n [\"client_nickname\", client.nickname],\n [\"client_version\", \"3.?.? [Build: 5680278000]\"],\n [\"client_platform\", \"Windows\"],\n [\"client_input_hardware\", \"1\"],\n [\"client_output_hardware\", \"1\"],\n [\"client_default_channel\", initOptions.defaultChannel],\n [\"client_default_channel_password\", initOptions.defaultChannelPasswordHash],\n [\"client_server_password\", initOptions.serverPasswordHash],\n [\"client_meta_data\", \"\"],\n [\n \"client_version_sign\",\n \"DX5NIYLvfJEUjuIbCidnoeozxIDRRkpq3I9vVMBmE9L2qnekOoBzSenkzsg2lC9CMv8K5hkEzhr2TYUYSwUXCg==\",\n ],\n [\"client_key_offset\", String(client.crypt.identity.offset)],\n [\"client_nickname_phonetic\", \"\"],\n [\"client_default_token\", \"\"],\n [\"hwid\", hwid],\n ]);\n}\n","import type { Command } from \"@honeybbq/teamspeak-core/internal\";\nimport type {\n ClientEnterEvent,\n ClientLeaveEvent,\n ClientMovedEvent,\n TextMessageEvent,\n PokeEvent,\n} from \"@honeybbq/teamspeak-core\";\nimport {\n parseClient,\n parseUint64,\n parseUint16,\n parseInt10,\n} from \"@honeybbq/teamspeak-core/internal\";\nimport { asChannelID, asClientID, asUID } from \"@honeybbq/teamspeak-core\";\n\nexport type NotificationResult =\n | { kind: \"clientEnter\"; info: ClientEnterEvent }\n | { kind: \"clientLeave\"; event: ClientLeaveEvent; isSelf: boolean }\n | { kind: \"clientMoved\"; event: ClientMovedEvent; reasonMessage: string }\n | { kind: \"textMessage\"; message: TextMessageEvent }\n | { kind: \"poked\"; event: PokeEvent }\n | { kind: \"unknown\" };\n\nexport function handleNotification(\n cmd: Command,\n selfCLID: number,\n clients: Map<number, ClientEnterEvent>,\n _nickname: string,\n): NotificationResult {\n switch (cmd.name) {\n case \"notifycliententerview\":\n return handleClientEnterView(cmd, clients);\n case \"notifyclientleftview\":\n return handleClientLeftView(cmd, selfCLID, clients);\n case \"notifyclientmoved\":\n return handleClientMoved(cmd, clients);\n case \"notifytextmessage\":\n return handleTextMessage(cmd, clients);\n case \"notifyclientpoke\":\n return handleClientPoked(cmd);\n default:\n return { kind: \"unknown\" };\n }\n}\n\nfunction handleClientEnterView(\n cmd: Command,\n clients: Map<number, ClientEnterEvent>,\n): NotificationResult {\n const info = parseClient(cmd.params);\n // No client has id 0: a row without one describes nobody.\n if (info.id === 0) return { kind: \"unknown\" };\n clients.set(info.id, info);\n return { kind: \"clientEnter\", info };\n}\n\nfunction handleClientLeftView(\n cmd: Command,\n selfCLID: number,\n clients: Map<number, ClientEnterEvent>,\n): NotificationResult {\n const clid = asClientID(parseUint16(cmd.params[\"clid\"] ?? \"\"));\n if (clid === 0) return { kind: \"unknown\" };\n const isSelf = clid === selfCLID;\n clients.delete(clid);\n return {\n kind: \"clientLeave\",\n event: {\n clientID: clid,\n reason: parseInt10(cmd.params[\"reasonid\"] ?? \"\"),\n reasonMessage: cmd.params[\"reasonmsg\"] ?? \"\",\n invokerID: asClientID(parseUint16(cmd.params[\"invokerid\"] ?? \"\")),\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: asUID(cmd.params[\"invokeruid\"] ?? \"\"),\n },\n isSelf,\n };\n}\n\nfunction handleClientMoved(\n cmd: Command,\n clients: Map<number, ClientEnterEvent>,\n): NotificationResult {\n const clid = asClientID(parseUint16(cmd.params[\"clid\"] ?? \"\"));\n const ctid = asChannelID(parseUint64(cmd.params[\"ctid\"] ?? \"\"));\n if (clid === 0) return { kind: \"unknown\" };\n\n const existing = clients.get(clid);\n if (existing) clients.set(clid, { ...existing, channelID: ctid });\n\n return {\n kind: \"clientMoved\",\n event: {\n clientID: clid,\n targetChannelID: ctid,\n reason: parseInt10(cmd.params[\"reasonid\"] ?? \"\"),\n invokerID: asClientID(parseUint16(cmd.params[\"invokerid\"] ?? \"\")),\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: asUID(cmd.params[\"invokeruid\"] ?? \"\"),\n },\n reasonMessage: cmd.params[\"reasonmsg\"] ?? \"\",\n };\n}\n\nfunction handleTextMessage(\n cmd: Command,\n clients: Map<number, ClientEnterEvent>,\n): NotificationResult {\n const invokerID = asClientID(parseUint16(cmd.params[\"invokerid\"] ?? \"\"));\n const invokerInfo = clients.get(invokerID);\n\n const message: TextMessageEvent = {\n targetMode: parseInt10(cmd.params[\"targetmode\"] ?? \"\"),\n targetID: asClientID(parseUint16(cmd.params[\"target\"] ?? \"\")),\n invokerID,\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: asUID(cmd.params[\"invokeruid\"] ?? invokerInfo?.uid ?? \"\"),\n message: cmd.params[\"msg\"] ?? \"\",\n invokerGroups: invokerInfo?.serverGroups ?? [],\n };\n\n return { kind: \"textMessage\", message };\n}\n\nfunction handleClientPoked(cmd: Command): NotificationResult {\n return {\n kind: \"poked\",\n event: {\n invokerID: asClientID(parseUint16(cmd.params[\"invokerid\"] ?? \"\")),\n invokerName: cmd.params[\"invokername\"] ?? \"\",\n invokerUID: asUID(cmd.params[\"invokeruid\"] ?? \"\"),\n message: cmd.params[\"msg\"] ?? \"\",\n },\n };\n}\n","interface Waiter {\n readonly resolve: () => void;\n readonly signal: AbortSignal | undefined;\n readonly onAbort: () => void;\n}\n\n/**\n * Token-bucket limiter for outbound TS3 commands.\n * Mirrors Go's commandThrottle.\n *\n * Waiters are released in the order they arrived: each used to poll for a\n * token on its own timer, so a command that came later could take the turn of\n * one that had waited longer, and the commands went out of order.\n */\nexport class CommandThrottle {\n static readonly TOKEN_RATE = 4.0; // tokens per second\n static readonly TOKEN_MAX = 8.0; // bucket capacity\n\n #tokens = 5.0;\n #lastUpdate = Date.now();\n readonly #waiters: Waiter[] = [];\n #timer: ReturnType<typeof setTimeout> | undefined;\n\n /**\n * Wait for a token, behind every earlier waiter. Aborting `signal` rejects\n * with its reason and gives the place in line up; the abort listener is\n * removed however the wait ends.\n */\n wait(signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) return Promise.reject(signal.reason);\n this.#refill();\n if (this.#waiters.length === 0 && this.#tokens >= 1.0) {\n this.#tokens -= 1.0;\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n const waiter: Waiter = {\n resolve,\n signal,\n onAbort: () => {\n const index = this.#waiters.indexOf(waiter);\n if (index >= 0) this.#waiters.splice(index, 1);\n if (this.#waiters.length === 0) this.#stopTimer();\n reject(signal!.reason);\n },\n };\n signal?.addEventListener(\"abort\", waiter.onAbort, { once: true });\n this.#waiters.push(waiter);\n this.#schedule();\n });\n }\n\n #refill(): void {\n const now = Date.now();\n const elapsed = (now - this.#lastUpdate) / 1000;\n this.#tokens = Math.min(\n this.#tokens + elapsed * CommandThrottle.TOKEN_RATE,\n CommandThrottle.TOKEN_MAX,\n );\n this.#lastUpdate = now;\n }\n\n /** Arm the timer for when the next token is due, unless it already is. */\n #schedule(): void {\n if (this.#timer !== undefined || this.#waiters.length === 0) return;\n const waitMs =\n this.#tokens >= 1.0\n ? 0\n : Math.ceil(((1.0 - this.#tokens) / CommandThrottle.TOKEN_RATE) * 1000) + 10;\n this.#timer = setTimeout(() => {\n this.#timer = undefined;\n this.#release();\n }, waitMs);\n }\n\n #stopTimer(): void {\n clearTimeout(this.#timer);\n this.#timer = undefined;\n }\n\n /** Hand the tokens there are to the waiters at the head of the line. */\n #release(): void {\n this.#refill();\n while (this.#waiters.length > 0 && this.#tokens >= 1.0) {\n this.#tokens -= 1.0;\n const waiter = this.#waiters.shift()!;\n waiter.signal?.removeEventListener(\"abort\", waiter.onAbort);\n waiter.resolve();\n }\n this.#schedule();\n }\n}\n","/**\n * Reports whether `actual` equals `expected` or equals `expected` followed by\n * only digits — the pattern TeamSpeak uses when a nickname is already taken.\n */\nexport function isAutoNicknameMatch(expected: string, actual: string): boolean {\n if (actual === expected) return true;\n if (!actual.startsWith(expected)) return false;\n const suffix = actual.slice(expected.length);\n return /^\\d+$/.test(suffix);\n}\n","/**\n * Diagnostics channels: the SDK's tracing points, for an application or an\n * APM agent (OpenTelemetry instruments `diagnostics_channel` directly) to\n * subscribe to.\n *\n * A library does not decide where its traces go, so the SDK publishes them\n * here, and with no subscriber a channel costs a property read.\n *\n * Messages carry the command's name, never its parameters: those hold\n * password hashes, which the server accepts as passwords, and privilege keys.\n *\n * ```ts\n * import { tracingChannel } from \"node:diagnostics_channel\";\n *\n * tracingChannel(\"honeybbq:teamspeak:command\").subscribe({\n * start: ({ command }) => console.time(command),\n * asyncEnd: ({ command }) => console.timeEnd(command),\n * error: ({ command, error }) => console.error(command, error),\n * });\n * ```\n */\n\nimport {\n channel,\n tracingChannel,\n type Channel,\n type TracingChannel,\n} from \"node:diagnostics_channel\";\nimport type { Client } from \"./client.js\";\n\n/** What `honeybbq:teamspeak:command` reports about a command. */\nexport interface CommandTrace {\n /** The command's name, such as `clientlist`. */\n readonly command: string;\n /** The client sending it. Its fields are private, so it carries no secret. */\n readonly client: Client;\n}\n\n/** What `honeybbq:teamspeak:packet` reports about a command arriving from the server. */\nexport interface PacketTrace {\n /** The command's name, such as `notifytextmessage`, or `\"\"` for a data row. */\n readonly command: string;\n /** The client receiving it. */\n readonly client: Client;\n}\n\n/**\n * Traces every command with an answer: `start` when it is sent, `asyncEnd`\n * when its answer arrives, `error` when it fails.\n */\nexport const commandChannel: TracingChannel<CommandTrace> = tracingChannel<CommandTrace>(\n \"honeybbq:teamspeak:command\",\n);\n\n/** Publishes every command the server sends. */\nexport const packetChannel: Channel<PacketTrace> = channel<PacketTrace>(\n \"honeybbq:teamspeak:packet\",\n);\n","/**\n * Reconnection policy.\n *\n * A dropped connection is normal on a UDP voice session, so a bot that cannot\n * recover is not usable unattended. Reconnecting is opt-in rather than\n * automatic: a silent reconnect makes a dropped session look like a healthy\n * one, and a caller that wanted to know about the drop never finds out.\n *\n * Backoff is not a nicety here. TeamSpeak bans an IP that opens several\n * connections in quick succession — measured at roughly three, after which the\n * server answers `error id=3329` and refuses everything. A reconnect loop\n * without a delay therefore bans itself, and the ban outlasts the outage it was\n * recovering from.\n */\n\nimport { ErrorCode, Reason, ServerError } from \"@honeybbq/teamspeak-core\";\nimport { AlreadyConnectedError, InvalidAddressError, RemovedError } from \"./errors.js\";\n\n/** How long to wait before each attempt. */\nexport interface BackoffPolicy {\n /** Delay before the first retry, in milliseconds. */\n readonly initialDelayMs: number;\n /** Ceiling for the delay; it never grows past this. */\n readonly maxDelayMs: number;\n /** Multiplier applied after each failed attempt. */\n readonly factor: number;\n /**\n * Fraction of the delay to randomise, 0 to 1.\n *\n * A fleet of bots that drop together would otherwise retry in lockstep and\n * hit the server in a burst. Jitter spreads them out.\n */\n readonly jitter: number;\n /** Give up after this many consecutive failures. 0 means never give up. */\n readonly maxAttempts: number;\n}\n\n/** One second, doubling, capped at a minute, with 20% jitter, never giving up. */\nexport const defaultBackoffPolicy: Readonly<BackoffPolicy> = Object.freeze({\n initialDelayMs: 1_000,\n maxDelayMs: 60_000,\n factor: 2,\n jitter: 0.2,\n maxAttempts: 0,\n});\n\n/**\n * How a client reconnects after its connection drops. Supplying it, even as\n * `{}`, turns reconnecting on; a deliberate `disconnect()` never reconnects.\n */\nexport interface ReconnectOptions {\n /** Tuning for the retry delays; unset fields keep {@link defaultBackoffPolicy}'s. */\n readonly backoff?:\n | { readonly [K in keyof BackoffPolicy]?: BackoffPolicy[K] | undefined }\n | undefined;\n /**\n * Decide whether a given failure is worth retrying. Returning false stops the\n * loop. Defaults to {@link defaultShouldRetry}.\n */\n readonly shouldRetry?: ((error: Error | undefined, attempt: number) => boolean) | undefined;\n}\n\n/**\n * Compute the delay before an attempt.\n *\n * `attempt` is 1-based: the delay before the first retry is `initialDelayMs`,\n * give or take the jitter, and the delay never grows past `maxDelayMs`.\n */\nexport function backoffDelay(policy: Readonly<BackoffPolicy>, attempt: number): number {\n return jitteredDelay(policy, attempt, Math.random);\n}\n\n/** @internal The delay, with `random` supplying the jitter. */\nexport function jitteredDelay(\n policy: Readonly<BackoffPolicy>,\n attempt: number,\n random: () => number,\n): number {\n const exponent = Math.max(0, attempt - 1);\n const raw = policy.initialDelayMs * policy.factor ** exponent;\n const capped = Math.min(raw, policy.maxDelayMs);\n\n if (policy.jitter <= 0) return Math.round(capped);\n\n // Full jitter would ignore the computed delay; this keeps the trend while\n // spreading peers, so a whole fleet does not retry on the same millisecond.\n // Kept under the ceiling, which a caller reasonably reads as a promise.\n const spread = capped * Math.min(policy.jitter, 1);\n const delay = capped + (random() * 2 - 1) * spread;\n return Math.round(Math.max(0, Math.min(delay, policy.maxDelayMs)));\n}\n\n/**\n * Server errors where retrying cannot help.\n *\n * Deliberately a short list of codes known to be refusals, rather than \"any\n * ServerError\". The server also answers transiently: after a dropped\n * connection it still holds the old session, and a reconnect with the same\n * identity is refused with 521 \"too many clones already connected\" until it\n * reaps the zombie — a condition that clears itself and is worth retrying.\n *\n * The asymmetry is deliberate. Retrying a permanent failure costs a few bounded\n * attempts; not retrying a transient one means never recovering.\n */\nconst PERMANENT_SERVER_ERRORS: ReadonlySet<number> = new Set([\n ErrorCode.ConnectFailedBanned,\n ErrorCode.BanFlooding,\n ErrorCode.ServerInvalidPassword,\n ErrorCode.ChannelInvalidPassword,\n ErrorCode.PermissionsClientInsufficient,\n]);\n\n/**\n * Whether a failure is worth another attempt.\n *\n * Transport failures are retried; so is a server that stopped, and a server\n * error other than the known refusals — a ban, flooding, a wrong server or\n * channel password, missing permissions — since some, such as 521 \"too many\n * clones\" right after a drop, clear by themselves. A kick or a ban is not:\n * someone removed the client on purpose. Nor is an AlreadyConnectedError: the\n * client was connected by other means; nor an InvalidAddressError.\n */\nexport function defaultShouldRetry(error: Error | undefined): boolean {\n // The client is connected, or connecting, already: there is nothing to retry.\n if (error instanceof AlreadyConnectedError) return false;\n // An address that cannot be one stays that way.\n if (error instanceof InvalidAddressError) return false;\n if (error instanceof RemovedError) {\n return error.reason !== Reason.KickServer && error.reason !== Reason.KickServerBan;\n }\n return !(error instanceof ServerError && PERMANENT_SERVER_ERRORS.has(error.code));\n}\n\nexport function resolveBackoffPolicy(options: ReconnectOptions): BackoffPolicy {\n const policy: Record<string, number> = { ...defaultBackoffPolicy };\n // An explicit undefined keeps the default, as an unset field does.\n for (const [key, value] of Object.entries(options.backoff ?? {})) {\n if (value !== undefined) policy[key] = value;\n }\n return policy as unknown as BackoffPolicy;\n}\n","import {\n type EventMap,\n type ClientOptions,\n type EventMiddleware,\n type AddrResolver,\n type Listener,\n type ServerEvent,\n type ServerEventName,\n type Unsubscribe,\n ClientStatus,\n} from \"./types.js\";\nimport {\n type ChannelID,\n type ClientEnterEvent,\n type ClientID,\n type Codec,\n type KickedEvent,\n type CommandMiddleware,\n type CommandOptions,\n type UID,\n asChannelID,\n asClientID,\n type Logger,\n ErrorCode,\n Reason,\n TeamspeakError,\n noopLogger,\n} from \"@honeybbq/teamspeak-core\";\nimport { AlreadyConnectedError, CryptoInitError, RemovedError } from \"./errors.js\";\nimport { abortable, abortReason } from \"./abort.js\";\nimport { Identity, Crypt } from \"./crypto/index.js\";\nimport { RESOLVE_BUDGET_MS, Resolver } from \"./discovery/resolver.js\";\nimport { PacketHandler } from \"./transport/handler.js\";\nimport { PacketType } from \"./transport/packet.js\";\nimport type { Packet } from \"./transport/packet.js\";\nimport { CommandTracker, appendReturnCode } from \"./commands.js\";\nimport { encodeRequest, parseServerError } from \"@honeybbq/teamspeak-core/internal\";\nimport { uploadFileData, downloadFileData } from \"./transfer.js\";\nimport { buildCommandChain, buildEventChain } from \"./events.js\";\nimport { processInit1 } from \"./handshake/crypt-handshake.js\";\nimport {\n handleHandshakeInitIV,\n handleHandshakeExpand2,\n handleInitServer,\n prepareClientPassword,\n} from \"./handshake.js\";\nimport type { CommandExecutor, CommandRequest } from \"@honeybbq/teamspeak-core\";\nimport { handleNotification } from \"./notifications.js\";\nimport { parseCommand } from \"@honeybbq/teamspeak-core/internal\";\nimport { CommandThrottle } from \"./throttle.js\";\nimport { splitCommandRows, sleep } from \"@honeybbq/teamspeak-core/internal\";\nimport { isAutoNicknameMatch } from \"./helpers.js\";\nimport type { FileUploadInfo, FileDownloadInfo } from \"@honeybbq/teamspeak-core\";\nimport { CommandTimeoutError, NotConnectedError } from \"@honeybbq/teamspeak-core\";\nimport { responseSpec } from \"@honeybbq/teamspeak-core/internal\";\nimport type { Readable, Writable } from \"node:stream\";\nimport type { SocketFactory, FileTransferSocketFactory } from \"./types.js\";\nimport { unknownServerCapabilities, type ServerCapabilities } from \"./capabilities.js\";\nimport { joinHostPort, parseConnectAddress, splitHostPort } from \"./address.js\";\nimport { commandChannel, packetChannel, type CommandTrace } from \"./diagnostics.js\";\nimport {\n backoffDelay,\n defaultShouldRetry,\n resolveBackoffPolicy,\n type ReconnectOptions,\n} from \"./reconnect.js\";\n\nexport { ClientStatus };\n\n/**\n * What clientinit sends about the connection, with the passwords already in\n * their wire form, `base64(sha1(password))`: hashed once, when the client is\n * made, so the plain text is never held.\n */\nexport interface ClientInitOptions {\n readonly serverPasswordHash: string;\n readonly defaultChannel: string;\n readonly defaultChannelPasswordHash: string;\n}\n\nfunction normalizeClientInitOptions(options: ClientOptions): ClientInitOptions {\n return {\n serverPasswordHash: prepareClientPassword(options.serverPassword ?? \"\"),\n defaultChannel: options.defaultChannel ?? \"\",\n defaultChannelPasswordHash: prepareClientPassword(options.defaultChannelPassword ?? \"\"),\n };\n}\n\n/**\n * What the handshake, and the package's own tests, reach inside a Client.\n * Not exported from the package: a Client keeps all of it in private fields,\n * so none of it shows in `util.inspect()`, `JSON.stringify()` or a debugger's\n * property list.\n *\n * @internal\n */\nexport interface ClientInternals {\n readonly crypt: Crypt;\n readonly handler: PacketHandler;\n readonly logger: Logger;\n readonly initOptions: ClientInitOptions;\n nickname: string;\n clid: number;\n capabilities: ServerCapabilities;\n /** Mark the attempt in progress connected. */\n markConnected(): void;\n /**\n * Send a command line without waiting for an answer, on the handshake's\n * own path: it needs an open socket, not a connected session.\n */\n execNoWait(command: string): Promise<void>;\n /** Handle a packet as if the current handler had received it. */\n handlePacket(packet: Packet): void;\n}\n\nlet internalsOf: (client: Client) => ClientInternals;\n\nlet sentLineHook: ((client: Client, line: string) => void) | undefined;\n\n/**\n * Observe every command line the client sends, as encoded. A seam for the\n * package's own tests; not exported from the package.\n *\n * @internal\n */\nexport function onSentLine(hook: ((client: Client, line: string) => void) | undefined): void {\n sentLineHook = hook;\n}\n\n/** @internal The internals of `client`. */\nexport function clientInternals(client: Client): ClientInternals {\n return internalsOf(client);\n}\n\n/** How long a command waits for its answer unless told otherwise. */\nconst DEFAULT_COMMAND_TIMEOUT_MS = 10_000;\n\n/**\n * How long `disconnect()` waits for the server to acknowledge its goodbye\n * unless told otherwise: the acknowledgement is a courtesy, and a connection\n * that has already died would otherwise hold it for a full command timeout.\n */\nconst DISCONNECT_TIMEOUT_MS = 1_000;\n\n/** How long each reconnection attempt may take. */\nconst RECONNECT_ATTEMPT_TIMEOUT_MS = 30_000;\n\n/** One connection attempt, settled once by the handshake or its failure. */\ninterface ConnectAttempt {\n readonly promise: Promise<void>;\n /**\n * Aborted when the attempt fails, is abandoned, or is interrupted by\n * disconnect(), so the address lookup and the socket being opened for it\n * stop too instead of finishing a connection nobody wants.\n */\n readonly signal: AbortSignal;\n settled: boolean;\n resolve(): void;\n reject(error: unknown): void;\n /**\n * Settle the attempt as failed now, which stops its lookup and socket, but\n * reject its promise only once `until` settles: disconnect() holds it until\n * `disconnected` has been delivered, so a caller that awaits disconnect()\n * before the connect() it interrupted still hears that reject in time.\n */\n rejectAfter(error: unknown, until: Promise<unknown>): void;\n}\n\nfunction newConnectAttempt(): ConnectAttempt {\n let resolve!: () => void;\n let reject!: (error: unknown) => void;\n const promise = new Promise<void>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n // The failure is reported to whoever awaits connect(); an attempt nobody\n // awaits any more must not surface as an unhandled rejection.\n promise.catch(() => {});\n const controller = new AbortController();\n const attempt: ConnectAttempt = {\n promise,\n signal: controller.signal,\n settled: false,\n resolve() {\n if (attempt.settled) return;\n attempt.settled = true;\n resolve();\n },\n reject(error) {\n if (attempt.settled) return;\n attempt.settled = true;\n controller.abort(error);\n reject(error);\n },\n rejectAfter(error, until) {\n if (attempt.settled) return;\n attempt.settled = true;\n controller.abort(error);\n void until.finally(() => reject(error));\n },\n };\n return attempt;\n}\n\n/**\n * Voice deliveries are dropped while more than this many deliveries of any\n * kind are waiting: audio is fifty packets a second per speaker, and a\n * listener that cannot keep up would otherwise queue it without bound.\n */\nconst MAX_PENDING_DELIVERIES = 256;\n\n/** How often dropped voice is reported, at most. */\nconst VOICE_DROP_WARN_INTERVAL_MS = 10_000;\n\n/** The only commands handled before crypto init completes. */\nconst PRE_INIT_COMMANDS: ReadonlySet<string> = new Set([\"clientinitiv\", \"initivexpand2\", \"error\"]);\n\ninterface Subscription {\n readonly listener: (payload: unknown) => void;\n removed: boolean;\n}\n\n/**\n * A TeamSpeak client over the voice protocol.\n *\n * Listeners run one at a time, in the order their events arrived, after the\n * packet that carried them has been handled, so a listener may call the client\n * and await an answer.\n */\nexport class Client implements CommandExecutor, AsyncDisposable {\n static {\n internalsOf = (client) => client.#internals;\n }\n\n #crypt: Crypt;\n #handler: PacketHandler;\n #logger: Logger;\n #nickname: string;\n #clid = 0;\n /**\n * What the server reported about itself in initserver, including the UID\n * hash it uses: TS3 hashes the public key with SHA-1 and TS6 with SHA-256.\n */\n #capabilities: ServerCapabilities = unknownServerCapabilities();\n #internals: ClientInternals;\n\n #identity: Identity;\n #addr: string;\n #resolver: AddrResolver;\n #clientInitOptions: ClientInitOptions;\n #socketFactory: SocketFactory | undefined;\n #fileTransferSocketFactory: FileTransferSocketFactory | undefined;\n /** Undefined when the client does not reconnect. */\n #reconnectOptions: ReconnectOptions | undefined;\n /**\n * Set while a reconnect attempt is in flight, so overlapping failures do not\n * start competing loops.\n */\n #reconnecting = false;\n /**\n * Why the last established session dropped: a reconnect loop whose own\n * attempt connected and then dropped before the loop resumed retries for it.\n */\n #lastDrop: Error | undefined;\n /** Set by an explicit disconnect(), which must never be undone by a retry. */\n #stopped = false;\n /**\n * The goodbye of a disconnect() still in progress, which a connect() waits\n * for: tearing the old session down after a new one has started would end\n * the new one instead.\n */\n #leaving: Promise<void> | undefined;\n /** How many times disconnect() was called, so a waiting connect() sees one. */\n #disconnects = 0;\n /**\n * Settles once the last queued `disconnected` has been delivered. A\n * connect() waits for it, so the end of one session is never heard during\n * the next: not by a listener added for the new session, and not by an\n * events() iterator started for it.\n */\n #disconnectedDelivered: Promise<void> | undefined;\n /** Cuts short the reconnect loop's wait, on disconnect(). */\n #stopReconnecting: AbortController | undefined;\n #status: ClientStatus = ClientStatus.Disconnected;\n #throttle = new CommandThrottle();\n #cmdTrack = new CommandTracker(() => this.#clid);\n #clients = new Map<number, ClientEnterEvent>();\n #attempt: ConnectAttempt = newConnectAttempt();\n\n #listeners = new Map<keyof EventMap, Subscription[]>();\n /** Deliveries waiting for their turn; see #emit. */\n #queue: Array<() => void> = [];\n #draining = false;\n #voiceDropped = 0;\n #voiceDropWarnedAt = -Infinity;\n\n #eventMiddlewares: readonly EventMiddleware[];\n #send: CommandExecutor[\"send\"];\n #eventChain: (event: ServerEvent) => void;\n\n constructor(identity: Identity, addr: string, nickname: string, options: ClientOptions = {}) {\n this.#identity = identity;\n this.#addr = addr;\n this.#nickname = nickname;\n this.#logger = options.logger ?? noopLogger;\n this.#resolver =\n options.resolver ?? new Resolver({ resolveNicknames: options.resolveNicknames });\n this.#clientInitOptions = normalizeClientInitOptions(options);\n this.#socketFactory = options.socketFactory;\n this.#fileTransferSocketFactory = options.fileTransferSocketFactory;\n this.#reconnectOptions = options.reconnect;\n\n this.#crypt = new Crypt(identity);\n this.#handler = this.#newHandler();\n\n // oxlint-disable-next-line no-this-alias -- accessors cannot be arrow functions\n const self = this;\n this.#internals = {\n get crypt() {\n return self.#crypt;\n },\n get handler() {\n return self.#handler;\n },\n get logger() {\n return self.#logger;\n },\n get initOptions() {\n return self.#clientInitOptions;\n },\n get nickname() {\n return self.#nickname;\n },\n set nickname(value) {\n self.#nickname = value;\n },\n get clid() {\n return self.#clid;\n },\n set clid(value) {\n self.#clid = value;\n },\n get capabilities() {\n return self.#capabilities;\n },\n set capabilities(value) {\n self.#capabilities = value;\n },\n markConnected: () => this.#markConnected(),\n execNoWait: (command) => this.#execNoWait(command, undefined, true),\n handlePacket: (packet) => this.#handlePacket(packet),\n };\n\n // Built once: the chains are read on every command and event, and\n // changing them while those run would make the behaviour depend on timing.\n const cmdMiddlewares: readonly CommandMiddleware[] = options.commandMiddleware ?? [];\n this.#eventMiddlewares = options.eventMiddleware ?? [];\n this.#send = buildCommandChain(cmdMiddlewares, (request, commandOptions = {}) =>\n this.#exec(encodeRequest(request, prepareClientPassword), commandOptions, false),\n );\n this.#eventChain = buildEventChain([...this.#eventMiddlewares], (event) =>\n this.#deliver(event.name, event.payload),\n );\n }\n\n /** Where the client is in its connection's life. */\n get status(): ClientStatus {\n return this.#status;\n }\n\n // ---- Connection -----------------------------------------------------------\n\n /**\n * Connect to the server. Resolves once the handshake completes.\n *\n * An address that cannot be one — no host, a port outside 1–65535 — rejects\n * with an InvalidAddressError at once, before anything starts. A host name\n * that does not resolve fails the attempt with a TeamspeakError whose\n * `cause` is the lookup's error.\n *\n * A failed attempt rejects with its cause, such as the server's error for a\n * rejected password. Aborting `signal` abandons the attempt and rejects with\n * the signal's reason. The signal bounds only the connecting: once this\n * resolves, the connection lasts until `disconnect()` or a drop.\n * `connect()` does not retry; the `reconnect` option only retries a\n * connection that drops after it was established.\n *\n * Called while a `disconnect()` is still saying goodbye, or while an earlier\n * session's `disconnected` is still waiting to be delivered, this waits for\n * that first, so the old session is closed, and its `disconnected`\n * delivered, before the new one starts: no listener or `events()` iterator\n * of the new session hears the old one end. A `disconnect()` called during\n * that wait wins: this then rejects with a NotConnectedError.\n *\n * `connected` is delivered after this resolves, so a listener added right\n * after `await client.connect()` still hears it.\n */\n async connect(options: { readonly signal?: AbortSignal | undefined } = {}): Promise<void> {\n const { signal } = options;\n signal?.throwIfAborted();\n const disconnects = this.#disconnects;\n if (this.#leaving !== undefined) await abortable(this.#leaving, signal);\n while (this.#disconnectedDelivered !== undefined) {\n await abortable(this.#disconnectedDelivered, signal);\n }\n if (this.#disconnects !== disconnects) throw new NotConnectedError();\n if (this.#status !== ClientStatus.Disconnected) throw new AlreadyConnectedError();\n // Checked before anything changes: an address that can never work leaves\n // the client as it was, with no attempt to announce the end of.\n parseConnectAddress(this.#addr);\n this.#stopped = false;\n\n this.#resetForConnect();\n this.#status = ClientStatus.Connecting;\n const attempt = this.#attempt;\n\n // The handshake may complete just as the signal fires, in which case\n // #failConnection leaves the session alone and the caller gets the\n // connection it made rather than one it would believe had failed.\n const onAbort = (): void => this.#failConnection(abortReason(signal!));\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n try {\n try {\n const targetAddr = await this.#resolveAddr(attempt.signal);\n if (!attempt.settled) {\n this.#logger.info(\"connecting to server\", { address: targetAddr });\n await this.#handler.connect(targetAddr, attempt.signal);\n }\n } catch (error) {\n // Without this the client stays Connecting and every later connect()\n // fails with AlreadyConnectedError.\n this.#failConnection(error);\n }\n await attempt.promise;\n } finally {\n signal?.removeEventListener(\"abort\", onAbort);\n }\n }\n\n /**\n * Leave the server and close the connection.\n *\n * Says goodbye first, waiting for the server's acknowledgement for a second\n * at most, or less if `signal` aborts sooner. The connection is closed\n * either way. A `connect()` still waiting for its handshake rejects with a\n * NotConnectedError, and so do the commands still waiting for an answer.\n * Resolves once `disconnected` has been delivered to the listeners, so one\n * added after `await client.disconnect()` does not hear it. Does nothing on\n * a client that is not connected; called again while an earlier call is\n * still saying goodbye, it waits for that one.\n */\n async disconnect(options: { readonly signal?: AbortSignal | undefined } = {}): Promise<void> {\n // Recorded before anything else: a dropped socket during the goodbye below\n // must not be mistaken for an outage worth retrying.\n this.#stopped = true;\n this.#disconnects++;\n this.#stopReconnecting?.abort();\n\n if (this.#leaving !== undefined) return this.#leaving;\n // Already ended, by a drop or a failed attempt: its `disconnected` may\n // still be on its way.\n if (this.#status === ClientStatus.Disconnected) return this.#disconnectedDelivered;\n\n const wasConnected = this.#status === ClientStatus.Connected;\n this.#status = ClientStatus.Disconnected;\n let left!: () => void;\n this.#attempt.rejectAfter(new NotConnectedError(), new Promise<void>((r) => (left = r)));\n\n const leaving = this.#leave(wasConnected, options.signal).finally(left);\n this.#leaving = leaving;\n try {\n await leaving;\n } finally {\n this.#leaving = undefined;\n }\n }\n\n async #leave(wasConnected: boolean, signal: AbortSignal | undefined): Promise<void> {\n this.#logger.info(\"disconnecting from server\");\n\n if (wasConnected) {\n try {\n // On the internal path: the status already says Disconnected.\n await this.#exec(\n \"clientdisconnect reasonmsg=Shutdown\",\n { signal, timeout: DISCONNECT_TIMEOUT_MS },\n true,\n );\n } catch {\n // A courtesy; the connection closes regardless.\n }\n }\n\n this.#handler.close();\n this.#cmdTrack.reset(new NotConnectedError());\n // Announced here; #handleConnectionClosed stays quiet once the status is\n // already Disconnected, so listeners hear about it once.\n await this.#announceDisconnected(undefined);\n }\n\n /** `await using client = …` disconnects when the scope ends. */\n [Symbol.asyncDispose](): Promise<void> {\n return this.disconnect();\n }\n\n // ---- Commands ------------------------------------------------------------\n\n /**\n * Send a raw command line and return the rows that answer it: the escape\n * hatch for a command the typed functions do not cover. The line is sent as\n * given, so its values must already be escaped and any channel password\n * already hashed. `CommandName` lists the command names.\n *\n * Rejects with a NotConnectedError unless the client is connected: while it\n * is still connecting, the session's keys may not exist yet.\n */\n exec(command: string, options: CommandOptions = {}): Promise<Record<string, string>[]> {\n return this.#exec(command, options, false);\n }\n\n /**\n * Send a raw command line without waiting for an answer, for the few\n * commands the server answers with nothing at all. `CommandName` lists\n * the command names.\n *\n * Commands are paced by a flood throttle; aborting `signal` while this waits\n * for its turn rejects with the signal's reason and sends nothing. Rejects\n * with a NotConnectedError unless the client is connected.\n */\n execNoWait(\n command: string,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): Promise<void> {\n return this.#execNoWait(command, options.signal, false);\n }\n\n /**\n * Whether a command may go out now. The handshake's own commands (`internal`)\n * need only an open socket; everything else needs a connected session, so\n * nothing a caller sends can go out under the public dummy key, or after\n * disconnect() has begun saying goodbye.\n */\n #canSend(internal: boolean): boolean {\n return this.#handler.isOpen && (internal || this.#status === ClientStatus.Connected);\n }\n\n async #execNoWait(\n command: string,\n signal: AbortSignal | undefined,\n internal: boolean,\n ): Promise<void> {\n signal?.throwIfAborted();\n if (!this.#canSend(internal)) throw new NotConnectedError();\n await this.#throttle.wait(signal);\n if (!this.#canSend(internal)) throw new NotConnectedError();\n this.#sendLine(command);\n }\n\n /**\n * Send a typed command; this is the CommandExecutor the typed commands run on.\n *\n * The request passes through the `commandMiddleware` first. Channel\n * passwords are then hashed, because that is this protocol's rule: the voice\n * protocol expects `base64(sha1(password))`, where ServerQuery takes the\n * password itself.\n */\n send(request: CommandRequest, options: CommandOptions = {}): Promise<Record<string, string>[]> {\n return this.#send(request, options);\n }\n\n #sendLine(line: string): void {\n const hook = sentLineHook;\n if (hook) hook(this, line);\n this.#handler.sendPacket(PacketType.Command, Buffer.from(line), 0);\n }\n\n #exec(\n command: string,\n options: CommandOptions,\n internal: boolean,\n ): Promise<Record<string, string>[]> {\n if (!commandChannel.hasSubscribers) return this.#execUntraced(command, options, internal);\n const trace: CommandTrace = { command: parseCommand(command)?.name ?? \"\", client: this };\n return commandChannel.tracePromise(() => this.#execUntraced(command, options, internal), trace);\n }\n\n async #execUntraced(\n command: string,\n options: CommandOptions,\n internal: boolean,\n ): Promise<Record<string, string>[]> {\n const { signal, timeout = DEFAULT_COMMAND_TIMEOUT_MS } = options;\n signal?.throwIfAborted();\n // A command sent on no socket used to vanish and surface 10 seconds later\n // as a timeout, which reads like a slow server rather than a usage error.\n if (!this.#canSend(internal)) throw new NotConnectedError();\n\n // Which notifications answer this command, and — for answers that arrive\n // after the `error` — the request field they echo back.\n const parsed = parseCommand(command);\n const spec = responseSpec(parsed?.name ?? \"\");\n const key = spec?.correlated?.key;\n const correlation = key === undefined ? undefined : parsed?.params[key];\n\n const [rc, answered] = this.#cmdTrack.register(spec, correlation);\n let timer: ReturnType<typeof setTimeout> | undefined;\n let onAbort: (() => void) | undefined;\n // Started before the throttle: the timeout bounds the whole command, its\n // wait for a turn included, and so does the signal.\n const givenUp = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new CommandTimeoutError(parsed?.name ?? \"\")), timeout);\n onAbort = () => reject(abortReason(signal!));\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n givenUp.catch(() => {});\n const throttleAbort = new AbortController();\n try {\n const withRc = appendReturnCode(command, rc);\n await Promise.race([this.#throttle.wait(throttleAbort.signal), givenUp]);\n if (!this.#canSend(internal)) throw new NotConnectedError();\n this.#sendLine(withRc);\n\n const result = await Promise.race([answered, givenUp]);\n if (result.err) throw result.err;\n return result.data;\n } finally {\n // A command given up while it waited for its turn gives the turn back.\n throttleAbort.abort();\n // Cleared, not left to fire: a pending timer keeps the process alive for\n // the full timeout after the last command has long been answered.\n clearTimeout(timer);\n if (onAbort) signal?.removeEventListener(\"abort\", onAbort);\n this.#cmdTrack.unregister(rc);\n }\n }\n\n // ---- Events --------------------------------------------------------------\n\n /**\n * Listen for an event. Returns a function that removes the listener.\n *\n * A listener that throws does not stop the others: the rest of the event's\n * listeners, and the events after it, are still delivered, and the exception\n * is rethrown on its own, from a microtask, so it surfaces as an\n * `uncaughtException` just as an EventEmitter listener's would. An async\n * listener's rejection is not caught, and surfaces as an unhandled\n * rejection.\n */\n on<K extends keyof EventMap>(event: K, listener: Listener<K>): Unsubscribe {\n const subscription: Subscription = {\n listener: listener as (payload: unknown) => void,\n removed: false,\n };\n // A new array rather than an edit in place: a delivery may be iterating\n // over the old one.\n this.#listeners.set(event, [...(this.#listeners.get(event) ?? []), subscription]);\n\n const unsubscribe = (): void => {\n if (subscription.removed) return;\n subscription.removed = true;\n const list = this.#listeners.get(event) ?? [];\n this.#listeners.set(\n event,\n list.filter((s) => s !== subscription),\n );\n };\n return Object.assign(unsubscribe, { [Symbol.dispose]: unsubscribe });\n }\n\n /** Listen for the next occurrence of an event only. */\n once<K extends keyof EventMap>(event: K, listener: Listener<K>): Unsubscribe {\n const unsubscribe = this.on(event, ((payload: EventMap[K]) => {\n unsubscribe();\n (listener as (payload: EventMap[K]) => void)(payload);\n }) as Listener<K>);\n return unsubscribe;\n }\n\n /**\n * An event as an async iterator, for `for await`:\n *\n * ```ts\n * for await (const message of client.events(\"textMessage\", { signal })) { … }\n * ```\n *\n * Events that arrive while the loop body runs are buffered, so none is\n * missed — except voice, of which at most 256 frames are buffered; the rest\n * are dropped, as for a listener that falls behind. Iteration ends when\n * `signal` aborts, when the loop exits early (`break`, `return`, a throw),\n * and — for every event but `disconnected` — when the client disconnects.\n * An abort stops listening at once and discards whatever is buffered.\n */\n events<K extends keyof EventMap>(\n event: K,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): AsyncIterableIterator<EventMap[K]> {\n const { signal } = options;\n const buffered: Array<EventMap[K]> = [];\n let wake: (() => void) | undefined;\n let ended = false;\n\n const stopListening = this.on(event, ((payload: EventMap[K]) => {\n if (ended) return;\n if (event === \"voiceData\" && buffered.length >= MAX_PENDING_DELIVERIES) {\n this.#dropVoice();\n return;\n }\n buffered.push(payload);\n wake?.();\n }) as Listener<K>);\n // Ends after what is already buffered, which arrived before the disconnect.\n const stopOnDisconnect =\n event === \"disconnected\"\n ? undefined\n : this.on(\"disconnected\", () => {\n ended = true;\n stopListening();\n wake?.();\n });\n const cleanup = (): void => {\n ended = true;\n stopListening();\n stopOnDisconnect?.();\n signal?.removeEventListener(\"abort\", abort);\n wake?.();\n };\n const abort = (): void => {\n buffered.length = 0;\n cleanup();\n };\n if (signal?.aborted) abort();\n else signal?.addEventListener(\"abort\", abort, { once: true });\n\n const iterator: AsyncIterableIterator<EventMap[K]> = {\n async next(): Promise<IteratorResult<EventMap[K]>> {\n while (buffered.length === 0 && !ended) {\n await new Promise<void>((resolve) => (wake = resolve));\n wake = undefined;\n }\n if (buffered.length > 0) return { value: buffered.shift()!, done: false };\n cleanup();\n return { value: undefined, done: true };\n },\n async return(): Promise<IteratorResult<EventMap[K]>> {\n buffered.length = 0;\n cleanup();\n return { value: undefined, done: true };\n },\n [Symbol.asyncIterator]() {\n return iterator;\n },\n };\n return iterator;\n }\n\n // ---- API shorthand -------------------------------------------------------\n\n /** This client's id on the server, assigned in the handshake; 0 before it. */\n get clientID(): ClientID {\n return asClientID(this.#clid);\n }\n\n /**\n * What the connected server is: version, generation, and the uid hash it\n * uses. Read from `initserver`; before connecting the family is `unknown`\n * and the uid hash SHA-1.\n */\n get serverCapabilities(): ServerCapabilities {\n return this.#capabilities;\n }\n\n /**\n * Our own `client_unique_identifier`, hashed with the algorithm the connected\n * server uses.\n *\n * TS3 uses SHA-1 and TS6 SHA-256, so this reads the algorithm learned during\n * initserver rather than assuming one. Comparing a hard-coded SHA-1 UID to a\n * TS6 server silently never matches.\n */\n get uid(): UID {\n return this.#identity.uid(this.#capabilities.uidAlgorithm);\n }\n\n /** The channel this client is in, as it last learned; 0 before connecting. */\n get channelID(): ChannelID {\n return this.#clients.get(this.#clid)?.channelID ?? asChannelID(0n);\n }\n\n /**\n * Send Opus voice directly to specific clients, bypassing channel routing.\n * Throws a NotConnectedError unless the client is connected.\n */\n sendWhisper(data: Uint8Array, targetClientIDs: readonly ClientID[], codec: Codec): void {\n if (!this.#canSend(false)) throw new NotConnectedError();\n this.#handler.sendWhisperPacket(data, [...targetClientIDs], codec);\n }\n\n /**\n * Send one encoded audio frame to the channel this client is in. Throws a\n * NotConnectedError unless the client is connected.\n */\n sendVoice(data: Uint8Array, codec: Codec): void {\n if (!this.#canSend(false)) throw new NotConnectedError();\n this.#handler.sendVoicePacket(data, codec);\n }\n\n // ---- File Transfer -------------------------------------------------------\n\n /**\n * Upload `data` over a negotiated transfer, through the client's\n * `fileTransferSocketFactory` if it has one.\n */\n uploadFileData(\n host: string,\n info: FileUploadInfo,\n data: Readable,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): Promise<void> {\n return uploadFileData(host, info, data, {\n ...options,\n socketFactory: this.#fileTransferSocketFactory,\n });\n }\n\n /**\n * Download a negotiated transfer into `dest`, through the client's\n * `fileTransferSocketFactory` if it has one.\n */\n downloadFileData(\n host: string,\n info: FileDownloadInfo,\n dest: Writable,\n options: { readonly signal?: AbortSignal | undefined } = {},\n ): Promise<void> {\n return downloadFileData(host, info, dest, {\n ...options,\n socketFactory: this.#fileTransferSocketFactory,\n });\n }\n\n // ---- Internal (package-visible) ------------------------------------------\n\n #markConnected(): void {\n // Only the attempt in progress can complete: never one that disconnect()\n // or a failure has already ended.\n if (this.#status !== ClientStatus.Connecting || this.#attempt.settled) return;\n this.#status = ClientStatus.Connected;\n this.#attempt.resolve();\n this.#emit(\"connected\", undefined);\n }\n\n // ---- Private -------------------------------------------------------------\n\n #newHandler(): PacketHandler {\n const handler = new PacketHandler(this.#crypt, this.#logger, this.#socketFactory);\n // Each callback checks that its handler is still the current one: a\n // packet or close reported late by one a later connect() already replaced\n // must not reach, or tear down, the new connection.\n handler.onPacket = (p) => {\n if (handler === this.#handler) this.#handlePacket(p);\n };\n handler.onClosed = (err) => {\n if (handler === this.#handler) this.#handleConnectionClosed(err);\n };\n handler.onReceiveError = (error) => {\n if (handler === this.#handler) this.#handleReceiveError(error);\n };\n return handler;\n }\n\n #resetForConnect(): void {\n this.#handler.close();\n this.#crypt = new Crypt(this.#identity);\n this.#handler = this.#newHandler();\n this.#attempt = newConnectAttempt();\n this.#cmdTrack.reset(new NotConnectedError());\n this.#clients.clear();\n this.#clid = 0;\n this.#capabilities = unknownServerCapabilities();\n }\n\n async #resolveAddr(signal: AbortSignal): Promise<string> {\n // Parsed, not tested for a colon: an IPv6 literal has colons and no port.\n const { host, port } = splitHostPort(this.#addr);\n const fallback = joinHostPort(host, port);\n // Every resolver, a custom one too, gets the same budget: past it the\n // address is used as given. A timer the tests can control, not\n // AbortSignal.timeout().\n const budget = new AbortController();\n const timer = setTimeout(\n () => budget.abort(new TeamspeakError(\"address resolution took too long\")),\n RESOLVE_BUDGET_MS,\n );\n const lookup = AbortSignal.any([signal, budget.signal]);\n try {\n // Raced against the signal: a resolver that ignores it must still not\n // hold up an attempt that has been given up.\n const resolved = await abortable(\n this.#resolver.resolve(this.#addr, { signal: lookup }),\n lookup,\n );\n return resolved[0]?.addr ?? fallback;\n } catch (error) {\n signal.throwIfAborted();\n this.#logger.warn(\"address resolution failed, falling back to direct\", {\n error: String(budget.signal.aborted ? budget.signal.reason : error),\n });\n return fallback;\n } finally {\n clearTimeout(timer);\n }\n }\n\n /**\n * A datagram from the server could not be handled. During the handshake that\n * is the connection failing, reported as a CryptoInitError with the cause;\n * once connected, one bad packet is not worth the session, so it is dropped.\n */\n #handleReceiveError(error: unknown): void {\n if (this.#status !== ClientStatus.Connected) {\n this.#failConnection(\n error instanceof CryptoInitError\n ? error\n : new CryptoInitError(\"the handshake failed on a malformed packet\", { cause: error }),\n );\n return;\n }\n this.#logger.debug(\"dropped a malformed packet\", { error: String(error) });\n }\n\n #handlePacket(p: Packet): void {\n const pType = p.typeFlagged & 0x0f;\n if (pType === 8 /* Init1 */) {\n if (this.#crypt.cryptoInitComplete) return;\n const response = processInit1(this.#crypt, p.data);\n if (response) {\n this.#handler.sendPacket(PacketType.Init1, response, 0);\n }\n return;\n }\n\n if ((pType === 0 /* Voice */ || pType === 1) /* VoiceWhisper */ && p.data.length > 5) {\n this.#handleVoicePacket(p.data);\n return;\n }\n\n if ((pType === 2 /* Command */ || pType === 3) /* CommandLow */ && p.data.length > 0) {\n this.#handleCommandLines(Buffer.from(p.data).toString(\"utf8\"));\n }\n }\n\n /**\n * Parse an incoming S2C voice packet.\n * Format: [VId: u16] [CId: u16] [Codec: u8] [Data: var]\n */\n #handleVoicePacket(payload: Uint8Array): void {\n // Audio arrives fifty times a second per speaker; build no event nobody\n // will see.\n if (!this.#listeners.get(\"voiceData\")?.length && this.#eventMiddlewares.length === 0) return;\n if (this.#queue.length > MAX_PENDING_DELIVERIES) {\n this.#dropVoice();\n return;\n }\n\n const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);\n const clientId = view.getUint16(2, false);\n if (clientId === this.#clid) return;\n\n // Copied: the packet's buffer is reused once this returns, and a listener\n // runs later.\n const data = payload.slice(5);\n this.#emitServerEvent({\n name: \"voiceData\",\n payload: { clientID: asClientID(clientId), codec: payload[4]!, data },\n });\n }\n\n #handleCommandLines(s: string): void {\n if (!s) return;\n const lines = s.split(\"\\0\").join(\"\\n\").split(\"\\n\");\n for (const line of lines) {\n const trimmed = line.replace(/\\r$/, \"\");\n if (!trimmed) continue;\n for (const row of splitCommandRows(trimmed)) {\n this.#handleCommandStr(row);\n }\n }\n }\n\n #handleCommandStr(s: string): void {\n const cmd = parseCommand(s);\n if (!cmd) return;\n // Before crypto init a packet needs only the public dummy key, so anyone\n // on the path could have sent it: nothing but the handshake's own steps,\n // and an error that may end the attempt, is taken then. A notification\n // would be a forged event, a row a forged answer.\n if (!this.#crypt.cryptoInitComplete && !PRE_INIT_COMMANDS.has(cmd.name)) {\n this.#logger.debug(\"dropped a command that arrived before crypto init\", {\n command: cmd.name,\n });\n return;\n }\n if (packetChannel.hasSubscribers) packetChannel.publish({ command: cmd.name, client: this });\n\n // No name means a response row: the server sends data without echoing the\n // command, so the row belongs to whichever command is awaiting a result.\n if (cmd.name === \"\") {\n if (Object.keys(cmd.params).length > 0) this.#cmdTrack.buffer(cmd.params);\n return;\n }\n\n // `channellistfinished` ends the server's welcome sequence. It carries no\n // data of its own, so it is the only reliable marker: the guard used to\n // trip on our own notifycliententerview, which the server sends *in the\n // middle* of the sequence — the channellist rows after it were then\n // buffered as if they were the response to the caller's first command,\n // which is how a channellist could come back with duplicate and empty rows.\n if (cmd.name === \"channellistfinished\") {\n this.#cmdTrack.signalWelcomeComplete();\n return;\n }\n\n if (cmd.name.startsWith(\"notify\")) {\n // Some commands are answered by a notification instead of data rows;\n // it still goes on to be dispatched as an event, since the same\n // notification also arrives unprompted.\n if (this.#cmdTrack.expects(cmd.name)) {\n this.#cmdTrack.buffer(cmd.params, cmd.name);\n this.#cmdTrack.offerCorrelated(cmd.name, cmd.params);\n }\n const result = handleNotification(cmd, this.#clid, this.#clients, this.#nickname);\n this.#processNotificationResult(result);\n if (this.#listeners.get(\"notification\")?.length || this.#eventMiddlewares.length > 0) {\n this.#emitServerEvent({\n name: \"notification\",\n payload: { name: cmd.name, params: { ...cmd.params } },\n });\n }\n return;\n }\n\n switch (cmd.name) {\n // The handshake's steps happen once: repeated after crypto init, they\n // could only re-key or re-announce a session that is already set up.\n case \"clientinitiv\":\n if (!this.#crypt.cryptoInitComplete) handleHandshakeInitIV(this.#internals, cmd.params);\n break;\n case \"initivexpand2\":\n if (!this.#crypt.cryptoInitComplete) handleHandshakeExpand2(this.#internals, cmd.params);\n break;\n case \"initserver\":\n // Only on a session with its keys: before crypto init a packet needs\n // nothing but the public dummy key, and an initserver taken then would\n // report a connection whose next command — clientinit with its password\n // hashes among them — goes out under that dummy key.\n if (this.#status === ClientStatus.Connecting && this.#crypt.cryptoInitComplete) {\n handleInitServer(this.#internals, cmd.params);\n }\n break;\n case \"error\":\n this.#handleError(cmd.params);\n break;\n default:\n // A named command the SDK does not model. Held under its own name, so\n // it answers a command only if that command declared it — not merely by\n // arriving while one is in flight.\n this.#cmdTrack.buffer(cmd.params, cmd.name);\n break;\n }\n }\n\n #handleError(params: Record<string, string>): void {\n const { err, rc } = parseServerError(params);\n if (rc !== null) {\n this.#cmdTrack.resolve(rc, err);\n } else {\n // No return_code: server is acknowledging an unsolicited command\n // (welcome-sequence channellist, no-RC commands like clientupdate, etc.).\n // Discard any rows buffered since the last resolved command.\n this.#cmdTrack.discardBuffer();\n }\n\n // A server error before the welcome sequence finished is the connection\n // failure itself — a rejected password, or an invalid clientinit parameter.\n // Report it as the cause instead of leaving the caller with a bare timeout.\n if (err && this.#status !== ClientStatus.Connected) {\n this.#failConnection(err);\n return;\n }\n\n // Only a connected session gets here, so only after crypto init: an error\n // under the public dummy key can fail an attempt, never stop the client.\n if (err?.code === ErrorCode.ConnectFailedBanned) {\n this.#logger.warn(\"banned by the server, closing the connection\");\n setImmediate(() => this.disconnect().catch(() => {}));\n }\n }\n\n #processNotificationResult(result: import(\"./notifications.js\").NotificationResult): void {\n switch (result.kind) {\n case \"clientEnter\": {\n const info = result.info;\n // Identify self by the clid initserver already assigned rather than by\n // nickname: any other client whose nickname happens to be \"<our\n // nick><digits>\" — which is how the server renames a client whose\n // nickname was taken — would otherwise be mistaken for us, poisoning\n // every outgoing packet header with a foreign clientID until the server\n // drops the connection for command-resend timeout.\n //\n // This no longer marks the end of the welcome sequence: the server\n // sends more welcome data after it, and `channellistfinished` is the\n // real terminator.\n if (info.id === this.#clid) {\n // Carries the rename the server applied if our nickname was taken.\n this.#nickname = info.nickname;\n } else if (this.#clid === 0 && isAutoNicknameMatch(this.#nickname, info.nickname)) {\n // initserver carried no aclid, so the welcome enter is the only way\n // to learn our clid. Gated on clid still being unknown so a later\n // lookalike can never hijack an established session.\n this.#clid = info.id;\n this.#handler.setClientID(info.id);\n this.#nickname = info.nickname;\n }\n this.#emitServerEvent({ name: \"clientEnter\", payload: info });\n break;\n }\n case \"clientLeave\": {\n const event = result.event;\n this.#emitServerEvent({ name: \"clientLeave\", payload: event });\n if (!result.isSelf) break;\n if (event.reason === Reason.KickServer || event.reason === Reason.KickServerBan) {\n this.#emit(\"kicked\", kickedEvent(event));\n }\n this.#removedByServer(\n new RemovedError(event.reason, event.reasonMessage, event.invokerName),\n );\n break;\n }\n case \"clientMoved\":\n this.#emitServerEvent({ name: \"clientMoved\", payload: result.event });\n // A channel kick moves the client to the default channel; it arrives\n // as a move, not as leaving view, which is where it used to be looked\n // for.\n if (result.event.clientID === this.#clid && result.event.reason === Reason.KickChannel) {\n this.#emit(\n \"kicked\",\n kickedEvent({ ...result.event, reasonMessage: result.reasonMessage }),\n );\n }\n break;\n case \"textMessage\":\n this.#emitServerEvent({ name: \"textMessage\", payload: result.message });\n break;\n case \"poked\":\n this.#emitServerEvent({ name: \"poked\", payload: result.event });\n break;\n }\n }\n\n /**\n * End a session the server has ended. The server stops answering a client it\n * has removed, so waiting for the transport to notice reported the end a\n * minute late, without its cause, and with the client claiming to be\n * connected meanwhile.\n */\n #removedByServer(cause: Error): void {\n this.#handleConnectionClosed(cause);\n this.#handler.close();\n }\n\n /**\n * Count a dropped voice delivery, and report the drops now and then: at most\n * once every ten seconds, with how many were dropped since the last report.\n */\n #dropVoice(): void {\n this.#voiceDropped++;\n const now = Date.now();\n if (now - this.#voiceDropWarnedAt < VOICE_DROP_WARN_INTERVAL_MS) return;\n this.#voiceDropWarnedAt = now;\n // The count since the last warning, so each one says how bad it is now.\n this.#logger.warn(\"voice dropped: listeners are not keeping up\", {\n dropped: this.#voiceDropped,\n });\n this.#voiceDropped = 0;\n }\n\n /** Queue a server event, through the event middleware. */\n #emitServerEvent(event: ServerEvent): void {\n this.#enqueue(() => this.#eventChain(event));\n }\n\n /**\n * Queue `disconnected`; the promise settles once it has been delivered, and\n * a connect() waits for it until then.\n */\n #announceDisconnected(cause: Error | undefined): Promise<void> {\n const delivered = new Promise<void>((resolve) =>\n this.#enqueue(() => {\n try {\n this.#deliver(\"disconnected\", cause);\n } finally {\n resolve();\n }\n }),\n );\n this.#disconnectedDelivered = delivered;\n void delivered.then(() => {\n if (this.#disconnectedDelivered === delivered) this.#disconnectedDelivered = undefined;\n });\n return delivered;\n }\n\n /** Queue a lifecycle event, which middleware does not see. */\n #emit<K extends Exclude<keyof EventMap, ServerEventName>>(event: K, payload: EventMap[K]): void {\n this.#enqueue(() => this.#deliver(event, payload));\n }\n\n #deliver<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n for (const subscription of this.#listeners.get(event) ?? []) {\n // Checked at delivery: a listener removed while its event was queued\n // does not get it.\n if (subscription.removed) continue;\n try {\n subscription.listener(payload);\n } catch (error) {\n // Rethrown on its own, as an uncaught exception, so it surfaces as one\n // from an EventEmitter listener would, and the listeners after it\n // still get the event.\n queueMicrotask(() => {\n throw error;\n });\n }\n }\n }\n\n /**\n * Run deliveries one at a time, in order, once the packet being handled is\n * done with. A listener that throws does so as an uncaught exception, as it\n * would from an EventEmitter, and the listeners and deliveries behind it\n * still run.\n */\n #enqueue(delivery: () => void): void {\n this.#queue.push(delivery);\n if (this.#draining) return;\n this.#draining = true;\n setImmediate(this.#drain);\n }\n\n #drain = (): void => {\n try {\n while (this.#queue.length > 0) this.#queue.shift()!();\n } finally {\n if (this.#queue.length > 0) setImmediate(this.#drain);\n else this.#draining = false;\n }\n };\n\n #handleConnectionClosed(err: Error | null): void {\n if (this.#status === ClientStatus.Disconnected) return;\n // Nothing in flight can be answered any more; failing it now, with the\n // reason, beats every caller timing out one by one.\n this.#cmdTrack.reset(new NotConnectedError(err ? { cause: err } : undefined));\n if (this.#status !== ClientStatus.Connected) {\n // The socket closed before the handshake finished, so this is a failed\n // connection attempt rather than a disconnect of a live session.\n this.#failConnection(\n err ?? new TeamspeakError(\"connection closed before the TeamSpeak handshake completed\"),\n );\n return;\n }\n this.#status = ClientStatus.Disconnected;\n // Never undefined for a drop: undefined means disconnect() only.\n const cause = err ?? new TeamspeakError(\"connection closed\");\n this.#lastDrop = cause;\n\n // Announced first, then retried: a caller watching `disconnected` should\n // hear about the drop even when a reconnect is already on its way, because\n // a silent recovery hides an outage.\n void this.#announceDisconnected(cause);\n this.#scheduleReconnect(cause).catch((error: unknown) => {\n this.#logger.error(\"reconnecting failed\", { error: String(error) });\n });\n }\n\n /**\n * Retry a dropped connection according to the reconnect policy.\n *\n * Never runs after an explicit disconnect, and never more than one at a time:\n * two failures in quick succession would otherwise start competing loops, and\n * a loop shorter than the server's antiflood window bans the IP rather than\n * reconnecting it. A drop while the loop runs is the loop's to retry: it\n * ends only once its attempt is still connected when it resumes.\n */\n async #scheduleReconnect(err: Error): Promise<void> {\n const options = this.#reconnectOptions;\n if (options === undefined || this.#stopped || this.#reconnecting) return;\n\n const policy = resolveBackoffPolicy(options);\n const shouldRetry = options.shouldRetry ?? defaultShouldRetry;\n\n this.#reconnecting = true;\n\n const stop = new AbortController();\n this.#stopReconnecting = stop;\n try {\n for (let attempt = 1; policy.maxAttempts === 0 || attempt <= policy.maxAttempts; attempt++) {\n if (this.#stopped) return;\n let retry: boolean;\n try {\n retry = shouldRetry(err, attempt);\n } catch (error) {\n this.#logger.error(\"shouldRetry threw; not reconnecting\", { error: String(error) });\n return;\n }\n if (!retry) {\n this.#logger.info(\"not retrying\", { attempt, reason: err.message });\n return;\n }\n\n const delay = backoffDelay(policy, attempt);\n this.#logger.info(\"reconnecting\", { attempt, delayMs: delay });\n // A timer that keeps the process alive: an application that does\n // nothing but stay connected would otherwise exit during the wait.\n await sleep(delay, stop.signal);\n if (this.#stopped) return;\n // Connected, or connecting, by hand during the wait: nothing is left to\n // retry, and an attempt now would only fail with AlreadyConnectedError.\n if (this.#status !== ClientStatus.Disconnected) {\n this.#logger.info(\"reconnect loop ended: connected by other means\", { attempt });\n return;\n }\n\n try {\n await this.connect({ signal: AbortSignal.timeout(RECONNECT_ATTEMPT_TIMEOUT_MS) });\n // Read afresh: the status may have changed while connect() resolved.\n if (this.status === ClientStatus.Connected) {\n this.#logger.info(\"reconnected\", { attempt });\n return;\n }\n // The new session dropped before this loop resumed — initserver and\n // the server's goodbye in one datagram, say. That drop found this\n // loop running and left the retrying to it.\n err = this.#lastDrop ?? new TeamspeakError(\"connection closed\");\n } catch (retryErr) {\n if (retryErr instanceof AlreadyConnectedError) return;\n err = retryErr instanceof Error ? retryErr : new TeamspeakError(String(retryErr));\n }\n }\n this.#logger.warn(\"reconnect attempts exhausted\", { attempts: policy.maxAttempts });\n } finally {\n this.#reconnecting = false;\n if (this.#stopReconnecting === stop) this.#stopReconnecting = undefined;\n }\n }\n\n /**\n * A connection attempt has failed for good: settle it with the cause, and\n * tear the connection down. Does nothing once the handshake has completed,\n * so it cannot end a live session.\n *\n * Without this, a handshake the server rejects (a wrong password, say, which\n * the server answers with an error instead of closing the socket) surfaces\n * only as the caller's own timeout, and the client stays in `Connecting`\n * forever without ever emitting `disconnected`.\n */\n #failConnection(error: unknown): void {\n if (this.#status === ClientStatus.Connected) return;\n this.#attempt.reject(error);\n\n if (this.#status === ClientStatus.Disconnected) return;\n this.#status = ClientStatus.Disconnected;\n this.#handler.close();\n void this.#announceDisconnected(\n error instanceof Error ? error : new TeamspeakError(String(error)),\n );\n }\n}\n\nfunction kickedEvent(event: {\n readonly reason: number;\n readonly reasonMessage: string;\n readonly invokerName: string;\n readonly invokerUID: UID;\n readonly invokerID: ClientID;\n}): KickedEvent {\n return {\n reason: event.reason,\n reasonMessage: event.reasonMessage,\n invokerName: event.invokerName,\n invokerUID: event.invokerUID,\n invokerID: event.invokerID,\n };\n}\n","/**\n * Commands only the voice protocol has.\n *\n * ServerQuery has no subscriptions — a query client hears every channel's\n * events once it registers for them — and no `channelgetdescription`, since its\n * `channelinfo` already carries the description. These run on the voice\n * client alone, which is why they take one rather than any CommandExecutor.\n */\n\nimport type { Client } from \"../client.js\";\nimport type { ChannelID, CommandOptions } from \"@honeybbq/teamspeak-core\";\n\n/** The channel's description, which `listChannels` omits for bandwidth. */\nexport async function getChannelDescription(\n client: Client,\n cid: ChannelID,\n options?: CommandOptions,\n): Promise<string> {\n const rows = await client.send(\n { command: \"channelgetdescription\", params: [[\"cid\", cid]] },\n options,\n );\n return rows[0]?.[\"channel_description\"] ?? \"\";\n}\n\n/**\n * Subscribe to a channel: receive its clients' events and voice without\n * joining it.\n */\nexport async function subscribeChannel(\n client: Client,\n cid: ChannelID,\n options?: CommandOptions,\n): Promise<void> {\n await client.send({ command: \"channelsubscribe\", params: [[\"cid\", cid]] }, options);\n}\n\n/** Stop receiving a subscribed channel's events and voice. */\nexport async function unsubscribeChannel(\n client: Client,\n cid: ChannelID,\n options?: CommandOptions,\n): Promise<void> {\n await client.send({ command: \"channelunsubscribe\", params: [[\"cid\", cid]] }, options);\n}\n\n/** Subscribe to every channel on the server. */\nexport async function subscribeAllChannels(\n client: Client,\n options?: CommandOptions,\n): Promise<void> {\n await client.send({ command: \"channelsubscribeall\" }, options);\n}\n\n/** Unsubscribe from every channel on the server. */\nexport async function unsubscribeAllChannels(\n client: Client,\n options?: CommandOptions,\n): Promise<void> {\n await client.send({ command: \"channelunsubscribeall\" }, options);\n}\n"],"mappings":"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"}