Skip to content

Commit 2cb462f

Browse files
authored
fix(bot): make Telegram bot english-only (#38)
1 parent 5172928 commit 2cb462f

15 files changed

Lines changed: 48 additions & 441 deletions

src/__tests__/bot-commands.test.ts

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,6 @@ describe("parseCommand", () => {
2222
it("rejects /launch without slug", () => {
2323
expect(parseCommand("/launch").tag).toBe("launch-missing");
2424
});
25-
it("parses /lang without arg as lang-help", () => {
26-
expect(parseCommand("/lang")).toEqual({ tag: "lang-help" });
27-
});
28-
it("parses /lang en", () => {
29-
expect(parseCommand("/lang en")).toEqual({ tag: "lang-set", locale: "en" });
30-
});
31-
it("parses /lang ru", () => {
32-
expect(parseCommand("/lang ru")).toEqual({ tag: "lang-set", locale: "ru" });
33-
});
34-
it("parses unknown /lang code as lang-invalid", () => {
35-
expect(parseCommand("/lang de")).toEqual({ tag: "lang-invalid", arg: "de" });
36-
});
3725
it("parses /getToken", () => {
3826
expect(parseCommand("/getToken")).toEqual({ tag: "get-token" });
3927
});
@@ -50,28 +38,8 @@ describe("parseCommand", () => {
5038
});
5139

5240
describe("bot messages", () => {
53-
it("createdMessage (ru) includes bootstrap steps without links", () => {
54-
const message = createdMessage(
55-
"ru",
56-
"demo-app",
57-
"npx @spawn-dock/create --token pair_demo",
58-
);
59-
60-
expect(message).toContain("Проект demo-app создан.");
61-
expect(message).toContain("1. Запусти bootstrap-команду локально:");
62-
expect(message).toContain("npx @spawn-dock/create --token pair_demo");
63-
expect(message).toContain("Эту команду можно запускать повторно для этого проекта.");
64-
expect(message).toContain("2. После bootstrap запусти:");
65-
expect(message).toContain("pnpm run dev");
66-
expect(message).not.toContain("Preview URL:");
67-
expect(message).not.toContain("Telegram Link:");
68-
expect(message).not.toContain("TMA URL:");
69-
expect(message).not.toContain("Ссылки:");
70-
});
71-
72-
it("createdMessage (en) uses English bootstrap copy", () => {
41+
it("createdMessage uses English bootstrap copy", () => {
7342
const message = createdMessage(
74-
"en",
7543
"demo-app",
7644
"npx @spawn-dock/create --token pair_demo",
7745
);
@@ -86,7 +54,6 @@ describe("bot messages", () => {
8654

8755
it("includes TMA, preview, and telegram links in launchMessage", () => {
8856
const message = launchMessage(
89-
"en",
9057
"demo-app",
9158
"connected",
9259
"https://example.com/tma?tgWebAppStartParam=demo-app",
@@ -103,7 +70,6 @@ describe("bot messages", () => {
10370

10471
it("previewReadyMessage keeps all links", () => {
10572
const message = previewReadyMessage(
106-
"ru",
10773
"demo-app",
10874
"https://example.com/preview/demo-app",
10975
"https://t.me/rustgpt_bot/tma?startapp=demo-app",

src/__tests__/bot-telegram.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ describe("setMyCommands", () => {
7171
for (const cmd of body.commands) {
7272
expect(cmd.command).toMatch(/^[a-z0-9_]+$/);
7373
}
74-
expect(body.commands.map((c) => c.command)).toContain("gettoken");
74+
const commandNames = body.commands.map((c) => c.command);
75+
expect(commandNames).toContain("gettoken");
76+
expect(commandNames).not.toContain("lang");
7577
});
7678
});

src/__tests__/mcp-auth.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ const state: StoreState = {
1717
revokedAt: null,
1818
}],
1919
tunnelSessions: [],
20-
userLocales: {},
2120
};
2221

2322
describe("readMcpApiKey", () => {

src/__tests__/server.test.ts

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ process.env.TELEGRAM_MINI_APP_SHORT_NAME ??= "tma";
2727

2828
function createRuntime(): Runtime {
2929
return {
30-
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [], userLocales: {} },
30+
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [] },
3131
connectionsBySlug: new Map(),
3232
pendingResponses: new Map(),
3333
};
@@ -49,7 +49,6 @@ function createAuthorizedRuntime(): Runtime {
4949
revokedAt: null,
5050
}],
5151
tunnelSessions: [],
52-
userLocales: {},
5352
},
5453
};
5554
}
@@ -59,7 +58,7 @@ const authorizedHeaders = {
5958
};
6059

6160
const mockRuntime: Runtime = {
62-
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [], userLocales: {} },
61+
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [] },
6362
connectionsBySlug: new Map(),
6463
pendingResponses: new Map(),
6564
};
@@ -116,7 +115,7 @@ describe("Express server", () => {
116115

117116
it("POST /v1/bootstrap/claim returns flat bootstrap fields", async () => {
118117
const app = createApp({
119-
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [], userLocales: {} },
118+
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [] },
120119
connectionsBySlug: new Map(),
121120
pendingResponses: new Map(),
122121
});
@@ -172,7 +171,7 @@ describe("Express server", () => {
172171

173172
it("POST /v1/bootstrap/claim replays the same credential when the token was already claimed", async () => {
174173
const app = createApp({
175-
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [], userLocales: {} },
174+
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [] },
176175
connectionsBySlug: new Map(),
177176
pendingResponses: new Map(),
178177
});
@@ -209,35 +208,6 @@ describe("Express server", () => {
209208
expect(res.body.error).toBe("bot_unauthorized");
210209
});
211210

212-
it("POST /api/bot/user-locale/sync stores locale from Telegram language_code", async () => {
213-
const runtime = createRuntime();
214-
const app = createApp(runtime);
215-
216-
const res = await request(app)
217-
.post("/api/bot/user-locale/sync")
218-
.set(botHeaders)
219-
.send({ ownerTelegramId: 99, telegramLanguageCode: "ru-RU" });
220-
221-
expect(res.status).toBe(200);
222-
expect(res.body.locale).toBe("ru");
223-
expect(runtime.state.userLocales["99"]).toBe("ru");
224-
});
225-
226-
it("POST /api/bot/user-locale/set updates explicit locale", async () => {
227-
const runtime = createRuntime();
228-
runtime.state.userLocales["5"] = "ru";
229-
const app = createApp(runtime);
230-
231-
const res = await request(app)
232-
.post("/api/bot/user-locale/set")
233-
.set(botHeaders)
234-
.send({ ownerTelegramId: 5, locale: "en" });
235-
236-
expect(res.status).toBe(200);
237-
expect(res.body.locale).toBe("en");
238-
expect(runtime.state.userLocales["5"]).toBe("en");
239-
});
240-
241211
it("POST /projects accepts bot-authorized creation without /api prefix", async () => {
242212
const app = createApp(createRuntime());
243213

@@ -314,7 +284,6 @@ describe("Express server", () => {
314284
pairingTokens: [],
315285
deviceCredentials: [],
316286
tunnelSessions: [],
317-
userLocales: {},
318287
},
319288
connectionsBySlug: new Map(),
320289
pendingResponses: new Map(),

src/bot/commands.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
// src/bot/commands.ts
2-
import type { BotLocale } from "../types.js";
3-
import { isBotLocale } from "./user-lang.js";
4-
52
export type BotCommand =
63
| { tag: "start" }
74
| { tag: "help" }
85
| { tag: "new"; title: string }
96
| { tag: "launch"; slug: string }
107
| { tag: "launch-missing" }
11-
| { tag: "lang-help" }
12-
| { tag: "lang-set"; locale: BotLocale }
13-
| { tag: "lang-invalid"; arg: string }
148
| { tag: "get-token" }
159
| { tag: "unknown"; input: string };
1610

@@ -30,12 +24,6 @@ export function parseCommand(input: string): BotCommand {
3024
const text = normalizeTelegramCommandText(input);
3125
if (text === "/start") return { tag: "start" };
3226
if (text === "/help") return { tag: "help" };
33-
if (text.startsWith("/lang")) {
34-
const rest = text.slice(5).trim().toLowerCase();
35-
if (!rest) return { tag: "lang-help" };
36-
if (isBotLocale(rest)) return { tag: "lang-set", locale: rest };
37-
return { tag: "lang-invalid", arg: rest };
38-
}
3927
if (text.startsWith("/new")) {
4028
const title = text.slice(4).trim();
4129
return { tag: "new", title: title || "SpawnDock App" };

0 commit comments

Comments
 (0)