feat(ts-protocol): surface invokerGroups on TS3TextMessage via pure mapper

This commit is contained in:
saopig1 committed 2026-06-26 20:35:31 +08:00
1 parent f98ce47c52
commit b090a8ec21
2 files changed
+62 -8

No files matched your search

+19 -8
View File
@@ -61,6 +61,24 @@ export interface TS3TextMessage {
invokerUid: string; invokerUid: string;
message: string; message: string;
targetMode: number; // 1=private, 2=channel, 3=server targetMode: number; // 1=private, 2=channel, 3=server
invokerGroups: string[]; // sender's TS server-group ids; [] when not in view cache
}
/**
* Map the library's TextMessage to our wrapper. Preserves invokerGroups (the
* sender's TS server groups), which the library populates only when the sender
* is in the bot's client-view cache; otherwise it is []. Used by the chat
* command permission gate.
*/
export function toTS3TextMessage(msg: TextMessage): TS3TextMessage {
return {
invokerName: msg.invokerName,
invokerId: String(msg.invokerID),
invokerUid: msg.invokerUID,
message: msg.message,
targetMode: msg.targetMode,
invokerGroups: msg.invokerGroups ?? [],
};
} }
export class TS3Client extends EventEmitter { export class TS3Client extends EventEmitter {
@@ -203,14 +221,7 @@ export class TS3Client extends EventEmitter {
}); });
this.client.on("textMessage", (msg: TextMessage) => { this.client.on("textMessage", (msg: TextMessage) => {
const tsMsg: TS3TextMessage = { this.emit("textMessage", toTS3TextMessage(msg));
invokerName: msg.invokerName,
invokerId: String(msg.invokerID),
invokerUid: msg.invokerUID,
message: msg.message,
targetMode: msg.targetMode,
};
this.emit("textMessage", tsMsg);
}); });
this.client.on("disconnected", (err) => { this.client.on("disconnected", (err) => {
+43
View File
@@ -0,0 +1,43 @@
import { describe, it, expect } from "vitest";
import { toTS3TextMessage } from "./client.js";
import type { TextMessage } from "@honeybbq/teamspeak-client";
function makeMsg(over: Partial<TextMessage> = {}): TextMessage {
return {
invokerName: "Alice",
invokerUID: "uid-abc",
message: "!stop",
invokerGroups: ["6", "8"],
targetMode: 2,
targetID: 0n,
invokerID: 5,
...over,
};
}
describe("toTS3TextMessage", () => {
it("maps core fields and stringifies invokerID", () => {
const r = toTS3TextMessage(makeMsg());
expect(r.invokerName).toBe("Alice");
expect(r.invokerId).toBe("5");
expect(r.invokerUid).toBe("uid-abc");
expect(r.message).toBe("!stop");
expect(r.targetMode).toBe(2);
});
it("preserves the sender's server groups", () => {
expect(toTS3TextMessage(makeMsg({ invokerGroups: ["6"] })).invokerGroups).toEqual(["6"]);
});
it("defaults missing invokerGroups to an empty array", () => {
const partial = {
invokerName: "Bob",
invokerUID: "u",
message: "!stop",
targetMode: 1,
targetID: 0n,
invokerID: 7,
} as unknown as TextMessage;
expect(toTS3TextMessage(partial).invokerGroups).toEqual([]);
});
});