├── .gitignore ├── package.json ├── examples ├── payload.js ├── version.js ├── ping.js ├── keyboard_inline.js └── bot.js ├── core ├── appsscript.json ├── 80 userdb.js ├── 20 event.js ├── 90 main.js ├── 00 version.js ├── 50 client.js ├── 70 fetch.js ├── 40 composer.js ├── 10 helper.js ├── 15 markup.js ├── 30 context.js └── 60 telegram.js ├── docs ├── bapia.md └── lumpia.md ├── deploy.md └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | .test 2 | .clasp* 3 | bak/ 4 | draft/ -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gaslibv3", 3 | "version": "3.6.0", 4 | "description": "GAS Lib v3 - lumpia", 5 | "main": "none.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "bangHasan", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /examples/payload.js: -------------------------------------------------------------------------------- 1 | const bot = new lumpia.init(token, { log_id: 12345 }); 2 | 3 | function doPost(e) { 4 | bot.doPost(e); 5 | } 6 | 7 | bot.start(ctx => { 8 | let message = "Bot telah di-start!"; 9 | if (ctx.payload) message += '\nDengan payload: ' + ctx.payload; 10 | ctx.reply(message); 11 | }) -------------------------------------------------------------------------------- /core/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "Asia/Jakarta", 3 | "dependencies": { 4 | }, 5 | "webapp": { 6 | "access": "ANYONE_ANONYMOUS", 7 | "executeAs": "USER_DEPLOYING" 8 | }, 9 | "exceptionLogging": "STACKDRIVER", 10 | "executionApi": { 11 | "access": "ANYONE" 12 | }, 13 | "runtimeVersion": "V8" 14 | } -------------------------------------------------------------------------------- /examples/version.js: -------------------------------------------------------------------------------- 1 | const bot = new lumpia.init(token, { log_id: 12345 }); 2 | 3 | function doPost(e) { 4 | bot.doPost(e); 5 | } 6 | 7 | bot.command(['ver', 'versi', 'version'], ctx => { 8 | let message; 9 | message = `🛠 Dibangun menggunakan GASLibv3\n\n🍦 ${lumpia.version.full}-${lumpia.version.name}`; 10 | message += `\n🔖 Github | 👥 @botindonesia`; 11 | 12 | return ctx.replyWithHTML(message, { disable_web_page_preview: true }) 13 | }); -------------------------------------------------------------------------------- /examples/ping.js: -------------------------------------------------------------------------------- 1 | const bot = new lumpia.init(token, { log_id: 12345 }); 2 | 3 | function doPost(e) { 4 | bot.doPost(e); 5 | } 6 | 7 | bot.cmd('ping', (ctx, next) => { 8 | let time_start = Date.now(); 9 | let res = ctx.replyIt('..pong!'); 10 | let time_stop = Date.now(); 11 | 12 | let time_delta = (time_stop - time_start) / 1000; // mili detik 13 | let time = new Intl.NumberFormat('id').format(time_delta); // jadiin detik, sekaligus di format 14 | 15 | let msg_id = res.result.message_id; 16 | 17 | bot.telegram.editMessageText(ctx.chat.id, msg_id, null, `Pong! Proses ${time} detik.`, { parse_mode: 'html' }); 18 | }) -------------------------------------------------------------------------------- /docs/bapia.md: -------------------------------------------------------------------------------- 1 | ## Histori 2 | 3 | 4 | ## b.14 5 | 6 | Banyak sekali, doc nya belum yak :-D 7 | Perubahan utama ada di file `context.js` dan `telegram.js` 8 | 9 | ### b.13 10 | 11 | Bot API 5.5 12 | 13 | - banChatSenderChat 14 | - unbanChatSenderChat 15 | 16 | ### b.12 17 | 18 | Bot API 5.4 19 | 20 | Add methods : 21 | 22 | - approveChatJoinRequest 23 | - declineChatJoinRequest 24 | 25 | ### b.11 26 | 27 | - add options: `username` 28 | - helper: `button.queryChat` 29 | 30 | ### b.7 31 | 32 | - replyIt WithHTML, WithVoice, WithAudio, WithDocument, ... 33 | 34 | ### b.6 35 | 36 | - Shorthand untuk `bot.tg` 37 | 38 | ### b.5 39 | - Ganti prototype ke class 40 | - publikasi class EventEmitter 41 | -------------------------------------------------------------------------------- /deploy.md: -------------------------------------------------------------------------------- 1 | ## Urutan Deploy 2 | 3 | ### 1. Version 4 | 5 | - Ganti `const active` 6 | - Ganti nomor versinya, `lumpia` dan `bapia` 7 | 8 | ### 2. Config 9 | 10 | Pada `.clasp.json` jangan sampai ketukar 11 | 12 | - Sesuikan `scriptId` lumpia / bapia 13 | 14 | ### 3. Docs 15 | 16 | Pada folder `/docs` 17 | 18 | - Sesuaikan dokumentasi bapia / lumpia 19 | 20 | ### 4. Readme 21 | 22 | sesuikan versi nya 23 | 24 | ### 5. Clasp 25 | 26 | - Cek: `clasp versions` 27 | - Push: `clasp push` 28 | - Release: `clasp version 'komentar'` 29 | 30 | ### Dev / Main 31 | 32 | Setelah selesai, jangan lupa pindah ke posisi branch `dev` 33 | 34 | git checkout dev 35 | 36 | ### Release 37 | 38 | pada github, buat release dan history log -------------------------------------------------------------------------------- /core/80 userdb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple Class handling user properties sebagai userDB 3 | * 4 | * Hasanudin H. Syafaat 5 | * TG @hasanudinhs 6 | * Email banghasan@orang.paling.cakep.seantero.web.id 7 | * 8 | * Support hanya di grup Telegram @botIndonesia 9 | * 10 | */ 11 | var userDB = class UserDB { 12 | /** 13 | *initialize constructor 14 | */ 15 | constructor() { 16 | this.service = PropertiesService.getUserProperties(); 17 | } 18 | 19 | setValue(kunci, nilai) { 20 | // contoh: setValue('token', '123:xxxx'); 21 | return this.service.setProperty(kunci, nilai); 22 | } 23 | 24 | setValues(data) { 25 | // contoh {nickname: 'Bob', region: 'US', language: 'EN'}; 26 | return this.service.setProperties(data); 27 | } 28 | 29 | getValue(kunci) { 30 | // contoh: getValue('token'); 31 | return this.service.getProperty(kunci); 32 | } 33 | 34 | getValues() { 35 | return this.service.getProperties(); 36 | } 37 | 38 | getKeys() { 39 | return this.service.getKeys(); 40 | } 41 | 42 | delete(kunci) { 43 | return this.service.deleteProperty(kunci); 44 | } 45 | 46 | deleteAll() { 47 | return this.service.deleteAllProperties(); 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /examples/keyboard_inline.js: -------------------------------------------------------------------------------- 1 | const bot = new lumpia.init(token, { log_id: 12345 }); 2 | 3 | function doPost(e) { 4 | bot.doPost(e); 5 | } 6 | 7 | const button = lumpia.button, 8 | markup = lumpia.markup, 9 | helper = lumpia.helper; 10 | 11 | // handle pesan POST 12 | function doPost(e) { 13 | bot.doPost(e); 14 | } 15 | 16 | bot.start(ctx => { 17 | // susun tombol keyboardnya, 1 dimensi array saja oke 18 | let keyboard = [ 19 | button.url('📚 Materi Bot', 'http://gg.gg/gasbot'), 20 | button.url('👥 @botindonesia', 'https://t.me/botindonesia'), 21 | button.text('😼 Halo Human', 'me_click') 22 | ]; 23 | 24 | // susun inline keyboardnya pakai markup, dengan jumlah kolom 2 jajar 25 | let inlineKeyboard = new markup().inlineKeyboard(keyboard, { columns: 2 }); 26 | 27 | // reply dengan HTML 28 | ctx.replyWithHTML(`🙋🏻‍♀️ Hai, ${helper.nama(ctx.from).html} perkenalkan aku ini bot.\n\n🛠 Dibuat dengan ${lumpia.version.name} ${lumpia.version.full}`, 29 | { reply_markup: inlineKeyboard }); 30 | }) 31 | 32 | 33 | // handle jawaban ketika button di klik 34 | bot.action('me_click', (ctx) => { 35 | ctx.answerCallbackQuery('✊🏼 Tetap semangat dan terus berkarya!'); 36 | }) -------------------------------------------------------------------------------- /docs/lumpia.md: -------------------------------------------------------------------------------- 1 | ## Versi 2 | 3 | ## v3.11 4 | 5 | Banyak sekali, doc nya belum yak :-D 6 | Perubahan utama ada di file `context.js` dan `telegram.js` 7 | 8 | ## v3.10 9 | 10 | - Context Method: 11 | - chatJoinRequest (`ctx.chatJoinRequest`) 12 | - approveChatJoinRequest() 13 | - declineChatJoinRequest() 14 | - banChatSenderChat() 15 | - unbanChatSenderChat() 16 | - banChatMember() 17 | - Telegram Class: banChatMember 18 | - Helper: Markup `formatHTML` handling spoiler 19 | - Deprecate `kickChatMember` in favour of `banChatMember` 20 | 21 | ## v3.9 22 | 23 | Bot API 5.5 24 | 25 | - banChatSenderChat 26 | - unbanChatSenderChat 27 | 28 | Ref: [https://core.telegram.org/bots/api#december-7-2021](https://core.telegram.org/bots/api#december-7-2021) 29 | 30 | ## v3.8 31 | 32 | **Bot API 5.4** 33 | 34 | Add methods : 35 | 36 | - approveChatJoinRequest 37 | - declineChatJoinRequest 38 | 39 | 40 | ## v3.7 41 | 42 | - add options: `username` 43 | - helper: `button.queryChat` 44 | 45 | ## v3.6 46 | 47 | - replyIt WithHTML, WithVoice, WithAudio, WithDocument, ... 48 | 49 | ## v3.5 50 | 51 | - change: _prototype_ helper and button to _class_ 52 | - publikasi class EventEmitter 53 | - shorthand `bot.tg` for `bot.telegram` 54 | - fix version number 55 | 56 | ### v3.1 57 | 58 | First public release 59 | on `10 Agustus 2021` / `1 Muharam 1443 H` 60 | 61 | - [x] Checkpoint 62 | - **Lumpia** - Stable v1.0 63 | - **Bapia** - Beta v4.0 64 | -------------------------------------------------------------------------------- /core/20 event.js: -------------------------------------------------------------------------------- 1 | /* 2 | Event Emitter for GASLibv3 3 | Simple source, simple to learn 4 | and simple to use :-) 5 | 6 | Hasanudin H Syafaat 7 | 7 Agustus 2021 8 | @botindonesia 9 | */ 10 | 11 | class EventEmitter { 12 | constructor() { 13 | this.observers = {}; 14 | } 15 | 16 | on(events, ...listeners) { 17 | return listeners.forEach(listener => this.addListener(events, listener)); 18 | } 19 | 20 | once(event, listener) { 21 | const onceEvent = (...args) => { 22 | listener(...args); 23 | this.off(event, onceEvent); 24 | } 25 | return this.addListener(event, onceEvent); 26 | } 27 | 28 | addListener(events, listener) { 29 | if (!Array.isArray(events)) events = [events]; 30 | events.forEach(event => { 31 | this.observers[event] = this.observers[event] || []; 32 | this.observers[event].push(listener); 33 | }); 34 | 35 | return this; 36 | } 37 | 38 | listenerCount(event) { 39 | if (!this.observers[event]) return 0; 40 | return this.observers[event].length; 41 | } 42 | 43 | off(event, listener) { 44 | if (!this.observers[event]) return; 45 | if (!listener) { 46 | delete this.observers[event]; 47 | return; 48 | } 49 | 50 | this.observers[event] = this.observers[event].filter(l => l !== listener); 51 | } 52 | 53 | emit(events, ...args) { 54 | if (!Array.isArray(events)) events = [events]; 55 | events.forEach(event => { 56 | if (this.observers[event]) { 57 | const cloned = [].concat(this.observers[event]); 58 | cloned.forEach(observer => { 59 | observer(...args); 60 | }); 61 | } 62 | }); 63 | 64 | if (this.observers['*']) { 65 | const cloned = [].concat(this.observers['*']); 66 | cloned.forEach(observer => { 67 | observer.apply(observer, [[...events], ...args]); 68 | }); 69 | } 70 | } 71 | } 72 | 73 | var Event = EventEmitter; -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## GAS Lib v3 2 | 3 | Google Apps Script Library for Telegram, 3rd edition. 4 | 5 | ![version](https://img.shields.io/badge/version-3.10-important) ![netifly](https://img.shields.io/netlify/76bd2cdb-6128-489b-9172-73f2aca1f978) ![GitHub last commit](https://img.shields.io/github/last-commit/telegrambotindonesia/GAS-Lib-v3) ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/telegrambotindonesia/GAS-Lib-v3) ![Lines of code](https://img.shields.io/tokei/lines/github/telegrambotindonesia/GAS-Lib-v3) ![GitHub issues](https://img.shields.io/github/issues/telegrambotindonesia/GAS-Lib-v3) ![GAS](https://img.shields.io/badge/google-apps%20script-blue) ![lang count](https://img.shields.io/github/languages/count/telegrambotindonesia/GAS-Lib-v3) ![javascript](https://img.shields.io/badge/lang-javascript-yellow) ![GitHub Discussions](https://img.shields.io/github/discussions/telegrambotindonesia/GAS-Lib-v3?color=red&label=comments) ![telegram botindonesia](https://img.shields.io/badge/telegram-@botindonesia-blue) ![GitHub contributors](https://img.shields.io/github/contributors/telegrambotindonesia/GAS-Lib-v3) ![visit](https://badges.pufler.dev/visits/telegrambotindonesia/GAS-Lib-v3) [![clasp](https://img.shields.io/badge/built%20with-clasp-4285f4.svg)](https://github.com/google/clasp) 6 | 7 | 8 | ## ID Library 9 | 10 | Frist Release : `10 Agustus 2021` / `1 Muharam 1443 H` 11 | 12 | ### lumpia 13 | 14 | This is stable release 15 | 16 | - Legacy: `MUD_wfLskZT2D99lRXLh94vvg_do21SJR` 17 | - New: `1Yo6vQRwjG5Gl9jeEF0g2tBTUa0XN5MyT4G_HeDpRr9DvabxhRcSdhPNj` 18 | 19 | 20 | ## Quick Start 21 | 22 | ```javascript 23 | const bot = new lumpia.init(tokenbot); 24 | 25 | function doPost(e) { 26 | bot.doPost(e); 27 | } 28 | 29 | bot.start(ctx => ctx.reply('Lets Go')); 30 | 31 | bot.cmd('ping', ctx => ctx.replyIt('Pong!')); 32 | 33 | bot.hears(/hello/i, ctx => ctx.reply('Hello too!')); 34 | 35 | bot.hears(/^\/say (.*)/i, ctx => ctx.replyIt(ctx.match[1])); 36 | ``` 37 | 38 | ## Docs 39 | 40 | - [lumpia.js.org](https://lumpia.js.org) 41 | 42 | ## Community 43 | 44 | - Telegram Group [@botIndonesia](https://t,.me/botindonesia) -------------------------------------------------------------------------------- /core/90 main.js: -------------------------------------------------------------------------------- 1 | /* 2 | kelas utama gas lib v3 3 | matoa / bapia / lumpia 4 | 5 | penjelasan detail cek docs lumpia.js.org 6 | */ 7 | 8 | class Main extends Composer { 9 | constructor(token, options = {}) { 10 | super(); 11 | this.ctx = false; 12 | this.options = { 13 | prefix_command: '/', 14 | username: '', 15 | ...options 16 | } 17 | this.telegram = new Telegram(token); 18 | } 19 | 20 | get token() { 21 | return this.telegram.token; 22 | } 23 | 24 | get tg() { 25 | return this.telegram; 26 | } 27 | 28 | set log_id(id) { 29 | this.options.log_id = id; 30 | } 31 | 32 | handleUpdate(update) { 33 | // handle update tidak dibuatkan handle error 34 | // jika ingin direct handleUpdate, gunakan try catch sendiri 35 | if (verbose) console.log('Update: ' + update); 36 | const ctx = new Context(update, this.telegram); 37 | this.handler[0](ctx, this.execute(ctx)); 38 | this.execTrigger(); 39 | } 40 | 41 | doPost(e) { 42 | if (!e) return console.log("Don't run doPost without love.. ^^"); 43 | if (verbose) console.log('Processing update'); 44 | 45 | // handle error 46 | try { 47 | let update; 48 | if (e.postData.type == "application/json") { 49 | update = JSON.parse(e.postData.contents); 50 | if (!update) throw Error('Update invalid data.'); 51 | if (DEBUG && this.options.log_id) return this.telegram.sendMessage(this.options.log_id, update); 52 | } 53 | 54 | return this.handleUpdate(update); 55 | 56 | } catch (e) { 57 | if (this.options.log_id) { 58 | try { 59 | if (verbose) console.log('Error: ' + e.message); 60 | return this.telegram.sendMessage(this.options.log_id, 'Error: ' + e.message); 61 | } catch (ee) { 62 | // error karena gak bisa kirim log ke akun telegram 63 | throw Error(ee); 64 | } 65 | } 66 | // error karena handle post 67 | throw Error(e); 68 | } 69 | 70 | } 71 | } 72 | 73 | var init = Main; -------------------------------------------------------------------------------- /core/00 version.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | GASLibv3 4 | ---------------- 5 | Public Release 6 | 7 | GAS Library untuk Telegram versi 3 8 | 9 | Adalah GAS Library untuk Telegram edisi ke tiga, merupakan suksesi 10 | dari GAS Library Telegram sebelumnya, edisi 1 dan edisi 2 11 | yang (alhamdulillah) banyak pemakainya. 12 | 13 | GAS Lib v3 ini terinspirasi dari Telegraf yang dirasa cukup praktis 14 | dalam penggunaan sehari-hari dan banyak dilakukan penyesuaian. 15 | 16 | Support hanya via komunitas di Grup Telegram @botindonesia 17 | atau via issues GITHUB 18 | contact personal hanya untuk proyek, client, teman / sahabat, atau keluarga 19 | 20 | Kanal khusus info release @GASindonesia 21 | 22 | Docs URL: https://lumpia.js.org 23 | Web: https://banghasan.com 24 | Email: banghasan@orang.paling.cakep.seantero.web.id 25 | Donasi: https://saweria.co/hasanudinhs 26 | ---------------- 27 | 28 | Release public pertama kali : 29 | - 10 Agustus 2021 / 1 Muharam 1443 H 30 | 31 | Last Release: 32 | - 23 Juli 2025 33 | ================ 34 | 35 | */ 36 | 37 | /* 38 | Penamaan 39 | 40 | stabil diberi nama lumpia 41 | sedangkan beta, diberi nama bapia 42 | 43 | Versi mayor adalah versi 3. 44 | Dimana nomor 3 adalah generasi atau edisi ke-3 dari Library GAS untuk Telegram ini. 45 | 46 | Versi minor adalah versi build. Yang akan terus bertambah meski hanya sedikit perbaikan. 47 | 48 | */ 49 | 50 | const dev = false; 51 | 52 | // const active = 'alpha'; 53 | // const active = "beta"; 54 | const active = "stable"; 55 | 56 | const app = { 57 | alpha: { 58 | name: "matoa", 59 | build: 1, 60 | // matoa tidak memiliki id, karena pakai mode develop langsung di run 61 | // dan tidak pernah di build 62 | }, 63 | stable: { 64 | name: "lumpia", 65 | build: 11, 66 | id: { 67 | legacy: "MUD_wfLskZT2D99lRXLh94vvg_do21SJR", 68 | new: "1Yo6vQRwjG5Gl9jeEF0g2tBTUa0XN5MyT4G_HeDpRr9DvabxhRcSdhPNj", 69 | }, 70 | }, 71 | beta: { 72 | name: "bapia", 73 | build: 14, 74 | id: { 75 | legacy: "M2iDAxzI3JJ4n6a8sryWJsfvg_do21SJR", 76 | new: "1OSN8eNlJtw2ehf3ul7h48Jb8rdeljKhC5Rw3cJo4nkEFITdS01Di0N_S", 77 | }, 78 | }, 79 | }; 80 | 81 | var version = { 82 | active, 83 | number: 3, 84 | name: app[active].name, 85 | build: app[active].build, 86 | full: "GAS Lib v3." + app[active].build + (dev ? "-dev" : ""), 87 | group: "@botindonesia", 88 | url: "https://lumpia.js.org/", 89 | email: "banghasan@orang.paling.cakep.seantero.web.id", 90 | }; 91 | 92 | // show logger log 93 | var verbose = false; 94 | 95 | // hook all message show json 96 | var DEBUG = false; 97 | -------------------------------------------------------------------------------- /examples/bot.js: -------------------------------------------------------------------------------- 1 | var token = '1234:abcedefghij'; 2 | 3 | const adminbot = 213567634; // your id 4 | const bot = new lumpia.init(token, { log_id: adminbot, prefix_command: '!/.' }); 5 | 6 | function doPost(e) { 7 | bot.doPost(e); 8 | } 9 | 10 | const button = lumpia.button, 11 | markup = lumpia.markup, 12 | helper = lumpia.helper; 13 | 14 | // middleware 15 | bot.use((ctx, next) => { 16 | ctx.state.hooked = true; 17 | next(); 18 | }) 19 | 20 | bot.cmd('hook', (ctx) => { 21 | console.log(`Semua pesan ${ctx.state.hooked ? 'berhasil' : 'gagal'} dihooked!`); 22 | }) 23 | 24 | 25 | bot.start(ctx => { 26 | // susun tombol keyboardnya, 1 dimensi array saja oke 27 | let keyboard = [ 28 | button.url('📚 Materi Bot', 'http://gg.gg/gasbot'), 29 | button.url('👥 @botindonesia', 'https://t.me/botindonesia'), 30 | button.text('😼 Halo Human', 'me_click') 31 | ]; 32 | 33 | // susun inline keyboardnya pakai markup, dengan jumlah kolom 2 jajar 34 | let inlineKeyboard = new markup().inlineKeyboard(keyboard, { columns: 2 }); 35 | 36 | // reply dengan HTML 37 | ctx.replyWithHTML(`🙋🏻‍♀️ Hai, ${helper.nama(ctx.from).html} perkenalkan aku ini bot.\n\n🛠 Dibuat dengan ${lumpia.version.name} ${lumpia.version.full}`, 38 | { reply_markup: inlineKeyboard }); 39 | }) 40 | 41 | // handle jawaban ketika button di klik 42 | bot.action('me_click', (ctx) => { 43 | ctx.answerCallbackQuery('✊🏼 Tetap semangat dan terus berkarya!'); 44 | }) 45 | 46 | 47 | // deteksi foto 48 | bot.on('photo', (ctx) => { 49 | let detail = []; 50 | ctx.message.photo.forEach(f => { 51 | let data = 'file_unique_id: ' + f.file_unique_id; 52 | data += '\n ├ file_id: ' + f.file_id; 53 | data += '\n ├ size: ' + f.file_size + ' bytes'; 54 | data += `\n └ res: ${f.width}x${f.height} px`; 55 | detail.push(data); 56 | }) 57 | ctx.replyIt(detail.join('\n\n')); 58 | }) 59 | 60 | bot.cmd('photo', (ctx) => { 61 | ctx.replyWithPhoto('https://avatars.githubusercontent.com/u/5436959?v=40', { caption: 'bukan raja Arthur yang bersama bayangan pedang' }) 62 | }) 63 | 64 | bot.cmd('ping', (ctx) => { 65 | let time_start = Date.now(); 66 | let res = ctx.replyIt('..pong!'); 67 | let time_stop = Date.now(); 68 | 69 | let time_delta = (time_stop - time_start) / 1000; // mili detik 70 | let time = new Intl.NumberFormat('id').format(time_delta); // jadiin detik, sekaligus di format 71 | 72 | let msg_id = res.result.message_id; 73 | 74 | bot.telegram.editMessageText(ctx.from.id, msg_id, null, `Pong! Proses ${time} detik.`, { parse_mode: 'html' }); 75 | }) 76 | 77 | bot.hears(/balik (.+)/i, (ctx) => ctx.reply(ctx.match[1].split('').reverse().join(''))); -------------------------------------------------------------------------------- /core/50 client.js: -------------------------------------------------------------------------------- 1 | /* 2 | Handle request dan respon API Telegram 3 | biasa disebut sebagai API Telegram Client 4 | 5 | Otomatisasi params bertipe JSON dan Blob 6 | tidak ada lagi pemisahan request dan requestForm 7 | */ 8 | 9 | // tipe data yang wajib bertipe JSON 10 | const FORM_DATA_JSON_FIELDS = [ 11 | 'results', 12 | 'reply_markup', 13 | 'mask_position', 14 | 'shipping_options' 15 | ]; 16 | 17 | // tipe yang berpotensi memiliki data bertipe blob 18 | // dikarenakan GAS tidak bisa mendeteksi secara langsung tipe blob 19 | // sehingga dibuat perkiraan field 20 | // --> sudah ditemukan, tapi males ngubah codingan 21 | // --> https://stackoverflow.com/questions/68665661/google-apps-script-how-detect-typeof-blob 22 | const BLOB_FIELDS = [ 23 | 'thumb', 24 | 'photo', 25 | 'audio', 26 | 'document', 27 | 'video', 28 | 'animation', 29 | 'video_note', 30 | 'sticker', 31 | 'png_sticker', 32 | 'tgs_sticker', 33 | 'certificate', 34 | 35 | ]; 36 | 37 | // belum diimplementasikan 38 | const DEFAULT_EXTENSIONS = { 39 | audio: 'mp3', 40 | photo: 'jpg', 41 | sticker: 'webp', 42 | video: 'mp4', 43 | animation: 'mp4', 44 | video_note: 'mp4', 45 | voice: 'ogg', 46 | }; 47 | 48 | class Client { 49 | // v3 dipantek ke API Official 50 | constructor() { 51 | this.urlApi = 'https://api.telegram.org/bot'; 52 | } 53 | 54 | callApi(method, data = {}) { 55 | if (!this.token) { 56 | throw new Error('Bot Token is required') 57 | } 58 | if (!method) { 59 | throw new Error('Method is required') 60 | } 61 | 62 | try { 63 | let options = maybeBlob(data) 64 | ? this.buildFormData(data) 65 | : this.buildJSON(data); 66 | 67 | 68 | let response = UrlFetchApp.fetch(this.urlApi + this.token + '/' + method, options); 69 | if (response.getResponseCode() == 200) { 70 | let result = JSON.parse(response.getContentText()); 71 | if (verbose) { 72 | console.log(method + ' Result:') 73 | console.log(result); 74 | } 75 | return result; 76 | } 77 | } catch (error) { 78 | throw Error(error.message); 79 | } 80 | 81 | } 82 | 83 | buildJSON(payload) { 84 | payload = JSON.stringify(payload, helper.replacer); 85 | if (verbose) console.log('build json: ' + payload); 86 | return { 87 | method: 'POST', 88 | contentType: 'application/json', 89 | payload 90 | }; 91 | } 92 | 93 | buildFormData(payload) { 94 | if (dev) console.log('build form'); 95 | for (const field of FORM_DATA_JSON_FIELDS) { 96 | if (helper.hasProp(payload, field) && typeof payload[field] !== 'string') { 97 | payload[field] = JSON.stringify(payload[field]); 98 | } 99 | } 100 | 101 | Object.keys(payload).forEach(key => { 102 | if (typeof payload[key] == 'number') payload[key] = String(payload[key]); 103 | }) 104 | 105 | if (dev) console.log(JSON.stringify(payload)); 106 | 107 | return { 108 | method: 'post', 109 | payload 110 | }; 111 | } 112 | } 113 | 114 | // metode baru deteksi 115 | // belum / tidak diimplementasikan dulu 116 | function isAttachBlob(payload) { 117 | if (!payload) return false; 118 | let result = false; 119 | helper.forEach(payload, key => { 120 | if (helper.hasProp(payload[key], 'copyBlob') && typeof payload[key].copyBlob === 'function') result = true; 121 | }); 122 | return result; 123 | } 124 | 125 | // saat ini: pakai metode yang ini 126 | // meprediksi isinya blob atau bukan 127 | function maybeBlob(payload) { 128 | if (!payload) return false; 129 | let result = false; 130 | for (const field of BLOB_FIELDS) 131 | if (helper.hasProp(payload, field)) 132 | if (!helper.isIn(['string', 'number'], helper.typeCheck(payload[field]))) result = true; 133 | 134 | return result; 135 | } 136 | 137 | // deteksi ada media kah 138 | // saat ini belum diimplementasikan 139 | function includesMedia(payload) { 140 | return Object.values(payload).some((value) => { 141 | if (Array.isArray(value)) { 142 | return value.some(({ media }) => media && typeof media === 'object' && (media.source || media.url)); 143 | } 144 | return (value && 145 | typeof value === 'object' && 146 | ((helper.hasProp(value, 'source') && value.source) || 147 | (helper.hasProp(value, 'url') && value.url) || 148 | (helper.hasPropType(value, 'media', 'object') && 149 | ((helper.hasProp(value.media, 'source') && value.media.source) || 150 | (helper.hasProp(value.media, 'url') && value.media.url))))); 151 | }); 152 | } -------------------------------------------------------------------------------- /core/70 fetch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple method fetch untuk REST API pada Google App Scripts 3 | * 4 | * Hasanudin H. Syafaat 5 | * TG @hasanudinhs 6 | * Email banghasan@orang.paling.cakep.seantero.web.id 7 | * 8 | * Support hanya di grup Telegram @botIndonesia 9 | * 10 | * Code date: 20 Februari 2021 11 | * 12 | * @param {String} url 13 | */ 14 | 15 | function Fetch(url = false) { 16 | ((this.req = { url: url, uri: "", options: { method: "get" } }), 17 | (this.req.url = url)); 18 | this.result = false; 19 | } 20 | 21 | Fetch.prototype = { 22 | setHeaders: function (headers) { 23 | return (this.req.options.headers = headers); 24 | }, 25 | 26 | setContentType: function (contentType) { 27 | return (this.req.options.contentType = contentType); 28 | }, 29 | 30 | setMethod: function (method) { 31 | return (this.req.options.method = method); 32 | }, 33 | 34 | setUrl: function (url) { 35 | return (this.req.url = url); 36 | }, 37 | 38 | getUrl: function () { 39 | return this.req.url; 40 | }, 41 | 42 | // request(url, options) 43 | request: function () { 44 | var url = arguments[0] ? arguments[0] : this.req.url + this.req.uri; 45 | var options = arguments[1] ? arguments[1] : this.req.options; 46 | if (!url) return false; 47 | this.result = UrlFetchApp.fetch(url, options); 48 | var dJSON = JSON.parse(this.result); 49 | if (dJSON) this.result = dJSON; 50 | return this.result; 51 | }, 52 | 53 | // addQuery({cari: "kata", khusus: "ya"}) : ?cari=kata&khusus=ya 54 | addQuery: function (obj) { 55 | return Object.keys(obj).reduce(function (p, e, i) { 56 | return ( 57 | p + 58 | (i == 0 ? "?" : "&") + 59 | (Array.isArray(obj[e]) 60 | ? obj[e].reduce(function (str, f, j) { 61 | return ( 62 | str + 63 | e + 64 | "=" + 65 | encodeURIComponent(f) + 66 | (j != obj[e].length - 1 ? "&" : "") 67 | ); 68 | }, "") 69 | : e + "=" + encodeURIComponent(obj[e])) 70 | ); 71 | }, ""); 72 | }, 73 | 74 | /* toJSON: function () { 75 | if (!this.result) return false; 76 | return JSON.parse(this.result); 77 | }, */ 78 | 79 | // get(url), get(uri) 80 | // get(url, uri) 81 | get: function () { 82 | this.req.options.method = "get"; 83 | 84 | // get(url), get(uri), get(obj) 85 | if (arguments.length >= 1) { 86 | if (typeof arguments[0] === "string") { 87 | // jika url 88 | if (/^https?:\/\//i.exec(arguments[0])) { 89 | this.req.url = arguments[0]; 90 | } else { 91 | // url harus ada isinya terlebih dahulu 92 | if (!this.req.url) return false; 93 | this.req.uri = arguments[0]; 94 | } 95 | } 96 | 97 | // jika objek {cari: "kata"} 98 | if (typeof arguments[0] === "object") { 99 | if (!this.req.url) return false; 100 | if (this.req.uri === "") { 101 | this.req.uri = this.addQuery(arguments[0]); 102 | } else { 103 | this.req.uri += this.addQuery(arguments[0]); 104 | } 105 | } 106 | } 107 | 108 | // get(url, data), get(uri, data) 109 | if (arguments.length >= 2) { 110 | // jika objek {cari: "kata"} 111 | if (typeof arguments[1] === "object") { 112 | if (this.req.uri === "") { 113 | this.req.uri = this.addQuery(arguments[1]); 114 | } else { 115 | this.req.uri += this.addQuery(arguments[1]); 116 | } 117 | } 118 | } 119 | 120 | return this.request(); 121 | }, 122 | 123 | post: function () { 124 | this.req.options.method = "post"; 125 | var isJSON = false; 126 | 127 | // post(url), post(uri), post(data) 128 | if (arguments.length >= 1) { 129 | if (typeof arguments[0] === "string") { 130 | // jika url 131 | if (/^https?:\/\//i.exec(arguments[0])) { 132 | this.req.url = arguments[0]; 133 | this.req.uri = ""; 134 | 135 | // jika uri 136 | } else { 137 | // url harus ada isinya terlebih dahulu 138 | if (!this.req.url) return false; 139 | this.req.uri = arguments[0]; 140 | } 141 | } 142 | 143 | if (typeof arguments[0] === "object") { 144 | var data = arguments[0]; 145 | } 146 | } 147 | 148 | // post(url|uri, data) post(data, isJSON) 149 | if (arguments.length >= 2) { 150 | if (typeof arguments[1] === "object") { 151 | var data = arguments[1]; 152 | } 153 | 154 | if (typeof arguments[1] === "boolean") { 155 | var isJSON = arguments[1]; 156 | } 157 | } 158 | 159 | // post(url|uri, data, isJSON) 160 | if (arguments.length >= 3) { 161 | if (typeof arguments[2] === "boolean") { 162 | var isJSON = arguments[2]; 163 | } 164 | } 165 | 166 | if (isJSON) { 167 | this.req.options.contentType = "application/json"; 168 | this.req.options.payload = JSON.stringify(data); 169 | } else { 170 | this.req.options.payload = data; 171 | } 172 | 173 | return this.request(); 174 | }, 175 | }; 176 | 177 | var fetch = Fetch; 178 | -------------------------------------------------------------------------------- /core/40 composer.js: -------------------------------------------------------------------------------- 1 | // daftar field yang tidak dibroadcast 2 | FIELD_NOT_BC = [ 3 | 'update_id', 4 | 'message_id', 5 | 'from', 6 | 'chat', 7 | 'date' 8 | ]; 9 | 10 | function escapeRegExp(s) { 11 | // $& means the whole matched string 12 | return s.replace(/[.*+\-?^${}()|[\]\\\/]/g, '\\$&') 13 | } 14 | 15 | class Composer extends EventEmitter { 16 | constructor() { 17 | super(); 18 | this.handler = [(ctx, next) => { next() }]; 19 | this.trigger = []; 20 | } 21 | 22 | /** 23 | * Registers a middleware. 24 | */ 25 | use(...fns) { 26 | this.compose(...fns); 27 | } 28 | 29 | // alias for use 30 | middleware(...fns) { 31 | this.compose(...fns); 32 | } 33 | 34 | 35 | // -- konsep event trigger 36 | 37 | // command( ['anu', 'ani'], (ctx, next) => {}) 38 | cmd(keys, callback) { 39 | return this.addTrigger('text', this.setRegex(keys, true), callback); 40 | } 41 | 42 | // alias cmd 43 | command(...args) { 44 | this.cmd(...args); 45 | } 46 | 47 | start(callback) { 48 | let username = this.options.username; 49 | let regex = new RegExp(`^(?[${escapeRegExp(this.options.prefix_command)}]start(?:@${username})?)\\s?(?.+)?`, 'i'); 50 | return this.addTrigger('text', regex, callback); 51 | } 52 | 53 | hear(keys, callback) { 54 | return this.addTrigger('text', this.setRegex(keys), callback); 55 | } 56 | 57 | // alias hear 58 | hears(...args) { 59 | this.hear(...args) 60 | } 61 | 62 | // handle callback 63 | action(keys, callback) { 64 | return this.addTrigger('action', this.setRegex(keys), callback); 65 | } 66 | 67 | // handle tambahan trigger: cmd, hear, action 68 | addTrigger(type, keys, callback) { 69 | keys = this.setRegex(keys); 70 | let data = { 71 | type, keys, 72 | callback 73 | } 74 | return this.trigger.push(data); 75 | } 76 | 77 | // eksekusi seluruh trigger 78 | execTrigger(index = 0) { 79 | let trigger = this.trigger; 80 | if (!trigger[index]) return; 81 | if (verbose) console.log('>> Trigger[' + index + ']: ' + trigger[index].keys.join(', ')); 82 | 83 | let update = this.ctx; 84 | let { type, keys, callback } = trigger[index]; 85 | 86 | let msg; 87 | if (type == 'text') { 88 | msg = update.message ?? update.channelPost; 89 | } 90 | if (type == 'action') { 91 | msg = update.callbackQuery; 92 | } 93 | 94 | let text = this.getText(msg); 95 | if (!text) return this.execTrigger(index + 1); 96 | 97 | let match, payload; 98 | keys.forEach(key => { 99 | // if (verbose) console.log(key + ' vs ' + text); 100 | let m = key.exec(text); 101 | if (m) { 102 | match = m; 103 | if (m.groups?.payload) payload = m.groups.payload; 104 | } 105 | }); 106 | 107 | if (match) { 108 | update.match = match; 109 | if (payload) update.payload = payload; 110 | return callback(update, () => this.execTrigger(index + 1)); 111 | } 112 | 113 | return this.execTrigger(index + 1); 114 | } 115 | 116 | 117 | // --- pembuatan middleware (dipisah, biar ga rumit ^^) 118 | compose(...fns) { 119 | if (!fns) return; 120 | fns.forEach(fn => { 121 | if (typeof fn === 'function') this.handler.push(fn); 122 | }); 123 | } 124 | 125 | // -- eksekusi middleware 126 | execute(update, index = 1) { 127 | let handler = this.handler || []; 128 | if (handler.length === 0) { 129 | this.ctx = update; 130 | return this.broadcast(); 131 | } 132 | return () => { 133 | if (!handler[index]) { 134 | this.ctx = update; 135 | return this.broadcast(); 136 | } 137 | return this.handler[index](update, this.execute(update, index + 1)); 138 | } 139 | } 140 | 141 | // --- fungsi-fungsi 142 | 143 | setRegex(keys, prefix = false) { 144 | if (!Array.isArray(keys)) keys = [keys]; 145 | let username = this.options.username; 146 | 147 | return keys.map((key) => { 148 | if (!key) { 149 | throw new Error('Invalid trigger'); 150 | } 151 | if (typeof key === 'function') { 152 | throw new Error('Invalid trigger'); 153 | } 154 | 155 | // if (key instanceof RegExp) return key; 156 | let type = helper.typeCheck(key); 157 | if (type == 'regexp') return key; 158 | 159 | if (type == 'string' || type == 'number') { 160 | // 161 | } else { 162 | throw Error('Invalid key.'); 163 | } 164 | 165 | let regex = prefix 166 | ? new RegExp(`^[${escapeRegExp(this.options.prefix_command)}]${escapeRegExp(key)}(?:@${username})?$`, 'i') 167 | : new RegExp(`^${escapeRegExp(key)}$`); 168 | return regex; 169 | }); 170 | } 171 | 172 | getText(msg) { 173 | /* if (!update) return undefined; 174 | let msg = update.message ?? update.channelPost ?? update.callback_query */ 175 | if (!msg) return undefined; 176 | if ('caption' in msg) return msg.caption; 177 | if ('text' in msg) return msg.text; 178 | if ('data' in msg) return msg.data; 179 | if ('game_short_name' in msg) return msg.game_short_name; 180 | return undefined; 181 | } 182 | 183 | // membroadcast event on 184 | broadcast() { 185 | let bc = {}; 186 | let ctx = this.ctx; 187 | let update = ctx.update; 188 | Object.keys(update).forEach(updateType => bc[updateType] = 1); 189 | if (update.message) { 190 | let msg = update.message; 191 | Object.keys(update.message).forEach(updateSubType => bc[updateSubType] = 1); 192 | let entities = msg.entities ?? msg.caption_entities; 193 | if (entities) { 194 | Object.values(entities).forEach(entity => bc[entity.type] = 1) 195 | } 196 | } 197 | 198 | let broadcasters = []; 199 | for (let key in bc) { 200 | if (FIELD_NOT_BC.indexOf(key) >= 0) continue; 201 | broadcasters.push(key); 202 | } 203 | ctx.broadcast = broadcasters; 204 | if (broadcasters.length > 0) this.emit(broadcasters, ctx); 205 | if (verbose) console.log('broadcast: ' + broadcasters.join(', ')); 206 | } 207 | 208 | } -------------------------------------------------------------------------------- /core/10 helper.js: -------------------------------------------------------------------------------- 1 | /* 2 | helper untuk bantuan saat coding bot 3 | tidak wajib dipakai, namun akan bermanfaat 4 | */ 5 | 6 | class Helper { 7 | /** 8 | * Checks if a given object has a property with a given name. 9 | * 10 | * Example invocation: 11 | * let obj = { 'foo': 'bar', 'baz': () => {} } 12 | * hasProp(obj, 'foo') // true 13 | * hasProp(obj, 'baz') // true 14 | * hasProp(obj, 'abc') // false 15 | * 16 | * @param obj An object to test 17 | * @param prop The name of the property 18 | */ 19 | 20 | hasProp(obj, prop) { 21 | return obj && prop in obj; 22 | } 23 | 24 | /** 25 | * Checks if a given object has a property with a given name. 26 | * Furthermore performs a `typeof` check on the property if it exists. 27 | * 28 | * Example invocation: 29 | * let obj = { 'foo': 'bar', 'baz': () => {} } 30 | * hasPropType(obj, 'foo', 'string') // true 31 | * hasPropType(obj, 'baz', 'function') // true 32 | * hasPropType(obj, 'abc', 'number') // false 33 | * 34 | * @param obj An object to test 35 | * @param prop The name of the property 36 | * @param type The type the property is expected to have 37 | */ 38 | hasPropType(obj, prop, type) { 39 | // eslint-disable-next-line valid-typeof 40 | return hasProp(obj, prop) && type === typeof obj[prop]; 41 | } 42 | 43 | compactOptions(options) { 44 | if (!options) { 45 | return options; 46 | } 47 | const keys = Object.keys(options); 48 | const compactKeys = keys.filter((key) => options[key] !== undefined); 49 | const compactEntries = compactKeys.map((key) => [key, options[key]]); 50 | return Object.fromEntries(compactEntries); 51 | } 52 | 53 | replacer(_, value) { 54 | if (value == null) 55 | return undefined; 56 | return value; 57 | } 58 | 59 | /* 60 | let a = [ 1, 2, 3]; 61 | console.log(helper.typeCheck(a)) // result: array 62 | */ 63 | typeCheck(value) { 64 | const return_value = Object.prototype.toString.call(value); 65 | // we can also use regex to do this... 66 | const type = return_value.substring( 67 | return_value.indexOf(" ") + 1, 68 | return_value.indexOf("]")); 69 | 70 | return type.toLowerCase(); 71 | } 72 | 73 | /* 74 | let admin = [ 123, 456 ]; 75 | if (helper.isIn(admin, msg.from.id)) { 76 | console.log('dia adalah admin!'); 77 | } 78 | */ 79 | isIn(array, index) { 80 | return (array.indexOf(index) > -1); 81 | } 82 | 83 | /* 84 | let data = { satu: 1, dua: 2}; 85 | helper.forEach(data, (isi, index) => console.log(index, isi)); 86 | */ 87 | forEach(obj, fn) { 88 | // Don't bother if no value provided 89 | if (obj === null || typeof obj === 'undefined') { 90 | return; 91 | } 92 | 93 | // Force an array if not already something iterable 94 | if (this.typeCheck(obj) !== 'object') { 95 | /*eslint no-param-reassign:0*/ 96 | obj = [obj]; 97 | } 98 | 99 | if (this.typeCheck(obj) == 'array') { 100 | // Iterate over array values 101 | for (var i = 0, l = obj.length; i < l; i++) { 102 | fn.call(null, obj[i], i, obj); 103 | } 104 | } else { 105 | // Iterate over object keys 106 | for (var key in obj) { 107 | if (Object.prototype.hasOwnProperty.call(obj, key)) { 108 | fn.call(null, obj[key], key, obj); 109 | } 110 | } 111 | } 112 | } 113 | 114 | // bantuan random Array dan Angka 115 | /* 116 | random(['aku', 'kamu', 'dia']) // hasil acakan dari aku, kamu, atau dia 117 | random(0,100) // hasil acakan antara angka 1 - 100 118 | */ 119 | random() { 120 | // random(list) : item 121 | if (arguments.length === 1 && this.typeCheck(arguments[0]) == 'array') { 122 | var list = arguments[0]; 123 | return list[Math.floor((Math.random() * list.length))]; 124 | } 125 | 126 | // random(min, max) : integer 127 | if (arguments.length === 2 && typeof (arguments[0]) === 'number' && typeof (arguments[1]) === 'number') { 128 | var min = arguments[0]; 129 | var max = arguments[1]; 130 | if (max < min) { [min, max] = [max, min]; } 131 | return Math.floor(Math.random() * (max - min + 1)) + min; 132 | } 133 | 134 | return false; 135 | } 136 | 137 | // blob = textBlob('namaFile', 'Hasanudin H Syafaat') 138 | textBlob(namaFile, isiText, extention = '.txt', mime = MimeType.PLAIN_TEXT) { 139 | return Utilities.newBlob('') 140 | .setDataFromString(isiText) 141 | .setName(namaFile + extention) 142 | .setContentType(mime); 143 | } 144 | 145 | // output mode web app url yang diakses secara langsung 146 | // ------- 147 | outputText(text) { 148 | return ContentService.createTextOutput(text); 149 | } 150 | 151 | outputJSON(data) { 152 | return ContentService.createTextOutput(JSON.stringify(data)).setMimeType(ContentService.MimeType.JSON); 153 | } 154 | 155 | outputHTML(text) { 156 | return HtmlService.createHtmlOutput(text); 157 | } 158 | // ------- 159 | 160 | /** 161 | Membersihkan tag HTML 162 | @param {string} text yang akan dibersihkan 163 | */ 164 | clearHTML(s) { 165 | return s 166 | .replace(/&/g, "&") 167 | .replace(//g, ">"); 169 | } 170 | 171 | /** 172 | Membersihkan tag Markdown 173 | @param {string} text yang akan dibersihkan 174 | */ 175 | clearMarkdown(s) { 176 | return s 177 | .replace(/_/g, "\\_") 178 | .replace(/\*/g, "\\*") 179 | .replace(/\[/g, "\\[") 180 | .replace(/`/g, "\\`"); 181 | } 182 | 183 | // shorthand untuk field name 184 | nama(data) { 185 | let first = data.first_name; 186 | 187 | let fullname = first; 188 | let last = data.last_name || false; 189 | if (last) fullname += ' ' + last; 190 | let html = '' + this.clearHTML(fullname) + ''; 191 | // tambahkan username jika punya 192 | let username = data.username ? data.username : false; 193 | 194 | if (username) html += ' @' + username; 195 | 196 | return { 197 | first, 198 | last, 199 | fullname, 200 | username, 201 | html, 202 | } 203 | } 204 | 205 | // alias nama 206 | name(...args) { 207 | return this.nama(...args); 208 | } 209 | 210 | } 211 | 212 | /* 213 | Bantuan cepat / pragmatis untuk keyboard inline 214 | turunan dari versi 1/2 (untuk compabilitas) 215 | */ 216 | class Button { 217 | text(text, data, hide = false) { 218 | return { text, callback_data: data, hide } 219 | } 220 | // inline = alias dari text 221 | inline(text, data, hide = false) { 222 | return { text, callback_data: data, hide } 223 | } 224 | // akan tersedia v3.7 225 | queryChat(text, data) { 226 | return { 227 | text, 228 | switch_inline_query_current_chat: data 229 | } 230 | } 231 | query(text, data) { 232 | return { 233 | text, 234 | switch_inline_query: data 235 | } 236 | } 237 | url(text, url, hide = false) { 238 | return { text, url, hide } 239 | } 240 | } 241 | 242 | var helper = new Helper(); 243 | var button = new Button(); -------------------------------------------------------------------------------- /core/15 markup.js: -------------------------------------------------------------------------------- 1 | /* 2 | Helper tambahan type markup 3 | baik Keyboard biasa ataupun inline 4 | -- 5 | jika rumit, gak usah dipakai 6 | gunakan metode jadul saja 7 | */ 8 | 9 | class Markup { 10 | forceReply(value = true) { 11 | this.force_reply = value 12 | return this 13 | } 14 | 15 | removeKeyboard(value = true) { 16 | this.remove_keyboard = value 17 | return this 18 | } 19 | 20 | selective(value = true) { 21 | this.selective = value 22 | return this 23 | } 24 | 25 | extra(options) { 26 | return { 27 | reply_markup: { ...this }, 28 | ...options 29 | } 30 | } 31 | 32 | keyboard(buttons, options) { 33 | const keyboard = buildKeyboard(buttons, { columns: 1, ...options }) 34 | if (keyboard && keyboard.length > 0) { 35 | this.keyboard = keyboard 36 | } 37 | return this 38 | } 39 | 40 | resize(value = true) { 41 | this.resize_keyboard = value 42 | return this 43 | } 44 | 45 | oneTime(value = true) { 46 | this.one_time_keyboard = value 47 | return this 48 | } 49 | 50 | inlineKeyboard(buttons, options) { 51 | const keyboard = buildKeyboard(buttons, { columns: buttons.length, ...options }) 52 | if (keyboard && keyboard.length > 0) { 53 | this.inline_keyboard = keyboard 54 | } 55 | return this 56 | } 57 | 58 | button(text, hide) { 59 | return Markup.button(text, hide) 60 | } 61 | 62 | contactRequestButton(text, hide) { 63 | return Markup.contactRequestButton(text, hide) 64 | } 65 | 66 | locationRequestButton(text, hide) { 67 | return Markup.locationRequestButton(text, hide) 68 | } 69 | 70 | urlButton(text, url, hide) { 71 | return Markup.urlButton(text, url, hide) 72 | } 73 | 74 | callbackButton(text, data, hide) { 75 | return Markup.callbackButton(text, data, hide) 76 | } 77 | 78 | switchToChatButton(text, value, hide) { 79 | return Markup.switchToChatButton(text, value, hide) 80 | } 81 | 82 | switchToCurrentChatButton(text, value, hide) { 83 | return Markup.switchToCurrentChatButton(text, value, hide) 84 | } 85 | 86 | gameButton(text, hide) { 87 | return Markup.gameButton(text, hide) 88 | } 89 | 90 | payButton(text, hide) { 91 | return Markup.payButton(text, hide) 92 | } 93 | 94 | loginButton(text, url, opts, hide) { 95 | return Markup.loginButton(text, url, opts, hide) 96 | } 97 | 98 | static removeKeyboard(value) { 99 | return new Markup().removeKeyboard(value) 100 | } 101 | 102 | static forceReply(value) { 103 | return new Markup().forceReply(value) 104 | } 105 | 106 | static keyboard(buttons, options) { 107 | return new Markup().keyboard(buttons, options) 108 | } 109 | 110 | static inlineKeyboard(buttons, options) { 111 | return new Markup().inlineKeyboard(buttons, options) 112 | } 113 | 114 | static resize(value = true) { 115 | return new Markup().resize(value) 116 | } 117 | 118 | static selective(value = true) { 119 | return new Markup().selective(value) 120 | } 121 | 122 | static oneTime(value = true) { 123 | return new Markup().oneTime(value) 124 | } 125 | 126 | static button(text, hide = false) { 127 | return { text: text, hide: hide } 128 | } 129 | 130 | static contactRequestButton(text, hide = false) { 131 | return { text: text, request_contact: true, hide: hide } 132 | } 133 | 134 | static locationRequestButton(text, hide = false) { 135 | return { text: text, request_location: true, hide: hide } 136 | } 137 | 138 | static pollRequestButton(text, type, hide = false) { 139 | return { text: text, request_poll: { type }, hide: hide } 140 | } 141 | 142 | static urlButton(text, url, hide = false) { 143 | return { text: text, url: url, hide: hide } 144 | } 145 | 146 | static callbackButton(text, data, hide = false) { 147 | return { text: text, callback_data: data, hide: hide } 148 | } 149 | 150 | static switchToChatButton(text, value, hide = false) { 151 | return { text: text, switch_inline_query: value, hide: hide } 152 | } 153 | 154 | static switchToCurrentChatButton(text, value, hide = false) { 155 | return { text: text, switch_inline_query_current_chat: value, hide: hide } 156 | } 157 | 158 | static gameButton(text, hide = false) { 159 | return { text: text, callback_game: {}, hide: hide } 160 | } 161 | 162 | static payButton(text, hide = false) { 163 | return { text: text, pay: true, hide: hide } 164 | } 165 | 166 | static loginButton(text, url, opts = {}, hide = false) { 167 | return { 168 | text: text, 169 | login_url: { ...opts, url: url }, 170 | hide: hide 171 | } 172 | } 173 | 174 | static formatHTML(text = '', entities = []) { 175 | const chars = [...text] 176 | const available = [...entities] 177 | const opened = [] 178 | const result = [] 179 | for (let offset = 0; offset < chars.length; offset++) { 180 | while (true) { 181 | const index = available.findIndex((entity) => entity.offset === offset) 182 | if (index === -1) { 183 | break 184 | } 185 | const entity = available[index] 186 | switch (entity.type) { 187 | case 'bold': 188 | result.push('') 189 | break 190 | case 'italic': 191 | result.push('') 192 | break 193 | case 'code': 194 | result.push('') 195 | break 196 | case 'pre': 197 | if (entity.language) { 198 | result.push(`
`)
199 |                         } else {
200 |                             result.push('
')
201 |                         }
202 |                         break
203 |                     case 'strikethrough':
204 |                         result.push('')
205 |                         break
206 |                     case 'underline':
207 |                         result.push('')
208 |                         break
209 |                     case 'text_mention':
210 |                         result.push(``)
211 |                         break
212 |                     case 'text_link':
213 |                         result.push(``)
214 |                         break
215 |                     case 'spoiler':
216 |                         result.push('')
217 |                         break
218 |                 }
219 |                 opened.unshift(entity)
220 |                 available.splice(index, 1)
221 |             }
222 | 
223 |             result.push(chars[offset])
224 | 
225 |             while (true) {
226 |                 const index = opened.findIndex((entity) => entity.offset + entity.length - 1 === offset)
227 |                 if (index === -1) {
228 |                     break
229 |                 }
230 |                 const entity = opened[index]
231 |                 switch (entity.type) {
232 |                     case 'bold':
233 |                         result.push('')
234 |                         break
235 |                     case 'italic':
236 |                         result.push('')
237 |                         break
238 |                     case 'code':
239 |                         result.push('')
240 |                         break
241 |                     case 'pre':
242 |                         if (entity.language) {
243 |                             result.push('
') 244 | } else { 245 | result.push('
') 246 | } 247 | break 248 | case 'strikethrough': 249 | result.push('') 250 | break 251 | case 'underline': 252 | result.push('') 253 | break 254 | case 'text_mention': 255 | case 'text_link': 256 | result.push('') 257 | break 258 | case 'spoiler': 259 | result.push('') 260 | break 261 | } 262 | opened.splice(index, 1) 263 | } 264 | } 265 | return result.join('') 266 | } 267 | } 268 | 269 | function buildKeyboard(buttons, options) { 270 | const result = [] 271 | if (!Array.isArray(buttons)) { 272 | return result 273 | } 274 | if (buttons.find(Array.isArray)) { 275 | return buttons.map(row => row.filter((button) => !button.hide)) 276 | } 277 | const wrapFn = options.wrap 278 | ? options.wrap 279 | : (btn, index, currentRow) => currentRow.length >= options.columns 280 | let currentRow = [] 281 | let index = 0 282 | for (const btn of buttons.filter((button) => !button.hide)) { 283 | if (wrapFn(btn, index, currentRow) && currentRow.length > 0) { 284 | result.push(currentRow) 285 | currentRow = [] 286 | } 287 | currentRow.push(btn) 288 | index++ 289 | } 290 | if (currentRow.length > 0) { 291 | result.push(currentRow) 292 | } 293 | return result 294 | } 295 | 296 | class Extra { 297 | constructor(opts) { 298 | this.load(opts) 299 | } 300 | 301 | load(opts = {}) { 302 | return Object.assign(this, opts) 303 | } 304 | 305 | inReplyTo(messageId) { 306 | this.reply_to_message_id = messageId 307 | return this 308 | } 309 | 310 | notifications(value = true) { 311 | this.disable_notification = !value 312 | return this 313 | } 314 | 315 | webPreview(value = true) { 316 | this.disable_web_page_preview = !value 317 | return this 318 | } 319 | 320 | markup(markup) { 321 | if (typeof markup === 'function') { 322 | markup = markup(new Markup()) 323 | } 324 | this.reply_markup = { ...markup } 325 | return this 326 | } 327 | 328 | HTML(value = true) { 329 | this.parse_mode = value ? 'HTML' : undefined 330 | return this 331 | } 332 | 333 | markdown(value = true) { 334 | this.parse_mode = value ? 'Markdown' : undefined 335 | return this 336 | } 337 | 338 | caption(caption = '') { 339 | this.caption = caption 340 | return this 341 | } 342 | 343 | static inReplyTo(messageId) { 344 | return new Extra().inReplyTo(messageId) 345 | } 346 | 347 | static notifications(value) { 348 | return new Extra().notifications(value) 349 | } 350 | 351 | static webPreview(value) { 352 | return new Extra().webPreview(value) 353 | } 354 | 355 | static load(opts) { 356 | return new Extra(opts) 357 | } 358 | 359 | static markup(markup) { 360 | return new Extra().markup(markup) 361 | } 362 | 363 | static HTML(value) { 364 | return new Extra().HTML(value) 365 | } 366 | 367 | static markdown(value) { 368 | return new Extra().markdown(value) 369 | } 370 | 371 | static caption(caption) { 372 | return new Extra().caption(caption) 373 | } 374 | } 375 | 376 | var markup = Markup; 377 | var extra = Extra; 378 | 379 | // -- 380 | 381 | /* let kb = new Markup().inlineKeyboard( [ 382 | markup.callbackButton('1', 'me_1'), markup.callbackButton('2', 'me_1'), 383 | markup.callbackButton('3', 'me_1', true), markup.callbackButton('4', 'me_1'), 384 | markup.callbackButton('5', 'me_1'), markup.callbackButton('6', 'me_1'), 385 | ], { columns: 2} ); 386 | 387 | console.log(JSON.stringify(kb, null, 2)); */ -------------------------------------------------------------------------------- /core/30 context.js: -------------------------------------------------------------------------------- 1 | /* 2 | * susun di sini 3 | * method yang akan disertaan pada ctx 4 | * 5 | * tambahan replyIt{markup} shortcut atas respon biasa 6 | */ 7 | 8 | class Context { 9 | constructor(update, tg) { 10 | this.update = update; 11 | this.tg = tg; 12 | this.state = {}; 13 | } 14 | get updateType() { 15 | const types = Object.keys(this.update).filter( 16 | (k) => typeof this.update[k] === "object", 17 | ); 18 | if (types.length !== 1) { 19 | throw new Error( 20 | `Cannot determine \`updateType\` of ${JSON.stringify(this.update)}`, 21 | ); 22 | } 23 | return types[0]; 24 | } 25 | get telegram() { 26 | return this.tg; 27 | } 28 | get message() { 29 | return this.update.message; 30 | } 31 | get editedMessage() { 32 | return this.update.edited_message; 33 | } 34 | get inlineQuery() { 35 | return this.update.inline_query; 36 | } 37 | get shippingQuery() { 38 | return this.update.shipping_query; 39 | } 40 | get preCheckoutQuery() { 41 | return this.update.pre_checkout_query; 42 | } 43 | get chosenInlineResult() { 44 | return this.update.chosen_inline_result; 45 | } 46 | get channelPost() { 47 | return this.update.channel_post; 48 | } 49 | get editedChannelPost() { 50 | return this.update.edited_channel_post; 51 | } 52 | get messageReaction() { 53 | return this.update.message_reaction; 54 | } 55 | get messageReactionCount() { 56 | return this.update.message_reaction_count; 57 | } 58 | get editedChannelPost() { 59 | return this.update.edited_channel_post; 60 | } 61 | get callbackQuery() { 62 | return this.update.callback_query; 63 | } 64 | get poll() { 65 | return this.update.poll; 66 | } 67 | get pollAnswer() { 68 | return this.update.poll_answer; 69 | } 70 | get myChatMember() { 71 | return this.update.my_chat_member; 72 | } 73 | get chatMember() { 74 | return this.update.chat_member; 75 | } 76 | get chat() { 77 | return ( 78 | this.chatMember ?? 79 | this.myChatMember ?? 80 | getMessageFromAnySource(this) 81 | )?.chat; 82 | } 83 | get senderChat() { 84 | return getMessageFromAnySource(this)?.sender_chat; 85 | } 86 | 87 | get chatJoinRequest() { 88 | return this.update.chat_join_request; 89 | } 90 | get chatBoost() { 91 | return this.update.chat_boost; 92 | } 93 | get removedChatBoost() { 94 | return this.update.removed_chat_boost; 95 | } 96 | 97 | get from() { 98 | return ( 99 | this.callbackQuery ?? 100 | this.inlineQuery ?? 101 | this.shippingQuery ?? 102 | this.preCheckoutQuery ?? 103 | this.chosenInlineResult ?? 104 | this.chatMember ?? 105 | this.myChatMember ?? 106 | this.chatJoinRequest ?? 107 | getMessageFromAnySource(this) 108 | )?.from; 109 | } 110 | get inlineMessageId() { 111 | return (this.callbackQuery ?? this.chosenInlineResult)?.inline_message_id; 112 | } 113 | 114 | get passportData() { 115 | if (this.message == null) return undefined; 116 | if (!("passport_data" in this.message)) return undefined; 117 | return this.message?.passport_data; 118 | } 119 | 120 | assert(value, method) { 121 | if (value === undefined) { 122 | throw new TypeError( 123 | `GASLibv3: "${method}" isn't available for "${this.updateType}"`, 124 | ); 125 | } 126 | } 127 | /** 128 | * @see https://core.telegram.org/bots/api#answerinlinequery 129 | */ 130 | answerInlineQuery(...args) { 131 | this.assert(this.inlineQuery, "answerInlineQuery"); 132 | return this.telegram.answerInlineQuery(this.inlineQuery.id, ...args); 133 | } 134 | /** 135 | * @see https://core.telegram.org/bots/api#answercallbackquery 136 | */ 137 | answerCbQuery(...args) { 138 | this.assert(this.callbackQuery, "answerCbQuery"); 139 | return this.telegram.answerCbQuery(this.callbackQuery.id, ...args); 140 | } 141 | answerCallbackQuery(...args) { 142 | return this.answerCbQuery(...args); 143 | } 144 | /** 145 | * @see https://core.telegram.org/bots/api#answercallbackquery 146 | */ 147 | answerGameQuery(...args) { 148 | this.assert(this.callbackQuery, "answerGameQuery"); 149 | return this.telegram.answerGameQuery(this.callbackQuery.id, ...args); 150 | } 151 | /** 152 | * @see https://core.telegram.org/bots/api#answershippingquery 153 | */ 154 | answerShippingQuery(...args) { 155 | this.assert(this.shippingQuery, "answerShippingQuery"); 156 | return this.telegram.answerShippingQuery(this.shippingQuery.id, ...args); 157 | } 158 | /** 159 | * @see https://core.telegram.org/bots/api#answerprecheckoutquery 160 | */ 161 | answerPreCheckoutQuery(...args) { 162 | this.assert(this.preCheckoutQuery, "answerPreCheckoutQuery"); 163 | return this.telegram.answerPreCheckoutQuery( 164 | this.preCheckoutQuery.id, 165 | ...args, 166 | ); 167 | } 168 | /** 169 | * @see https://core.telegram.org/bots/api#editmessagetext 170 | */ 171 | editMessageText(text, extra) { 172 | this.assert(this.callbackQuery ?? this.inlineMessageId, "editMessageText"); 173 | return this.telegram.editMessageText( 174 | this.chat?.id, 175 | this.callbackQuery?.message?.message_id, 176 | this.inlineMessageId, 177 | text, 178 | extra, 179 | ); 180 | } 181 | /** 182 | * @see https://core.telegram.org/bots/api#editmessagecaption 183 | */ 184 | editMessageCaption(caption, extra) { 185 | this.assert( 186 | this.callbackQuery ?? this.inlineMessageId, 187 | "editMessageCaption", 188 | ); 189 | return this.telegram.editMessageCaption( 190 | this.chat?.id, 191 | this.callbackQuery?.message?.message_id, 192 | this.inlineMessageId, 193 | caption, 194 | extra, 195 | ); 196 | } 197 | /** 198 | * @see https://core.telegram.org/bots/api#editmessagemedia 199 | */ 200 | editMessageMedia(media, extra) { 201 | this.assert(this.callbackQuery ?? this.inlineMessageId, "editMessageMedia"); 202 | return this.telegram.editMessageMedia( 203 | this.chat?.id, 204 | this.callbackQuery?.message?.message_id, 205 | this.inlineMessageId, 206 | media, 207 | extra, 208 | ); 209 | } 210 | /** 211 | * @see https://core.telegram.org/bots/api#editmessagereplymarkup 212 | */ 213 | editMessageReplyMarkup(markup) { 214 | this.assert( 215 | this.callbackQuery ?? this.inlineMessageId, 216 | "editMessageReplyMarkup", 217 | ); 218 | return this.telegram.editMessageReplyMarkup( 219 | this.chat?.id, 220 | this.callbackQuery?.message?.message_id, 221 | this.inlineMessageId, 222 | markup, 223 | ); 224 | } 225 | /** 226 | * @see https://core.telegram.org/bots/api#editmessagelivelocation 227 | */ 228 | editMessageLiveLocation(latitude, longitude, extra) { 229 | this.assert( 230 | this.callbackQuery ?? this.inlineMessageId, 231 | "editMessageLiveLocation", 232 | ); 233 | return this.telegram.editMessageLiveLocation( 234 | this.chat?.id, 235 | this.callbackQuery?.message?.message_id, 236 | this.inlineMessageId, 237 | latitude, 238 | longitude, 239 | extra, 240 | ); 241 | } 242 | /** 243 | * @see https://core.telegram.org/bots/api#stopmessagelivelocation 244 | */ 245 | stopMessageLiveLocation(markup) { 246 | this.assert( 247 | this.callbackQuery ?? this.inlineMessageId, 248 | "stopMessageLiveLocation", 249 | ); 250 | return this.telegram.stopMessageLiveLocation( 251 | this.chat?.id, 252 | this.callbackQuery?.message?.message_id, 253 | this.inlineMessageId, 254 | markup, 255 | ); 256 | } 257 | 258 | /** 259 | * @see https://core.telegram.org/bots/api#sendmessage 260 | */ 261 | sendMessage(text, extra) { 262 | this.assert(this.chat, "sendMessage"); 263 | return this.telegram.sendMessage(this.chat.id, text, { 264 | message_thread_id: getThreadId(this), 265 | ...extra, 266 | }); 267 | } 268 | 269 | /** 270 | * @see https://core.telegram.org/bots/api#sendmessage 271 | */ 272 | reply(...args) { 273 | return this.sendMessage(...args); 274 | } 275 | /** 276 | * @see https://core.telegram.org/bots/api#sendmessage 277 | */ 278 | replyIt(text, extra) { 279 | return this.reply(text, { 280 | reply_to_message_id: this.message.message_id, 281 | ...extra, 282 | }); 283 | } 284 | /** 285 | * @see https://core.telegram.org/bots/api#getchat 286 | */ 287 | getChat(...args) { 288 | this.assert(this.chat, "getChat"); 289 | return this.telegram.getChat(this.chat.id, ...args); 290 | } 291 | /** 292 | * @see https://core.telegram.org/bots/api#exportchatinvitelink 293 | */ 294 | exportChatInviteLink(...args) { 295 | this.assert(this.chat, "exportChatInviteLink"); 296 | return this.telegram.exportChatInviteLink(this.chat.id, ...args); 297 | } 298 | /** 299 | * @see https://core.telegram.org/bots/api#createchatinvitelink 300 | */ 301 | createChatInviteLink(...args) { 302 | this.assert(this.chat, "createChatInviteLink"); 303 | return this.telegram.createChatInviteLink(this.chat.id, ...args); 304 | } 305 | /** 306 | * @see https://core.telegram.org/bots/api#editchatinvitelink 307 | */ 308 | editChatInviteLink(...args) { 309 | this.assert(this.chat, "editChatInviteLink"); 310 | return this.telegram.editChatInviteLink(this.chat.id, ...args); 311 | } 312 | /** 313 | * @see https://core.telegram.org/bots/api#revokechatinvitelink 314 | */ 315 | revokeChatInviteLink(...args) { 316 | this.assert(this.chat, "revokeChatInviteLink"); 317 | return this.telegram.revokeChatInviteLink(this.chat.id, ...args); 318 | } 319 | /** 320 | * @see https://core.telegram.org/bots/api#banchatmember 321 | */ 322 | banChatMember(...args) { 323 | this.assert(this.chat, "banChatMember"); 324 | return this.telegram.kickChatMember(this.chat.id, ...args); 325 | } 326 | /** 327 | * @see https://core.telegram.org/bots/api#unbanchatmember 328 | */ 329 | unbanChatMember(...args) { 330 | this.assert(this.chat, "unbanChatMember"); 331 | return this.telegram.unbanChatMember(this.chat.id, ...args); 332 | } 333 | /** 334 | * @see https://core.telegram.org/bots/api#restrictchatmember 335 | */ 336 | restrictChatMember(...args) { 337 | this.assert(this.chat, "restrictChatMember"); 338 | return this.telegram.restrictChatMember(this.chat.id, ...args); 339 | } 340 | /** 341 | * @see https://core.telegram.org/bots/api#promotechatmember 342 | */ 343 | promoteChatMember(...args) { 344 | this.assert(this.chat, "promoteChatMember"); 345 | return this.telegram.promoteChatMember(this.chat.id, ...args); 346 | } 347 | /** 348 | * @see https://core.telegram.org/bots/api#setchatadministratorcustomtitle 349 | */ 350 | setChatAdministratorCustomTitle(...args) { 351 | this.assert(this.chat, "setChatAdministratorCustomTitle"); 352 | return this.telegram.setChatAdministratorCustomTitle(this.chat.id, ...args); 353 | } 354 | /** 355 | * @see https://core.telegram.org/bots/api#setchatphoto 356 | */ 357 | setChatPhoto(...args) { 358 | this.assert(this.chat, "setChatPhoto"); 359 | return this.telegram.setChatPhoto(this.chat.id, ...args); 360 | } 361 | /** 362 | * @see https://core.telegram.org/bots/api#deletechatphoto 363 | */ 364 | deleteChatPhoto(...args) { 365 | this.assert(this.chat, "deleteChatPhoto"); 366 | return this.telegram.deleteChatPhoto(this.chat.id, ...args); 367 | } 368 | /** 369 | * @see https://core.telegram.org/bots/api#setchattitle 370 | */ 371 | setChatTitle(...args) { 372 | this.assert(this.chat, "setChatTitle"); 373 | return this.telegram.setChatTitle(this.chat.id, ...args); 374 | } 375 | /** 376 | * @see https://core.telegram.org/bots/api#setchatdescription 377 | */ 378 | setChatDescription(...args) { 379 | this.assert(this.chat, "setChatDescription"); 380 | return this.telegram.setChatDescription(this.chat.id, ...args); 381 | } 382 | /** 383 | * @see https://core.telegram.org/bots/api#pinchatmessage 384 | */ 385 | pinChatMessage(...args) { 386 | this.assert(this.chat, "pinChatMessage"); 387 | return this.telegram.pinChatMessage(this.chat.id, ...args); 388 | } 389 | /** 390 | * @see https://core.telegram.org/bots/api#unpinchatmessage 391 | */ 392 | unpinChatMessage(...args) { 393 | this.assert(this.chat, "unpinChatMessage"); 394 | return this.telegram.unpinChatMessage(this.chat.id, ...args); 395 | } 396 | /** 397 | * @see https://core.telegram.org/bots/api#unpinallchatmessages 398 | */ 399 | unpinAllChatMessages(...args) { 400 | this.assert(this.chat, "unpinAllChatMessages"); 401 | return this.telegram.unpinAllChatMessages(this.chat.id, ...args); 402 | } 403 | /** 404 | * @see https://core.telegram.org/bots/api#leavechat 405 | */ 406 | leaveChat(...args) { 407 | this.assert(this.chat, "leaveChat"); 408 | return this.telegram.leaveChat(this.chat.id, ...args); 409 | } 410 | /** 411 | * @see https://core.telegram.org/bots/api#setchatpermissions 412 | */ 413 | setChatPermissions(...args) { 414 | this.assert(this.chat, "setChatPermissions"); 415 | return this.telegram.setChatPermissions(this.chat.id, ...args); 416 | } 417 | /** 418 | * @see https://core.telegram.org/bots/api#getchatadministrators 419 | */ 420 | getChatAdministrators(...args) { 421 | this.assert(this.chat, "getChatAdministrators"); 422 | return this.telegram.getChatAdministrators(this.chat.id, ...args); 423 | } 424 | /** 425 | * @see https://core.telegram.org/bots/api#getchatmember 426 | */ 427 | getChatMember(...args) { 428 | this.assert(this.chat, "getChatMember"); 429 | return this.telegram.getChatMember(this.chat.id, ...args); 430 | } 431 | /** 432 | * @see https://core.telegram.org/bots/api#getchatmembercount 433 | */ 434 | getChatMembersCount(...args) { 435 | this.assert(this.chat, "getChatMembersCount"); 436 | return this.telegram.getChatMembersCount(this.chat.id, ...args); 437 | } 438 | /** 439 | * @see https://core.telegram.org/bots/api#setpassportdataerrors 440 | */ 441 | setPassportDataErrors(errors) { 442 | this.assert(this.from, "setPassportDataErrors"); 443 | return this.telegram.setPassportDataErrors(this.from.id, errors); 444 | } 445 | /** 446 | * @see https://core.telegram.org/bots/api#sendphoto 447 | */ 448 | sendPhoto(photo, extra) { 449 | this.assert(this.chat, "sendPhoto"); 450 | return this.telegram.sendPhoto(this.chat.id, photo, { 451 | message_thread_id: getThreadId(this), 452 | ...extra, 453 | }); 454 | } 455 | /** 456 | * @see https://core.telegram.org/bots/api#replywithphoto 457 | */ 458 | replyWithPhoto(...args) { 459 | this.assert(this.chat, "replyWithPhoto"); 460 | return this.sendPhoto(...args); 461 | } 462 | replyItWithPhoto(photo, extra) { 463 | return this.replyWithPhoto(photo, { 464 | reply_to_message_id: this.message.message_id, 465 | ...extra, 466 | }); 467 | } 468 | /** 469 | * @see https://core.telegram.org/bots/api#sendmediagroup 470 | */ 471 | sendMediaGroup(media, extra) { 472 | this.assert(this.chat, "sendMediaGroup"); 473 | return this.telegram.sendMediaGroup(this.chat.id, media, { 474 | message_thread_id: getThreadId(this), 475 | ...extra, 476 | }); 477 | } 478 | /** 479 | * @see https://core.telegram.org/bots/api#replywithmediagroup 480 | */ 481 | replyWithMediaGroup(...args) { 482 | this.assert(this.chat, "replyWithMediaGroup"); 483 | return this.sendMediaGroup(...args); 484 | } 485 | /** 486 | * @see https://core.telegram.org/bots/api#sendaudio 487 | */ 488 | sendAudio(audio, extra) { 489 | this.assert(this.chat, "sendAudio"); 490 | return this.telegram.sendAudio(this.chat.id, audio, { 491 | message_thread_id: getThreadId(this), 492 | ...extra, 493 | }); 494 | } 495 | /** 496 | * @see https://core.telegram.org/bots/api#sendaudio 497 | */ 498 | replyWithAudio(...args) { 499 | return this.sendAudio(...args); 500 | } 501 | 502 | replyItWithAudio(audio, extra) { 503 | return this.replyWithAudio(audio, { 504 | reply_to_message_id: this.message.message_id, 505 | ...extra, 506 | }); 507 | } 508 | /** 509 | * @see https://core.telegram.org/bots/api#senddice 510 | */ 511 | sendDice(extra) { 512 | this.assert(this.chat, "sendDice"); 513 | return this.telegram.sendDice(this.chat.id, { 514 | message_thread_id: getThreadId(this), 515 | ...extra, 516 | }); 517 | } 518 | 519 | /** 520 | * @see https://core.telegram.org/bots/api#senddice 521 | */ 522 | replyWithDice(...args) { 523 | return this.sendDice(...args); 524 | } 525 | /** 526 | * @see https://core.telegram.org/bots/api#senddocument 527 | */ 528 | sendDocument(document, extra) { 529 | this.assert(this.chat, "sendDocument"); 530 | return this.telegram.sendDocument(this.chat.id, document, { 531 | message_thread_id: getThreadId(this), 532 | ...extra, 533 | }); 534 | } 535 | /** 536 | * @see https://core.telegram.org/bots/api#senddocument 537 | */ 538 | replyWithDocument(...args) { 539 | return this.sendDocument(...args); 540 | } 541 | replyItWithDocument(doc, extra) { 542 | this.replyWithDocument(doc, { 543 | reply_to_message_id: this.message.message_id, 544 | ...extra, 545 | }); 546 | } 547 | 548 | /** 549 | * @see https://core.telegram.org/bots/api#sendsticker 550 | */ 551 | sendSticker(sticker, extra) { 552 | this.assert(this.chat, "sendSticker"); 553 | return this.telegram.sendSticker(this.chat.id, sticker, { 554 | message_thread_id: getThreadId(this), 555 | ...extra, 556 | }); 557 | } 558 | /** 559 | * @see https://core.telegram.org/bots/api#sendsticker 560 | */ 561 | replyWithSticker(...args) { 562 | return this.sendSticker(...args); 563 | } 564 | replyItWithSticker(sticker, extra) { 565 | return this.replyWithSticker(sticker, { 566 | reply_to_message_id: this.message.message_id, 567 | ...extra, 568 | }); 569 | } 570 | /** 571 | * @see https://core.telegram.org/bots/api#sendvideo 572 | */ 573 | sendVideo(video, extra) { 574 | this.assert(this.chat, "sendVideo"); 575 | return this.telegram.sendVideo(this.chat.id, video, { 576 | message_thread_id: getThreadId(this), 577 | ...extra, 578 | }); 579 | } 580 | /** 581 | * @see https://core.telegram.org/bots/api#sendvideo 582 | */ 583 | replyWithVideo(...args) { 584 | return this.sendVideo(...args); 585 | } 586 | replyItWithVideo(video, extra) { 587 | return this.replyWithVideo(video, { 588 | reply_to_message_id: this.message.message_id, 589 | ...extra, 590 | }); 591 | } 592 | 593 | /** 594 | * @see https://core.telegram.org/bots/api#sendanimation 595 | */ 596 | sendAnimation(animation, extra) { 597 | this.assert(this.chat, "sendAnimation"); 598 | return this.telegram.sendAnimation(this.chat.id, animation, { 599 | message_thread_id: getThreadId(this), 600 | ...extra, 601 | }); 602 | } 603 | /** 604 | * @see https://core.telegram.org/bots/api#sendanimation 605 | */ 606 | replyWithAnimation(...args) { 607 | return this.sendAnimation(...args); 608 | } 609 | replyItWithAnimation(animation, extra) { 610 | return this.replyWithAnimation(animation, { 611 | reply_to_message_id: this.message.message_id, 612 | ...extra, 613 | }); 614 | } 615 | /** 616 | * @see https://core.telegram.org/bots/api#sendvideonote 617 | */ 618 | sendVideoNote(videoNote, extra) { 619 | this.assert(this.chat, "sendVideoNote"); 620 | return this.telegram.sendVideoNote(this.chat.id, videoNote, { 621 | message_thread_id: getThreadId(this), 622 | ...extra, 623 | }); 624 | } 625 | /** 626 | * @see https://core.telegram.org/bots/api#sendvideonote 627 | */ 628 | replyWithVideoNote(...args) { 629 | return this.sendVideoNote(...args); 630 | } 631 | /** 632 | * @see https://core.telegram.org/bots/api#sendinvoice 633 | */ 634 | sendInvoice(invoice, extra) { 635 | this.assert(this.chat, "sendInvoice"); 636 | return this.telegram.sendInvoice(this.chat.id, invoice, { 637 | message_thread_id: getThreadId(this), 638 | ...extra, 639 | }); 640 | } 641 | /** 642 | * @see https://core.telegram.org/bots/api#sendinvoice 643 | */ 644 | replyWithInvoice(...args) { 645 | return this.sendInvoice(...args); 646 | } 647 | /** 648 | * @see https://core.telegram.org/bots/api#sendgame 649 | */ 650 | sendGame(game, extra) { 651 | this.assert(this.chat, "sendGame"); 652 | return this.telegram.sendGame(this.chat.id, game, { 653 | message_thread_id: getThreadId(this), 654 | ...extra, 655 | }); 656 | } 657 | /** 658 | * @see https://core.telegram.org/bots/api#sendgame 659 | */ 660 | replyWithGame(...args) { 661 | return this.sendGame(...args); 662 | } 663 | /** 664 | * @see https://core.telegram.org/bots/api#sendvoice 665 | */ 666 | sendVoice(voice, extra) { 667 | this.assert(this.chat, "sendVoice"); 668 | return this.telegram.sendVoice(this.chat.id, voice, { 669 | message_thread_id: getThreadId(this), 670 | ...extra, 671 | }); 672 | } 673 | /** 674 | * @see https://core.telegram.org/bots/api#sendvoice 675 | */ 676 | replyWithVoice(...args) { 677 | return this.sendVoice(...args); 678 | } 679 | 680 | /** 681 | * @see https://core.telegram.org/bots/api#sendpoll 682 | */ 683 | sendPoll(poll, options, extra) { 684 | this.assert(this.chat, "sendPoll"); 685 | return this.telegram.sendPoll(this.chat.id, poll, options, { 686 | message_thread_id: getThreadId(this), 687 | ...extra, 688 | }); 689 | } 690 | /** 691 | * @see https://core.telegram.org/bots/api#sendpoll 692 | */ 693 | replyWithPoll(...args) { 694 | return this.sendPoll(...args); 695 | } 696 | /** 697 | * @see https://core.telegram.org/bots/api#sendpoll 698 | */ 699 | sendQuiz(quiz, options, extra) { 700 | this.assert(this.chat, "sendQuiz"); 701 | return this.telegram.sendQuiz(this.chat.id, quiz, options, { 702 | message_thread_id: getThreadId(this), 703 | ...extra, 704 | }); 705 | } 706 | /** 707 | * @see https://core.telegram.org/bots/api#sendpoll 708 | */ 709 | replyWithQuiz(...args) { 710 | return this.sendQuiz(...args); 711 | } 712 | /** 713 | * @see https://core.telegram.org/bots/api#stoppoll 714 | */ 715 | stopPoll(...args) { 716 | this.assert(this.chat, "stopPoll"); 717 | return this.telegram.stopPoll(this.chat.id, ...args); 718 | } 719 | 720 | /** 721 | * @see https://core.telegram.org/bots/api#sendchataction 722 | */ 723 | sendChatAction(action, extra) { 724 | this.assert(this.chat, "sendChatAction"); 725 | return this.telegram.sendChatAction(this.chat.id, action, { 726 | message_thread_id: getThreadId(this), 727 | ...extra, 728 | }); 729 | } 730 | 731 | /** 732 | * @see https://core.telegram.org/bots/api#replywithchataction 733 | */ 734 | replyWithChatAction(...args) { 735 | this.assert(this.chat, "replyWithChatAction"); 736 | return this.sendChatAction(this.chat.id, ...args); 737 | } 738 | /** 739 | * @see https://core.telegram.org/bots/api#replywithlocation 740 | */ 741 | replyWithLocation(...args) { 742 | this.assert(this.chat, "replyWithLocation"); 743 | return this.telegram.sendLocation(this.chat.id, ...args); 744 | } 745 | 746 | replyItWithLocation(latitude, longitude, extra) { 747 | return this.replyWithLocation(latitude, longitude, { 748 | reply_to_message_id: this.message.message_id, 749 | ...extra, 750 | }); 751 | } 752 | /** 753 | * @see https://core.telegram.org/bots/api#sendvenue 754 | */ 755 | sendVenue(latitude, longitude, title, address, extra) { 756 | this.assert(this.chat, "sendVenue"); 757 | return this.telegram.sendVenue( 758 | this.chat.id, 759 | latitude, 760 | longitude, 761 | title, 762 | address, 763 | { message_thread_id: getThreadId(this), ...extra }, 764 | ); 765 | } 766 | /** 767 | * @see https://core.telegram.org/bots/api#sendvenue 768 | */ 769 | replyWithVenue(...args) { 770 | return this.sendVenue(...args); 771 | } 772 | /** 773 | * @see https://core.telegram.org/bots/api#sendcontact 774 | */ 775 | sendContact(phoneNumber, firstName, extra) { 776 | this.assert(this.chat, "sendContact"); 777 | return this.telegram.sendContact(this.chat.id, phoneNumber, firstName, { 778 | message_thread_id: getThreadId(this), 779 | ...extra, 780 | }); 781 | } 782 | /** 783 | * @see https://core.telegram.org/bots/api#sendcontact 784 | */ 785 | replyWithContact(...args) { 786 | return this.sendContact(...args); 787 | } 788 | 789 | /** 790 | * Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this 791 | * to work and must have the can_manage_topics administrator rights. Returns information about the created topic as a 792 | * ForumTopic object. 793 | * 794 | * @see https://core.telegram.org/bots/api#createforumtopic 795 | */ 796 | createForumTopic(...args) { 797 | this.assert(this.chat, "createForumTopic"); 798 | return this.telegram.createForumTopic(this.chat.id, ...args); 799 | } 800 | /** 801 | * Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must be an administrator in 802 | * the chat for this to work and must have can_manage_topics administrator rights, unless it is the creator of the 803 | * topic. Returns True on success. 804 | * 805 | * @see https://core.telegram.org/bots/api#editforumtopic 806 | */ 807 | editForumTopic(extra) { 808 | this.assert(this.chat, "editForumTopic"); 809 | this.assert(this.message?.message_thread_id, "editForumTopic"); 810 | return this.telegram.editForumTopic( 811 | this.chat.id, 812 | this.message.message_thread_id, 813 | extra, 814 | ); 815 | } 816 | /** 817 | * Use this method to close an open topic in a forum supergroup chat. The bot must be an administrator in the chat 818 | * for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. 819 | * Returns True on success. 820 | * 821 | * @see https://core.telegram.org/bots/api#closeforumtopic 822 | */ 823 | closeForumTopic() { 824 | this.assert(this.chat, "closeForumTopic"); 825 | this.assert(this.message?.message_thread_id, "closeForumTopic"); 826 | return this.telegram.closeForumTopic( 827 | this.chat.id, 828 | this.message.message_thread_id, 829 | ); 830 | } 831 | /** 832 | * Use this method to reopen a closed topic in a forum supergroup chat. The bot must be an administrator in the chat 833 | * for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. 834 | * Returns True on success. 835 | * 836 | * @see https://core.telegram.org/bots/api#reopenforumtopic 837 | */ 838 | reopenForumTopic() { 839 | this.assert(this.chat, "reopenForumTopic"); 840 | this.assert(this.message?.message_thread_id, "reopenForumTopic"); 841 | return this.telegram.reopenForumTopic( 842 | this.chat.id, 843 | this.message.message_thread_id, 844 | ); 845 | } 846 | /** 847 | * Use this method to delete a forum topic along with all its messages in a forum supergroup chat. The bot must be an 848 | * administrator in the chat for this to work and must have the can_delete_messages administrator rights. 849 | * Returns True on success. 850 | * 851 | * @see https://core.telegram.org/bots/api#deleteforumtopic 852 | */ 853 | deleteForumTopic() { 854 | this.assert(this.chat, "deleteForumTopic"); 855 | this.assert(this.message?.message_thread_id, "deleteForumTopic"); 856 | return this.telegram.deleteForumTopic( 857 | this.chat.id, 858 | this.message.message_thread_id, 859 | ); 860 | } 861 | /** 862 | * Use this method to clear the list of pinned messages in a forum topic. The bot must be an administrator in the chat 863 | * for this to work and must have the can_pin_messages administrator right in the supergroup. Returns True on success. 864 | * 865 | * @see https://core.telegram.org/bots/api#unpinallforumtopicmessages 866 | */ 867 | unpinAllForumTopicMessages() { 868 | this.assert(this.chat, "unpinAllForumTopicMessages"); 869 | this.assert(this.message?.message_thread_id, "unpinAllForumTopicMessages"); 870 | return this.telegram.unpinAllForumTopicMessages( 871 | this.chat.id, 872 | this.message.message_thread_id, 873 | ); 874 | } 875 | /** 876 | * Use this method to edit the name of the 'General' topic in a forum supergroup chat. The bot must be an administrator 877 | * in the chat for this to work and must have can_manage_topics administrator rights. Returns True on success. 878 | * 879 | * @see https://core.telegram.org/bots/api#editgeneralforumtopic 880 | */ 881 | editGeneralForumTopic(name) { 882 | this.assert(this.chat, "editGeneralForumTopic"); 883 | return this.telegram.editGeneralForumTopic(this.chat.id, name); 884 | } 885 | /** 886 | * Use this method to close an open 'General' topic in a forum supergroup chat. The bot must be an administrator in the 887 | * chat for this to work and must have the can_manage_topics administrator rights. Returns True on success. 888 | * 889 | * @see https://core.telegram.org/bots/api#closegeneralforumtopic 890 | */ 891 | closeGeneralForumTopic() { 892 | this.assert(this.chat, "closeGeneralForumTopic"); 893 | return this.telegram.closeGeneralForumTopic(this.chat.id); 894 | } 895 | /** 896 | * Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must be an administrator in 897 | * the chat for this to work and must have the can_manage_topics administrator rights. The topic will be automatically 898 | * unhidden if it was hidden. Returns True on success. 899 | * 900 | * @see https://core.telegram.org/bots/api#reopengeneralforumtopic 901 | */ 902 | reopenGeneralForumTopic() { 903 | this.assert(this.chat, "reopenGeneralForumTopic"); 904 | return this.telegram.reopenGeneralForumTopic(this.chat.id); 905 | } 906 | /** 907 | * Use this method to hide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat 908 | * for this to work and must have the can_manage_topics administrator rights. The topic will be automatically closed 909 | * if it was open. Returns True on success. 910 | * 911 | * @see https://core.telegram.org/bots/api#hidegeneralforumtopic 912 | */ 913 | hideGeneralForumTopic() { 914 | this.assert(this.chat, "hideGeneralForumTopic"); 915 | return this.telegram.hideGeneralForumTopic(this.chat.id); 916 | } 917 | /** 918 | * Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the 919 | * chat for this to work and must have the can_manage_topics administrator rights. Returns True on success. 920 | * 921 | * @see https://core.telegram.org/bots/api#unhidegeneralforumtopic 922 | */ 923 | unhideGeneralForumTopic() { 924 | this.assert(this.chat, "unhideGeneralForumTopic"); 925 | return this.telegram.unhideGeneralForumTopic(this.chat.id); 926 | } 927 | /** 928 | * Use this method to clear the list of pinned messages in a General forum topic. 929 | * The bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator 930 | * right in the supergroup. 931 | * 932 | * @param chat_id Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) 933 | * 934 | * @see https://core.telegram.org/bots/api#unpinallgeneralforumtopicmessages 935 | */ 936 | unpinAllGeneralForumTopicMessages() { 937 | this.assert(this.chat, "unpinAllGeneralForumTopicMessages"); 938 | return this.telegram.unpinAllGeneralForumTopicMessages(this.chat.id); 939 | } 940 | 941 | /** 942 | * @deprecated use {@link Telegram.getStickerSet} 943 | * @see https://core.telegram.org/bots/api#getstickerset 944 | */ 945 | getStickerSet(setName) { 946 | return this.telegram.getStickerSet(setName); 947 | } 948 | /** 949 | * @see https://core.telegram.org/bots/api#setchatstickerset 950 | */ 951 | setChatStickerSet(setName) { 952 | this.assert(this.chat, "setChatStickerSet"); 953 | return this.telegram.setChatStickerSet(this.chat.id, setName); 954 | } 955 | /** 956 | * @see https://core.telegram.org/bots/api#deletechatstickerset 957 | */ 958 | deleteChatStickerSet() { 959 | this.assert(this.chat, "deleteChatStickerSet"); 960 | return this.telegram.deleteChatStickerSet(this.chat.id); 961 | } 962 | /** 963 | * @deprecated use {@link Telegram.setStickerPositionInSet} 964 | * @see https://core.telegram.org/bots/api#setstickerpositioninset 965 | */ 966 | setStickerPositionInSet(sticker, position) { 967 | return this.telegram.setStickerPositionInSet(sticker, position); 968 | } 969 | /** 970 | * @deprecated use {@link Telegram.setStickerSetThumb} 971 | * @see https://core.telegram.org/bots/api#setstickersetthumb 972 | */ 973 | setStickerSetThumb(...args) { 974 | return this.telegram.setStickerSetThumb(...args); 975 | } 976 | /** 977 | * @deprecated use {@link Telegram.deleteStickerFromSet} 978 | * @see https://core.telegram.org/bots/api#deletestickerfromset 979 | */ 980 | deleteStickerFromSet(sticker) { 981 | return this.telegram.deleteStickerFromSet(sticker); 982 | } 983 | /** 984 | * @see https://core.telegram.org/bots/api#uploadstickerfile 985 | */ 986 | uploadStickerFile(...args) { 987 | this.assert(this.from, "uploadStickerFile"); 988 | return this.telegram.uploadStickerFile(this.from.id, ...args); 989 | } 990 | /** 991 | * @see https://core.telegram.org/bots/api#createnewstickerset 992 | */ 993 | createNewStickerSet(...args) { 994 | this.assert(this.from, "createNewStickerSet"); 995 | return this.telegram.createNewStickerSet(this.from.id, ...args); 996 | } 997 | /** 998 | * @see https://core.telegram.org/bots/api#addstickertoset 999 | */ 1000 | addStickerToSet(...args) { 1001 | this.assert(this.from, "addStickerToSet"); 1002 | return this.telegram.addStickerToSet(this.from.id, ...args); 1003 | } 1004 | /** 1005 | * @deprecated use {@link Telegram.getMyCommands} 1006 | * @see https://core.telegram.org/bots/api#getmycommands 1007 | */ 1008 | getMyCommands() { 1009 | return this.telegram.getMyCommands(); 1010 | } 1011 | /** 1012 | * @deprecated use {@link Telegram.setMyCommands} 1013 | * @see https://core.telegram.org/bots/api#setmycommands 1014 | */ 1015 | setMyCommands(commands) { 1016 | return this.telegram.setMyCommands(commands); 1017 | } 1018 | /** 1019 | * @see https://core.telegram.org/bots/api#sendmessage 1020 | */ 1021 | replyWithMarkdown(markdown, extra) { 1022 | return this.reply(markdown, { parse_mode: "Markdown", ...extra }); 1023 | } 1024 | replyItWithMarkdown(markdown, extra) { 1025 | return this.replyIt(markdown, { parse_mode: "Markdown", ...extra }); 1026 | } 1027 | /** 1028 | * @see https://core.telegram.org/bots/api#sendmessage 1029 | */ 1030 | replyWithMarkdownV2(markdown, extra) { 1031 | return this.reply(markdown, { parse_mode: "MarkdownV2", ...extra }); 1032 | } 1033 | replyItWithMarkdownV2(markdown, extra) { 1034 | return this.replyIt(markdown, { parse_mode: "MarkdownV2", ...extra }); 1035 | } 1036 | /** 1037 | * @see https://core.telegram.org/bots/api#sendmessage 1038 | */ 1039 | replyWithHTML(html, extra) { 1040 | return this.reply(html, { parse_mode: "HTML", ...extra }); 1041 | } 1042 | replyItWithHTML(text, extra) { 1043 | return this.replyIt(text, { parse_mode: "HTML", ...extra }); 1044 | } 1045 | /** 1046 | * @see https://core.telegram.org/bots/api#deletemessage 1047 | */ 1048 | deleteMessage(messageId) { 1049 | this.assert(this.chat, "deleteMessage"); 1050 | if (typeof messageId !== "undefined") { 1051 | return this.telegram.deleteMessage(this.chat.id, messageId); 1052 | } 1053 | const message = getMessageFromAnySource(this); 1054 | this.assert(message, "deleteMessage"); 1055 | return this.telegram.deleteMessage(this.chat.id, message.message_id); 1056 | } 1057 | /** 1058 | * Context-aware shorthand for {@link Telegram.deleteMessages} 1059 | * @param messageIds Identifiers of 1-100 messages to delete. See deleteMessage for limitations on which messages can be deleted 1060 | */ 1061 | deleteMessages(messageIds) { 1062 | this.assert(this.chat, "deleteMessages"); 1063 | return this.telegram.deleteMessages(this.chat.id, messageIds); 1064 | } 1065 | /** 1066 | * @see https://core.telegram.org/bots/api#forwardmessage 1067 | */ 1068 | forwardMessage(chatId, extra) { 1069 | const message = getMessageFromAnySource(this); 1070 | this.assert(message, "forwardMessage"); 1071 | return this.telegram.forwardMessage( 1072 | chatId, 1073 | message.chat.id, 1074 | message.message_id, 1075 | extra, 1076 | ); 1077 | } 1078 | /** 1079 | * Shorthand for {@link Telegram.forwardMessages} 1080 | * @see https://core.telegram.org/bots/api#forwardmessages 1081 | */ 1082 | forwardMessages(chatId, messageIds, extra) { 1083 | this.assert(this.chat, "forwardMessages"); 1084 | return this.telegram.forwardMessages( 1085 | chatId, 1086 | this.chat.id, 1087 | messageIds, 1088 | extra, 1089 | ); 1090 | } 1091 | /** 1092 | * @see https://core.telegram.org/bots/api#copymessage 1093 | */ 1094 | copyMessage(chatId, extra) { 1095 | const message = getMessageFromAnySource(this); 1096 | this.assert(message, "copyMessage"); 1097 | return this.telegram.copyMessage( 1098 | chatId, 1099 | message.chat.id, 1100 | message.message_id, 1101 | extra, 1102 | ); 1103 | } 1104 | /** 1105 | * Context-aware shorthand for {@link Telegram.copyMessages} 1106 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 1107 | * @param messageIds Identifiers of 1-100 messages in the chat from_chat_id to copy. The identifiers must be specified in a strictly increasing order. 1108 | */ 1109 | copyMessages(chatId, messageIds, extra) { 1110 | var _a; 1111 | this.assert(this.chat, "copyMessages"); 1112 | return this.telegram.copyMessages(chatId, this.chat?.id, messageIds, extra); 1113 | } 1114 | /** 1115 | * @see https://core.telegram.org/bots/api#approvechatjoinrequest 1116 | */ 1117 | approveChatJoinRequest(...args) { 1118 | this.assert(this.chat, "approveChatJoinRequest"); 1119 | return this.telegram.approveChatJoinRequest(message.chat.id, ...args); 1120 | } 1121 | 1122 | /** 1123 | * @see https://core.telegram.org/bots/api#declinechatjoinrequest 1124 | */ 1125 | declineChatJoinRequest(...args) { 1126 | this.assert(this.chat, "declineChatJoinRequest"); 1127 | return this.telegram.declineChatJoinRequest(message.chat.id, ...args); 1128 | } 1129 | 1130 | /** 1131 | * @see https://core.telegram.org/bots/api#banchatsenderchat 1132 | */ 1133 | banChatSenderChat(...args) { 1134 | this.assert(this.chat, "banChatSenderChat"); 1135 | return this.telegram.banChatSenderChat(this.chat.id, ...args); 1136 | } 1137 | 1138 | /** 1139 | * @see https://core.telegram.org/bots/api#unbanchatsenderchat 1140 | */ 1141 | unbanChatSenderChat(...args) { 1142 | this.assert(this.chat, "unbanChatSenderChat"); 1143 | return this.telegram.unbanChatSenderChat(this.chat.id, ...args); 1144 | } 1145 | /** 1146 | * Use this method to change the bot's menu button in the current private chat. Returns true on success. 1147 | * @see https://core.telegram.org/bots/api#setchatmenubutton 1148 | */ 1149 | setChatMenuButton(menuButton) { 1150 | this.assert(this.chat, "setChatMenuButton"); 1151 | return this.telegram.setChatMenuButton({ 1152 | chatId: this.chat.id, 1153 | menuButton, 1154 | }); 1155 | } 1156 | /** 1157 | * Use this method to get the current value of the bot's menu button in the current private chat. Returns MenuButton on success. 1158 | * @see https://core.telegram.org/bots/api#getchatmenubutton 1159 | */ 1160 | getChatMenuButton() { 1161 | this.assert(this.chat, "getChatMenuButton"); 1162 | return this.telegram.getChatMenuButton({ chatId: this.chat.id }); 1163 | } 1164 | /** 1165 | * @see https://core.telegram.org/bots/api#setmydefaultadministratorrights 1166 | */ 1167 | setMyDefaultAdministratorRights(extra) { 1168 | return this.telegram.setMyDefaultAdministratorRights(extra); 1169 | } 1170 | /** 1171 | * @see https://core.telegram.org/bots/api#getmydefaultadministratorrights 1172 | */ 1173 | getMyDefaultAdministratorRights(extra) { 1174 | return this.telegram.getMyDefaultAdministratorRights(extra); 1175 | } 1176 | } 1177 | 1178 | function getMessageFromAnySource(ctx) { 1179 | return ( 1180 | ctx.message ?? 1181 | ctx.editedMessage ?? 1182 | ctx.callbackQuery?.message ?? 1183 | ctx.channelPost ?? 1184 | ctx.editedChannelPost 1185 | ); 1186 | } 1187 | 1188 | function getThreadId(ctx) { 1189 | const msg = ctx.msg; 1190 | return msg?.isAccessible() 1191 | ? msg.is_topic_message 1192 | ? msg.message_thread_id 1193 | : undefined 1194 | : undefined; 1195 | } 1196 | -------------------------------------------------------------------------------- /core/60 telegram.js: -------------------------------------------------------------------------------- 1 | /* 2 | Class untuk method berhubungan dengan telegram client 3 | 4 | - penambahan method answerCallbackQuery, karena dibuat aliasnya 5 | - metode konstruktor disederhanakan 6 | */ 7 | 8 | class Telegram extends Client { 9 | constructor(token) { 10 | super(); 11 | this.token = token; 12 | } 13 | 14 | /** 15 | * Get basic information about the bot 16 | */ 17 | getMe() { 18 | return this.callApi("getMe", {}); 19 | } 20 | /** 21 | * Get basic info about a file and prepare it for downloading 22 | * @param fileId Id of file to get link to 23 | */ 24 | getFile(fileId) { 25 | return this.callApi("getFile", { file_id: fileId }); 26 | } 27 | /** 28 | * Get download link to a file 29 | */ 30 | getFileLink(fileId) { 31 | return Promise.resolve(fileId) 32 | .then((fileId) => { 33 | if (fileId && fileId.file_path) { 34 | return fileId; 35 | } 36 | const id = fileId && fileId.file_id ? fileId.file_id : fileId; 37 | return this.getFile(id); 38 | }) 39 | .then( 40 | (file) => 41 | `${this.options.apiRoot}/file/bot${this.token}/${file.file_path}`, 42 | ); 43 | } 44 | /** 45 | * Directly request incoming updates. 46 | * You should probably use `Telegraf::launch` instead. 47 | */ 48 | getUpdates(timeout, limit, offset, allowedUpdates) { 49 | return this.callApi("getUpdates", { 50 | allowed_updates: allowedUpdates, 51 | limit, 52 | offset, 53 | timeout, 54 | }); 55 | } 56 | getWebhookInfo() { 57 | return this.callApi("getWebhookInfo", {}); 58 | } 59 | getGameHighScores(userId, inlineMessageId, chatId, messageId) { 60 | return this.callApi("getGameHighScores", { 61 | user_id: userId, 62 | inline_message_id: inlineMessageId, 63 | chat_id: chatId, 64 | message_id: messageId, 65 | }); 66 | } 67 | setGameScore( 68 | userId, 69 | score, 70 | inlineMessageId, 71 | chatId, 72 | messageId, 73 | editMessage = true, 74 | force = false, 75 | ) { 76 | return this.callApi("setGameScore", { 77 | force, 78 | score, 79 | user_id: userId, 80 | inline_message_id: inlineMessageId, 81 | chat_id: chatId, 82 | message_id: messageId, 83 | disable_edit_message: !editMessage, 84 | }); 85 | } 86 | /** 87 | * Specify a url to receive incoming updates via an outgoing webhook 88 | * @param url HTTPS url to send updates to. Use an empty string to remove webhook integration 89 | */ 90 | setWebhook(url, extra) { 91 | return this.callApi("setWebhook", { 92 | url, 93 | ...extra, 94 | }); 95 | } 96 | /** 97 | * Remove webhook integration 98 | */ 99 | deleteWebhook(extra) { 100 | return this.callApi("deleteWebhook", { 101 | ...extra, 102 | }); 103 | } 104 | /** 105 | * Send a text message 106 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 107 | * @param text Text of the message to be sent 108 | */ 109 | sendMessage(chatId, text, extra) { 110 | return this.callApi("sendMessage", { chat_id: chatId, text, ...extra }); 111 | } 112 | /** 113 | * Forward existing message. 114 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 115 | * @param fromChatId Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername) 116 | * @param messageId Message identifier in the chat specified in from_chat_id 117 | */ 118 | forwardMessage(chatId, fromChatId, messageId, extra) { 119 | return this.callApi("forwardMessage", { 120 | chat_id: chatId, 121 | from_chat_id: fromChatId, 122 | message_id: messageId, 123 | ...extra, 124 | }); 125 | } 126 | 127 | /** 128 | * Use this method to forward multiple messages of any kind. If some of the specified messages can't be found or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. Album grouping is kept for forwarded messages. 129 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 130 | * @param fromChatId Unique identifier for the chat where the original messages were sent (or channel username in the format @channelusername) 131 | * @param messageIds Identifiers of 1-100 messages in the chat from_chat_id to forward. The identifiers must be specified in a strictly increasing order. 132 | */ 133 | forwardMessages(chatId, fromChatId, messageIds, extra) { 134 | return this.callApi("forwardMessages", { 135 | chat_id: chatId, 136 | from_chat_id: fromChatId, 137 | message_ids: messageIds, 138 | ...extra, 139 | }); 140 | } 141 | 142 | /** 143 | * Use this method when you need to tell the user that something is happening on the bot's side. 144 | * The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). 145 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 146 | */ 147 | sendChatAction(chatId, action, extra) { 148 | return this.callApi("sendChatAction", { 149 | chat_id: chatId, 150 | action, 151 | ...extra, 152 | }); 153 | } 154 | 155 | /** 156 | * Use this method to change the chosen reactions on a message. Service messages can't be reacted to. 157 | * Automatically forwarded messages from a channel to its discussion group have the same available 158 | * reactions as messages in the channel. In albums, bots must react to the first message. 159 | * @param chat_id Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) 160 | * @param message_id Identifier of the target message 161 | * @param reaction New list of reaction types to set on the message. Currently, as non-premium users, bots can set up 162 | * to one reaction per message. A custom emoji reaction can be used if it is either already present on the message 163 | * or explicitly allowed by chat administrators. 164 | * @param is_big Pass True to set the reaction with a big animation 165 | * @returns 166 | */ 167 | setMessageReaction(chatId, messageId, reaction, is_big) { 168 | return this.callApi("setMessageReaction", { 169 | chatId, 170 | messageId, 171 | reaction, 172 | is_big, 173 | }); 174 | } 175 | 176 | getUserProfilePhotos(userId, offset, limit) { 177 | return this.callApi("getUserProfilePhotos", { 178 | user_id: userId, 179 | offset, 180 | limit, 181 | }); 182 | } 183 | /** 184 | * Send point on the map 185 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 186 | */ 187 | sendLocation(chatId, latitude, longitude, extra) { 188 | return this.callApi("sendLocation", { 189 | chat_id: chatId, 190 | latitude, 191 | longitude, 192 | ...extra, 193 | }); 194 | } 195 | sendVenue(chatId, latitude, longitude, title, address, extra) { 196 | return this.callApi("sendVenue", { 197 | latitude, 198 | longitude, 199 | title, 200 | address, 201 | chat_id: chatId, 202 | ...extra, 203 | }); 204 | } 205 | /** 206 | * @param chatId Unique identifier for the target private chat 207 | */ 208 | sendInvoice(chatId, invoice, extra) { 209 | return this.callApi("sendInvoice", { 210 | chat_id: chatId, 211 | ...invoice, 212 | ...extra, 213 | }); 214 | } 215 | sendContact(chatId, phoneNumber, firstName, extra) { 216 | return this.callApi("sendContact", { 217 | chat_id: chatId, 218 | phone_number: phoneNumber, 219 | first_name: firstName, 220 | ...extra, 221 | }); 222 | } 223 | /** 224 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 225 | */ 226 | sendPhoto(chatId, photo, extra) { 227 | return this.callApi("sendPhoto", { chat_id: chatId, photo, ...extra }); 228 | } 229 | /** 230 | * Send a dice, which will have a random value from 1 to 6. 231 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 232 | */ 233 | sendDice(chatId, extra) { 234 | return this.callApi("sendDice", { chat_id: chatId, ...extra }); 235 | } 236 | /** 237 | * Send general files. Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future. 238 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 239 | */ 240 | sendDocument(chatId, document, extra) { 241 | return this.callApi("sendDocument", { 242 | chat_id: chatId, 243 | document, 244 | ...extra, 245 | }); 246 | } 247 | /** 248 | * Send audio files, if you want Telegram clients to display them in the music player. 249 | * Your audio must be in the .mp3 format. 250 | * Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future. 251 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 252 | */ 253 | sendAudio(chatId, audio, extra) { 254 | return this.callApi("sendAudio", { chat_id: chatId, audio, ...extra }); 255 | } 256 | /** 257 | * Send .webp stickers 258 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 259 | */ 260 | sendSticker(chatId, sticker, extra) { 261 | return this.callApi("sendSticker", { chat_id: chatId, sticker, ...extra }); 262 | } 263 | /** 264 | * Send video files, Telegram clients support mp4 videos (other formats may be sent as Document) 265 | * Bots can currently send video files of up to 50 MB in size, this limit may be changed in the future. 266 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 267 | */ 268 | sendVideo(chatId, video, extra) { 269 | return this.callApi("sendVideo", { chat_id: chatId, video, ...extra }); 270 | } 271 | /** 272 | * Send .gif animations 273 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 274 | */ 275 | sendAnimation(chatId, animation, extra) { 276 | return this.callApi("sendAnimation", { 277 | chat_id: chatId, 278 | animation, 279 | ...extra, 280 | }); 281 | } 282 | /** 283 | * Send video messages 284 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 285 | */ 286 | sendVideoNote(chatId, videoNote, extra) { 287 | return this.callApi("sendVideoNote", { 288 | chat_id: chatId, 289 | video_note: videoNote, 290 | ...extra, 291 | }); 292 | } 293 | /** 294 | * Send audio files, if you want Telegram clients to display the file as a playable voice message. For this to work, your audio must be in an .ogg file encoded with OPUS (other formats may be sent as Audio or Document). On success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future. 295 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 296 | */ 297 | sendVoice(chatId, voice, extra) { 298 | return this.callApi("sendVoice", { chat_id: chatId, voice, ...extra }); 299 | } 300 | /** 301 | * @param chatId Unique identifier for the target chat 302 | * @param gameShortName Short name of the game, serves as the unique identifier for the game. Set up your games via Botfather. 303 | */ 304 | sendGame(chatId, gameName, extra) { 305 | return this.callApi("sendGame", { 306 | chat_id: chatId, 307 | game_short_name: gameName, 308 | ...extra, 309 | }); 310 | } 311 | /** 312 | * Send a group of photos or videos as an album 313 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 314 | * @param media A JSON-serialized array describing photos and videos to be sent, must include 2–10 items 315 | */ 316 | sendMediaGroup(chatId, media, extra) { 317 | return this.callApi("sendMediaGroup", { chat_id: chatId, media, ...extra }); 318 | } 319 | /** 320 | * Send a native poll. 321 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 322 | * @param question Poll question, 1-255 characters 323 | * @param options A JSON-serialized list of answer options, 2-10 strings 1-100 characters each 324 | */ 325 | sendPoll(chatId, question, options, extra) { 326 | return this.callApi("sendPoll", { 327 | chat_id: chatId, 328 | type: "regular", 329 | question, 330 | options, 331 | ...extra, 332 | }); 333 | } 334 | /** 335 | * Send a native quiz. 336 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 337 | * @param question Poll question, 1-255 characters 338 | * @param options A JSON-serialized list of answer options, 2-10 strings 1-100 characters each 339 | */ 340 | sendQuiz(chatId, question, options, extra) { 341 | return this.callApi("sendPoll", { 342 | chat_id: chatId, 343 | type: "quiz", 344 | question, 345 | options, 346 | ...extra, 347 | }); 348 | } 349 | /** 350 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 351 | * @param messageId Identifier of the original message with the poll 352 | */ 353 | stopPoll(chatId, messageId, extra) { 354 | return this.callApi("stopPoll", { 355 | chat_id: chatId, 356 | message_id: messageId, 357 | ...extra, 358 | }); 359 | } 360 | /** 361 | * Get up to date information about the chat (current name of the user for one-on-one conversations, current username of a user, group or channel, etc.) 362 | * @param chatId Unique identifier for the target chat or username of the target supergroup or channel (in the format @channelusername) 363 | */ 364 | getChat(chatId) { 365 | return this.callApi("getChat", { chat_id: chatId }); 366 | } 367 | /** 368 | * @param chatId Unique identifier for the target chat or username of the target supergroup or channel (in the format @channelusername) 369 | */ 370 | getChatAdministrators(chatId) { 371 | return this.callApi("getChatAdministrators", { chat_id: chatId }); 372 | } 373 | /** 374 | * Get information about a member of a chat. 375 | * @param chatId Unique identifier for the target chat or username of the target supergroup or channel (in the format @channelusername) 376 | * @param userId Unique identifier of the target user 377 | */ 378 | getChatMember(chatId, userId) { 379 | return this.callApi("getChatMember", { chat_id: chatId, user_id: userId }); 380 | } 381 | /** 382 | * Get the number of members in a chat 383 | * @param chatId Unique identifier for the target chat or username of the target supergroup or channel (in the format @channelusername) 384 | */ 385 | getChatMembersCount(chatId) { 386 | return this.callApi("getChatMembersCount", { chat_id: chatId }); 387 | } 388 | /** 389 | * Send answers to an inline query. 390 | * No more than 50 results per query are allowed. 391 | */ 392 | answerInlineQuery(inlineQueryId, results, extra) { 393 | return this.callApi("answerInlineQuery", { 394 | inline_query_id: inlineQueryId, 395 | results, 396 | ...extra, 397 | }); 398 | } 399 | setChatPermissions(chatId, permissions) { 400 | return this.callApi("setChatPermissions", { chat_id: chatId, permissions }); 401 | } 402 | /** 403 | * Kick a user from a group, a supergroup or a channel. In the case of supergroups and channels, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights 404 | * @param chatId Unique identifier for the target group or username of the target supergroup or channel (in the format `@channelusername`) 405 | * @param untilDate Date when the user will be unbanned, unix time. If user is banned for more than 366 days or less than 30 seconds from the current time they are considered to be banned forever 406 | */ 407 | banChatMember(chatId, userId, extra) { 408 | return this.callApi("banChatMember", { 409 | chat_id: chatId, 410 | user_id: userId, 411 | ...extra, 412 | }); 413 | } 414 | /** 415 | * Promote or demote a user in a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Pass False for all boolean parameters to demote a user. 416 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) 417 | */ 418 | promoteChatMember(chatId, userId, extra) { 419 | return this.callApi("promoteChatMember", { 420 | chat_id: chatId, 421 | user_id: userId, 422 | ...extra, 423 | }); 424 | } 425 | /** 426 | * Restrict a user in a supergroup. The bot must be an administrator in the supergroup for this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift restrictions from a user. 427 | * @param chatId Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) 428 | */ 429 | restrictChatMember(chatId, userId, extra) { 430 | return this.callApi("restrictChatMember", { 431 | chat_id: chatId, 432 | user_id: userId, 433 | ...extra, 434 | }); 435 | } 436 | setChatAdministratorCustomTitle(chatId, userId, title) { 437 | return this.callApi("setChatAdministratorCustomTitle", { 438 | chat_id: chatId, 439 | user_id: userId, 440 | custom_title: title, 441 | }); 442 | } 443 | /** 444 | * Export an invite link to a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. 445 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 446 | */ 447 | exportChatInviteLink(chatId) { 448 | return this.callApi("exportChatInviteLink", { chat_id: chatId }); 449 | } 450 | createChatInviteLink(chatId, extra) { 451 | return this.callApi("createChatInviteLink", { 452 | chat_id: chatId, 453 | ...extra, 454 | }); 455 | } 456 | editChatInviteLink(chatId, inviteLink, extra) { 457 | return this.callApi("editChatInviteLink", { 458 | chat_id: chatId, 459 | invite_link: inviteLink, 460 | ...extra, 461 | }); 462 | } 463 | revokeChatInviteLink(chatId, inviteLink) { 464 | return this.callApi("revokeChatInviteLink", { 465 | chat_id: chatId, 466 | invite_link: inviteLink, 467 | }); 468 | } 469 | setChatPhoto(chatId, photo) { 470 | return this.callApi("setChatPhoto", { chat_id: chatId, photo }); 471 | } 472 | deleteChatPhoto(chatId) { 473 | return this.callApi("deleteChatPhoto", { chat_id: chatId }); 474 | } 475 | /** 476 | * Change the title of a chat. Titles can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights 477 | * @param chatId Unique identifier for the target group or username of the target supergroup or channel (in the format `@channelusername`) 478 | * @param title New chat title, 1-255 characters 479 | */ 480 | setChatTitle(chatId, title) { 481 | return this.callApi("setChatTitle", { chat_id: chatId, title }); 482 | } 483 | setChatDescription(chatId, description) { 484 | return this.callApi("setChatDescription", { chat_id: chatId, description }); 485 | } 486 | /** 487 | * Pin a message in a group, a supergroup, or a channel. The bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' admin right in the supergroup or 'can_edit_messages' admin right in the channel. 488 | * @param chatId Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) 489 | */ 490 | pinChatMessage(chatId, messageId, extra) { 491 | return this.callApi("pinChatMessage", { 492 | chat_id: chatId, 493 | message_id: messageId, 494 | ...extra, 495 | }); 496 | } 497 | /** 498 | * Unpin a message in a group, a supergroup, or a channel. The bot must be an administrator in the chat for this to work and must have the 'can_pin_messages' admin right in the supergroup or 'can_edit_messages' admin right in the channel. 499 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 500 | */ 501 | unpinChatMessage(chatId, messageId) { 502 | return this.callApi("unpinChatMessage", { 503 | chat_id: chatId, 504 | message_id: messageId, 505 | }); 506 | } 507 | /** 508 | * Clear the list of pinned messages in a chat 509 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 510 | */ 511 | unpinAllChatMessages(chatId) { 512 | return this.callApi("unpinAllChatMessages", { chat_id: chatId }); 513 | } 514 | /** 515 | * Use this method for your bot to leave a group, supergroup or channel 516 | * @param chatId Unique identifier for the target chat or username of the target supergroup or channel (in the format @channelusername) 517 | */ 518 | leaveChat(chatId) { 519 | return this.callApi("leaveChat", { chat_id: chatId }); 520 | } 521 | /** 522 | * Unban a user from a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights 523 | * @param chatId Unique identifier for the target group or username of the target supergroup or channel (in the format @username) 524 | * @param userId Unique identifier of the target user 525 | */ 526 | unbanChatMember(chatId, userId, extra) { 527 | return this.callApi("unbanChatMember", { 528 | chat_id: chatId, 529 | user_id: userId, 530 | ...extra, 531 | }); 532 | } 533 | answerCbQuery(callbackQueryId, text, extra) { 534 | return this.callApi("answerCallbackQuery", { 535 | text, 536 | callback_query_id: callbackQueryId, 537 | ...extra, 538 | }); 539 | } 540 | answerCallbackQuery(...args) { 541 | return this.answerCbQuery(...args); 542 | } 543 | answerGameQuery(callbackQueryId, url) { 544 | return this.callApi("answerCallbackQuery", { 545 | url, 546 | callback_query_id: callbackQueryId, 547 | }); 548 | } 549 | /** 550 | * Use this method to get the list of boosts added to a chat by a user. Requires administrator rights in the chat. Returns a UserChatBoosts object. 551 | * @param chatId Unique identifier for the chat or username of the channel (in the format `@channelusername`) 552 | * @param userId Unique identifier of the target user 553 | */ 554 | getUserChatBoosts(chatId, userId) { 555 | return this.callApi("getUserChatBoosts", { 556 | chatId, 557 | userId, 558 | }); 559 | } 560 | /** 561 | * If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, 562 | * the Bot API will send an Update with a shipping_query field to the bot. 563 | * Reply to shipping queries. 564 | * @param ok Specify True if delivery to the specified address is possible and False if there are any problems (for example, if delivery to the specified address is not possible) 565 | * @param shippingOptions Required if ok is True. A JSON-serialized array of available shipping options. 566 | * @param errorMessage Required if ok is False. Error message in human readable form that explains why it is impossible to complete the order (e.g. "Sorry, delivery to your desired address is unavailable'). Telegram will display this message to the user. 567 | */ 568 | answerShippingQuery(shippingQueryId, ok, shippingOptions, errorMessage) { 569 | return this.callApi("answerShippingQuery", { 570 | ok, 571 | shipping_query_id: shippingQueryId, 572 | shipping_options: shippingOptions, 573 | error_message: errorMessage, 574 | }); 575 | } 576 | /** 577 | * Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form of an Update with the field pre_checkout_query. 578 | * Respond to such pre-checkout queries. On success, True is returned. 579 | * Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent. 580 | * @param ok Specify True if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Use False if there are any problems. 581 | * @param errorMessage Required if ok is False. Error message in human readable form that explains the reason for failure to proceed with the checkout (e.g. "Sorry, somebody just bought the last of our amazing black T-shirts while you were busy filling out your payment details. Please choose a different color or garment!"). Telegram will display this message to the user. 582 | */ 583 | answerPreCheckoutQuery(preCheckoutQueryId, ok, errorMessage) { 584 | return this.callApi("answerPreCheckoutQuery", { 585 | ok, 586 | pre_checkout_query_id: preCheckoutQueryId, 587 | error_message: errorMessage, 588 | }); 589 | } 590 | answerWebAppQuery(webAppQueryId, result) { 591 | return this.callApi("answerWebAppQuery", { 592 | web_app_query_id: webAppQueryId, 593 | result, 594 | }); 595 | } 596 | /** 597 | * Edit text and game messages sent by the bot or via the bot (for inline bots). 598 | * On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. 599 | * @param chatId Required if inlineMessageId is not specified. Unique identifier for the target chat or username of the target channel (in the format @channelusername) 600 | * @param messageId Required if inlineMessageId is not specified. Identifier of the sent message 601 | * @param inlineMessageId Required if chatId and messageId are not specified. Identifier of the inline message 602 | * @param text New text of the message 603 | */ 604 | editMessageText(chatId, messageId, inlineMessageId, text, extra) { 605 | return this.callApi("editMessageText", { 606 | text, 607 | chat_id: chatId, 608 | message_id: messageId, 609 | inline_message_id: inlineMessageId, 610 | ...extra, 611 | }); 612 | } 613 | /** 614 | * Edit captions of messages sent by the bot or via the bot (for inline bots). 615 | * On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. 616 | * @param chatId Required if inlineMessageId is not specified. Unique identifier for the target chat or username of the target channel (in the format @channelusername) 617 | * @param messageId Required if inlineMessageId is not specified. Identifier of the sent message 618 | * @param inlineMessageId Required if chatId and messageId are not specified. Identifier of the inline message 619 | * @param caption New caption of the message 620 | * @param markup A JSON-serialized object for an inline keyboard. 621 | */ 622 | editMessageCaption(chatId, messageId, inlineMessageId, caption, extra) { 623 | return this.callApi("editMessageCaption", { 624 | caption, 625 | chat_id: chatId, 626 | message_id: messageId, 627 | inline_message_id: inlineMessageId, 628 | ...extra, 629 | }); 630 | } 631 | /** 632 | * Edit animation, audio, document, photo, or video messages. 633 | * If a message is a part of a message album, then it can be edited only to a photo or a video. 634 | * Otherwise, message type can be changed arbitrarily. 635 | * When inline message is edited, new file can't be uploaded. 636 | * Use previously uploaded file via its file_id or specify a URL. 637 | * @param chatId Required if inlineMessageId is not specified. Unique identifier for the target chat or username of the target channel (in the format @channelusername) 638 | * @param messageId Required if inlineMessageId is not specified. Identifier of the sent message 639 | * @param inlineMessageId Required if chatId and messageId are not specified. Identifier of the inline message 640 | * @param media New media of message 641 | * @param markup Markup of inline keyboard 642 | */ 643 | editMessageMedia(chatId, messageId, inlineMessageId, media, extra) { 644 | return this.callApi("editMessageMedia", { 645 | chat_id: chatId, 646 | message_id: messageId, 647 | inline_message_id: inlineMessageId, 648 | media, 649 | ...extra, 650 | }); 651 | } 652 | /** 653 | * Edit only the reply markup of messages sent by the bot or via the bot (for inline bots). 654 | * @param chatId Required if inlineMessageId is not specified. Unique identifier for the target chat or username of the target channel (in the format @channelusername) 655 | * @param messageId Required if inlineMessageId is not specified. Identifier of the sent message 656 | * @param inlineMessageId Required if chatId and messageId are not specified. Identifier of the inline message 657 | * @param markup A JSON-serialized object for an inline keyboard. 658 | * @returns If edited message is sent by the bot, the edited Message is returned, otherwise True is returned. 659 | */ 660 | editMessageReplyMarkup(chatId, messageId, inlineMessageId, markup) { 661 | return this.callApi("editMessageReplyMarkup", { 662 | chat_id: chatId, 663 | message_id: messageId, 664 | inline_message_id: inlineMessageId, 665 | reply_markup: markup, 666 | }); 667 | } 668 | editMessageLiveLocation( 669 | chatId, 670 | messageId, 671 | inlineMessageId, 672 | latitude, 673 | longitude, 674 | extra, 675 | ) { 676 | return this.callApi("editMessageLiveLocation", { 677 | latitude, 678 | longitude, 679 | chat_id: chatId, 680 | message_id: messageId, 681 | inline_message_id: inlineMessageId, 682 | ...extra, 683 | }); 684 | } 685 | stopMessageLiveLocation(chatId, messageId, inlineMessageId, markup) { 686 | return this.callApi("stopMessageLiveLocation", { 687 | chat_id: chatId, 688 | message_id: messageId, 689 | inline_message_id: inlineMessageId, 690 | reply_markup: markup, 691 | }); 692 | } 693 | /** 694 | * Delete a message, including service messages, with the following limitations: 695 | * - A message can only be deleted if it was sent less than 48 hours ago. 696 | * - Bots can delete outgoing messages in groups and supergroups. 697 | * - Bots granted can_post_messages permissions can delete outgoing messages in channels. 698 | * - If the bot is an administrator of a group, it can delete any message there. 699 | * - If the bot has can_delete_messages permission in a supergroup or a channel, it can delete any message there. 700 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 701 | */ 702 | deleteMessage(chatId, messageId) { 703 | return this.callApi("deleteMessage", { 704 | chat_id: chatId, 705 | message_id: messageId, 706 | }); 707 | } 708 | deleteMessages(chatId, messageIds) { 709 | return this.callApi("deleteMessages", { 710 | chat_id: chatId, 711 | message_ids: messageIds, 712 | }); 713 | } 714 | setChatStickerSet(chatId, setName) { 715 | return this.callApi("setChatStickerSet", { 716 | chat_id: chatId, 717 | sticker_set_name: setName, 718 | }); 719 | } 720 | deleteChatStickerSet(chatId) { 721 | return this.callApi("deleteChatStickerSet", { chat_id: chatId }); 722 | } 723 | getStickerSet(name) { 724 | return this.callApi("getStickerSet", { name }); 725 | } 726 | 727 | /** 728 | * Use this method to get custom emoji stickers, which can be used as a forum topic icon by any user. 729 | * Requires no parameters. Returns an Array of Sticker objects. 730 | * 731 | * @see https://core.telegram.org/bots/api#getforumtopiciconstickers 732 | */ 733 | getForumTopicIconStickers() { 734 | return this.callApi("getForumTopicIconStickers", {}); 735 | } 736 | /** 737 | * Use this method to create a topic in a forum supergroup chat. The bot must be an administrator in the chat for this 738 | * to work and must have the can_manage_topics administrator rights. Returns information about the created topic as a 739 | * ForumTopic object. 740 | * 741 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 742 | * @param name Topic name, 1-128 characters 743 | * 744 | * @see https://core.telegram.org/bots/api#createforumtopic 745 | */ 746 | createForumTopic(chatId, name, extra) { 747 | return this.callApi("createForumTopic", { 748 | chatId, 749 | name, 750 | ...extra, 751 | }); 752 | } 753 | 754 | /** 755 | * Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must be an administrator in 756 | * the chat for this to work and must have can_manage_topics administrator rights, unless it is the creator of the 757 | * topic. Returns True on success. 758 | * 759 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 760 | * @param message_thread_id Unique identifier for the target message thread of the forum topic 761 | * 762 | * @see https://core.telegram.org/bots/api#editforumtopic 763 | */ 764 | editForumTopic(chatId, message_thread_id, extra) { 765 | return this.callApi("editForumTopic", { 766 | chatId, 767 | message_thread_id, 768 | ...extra, 769 | }); 770 | } 771 | /** 772 | * Use this method to close an open topic in a forum supergroup chat. The bot must be an administrator in the chat 773 | * for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. 774 | * Returns True on success. 775 | * 776 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 777 | * @param message_thread_id Unique identifier for the target message thread of the forum topic 778 | * 779 | * @see https://core.telegram.org/bots/api#closeforumtopic 780 | */ 781 | closeForumTopic(chatId, message_thread_id) { 782 | return this.callApi("closeForumTopic", { 783 | chatId, 784 | message_thread_id, 785 | }); 786 | } 787 | /** 788 | * Use this method to reopen a closed topic in a forum supergroup chat. The bot must be an administrator in the chat 789 | * for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic. 790 | * Returns True on success. 791 | * 792 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 793 | * @param message_thread_id Unique identifier for the target message thread of the forum topic 794 | * 795 | * @see https://core.telegram.org/bots/api#reopenforumtopic 796 | */ 797 | reopenForumTopic(chatId, message_thread_id) { 798 | return this.callApi("reopenForumTopic", { 799 | chatId, 800 | message_thread_id, 801 | }); 802 | } 803 | /** 804 | * Use this method to delete a forum topic along with all its messages in a forum supergroup chat. The bot must be an 805 | * administrator in the chat for this to work and must have the can_delete_messages administrator rights. 806 | * Returns True on success. 807 | * 808 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 809 | * @param message_thread_id Unique identifier for the target message thread of the forum topic 810 | * 811 | * @see https://core.telegram.org/bots/api#deleteforumtopic 812 | */ 813 | deleteForumTopic(chatId, message_thread_id) { 814 | return this.callApi("deleteForumTopic", { 815 | chatId, 816 | message_thread_id, 817 | }); 818 | } 819 | /** 820 | * Use this method to clear the list of pinned messages in a forum topic. The bot must be an administrator in the chat 821 | * for this to work and must have the can_pin_messages administrator right in the supergroup. Returns True on success. 822 | * 823 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 824 | * @param message_thread_id Unique identifier for the target message thread of the forum topic 825 | * 826 | * @see https://core.telegram.org/bots/api#unpinallforumtopicmessages 827 | */ 828 | unpinAllForumTopicMessages(chatId, message_thread_id) { 829 | return this.callApi("unpinAllForumTopicMessages", { 830 | chatId, 831 | message_thread_id, 832 | }); 833 | } 834 | /** 835 | * Use this method to edit the name of the 'General' topic in a forum supergroup chat. The bot must be an administrator 836 | * in the chat for this to work and must have can_manage_topics administrator rights. Returns True on success. 837 | * 838 | * @param chatId Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) 839 | * @param name New topic name, 1-128 characters 840 | * 841 | * @see https://core.telegram.org/bots/api#editgeneralforumtopic 842 | */ 843 | editGeneralForumTopic(chatId, name) { 844 | return this.callApi("editGeneralForumTopic", { chatId, name }); 845 | } 846 | /** 847 | * Use this method to close an open 'General' topic in a forum supergroup chat. The bot must be an administrator in the 848 | * chat for this to work and must have the can_manage_topics administrator rights. Returns True on success. 849 | * 850 | * @param chatId Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) 851 | * 852 | * @see https://core.telegram.org/bots/api#closegeneralforumtopic 853 | */ 854 | closeGeneralForumTopic(chatId) { 855 | return this.callApi("closeGeneralForumTopic", { chatId }); 856 | } 857 | /** 858 | * Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must be an administrator in 859 | * the chat for this to work and must have the can_manage_topics administrator rights. The topic will be automatically 860 | * unhidden if it was hidden. Returns True on success. 861 | * 862 | * @param chatId Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) 863 | * 864 | * @see https://core.telegram.org/bots/api#reopengeneralforumtopic 865 | */ 866 | reopenGeneralForumTopic(chatId) { 867 | return this.callApi("reopenGeneralForumTopic", { chatId }); 868 | } 869 | /** 870 | * Use this method to hide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the chat 871 | * for this to work and must have the can_manage_topics administrator rights. The topic will be automatically closed 872 | * if it was open. Returns True on success. 873 | * 874 | * @param chatId Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) 875 | * 876 | * @see https://core.telegram.org/bots/api#hidegeneralforumtopic 877 | */ 878 | hideGeneralForumTopic(chatId) { 879 | return this.callApi("hideGeneralForumTopic", { chatId }); 880 | } 881 | /** 882 | * Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must be an administrator in the 883 | * chat for this to work and must have the can_manage_topics administrator rights. Returns True on success. 884 | * 885 | * @param chatId Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) 886 | * 887 | * @see https://core.telegram.org/bots/api#unhidegeneralforumtopic 888 | */ 889 | unhideGeneralForumTopic(chatId) { 890 | return this.callApi("unhideGeneralForumTopic", { chatId }); 891 | } 892 | /** 893 | * Use this method to clear the list of pinned messages in a General forum topic. 894 | * The bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator 895 | * right in the supergroup. 896 | * 897 | * @param chatId Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) 898 | */ 899 | unpinAllGeneralForumTopicMessages(chatId) { 900 | return this.callApi("unpinAllGeneralForumTopicMessages", { chatId }); 901 | } 902 | /** 903 | * Upload a .png file with a sticker for later use in createNewStickerSet and addStickerToSet methods (can be used multiple times) 904 | * https://core.telegram.org/bots/api#sending-files 905 | * @param ownerId User identifier of sticker file owner 906 | * @param stickerFile Png image with the sticker, must be up to 512 kilobytes in size, dimensions must not exceed 512px, and either width or height must be exactly 512px. 907 | */ 908 | uploadStickerFile(ownerId, stickerFile) { 909 | return this.callApi("uploadStickerFile", { 910 | user_id: ownerId, 911 | png_sticker: stickerFile, 912 | }); 913 | } 914 | /** 915 | * Create new sticker set owned by a user. The bot will be able to edit the created sticker set 916 | * @param ownerId User identifier of created sticker set owner 917 | * @param name Short name of sticker set, to be used in t.me/addstickers/ URLs (e.g., animals). Can contain only english letters, digits and underscores. Must begin with a letter, can't contain consecutive underscores and must end in “_by_”. is case insensitive. 1-64 characters. 918 | * @param title Sticker set title, 1-64 characters 919 | */ 920 | createNewStickerSet(ownerId, name, title, stickerData) { 921 | return this.callApi("createNewStickerSet", { 922 | name, 923 | title, 924 | user_id: ownerId, 925 | ...stickerData, 926 | }); 927 | } 928 | /** 929 | * Add a new sticker to a set created by the bot 930 | * @param ownerId User identifier of sticker set owner 931 | * @param name Sticker set name 932 | */ 933 | addStickerToSet(ownerId, name, stickerData) { 934 | return this.callApi("addStickerToSet", { 935 | name, 936 | user_id: ownerId, 937 | ...stickerData, 938 | }); 939 | } 940 | /** 941 | * Move a sticker in a set created by the bot to a specific position 942 | * @param sticker File identifier of the sticker 943 | * @param position New sticker position in the set, zero-based 944 | */ 945 | setStickerPositionInSet(sticker, position) { 946 | return this.callApi("setStickerPositionInSet", { 947 | sticker, 948 | position, 949 | }); 950 | } 951 | setStickerSetThumb(name, userId, thumb) { 952 | return this.callApi("setStickerSetThumb", { name, user_id: userId, thumb }); 953 | } 954 | setStickerMaskPosition(sticker, mask_position) { 955 | return this.callApi("setStickerMaskPosition", { sticker, mask_position }); 956 | } 957 | setStickerKeywords(sticker, keywords) { 958 | return this.callApi("setStickerKeywords", { sticker, keywords }); 959 | } 960 | setStickerEmojiList(sticker, emoji_list) { 961 | return this.callApi("setStickerEmojiList", { sticker, emoji_list }); 962 | } 963 | deleteStickerSet(name) { 964 | return this.callApi("deleteStickerSet", { name }); 965 | } 966 | setStickerSetTitle(name, title) { 967 | return this.callApi("setStickerSetTitle", { name, title }); 968 | } 969 | setCustomEmojiStickerSetThumbnail(name, custom_emoji_id) { 970 | return this.callApi("setCustomEmojiStickerSetThumbnail", { 971 | name, 972 | custom_emoji_id, 973 | }); 974 | } 975 | /** 976 | * Delete a sticker from a set created by the bot. 977 | * @param sticker File identifier of the sticker 978 | */ 979 | deleteStickerFromSet(sticker) { 980 | return this.callApi("deleteStickerFromSet", { sticker }); 981 | } 982 | getCustomEmojiStickers(custom_emoji_ids) { 983 | return this.callApi("getCustomEmojiStickers", { custom_emoji_ids }); 984 | } 985 | /** 986 | * Get the current list of the bot's commands. 987 | */ 988 | getMyCommands(extra = {}) { 989 | return this.callApi("getMyCommands", extra); 990 | } 991 | /** 992 | * Change the list of the bot's commands. 993 | * @param commands A list of bot commands to be set as the list of the bot's commands. At most 100 commands can be specified. 994 | */ 995 | setMyCommands(commands, extra) { 996 | return this.callApi("setMyCommands", { commands, ...extra }); 997 | } 998 | deleteMyCommands(extra = {}) { 999 | return this.callApi("deleteMyCommands", extra); 1000 | } 1001 | setPassportDataErrors(userId, errors) { 1002 | return this.callApi("setPassportDataErrors", { 1003 | user_id: userId, 1004 | errors: errors, 1005 | }); 1006 | } 1007 | /** 1008 | * Use this method to change the bot's description, which is shown in the chat with the bot if the chat is empty. 1009 | * @param description New bot description; 0-512 characters. Pass an empty string to remove the dedicated description for the given language. 1010 | * @param language_code A two-letter ISO 639-1 language code. If empty, the description will be applied to all users for whose language there is no dedicated description. 1011 | */ 1012 | setMyDescription(description, language_code) { 1013 | return this.callApi("setMyDescription", { description, language_code }); 1014 | } 1015 | /** 1016 | * Use this method to change the bot's name. 1017 | * @param name New bot name; 0-64 characters. Pass an empty string to remove the dedicated name for the given language. 1018 | * @param language_code A two-letter ISO 639-1 language code. If empty, the name will be shown to all users for whose language there is no dedicated name. 1019 | */ 1020 | setMyName(name, language_code) { 1021 | return this.callApi("setMyName", { name, language_code }); 1022 | } 1023 | /** 1024 | * Use this method to get the current bot name for the given user language. 1025 | * @param language_code A two-letter ISO 639-1 language code or an empty string 1026 | */ 1027 | getMyName(language_code) { 1028 | return this.callApi("getMyName", { language_code }); 1029 | } 1030 | /** 1031 | * Use this method to get the current bot description for the given user language. 1032 | * @param language_code A two-letter ISO 639-1 language code. 1033 | */ 1034 | getMyDescription(language_code) { 1035 | return this.callApi("getMyDescription", { language_code }); 1036 | } 1037 | /** 1038 | * Use this method to change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot. 1039 | * @param description New short description for the bot; 0-120 characters. Pass an empty string to remove the dedicated short description for the given language. 1040 | * @param language_code A two-letter ISO 639-1 language code. If empty, the short description will be applied to all users for whose language there is no dedicated short description. 1041 | */ 1042 | setMyShortDescription(short_description, language_code) { 1043 | return this.callApi("setMyShortDescription", { 1044 | short_description, 1045 | language_code, 1046 | }); 1047 | } 1048 | /** 1049 | * Use this method to get the current bot short description for the given user language. 1050 | * @param language_code A two-letter ISO 639-1 language code or an empty string 1051 | */ 1052 | getMyShortDescription(language_code) { 1053 | return this.callApi("getMyShortDescription", { language_code }); 1054 | } 1055 | setPassportDataErrors(userId, errors) { 1056 | return this.callApi("setPassportDataErrors", { 1057 | user_id: userId, 1058 | errors: errors, 1059 | }); 1060 | } 1061 | /** 1062 | * Send copy of existing message. 1063 | * @deprecated use `copyMessage` instead 1064 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 1065 | * @param message Received message object 1066 | */ 1067 | sendCopy(chatId, message, extra) { 1068 | return this.copyMessage(chatId, message.chat.id, message.message_id, extra); 1069 | } 1070 | /** 1071 | * Send copy of existing message 1072 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 1073 | * @param fromChatId Unique identifier for the chat where the original message was sent (or channel username in the format @channelusername) 1074 | * @param messageId Message identifier in the chat specified in from_chat_id 1075 | */ 1076 | copyMessage(chatId, fromChatId, messageId, extra) { 1077 | return this.callApi("copyMessage", { 1078 | chat_id: chatId, 1079 | from_chat_id: fromChatId, 1080 | message_id: messageId, 1081 | ...extra, 1082 | }); 1083 | } 1084 | /** 1085 | * Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. Service messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. 1086 | * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) 1087 | * @param fromChatId Unique identifier for the chat where the original messages were sent (or channel username in the format @channelusername) 1088 | * @param messageIds Identifiers of 1-100 messages in the chat from_chat_id to copy. The identifiers must be specified in a strictly increasing order. 1089 | */ 1090 | copyMessages(chatId, fromChatId, messageIds, extra) { 1091 | return this.callApi("copyMessages", { 1092 | chat_id: chatId, 1093 | from_chat_id: fromChatId, 1094 | message_ids: messageIds, 1095 | ...extra, 1096 | }); 1097 | } 1098 | 1099 | // Bot API 5.4 1100 | 1101 | /** 1102 | * 1103 | * Use this method to approve a chat join request. 1104 | * The bot must be an administrator in the chat for this to work and must have the can_invite_users administrator right. 1105 | * Returns True on success. 1106 | */ 1107 | approveChatJoinRequest(chatId, userId, extra) { 1108 | return this.callApi("approveChatJoinRequest", { 1109 | chat_id: chatId, 1110 | user_id: userId, 1111 | ...extra, 1112 | }); 1113 | } 1114 | 1115 | /** 1116 | * 1117 | * Use this method to decline a chat join request. 1118 | * The bot must be an administrator in the chat for this to work and must have the can_invite_users administrator right. 1119 | * Returns True on success. 1120 | */ 1121 | declineChatJoinRequest(chatId, userId, extra) { 1122 | return this.callApi("declineChatJoinRequest", { 1123 | chat_id: chatId, 1124 | user_id: userId, 1125 | ...extra, 1126 | }); 1127 | } 1128 | 1129 | /** 1130 | * Use this method to ban a channel chat in a supergroup or a channel. 1131 | * Until the chat is unbanned, the owner of the banned chat won't be able to send messages on behalf of any of their channels. 1132 | * The bot must be an administrator in the supergroup or channel for this to work and must have the appropriate administrator rights. 1133 | * Returns True on success. 1134 | */ 1135 | banChatSenderChat(chatId, senderChatId, extra) { 1136 | return this.callApi("banChatSenderChat", { 1137 | chat_id: chatId, 1138 | sender_chat_id: senderChatId, 1139 | ...extra, 1140 | }); 1141 | } 1142 | 1143 | /** 1144 | * Use this method to unban a previously banned channel chat in a supergroup or channel. 1145 | * The bot must be an administrator for this to work and must have the appropriate administrator rights. 1146 | * Returns True on success. 1147 | */ 1148 | unbanChatSenderChat(chatId, senderChatId, extra) { 1149 | return this.callApi("unbanChatSenderChat", { 1150 | chat_id: chatId, 1151 | sender_chat_id: senderChatId, 1152 | ...extra, 1153 | }); 1154 | } 1155 | 1156 | /** 1157 | * Use this method to change the bot's menu button in a private chat, or the default menu button. Returns true on success. 1158 | * @param chatId Unique identifier for the target private chat. If not specified, default bot's menu button will be changed. 1159 | * @param menuButton An object for the bot's new menu button. 1160 | */ 1161 | setChatMenuButton({ chatId, menuButton } = {}) { 1162 | return this.callApi("setChatMenuButton", { 1163 | chat_id: chatId, 1164 | menu_button: menuButton, 1165 | }); 1166 | } 1167 | /** 1168 | * Use this method to get the current value of the bot's menu button in a private chat, or the default menu button. Returns MenuButton on success. 1169 | * @param chatId Unique identifier for the target private chat. If not specified, default bot's menu button will be returned. 1170 | */ 1171 | getChatMenuButton({ chatId } = {}) { 1172 | return this.callApi("getChatMenuButton", { 1173 | chat_id: chatId, 1174 | }); 1175 | } 1176 | /** 1177 | * Use this method to change the default administrator rights requested by the bot when it's added as an administrator to groups or channels. 1178 | * These rights will be suggested to users, but they are are free to modify the list before adding the bot. 1179 | */ 1180 | setMyDefaultAdministratorRights({ rights, forChannels } = {}) { 1181 | return this.callApi("setMyDefaultAdministratorRights", { 1182 | rights, 1183 | for_channels: forChannels, 1184 | }); 1185 | } 1186 | /** 1187 | * Use this method to get the current default administrator rights of the bot. Returns ChatAdministratorRights on success. 1188 | * @param forChannels Pass true to get default administrator rights of the bot in channels. Otherwise, default administrator rights of the bot for groups and supergroups will be returned. 1189 | */ 1190 | getMyDefaultAdministratorRights({ forChannels } = {}) { 1191 | return this.callApi("getMyDefaultAdministratorRights", { 1192 | for_channels: forChannels, 1193 | }); 1194 | } 1195 | 1196 | /** 1197 | * Log out from the cloud Bot API server before launching the bot locally 1198 | */ 1199 | logOut() { 1200 | return this.callApi("logOut", {}); 1201 | } 1202 | /** 1203 | * Close the bot instance before moving it from one local server to another 1204 | */ 1205 | close() { 1206 | return this.callApi("close", {}); 1207 | } 1208 | } 1209 | --------------------------------------------------------------------------------