Comparing version 1.1.2 to 2.0.0-alpha.0
581
api.md
# API reference | ||
- [Telegraf-API](#telegraf-api) | ||
- [Context](#context) | ||
- [Telegraf](#telegraf-api) | ||
- [Telegram](#telegram-api) | ||
- [Uploading files](#file) | ||
- [Shortcuts](#shortcuts) | ||
## Context | ||
A Telegraf Context encapsulates telegram message. | ||
Context is created per request and contains following props: | ||
```js | ||
app.use((ctx) => { | ||
ctx.telegram // Telegram instance | ||
ctx.updateType // Update type(message, inline_query, etc.) | ||
[ctx.updateSubType] // Update subtype(text, sticker, audio, etc.) | ||
[ctx.message] // Received message | ||
[ctx.editedMessage] // Edited message | ||
[ctx.inlineQuery] // Received inline query | ||
[ctx.chosenInlineResult] // Received inline query result | ||
[ctx.callbackQuery] // Received callback query | ||
[ctx.chat] // Current chat info | ||
[ctx.from] // Sender info | ||
[ctx.match] // Regex match (available only for `hears` handler) | ||
}) | ||
``` | ||
The recommended way to extend application context. | ||
```js | ||
const app = new Telegraf(process.env.BOT_TOKEN) | ||
app.context.db = { | ||
getScores: () => { return 42 } | ||
} | ||
app.on('text', (ctx) => { | ||
const scores = ctx.db.getScores(ctx.message.from.username) | ||
return ctx.reply(`${ctx.message.from.username}: ${score}`) | ||
}) | ||
``` | ||
Context shortcuts for **message** update: | ||
- `ctx.getChat() -> `[`ctx.telegram.getChat()`](#getchat) | ||
- `ctx.getChatAdministrators() -> `[`ctx.telegram.getChatAdministrators()`](#getchatadministrators) | ||
- `ctx.getChatMember() -> `[`ctx.telegram.getChatMember()`](#getchatmember) | ||
- `ctx.getChatMembersCount() -> `[`ctx.telegram.getChatMembersCount()`](#getchatmemberscount) | ||
- `ctx.leaveChat() -> `[`ctx.telegram.leaveChat()`](#leavechat) | ||
- `ctx.reply() -> `[`ctx.telegram.sendMessage()`](#sendmessage) | ||
- `ctx.replyWithMarkdown() -> `[`ctx.telegram.sendMessage()`](#sendmessage) | ||
- `ctx.replyWithHTML() -> `[`ctx.telegram.sendMessage()`](#sendmessage) | ||
- `ctx.replyWithAudio() -> `[`ctx.telegram.sendAudio()`](#sendaudio) | ||
- `ctx.replyWithChatAction() -> `[`ctx.telegram.sendChatAction()`](#sendchataction) | ||
- `ctx.replyWithDocument() -> `[`ctx.telegram.sendDocument()`](#senddocument) | ||
- `ctx.replyWithLocation() -> `[`ctx.telegram.sendLocation()`](#sendlocation) | ||
- `ctx.replyWithPhoto() -> `[`ctx.telegram.sendPhoto()`](#sendphoto) | ||
- `ctx.replyWithSticker() -> `[`ctx.telegram.sendSticker()`](#sendsticker) | ||
- `ctx.replyWithVideo() -> `[`ctx.telegram.sendVideo()`](#sendvideo) | ||
- `ctx.replyWithVoice() -> `[`ctx.telegram.sendVoice()`](#sendvoice) | ||
Context shortcuts for **callback_query** update: | ||
- `ctx.answerCallbackQuery() -> `[`ctx.telegram.answerCallbackQuery()`](#answercallbackquery) | ||
- `ctx.getChat() -> `[`ctx.telegram.getChat()`](#getchat) | ||
- `ctx.getChatAdministrators() -> `[`ctx.telegram.getChatAdministrators()`](#getchatadministrators) | ||
- `ctx.getChatMember() -> `[`ctx.telegram.getChatMember()`](#getchatmember) | ||
- `ctx.getChatMembersCount() -> `[`ctx.telegram.getChatMembersCount()`](#getchatmemberscount) | ||
- `ctx.leaveChat() -> `[`ctx.telegram.leaveChat()`](#leavechat) | ||
- `ctx.reply() -> `[`ctx.telegram.sendMessage()`](#sendmessage) | ||
- `ctx.replyWithMarkdown() -> `[`ctx.telegram.sendMessage()`](#sendmessage) | ||
- `ctx.replyWithHTML() -> `[`ctx.telegram.sendMessage()`](#sendmessage) | ||
- `ctx.replyWithAudio() -> `[`ctx.telegram.sendAudio()`](#sendaudio) | ||
- `ctx.replyWithChatAction() -> `[`ctx.telegram.sendChatAction()`](#sendchataction) | ||
- `ctx.replyWithDocument() -> `[`ctx.telegram.sendDocument()`](#senddocument) | ||
- `ctx.replyWithLocation() -> `[`ctx.telegram.sendLocation()`](#sendlocation) | ||
- `ctx.replyWithPhoto() -> `[`ctx.telegram.sendPhoto()`](#sendphoto) | ||
- `ctx.replyWithSticker() -> `[`ctx.telegram.sendSticker()`](#sendsticker) | ||
- `ctx.replyWithVideo() -> `[`ctx.telegram.sendVideo()`](#sendvideo) | ||
- `ctx.replyWithVoice() -> `[`ctx.telegram.sendVoice()`](#sendvoice) | ||
Context shortcuts for **inline_query** update: | ||
- `ctx.answerInlineQuery() -> `[`ctx.telegram.answerInlineQuery()`](#answerinlinequery) | ||
### Examples | ||
```js | ||
var bot = new Telegraf(process.env.BOT_TOKEN) | ||
bot.on('text', (ctx) => { | ||
// Simple usage | ||
ctx.telegram.sendMessage(ctx.message.chat.id, `Hello ${ctx.state.role}`) | ||
// Using shortcut | ||
ctx.reply(`Hello ${ctx.state.role}`) | ||
// If you want to mark message as reply to source message | ||
ctx.reply(`Hello ${ctx.state.role}`, { reply_to_message_id: ctx.message.id }) | ||
}) | ||
bot.on('/quit', (ctx) => { | ||
// Simple usage | ||
ctx.telegram.leaveChat(ctx.message.chat.id) | ||
// Using shortcut | ||
ctx.leaveChat() | ||
}) | ||
bot.on('callback_query', (ctx) => { | ||
// Simple usage | ||
ctx.telegram.answerCallbackQuery(ctx.callbackQuery.id) | ||
// Using shortcut | ||
ctx.answerCallbackQuery() | ||
}) | ||
bot.on('inline_query', (ctx) => { | ||
var result = [] | ||
// Simple usage | ||
ctx.telegram.answerInlineQuery(ctx.inlineQuery.id, result) | ||
// Using shortcut | ||
ctx.answerInlineQuery(result) | ||
}) | ||
``` | ||
## Telegraf API | ||
- [`Telegraf.mount(messageType, handler, [handler...])`](#mount) | ||
```js | ||
const Telegraf = require('telegraf') | ||
``` | ||
- [`Telegraf.mount(messageType, handler)`](#mount) | ||
- [`Telegraf.compose(handlers)`](#compose) | ||
- [`new Telegraf(token)`](#new) | ||
- [`new Telegraf(token)`](#new-telegraf) | ||
- [`.use(function)`](#use) | ||
- [`.on(messageType, handler, [handler...])`](#on) | ||
- [`.hears(string|ReGex, handler, [handler...])`](#hears) | ||
- [`.startPolling(timeout, limit)`](#startPolling) | ||
- [`.startWebHook(webHookPath, tlsOptions, port, [host])`](#startwebhook) | ||
- [`.stop()`](#stop) | ||
- [`.webHookCallback(webHookPath)`](#webhookcallback) | ||
- [`.handleUpdate(rawUpdate, response)`](#handleupdate) | ||
* * * | ||
<a name="mount"></a> | ||
#### `Telegraf.mount(updateType, handler) => function` | ||
Generates middleware for handling provided [update type](#update-types). | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| updateType | `string`\|`string[]` | [update type](#update-types) | | ||
| handler | `function` | Handler | | ||
* * * | ||
<a name="compose"></a> | ||
#### `Telegraf.compose(handlers) => function` | ||
Compose `middleware` returning a fully valid middleware comprised of all those which are passed. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| handlers | `function[]` | Array of handlers | | ||
* * * | ||
<a name="new-telegraf"></a> | ||
#### `new Telegraf(token)` | ||
Initialize new Telegraf app. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| token | `string` | [Bot Token](https://core.telegram.org/bots#3-how-do-i-create-a-bot) | | ||
* * * | ||
<a name="use"></a> | ||
#### `telegraf.use(middleware)` | ||
Registers a middleware. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| middleware | `function` | Middleware function | | ||
* * * | ||
<a name="on"></a> | ||
#### `telegraf.on(updateType, handler, [handler...])` | ||
Registers handler for provided [update type](#update-types). | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| updateType | `string`\|`string[]` | [update type](#update-types) | | ||
| handler | `function` | Handler | | ||
* * * | ||
<a name="hears"></a> | ||
#### `telegraf.hears(pattern, handler, [handler...])` | ||
Registers handler only for `text` updates using string pattern or RegEx. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| pattern | `string`\|`RegEx` | Pattern or RegEx | | ||
| handler | `function` | Handler | | ||
* * * | ||
<a name="startPolling"></a> | ||
#### `telegraf.startPolling(timeout, limit)` | ||
Start poll updates. | ||
| Param | Type | Default | Description | | ||
| --- | --- | --- | --- | | ||
| timeout | `number` | 0 | Poll timeout | | ||
| limit | `number` | 100 | Limits the number of updates to be retrieved | | ||
* * * | ||
<a name="startwebhook"></a> | ||
#### `telegraf.startWebHook(webHookPath, tlsOptions, port, [host])` | ||
Start listening @ `https://host:port/webHookPath` for Telegram calls. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| webHookPath | `string` | Webhook url path (see Telegraf.setWebHook) | | ||
| tlsOptions | `object` | (Optional) [TLS server options](https://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener). Pass null to use http | | ||
| port | `number` | Port number | | ||
| [host] | `string` | (Optional) Hostname | | ||
* * * | ||
<a name="stop"></a> | ||
#### `telegraf.stop()` | ||
Stop WebHook and polling | ||
* * * | ||
<a name="webhookcallback"></a> | ||
#### `telegraf.webHookCallback(webHookPath) => Function` | ||
Return a callback function suitable for the http[s].createServer() method to handle a request. | ||
You may also use this callback function to mount your telegraf app in a Koa/Connect/Express app. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| webHookPath | `string` | Webhook url path (see Telegraf.setWebHook) | | ||
* * * | ||
<a name="handleupdate"></a> | ||
#### `telegraf.handleUpdate(rawUpdate, [webHookResponse])` | ||
Handle raw Telegram update. | ||
In case you use centralized webhook server, queue, etc. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| rawUpdate | `object` | Telegram update payload | | ||
| [webHookResponse] | `object` | (Optional) [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) | | ||
## Telegram API | ||
```js | ||
const Telegram = require('telegraf').Telegram | ||
``` | ||
- [`new Telegram(token)`](#new-telegram) | ||
- [`.answerCallbackQuery(callbackQueryId, text, showAlert)`](#answercallbackquery) | ||
@@ -27,7 +296,4 @@ - [`.answerInlineQuery(inlineQueryId, results, extra)`](#answerinlinequery) | ||
- [`.getUserProfilePhotos(userId, offset, limit)`](#getuserprofilephotos) | ||
- [`.handleUpdate(rawUpdate, response)`](#handleupdate) | ||
- [`.hears(string|ReGex, handler, [handler...])`](#hears) | ||
- [`.kickChatMember(chatId, userId)`](#kickchatmember) | ||
- [`.leaveChat(chatId)`](#leavechat) | ||
- [`.on(messageType, handler, [handler...])`](#on) | ||
- [`.removeWebHook()`](#removewebhook) | ||
@@ -46,37 +312,9 @@ - [`.sendAudio(chatId, audio, extra)`](#sendaudio) | ||
- [`.setWebHook(url, cert)`](#setwebhook) | ||
- [`.startPolling(timeout, limit)`](#startPolling) | ||
- [`.startWebHook(webHookPath, tlsOptions, port, [host])`](#startwebhook) | ||
- [`.stop()`](#stop) | ||
- [`.unbanChatMember(chatId, userId)`](#unbanchatmember) | ||
- [`.use(function)`](#use) | ||
- [`.webHookCallback(webHookPath)`](#webhookcallback) | ||
*** | ||
<a name="mount"></a> | ||
#### `Telegraf.mount(updateType, handler, [handler...]) => GeneratorFunction` | ||
Generates middleware for handling provided [update type](#update-types). | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| updateType | `string`\|`string[]` | [update type](#update-types) | | ||
| handler | `GeneratorFunction` | Handler | | ||
* * * | ||
<a name="compose"></a> | ||
#### `Telegraf.compose(handlers) => GeneratorFunction` | ||
<a name="new-telegram"></a> | ||
#### `new Telegram(token, options)` | ||
Compose `middleware` returning a fully valid middleware comprised of all those which are passed. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| handlers | `GeneratorFunction[]` | Array of handlers | | ||
* * * | ||
<a name="new"></a> | ||
#### `new Telegraf(token)` | ||
Initialize new Telegraf app. | ||
@@ -87,7 +325,9 @@ | ||
| token | `string` | [Bot Token](https://core.telegram.org/bots#3-how-do-i-create-a-bot) | | ||
| token | `object` | Options | | ||
* * * | ||
<a name="answercallbackquery"></a> | ||
#### `telegraf.answerCallbackQuery(callbackQueryId, text, showAlert) => Promise` | ||
#### `telegram.answerCallbackQuery(callbackQueryId, text, showAlert) => Promise` | ||
@@ -107,3 +347,3 @@ Use this method to send answers to callback queries. | ||
<a name="answerinlinequery"></a> | ||
#### `telegraf.answerInlineQuery(inlineQueryId, results, extra) => Promise` | ||
#### `telegram.answerInlineQuery(inlineQueryId, results, extra) => Promise` | ||
@@ -121,3 +361,3 @@ Use this method to send answers to an inline query. | ||
<a name="editmessagecaption"></a> | ||
#### `telegraf.editMessageCaption(chatId, messageId, caption, extra) => Promise` | ||
#### `telegram.editMessageCaption(chatId, messageId, caption, extra) => Promise` | ||
@@ -136,3 +376,3 @@ Use this method to edit captions of messages sent by the bot or via the bot | ||
<a name="editmessagereplymarkup"></a> | ||
#### `telegraf.editMessageReplyMarkup(chatId, messageId, markup, extra) => Promise` | ||
#### `telegram.editMessageReplyMarkup(chatId, messageId, markup, extra) => Promise` | ||
@@ -151,3 +391,3 @@ Use this method to edit only the reply markup of messages sent by the bot or via the bot. | ||
<a name="editmessagetext"></a> | ||
#### `telegraf.editMessageText(chatId, messageId, text, extra) => Promise` | ||
#### `telegram.editMessageText(chatId, messageId, text, extra) => Promise` | ||
@@ -166,3 +406,3 @@ Use this method to edit text messages sent by the bot or via the bot. | ||
<a name="forwardmessage"></a> | ||
#### `telegraf.forwardMessage(chatId, fromChatId, messageId, extra) => Promise` | ||
#### `telegram.forwardMessage(chatId, fromChatId, messageId, extra) => Promise` | ||
@@ -182,3 +422,3 @@ Forwards message. | ||
<a name="sendcopy"></a> | ||
#### `telegraf.sendCopy(chatId, message, extra) => Promise` | ||
#### `telegram.sendCopy(chatId, message, extra) => Promise` | ||
@@ -196,3 +436,3 @@ Sends message copy. | ||
<a name="getchat"></a> | ||
#### `telegraf.getChat(chatId) => Promise` | ||
#### `telegram.getChat(chatId) => Promise` | ||
@@ -210,3 +450,3 @@ Use this method to 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.). | ||
<a name="getchatadministrators"></a> | ||
#### `telegraf.getChatAdministrators(chatId) => Promise` | ||
#### `telegram.getChatAdministrators(chatId) => Promise` | ||
@@ -224,3 +464,3 @@ Use this method to get a list of administrators in a chat. On success, returns an Array of ChatMember objects that contains information about all chat administrators except other bots. If the chat is a group or a supergroup and no administrators were appointed, only the creator will be returned. | ||
<a name="getchatmember"></a> | ||
#### `telegraf.getChatMember(chatId) => Promise` | ||
#### `telegram.getChatMember(chatId) => Promise` | ||
@@ -237,3 +477,3 @@ Use this method to get information about a member of a chat. | ||
<a name="getchatmemberscount"></a> | ||
#### `telegraf.getChatMembersCount(chatId) => Promise` | ||
#### `telegram.getChatMembersCount(chatId) => Promise` | ||
@@ -251,3 +491,3 @@ Use this method to get the number of members in a chat. | ||
<a name="getfile"></a> | ||
#### `telegraf.getFile(fileId) => Promise` | ||
#### `telegram.getFile(fileId) => Promise` | ||
@@ -265,3 +505,3 @@ Returns basic info about a file and prepare it for downloading. | ||
<a name="getFileLink"></a> | ||
#### `telegraf.getFileLink(fileId) => Promise` | ||
#### `telegram.getFileLink(fileId) => Promise` | ||
@@ -279,3 +519,3 @@ Returns link to file. | ||
<a name="getme"></a> | ||
#### `telegraf.getMe() => Promise` | ||
#### `telegram.getMe() => Promise` | ||
@@ -289,3 +529,3 @@ Returns basic information about the bot. | ||
<a name="getuserprofilephotos"></a> | ||
#### `telegraf.getUserProfilePhotos(userId, offset, limit) => Promise` | ||
#### `telegram.getUserProfilePhotos(userId, offset, limit) => Promise` | ||
@@ -304,29 +544,4 @@ Returns profiles photos for provided user. | ||
<a name="handleupdate"></a> | ||
#### `telegraf.handleUpdate(rawUpdate, [webHookResponse])` | ||
Handle raw Telegram update. | ||
In case you use centralized webhook server, queue, etc. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| rawUpdate | `object` | Telegram update payload | | ||
| [webHookResponse] | `object` | (Optional) [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) | | ||
* * * | ||
<a name="hears"></a> | ||
#### `telegraf.hears(pattern, handler, [handler...])` | ||
Registers handler only for `text` updates using string pattern or RegEx. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| pattern | `string`\|`RegEx` | Pattern or RegEx | | ||
| handler | `GeneratorFunction` | Handler | | ||
* * * | ||
<a name="kickchatmember"></a> | ||
#### `telegraf.kickChatMember(chatId, userId) => Promise` | ||
#### `telegram.kickChatMember(chatId, userId) => Promise` | ||
@@ -346,3 +561,3 @@ Use this method to kick a user from a group or a supergroup. | ||
<a name="leavechat"></a> | ||
#### `telegraf.leaveChat(chatId) => Promise` | ||
#### `telegram.leaveChat(chatId) => Promise` | ||
@@ -359,24 +574,13 @@ Use this method for your bot to leave a group, supergroup or channel. | ||
<a name="on"></a> | ||
#### `telegraf.on(updateType, handler, [handler...])` | ||
Registers handler for provided [update type](#update-types). | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| updateType | `string`\|`string[]` | [update type](#update-types) | | ||
| handler | `GeneratorFunction` | Handler | | ||
* * * | ||
<a name="removewebhook"></a> | ||
#### `telegraf.removeWebHook() => Promise` | ||
#### `telegram.removeWebHook() => Promise` | ||
Removes webhook. Shortcut for `Telegraf.setWebHook('')` | ||
Removes webhook. Shortcut for `Telegram.setWebHook('')` | ||
<sub>[Related Telegram api docs](https://core.telegram.org/bots/api#removewebhook)</sub> | ||
* * * | ||
<a name="sendaudio"></a> | ||
#### `telegraf.sendAudio(chatId, audio, extra) => Promise` | ||
#### `telegram.sendAudio(chatId, audio, extra) => Promise` | ||
@@ -394,3 +598,3 @@ Sends audio. | ||
<a name="sendchataction"></a> | ||
#### `telegraf.sendChatAction(chatId, action) => Promise` | ||
#### `telegram.sendChatAction(chatId, action) => Promise` | ||
@@ -407,3 +611,3 @@ Sends chat action. | ||
<a name="sendcontact"></a> | ||
#### `telegraf.sendContact(chatId, phoneNumber, firstName, extra) => Promise` | ||
#### `telegram.sendContact(chatId, phoneNumber, firstName, extra) => Promise` | ||
@@ -422,3 +626,3 @@ Sends document. | ||
<a name="senddocument"></a> | ||
#### `telegraf.sendDocument(chatId, doc, extra) => Promise` | ||
#### `telegram.sendDocument(chatId, doc, extra) => Promise` | ||
@@ -436,3 +640,3 @@ Sends document. | ||
<a name="sendlocation"></a> | ||
#### `telegraf.sendLocation(chatId, latitude, longitude, extra) => Promise` | ||
#### `telegram.sendLocation(chatId, latitude, longitude, extra) => Promise` | ||
@@ -451,3 +655,3 @@ Sends location. | ||
<a name="sendmessage"></a> | ||
#### `telegraf.sendMessage(chatId, text, extra) => Promise` | ||
#### `telegram.sendMessage(chatId, text, extra) => Promise` | ||
@@ -465,3 +669,3 @@ Sends text message. | ||
<a name="sendphoto"></a> | ||
#### `telegraf.sendPhoto(chatId, photo, extra) => Promise` | ||
#### `telegram.sendPhoto(chatId, photo, extra) => Promise` | ||
@@ -479,3 +683,3 @@ Sends photo. | ||
<a name="sendsticker"></a> | ||
#### `telegraf.sendSticker(chatId, sticker, extra) => Promise` | ||
#### `telegram.sendSticker(chatId, sticker, extra) => Promise` | ||
@@ -493,3 +697,3 @@ Sends sticker. | ||
<a name="sendvenue"></a> | ||
#### `telegraf.sendVenue(chatId, latitude, longitude, title, address, extra) => Promise` | ||
#### `telegram.sendVenue(chatId, latitude, longitude, title, address, extra) => Promise` | ||
@@ -510,3 +714,3 @@ Sends venue information. | ||
<a name="sendvideo"></a> | ||
#### `telegraf.sendVideo(chatId, video, extra) => Promise` | ||
#### `telegram.sendVideo(chatId, video, extra) => Promise` | ||
@@ -524,3 +728,3 @@ Sends video. | ||
<a name="sendvoice"></a> | ||
#### `telegraf.sendVoice(chatId, voice, extra) => Promise` | ||
#### `telegram.sendVoice(chatId, voice, extra) => Promise` | ||
@@ -538,3 +742,3 @@ Sends voice. | ||
<a name="setwebhook"></a> | ||
#### `telegraf.setWebHook(url, [cert]) => Promise` | ||
#### `telegram.setWebHook(url, [cert]) => Promise` | ||
@@ -552,37 +756,4 @@ Specifies an url to receive incoming updates via an outgoing webhook. | ||
<a name="startwebhook"></a> | ||
#### `telegraf.startWebHook(webHookPath, tlsOptions, port, [host])` | ||
Start listening @ `https://host:port/webHookPath` for Telegram calls. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| webHookPath | `string` | Webhook url path (see Telegraf.setWebHook) | | ||
| tlsOptions | `object` | (Optional) [TLS server options](https://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener). Pass null to use http | | ||
| port | `number` | Port number | | ||
| [host] | `string` | (Optional) Hostname | | ||
* * * | ||
<a name="startPolling"></a> | ||
#### `telegraf.startPolling(timeout, limit)` | ||
Start poll updates. | ||
| Param | Type | Default | Description | | ||
| --- | --- | --- | --- | | ||
| timeout | `number` | 0 | Poll timeout | | ||
| limit | `number` | 100 | Limits the number of updates to be retrieved | | ||
* * * | ||
<a name="stop"></a> | ||
#### `telegraf.stop()` | ||
Stop WebHook and polling | ||
* * * | ||
<a name="unbanchatmember"></a> | ||
#### `telegraf.unbanChatMember(chatId, userId) => Promise` | ||
#### `telegram.unbanChatMember(chatId, userId) => Promise` | ||
@@ -600,25 +771,2 @@ Use this method to unban a previously kicked user in a supergroup. | ||
<a name="use"></a> | ||
#### `telegraf.use(middleware)` | ||
Registers a middleware. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| middleware | `function` | Middleware function | | ||
* * * | ||
<a name="webhookcallback"></a> | ||
#### `telegraf.webHookCallback(webHookPath) => Function` | ||
Return a callback function suitable for the http[s].createServer() method to handle a request. | ||
You may also use this callback function to mount your telegraf app in a Koa/Connect/Express app. | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| webHookPath | `string` | Webhook url path (see Telegraf.setWebHook) | | ||
* * * | ||
### Update types | ||
@@ -640,10 +788,10 @@ | ||
// Handle message update | ||
telegraf.on('message', function * () { | ||
this.reply('Hey there!') | ||
telegraf.on('message', (ctx) => { | ||
return ctx.reply('Hey there!') | ||
}) | ||
// Handle sticker update | ||
telegraf.on(['sticker', 'photo'], function * () { | ||
console.log(this.message) | ||
this.reply('Cool!') | ||
telegraf.on(['sticker', 'photo'], (ctx) => { | ||
console.log(ctx.message) | ||
return ctx.reply('Cool!') | ||
}) | ||
@@ -668,3 +816,3 @@ | ||
*FYI: Telegram servers detect content type using file extension(May 2016).* | ||
*FYI: Telegram servers detect content type using file extension (May 2016).* | ||
@@ -675,6 +823,6 @@ Example: | ||
// resend existing file by file_id | ||
telegraf.sendSticker('chatId', '123123jkbhj6b') | ||
telegram.sendSticker('chatId', '123123jkbhj6b') | ||
// send file | ||
telegraf.sendVideo('chatId', { | ||
telegram.sendVideo('chatId', { | ||
source: '/path/to/video.mp4' | ||
@@ -684,3 +832,3 @@ }) | ||
// send stream | ||
telegraf.sendVideo('chatId', { | ||
telegram.sendVideo('chatId', { | ||
source: fs.createReadStream('/path/to/video.mp4') | ||
@@ -690,3 +838,3 @@ }) | ||
// send buffer | ||
telegraf.sendVoice('chatId', { | ||
telegram.sendVoice('chatId', { | ||
source: new Buffer() | ||
@@ -696,3 +844,3 @@ }) | ||
// send url | ||
telegraf.sendPhoto('chatId', { | ||
telegram.sendPhoto('chatId', { | ||
url: 'http://lorempixel.com/400/200/cats/', | ||
@@ -704,88 +852,1 @@ filename: 'kitten.jpg' | ||
<sub>[Related Telegram api docs](https://core.telegram.org/bots/api#file)</sub> | ||
## Shortcuts | ||
Available shortcuts for **message** update: | ||
- `this.getChat() -> `[`telegraf.getChat()`](#getchat) | ||
- `this.getChatAdministrators() -> `[`telegraf.getChatAdministrators()`](#getchatadministrators) | ||
- `this.getChatMember() -> `[`telegraf.getChatMember()`](#getchatmember) | ||
- `this.getChatMembersCount() -> `[`telegraf.getChatMembersCount()`](#getchatmemberscount) | ||
- `this.leaveChat() -> `[`telegraf.leaveChat()`](#leavechat) | ||
- `this.reply() -> `[`telegraf.sendMessage()`](#sendmessage) | ||
- `this.replyWithMarkdown() -> `[`telegraf.sendMessage()`](#sendmessage) | ||
- `this.replyWithHTML() -> `[`telegraf.sendMessage()`](#sendmessage) | ||
- `this.replyWithAudio() -> `[`telegraf.sendAudio()`](#sendaudio) | ||
- `this.replyWithChatAction() -> `[`telegraf.sendChatAction()`](#sendchataction) | ||
- `this.replyWithDocument() -> `[`telegraf.sendDocument()`](#senddocument) | ||
- `this.replyWithLocation() -> `[`telegraf.sendLocation()`](#sendlocation) | ||
- `this.replyWithPhoto() -> `[`telegraf.sendPhoto()`](#sendphoto) | ||
- `this.replyWithSticker() -> `[`telegraf.sendSticker()`](#sendsticker) | ||
- `this.replyWithVideo() -> `[`telegraf.sendVideo()`](#sendvideo) | ||
- `this.replyWithVoice() -> `[`telegraf.sendVoice()`](#sendvoice) | ||
Available shortcuts for **callback_query** update: | ||
- `this.answerCallbackQuery() -> `[`telegraf.answerCallbackQuery()`](#answercallbackquery) | ||
- `this.getChat() -> `[`telegraf.getChat()`](#getchat) | ||
- `this.getChatAdministrators() -> `[`telegraf.getChatAdministrators()`](#getchatadministrators) | ||
- `this.getChatMember() -> `[`telegraf.getChatMember()`](#getchatmember) | ||
- `this.getChatMembersCount() -> `[`telegraf.getChatMembersCount()`](#getchatmemberscount) | ||
- `this.leaveChat() -> `[`telegraf.leaveChat()`](#leavechat) | ||
- `this.reply() -> `[`telegraf.sendMessage()`](#sendmessage) | ||
- `this.replyWithMarkdown() -> `[`telegraf.sendMessage()`](#sendmessage) | ||
- `this.replyWithHTML() -> `[`telegraf.sendMessage()`](#sendmessage) | ||
- `this.replyWithAudio() -> `[`telegraf.sendAudio()`](#sendaudio) | ||
- `this.replyWithChatAction() -> `[`telegraf.sendChatAction()`](#sendchataction) | ||
- `this.replyWithDocument() -> `[`telegraf.sendDocument()`](#senddocument) | ||
- `this.replyWithLocation() -> `[`telegraf.sendLocation()`](#sendlocation) | ||
- `this.replyWithPhoto() -> `[`telegraf.sendPhoto()`](#sendphoto) | ||
- `this.replyWithSticker() -> `[`telegraf.sendSticker()`](#sendsticker) | ||
- `this.replyWithVideo() -> `[`telegraf.sendVideo()`](#sendvideo) | ||
- `this.replyWithVoice() -> `[`telegraf.sendVoice()`](#sendvoice) | ||
Available shortcuts for **inline_query** update: | ||
- `this.answerInlineQuery() -> `[`telegraf.answerInlineQuery()`](#answerinlinequery) | ||
### Examples | ||
```js | ||
var telegraf = new Telegraf(process.env.BOT_TOKEN) | ||
telegraf.on('text', function * (){ | ||
// Simple usage | ||
telegraf.sendMessage(this.message.chat.id, `Hello ${this.state.role}`) | ||
// Using shortcut | ||
this.reply(`Hello ${this.state.role}`) | ||
// If you want to mark message as reply to source message | ||
this.reply(`Hello ${this.state.role}`, { reply_to_message_id: this.message.id }) | ||
}) | ||
telegraf.on('/quit', function * (){ | ||
// Simple usage | ||
telegraf.leaveChat(this.message.chat.id) | ||
// Using shortcut | ||
this.leaveChat() | ||
}) | ||
telegraf.on('callback_query', function * (){ | ||
// Simple usage | ||
telegraf.answerCallbackQuery(this.callbackQuery.id) | ||
// Using shortcut | ||
this.answerCallbackQuery() | ||
}) | ||
telegraf.on('inline_query', function * (){ | ||
var result = [] | ||
// Simple usage | ||
telegraf.answerInlineQuery(this.inlineQuery.id, result) | ||
// Using shortcut | ||
this.answerInlineQuery(result) | ||
}) | ||
``` |
@@ -12,12 +12,12 @@ var debug = require('debug')('telegraf:session-memory') | ||
return function * (next) { | ||
var key = opts.getSessionKey(this) | ||
return (ctx, next) => { | ||
var key = opts.getSessionKey(ctx) | ||
if (!key) { | ||
return yield next | ||
return next() | ||
} | ||
var session = {} | ||
this.__defineGetter__('session', function () { | ||
ctx.__defineGetter__('session', function () { | ||
return session | ||
}) | ||
this.__defineSetter__('session', function (val) { | ||
ctx.__defineSetter__('session', function (val) { | ||
session = Object.assign({}, val) | ||
@@ -28,5 +28,3 @@ }) | ||
session = db[key] || {} | ||
yield next | ||
} catch (err) { | ||
throw err | ||
return next() | ||
} finally { | ||
@@ -33,0 +31,0 @@ debug('save session', session) |
@@ -1,3 +0,1 @@ | ||
var _ = require('lodash') | ||
module.exports = { | ||
@@ -41,20 +39,2 @@ defaultExtensions: { | ||
], | ||
chatShortcuts: [ | ||
{ name: 'reply', target: 'sendMessage' }, | ||
{ name: 'getChat', target: 'getChat' }, | ||
{ name: 'leaveChat', target: 'leaveChat' }, | ||
{ name: 'getChatAdministrators', target: 'getChatAdministrators' }, | ||
{ name: 'getChatMember', target: 'getChatMember' }, | ||
{ name: 'getChatMembersCount', target: 'getChatMembersCount' }, | ||
{ name: 'replyWithPhoto', target: 'sendPhoto' }, | ||
{ name: 'replyWithAudio', target: 'sendAudio' }, | ||
{ name: 'replyWithDocument', target: 'sendDocument' }, | ||
{ name: 'replyWithSticker', target: 'sendSticker' }, | ||
{ name: 'replyWithVideo', target: 'sendVideo' }, | ||
{ name: 'replyWithVoice', target: 'sendVoice' }, | ||
{ name: 'replyWithChatAction', target: 'sendChatAction' }, | ||
{ name: 'replyWithLocation', target: 'sendLocation' }, | ||
{ name: 'replyWithVenue', target: 'sendVenue' }, | ||
{ name: 'replyWithContact', target: 'sendContact' } | ||
], | ||
webHookAnswerBlacklist: [ | ||
@@ -92,4 +72,4 @@ 'getChat', | ||
sticker: (message) => message.sticker.file_id, | ||
photo: (message) => _.max(message.photo, 'file_size').file_id | ||
photo: (message) => message.photo[message.photo.length - 1].file_id | ||
} | ||
} |
@@ -1,397 +0,318 @@ | ||
var debug = require('debug')('telegraf:core') | ||
var Promise = require('bluebird') | ||
var ware = require('co-ware') | ||
var util = require('util') | ||
var Telegram = require('./telegram-api') | ||
var memorySession = require('./memory-session') | ||
var platform = require('./platform') | ||
const debug = require('debug')('telegraf:core') | ||
const Promise = require('bluebird') | ||
const Telegram = require('./telegram') | ||
const memorySession = require('./memory-session') | ||
const TelegrafContext = require('./context') | ||
/** | ||
* Represents a Telegraf app. | ||
* @constructor | ||
* @param {string} token - Telegram token. | ||
* @param {object} options - Additional options. | ||
*/ | ||
function Telegraf (token, options) { | ||
this.options = Object.assign({webHookAnswer: true}, options) | ||
this.middleware = [] | ||
this.context = {} | ||
this.polling = { | ||
offset: 0, | ||
started: false | ||
} | ||
Telegram.call(this, token, this.options.apiRoot) | ||
} | ||
// String -> RegEx magic! | ||
var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g | ||
util.inherits(Telegraf, Telegram) | ||
class Telegraf { | ||
/** | ||
* Expose `Telegraf`. | ||
*/ | ||
module.exports = Telegraf | ||
/** | ||
* Initialize a new `Telegraf` application. | ||
* @param {string} token - Telegram token. | ||
* @param {object} options - Additional options. | ||
* @api public | ||
*/ | ||
constructor (token, options) { | ||
const opts = Object.assign({webHookAnswer: true}, options) | ||
this.token = token | ||
this.telegram = new Telegram(token) | ||
this.options = opts | ||
this.middleware = [] | ||
this.context = {} | ||
this.polling = { | ||
offset: 0, | ||
started: false | ||
} | ||
} | ||
/** | ||
* Telegraf prototype. | ||
*/ | ||
var telegraf = Telegraf.prototype | ||
/** | ||
* Default error handler. | ||
* | ||
* @param {Error} err | ||
* @api private | ||
*/ | ||
onError (err) { | ||
const msg = err.stack || err.toString() | ||
console.error() | ||
console.error(msg.replace(/^/gm, ' ')) | ||
console.error() | ||
throw err | ||
} | ||
/** | ||
* Expose `memorySession`. | ||
*/ | ||
Telegraf.memorySession = memorySession | ||
/** | ||
* Start polling loop. | ||
* | ||
* @param {number} timeout | ||
* @param {number} limit | ||
* @return {Telegraf} self | ||
* @api public | ||
*/ | ||
startPolling (timeout, limit) { | ||
this.polling.started = true | ||
this.polling.timeout = timeout || 0 | ||
this.polling.limit = limit || 100 | ||
this.pollingLoop() | ||
return this | ||
} | ||
/** | ||
* O(1) | ||
* | ||
* @api private | ||
*/ | ||
function * noop () {} | ||
/** | ||
* Compose `middleware` returning | ||
* a fully valid middleware comprised | ||
* of all those which are passed. | ||
* | ||
* @param {GeneratorFumction[]} middleware | ||
* @return {GeneratorFumction} | ||
* @api public | ||
*/ | ||
Telegraf.compose = function (middleware) { | ||
return function * (next) { | ||
if (!next) { | ||
next = noop() | ||
/** | ||
* Return a callback function suitable for the http[s].createServer() method to handle a request. | ||
* You may also use this callback function to mount your telegraf app in a Koa/Connect/Express app. | ||
* | ||
* @param {string} webHookPath - Webhook secret path | ||
* @return {Function} | ||
* @api public | ||
*/ | ||
webHookCallback (webHookPath) { | ||
webHookPath = webHookPath || '/' | ||
return (req, res, next) => { | ||
if (req.method !== 'POST' || req.url !== `${webHookPath}`) { | ||
if (next && typeof next === 'function') { | ||
return next() | ||
} | ||
res.statusCode = 403 | ||
return res.end() | ||
} | ||
var body = '' | ||
req.on('data', (chunk) => { | ||
body += chunk.toString() | ||
}) | ||
req.on('end', () => { | ||
try { | ||
const update = JSON.parse(body) | ||
this.handleUpdate(update, res) | ||
.then(() => { | ||
if (!res.finished) { | ||
res.writeHead(200) | ||
res.end() | ||
} | ||
}) | ||
.catch((err) => { | ||
debug('webhook error', err) | ||
res.writeHead(500) | ||
res.end() | ||
}) | ||
} catch (error) { | ||
this.onError(error) | ||
res.writeHead(415) | ||
res.end() | ||
} | ||
}) | ||
} | ||
var i = middleware.length | ||
while (i--) { | ||
next = middleware[i].call(this, next) | ||
} | ||
return yield * next | ||
} | ||
} | ||
/** | ||
* Generates `middleware` for handling provided update types. | ||
* | ||
* @param {string|string[]} updateTypes | ||
* @param {(GeneratorFunction|GeneratorFunction[])} fn - middleware | ||
* @api public | ||
*/ | ||
Telegraf.mount = function (updateTypes) { | ||
if (typeof updateTypes === 'string') { | ||
updateTypes = [updateTypes] | ||
/** | ||
* Start WebHook. | ||
* | ||
* @param {string} webHookPath - Webhook secret path | ||
* @param {Object} tlsOptions - TLS options | ||
* @param {number} port - Port number | ||
* @param {string} [host] - WebHook secret path | ||
* @return {Telegraf} self | ||
* @api public | ||
*/ | ||
startWebHook (webHookPath, tlsOptions, port, host) { | ||
const callback = this.webHookCallback(webHookPath) | ||
this.webhookServer = tlsOptions | ||
? require('https').createServer(tlsOptions, callback) | ||
: require('http').createServer(callback) | ||
this.webhookServer.listen(port, host, () => { | ||
debug('WebHook listening on port: %s', port) | ||
}) | ||
return this | ||
} | ||
var fns = [].slice.call(arguments, 1) | ||
return function * (next) { | ||
if (updateTypes.indexOf(this.updateType) !== -1 || updateTypes.indexOf(this.updateSubType) !== -1) { | ||
yield Telegraf.compose(fns) | ||
/** | ||
* Stop WebHook/Polling. | ||
* | ||
* @return {Telegraf} self | ||
* @api public | ||
*/ | ||
stop () { | ||
this.polling.started = false | ||
if (this.webhookServer) { | ||
this.webhookServer.close() | ||
} | ||
yield next | ||
return this | ||
} | ||
} | ||
/** | ||
* Default error handler. | ||
* | ||
* @param {Error} err | ||
* @api private | ||
*/ | ||
telegraf.onError = function (err) { | ||
var msg = err.stack || err.toString() | ||
console.error() | ||
console.error(msg.replace(/^/gm, ' ')) | ||
console.error() | ||
throw err | ||
} | ||
/** | ||
* Register a middleware. | ||
* | ||
* @param {Function} fn - middleware | ||
* @return {Telegraf} self | ||
* @api public | ||
*/ | ||
use (fn) { | ||
if (typeof fn !== 'function') { | ||
throw new TypeError('Middleware must be composed of functions') | ||
} | ||
this.middleware.push(fn) | ||
return this | ||
} | ||
/** | ||
* Start polling loop. | ||
* | ||
* @param {number} timeout | ||
* @param {number} limit | ||
* @return {Telegraf} self | ||
* @api public | ||
*/ | ||
telegraf.startPolling = function (timeout, limit) { | ||
this.polling.started = true | ||
this.polling.timeout = timeout || 0 | ||
this.polling.limit = limit || 100 | ||
this.pollingLoop() | ||
return this | ||
} | ||
/** | ||
* Use the given middleware as handler for `updateType`. | ||
* | ||
* @param {string} updateType - Update type | ||
* @param {(Function|Function[])} fn - middleware | ||
* @return {Telegraf} self | ||
* @api public | ||
*/ | ||
on (updateTypes) { | ||
const fns = [].slice.call(arguments, 1) | ||
if (fns.length === 0) { | ||
throw new TypeError('At least one Middleware must be provided') | ||
} | ||
this.use(Telegraf.mount(updateTypes, Telegraf.compose(fns))) | ||
return this | ||
} | ||
/** | ||
* Return a callback function suitable for the http[s].createServer() method to handle a request. | ||
* You may also use this callback function to mount your telegraf app in a Koa/Connect/Express app. | ||
* | ||
* @param {string} webHookPath - Webhook secret path | ||
* @return {Function} | ||
* @api public | ||
*/ | ||
telegraf.webHookCallback = function (webHookPath) { | ||
webHookPath = webHookPath || '/' | ||
return (req, res, next) => { | ||
if (req.method !== 'POST' || req.url !== `${webHookPath}`) { | ||
if (next && typeof next === 'function') { | ||
return next() | ||
/** | ||
* Use the given middleware as handler for text `trigger`. | ||
* | ||
* @param {(string|RegEx)} trigger - Text trigger | ||
* @param {(Function|Function[])} fn - middleware | ||
* @return {Telegraf} self | ||
* @api public | ||
*/ | ||
hears (trigger) { | ||
const regex = trigger instanceof RegExp | ||
? trigger | ||
: new RegExp(trigger.replace(matchOperatorsRe, '\\$&')) | ||
const fns = [].slice.call(arguments, 1) | ||
const handler = Telegraf.compose(fns) | ||
var middleware = (ctx, next) => { | ||
const result = regex.exec(ctx.message.text) | ||
if (result) { | ||
ctx.match = result || [] | ||
return handler(ctx, next) | ||
} | ||
res.statusCode = 403 | ||
return res.end() | ||
return next() | ||
} | ||
var body = '' | ||
req.on('data', (chunk) => { | ||
body += chunk.toString() | ||
}) | ||
req.on('end', () => { | ||
try { | ||
var update = JSON.parse(body) | ||
this.handleUpdate(update, res) | ||
.then(() => { | ||
if (!res.finished) { | ||
res.writeHead(200) | ||
res.end() | ||
} | ||
}) | ||
.catch((err) => { | ||
debug('webhook error', err) | ||
res.writeHead(500) | ||
res.end() | ||
}) | ||
} catch (error) { | ||
this.onError(error) | ||
res.writeHead(415) | ||
res.end() | ||
} | ||
}) | ||
this.use(Telegraf.mount('text', middleware)) | ||
return this | ||
} | ||
} | ||
/** | ||
* Start WebHook. | ||
* | ||
* @param {string} webHookPath - Webhook secret path | ||
* @param {Object} tlsOptions - TLS options | ||
* @param {number} port - Port number | ||
* @param {string} [host] - WebHook secret path | ||
* @return {Telegraf} self | ||
* @api public | ||
*/ | ||
telegraf.startWebHook = function (webHookPath, tlsOptions, port, host) { | ||
var callback = this.webHookCallback(webHookPath) | ||
this.webhookServer = tlsOptions | ||
? require('https').createServer(tlsOptions, callback) | ||
: require('http').createServer(callback) | ||
this.webhookServer.listen(port, host, () => { | ||
debug('WebHook listening on port: %s', port) | ||
}) | ||
return this | ||
} | ||
/** | ||
* Handle Telegram update | ||
* | ||
* @param {Object} update - Telegram update object | ||
* @param {Object} [webHookResponse] - http.ServerResponse | ||
* @return {Promise} | ||
* @api public | ||
*/ | ||
handleUpdate (update, webHookResponse) { | ||
debug('⚡ update', update.update_id) | ||
const ctx = new TelegrafContext(this.token, update, webHookResponse) | ||
for (let key in this.context) { | ||
ctx[key] = this.context[key] | ||
} | ||
const fn = Telegraf.compose(this.middleware) | ||
return fn(ctx).catch(this.onError) | ||
} | ||
/** | ||
* Stop WebHook/Polling. | ||
* | ||
* @return {Telegraf} self | ||
* @api public | ||
*/ | ||
telegraf.stop = function () { | ||
this.polling.started = false | ||
if (this.webhookServer) { | ||
this.webhookServer.close() | ||
/** | ||
* Polling loop | ||
* | ||
* @api private | ||
*/ | ||
pollingLoop () { | ||
if (!this.polling.started) { | ||
return | ||
} | ||
this.telegram.getUpdates(this.polling.timeout, this.polling.limit, this.polling.offset) | ||
.catch((err) => { | ||
console.error('Telegraf: network error', err) | ||
return new Promise((resolve) => { | ||
setTimeout(() => resolve([]), 1000) | ||
}) | ||
}) | ||
.map((update) => { | ||
return this.handleUpdate(update).then(() => { | ||
this.polling.offset = update.update_id + 1 | ||
}) | ||
}, {concurrency: 1}) | ||
.then(() => this.pollingLoop()) | ||
.catch((err) => { | ||
console.error('Telegraf: polling error', err) | ||
this.polling.started = false | ||
}) | ||
} | ||
return this | ||
} | ||
/** | ||
* Register a middleware. | ||
* | ||
* @param {GeneratorFunction} fn - middleware | ||
* @return {Telegraf} self | ||
* @api public | ||
* Expose `memorySession`. | ||
*/ | ||
telegraf.use = function (fn) { | ||
this.middleware.push(fn) | ||
return this | ||
} | ||
Telegraf.memorySession = memorySession | ||
/** | ||
* Use the given middleware as handler for `updateType`. | ||
* | ||
* @param {string} updateType - Update type | ||
* @param {(GeneratorFunction|GeneratorFunction[])} fn - middleware | ||
* @return {Telegraf} self | ||
* @api public | ||
* Expose `Telegram`. | ||
*/ | ||
telegraf.on = function (updateTypes) { | ||
var fns = [].slice.call(arguments, 1) | ||
this.use(Telegraf.mount(updateTypes, Telegraf.compose(fns))) | ||
return this | ||
} | ||
Telegraf.Telegram = Telegram | ||
// String -> RegEx magic! | ||
var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g | ||
/** | ||
* Use the given middleware as handler for text `trigger`. | ||
* Compose `middleware` returning | ||
* a fully valid middleware comprised | ||
* of all those which are passed. | ||
* | ||
* @param {(string|RegEx)} trigger - Text trigger | ||
* @param {(GeneratorFunction|GeneratorFunction[])} fn - middleware | ||
* @return {Telegraf} self | ||
* @param {Function[]} middleware | ||
* @return {Function} | ||
* @api public | ||
*/ | ||
telegraf.hears = function (trigger) { | ||
var regex = trigger instanceof RegExp | ||
? trigger | ||
: new RegExp(trigger.replace(matchOperatorsRe, '\\$&')) | ||
var fns = [].slice.call(arguments, 1) | ||
var middleware = Telegraf.mount('text', function * (next) { | ||
var result = regex.exec(this.message.text) | ||
if (result) { | ||
this.__defineGetter__('match', function () { | ||
return result || [] | ||
}) | ||
yield Telegraf.compose(fns) | ||
Telegraf.compose = function (middleware) { | ||
if (!Array.isArray(middleware)) { | ||
middleware = [middleware] | ||
} | ||
for (const fn of middleware) { | ||
if (typeof fn !== 'function') { | ||
throw new TypeError('Middleware must be composed of functions') | ||
} | ||
yield next | ||
}) | ||
this.use(middleware) | ||
return this | ||
} | ||
/** | ||
* Polling loop | ||
* | ||
* @api private | ||
*/ | ||
telegraf.pollingLoop = function () { | ||
if (!this.polling.started) { | ||
return | ||
} | ||
this.getUpdates(this.polling.timeout, this.polling.limit, this.polling.offset) | ||
.catch((err) => { | ||
console.error('Telegraf: network error', err) | ||
return new Promise((resolve) => { | ||
setTimeout(() => resolve([]), 1000) | ||
}) | ||
}) | ||
.map((update) => { | ||
return this.handleUpdate(update).then(() => { | ||
this.polling.offset = update.update_id + 1 | ||
}) | ||
}, {concurrency: 1}) | ||
.then(() => this.pollingLoop()) | ||
.catch((err) => { | ||
console.error('Telegraf: polling error', err) | ||
this.polling.started = false | ||
}) | ||
} | ||
/** | ||
* Extract raw Telegram update | ||
* | ||
* @param {Object} update - raw Telegram update | ||
* @return {Object} normalized update | ||
* @api private | ||
*/ | ||
telegraf.extractUpdate = function (update) { | ||
var result = {} | ||
platform.updateTypes.forEach((key) => { | ||
if (update[key]) { | ||
result.payload = update[key] | ||
result.type = key | ||
return (ctx, next) => { | ||
let index = -1 | ||
return dispatch(0) | ||
function dispatch (i) { | ||
if (i <= index) { | ||
return Promise.reject(new Error('next() called multiple times')) | ||
} | ||
index = i | ||
const fn = middleware[i] || next | ||
if (!fn) { | ||
return Promise.resolve() | ||
} | ||
try { | ||
return Promise.resolve(fn(ctx, () => dispatch(i + 1))) | ||
} catch (err) { | ||
return Promise.reject(err) | ||
} | ||
} | ||
}) | ||
if (update.message) { | ||
platform.messageSubTypes.forEach((messageType) => { | ||
if (update.message[messageType]) { | ||
result.subType = messageType | ||
} | ||
}) | ||
} | ||
return result | ||
} | ||
/** | ||
* Handle Telegram update | ||
* Generates `middleware` for handling provided update types. | ||
* | ||
* @param {Object} rawUpdate - Telegram update object | ||
* @param {Object} [webHookResponse] - http.ServerResponse | ||
* @return {Promise} | ||
* @param {string|string[]} updateTypes | ||
* @param {(Function)} fn - middleware | ||
* @api public | ||
*/ | ||
telegraf.handleUpdate = function (rawUpdate, webHookResponse) { | ||
var update = this.extractUpdate(rawUpdate) | ||
if (!update.type) { | ||
throw new Error('Undefined update type') | ||
Telegraf.mount = function (updateTypes, middleware) { | ||
if (typeof updateTypes === 'string') { | ||
updateTypes = [updateTypes] | ||
} | ||
debug('⚡ update', update.type, update.subType || '-') | ||
var chat = {id: ''} | ||
var sender = {id: ''} | ||
if (update.payload.from) { | ||
sender = update.payload.from | ||
} | ||
if (update.payload && update.payload.chat) { | ||
chat = update.payload.chat | ||
} | ||
if (update.payload && update.payload.message && update.payload.message.chat) { | ||
chat = update.payload.message.chat | ||
} | ||
var state = {} | ||
var context = Object.assign({ | ||
telegraf: this, | ||
updateType: update.type, | ||
updateSubType: update.subType, | ||
chat: chat, | ||
from: sender, | ||
state: state | ||
}, this.context) | ||
var proxy = this | ||
if (this.options.webHookAnswer && webHookResponse) { | ||
var self = this | ||
// 🐵-patching | ||
proxy = { | ||
sendRequest: function (method, options) { | ||
return self.sendRequest(method, options, webHookResponse) | ||
} | ||
return (ctx, next) => { | ||
if (updateTypes.indexOf(ctx.updateType) !== -1 || updateTypes.indexOf(ctx.updateSubType) !== -1) { | ||
return middleware(ctx, next) | ||
} | ||
return next() | ||
} | ||
} | ||
var payload = update.payload | ||
var chatId = (payload.chat && payload.chat.id) || | ||
(payload.message && payload.message.chat && payload.message.chat.id) | ||
if (chatId) { | ||
platform.chatShortcuts.forEach((command) => { | ||
context[command.name] = this[command.target].bind(proxy, chatId) | ||
}) | ||
context.replyWithMarkdown = function (markdown, extra) { | ||
return context.reply(markdown, Object.assign({ parse_mode: 'Markdown' }, extra)) | ||
} | ||
context.replyWithHTML = function (html, extra) { | ||
return context.reply(html, Object.assign({ parse_mode: 'HTML' }, extra)) | ||
} | ||
} | ||
// 🐫-case | ||
var payloadName = update.type.replace(/^([A-Z])|[\s-_](\w)/g, (match, group1, group2) => { | ||
return group2 ? group2.toUpperCase() : group1.toLowerCase() | ||
}) | ||
context.__defineGetter__(payloadName, function () { | ||
return payload | ||
}) | ||
if (update.type === 'callback_query') { | ||
context.answerCallbackQuery = this.answerCallbackQuery.bind(proxy, payload.id) | ||
} | ||
if (update.type === 'inline_query') { | ||
context.answerInlineQuery = this.answerInlineQuery.bind(proxy, payload.id) | ||
} | ||
var ctx = ware() | ||
ctx.context = context | ||
ctx.use(Telegraf.compose(this.middleware)) | ||
ctx.on('error', this.onError) | ||
return ctx.run() | ||
} | ||
/** | ||
* Expose `Telegraf`. | ||
*/ | ||
module.exports = Telegraf |
{ | ||
"name": "telegraf", | ||
"version": "1.1.2", | ||
"version": "2.0.0-alpha.0", | ||
"description": "📢 Modern Telegram bot framework", | ||
@@ -33,3 +33,4 @@ "main": "lib/telegraf.js", | ||
"lib/telegraf.js", | ||
"lib/telegram-api.js", | ||
"lib/telegram.js", | ||
"lib/context.js", | ||
"lib/platform.js", | ||
@@ -43,6 +44,4 @@ "lib/memory-session.js" | ||
"bluebird": "^3.4.0", | ||
"co-ware": "^1.6.0", | ||
"debug": "^2.2.0", | ||
"is-stream": "^1.1.0", | ||
"lodash": "^4.13.1", | ||
"multipart-stream": "^2.0.1", | ||
@@ -49,0 +48,0 @@ "node-fetch": "^1.5.1" |
179
readme.md
@@ -27,11 +27,11 @@ [](https://www.npmjs.com/package/telegraf) | ||
```js | ||
var Telegraf = require('telegraf'); | ||
var telegraf = new Telegraf(process.env.BOT_TOKEN); | ||
const Telegraf = require('telegraf') | ||
const app = new Telegraf(process.env.BOT_TOKEN) | ||
// Message handling | ||
telegraf.on('message', function * () { | ||
this.reply('*42*', { parse_mode: 'Markdown' }) | ||
app.on('message', (ctx) => { | ||
return ctx.reply('*42*', { parse_mode: 'Markdown' }) | ||
}) | ||
telegraf.startPolling() | ||
app.startPolling() | ||
``` | ||
@@ -42,22 +42,22 @@ | ||
```js | ||
var Telegraf = require('telegraf'); | ||
var telegraf = new Telegraf(process.env.BOT_TOKEN); | ||
const Telegraf = require('telegraf') | ||
const app = new Telegraf(process.env.BOT_TOKEN) | ||
// Look ma, middleware! | ||
var sayYoMiddleware = function * (next) { | ||
yield this.reply('yo') | ||
yield next | ||
const sayYoMiddleware = (ctx, next) => { | ||
return ctx.reply('yo').then(next) | ||
} | ||
// Command handling | ||
telegraf.hears('/command', sayYoMiddleware, function * () { | ||
this.reply('Sure') | ||
app.hears('/command', sayYoMiddleware, (ctx) => { | ||
return ctx.reply('Sure') | ||
}) | ||
// Wow! RegEx | ||
telegraf.hears(/reverse (.+)/, sayYoMiddleware, function * () { | ||
this.reply(this.match[1].split('').reverse().join('')) | ||
app.hears(/reverse (.+)/, sayYoMiddleware, (ctx) => { | ||
return ctx.reply(ctx.match[1].split('').reverse().join('')) | ||
}) | ||
telegraf.startPolling() | ||
app.startPolling() | ||
``` | ||
@@ -71,83 +71,58 @@ | ||
A Telegraf application is an object containing an array of middleware generator functions | ||
which are composed and executed in a stack-like manner upon request. Telegraf is similar to many | ||
other middleware systems that you may have encountered such as Koa, Ruby's Rack, Connect, and so on - | ||
however a key design decision was made to provide high level "sugar" at the otherwise low-level | ||
middleware layer. This improves interoperability, robustness, and makes writing middleware much | ||
more enjoyable. | ||
A Telegraf application is an object containing an array of middlewares which are composed | ||
and executed in a stack-like manner upon request. Is similar to many other middleware systems | ||
that you may have encountered such as Koa, Ruby's Rack, Connect. | ||
```js | ||
var telegraf = new Telegraf(process.env.BOT_TOKEN) | ||
const app = new Telegraf(process.env.BOT_TOKEN) | ||
telegraf.on('text', function * (){ | ||
this.reply('Hello World') | ||
app.on('text', (ctx) => { | ||
return ctx.reply('Hello World') | ||
}) | ||
telegraf.startPolling() | ||
app.startPolling() | ||
``` | ||
### Cascading | ||
Telegraf middleware cascade in a more traditional way as you may be used to with similar tools - | ||
this was previously difficult to make user friendly with node's use of callbacks. | ||
However with generators we can achieve "true" middleware. Contrasting Connect's implementation which | ||
simply passes control through series of functions until one returns, Telegraf yields "downstream", then | ||
control flows back "upstream". | ||
The following example bot will reply with "Hello World", however first the message flows through | ||
the `logger` middleware to mark when the message has been received. When a middleware invokes `yield next` | ||
the function suspends and passes control to the next middleware defined. After there are no more | ||
middleware to execute downstream, the stack will unwind and each middleware is resumed to perform | ||
its upstream behaviour. | ||
```js | ||
var telegraf = new Telegraf(process.env.BOT_TOKEN) | ||
// Logger middleware | ||
telegraf.use(function * (next){ | ||
var start = new Date | ||
this.state.started = start | ||
yield next | ||
var ms = new Date - start | ||
debug('response time %sms', ms) | ||
}) | ||
telegraf.on('text', function * (){ | ||
this.reply('Hello World') | ||
}) | ||
``` | ||
### Context | ||
A Telegraf Context encapsulates telegram message. | ||
Context is created per request, and is referenced in middleware as the receiver, or the this identifier, as shown in the following snippet: | ||
Context is created per request and contains following props: | ||
```js | ||
telegraf.use(function * () { | ||
this.telegraf // Telegraf instance | ||
this.updateType // Update type(message, inline_query, etc.) | ||
[this.updateSubType] // Update subtype(text, sticker, audio, etc.) | ||
[this.message] // Received message | ||
[this.editedMessage] // Edited message | ||
[this.inlineQuery] // Received inline query | ||
[this.chosenInlineResult] // Received inline query result | ||
[this.callbackQuery] // Received callback query | ||
[this.chat] // Current chat info | ||
[this.from] // Sender info | ||
[this.match] // Regex match (available only for `hears` handler) | ||
app.use((ctx) => { | ||
ctx.telegram // Telegram instance | ||
ctx.updateType // Update type(message, inline_query, etc.) | ||
[ctx.updateSubType] // Update subtype(text, sticker, audio, etc.) | ||
[ctx.message] // Received message | ||
[ctx.editedMessage] // Edited message | ||
[ctx.inlineQuery] // Received inline query | ||
[ctx.chosenInlineResult] // Received inline query result | ||
[ctx.callbackQuery] // Received callback query | ||
[ctx.chat] // Current chat info | ||
[ctx.from] // Sender info | ||
[ctx.match] // Regex match (available only for `hears` handler) | ||
}) | ||
``` | ||
[Context api docs](/api.md#context) | ||
The recommended way to extend application context. | ||
### Cascading | ||
Middleware normally takes two parameters (ctx, next), `ctx` is the context for one Telegram message, | ||
`next` is a function that is invoked to execute the downstream middleware. | ||
It returns a Promise with a then function for running code after completion. | ||
```js | ||
var telegraf = new Telegraf(process.env.BOT_TOKEN) | ||
const app = new Telegraf(process.env.BOT_TOKEN) | ||
telegraf.context.db = { | ||
getScores: function () { return 42 } | ||
} | ||
// Logger middleware | ||
app.use((ctx, next) => { | ||
const start = new Date() | ||
return next().then(() => { | ||
const ms = new Date() - start | ||
console.log('response time %sms', ms) | ||
}) | ||
}) | ||
telegraf.on('text', function * (){ | ||
var scores = this.db.getScores(this.message.from.username) | ||
this.reply(`${this.message.from.username}: ${score}`) | ||
app.on('text', (ctx) => { | ||
return ctx.reply('Hello World') | ||
}) | ||
@@ -161,11 +136,11 @@ ``` | ||
```js | ||
var telegraf = new Telegraf(process.env.BOT_TOKEN) | ||
const app = new Telegraf(process.env.BOT_TOKEN) | ||
telegraf.use(function * (next) { | ||
this.state.role = getUserRole(this.message) | ||
yield next | ||
app.use((ctx, next) => { | ||
ctx.state.role = getUserRole(ctx.message) | ||
return next() | ||
}) | ||
telegraf.on('text', function * (){ | ||
this.reply(`Hello ${this.state.role}`) | ||
app.on('text', (ctx) => { | ||
return ctx.reply(`Hello ${ctx.state.role}`) | ||
}) | ||
@@ -177,11 +152,11 @@ ``` | ||
```js | ||
var telegraf = new Telegraf(process.env.BOT_TOKEN) | ||
const app = new Telegraf(process.env.BOT_TOKEN) | ||
// Session state will be lost on app restart | ||
telegraf.use(Telegraf.memorySession()) | ||
app.use(Telegraf.memorySession()) | ||
telegraf.on('text', function * (){ | ||
this.session.counter = this.session.counter || 0 | ||
this.session.counter++ | ||
this.reply(`Message counter:${this.session.counter}`) | ||
app.on('text', () => { | ||
ctx.session.counter = ctx.session.counter || 0 | ||
ctx.session.counter++ | ||
return ctx.reply(`Message counter:${ctx.session.counter}`) | ||
}) | ||
@@ -196,6 +171,6 @@ ``` | ||
var telegraf = new Telegraf(process.env.BOT_TOKEN) | ||
const app = new Telegraf(process.env.BOT_TOKEN) | ||
// TLS options | ||
var tlsOptions = { | ||
const tlsOptions = { | ||
key: fs.readFileSync('server-key.pem'), | ||
@@ -210,3 +185,3 @@ cert: fs.readFileSync('server-cert.pem'), | ||
// Set telegram webhook | ||
telegraf.setWebHook('https://server.tld:8443/secret-path', { | ||
app.telegram.setWebHook('https://server.tld:8443/secret-path', { | ||
content: 'server-cert.pem' | ||
@@ -216,7 +191,7 @@ }) | ||
// Start https webhook | ||
telegraf.startWebHook('/secret-path', tlsOptions, 8443) | ||
app.startWebHook('/secret-path', tlsOptions, 8443) | ||
// Http webhook, for nginx/heroku users. | ||
telegraf.startWebHook('/secret-path', null, 5000) | ||
app.startWebHook('/secret-path', null, 5000) | ||
@@ -226,20 +201,20 @@ | ||
require('http') | ||
.createServer(telegraf.webHookCallback('/secret-path')) | ||
.createServer(app.webHookCallback('/secret-path')) | ||
.listen(3000) | ||
require('https') | ||
.createServer(tlsOptions, telegraf.webHookCallback('/secret-path')) | ||
.createServer(tlsOptions, app.webHookCallback('/secret-path')) | ||
.listen(8443) | ||
// Connect/Express.js integration | ||
var express = require('express') | ||
var app = express() | ||
const express = require('express') | ||
const expressApp = express() | ||
app.use(telegraf.webHookCallback('/secret-path')) | ||
expressApp.use(app.webHookCallback('/secret-path')) | ||
app.get('/', function (req, res) { | ||
expressApp.get('/', (req, res) => { | ||
res.send('Hello World!') | ||
}) | ||
app.listen(3000, function () { | ||
expressApp.listen(3000, () => { | ||
console.log('Example app listening on port 3000!') | ||
@@ -256,3 +231,3 @@ }) | ||
```js | ||
telegraf.onError = function(err){ | ||
telegraf.onError = (err) => { | ||
log.error('server error', err) | ||
@@ -259,0 +234,0 @@ throw err |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
66413
5
8
1237
1
255
5
- Removedco-ware@^1.6.0
- Removedlodash@^4.13.1
- Removedco@4.6.0(transitive)
- Removedco-ware@1.6.0(transitive)
- Removedkoa-compose@2.5.1(transitive)
- Removedlodash@4.17.21(transitive)