Skip to content

Commit d75fcc7

Browse files
Xiaofuziodshu zf
andauthored
fix(bridge): convert <br> to newline for Telegram HTML mode (#23)
The Telegram Bot API's HTML parse mode does not support the <br> tag and rejects it with "400 Bad Request: can't parse entities: Unsupported start tag 'br'". Previously, markdownToHtml kept <br> in its whitelist, so any CommonMark hard break (trailing two spaces or backslash) produced by markdown-it would be forwarded to Telegram and crash the bridge with an uncaught GrammyError. Fix by replacing <br> with a literal newline before the whitelist strip, and removing br from the whitelist comment/regex. Repro: send any message whose markdown contains a hard line break, e.g. "line one \nline two" — the bridge process exits with an unhandled GrammyError in MessageRenderer.flushCallback. Adds two regression tests covering both CommonMark hard break forms. Co-authored-by: shu zf <shuzf@aicoda.tech>
1 parent a69ed1c commit d75fcc7

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

bridge/src/__tests__/markdown.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ describe('Telegram rendering', () => {
2121
// Telegram doesn't support <h1>, should be plain text or bold
2222
expect(result).not.toContain('<h1>');
2323
});
24+
25+
it('converts <br> from markdown hard break to newline', () => {
26+
// CommonMark hard break: two trailing spaces before newline -> <br>
27+
// Telegram HTML parse mode does NOT support <br> and rejects it with
28+
// 400 Bad Request: can't parse entities: Unsupported start tag "br".
29+
const result = markdownToTelegram('line one \nline two');
30+
expect(result).not.toContain('<br');
31+
expect(result).toContain('line one');
32+
expect(result).toContain('line two');
33+
});
34+
35+
it('converts backslash hard break to newline', () => {
36+
// CommonMark hard break: trailing backslash -> <br>
37+
const result = markdownToTelegram('line one\\\nline two');
38+
expect(result).not.toContain('<br');
39+
expect(result).toContain('line one');
40+
expect(result).toContain('line two');
41+
});
2442
});
2543

2644
describe('Discord chunking', () => {

bridge/src/markdown/ir.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,12 @@ export function markdownToHtml(text: string): string {
156156
// Strip <hr> tags
157157
html = html.replace(/<hr\s*\/?>/g, '---\n');
158158

159-
// Strip any remaining unsupported HTML tags (keep: b, i, s, u, code, pre, a, br)
160-
html = html.replace(/<\/?(?!b>|\/b>|i>|\/i>|s>|\/s>|u>|\/u>|code>|\/code>|pre>|\/pre>|a[\s>]|\/a>|br\s*\/?>)[a-z][a-z0-9]*[^>]*>/gi, '');
159+
// <br> is NOT supported by Telegram HTML parse mode — convert to newline
160+
// (Telegram API rejects <br> with 400: Unsupported start tag "br")
161+
html = html.replace(/<br\s*\/?>/gi, '\n');
162+
163+
// Strip any remaining unsupported HTML tags (keep: b, i, s, u, code, pre, a)
164+
html = html.replace(/<\/?(?!b>|\/b>|i>|\/i>|s>|\/s>|u>|\/u>|code>|\/code>|pre>|\/pre>|a[\s>]|\/a>)[a-z][a-z0-9]*[^>]*>/gi, '');
161165

162166
return html.trim();
163167
}

0 commit comments

Comments
 (0)