{"id":13716721,"url":"https://github.com/Naltox/telegram-node-bot","last_synced_at":"2025-05-07T06:30:55.175Z","repository":{"id":36190824,"uuid":"40495024","full_name":"Naltox/telegram-node-bot","owner":"Naltox","description":"Node module for creating Telegram bots.","archived":false,"fork":false,"pushed_at":"2023-01-18T11:33:33.000Z","size":627,"stargazers_count":723,"open_issues_count":54,"forks_count":143,"subscribers_count":39,"default_branch":"master","last_synced_at":"2024-11-06T03:05:48.560Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Naltox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-10T17:06:30.000Z","updated_at":"2024-10-21T11:59:47.000Z","dependencies_parsed_at":"2023-02-10T14:45:15.087Z","dependency_job_id":null,"html_url":"https://github.com/Naltox/telegram-node-bot","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Naltox%2Ftelegram-node-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Naltox%2Ftelegram-node-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Naltox%2Ftelegram-node-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Naltox%2Ftelegram-node-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Naltox","download_url":"https://codeload.github.com/Naltox/telegram-node-bot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224567748,"owners_count":17332830,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T00:01:13.676Z","updated_at":"2024-11-14T04:32:11.890Z","avatar_url":"https://github.com/Naltox.png","language":"JavaScript","readme":"# telegram-node-bot\nVery powerful module for creating Telegram bots.\n\n[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=KDM7K3BBVV2E8)\n\n[Full API reference](http://nabovyan.xyz/telegram-node-bot/)\n\n[help chat](http://nabovyan.xyz/tg-dev-chat)\n\n## Installation\n\nTo install the stable version:\n\n```bash\nnpm install --save telegram-node-bot\n```\n\nThis assumes you are using [npm](https://www.npmjs.com/) as your package manager.\nIf you don’t, you can access these files on [unpkg](https://unpkg.com/telegram-node-bot/), download them, or point your package manager to them.\n\n## Whats new in 4.0?\n\n* Bug fixes\n* Clustering\n* New router\n* Web admin\n\n## Get started\n\nFirst of all you need to create your bot and get Token, you can do it right in telegram, just write to @BotFather.\n\nNow let's write simple bot!\n\n```js\n'use strict'\n\nconst Telegram = require('telegram-node-bot')\nconst TelegramBaseController = Telegram.TelegramBaseController\nconst TextCommand = Telegram.TextCommand\nconst tg = new Telegram.Telegram('YOUR_TOKEN')\n\nclass PingController extends TelegramBaseController {\n    /**\n     * @param {Scope} $\n     */\n    pingHandler($) {\n        $.sendMessage('pong')\n    }\n\n    get routes() {\n        return {\n            'pingCommand': 'pingHandler'\n        }\n    }\n}\n\ntg.router\n    .when(\n        new TextCommand('ping', 'pingCommand'),\n        new PingController()\n    )\n```\nThat's it!\n\n![Bot](ScreenShot.png)\n\n## Introduction\n\nI'm using something like MVC, so we have router and controllers.\nFirst you need to declare your commands and which controller will handle it.\nThen you need to write controllers and handle specific commands in it.\n\n## Router\nLets say our bot has three commands: /start, /stop and /restart\nAnd we want that commands to be handled by different controllers.\n\nRouter declaration code will be like this:\n\n```js\ntg.router\n    .when(new TextCommand('/start', 'startCommand'), new StartController())\n    .when(new TextCommand('/stop', 'stopCommand'), new StopController())\n    .when(new TextCommand('/restart', 'restartCommand'), new RestartController())\n```\n\nProbably we will have a case when user send us command we didn't know, for that case router have `otherwise` function:\n\n```js\ntg.router\n    .when(new TextCommand('/start', 'startCommand'), new StartController())\n    .when(new TextCommand('/stop', 'stopCommand'), new StopController())\n    .when(new TextCommand('/restart', 'restartCommand'), new RestartController())\n    .otherwise(new OtherwiseController())\n```\n\nNow all unknown commands will be handled by OtherwiseController:\n\n```js\nclass OtherwiseController extends TelegramBaseController {\n    handle() {\n        console.log('otherwise')\n    }\n}\n```\n\nIn this cases for all controllers will be called `handle` method to handle request. But you can pass your custom handler name as second parameter to any command:\n\n```js\ntg.router\n    .when(\n        new TextCommand('/start', 'startHandler'),\n        new StartController()\n    )\n```\nThen you must add `routes` property to your controller like this:\n```js\nclass StartConstoller extends TelegramBaseController {\n    /**\n     * @param {Scope} $\n     */\n    start($) {\n        $.sendMessage('Hello!')\n    }\n\n    get routes() {\n        return {\n            'startHandler': 'start'\n        }\n    }\n}\n```\n\nYou can define controller for inline queries using `inlineQuery` method:\n\n```js\ntg.router\n    .inlineQuery(new InlineModeController())\n```\n\nAnd controllers for callback queries using `callbackQuery`:\n\n```js\ntg.router\n    .callbackQuery(new CallbackQueryController())\n```\n\n## List of all commands\n\n* TextCommand - just text command like `/start`\n```js\ntg.router\n    .when(\n        new TextCommand('/start', 'startHandler'),\n        new StartController()\n    )\n```\n* RegextCommand - any regexp command\n```js\ntg.router\n    .when(\n        new RegexpCommand(/test/g, 'testHandler'),\n        new TestController()\n    )\n```\n* CustomFilterCommand - custom command\n```js\ntg.router\n    .when(\n        new CustomFilterCommand($ =\u003e {\n            return $.message.text == 'some text'\n        }, 'customFilterHandler'),\n        new CustomFilterHandlerController()\n    )\n```\n\nYou can also create your own command, just extend `BaseCommand`\n\n\n## Controllers\n\nThere are three types of controllers:\n\n* Controller for messages - `TelegramBaseController`\n* Controller for CallbackQueries - `TelegramBaseCallbackQueryController`\n* Controller for InlineQueries - `TelegramBaseInlineQueryController`\n\n\n## TelegramBaseController\n\nTo create controller for message updates you must extend `TelegramBaseController`.\n\nIf you want specific methods of your controller be called for specific commands, you should return a plain object in `routes` property where key is a route and value is name of your method.\nIn that case `handle` method will not be called and scope will be passed to your method.\nExample:\n\n```js\nclass TestController extends TelegramBaseController {\n    get routes() {\n        return {\n            'test': 'testHandler'\n        }\n    }\n}\n```\n\nIf there are no routes defined then `handle` method of your controller will be called.\n\nThere is also `before` method, this method will be called after all updates and you should return the scope, you can modify scope if you want:\n\n```js\nclass TestController extends TelegramBaseController {\n    before(scope) {\n        scope.someData = true\n\n        return scope\n    }\n}\n```\nRemember: if you want to handle command in controller you need to declare it in router.\n\nAll instances of TelegramBaseController also have private `_api` property which is a reference to `TelegramApi` and private `_localization` property which is a reference to `Ivan`\n\n## TelegramBaseCallbackQueryController\n\nTo create such controller you must extend TelegramBaseCallbackQueryController.\n\nThis controllers are very simple, they have only one method - `handle`, this method will be called for all queries and instance of `CallbackQuery` will be passed.\n\n## TelegramBaseInlineQueryController\n\nTo create such controller you must extend TelegramBaseInlineQueryController.\n\nThese controllers also have `handle` method which will be called for all queries and an instance of `InlineScope` will be passed.\nAlso they its have `chosenResult` method which will be called when user select some result, an instance of `ChosenInlineResult`\n\nAlso as the `TelegramBaseController` it has `_api` and `_localization` properties.\n\n## Getting updates\nYou can use long-pooling or webhooks to get updates.\nLong-pooling used by default. To use webhooks you need to init library like this:\n```js\nconst tg = new Telegram.Telegram('YOUR_TOKEN', {\n    webhook: {\n        url: 'https://61f66256.ngrok.io',\n        port: 3000,\n        host: 'localhost'\n    }\n})\n```\nYou can also create any other custom update fetcher: just extend Telegram.BaseUpdateFetcher and pass it to library:\n```js\nconst tg = new Telegram.Telegram('YOUR_TOKEN', {\n    updateFetcher: new MyUpdateFetcher()\n})\n```\n\n\n## Clustering\nBy default library will create one worker per cpu. You can change it like this:\n\n```js\nconst tg = new Telegram.Telegram('YOUR_TOKEN', {\n    workers: 1\n})\n```\n\nIf you want run some code on main process use `tg.onMaster` method:\n\n```js\nconst tg = new Telegram.Telegram('YOUR_TOKEN', {\n    workers: 1\n})\n\ntg.sendMessage(123, 'test message') //will be sent 2 times (one time on master and one time on worker)\n\ntg.onMaster(() =\u003e {\n    tg.sendMessage(123, 'test message') //will be sent one time\n})\n```\n\n## Web admin\nBy default library will start web admin at localhost:7777, to change that use `webAdmin` properpty:\n```js\nconst tg = new Telegram.Telegram('YOUR_TOKEN', {\n    webAdmin: {\n        port: 1234,\n        host: 'localhost'\n    }\n})\n```\n\n## API\nYou can call api methods two ways:\n\nDirectly from tg:\n\n```js\ntg.api.sendMessage(chatId, 'Hi')\n```\n\nOr if you using controllers controller will pass you context `$` that already knows current chat id, so it's more easy to use:\n\n```js\n$.sendMessage('Hi')\n```\n\nAll methods have required parameters and optional parameters, you can find them in  [api documentation](https://core.telegram.org/bots/api#available-methods)\nIf you want to pass optional parameters you should pass them as an object:\n```js\n$.sendMessage('Hi', { disable_notification: true })\n```\n\n## Scope\n\nThere is two types of scope:\n\n* scope for message controllers - `Scope`\n* scope for inline mode controller - `InlineScope`\n\nMessage controllers scope:\n\nscope will be passed to `handle` method or to your methods defined in `routes`\n\nMain feature of scope is that scope already knows current chat id, so there is no need to pass that parameter.\nScope have all api methods that have chatId as their first parameter already filled.\n\nScope also contains some information about update.\n\n\nInline controllers scope also has all api methods filled with userId.\n\n## Forms\n\nIn message controllers scope has `runForm` method.\n\nWith `$.runForm` method you can create forms:\n\n```js\nconst form = {\n    name: {\n\t    q: 'Send me your name',\n\t    error: 'sorry, wrong input',\n\t    validator: (message, callback) =\u003e {\n\t\t    if(message.text) {\n\t\t\t    callback(true, message.text) //you must pass the result also\n\t\t\t    return\n\t\t    }\n\n\t\t    callback(false)\n\t    }\n    },\n    age: {\n\t    q: 'Send me your age',\n\t    error: 'sorry, wrong input',\n\t    validator: (message, callback) =\u003e {\n\t\t    if(message.text \u0026\u0026 IsNumeric(message.text)) {\n\t\t\t    callback(true, toInt(message.text))\n\t\t\t    return\n\t\t    }\n\n\t\t    callback(false)\n\t    }\n    }\n}\n\n$.runForm(form, (result) =\u003e {\n\tconsole.log(result)\n})\n```\n\nBot will send the 'q' message to user, wait for message, validate it with your validator function and save the answer, if validation fails bot will ask again that question.\nYou can also do some filtering in your validator, so you can pass the result as second parameter to callback.\nYou can also pass keyboard to `keyboard` field.\n\n## Menu\n\nYou can create menu with $.runMenu function:\n\n```js\n$.runMenu({\n    message: 'Select:',\n    options: {\n        parse_mode: 'Markdown' // in options field you can pass some additional data, like parse_mode\n    },\n    'Exit': {\n\t    message: 'Do you realy want to exit?',\n\t    resizeKeyboard: true,\n\t    'yes': () =\u003e {\n\n\t    },\n\t    'no': () =\u003e {\n\n\t    }\n    },\n    'anyMatch': () =\u003e { //will be executed at any other message\n\n    }\n})\n```\n\nBot will create keyboard and send it with your message, when user tap button bot will call its callback, if it's submenu bot will send submenu.\n\nLayouting menu:\n\nYou can pass the maximum number of buttons in line like this:\n\n```js\n$.runMenu({\n    message: 'Select:',\n    layout: 2,\n    'test1': () =\u003e {}, //will be on first line\n    'test2': () =\u003e {}, //will be on first line\n    'test3': () =\u003e {}, //will be on second line\n    'test4': () =\u003e {}, //will be on second line\n    'test5': () =\u003e {}, //will be on third line\n})\n```\nOr you can pass an array of number of buttons for each line:\n\n```js\n$.runMenu({\n    message: 'Select:',\n    layout: [1, 2, 1, 1],\n    'test1': () =\u003e {}, //will be on first line\n    'test2': () =\u003e {}, //will be on second line\n    'test3': () =\u003e {}, //will be on second line\n    'test4': () =\u003e {}, //will be on third line\n    'test5': () =\u003e {}, //will be on fourth line\n})\n```\n\n## Inline Menu\n\nYou can create inline menu using $.runInlineMenu:\n\n```js\n$.runInlineMenu({\n    layout: 2, //some layouting here\n    method: 'sendMessage', //here you must pass the method name\n    params: ['text'], //here you must pass the parameters for that method\n    menu: [\n        {\n            text: '1', //text of the button\n            callback: (callbackQuery, message) =\u003e { //to your callback will be passed callbackQuery and response from method\n                console.log(1)\n            }\n        },\n        {\n            text: 'Exit',\n            message: 'Are you sure?',\n            layout: 2,\n            menu: [ //Sub menu (current message will be edited)\n                {\n                    text: 'Yes!',\n                    callback: () =\u003e {\n\n                    }\n                },\n                {\n                    text: 'No!',\n                    callback: () =\u003e {\n\n                    }\n                }\n            ]\n        }\n    ]\n})\n```\n\n## waitForRequest\n\nMessages controller scope has `waitForRequest` method after calling that the next update from current user will be passed to promise.\n\n## waitForCallbackQuery\n\nIf you send some inline keyboard after that you can call this method, pass to it string or array of string with callback data or your InlineKeyboardMarkup and then when user press button CallbackQuery will be passed to Promise\n\n```js\n$.sendMessage('Send me your name')\n$.waitForRequest\n    .then($ =\u003e {\n        $.sendMessage(`Hi ${$.message.text}!`)\n    })\n```\n## Sessions\n\nFor user:\n\n```js\n$.setUserSession('someKey', 'some data')\n    .then(() =\u003e {\n        return $.getUserSession('someKey')\n    })\n    .then(data =\u003e {\n        console.log(data)\n    })\n```\n\nFor chat:\n\n```js\n$.setChatSession('someKey', 'some data')\n    .then(() =\u003e {\n        return $.getChatSession('someKey')\n    })\n    .then(data =\u003e {\n        console.log(data)\n    })\n```\n\n\nBy default sessions are stored in memory, but you can store them anywhere, you need to extend `BaseStorage` and pass instance of your storage to `Telegram`:\n\n```js\nconst tg = new Telegram.Telegram('YOUR_TOKEN',{\n    storage: new MyStorage()\n})\n```\n\n## Logging\n\nModule makes some logs during work, by default logs are written to console, but you can create your own logger if you want, you must extend `BaseLogger` and pass instance of your logger to `Telegram`:\n\n```js\nconst tg = new Telegram.Telegram('YOUR_TOKEN', {\n    logger: new MyLogger()\n})\n```\n\n## Localization\n\nTo use localization you need to pass your localization files to `Telegram`, they must be like this:\n\n```js\n{\n  \"lang\": \"Ru\",\n  \"phrases\": {\n    \"startMessage\": \"тест\"\n  }\n}\n```\n\nafter creating your files you need to pass them to `Telegram`:\n\n```js\nconst tg = new Telegram.Telegram('YOUR_TOKEN', {\n    localization: [require('./Ru.json')]\n})\n```\n\nNow you can use them in controllers like this:\n```js\nconsole.log(this._localization.Ru.startMessage)\n```\n\nYou can even set the language for specific user:\n```js\nthis._localization.setLanguageForUser(123456, 'Ru')\n```\n\nOr get phrases for user:\n```js\nthis._localization.forUser(123456)\n```\n\n## Scope extensions:\n\nLets say you have some function that you want to be in scope, now you can do that like this:\n\n\n```js\n'use strict'\n\nconst Telegram = require('telegram-node-bot')\nconst TelegramBaseController = Telegram.TelegramBaseController\nconst BaseScopeExtension = Telegram.BaseScopeExtension\nconst tg = new Telegram.Telegram('YOUR_TOKEN')\n\nclass SumScopeExtension extends BaseScopeExtension {\n    process(num1, num2) {\n        return num1 + num2\n    }\n\n    get name() {\n        return 'sum'\n    }\n}\n\nclass SumController extends TelegramBaseController {\n    /**\n     * @param {Scope} $\n     */\n    sumHandler($) {\n        $.sendMessage($.sum($.query.num1, $.query.num2))\n    }\n\n    get routes() {\n        return {\n            '/sum :num1 :num2': 'sumHandler'\n        }\n    }\n}\n\ntg.router\n    .when(['/sum :num1 :num2'], new SumController())\n\ntg.addScopeExtension(SumScopeExtension)\n```\n\n## Sending files\n\nFrom file id:\n\n```js\n$.sendPhoto(InputFile.byId('ID')) or $.sendPhoto('ID')\n```\n\nFrom url:\n\n```js\n$.sendPhoto(InputFile.byUrl('URL', 'image.jpg')) or $.sendPhoto({ url: 'URL', filename: 'image.jpg'})\n```\n\nBy path:\n\n```js\n$.sendPhoto(InputFile.byFilePath('path/to/file')) or $.sendPhoto({ path: 'path/to/file'})\n```\n\n[Full API reference](http://nabovyan.xyz/telegram-node-bot/)\n\n## License\n\nCopyright (c) 2016 Narek Abovyan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","funding_links":["https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=KDM7K3BBVV2E8"],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNaltox%2Ftelegram-node-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNaltox%2Ftelegram-node-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNaltox%2Ftelegram-node-bot/lists"}