From ac705ddbcd582840b197c8a72c3b7a1a1050c526 Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:29:04 +0800 Subject: [PATCH 01/12] Update wrangler.jsonc --- wrangler.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrangler.jsonc b/wrangler.jsonc index 14f7a05..e804ab6 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -1,6 +1,6 @@ { "$schema": "node_modules/wrangler/config-schema.json", - "name": "cloud-code", + "name": "io", "main": "./src/index.ts", "compatibility_date": "2026-01-01", "compatibility_flags": ["nodejs_compat"], From 702b6c641c17c1bb523a08d1e81fcac063935db2 Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Thu, 23 Jul 2026 15:06:05 +0200 Subject: [PATCH 02/12] Telegram --- src/index.ts | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/src/index.ts b/src/index.ts index 95a8d38..0ce8daa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,3 +40,105 @@ async function handleFetch(request: Request) { export default { fetch: handleFetch, } satisfies ExportedHandler + +/** + * https://github.com/cvzi/telegram-bot-cloudflare + */ + +const TOKEN = ENV_BOT_TOKEN // Get it from @BotFather https://core.telegram.org/bots#6-botfather +const WEBHOOK = '/endpoint' +const SECRET = ENV_BOT_SECRET // A-Z, a-z, 0-9, _ and - + +/** + * Wait for requests to the worker + */ +addEventListener('fetch', event => { + const url = new URL(event.request.url) + if (url.pathname === WEBHOOK) { + event.respondWith(handleWebhook(event)) + } else if (url.pathname === '/registerWebhook') { + event.respondWith(registerWebhook(event, url, WEBHOOK, SECRET)) + } else if (url.pathname === '/unRegisterWebhook') { + event.respondWith(unRegisterWebhook(event)) + } else { + event.respondWith(new Response('No handler for this request')) + } +}) + +/** + * Handle requests to WEBHOOK + * https://core.telegram.org/bots/api#update + */ +async function handleWebhook (event) { + // Check secret + if (event.request.headers.get('X-Telegram-Bot-Api-Secret-Token') !== SECRET) { + return new Response('Unauthorized', { status: 403 }) + } + + // Read request body synchronously + const update = await event.request.json() + // Deal with response asynchronously + event.waitUntil(onUpdate(update)) + + return new Response('Ok') +} + +/** + * Handle incoming Update + * https://core.telegram.org/bots/api#update + */ +async function onUpdate (update) { + if ('message' in update) { + await onMessage(update.message) + } +} + +/** + * Handle incoming Message + * https://core.telegram.org/bots/api#message + */ +function onMessage (message) { + return sendPlainText(message.chat.id, 'Echo:\n' + message.text) +} + +/** + * Send plain text message + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendPlainText (chatId, text) { + return (await fetch(apiUrl('sendMessage', { + chat_id: chatId, + text + }))).json() +} + +/** + * Set webhook to this worker's url + * https://core.telegram.org/bots/api#setwebhook + */ +async function registerWebhook (event, requestUrl, suffix, secret) { + // https://core.telegram.org/bots/api#setwebhook + const webhookUrl = `${requestUrl.protocol}//${requestUrl.hostname}${suffix}` + const r = await (await fetch(apiUrl('setWebhook', { url: webhookUrl, secret_token: secret }))).json() + return new Response('ok' in r && r.ok ? 'Ok' : JSON.stringify(r, null, 2)) +} + +/** + * Remove webhook + * https://core.telegram.org/bots/api#setwebhook + */ +async function unRegisterWebhook (event) { + const r = await (await fetch(apiUrl('setWebhook', { url: '' }))).json() + return new Response('ok' in r && r.ok ? 'Ok' : JSON.stringify(r, null, 2)) +} + +/** + * Return url to telegram api, optionally with parameters added + */ +function apiUrl (methodName, params = null) { + let query = '' + if (params) { + query = '?' + new URLSearchParams(params).toString() + } + return `https://api.telegram.org/bot${TOKEN}/${methodName}${query}` +} From 0b079ff9c078562da33062787750744e9f6064f0 Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Thu, 23 Jul 2026 16:21:29 +0200 Subject: [PATCH 03/12] Update index.ts --- src/index.ts | 180 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 161 insertions(+), 19 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0ce8daa..86ce674 100644 --- a/src/index.ts +++ b/src/index.ts @@ -85,31 +85,16 @@ async function handleWebhook (event) { /** * Handle incoming Update + * supports messages and callback queries (inline button presses) * https://core.telegram.org/bots/api#update */ async function onUpdate (update) { if ('message' in update) { await onMessage(update.message) } -} - -/** - * Handle incoming Message - * https://core.telegram.org/bots/api#message - */ -function onMessage (message) { - return sendPlainText(message.chat.id, 'Echo:\n' + message.text) -} - -/** - * Send plain text message - * https://core.telegram.org/bots/api#sendmessage - */ -async function sendPlainText (chatId, text) { - return (await fetch(apiUrl('sendMessage', { - chat_id: chatId, - text - }))).json() + if ('callback_query' in update) { + await onCallbackQuery(update.callback_query) + } } /** @@ -142,3 +127,160 @@ function apiUrl (methodName, params = null) { } return `https://api.telegram.org/bot${TOKEN}/${methodName}${query}` } + +/** + * Send plain text message + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendPlainText (chatId, text) { + return (await fetch(apiUrl('sendMessage', { + chat_id: chatId, + text + }))).json() +} + +/** + * Send text message formatted with MarkdownV2-style + * Keep in mind that any markdown characters _*[]()~`>#+-=|{}.! that + * are not part of your formatting must be escaped. Incorrectly escaped + * messages will not be sent. See escapeMarkdown() + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendMarkdownV2Text (chatId, text) { + return (await fetch(apiUrl('sendMessage', { + chat_id: chatId, + text, + parse_mode: 'MarkdownV2' + }))).json() +} + +/** + * Escape string for use in MarkdownV2-style text + * if `except` is provided, it should be a string of characters to not escape + * https://core.telegram.org/bots/api#markdownv2-style + */ +function escapeMarkdown (str, except = '') { + const all = '_*[]()~`>#+-=|{}.!\\'.split('').filter(c => !except.includes(c)) + const regExSpecial = '^$*+?.()|{}[]\\' + const regEx = new RegExp('[' + all.map(c => (regExSpecial.includes(c) ? '\\' + c : c)).join('') + ']', 'gim') + return str.replace(regEx, '\\$&') +} + +/** + * Send a message with a single button + * `button` must be an button-object like `{ text: 'Button', callback_data: 'data'}` + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendInlineButton (chatId, text, button) { + return sendInlineButtonRow(chatId, text, [button]) +} + +/** + * Send a message with buttons, `buttonRow` must be an array of button objects + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendInlineButtonRow (chatId, text, buttonRow) { + return sendInlineButtons(chatId, text, [buttonRow]) +} + +/** + * Send a message with buttons, `buttons` must be an array of arrays of button objects + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendInlineButtons (chatId, text, buttons) { + return (await fetch(apiUrl('sendMessage', { + chat_id: chatId, + reply_markup: JSON.stringify({ + inline_keyboard: buttons + }), + text + }))).json() +} + +/** + * Answer callback query (inline button press) + * This stops the loading indicator on the button and optionally shows a message + * https://core.telegram.org/bots/api#answercallbackquery + */ +async function answerCallbackQuery (callbackQueryId, text = null) { + const data = { + callback_query_id: callbackQueryId + } + if (text) { + data.text = text + } + return (await fetch(apiUrl('answerCallbackQuery', data))).json() +} + +/** + * Handle incoming callback_query (inline button press) + * https://core.telegram.org/bots/api#message + */ +async function onCallbackQuery (callbackQuery) { + await sendMarkdownV2Text(callbackQuery.message.chat.id, escapeMarkdown(`You pressed the button with data=\`${callbackQuery.data}\``, '`')) + return answerCallbackQuery(callbackQuery.id, 'Button press acknowledged!') +} + +/** + * Handle incoming Message + * https://core.telegram.org/bots/api#message + */ +function onMessage (message) { + if (message.text.startsWith('/start') || message.text.startsWith('/help')) { + return sendMarkdownV2Text(message.chat.id, '*Functions:*\n' + + escapeMarkdown( + '`/help` - This message\n' + + '/button2 - Sends a message with two button\n' + + '/button4 - Sends a message with four buttons\n' + + '/markdown - Sends some MarkdownV2 examples\n', + '`')) + } else if (message.text.startsWith('/button2')) { + return sendTwoButtons(message.chat.id) + } else if (message.text.startsWith('/button4')) { + return sendFourButtons(message.chat.id) + } else if (message.text.startsWith('/markdown')) { + return sendMarkdownExample(message.chat.id) + } else { + return sendMarkdownV2Text(message.chat.id, escapeMarkdown('*Unknown command:* `' + message.text + '`\n' + + 'Use /help to see available commands.', '*`')) + } +} + +function sendTwoButtons (chatId) { + return sendInlineButtonRow(chatId, 'Press one of the two button', [{ + text: 'Button One', + callback_data: 'data_1' + }, { + text: 'Button Two', + callback_data: 'data_2' + }]) +} + +function sendFourButtons (chatId) { + return sendInlineButtons(chatId, 'Press a button', [ + [ + { + text: 'Button top left', + callback_data: 'Utah' + }, { + text: 'Button top right', + callback_data: 'Colorado' + } + ], + [ + { + text: 'Button bottom left', + callback_data: 'Arizona' + }, { + text: 'Button bottom right', + callback_data: 'New Mexico' + } + ] + ]) +} + +async function sendMarkdownExample (chatId) { + await sendMarkdownV2Text(chatId, 'This is *bold* and this is _italic_') + await sendMarkdownV2Text(chatId, escapeMarkdown('You can write it like this: *bold* and _italic_')) + return sendMarkdownV2Text(chatId, escapeMarkdown('...but users may write ** and __ e.g. `**bold**` and `__italic__`', '`')) +} From b61acf69115615f5776c7e55e239cc35f251249c Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Sun, 26 Jul 2026 08:58:15 +0200 Subject: [PATCH 04/12] Create homepage.ts --- src/homepage.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/homepage.ts diff --git a/src/homepage.ts b/src/homepage.ts new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/homepage.ts @@ -0,0 +1 @@ + From 9e73100d31460f5c89eab99dec9528e3d039de52 Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Sun, 26 Jul 2026 08:58:46 +0200 Subject: [PATCH 05/12] Create telegram-boy --- src/telegram-boy | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/telegram-boy diff --git a/src/telegram-boy b/src/telegram-boy new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/telegram-boy @@ -0,0 +1 @@ + From 2d2d4fa7073e904c4dec280187cf795f8335d2f6 Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Sun, 26 Jul 2026 10:43:49 +0200 Subject: [PATCH 06/12] Update and rename homepage.ts to homepage.html --- src/homepage.html | 10 ++++++++++ src/homepage.ts | 1 - 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/homepage.html delete mode 100644 src/homepage.ts diff --git a/src/homepage.html b/src/homepage.html new file mode 100644 index 0000000..e6b49e5 --- /dev/null +++ b/src/homepage.html @@ -0,0 +1,10 @@ + + + + This is the title of the webpage! + + + +

welcome page

+ + diff --git a/src/homepage.ts b/src/homepage.ts deleted file mode 100644 index 8b13789..0000000 --- a/src/homepage.ts +++ /dev/null @@ -1 +0,0 @@ - From a06d8acf780e7518cc171cec8faa7fa64783ffcd Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Sun, 26 Jul 2026 23:13:51 +0200 Subject: [PATCH 07/12] Update and rename telegram-boy to telegram-boy.js --- src/telegram-boy | 1 - src/telegram-boy.js | 243 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+), 1 deletion(-) delete mode 100644 src/telegram-boy create mode 100644 src/telegram-boy.js diff --git a/src/telegram-boy b/src/telegram-boy deleted file mode 100644 index 8b13789..0000000 --- a/src/telegram-boy +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/telegram-boy.js b/src/telegram-boy.js new file mode 100644 index 0000000..63813eb --- /dev/null +++ b/src/telegram-boy.js @@ -0,0 +1,243 @@ +/** + * https://github.com/cvzi/telegram-bot-cloudflare + */ + +const TOKEN = ENV_BOT_TOKEN // Get it from @BotFather https://core.telegram.org/bots#6-botfather +const WEBHOOK = '/endpoint' +const SECRET = ENV_BOT_SECRET // A-Z, a-z, 0-9, _ and - + +/** + * Wait for requests to the worker + */ +addEventListener('fetch', event => { + const url = new URL(event.request.url) + if (url.pathname === WEBHOOK) { + event.respondWith(handleWebhook(event)) + } else if (url.pathname === '/registerWebhook') { + event.respondWith(registerWebhook(event, url, WEBHOOK, SECRET)) + } else if (url.pathname === '/unRegisterWebhook') { + event.respondWith(unRegisterWebhook(event)) + } else { + event.respondWith(new Response('No handler for this request')) + } +}) + +/** + * Handle requests to WEBHOOK + * https://core.telegram.org/bots/api#update + */ +async function handleWebhook (event) { + // Check secret + if (event.request.headers.get('X-Telegram-Bot-Api-Secret-Token') !== SECRET) { + return new Response('Unauthorized', { status: 403 }) + } + + // Read request body synchronously + const update = await event.request.json() + // Deal with response asynchronously + event.waitUntil(onUpdate(update)) + + return new Response('Ok') +} + +/** + * Handle incoming Update + * supports messages and callback queries (inline button presses) + * https://core.telegram.org/bots/api#update + */ +async function onUpdate (update) { + if ('message' in update) { + await onMessage(update.message) + } + if ('callback_query' in update) { + await onCallbackQuery(update.callback_query) + } +} + +/** + * Set webhook to this worker's url + * https://core.telegram.org/bots/api#setwebhook + */ +async function registerWebhook (event, requestUrl, suffix, secret) { + // https://core.telegram.org/bots/api#setwebhook + const webhookUrl = `${requestUrl.protocol}//${requestUrl.hostname}${suffix}` + const r = await (await fetch(apiUrl('setWebhook', { url: webhookUrl, secret_token: secret }))).json() + return new Response('ok' in r && r.ok ? 'Ok' : JSON.stringify(r, null, 2)) +} + +/** + * Remove webhook + * https://core.telegram.org/bots/api#setwebhook + */ +async function unRegisterWebhook (event) { + const r = await (await fetch(apiUrl('setWebhook', { url: '' }))).json() + return new Response('ok' in r && r.ok ? 'Ok' : JSON.stringify(r, null, 2)) +} + +/** + * Return url to telegram api, optionally with parameters added + */ +function apiUrl (methodName, params = null) { + let query = '' + if (params) { + query = '?' + new URLSearchParams(params).toString() + } + return `https://api.telegram.org/bot${TOKEN}/${methodName}${query}` +} + +/** + * Send plain text message + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendPlainText (chatId, text) { + return (await fetch(apiUrl('sendMessage', { + chat_id: chatId, + text + }))).json() +} + +/** + * Send text message formatted with MarkdownV2-style + * Keep in mind that any markdown characters _*[]()~`>#+-=|{}.! that + * are not part of your formatting must be escaped. Incorrectly escaped + * messages will not be sent. See escapeMarkdown() + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendMarkdownV2Text (chatId, text) { + return (await fetch(apiUrl('sendMessage', { + chat_id: chatId, + text, + parse_mode: 'MarkdownV2' + }))).json() +} + +/** + * Escape string for use in MarkdownV2-style text + * if `except` is provided, it should be a string of characters to not escape + * https://core.telegram.org/bots/api#markdownv2-style + */ +function escapeMarkdown (str, except = '') { + const all = '_*[]()~`>#+-=|{}.!\\'.split('').filter(c => !except.includes(c)) + const regExSpecial = '^$*+?.()|{}[]\\' + const regEx = new RegExp('[' + all.map(c => (regExSpecial.includes(c) ? '\\' + c : c)).join('') + ']', 'gim') + return str.replace(regEx, '\\$&') +} + +/** + * Send a message with a single button + * `button` must be an button-object like `{ text: 'Button', callback_data: 'data'}` + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendInlineButton (chatId, text, button) { + return sendInlineButtonRow(chatId, text, [button]) +} + +/** + * Send a message with buttons, `buttonRow` must be an array of button objects + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendInlineButtonRow (chatId, text, buttonRow) { + return sendInlineButtons(chatId, text, [buttonRow]) +} + +/** + * Send a message with buttons, `buttons` must be an array of arrays of button objects + * https://core.telegram.org/bots/api#sendmessage + */ +async function sendInlineButtons (chatId, text, buttons) { + return (await fetch(apiUrl('sendMessage', { + chat_id: chatId, + reply_markup: JSON.stringify({ + inline_keyboard: buttons + }), + text + }))).json() +} + +/** + * Answer callback query (inline button press) + * This stops the loading indicator on the button and optionally shows a message + * https://core.telegram.org/bots/api#answercallbackquery + */ +async function answerCallbackQuery (callbackQueryId, text = null) { + const data = { + callback_query_id: callbackQueryId + } + if (text) { + data.text = text + } + return (await fetch(apiUrl('answerCallbackQuery', data))).json() +} + +/** + * Handle incoming callback_query (inline button press) + * https://core.telegram.org/bots/api#message + */ +async function onCallbackQuery (callbackQuery) { + await sendMarkdownV2Text(callbackQuery.message.chat.id, escapeMarkdown(`You pressed the button with data=\`${callbackQuery.data}\``, '`')) + return answerCallbackQuery(callbackQuery.id, 'Button press acknowledged!') +} + +/** + * Handle incoming Message + * https://core.telegram.org/bots/api#message + */ +function onMessage (message) { + if (message.text.startsWith('/start') || message.text.startsWith('/help')) { + return sendMarkdownV2Text(message.chat.id, '*Functions:*\n' + + escapeMarkdown( + '`/help` - This message\n' + + '/button2 - Sends a message with two button\n' + + '/button4 - Sends a message with four buttons\n' + + '/markdown - Sends some MarkdownV2 examples\n', + '`')) + } else if (message.text.startsWith('/button2')) { + return sendTwoButtons(message.chat.id) + } else if (message.text.startsWith('/button4')) { + return sendFourButtons(message.chat.id) + } else if (message.text.startsWith('/markdown')) { + return sendMarkdownExample(message.chat.id) + } else { + return sendMarkdownV2Text(message.chat.id, escapeMarkdown('*Unknown command:* `' + message.text + '`\n' + + 'Use /help to see available commands.', '*`')) + } +} + +function sendTwoButtons (chatId) { + return sendInlineButtonRow(chatId, 'Press one of the two button', [{ + text: 'Button One', + callback_data: 'data_1' + }, { + text: 'Button Two', + callback_data: 'data_2' + }]) +} + +function sendFourButtons (chatId) { + return sendInlineButtons(chatId, 'Press a button', [ + [ + { + text: 'Button top left', + callback_data: 'Utah' + }, { + text: 'Button top right', + callback_data: 'Colorado' + } + ], + [ + { + text: 'Button bottom left', + callback_data: 'Arizona' + }, { + text: 'Button bottom right', + callback_data: 'New Mexico' + } + ] + ]) +} + +async function sendMarkdownExample (chatId) { + await sendMarkdownV2Text(chatId, 'This is *bold* and this is _italic_') + await sendMarkdownV2Text(chatId, escapeMarkdown('You can write it like this: *bold* and _italic_')) + return sendMarkdownV2Text(chatId, escapeMarkdown('...but users may write ** and __ e.g. `**bold**` and `__italic__`', '`')) +} From 68cb1ba3b6d1aed48c92131160d3e14e2b1c0596 Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Sun, 26 Jul 2026 23:17:01 +0200 Subject: [PATCH 08/12] Update index.ts --- src/index.ts | 244 --------------------------------------------------- 1 file changed, 244 deletions(-) diff --git a/src/index.ts b/src/index.ts index 86ce674..95a8d38 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,247 +40,3 @@ async function handleFetch(request: Request) { export default { fetch: handleFetch, } satisfies ExportedHandler - -/** - * https://github.com/cvzi/telegram-bot-cloudflare - */ - -const TOKEN = ENV_BOT_TOKEN // Get it from @BotFather https://core.telegram.org/bots#6-botfather -const WEBHOOK = '/endpoint' -const SECRET = ENV_BOT_SECRET // A-Z, a-z, 0-9, _ and - - -/** - * Wait for requests to the worker - */ -addEventListener('fetch', event => { - const url = new URL(event.request.url) - if (url.pathname === WEBHOOK) { - event.respondWith(handleWebhook(event)) - } else if (url.pathname === '/registerWebhook') { - event.respondWith(registerWebhook(event, url, WEBHOOK, SECRET)) - } else if (url.pathname === '/unRegisterWebhook') { - event.respondWith(unRegisterWebhook(event)) - } else { - event.respondWith(new Response('No handler for this request')) - } -}) - -/** - * Handle requests to WEBHOOK - * https://core.telegram.org/bots/api#update - */ -async function handleWebhook (event) { - // Check secret - if (event.request.headers.get('X-Telegram-Bot-Api-Secret-Token') !== SECRET) { - return new Response('Unauthorized', { status: 403 }) - } - - // Read request body synchronously - const update = await event.request.json() - // Deal with response asynchronously - event.waitUntil(onUpdate(update)) - - return new Response('Ok') -} - -/** - * Handle incoming Update - * supports messages and callback queries (inline button presses) - * https://core.telegram.org/bots/api#update - */ -async function onUpdate (update) { - if ('message' in update) { - await onMessage(update.message) - } - if ('callback_query' in update) { - await onCallbackQuery(update.callback_query) - } -} - -/** - * Set webhook to this worker's url - * https://core.telegram.org/bots/api#setwebhook - */ -async function registerWebhook (event, requestUrl, suffix, secret) { - // https://core.telegram.org/bots/api#setwebhook - const webhookUrl = `${requestUrl.protocol}//${requestUrl.hostname}${suffix}` - const r = await (await fetch(apiUrl('setWebhook', { url: webhookUrl, secret_token: secret }))).json() - return new Response('ok' in r && r.ok ? 'Ok' : JSON.stringify(r, null, 2)) -} - -/** - * Remove webhook - * https://core.telegram.org/bots/api#setwebhook - */ -async function unRegisterWebhook (event) { - const r = await (await fetch(apiUrl('setWebhook', { url: '' }))).json() - return new Response('ok' in r && r.ok ? 'Ok' : JSON.stringify(r, null, 2)) -} - -/** - * Return url to telegram api, optionally with parameters added - */ -function apiUrl (methodName, params = null) { - let query = '' - if (params) { - query = '?' + new URLSearchParams(params).toString() - } - return `https://api.telegram.org/bot${TOKEN}/${methodName}${query}` -} - -/** - * Send plain text message - * https://core.telegram.org/bots/api#sendmessage - */ -async function sendPlainText (chatId, text) { - return (await fetch(apiUrl('sendMessage', { - chat_id: chatId, - text - }))).json() -} - -/** - * Send text message formatted with MarkdownV2-style - * Keep in mind that any markdown characters _*[]()~`>#+-=|{}.! that - * are not part of your formatting must be escaped. Incorrectly escaped - * messages will not be sent. See escapeMarkdown() - * https://core.telegram.org/bots/api#sendmessage - */ -async function sendMarkdownV2Text (chatId, text) { - return (await fetch(apiUrl('sendMessage', { - chat_id: chatId, - text, - parse_mode: 'MarkdownV2' - }))).json() -} - -/** - * Escape string for use in MarkdownV2-style text - * if `except` is provided, it should be a string of characters to not escape - * https://core.telegram.org/bots/api#markdownv2-style - */ -function escapeMarkdown (str, except = '') { - const all = '_*[]()~`>#+-=|{}.!\\'.split('').filter(c => !except.includes(c)) - const regExSpecial = '^$*+?.()|{}[]\\' - const regEx = new RegExp('[' + all.map(c => (regExSpecial.includes(c) ? '\\' + c : c)).join('') + ']', 'gim') - return str.replace(regEx, '\\$&') -} - -/** - * Send a message with a single button - * `button` must be an button-object like `{ text: 'Button', callback_data: 'data'}` - * https://core.telegram.org/bots/api#sendmessage - */ -async function sendInlineButton (chatId, text, button) { - return sendInlineButtonRow(chatId, text, [button]) -} - -/** - * Send a message with buttons, `buttonRow` must be an array of button objects - * https://core.telegram.org/bots/api#sendmessage - */ -async function sendInlineButtonRow (chatId, text, buttonRow) { - return sendInlineButtons(chatId, text, [buttonRow]) -} - -/** - * Send a message with buttons, `buttons` must be an array of arrays of button objects - * https://core.telegram.org/bots/api#sendmessage - */ -async function sendInlineButtons (chatId, text, buttons) { - return (await fetch(apiUrl('sendMessage', { - chat_id: chatId, - reply_markup: JSON.stringify({ - inline_keyboard: buttons - }), - text - }))).json() -} - -/** - * Answer callback query (inline button press) - * This stops the loading indicator on the button and optionally shows a message - * https://core.telegram.org/bots/api#answercallbackquery - */ -async function answerCallbackQuery (callbackQueryId, text = null) { - const data = { - callback_query_id: callbackQueryId - } - if (text) { - data.text = text - } - return (await fetch(apiUrl('answerCallbackQuery', data))).json() -} - -/** - * Handle incoming callback_query (inline button press) - * https://core.telegram.org/bots/api#message - */ -async function onCallbackQuery (callbackQuery) { - await sendMarkdownV2Text(callbackQuery.message.chat.id, escapeMarkdown(`You pressed the button with data=\`${callbackQuery.data}\``, '`')) - return answerCallbackQuery(callbackQuery.id, 'Button press acknowledged!') -} - -/** - * Handle incoming Message - * https://core.telegram.org/bots/api#message - */ -function onMessage (message) { - if (message.text.startsWith('/start') || message.text.startsWith('/help')) { - return sendMarkdownV2Text(message.chat.id, '*Functions:*\n' + - escapeMarkdown( - '`/help` - This message\n' + - '/button2 - Sends a message with two button\n' + - '/button4 - Sends a message with four buttons\n' + - '/markdown - Sends some MarkdownV2 examples\n', - '`')) - } else if (message.text.startsWith('/button2')) { - return sendTwoButtons(message.chat.id) - } else if (message.text.startsWith('/button4')) { - return sendFourButtons(message.chat.id) - } else if (message.text.startsWith('/markdown')) { - return sendMarkdownExample(message.chat.id) - } else { - return sendMarkdownV2Text(message.chat.id, escapeMarkdown('*Unknown command:* `' + message.text + '`\n' + - 'Use /help to see available commands.', '*`')) - } -} - -function sendTwoButtons (chatId) { - return sendInlineButtonRow(chatId, 'Press one of the two button', [{ - text: 'Button One', - callback_data: 'data_1' - }, { - text: 'Button Two', - callback_data: 'data_2' - }]) -} - -function sendFourButtons (chatId) { - return sendInlineButtons(chatId, 'Press a button', [ - [ - { - text: 'Button top left', - callback_data: 'Utah' - }, { - text: 'Button top right', - callback_data: 'Colorado' - } - ], - [ - { - text: 'Button bottom left', - callback_data: 'Arizona' - }, { - text: 'Button bottom right', - callback_data: 'New Mexico' - } - ] - ]) -} - -async function sendMarkdownExample (chatId) { - await sendMarkdownV2Text(chatId, 'This is *bold* and this is _italic_') - await sendMarkdownV2Text(chatId, escapeMarkdown('You can write it like this: *bold* and _italic_')) - return sendMarkdownV2Text(chatId, escapeMarkdown('...but users may write ** and __ e.g. `**bold**` and `__italic__`', '`')) -} From 31a6ec86616f2eeda541867447d5fbb22b54df07 Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Mon, 27 Jul 2026 09:12:57 +0200 Subject: [PATCH 09/12] Update index.ts --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index 95a8d38..01ad523 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,3 +40,4 @@ async function handleFetch(request: Request) { export default { fetch: handleFetch, } satisfies ExportedHandler +} From 79e6d2f3976e8a73e38d4ffb28d5dda16315454e Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Mon, 27 Jul 2026 14:32:40 +0200 Subject: [PATCH 10/12] Update index.ts --- src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 01ad523..95a8d38 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,4 +40,3 @@ async function handleFetch(request: Request) { export default { fetch: handleFetch, } satisfies ExportedHandler -} From acae8a4818f738055075ff0b132e2058791fe267 Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Mon, 27 Jul 2026 14:41:08 +0200 Subject: [PATCH 11/12] Update wrangler.jsonc --- wrangler.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrangler.jsonc b/wrangler.jsonc index e804ab6..bce18f8 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -1,6 +1,6 @@ { "$schema": "node_modules/wrangler/config-schema.json", - "name": "io", + "name": "ia", "main": "./src/index.ts", "compatibility_date": "2026-01-01", "compatibility_flags": ["nodejs_compat"], From d23d4cff4eb939d587a8c80b8f27cb5234f726f6 Mon Sep 17 00:00:00 2001 From: th333boo <55201915+th333boo@users.noreply.github.com> Date: Mon, 27 Jul 2026 15:25:01 +0200 Subject: [PATCH 12/12] Update wrangler.jsonc --- wrangler.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrangler.jsonc b/wrangler.jsonc index bce18f8..e804ab6 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -1,6 +1,6 @@ { "$schema": "node_modules/wrangler/config-schema.json", - "name": "ia", + "name": "io", "main": "./src/index.ts", "compatibility_date": "2026-01-01", "compatibility_flags": ["nodejs_compat"],