@moxxy/plugin-telegram 0.27.0
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/LICENSE +21 -0
- package/dist/approval.d.ts +37 -0
- package/dist/approval.d.ts.map +1 -0
- package/dist/approval.js +75 -0
- package/dist/approval.js.map +1 -0
- package/dist/channel/approval-prompt.d.ts +20 -0
- package/dist/channel/approval-prompt.d.ts.map +1 -0
- package/dist/channel/approval-prompt.js +34 -0
- package/dist/channel/approval-prompt.js.map +1 -0
- package/dist/channel/callback-handler.d.ts +32 -0
- package/dist/channel/callback-handler.d.ts.map +1 -0
- package/dist/channel/callback-handler.js +212 -0
- package/dist/channel/callback-handler.js.map +1 -0
- package/dist/channel/frame-pump.d.ts +58 -0
- package/dist/channel/frame-pump.d.ts.map +1 -0
- package/dist/channel/frame-pump.js +159 -0
- package/dist/channel/frame-pump.js.map +1 -0
- package/dist/channel/html.d.ts +24 -0
- package/dist/channel/html.d.ts.map +1 -0
- package/dist/channel/html.js +62 -0
- package/dist/channel/html.js.map +1 -0
- package/dist/channel/pairing-handler.d.ts +66 -0
- package/dist/channel/pairing-handler.d.ts.map +1 -0
- package/dist/channel/pairing-handler.js +147 -0
- package/dist/channel/pairing-handler.js.map +1 -0
- package/dist/channel/permission-prompt.d.ts +21 -0
- package/dist/channel/permission-prompt.d.ts.map +1 -0
- package/dist/channel/permission-prompt.js +36 -0
- package/dist/channel/permission-prompt.js.map +1 -0
- package/dist/channel/slash-handler.d.ts +47 -0
- package/dist/channel/slash-handler.d.ts.map +1 -0
- package/dist/channel/slash-handler.js +214 -0
- package/dist/channel/slash-handler.js.map +1 -0
- package/dist/channel/text-handler.d.ts +43 -0
- package/dist/channel/text-handler.d.ts.map +1 -0
- package/dist/channel/text-handler.js +116 -0
- package/dist/channel/text-handler.js.map +1 -0
- package/dist/channel/turn-runner.d.ts +40 -0
- package/dist/channel/turn-runner.d.ts.map +1 -0
- package/dist/channel/turn-runner.js +67 -0
- package/dist/channel/turn-runner.js.map +1 -0
- package/dist/channel/typing-indicator.d.ts +14 -0
- package/dist/channel/typing-indicator.d.ts.map +1 -0
- package/dist/channel/typing-indicator.js +29 -0
- package/dist/channel/typing-indicator.js.map +1 -0
- package/dist/channel/voice-handler.d.ts +42 -0
- package/dist/channel/voice-handler.d.ts.map +1 -0
- package/dist/channel/voice-handler.js +138 -0
- package/dist/channel/voice-handler.js.map +1 -0
- package/dist/channel.d.ts +118 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +478 -0
- package/dist/channel.js.map +1 -0
- package/dist/channel.test-d.d.ts +2 -0
- package/dist/channel.test-d.d.ts.map +1 -0
- package/dist/channel.test-d.js +5 -0
- package/dist/channel.test-d.js.map +1 -0
- package/dist/format.d.ts +38 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +237 -0
- package/dist/format.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +304 -0
- package/dist/index.js.map +1 -0
- package/dist/keys.d.ts +37 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +42 -0
- package/dist/keys.js.map +1 -0
- package/dist/pair-flow.d.ts +18 -0
- package/dist/pair-flow.d.ts.map +1 -0
- package/dist/pair-flow.js +119 -0
- package/dist/pair-flow.js.map +1 -0
- package/dist/pairing.d.ts +90 -0
- package/dist/pairing.d.ts.map +1 -0
- package/dist/pairing.js +97 -0
- package/dist/pairing.js.map +1 -0
- package/dist/permission.d.ts +25 -0
- package/dist/permission.d.ts.map +1 -0
- package/dist/permission.js +49 -0
- package/dist/permission.js.map +1 -0
- package/dist/render.d.ts +68 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +439 -0
- package/dist/render.js.map +1 -0
- package/dist/setup-wizard.d.ts +21 -0
- package/dist/setup-wizard.d.ts.map +1 -0
- package/dist/setup-wizard.js +140 -0
- package/dist/setup-wizard.js.map +1 -0
- package/package.json +91 -0
- package/src/approval.test.ts +103 -0
- package/src/approval.ts +86 -0
- package/src/channel/approval-prompt.ts +46 -0
- package/src/channel/callback-handler.test.ts +188 -0
- package/src/channel/callback-handler.ts +256 -0
- package/src/channel/frame-pump.ts +176 -0
- package/src/channel/html.test.ts +40 -0
- package/src/channel/html.ts +60 -0
- package/src/channel/pairing-handler.ts +181 -0
- package/src/channel/permission-prompt.ts +51 -0
- package/src/channel/slash-handler.ts +259 -0
- package/src/channel/text-handler.test.ts +222 -0
- package/src/channel/text-handler.ts +174 -0
- package/src/channel/turn-runner.ts +102 -0
- package/src/channel/typing-indicator.ts +31 -0
- package/src/channel/voice-handler.test.ts +328 -0
- package/src/channel/voice-handler.ts +198 -0
- package/src/channel/voice-reply.test.ts +223 -0
- package/src/channel.test-d.ts +7 -0
- package/src/channel.ts +564 -0
- package/src/format.test.ts +159 -0
- package/src/format.ts +257 -0
- package/src/index.ts +347 -0
- package/src/keys.ts +52 -0
- package/src/pair-flow.ts +131 -0
- package/src/pairing.test.ts +113 -0
- package/src/pairing.ts +184 -0
- package/src/permission.test.ts +56 -0
- package/src/permission.ts +61 -0
- package/src/render.test.ts +350 -0
- package/src/render.ts +522 -0
- package/src/setup-wizard.ts +178 -0
- package/src/subcommands.test.ts +153 -0
package/dist/format.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert the model's Markdown output into Telegram-flavoured HTML so
|
|
3
|
+
* the bot renders **bold**, `code`, ```code blocks```, [links](…),
|
|
4
|
+
* lists, and headings instead of dumping raw `**` and `#` characters
|
|
5
|
+
* into the chat.
|
|
6
|
+
*
|
|
7
|
+
* Why HTML and not MarkdownV2: MarkdownV2 requires escaping
|
|
8
|
+
* `_ * [ ] ( ) ~ \` > # + - = | { } . !` literally everywhere they
|
|
9
|
+
* AREN'T part of formatting — one stray `.` in a sentence breaks the
|
|
10
|
+
* whole message. HTML only needs three escapes (`< > &`) in text
|
|
11
|
+
* segments, and Telegram's HTML mode supports every tag we need
|
|
12
|
+
* (`<b>`, `<i>`, `<s>`, `<tg-spoiler>`, `<code>`, `<pre>`, `<a>`,
|
|
13
|
+
* `<blockquote>` / `<blockquote expandable>`).
|
|
14
|
+
*
|
|
15
|
+
* Telegram has no native headings or list elements, so:
|
|
16
|
+
* - `#`, `##`, `###` headings → bold text on their own line.
|
|
17
|
+
* - `- item` / `* item` bullets → `• item` (bullet glyph).
|
|
18
|
+
* - `1. item` numbered → kept as-is (the digit is fine).
|
|
19
|
+
*
|
|
20
|
+
* Beyond CommonMark we also map a few extensions so the model can lean
|
|
21
|
+
* on Telegram's richer surface without learning a new syntax:
|
|
22
|
+
* - `~~strike~~` → `<s>` strikethrough.
|
|
23
|
+
* - `||spoiler||` → `<tg-spoiler>` (tap-to-reveal hidden text).
|
|
24
|
+
* - `> [!note] Heading` → a titled, emoji-tagged callout blockquote.
|
|
25
|
+
* - `> [!details]- Title` → a COLLAPSED (expandable) callout — the
|
|
26
|
+
* load-bearing "hide the details" box. The
|
|
27
|
+
* trailing `-` forces collapsed, `+` forces
|
|
28
|
+
* open; some types (details/example/faq)
|
|
29
|
+
* collapse by default.
|
|
30
|
+
* - a plain `>` quote that runs long auto-collapses into an
|
|
31
|
+
* `<blockquote expandable>` so a wall of quoted text stays tidy.
|
|
32
|
+
*
|
|
33
|
+
* Code blocks are emitted as `<pre><code class="language-xxx">…</code></pre>`,
|
|
34
|
+
* inline code as `<code>…</code>`. Everything inside code is escaped
|
|
35
|
+
* but no formatting markers run.
|
|
36
|
+
*/
|
|
37
|
+
export function markdownToTelegramHtml(md) {
|
|
38
|
+
// Pull fenced code blocks out FIRST so their contents skip inline
|
|
39
|
+
// markdown processing. Replace each with a placeholder, render the
|
|
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+$/, '') +
|
|
45
|
+
'</code></pre>';
|
|
46
|
+
fences.push(html);
|
|
47
|
+
return ` FENCE${fences.length - 1} `;
|
|
48
|
+
});
|
|
49
|
+
// Pull inline code spans out next, same reason.
|
|
50
|
+
const inlines = [];
|
|
51
|
+
working = working.replace(/`([^`\n]+)`/g, (_, body) => {
|
|
52
|
+
inlines.push(`<code>${escapeHtml(String(body))}</code>`);
|
|
53
|
+
return ` INLINE${inlines.length - 1} `;
|
|
54
|
+
});
|
|
55
|
+
// Now safe to escape HTML special chars in everything else.
|
|
56
|
+
working = escapeHtml(working);
|
|
57
|
+
// Headings → bold. Telegram has no heading element; bold + line
|
|
58
|
+
// break is the conventional substitution.
|
|
59
|
+
working = working.replace(/^(#{1,6})\s+(.*)$/gm, (_, _hashes, text) => `<b>${String(text)}</b>`);
|
|
60
|
+
// Block quotes (>) — Telegram supports <blockquote> and, since Bot API
|
|
61
|
+
// 7.0, <blockquote expandable> (a collapsible "show more" box). Wrap
|
|
62
|
+
// consecutive quote lines into one block and let `renderBlockquote`
|
|
63
|
+
// decide collapsed-vs-open from an optional `[!callout]` marker or the
|
|
64
|
+
// quote's length.
|
|
65
|
+
working = working.replace(/((?:^>[^\n]*\n?)+)/gm, (m) => {
|
|
66
|
+
const stripped = m
|
|
67
|
+
.replace(/> ?/g, '')
|
|
68
|
+
.replace(/\n$/, '');
|
|
69
|
+
return `${renderBlockquote(stripped)}\n`;
|
|
70
|
+
});
|
|
71
|
+
// Bullet list items → bullet glyph. Match leading whitespace +
|
|
72
|
+
// -/*/+ + space. Don't touch indented sub-bullets' indent.
|
|
73
|
+
working = working.replace(/^(\s*)([-*+])\s+/gm, (_m, indent) => `${indent}• `);
|
|
74
|
+
// Bold **text** — process before italic so `**text**` doesn't get
|
|
75
|
+
// captured by the single-asterisk italic rule first.
|
|
76
|
+
working = working.replace(/\*\*([^*\n]+)\*\*/g, (_, body) => `<b>${String(body)}</b>`);
|
|
77
|
+
// Bold __text__
|
|
78
|
+
working = working.replace(/__([^_\n]+)__/g, (_, body) => `<b>${String(body)}</b>`);
|
|
79
|
+
// Strikethrough ~~text~~ → <s>. (GitHub flavour; a single `~` stays
|
|
80
|
+
// literal so it never eats a stray tilde in prose.)
|
|
81
|
+
working = working.replace(/~~([^~\n]+)~~/g, (_, body) => `<s>${String(body)}</s>`);
|
|
82
|
+
// Spoiler ||text|| → <tg-spoiler> (Telegram's tap-to-reveal). Content
|
|
83
|
+
// can't span a `|` so a single bar / table pipe is left untouched.
|
|
84
|
+
working = working.replace(/\|\|([^|\n]+)\|\|/g, (_, body) => `<tg-spoiler>${String(body)}</tg-spoiler>`);
|
|
85
|
+
// Italic *text* and _text_. Use lookarounds to avoid matching
|
|
86
|
+
// mid-word underscores (`some_var_name`) and stray bullets.
|
|
87
|
+
working = working.replace(/(^|[\s(,.!?:;])\*([^*\n]+)\*(?=$|[\s),.!?:;])/g, (_m, pre, body) => `${pre}<i>${String(body)}</i>`);
|
|
88
|
+
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 `&` 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 `&` → `&` is needed
|
|
95
|
+
// for the typical case; `<>` shouldn't appear in a URL but unescape
|
|
96
|
+
// them defensively.
|
|
97
|
+
const cleanUrl = String(url).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
98
|
+
// The anchor target comes from arbitrary model output (and, via prompt
|
|
99
|
+
// injection, untrusted data the model echoes). Don't rely on Telegram's
|
|
100
|
+
// server-side parser as the sole sanitizer: emit a clickable <a> only for
|
|
101
|
+
// an explicit allow-list of schemes (and scheme-relative URLs). Anything
|
|
102
|
+
// else — `javascript:`, `data:`, `file:`, `tg://` deep links — is left as
|
|
103
|
+
// the original `[text](url)` text (already HTML-escaped upstream) so it
|
|
104
|
+
// can't navigate the client.
|
|
105
|
+
if (!isAllowedUrl(cleanUrl))
|
|
106
|
+
return String(m);
|
|
107
|
+
return `<a href="${escapeAttr(cleanUrl)}">${String(text)}</a>`;
|
|
108
|
+
});
|
|
109
|
+
// Splice fenced + inline code back in.
|
|
110
|
+
working = working.replace(/ INLINE(\d+) /g, (_, i) => inlines[Number(i)] ?? '');
|
|
111
|
+
working = working.replace(/ FENCE(\d+) /g, (_, i) => fences[Number(i)] ?? '');
|
|
112
|
+
return working;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* GitHub / Obsidian-style callout types we recognise as the first line of a
|
|
116
|
+
* blockquote (`[!note]`, `[!warning]`, …). Each maps to a leading emoji, a
|
|
117
|
+
* default title, and whether the box collapses by default. `fold: true` types
|
|
118
|
+
* (details / example / faq) start COLLAPSED — they're meant for "extra info you
|
|
119
|
+
* can open if you want", which is exactly the detail-hiding the channel is for.
|
|
120
|
+
*/
|
|
121
|
+
const CALLOUTS = {
|
|
122
|
+
note: { emoji: 'ℹ️', label: 'Note', fold: false },
|
|
123
|
+
info: { emoji: 'ℹ️', label: 'Info', fold: false },
|
|
124
|
+
tip: { emoji: '💡', label: 'Tip', fold: false },
|
|
125
|
+
hint: { emoji: '💡', label: 'Hint', fold: false },
|
|
126
|
+
important: { emoji: '❗', label: 'Important', fold: false },
|
|
127
|
+
warning: { emoji: '⚠️', label: 'Warning', fold: false },
|
|
128
|
+
caution: { emoji: '⚠️', label: 'Caution', fold: false },
|
|
129
|
+
danger: { emoji: '🚨', label: 'Danger', fold: false },
|
|
130
|
+
error: { emoji: '🚨', label: 'Error', fold: false },
|
|
131
|
+
success: { emoji: '✅', label: 'Success', fold: false },
|
|
132
|
+
done: { emoji: '✅', label: 'Done', fold: false },
|
|
133
|
+
question: { emoji: '❓', label: 'Question', fold: false },
|
|
134
|
+
faq: { emoji: '❓', label: 'FAQ', fold: true },
|
|
135
|
+
quote: { emoji: '💬', label: 'Quote', fold: false },
|
|
136
|
+
details: { emoji: '📋', label: 'Details', fold: true },
|
|
137
|
+
example: { emoji: '📋', label: 'Example', fold: true },
|
|
138
|
+
};
|
|
139
|
+
/** A quote this big collapses into an expandable box even without a marker. */
|
|
140
|
+
const LONG_QUOTE_LINES = 4;
|
|
141
|
+
const LONG_QUOTE_CHARS = 280;
|
|
142
|
+
/**
|
|
143
|
+
* Render the (already HTML-escaped) inner text of a `>` blockquote into a
|
|
144
|
+
* Telegram `<blockquote>` / `<blockquote expandable>`.
|
|
145
|
+
*
|
|
146
|
+
* Three shapes, in order of precedence:
|
|
147
|
+
* 1. Recognised callout — first line is `[!type]`, optionally `+`/`-` then a
|
|
148
|
+
* title. Emits a bold `emoji Title` header line, then the body; collapses
|
|
149
|
+
* when the marker is `-` or the type folds by default.
|
|
150
|
+
* 2. Long plain quote — no marker but ≥4 lines / ≥280 chars → expandable so a
|
|
151
|
+
* wall of quoted text doesn't dominate the chat.
|
|
152
|
+
* 3. Short plain quote — a normal, always-open `<blockquote>`.
|
|
153
|
+
*
|
|
154
|
+
* The close tag is always `</blockquote>` (the `expandable` lives only on the
|
|
155
|
+
* open tag — Telegram rejects it on the close).
|
|
156
|
+
*/
|
|
157
|
+
function renderBlockquote(stripped) {
|
|
158
|
+
const callout = parseCallout(stripped);
|
|
159
|
+
let inner;
|
|
160
|
+
let expandable;
|
|
161
|
+
if (callout) {
|
|
162
|
+
inner = callout.body ? `${callout.header}\n${callout.body}` : callout.header;
|
|
163
|
+
expandable = callout.expandable;
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
inner = stripped;
|
|
167
|
+
expandable = isLongQuote(stripped);
|
|
168
|
+
}
|
|
169
|
+
const open = expandable ? '<blockquote expandable>' : '<blockquote>';
|
|
170
|
+
return `${open}${inner}</blockquote>`;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Parse a `[!type]`/`[!type]-`/`[!type]+ Title` first line. Returns null when
|
|
174
|
+
* the first line isn't a RECOGNISED callout, so an unknown `[!whatever]` is left
|
|
175
|
+
* as ordinary quote text rather than guessing a rendering for it.
|
|
176
|
+
*/
|
|
177
|
+
function parseCallout(stripped) {
|
|
178
|
+
const nl = stripped.indexOf('\n');
|
|
179
|
+
const firstLine = nl === -1 ? stripped : stripped.slice(0, nl);
|
|
180
|
+
const rest = nl === -1 ? '' : stripped.slice(nl + 1);
|
|
181
|
+
const m = /^\[!(\w+)\]([+-]?)[ \t]*(.*)$/.exec(firstLine.trim());
|
|
182
|
+
if (!m)
|
|
183
|
+
return null;
|
|
184
|
+
const meta = CALLOUTS[m[1].toLowerCase()];
|
|
185
|
+
if (!meta)
|
|
186
|
+
return null;
|
|
187
|
+
const fold = m[2];
|
|
188
|
+
const title = m[3].trim() || meta.label;
|
|
189
|
+
return {
|
|
190
|
+
header: `<b>${meta.emoji} ${title}</b>`,
|
|
191
|
+
body: rest,
|
|
192
|
+
expandable: fold === '-' ? true : fold === '+' ? false : meta.fold,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/** True when a plain quote is long enough to be worth collapsing. */
|
|
196
|
+
function isLongQuote(stripped) {
|
|
197
|
+
if (stripped.length >= LONG_QUOTE_CHARS)
|
|
198
|
+
return true;
|
|
199
|
+
let lines = 1;
|
|
200
|
+
for (let i = 0; i < stripped.length; i++)
|
|
201
|
+
if (stripped[i] === '\n')
|
|
202
|
+
lines++;
|
|
203
|
+
return lines >= LONG_QUOTE_LINES;
|
|
204
|
+
}
|
|
205
|
+
/** Schemes we let through as a clickable `<a href>`. */
|
|
206
|
+
const ALLOWED_URL_SCHEMES = new Set(['http', 'https', 'mailto', 'tel']);
|
|
207
|
+
/**
|
|
208
|
+
* True when `url` is safe to emit as an anchor target. A URL with an explicit
|
|
209
|
+
* `scheme:` prefix must use an allow-listed scheme; URLs without a scheme
|
|
210
|
+
* (relative paths, `#anchors`, `//host`, bare `host.com/...`) carry no
|
|
211
|
+
* navigation scheme and are allowed. This rejects `javascript:`, `data:`,
|
|
212
|
+
* `file:`, `tg://`, and any other unexpected scheme.
|
|
213
|
+
*/
|
|
214
|
+
function isAllowedUrl(url) {
|
|
215
|
+
// Control chars (incl. an embedded NUL/SOH) have no legitimate place in a URL
|
|
216
|
+
// and are a classic way to slip a dangerous scheme past a naive check — reject
|
|
217
|
+
// outright rather than try to normalize them away.
|
|
218
|
+
for (let i = 0; i < url.length; i++) {
|
|
219
|
+
if (url.charCodeAt(i) <= 0x1f || url.charCodeAt(i) === 0x7f)
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
// Strip leading whitespace/hyphen an attacker might use to shift the apparent
|
|
223
|
+
// scheme boundary, then detect the scheme.
|
|
224
|
+
const trimmed = url.replace(/^[\s-]+/, '');
|
|
225
|
+
// RFC3986 scheme: ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) ":".
|
|
226
|
+
const m = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(trimmed);
|
|
227
|
+
if (!m)
|
|
228
|
+
return true; // no explicit scheme — relative/anchor/host-only link
|
|
229
|
+
return ALLOWED_URL_SCHEMES.has(m[1].toLowerCase());
|
|
230
|
+
}
|
|
231
|
+
function escapeHtml(s) {
|
|
232
|
+
return s.replace(/[&<>]/g, (c) => (c === '&' ? '&' : c === '<' ? '<' : '>'));
|
|
233
|
+
}
|
|
234
|
+
function escapeAttr(s) {
|
|
235
|
+
return s.replace(/[&<>"]/g, (c) => c === '&' ? '&' : c === '<' ? '<' : c === '>' ? '>' : '"');
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Plugin } from '@moxxy/sdk';
|
|
2
|
+
import type { VaultStore } from '@moxxy/plugin-vault';
|
|
3
|
+
export { TelegramChannel, type TelegramChannelOptions, type TelegramStartOpts, } from './channel.js';
|
|
4
|
+
export { TelegramPermissionResolver, type PendingPermission } from './permission.js';
|
|
5
|
+
export { TelegramApprovalResolver, type PendingApproval } from './approval.js';
|
|
6
|
+
export { createPairingState, beginHostIssuedPairing, handleStart, submitChatCode, isAuthorized, clearPairing, type PairingPhase, type PairingState, type PairingDecision, } from './pairing.js';
|
|
7
|
+
export type { PairingConfirmResult } from './channel.js';
|
|
8
|
+
export { TurnRenderer, splitForTelegram } from './render.js';
|
|
9
|
+
export { markdownToTelegramHtml } from './format.js';
|
|
10
|
+
export interface BuildTelegramPluginOptions {
|
|
11
|
+
readonly vault: VaultStore;
|
|
12
|
+
}
|
|
13
|
+
export { TELEGRAM_TOKEN_KEY, TELEGRAM_AUTHORIZED_CHAT_KEY, TELEGRAM_TOKEN_RE } from './keys.js';
|
|
14
|
+
export declare function buildTelegramPlugin(opts: BuildTelegramPluginOptions): Plugin;
|
|
15
|
+
/**
|
|
16
|
+
* Discovery-loadable default export: resolves the vault from the inter-plugin
|
|
17
|
+
* service registry in `onInit` (the vault plugin publishes `'vault'`). Requires
|
|
18
|
+
* `@moxxy/plugin-vault` to load first (declared in `package.json`
|
|
19
|
+
* `moxxy.requirements`). The channel + tools read the vault via `getVault()`,
|
|
20
|
+
* so resolution is deferred to call time — after `onInit` has wired it.
|
|
21
|
+
*/
|
|
22
|
+
export declare const telegramPlugin: Plugin;
|
|
23
|
+
export default telegramPlugin;
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAC1G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAStD,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,0BAA0B,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,wBAAwB,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,WAAW,EACX,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,OAAO,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAMhG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,0BAA0B,GAAG,MAAM,CAG5E;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,EAAE,MAgBzB,CAAC;AAoRL,eAAe,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { defineChannel, defineTool, definePlugin, z } from '@moxxy/sdk';
|
|
2
|
+
import { Api, GrammyError } from 'grammy';
|
|
3
|
+
import { markdownToTelegramHtml } from './format.js';
|
|
4
|
+
import { stripHtml } from './channel/html.js';
|
|
5
|
+
import { TelegramChannel } from './channel.js';
|
|
6
|
+
import { TELEGRAM_AUTHORIZED_CHAT_KEY, TELEGRAM_TOKEN_KEY, parseChatId } from './keys.js';
|
|
7
|
+
import { runTelegramWizard } from './setup-wizard.js';
|
|
8
|
+
import { runPairFlow } from './pair-flow.js';
|
|
9
|
+
export { TelegramChannel, } from './channel.js';
|
|
10
|
+
export { TelegramPermissionResolver } from './permission.js';
|
|
11
|
+
export { TelegramApprovalResolver } from './approval.js';
|
|
12
|
+
export { createPairingState, beginHostIssuedPairing, handleStart, submitChatCode, isAuthorized, clearPairing, } from './pairing.js';
|
|
13
|
+
export { TurnRenderer, splitForTelegram } from './render.js';
|
|
14
|
+
export { markdownToTelegramHtml } from './format.js';
|
|
15
|
+
export { TELEGRAM_TOKEN_KEY, TELEGRAM_AUTHORIZED_CHAT_KEY, TELEGRAM_TOKEN_RE } from './keys.js';
|
|
16
|
+
// Backwards-compat aliases for the existing call sites in this file.
|
|
17
|
+
const TOKEN_KEY = TELEGRAM_TOKEN_KEY;
|
|
18
|
+
const AUTHORIZED_CHAT_KEY = TELEGRAM_AUTHORIZED_CHAT_KEY;
|
|
19
|
+
export function buildTelegramPlugin(opts) {
|
|
20
|
+
// Host-injected vault (available immediately).
|
|
21
|
+
return makeTelegramPlugin(() => opts.vault);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Discovery-loadable default export: resolves the vault from the inter-plugin
|
|
25
|
+
* service registry in `onInit` (the vault plugin publishes `'vault'`). Requires
|
|
26
|
+
* `@moxxy/plugin-vault` to load first (declared in `package.json`
|
|
27
|
+
* `moxxy.requirements`). The channel + tools read the vault via `getVault()`,
|
|
28
|
+
* so resolution is deferred to call time — after `onInit` has wired it.
|
|
29
|
+
*/
|
|
30
|
+
export const telegramPlugin = (() => {
|
|
31
|
+
let resolved = null;
|
|
32
|
+
const getVault = () => {
|
|
33
|
+
if (!resolved) {
|
|
34
|
+
throw new Error('@moxxy/plugin-telegram: the "vault" service is unavailable — @moxxy/plugin-vault must load first');
|
|
35
|
+
}
|
|
36
|
+
return resolved;
|
|
37
|
+
};
|
|
38
|
+
const hooks = {
|
|
39
|
+
onInit: (ctx) => {
|
|
40
|
+
resolved = ctx.services.require('vault');
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
return makeTelegramPlugin(getVault, hooks);
|
|
44
|
+
})();
|
|
45
|
+
function makeTelegramPlugin(getVault, hooks) {
|
|
46
|
+
return definePlugin({
|
|
47
|
+
name: '@moxxy/plugin-telegram',
|
|
48
|
+
version: '0.0.0',
|
|
49
|
+
...(hooks ? { hooks } : {}),
|
|
50
|
+
channels: [
|
|
51
|
+
defineChannel({
|
|
52
|
+
name: 'telegram',
|
|
53
|
+
description: 'Telegram bot channel via grammy. QR deep-link chat pairing.',
|
|
54
|
+
// Like Slack, run on a dedicated, isolated runner (separate socket +
|
|
55
|
+
// sticky session) so the bot keeps its own persistent history apart from
|
|
56
|
+
// the user's desktop/TUI work. Telegram long-polls (no tunnel needed).
|
|
57
|
+
dedicatedRunner: true,
|
|
58
|
+
sessionSource: 'telegram',
|
|
59
|
+
// Self-described config so a control surface (TUI `/channels`, `moxxy
|
|
60
|
+
// channels start`) can configure + run Telegram without a hardcoded table.
|
|
61
|
+
config: {
|
|
62
|
+
fields: [
|
|
63
|
+
{
|
|
64
|
+
name: 'token',
|
|
65
|
+
label: 'Bot token',
|
|
66
|
+
vaultKey: TELEGRAM_TOKEN_KEY,
|
|
67
|
+
required: true,
|
|
68
|
+
secret: true,
|
|
69
|
+
placeholder: '123456:ABC-DEF…',
|
|
70
|
+
help: 'Create a bot with @BotFather and paste its token',
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
hasRequestUrl: false,
|
|
74
|
+
runHint: 'Scan the QR (or open the link) and tap START in Telegram to pair your chat — no code to type.',
|
|
75
|
+
connect: {
|
|
76
|
+
kind: 'qr',
|
|
77
|
+
title: 'Connect your Telegram',
|
|
78
|
+
hint: 'Scan the QR with your phone (or tap Open in Telegram), then press START — your chat pairs automatically.',
|
|
79
|
+
openable: true,
|
|
80
|
+
openLabel: 'Open in Telegram',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
create: (deps) => new TelegramChannel({
|
|
84
|
+
vault: getVault(),
|
|
85
|
+
token: deps.options?.['token'] ?? undefined,
|
|
86
|
+
logger: deps.logger,
|
|
87
|
+
}),
|
|
88
|
+
isAvailable: async () => {
|
|
89
|
+
const envToken = process.env.MOXXY_TELEGRAM_TOKEN;
|
|
90
|
+
if (envToken)
|
|
91
|
+
return { ok: true };
|
|
92
|
+
try {
|
|
93
|
+
const stored = await getVault().has(TOKEN_KEY);
|
|
94
|
+
if (stored)
|
|
95
|
+
return { ok: true };
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
reason: "No bot token. Set MOXXY_TELEGRAM_TOKEN, or store one in the vault as '" +
|
|
99
|
+
TOKEN_KEY +
|
|
100
|
+
"' via the `telegram-setup` skill.",
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return {
|
|
105
|
+
ok: false,
|
|
106
|
+
reason: 'Set MOXXY_TELEGRAM_TOKEN to skip the vault, or unlock the vault first.',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
interactiveCommand: 'setup',
|
|
111
|
+
subcommands: {
|
|
112
|
+
setup: {
|
|
113
|
+
description: 'Interactive setup: store a bot token, pair a chat, then start the bot. Shown by default for `moxxy telegram` on a TTY.',
|
|
114
|
+
run: async (ctx) => {
|
|
115
|
+
// The wizard drives token entry + pairing through clack
|
|
116
|
+
// prompts, so it needs an interactive terminal. In a
|
|
117
|
+
// headless invocation we just start the bot directly.
|
|
118
|
+
if (process.stdin.isTTY !== true) {
|
|
119
|
+
return ctx.startChannel();
|
|
120
|
+
}
|
|
121
|
+
return runTelegramWizard(ctx);
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
pair: {
|
|
125
|
+
description: 'Open a pairing window and print a QR. Scan it (or open the link) and tap START in Telegram to pair your chat — the same mechanism the desktop uses.',
|
|
126
|
+
run: async (ctx) => {
|
|
127
|
+
// Pairing renders a QR for the user to scan, so it needs an
|
|
128
|
+
// interactive terminal. In a headless invocation we bail with a
|
|
129
|
+
// clear message instead of starting a bot nobody can pair. (The
|
|
130
|
+
// desktop Channels panel pairs the same way without a TTY — it
|
|
131
|
+
// renders the QR in the GUI.)
|
|
132
|
+
if (process.stdin.isTTY !== true) {
|
|
133
|
+
process.stderr.write('Pairing needs a TTY to show the QR. Run `moxxy channels telegram pair` on a workstation, or pair from the desktop Channels panel.\n');
|
|
134
|
+
return 1;
|
|
135
|
+
}
|
|
136
|
+
return runPairFlow(ctx);
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
unpair: {
|
|
140
|
+
description: 'Forget the currently authorized Telegram chat.',
|
|
141
|
+
run: async (ctx) => {
|
|
142
|
+
const vault = ctx.deps.vault;
|
|
143
|
+
if (!vault) {
|
|
144
|
+
process.stderr.write('vault unavailable\n');
|
|
145
|
+
return 1;
|
|
146
|
+
}
|
|
147
|
+
const removed = await vault.delete(AUTHORIZED_CHAT_KEY);
|
|
148
|
+
process.stdout.write(removed ? 'unpaired\n' : 'no pairing was active\n');
|
|
149
|
+
return 0;
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
status: {
|
|
153
|
+
description: 'Report whether a Telegram token + an authorized chat are configured.',
|
|
154
|
+
run: async (ctx) => {
|
|
155
|
+
const vault = ctx.deps.vault;
|
|
156
|
+
if (!vault) {
|
|
157
|
+
process.stderr.write('vault unavailable\n');
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
const hasToken = await vault.has(TOKEN_KEY);
|
|
161
|
+
const authorized = await vault.get(AUTHORIZED_CHAT_KEY);
|
|
162
|
+
process.stdout.write(JSON.stringify({
|
|
163
|
+
tokenConfigured: hasToken,
|
|
164
|
+
authorizedChatId: parseChatId(authorized),
|
|
165
|
+
}, null, 2) + '\n');
|
|
166
|
+
return 0;
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
}),
|
|
171
|
+
],
|
|
172
|
+
tools: [
|
|
173
|
+
defineTool({
|
|
174
|
+
name: 'telegram_set_token',
|
|
175
|
+
description: 'Store a Telegram bot token (from @BotFather) in the vault under telegram_bot_token. Validates the token shape but does not test connectivity.',
|
|
176
|
+
inputSchema: z.object({
|
|
177
|
+
token: z.string().regex(/^\d+:[A-Za-z0-9_-]{20,}$/, 'token must look like 1234567890:ABC...'),
|
|
178
|
+
}),
|
|
179
|
+
permission: { action: 'prompt' },
|
|
180
|
+
// Vault writes land in ~/.moxxy/vault.json (key material in
|
|
181
|
+
// ~/.moxxy/vault.key) — hence the vault.* glob.
|
|
182
|
+
isolation: {
|
|
183
|
+
capabilities: {
|
|
184
|
+
fs: { read: ['~/.moxxy/vault.*'], write: ['~/.moxxy/vault.*'] },
|
|
185
|
+
net: { mode: 'none' },
|
|
186
|
+
timeMs: 10_000,
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
handler: async ({ token }) => {
|
|
190
|
+
await getVault().set(TOKEN_KEY, token, ['telegram']);
|
|
191
|
+
return `stored Telegram token (${token.split(':')[0]}:…) in vault`;
|
|
192
|
+
},
|
|
193
|
+
}),
|
|
194
|
+
defineTool({
|
|
195
|
+
name: 'telegram_status',
|
|
196
|
+
description: 'Report whether a Telegram token + an authorized chat are configured.',
|
|
197
|
+
inputSchema: z.object({}),
|
|
198
|
+
isolation: {
|
|
199
|
+
capabilities: {
|
|
200
|
+
fs: { read: ['~/.moxxy/vault.*'] },
|
|
201
|
+
net: { mode: 'none' },
|
|
202
|
+
timeMs: 10_000,
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
handler: async () => {
|
|
206
|
+
const hasToken = await getVault().has(TOKEN_KEY);
|
|
207
|
+
const authorized = await getVault().get(AUTHORIZED_CHAT_KEY);
|
|
208
|
+
return {
|
|
209
|
+
tokenConfigured: hasToken,
|
|
210
|
+
authorizedChatId: parseChatId(authorized),
|
|
211
|
+
};
|
|
212
|
+
},
|
|
213
|
+
}),
|
|
214
|
+
defineTool({
|
|
215
|
+
name: 'telegram_send_message',
|
|
216
|
+
description: 'Push a one-off message to the currently authorized Telegram chat. Use this from a ' +
|
|
217
|
+
'scheduled prompt to deliver results without an interactive channel running. By ' +
|
|
218
|
+
'default the text is rendered with the same rich Markdown→Telegram formatting as ' +
|
|
219
|
+
'interactive replies (bold, code, `> [!type]` callouts, `||spoilers||`, etc.); pass ' +
|
|
220
|
+
'an explicit `parseMode` to send the raw text under that parse mode instead. Requires ' +
|
|
221
|
+
'a stored bot token + a paired chat (run `moxxy channels telegram pair` once).',
|
|
222
|
+
inputSchema: z.object({
|
|
223
|
+
text: z.string().min(1).max(4096),
|
|
224
|
+
/** Optional override; defaults to the vault-paired chat id. */
|
|
225
|
+
chatId: z.number().int().optional(),
|
|
226
|
+
/**
|
|
227
|
+
* Force a specific Telegram parse mode and send `text` verbatim under
|
|
228
|
+
* it. Omit to get the default Markdown→HTML rendering (recommended).
|
|
229
|
+
*/
|
|
230
|
+
parseMode: z.enum(['MarkdownV2', 'Markdown', 'HTML']).optional(),
|
|
231
|
+
}),
|
|
232
|
+
permission: { action: 'prompt' },
|
|
233
|
+
isolation: {
|
|
234
|
+
capabilities: {
|
|
235
|
+
fs: { read: ['~/.moxxy/vault.*'] },
|
|
236
|
+
net: { mode: 'allowlist', hosts: ['api.telegram.org'] },
|
|
237
|
+
env: ['MOXXY_TELEGRAM_TOKEN'],
|
|
238
|
+
timeMs: 60_000,
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
handler: async ({ text, chatId, parseMode }) => {
|
|
242
|
+
const token = process.env.MOXXY_TELEGRAM_TOKEN ?? (await getVault().get(TOKEN_KEY));
|
|
243
|
+
if (!token) {
|
|
244
|
+
throw new Error('no Telegram bot token configured (set MOXXY_TELEGRAM_TOKEN or run `moxxy init` to store one)');
|
|
245
|
+
}
|
|
246
|
+
const targetChat = chatId ?? parseChatId(await getVault().get(AUTHORIZED_CHAT_KEY));
|
|
247
|
+
if (!targetChat) {
|
|
248
|
+
throw new Error('no authorized chat — run `moxxy channels telegram pair` first or pass `chatId` explicitly');
|
|
249
|
+
}
|
|
250
|
+
// Use grammy's lightweight `Api` client directly rather than a full
|
|
251
|
+
// `Bot` (which builds a polling-capable instance + lazily resolves
|
|
252
|
+
// bot info). This is a one-off send — no long-polling — so the Bot
|
|
253
|
+
// wrapper was pure overhead per invocation.
|
|
254
|
+
const api = new Api(token);
|
|
255
|
+
if (parseMode) {
|
|
256
|
+
// Explicit mode → caller owns the markup; send text verbatim.
|
|
257
|
+
await api.sendMessage(targetChat, text, { parse_mode: parseMode });
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
// Default → render Markdown to Telegram HTML for the same rich look
|
|
261
|
+
// as interactive replies, falling back to plain text if the model's
|
|
262
|
+
// text produced an entity Telegram can't parse (rare).
|
|
263
|
+
const html = markdownToTelegramHtml(text);
|
|
264
|
+
try {
|
|
265
|
+
await api.sendMessage(targetChat, html, {
|
|
266
|
+
parse_mode: 'HTML',
|
|
267
|
+
link_preview_options: { is_disabled: true },
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
if (err instanceof GrammyError && /can't parse entities|Bad Request: can't parse/i.test(err.description ?? '')) {
|
|
272
|
+
await api.sendMessage(targetChat, stripHtml(html));
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
throw err;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return { delivered: true, chatId: targetChat, length: text.length };
|
|
280
|
+
},
|
|
281
|
+
}),
|
|
282
|
+
defineTool({
|
|
283
|
+
name: 'telegram_unpair',
|
|
284
|
+
description: 'Forget the currently authorized Telegram chat. The next /start will start a fresh pairing.',
|
|
285
|
+
inputSchema: z.object({}),
|
|
286
|
+
permission: { action: 'prompt' },
|
|
287
|
+
isolation: {
|
|
288
|
+
capabilities: {
|
|
289
|
+
fs: { read: ['~/.moxxy/vault.*'], write: ['~/.moxxy/vault.*'] },
|
|
290
|
+
net: { mode: 'none' },
|
|
291
|
+
timeMs: 10_000,
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
handler: async () => {
|
|
295
|
+
const removed = await getVault().delete(AUTHORIZED_CHAT_KEY);
|
|
296
|
+
return removed ? 'unpaired' : 'no pairing was active';
|
|
297
|
+
},
|
|
298
|
+
}),
|
|
299
|
+
],
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
// Discovery entry: `createPluginLoader` requires a default Plugin export.
|
|
303
|
+
export default telegramPlugin;
|
|
304
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/keys.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault keys + token validation shared by the channel, its subcommands, and the
|
|
3
|
+
* interactive setup wizard. Kept in their own module so the wizard / pair-flow
|
|
4
|
+
* helpers can import them without pulling in the plugin's full index.
|
|
5
|
+
*/
|
|
6
|
+
/** Vault key the plugin uses for the Bot API token. */
|
|
7
|
+
export declare const TELEGRAM_TOKEN_KEY = "telegram_bot_token";
|
|
8
|
+
/** Vault key the plugin uses for the paired chat id. */
|
|
9
|
+
export declare const TELEGRAM_AUTHORIZED_CHAT_KEY = "telegram_authorized_chat_id";
|
|
10
|
+
/**
|
|
11
|
+
* Vault key for the voice-replies preference. Single-paired-chat model, so a
|
|
12
|
+
* simple present-flag (`'1'` = on, absent = off) keyed like the other telegram
|
|
13
|
+
* keys, toggled from the paired chat via `/voice`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const TELEGRAM_VOICE_REPLIES_KEY = "telegram_voice_replies";
|
|
16
|
+
/** Regex validating a Telegram bot token (`<digits>:<22+ url-safe>`). */
|
|
17
|
+
export declare const TELEGRAM_TOKEN_RE: RegExp;
|
|
18
|
+
/** The narrow vault slice the voice-replies flag helpers use. */
|
|
19
|
+
interface VoiceFlagVault {
|
|
20
|
+
get(name: string): Promise<string | null>;
|
|
21
|
+
set(name: string, value: string): Promise<void>;
|
|
22
|
+
delete(name: string): Promise<boolean>;
|
|
23
|
+
}
|
|
24
|
+
/** Read the persisted voice-replies preference (`'1'` → on). */
|
|
25
|
+
export declare function loadVoiceReplies(vault: Pick<VoiceFlagVault, 'get'>): Promise<boolean>;
|
|
26
|
+
/** Persist the voice-replies preference: store `'1'` when on, remove it when off. */
|
|
27
|
+
export declare function saveVoiceReplies(vault: Pick<VoiceFlagVault, 'set' | 'delete'>, on: boolean): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Parse a stored chat-id (the vault keeps it as a string). Returns `null` for a
|
|
30
|
+
* missing OR corrupt value rather than letting `Number(x)` yield `NaN` — a
|
|
31
|
+
* silent NaN serializes to `null` in status output (masking the corruption) and
|
|
32
|
+
* would otherwise be passed to `api.sendMessage(NaN, …)` as a real target,
|
|
33
|
+
* producing an opaque Telegram 400 instead of a clear "not paired" signal.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseChatId(raw: string | null | undefined): number | null;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,uDAAuD;AACvD,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,wDAAwD;AACxD,eAAO,MAAM,4BAA4B,gCAAgC,CAAC;AAC1E;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AACnE,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,QAA6B,CAAC;AAE5D,iEAAiE;AACjE,UAAU,cAAc;IACtB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxC;AAED,gEAAgE;AAChE,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAE3F;AAED,qFAAqF;AACrF,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,QAAQ,CAAC,EAC7C,EAAE,EAAE,OAAO,GACV,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAIzE"}
|