@moxxy/plugin-telegram 0.36.1 → 0.37.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/channel/html.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAWxD;AAED;;;;;;;gFAOgF;AAChF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS9C;AAaD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAErD"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/channel/html.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAWxD;AAED;;;;;;;gFAOgF;AAChF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ9C;AAgCD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAErD"}
@@ -35,8 +35,7 @@ export function composeFrame(snap) {
35
35
  * (`'`, `'`) are handled too, since escaped user/code content can
36
36
  * carry them and they'd otherwise leak literally into the fallback message. */
37
37
  export function stripHtml(html) {
38
- return html
39
- .replace(/<\/?[a-z][^>]*>/gi, '')
38
+ return stripTags(html)
40
39
  .replace(/&#(\d+);/g, (_, dec) => safeFromCodePoint(parseInt(dec, 10)))
41
40
  .replace(/&#x([0-9a-f]+);/gi, (_, hex) => safeFromCodePoint(parseInt(hex, 16)))
42
41
  .replace(/&lt;/g, '<')
@@ -44,6 +43,24 @@ export function stripHtml(html) {
44
43
  .replace(/&quot;/g, '"')
45
44
  .replace(/&amp;/g, '&');
46
45
  }
46
+ function stripTags(html) {
47
+ const out = [];
48
+ let cursor = 0;
49
+ while (cursor < html.length) {
50
+ if (html[cursor] !== '<') {
51
+ out.push(html[cursor] ?? '');
52
+ cursor += 1;
53
+ continue;
54
+ }
55
+ const end = html.indexOf('>', cursor + 1);
56
+ if (end === -1) {
57
+ out.push(html.slice(cursor));
58
+ break;
59
+ }
60
+ cursor = end + 1;
61
+ }
62
+ return out.join('');
63
+ }
47
64
  /** Decode a numeric entity's code point, leaving an out-of-range/invalid value
48
65
  * untouched (return empty) rather than throwing. */
49
66
  function safeFromCodePoint(cp) {
@@ -1 +1 @@
1
- {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/channel/html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAGtD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAC,IAAmB;IAC9C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,IAAI,CAAC,YAAY;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACrD,IAAI,IAAI,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7D,+DAA+D;IAC/D,sEAAsE;IACtE,wEAAwE;IACxE,qEAAqE;IACrE,IAAI,IAAI,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,IAAI,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;gFAOgF;AAChF,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,IAAI;SACR,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,GAAW,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;SAC9E,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,GAAW,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;SACtF,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED;qDACqD;AACrD,SAAS,iBAAiB,CAAC,EAAU;IACnC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,QAAQ;QAAE,OAAO,EAAE,CAAC;IAC/D,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,CAAS,EAAE,CAAS;IAC3C,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC;AACjD,CAAC"}
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/channel/html.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAwFzD"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CA6FzD"}
package/dist/format.js CHANGED
@@ -38,20 +38,28 @@ export function markdownToTelegramHtml(md) {
38
38
  // Pull fenced code blocks out FIRST so their contents skip inline
39
39
  // markdown processing. Replace each with a placeholder, render the
40
40
  // rest, then splice them back.
41
- const fences = [];
42
- let working = md.replace(/```([a-zA-Z0-9_+-]*)\n?([\s\S]*?)```/g, (_, lang, body) => {
43
- const html = `<pre><code${lang ? ` class="language-${escapeHtml(String(lang))}"` : ''}>` +
44
- escapeHtml(String(body)).replace(/\n+$/, '') +
41
+ const extracted = extractFences(md);
42
+ const fences = extracted.fences.map(({ lang, body }) => {
43
+ const html = `<pre><code${lang ? ` class="language-${escapeHtml(lang)}"` : ''}>` +
44
+ escapeHtml(trimTrailingNewlines(body)) +
45
45
  '</code></pre>';
46
- fences.push(html);
47
- return ` FENCE${fences.length - 1} `;
46
+ return html;
48
47
  });
48
+ let working = extracted.working;
49
49
  // Pull inline code spans out next, same reason.
50
50
  const inlines = [];
51
51
  working = working.replace(/`([^`\n]+)`/g, (_, body) => {
52
52
  inlines.push(`<code>${escapeHtml(String(body))}</code>`);
53
53
  return ` INLINE${inlines.length - 1} `;
54
54
  });
55
+ // Pull link destinations out before HTML escaping. The visible label stays
56
+ // in the Markdown pipeline, while the raw target is validated and escaped
57
+ // exactly once when the final anchor is emitted.
58
+ const linkTargets = [];
59
+ working = working.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (_match, text, url) => {
60
+ linkTargets.push(String(url));
61
+ return `[${String(text)}](LINKTARGET${linkTargets.length - 1})`;
62
+ });
55
63
  // Now safe to escape HTML special chars in everything else.
56
64
  working = escapeHtml(working);
57
65
  // Headings → bold. Telegram has no heading element; bold + line
@@ -86,15 +94,12 @@ export function markdownToTelegramHtml(md) {
86
94
  // mid-word underscores (`some_var_name`) and stray bullets.
87
95
  working = working.replace(/(^|[\s(,.!?:;])\*([^*\n]+)\*(?=$|[\s),.!?:;])/g, (_m, pre, body) => `${pre}<i>${String(body)}</i>`);
88
96
  working = working.replace(/(^|[\s(,.!?:;])_([^_\n]+)_(?=$|[\s),.!?:;])/g, (_m, pre, body) => `${pre}<i>${String(body)}</i>`);
89
- // Links [text](url) — strip url tracking params if needed later;
90
- // for now just emit. URLs may contain `&` which is already escaped
91
- // to `&amp;` by escapeHtml above; that's valid inside href.
92
- working = working.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (m, text, url) => {
93
- // The url got HTML-escaped earlier; restore enough that the link
94
- // actually points where it should. Only `&amp;` → `&` is needed
95
- // for the typical case; `<>` shouldn't appear in a URL but unescape
96
- // them defensively.
97
- const cleanUrl = String(url).replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
97
+ // Links [text](url). Targets were removed before escaping, so they cannot
98
+ // be double-decoded and are escaped once at this attribute boundary.
99
+ working = working.replace(/\[([^\]]+)\]\(LINKTARGET(\d+)\)/g, (_match, text, index) => {
100
+ const cleanUrl = linkTargets[Number(index)];
101
+ if (cleanUrl === undefined)
102
+ return String(text);
98
103
  // The anchor target comes from arbitrary model output (and, via prompt
99
104
  // injection, untrusted data the model echoes). Don't rely on Telegram's
100
105
  // server-side parser as the sole sanitizer: emit a clickable <a> only for
@@ -103,7 +108,7 @@ export function markdownToTelegramHtml(md) {
103
108
  // the original `[text](url)` text (already HTML-escaped upstream) so it
104
109
  // can't navigate the client.
105
110
  if (!isAllowedUrl(cleanUrl))
106
- return String(m);
111
+ return `[${String(text)}](${escapeHtml(cleanUrl)})`;
107
112
  return `<a href="${escapeAttr(cleanUrl)}">${String(text)}</a>`;
108
113
  });
109
114
  // Splice fenced + inline code back in.
@@ -111,6 +116,42 @@ export function markdownToTelegramHtml(md) {
111
116
  working = working.replace(/ FENCE(\d+) /g, (_, i) => fences[Number(i)] ?? '');
112
117
  return working;
113
118
  }
119
+ function extractFences(md) {
120
+ const output = [];
121
+ const fences = [];
122
+ let cursor = 0;
123
+ while (cursor < md.length) {
124
+ const start = md.indexOf('```', cursor);
125
+ if (start === -1)
126
+ break;
127
+ let bodyStart = start + 3;
128
+ while (bodyStart < md.length && isFenceLanguageChar(md[bodyStart]))
129
+ bodyStart += 1;
130
+ const lang = md.slice(start + 3, bodyStart);
131
+ if (md[bodyStart] === '\n')
132
+ bodyStart += 1;
133
+ const close = md.indexOf('```', bodyStart);
134
+ if (close === -1)
135
+ break;
136
+ output.push(md.slice(cursor, start), ` FENCE${fences.length} `);
137
+ fences.push({ lang, body: md.slice(bodyStart, close) });
138
+ cursor = close + 3;
139
+ }
140
+ output.push(md.slice(cursor));
141
+ return { working: output.join(''), fences };
142
+ }
143
+ function isFenceLanguageChar(char) {
144
+ return char !== undefined && ((char >= 'a' && char <= 'z') ||
145
+ (char >= 'A' && char <= 'Z') ||
146
+ (char >= '0' && char <= '9') ||
147
+ char === '_' || char === '+' || char === '-');
148
+ }
149
+ function trimTrailingNewlines(value) {
150
+ let end = value.length;
151
+ while (end > 0 && value[end - 1] === '\n')
152
+ end -= 1;
153
+ return value.slice(0, end);
154
+ }
114
155
  /**
115
156
  * GitHub / Obsidian-style callout types we recognise as the first line of a
116
157
  * blockquote (`[!note]`, `[!warning]`, …). Each maps to a leading emoji, a
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moxxy/plugin-telegram",
3
- "version": "0.36.1",
3
+ "version": "0.37.1",
4
4
  "description": "Telegram channel for moxxy via grammy. Treats Telegram chats as a bidirectional channel: prompts in, assistant + tool prompts out, inline-keyboard permission flow, QR deep-link chat pairing.",
5
5
  "keywords": [
6
6
  "moxxy",
@@ -68,19 +68,19 @@
68
68
  "@clack/prompts": "^1.4.0",
69
69
  "grammy": "^1.30.0",
70
70
  "qrcode": "^1.5.4",
71
- "@moxxy/channel-kit": "0.36.1",
72
- "@moxxy/core": "0.36.1",
73
- "@moxxy/plugin-vault": "0.36.1",
74
- "@moxxy/config": "0.36.1",
75
- "@moxxy/sdk": "0.36.1"
71
+ "@moxxy/config": "0.37.1",
72
+ "@moxxy/channel-kit": "0.37.1",
73
+ "@moxxy/core": "0.37.1",
74
+ "@moxxy/plugin-vault": "0.37.1",
75
+ "@moxxy/sdk": "0.37.1"
76
76
  },
77
77
  "devDependencies": {
78
78
  "@types/node": "^22.10.0",
79
79
  "@types/qrcode": "^1.5.5",
80
80
  "typescript": "^5.7.3",
81
- "vitest": "^2.1.8",
82
- "@moxxy/tsconfig": "0.0.0",
83
- "@moxxy/vitest-preset": "0.0.0"
81
+ "vitest": "^3.2.6",
82
+ "@moxxy/vitest-preset": "0.0.0",
83
+ "@moxxy/tsconfig": "0.0.0"
84
84
  },
85
85
  "scripts": {
86
86
  "build": "tsc -p tsconfig.json",
@@ -6,6 +6,10 @@ describe('stripHtml', () => {
6
6
  expect(stripHtml('<b>bold</b> and <code>code</code>')).toBe('bold and code');
7
7
  });
8
8
 
9
+ it('does not create a fresh tag when adjacent markup is removed', () => {
10
+ expect(stripHtml('<scr<script>hidden</script>ipt>visible</script>')).toBe('hiddenipt>visible');
11
+ });
12
+
9
13
  it('decodes the four named entities', () => {
10
14
  expect(stripHtml('a &lt; b &gt; c &amp; d &quot;e&quot;')).toBe('a < b > c & d "e"');
11
15
  });
@@ -34,8 +34,7 @@ export function composeFrame(snap: RenderedFrame): string {
34
34
  * (`&#39;`, `&#x27;`) are handled too, since escaped user/code content can
35
35
  * carry them and they'd otherwise leak literally into the fallback message. */
36
36
  export function stripHtml(html: string): string {
37
- return html
38
- .replace(/<\/?[a-z][^>]*>/gi, '')
37
+ return stripTags(html)
39
38
  .replace(/&#(\d+);/g, (_, dec: string) => safeFromCodePoint(parseInt(dec, 10)))
40
39
  .replace(/&#x([0-9a-f]+);/gi, (_, hex: string) => safeFromCodePoint(parseInt(hex, 16)))
41
40
  .replace(/&lt;/g, '<')
@@ -44,6 +43,25 @@ export function stripHtml(html: string): string {
44
43
  .replace(/&amp;/g, '&');
45
44
  }
46
45
 
46
+ function stripTags(html: string): string {
47
+ const out: string[] = [];
48
+ let cursor = 0;
49
+ while (cursor < html.length) {
50
+ if (html[cursor] !== '<') {
51
+ out.push(html[cursor] ?? '');
52
+ cursor += 1;
53
+ continue;
54
+ }
55
+ const end = html.indexOf('>', cursor + 1);
56
+ if (end === -1) {
57
+ out.push(html.slice(cursor));
58
+ break;
59
+ }
60
+ cursor = end + 1;
61
+ }
62
+ return out.join('');
63
+ }
64
+
47
65
  /** Decode a numeric entity's code point, leaving an out-of-range/invalid value
48
66
  * untouched (return empty) rather than throwing. */
49
67
  function safeFromCodePoint(cp: number): string {
@@ -34,11 +34,22 @@ describe('markdownToTelegramHtml', () => {
34
34
  expect(out).toContain('**not bold**');
35
35
  });
36
36
 
37
+ it('leaves a long unterminated fence literal', () => {
38
+ const input = `\`\`\`${'a'.repeat(50_000)}`;
39
+ expect(markdownToTelegramHtml(input)).toBe(input);
40
+ });
41
+
37
42
  it('converts links to <a href="...">', () => {
38
43
  const out = markdownToTelegramHtml('See [docs](https://example.com).');
39
44
  expect(out).toContain('<a href="https://example.com">docs</a>');
40
45
  });
41
46
 
47
+ it('escapes a link target exactly once', () => {
48
+ const out = markdownToTelegramHtml('[search](https://example.com/?a=1&b=%3Ctwo%3E)');
49
+ expect(out).toContain('href="https://example.com/?a=1&amp;b=%3Ctwo%3E"');
50
+ expect(out).not.toContain('&amp;amp;');
51
+ });
52
+
42
53
  it('allows http, mailto, and tel scheme links', () => {
43
54
  expect(markdownToTelegramHtml('[a](http://x.com)')).toContain('<a href="http://x.com">');
44
55
  expect(markdownToTelegramHtml('[m](mailto:a@b.com)')).toContain('<a href="mailto:a@b.com">');
package/src/format.ts CHANGED
@@ -38,15 +38,15 @@ export function markdownToTelegramHtml(md: string): string {
38
38
  // Pull fenced code blocks out FIRST so their contents skip inline
39
39
  // markdown processing. Replace each with a placeholder, render the
40
40
  // rest, then splice them back.
41
- const fences: string[] = [];
42
- let working = md.replace(/```([a-zA-Z0-9_+-]*)\n?([\s\S]*?)```/g, (_, lang, body) => {
41
+ const extracted = extractFences(md);
42
+ const fences = extracted.fences.map(({ lang, body }) => {
43
43
  const html =
44
- `<pre><code${lang ? ` class="language-${escapeHtml(String(lang))}"` : ''}>` +
45
- escapeHtml(String(body)).replace(/\n+$/, '') +
44
+ `<pre><code${lang ? ` class="language-${escapeHtml(lang)}"` : ''}>` +
45
+ escapeHtml(trimTrailingNewlines(body)) +
46
46
  '</code></pre>';
47
- fences.push(html);
48
- return ` FENCE${fences.length - 1} `;
47
+ return html;
49
48
  });
49
+ let working = extracted.working;
50
50
 
51
51
  // Pull inline code spans out next, same reason.
52
52
  const inlines: string[] = [];
@@ -55,6 +55,15 @@ export function markdownToTelegramHtml(md: string): string {
55
55
  return ` INLINE${inlines.length - 1} `;
56
56
  });
57
57
 
58
+ // Pull link destinations out before HTML escaping. The visible label stays
59
+ // in the Markdown pipeline, while the raw target is validated and escaped
60
+ // exactly once when the final anchor is emitted.
61
+ const linkTargets: string[] = [];
62
+ working = working.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (_match, text, url) => {
63
+ linkTargets.push(String(url));
64
+ return `[${String(text)}](LINKTARGET${linkTargets.length - 1})`;
65
+ });
66
+
58
67
  // Now safe to escape HTML special chars in everything else.
59
68
  working = escapeHtml(working);
60
69
 
@@ -97,15 +106,11 @@ export function markdownToTelegramHtml(md: string): string {
97
106
  working = working.replace(/(^|[\s(,.!?:;])\*([^*\n]+)\*(?=$|[\s),.!?:;])/g, (_m, pre, body) => `${pre}<i>${String(body)}</i>`);
98
107
  working = working.replace(/(^|[\s(,.!?:;])_([^_\n]+)_(?=$|[\s),.!?:;])/g, (_m, pre, body) => `${pre}<i>${String(body)}</i>`);
99
108
 
100
- // Links [text](url) — strip url tracking params if needed later;
101
- // for now just emit. URLs may contain `&` which is already escaped
102
- // to `&amp;` by escapeHtml above; that's valid inside href.
103
- working = working.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, (m, text, url) => {
104
- // The url got HTML-escaped earlier; restore enough that the link
105
- // actually points where it should. Only `&amp;` → `&` is needed
106
- // for the typical case; `<>` shouldn't appear in a URL but unescape
107
- // them defensively.
108
- const cleanUrl = String(url).replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>');
109
+ // Links [text](url). Targets were removed before escaping, so they cannot
110
+ // be double-decoded and are escaped once at this attribute boundary.
111
+ working = working.replace(/\[([^\]]+)\]\(LINKTARGET(\d+)\)/g, (_match, text, index) => {
112
+ const cleanUrl = linkTargets[Number(index)];
113
+ if (cleanUrl === undefined) return String(text);
109
114
  // The anchor target comes from arbitrary model output (and, via prompt
110
115
  // injection, untrusted data the model echoes). Don't rely on Telegram's
111
116
  // server-side parser as the sole sanitizer: emit a clickable <a> only for
@@ -113,7 +118,7 @@ export function markdownToTelegramHtml(md: string): string {
113
118
  // else — `javascript:`, `data:`, `file:`, `tg://` deep links — is left as
114
119
  // the original `[text](url)` text (already HTML-escaped upstream) so it
115
120
  // can't navigate the client.
116
- if (!isAllowedUrl(cleanUrl)) return String(m);
121
+ if (!isAllowedUrl(cleanUrl)) return `[${String(text)}](${escapeHtml(cleanUrl)})`;
117
122
  return `<a href="${escapeAttr(cleanUrl)}">${String(text)}</a>`;
118
123
  });
119
124
 
@@ -124,6 +129,45 @@ export function markdownToTelegramHtml(md: string): string {
124
129
  return working;
125
130
  }
126
131
 
132
+ function extractFences(md: string): {
133
+ readonly working: string;
134
+ readonly fences: ReadonlyArray<{ readonly lang: string; readonly body: string }>;
135
+ } {
136
+ const output: string[] = [];
137
+ const fences: Array<{ lang: string; body: string }> = [];
138
+ let cursor = 0;
139
+ while (cursor < md.length) {
140
+ const start = md.indexOf('```', cursor);
141
+ if (start === -1) break;
142
+ let bodyStart = start + 3;
143
+ while (bodyStart < md.length && isFenceLanguageChar(md[bodyStart])) bodyStart += 1;
144
+ const lang = md.slice(start + 3, bodyStart);
145
+ if (md[bodyStart] === '\n') bodyStart += 1;
146
+ const close = md.indexOf('```', bodyStart);
147
+ if (close === -1) break;
148
+ output.push(md.slice(cursor, start), ` FENCE${fences.length} `);
149
+ fences.push({ lang, body: md.slice(bodyStart, close) });
150
+ cursor = close + 3;
151
+ }
152
+ output.push(md.slice(cursor));
153
+ return { working: output.join(''), fences };
154
+ }
155
+
156
+ function isFenceLanguageChar(char: string | undefined): boolean {
157
+ return char !== undefined && (
158
+ (char >= 'a' && char <= 'z') ||
159
+ (char >= 'A' && char <= 'Z') ||
160
+ (char >= '0' && char <= '9') ||
161
+ char === '_' || char === '+' || char === '-'
162
+ );
163
+ }
164
+
165
+ function trimTrailingNewlines(value: string): string {
166
+ let end = value.length;
167
+ while (end > 0 && value[end - 1] === '\n') end -= 1;
168
+ return value.slice(0, end);
169
+ }
170
+
127
171
  /**
128
172
  * GitHub / Obsidian-style callout types we recognise as the first line of a
129
173
  * blockquote (`[!note]`, `[!warning]`, …). Each maps to a leading emoji, a