Constructor
new Composer(…fns)
Constructs a new composer based on the provided middleware. If no middleware is given, the composer instance will simply make all context objects pass through without touching them.
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | The middlewares to compose as arguments |
- Source
Methods
action(triggers, …fns) → {Composer}
Registers some middleware(s) for callback queries, i.e. the updates that Telegram delivers to your bot when a user clicks an inline button (that is a button under a message).
This method is essentially the same as calling
bot.on('callback_query', ctx => { ... })
but it also allows you to match the query data against a given text or regular expression.
// Create an inline keyboard
const keyboard = Markup.inlineKeyboard([
Markup.callbackButton('Go!', 'button-payload')
])
// Send a message with the keyboard
await bot.telegram.sendMessage(chat_id, 'Press a button!', keyboard.extra())
// Listen to users pressing buttons with that specific payload
bot.action('button-payload', ctx => { ... })
// Listen to users pressing any button your bot ever sent
bot.on('callback_query', ctx => { ... })
Always remember to call Telegram#answerCbQuery or OpengramContext#answerCbQuery — even if you don't perform any action: https://core.telegram.org/bots/api#answercallbackquery
bot.on('callback_query', async ctx => {
await ctx.answerCbQuery()
})
You can pass one or an array of triggers (Regexp / strings). Your middleware(s) will be executed if at least one of them matches.
Note how
ctx.match
will contain the result of the regular expression. Soctx.match[1]
refers to the part of the regexp that was matched by([0-9]+)
, i.e. the text that comes after "button:".bot.action(/button:([0-9]+)/, ctx => ctx.reply(`You choose button with number ${ctx.match[1]} in payload`)) const keyboard = Markup.inlineKeyboard([ Markup.callbackButton('Button 1', 'button:1'), Markup.callbackButton('Button 2', 'button:2'), Markup.callbackButton('Button 3', 'button:3') ]) await bot.telegram.sendMessage(chat_id, 'Press a button!', keyboard.extra())
You can also paste function (or array of functions) that takes the value and context as arguments and returns true or false (or some Truthy
result) based on them. This can be used, for example, for dynamic text matching at i18n. The result returned by the function will be available from ctx.match
bot.action(
(value, ctx) => {
//... some checks ...
return ['some', 'data']
},
// Show cb query answer for all queries with "I love some data"
ctx => ctx.answerCbQuery(`I love ${ctx.match[0]} ${ctx.match[1]}`)
)
Name | Type | Attributes | Description |
---|---|---|---|
triggers | Trigger | | One or an array of regular expressions / strings to search in the payload | |
fns | Middleware | <repeatable> | The middleware(s) to register as arguments |
- Source
- Type:
- Composer
cashtag(…args) → {Composer}
Registers some middleware(s) that will only be executed if hashtag
entity is present in the update
Shortcut to Composer.entity('cashtag', ...)
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
args | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
command(commands, …fns)
Registers some middleware(s) that will only be executed when a certain command is found.
// Reacts to /start commands
bot.command('start', ctx => { ... })
// Reacts to /help commands
bot.command('help', ctx => { ... })
Note: Commands are not matched in the middle of the text.
bot.command('start', ctx => { ... })
// ... does not match:
// A message saying: “some text /start some more text”
// A photo message with the caption “some text /start some more text”
By default, commands are detected in channel posts and media captions, too. This means that ctx.message
for channel post or ctx.message.text
for media is potentially undefined
, so you should use ctx.channelPost
and ctx.message.caption
accordingly for channel posts. Alternatively, if you want to limit your bot to finding commands only in private and group chats, you can use
const { Opengram, Composer: { command } } = require('opengram')
// ...
bot.on('message', command('start', ctx => ctx.reply('Only private / group messages or media with caption')))`
or using Composer.chatType:
const { Opengram, Composer, Composer: { command } } = require('opengram')
// ...
bot.use(
Composer.chatType(
["private", "group", "supergroup"],
command('start', ctx => ctx.reply('Only private / group messages or media with caption'))
)
)
for match all message exclude channel posts, or
const { Opengram, Composer: { command } } = require('opengram')
// ...
bot.on('text', command('start', ctx => ctx.reply('Math commands only text, not media captions')))
for match only text message, not media caption or even store a message-only version of your bot in a variable like so:
Be careful, the example above may not work as expected if
channelMode
is enabled.By default
text
type not match channel posts, butchannel_post
matched astext
type andctx.message
potentiallyundefined
whenchannelMode
enabled. You can add additional chat type check for this case
Name | Type | Attributes | Description |
---|---|---|---|
commands | string | | The command or array of commands to look for | |
fns | Middleware | <repeatable> | The middleware(s) to register as arguments |
- Source
customEmoji(…args) → {Composer}
Registers some middleware(s) that will only be executed if custom_emoji
entity is present in the update
Shortcut to Composer.entity('custom_emoji', ...)
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
args | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
drop(predicate) → {Composer}
Registers middleware behind a custom filter function that operates on the context object and decides whether to execute the middleware.
In other words, the middleware(s) after that middleware will only be executed if the given predicate returns false
for the given context object. Note that the predicate may be asynchronous, i.e. it can return a Promise of a boolean.
This method is the same using filter
(normal usage) with a negated predicate.
// Drop all message updates sent more than 6 hr in all middlewares / handlers registered after bot.drop(...)
bot.drop(ctx => {
if(!ctx.message) return false // Drop only messages
return (Date.now() / 1000) - ctx.message.date < 60 * 60 * 6
})
// Called only for messages with date < 6 hr after send
bot.on('message', () => ctx.reply('Good, update date less then 6 hours!'))
Name | Type | Description |
---|---|---|
predicate | PredicateFn | | The predicate to check. Can be async, returns boolean or Promise with boolean |
- Source
- Type:
- Composer
email(…args) → {Composer}
Registers some middleware(s) that will only be executed if email
entity is present in the update
Shortcut to Composer.entity('email', ...)
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
args | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
entity(predicate, …fns) → {Composer}
Registers some middleware(s) that will only be executed if a certain entity is present in the update
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
predicate | EntityPredicate | The predicate to check. Can be async, returns boolean or Promise with boolean | |
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
filter(predicate) → {Composer}
Registers middleware(s) behind a custom filter function that operates on the context object and decides whether to execute the middleware. In other words, the middleware will only be executed if the given predicate returns true
for the given context object. Otherwise, it will be skipped and the next middleware will be executed.
In other words, the middleware after that middleware will only be executed if the given predicate returns true
for the given context object. Note that the predicate may be asynchronous, i.e. it can return a Promise of a boolean.
// Only process every second update
bot.filter(ctx => ctx.update.update_id % 2 === 0)
bot.on('message', ctx => ctx.reply('Update id of this message is divided by two without a remainder'))
Name | Type | Description |
---|---|---|
predicate | PredicateFn | | The predicate to check. Can be async, returns boolean or Promise with boolean |
- Source
- Type:
- Composer
gameQuery(…fns) → {Composer}
Registers some middleware(s) for game queries, i.e. the updates that Telegram delivers to your bot when a user clicks an inline button for the HTML5 games platform on Telegram.
This method is essentially the same as calling
bot.on('callback_query', ctx => {
if (ctx.callbackQuery.game_short_name) {
...
}
})
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | The middleware to register as arguments |
- Source
- Type:
- Composer
hashtag(…args) → {Composer}
Registers some middleware(s) that will only be executed if hashtag
entity is present in the update
Shortcut to Composer.entity('hashtag', ...)
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
args | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
hears(triggers, …fns)
Registers some middleware(s) that will only be executed when the message / channel post contains some text (in media caption too). Is it possible to pass a regular expression to match:
// Match some text (exact match)
bot.hears('I love anime', ctx => ctx.reply('I love too'))
// Match a regular expression
bot.hears(/\/echo (.+)/, ctx => ctx.reply(ctx.match[1]))
Note how
ctx.match
will contain the result of the regular expression. Soctx.match[1]
refers to the part of the regex that was matched by(.+)
, i.e. the text that comes after "/echo".
You can also paste function (or array of functions) that takes the value and context as arguments and returns true or false (or some Truthy
result) based on them. This can be used, for example, for dynamic text matching at i18n. The result returned by the function will be available from ctx.match
bot.hears(
(value, ctx) => {
//... some checks ...
return ['some', 'data']
},
ctx => ctx.reply(`I love ${ctx.match[0]} ${ctx.match[1]}`) // Replies at all with "I love some data"
)
You can pass an array of triggers. Your middleware will be executed if at least one of them matches.
Both text and captions of the received messages will be scanned. For example, when a photo is sent to the chat and its caption matches the trigger, your middleware will be executed.
If you only want to match text messages and not captions, you can do this:
const { Composer: { hears } } = require('opengram')
// Only matches text messages for the regex
bot.on('text', hears(/\/echo (.+)/, ctx => { ... }))
Be careful, the example above may not work as expected if
channelMode
is enabled.By default
text
type not match channel posts, butchannel_post
matched astext
type andctx.message
potentiallyundefined
whenchannelMode
enabled. You can add additional chat type check for this case
Name | Type | Attributes | Description |
---|---|---|---|
triggers | Trigger | | The text / array of texts / regex / function to look for | |
fns | Middleware | <repeatable> | The middleware(s) to register as argument(s) |
- Source
help(…fns) → {Middleware}
Registers some middleware that will only be executed when /help
command is found.
Shortcut to Composer.command('help', ...)
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
inlineQuery(triggers, …fns) → {Composer}
Registers middleware for inline queries. Telegram sends an inline query to your bot whenever a user types @your_bot_name ...
into a text field in Telegram.
Your bot will then receive the entered search query and can respond with a number of results (text, images, etc.) that the user can pick from to send a message via your bot to the respective chat. Check here to read more about inline bots.
Note that you have to enable inline mode for you bot by contacting @BotFather first.
// Listen for users typing `@your_bot_name query`
bot.inlineQuery('query', async ctx => {
// Answer the inline query, confer https://core.telegram.org/bots/api#answerinlinequery
await ctx.answerInlineQuery( ... )
})
You can pass one or an array of triggers (Regexp / strings). Your middleware(s) will be executed if at least one of them matches.
Note how
ctx.match
will contain the result of the regular expression. Soctx.match[1]
refers to the part of the regexp that was matched by([0-9]+)
, i.e. the text that comes after "query:".
// Listen for users typing `@your_bot_name query`
bot.inlineQuery(/query:([0-9]+)/, async ctx => {
// Answer the inline query, confer https://core.telegram.org/bots/api#answerinlinequery
await ctx.answerInlineQuery([{
type: 'article',
id: Math.random(),
title: 'Regex test',
cache_time: 1,
description: `Query Regex result: ${ctx.match[1]}`,
input_message_content: {
message_text: `Query Regex result: ${ctx.match[1]}`,
}
}])
})
You can also paste function (or array of functions) that takes the value and context as arguments and returns true or false (or some Truthy
result) based on them. This can be used, for example, for dynamic text matching at i18n. The result returned by the function will be available from ctx.match
bot.inlineQuery(
(value, ctx) => {
//... some checks ...
return ['some', 'data']
},
// Show cb query answer for all queries with "I love some data"
ctx => ctx.answerInlineQuery([{
type: 'article',
id: Math.random(),
title: 'Regex test',
cache_time: 1,
description: `I love ${ctx.match[0]} ${ctx.match[1]}`,
input_message_content: {
message_text: `I love ${ctx.match[0]} ${ctx.match[1]}`,
}
}])
})
Name | Type | Attributes | Description |
---|---|---|---|
triggers | Trigger | | The inline query text or array of text to match | |
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
mention(…args) → {Composer}
Registers some middleware(s) that will only be executed if mention
entity is present in the update
Shortcut to Composer.entity('mention', ...)
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
args | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
middleware() → {Middleware}
Returns the middleware to embed
- Source
- Type:
- Middleware
on(updateTypes, …fns) → {Composer}
Registers some middleware(s) that will only be executed for some specific updates, namely those matching the provided filter query. Filter queries are a concise way to specify which updates you are interested in.
Here are some examples of valid filter queries:
// All kinds of message updates
bot.on('message', ctx => { ... })
// Text messages
bot.on('text', ctx => { ... })
// Messages with document
bot.on('document', ctx => { ... })
It is possible to pass multiple filter queries in an array, i.e.
// Matches all messages that contain a video or audio
bot.on(['audio', 'video'], ctx => { ... })
Your middleware will be executed if any of the provided filter queries matches (logical OR).
This method returns same as Composer#use.
Name | Type | Attributes | Description |
---|---|---|---|
updateTypes | UpdateType | | The update type or array of update types to use, may also be an array or string | |
fns | Middleware | <repeatable> | The middleware(s) to register with the given types as argument(s) |
- Source
- Type:
- Composer
phone(…args) → {Composer}
Registers some middleware(s) that will only be executed if phone
entity is present in the update
Shortcut to Composer.entity('phone', ...)
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
args | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
settings(…fns) → {Middleware}
Registers some middleware that will only be executed when /settings
command is found.
Shortcut to Composer.command('settings', ...)
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
spoiler(…args) → {Composer}
Registers some middleware(s) that will only be executed if spoiler
entity is present in the update
Shortcut to Composer.entity('spoiler', ...)
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
args | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
start(…fns) → {Middleware}
Registers some middleware that will only be executed when /start
command is found.
Shortcut to Composer.command('start', ...)
, but with additional functionally, when you use this and deep linking, you can get start payload from ctx.startPayload
For example if user start the bot from link like this: http://t.me/examplebot?start=1234
With this code, bot reply user with text of start payload:
bot.start(ctx => ctx.reply(`Start payload: ${ctx.startPayload}`)) // Reply with "Start payload: 1234"
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
textLink(…args) → {Composer}
Registers some middleware(s) that will only be executed if text_link
entity is present in the update
Shortcut to Composer.entity('text_link', ...)
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
args | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
textMention(…args) → {Composer}
Registers some middleware(s) that will only be executed if text_mention
entity is present in the update
Shortcut to Composer.entity('text_mention', ...)
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
args | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
url(…args) → {Composer}
Registers some middleware(s) that will only be executed if url
entity is present in the update
Shortcut to Composer.entity('url', ...)
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
args | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Composer
use(…fns) → {Composer}
Registers some middleware(s) that receives all updates. It is installed by concatenating it to the end of all previously installed middleware.
Often, this method is used to install middleware(s) that behaves like a plugin, for example session middleware.
bot.use(session())
You can pass middleware separated by commas as arguments or as a chain of calls:
const { Opengram, Stage, session } = require('opengram')
const bot = require('opengram')
const stage = new Stage([...])
bot.use(session(), stage) // As arguments
or
const { Opengram, Stage, session } = require('opengram')
const bot = require('opengram')
const stage = new Stage([...])
bot // As chain of calls
.use(session())
.use(stage)
This method returns a new instance of Composer.
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | The middleware(s) to register as arguments |
- Source
- Type:
- Composer
(static) acl(userId, …fns) → {Middleware}
Generates and returns a middleware that runs the given middleware(s) only for when array of given id's contains user id or predicate function returns true for given context
Access-control list - allows you to create guards for middlewares
Usage example:
bot.use(
Composer.admin(
1234567890,
Composer.reply('Some middleware for admin of bot - 1234567890')
)
)
bot.use(
Composer.admin(
[1234567890, 09876543],
Composer.reply('Some middleware for admins of bot - 1234567890 and 09876543')
)
)
function checkIsAdmin (ctx) {
// ...
return true
}
bot.use(
Composer.admin(
ctx => checkIsAdmin(ctx),
Composer.reply('Some middleware for admins of bot')
)
)
Name | Type | Attributes | Description |
---|---|---|---|
userId | PredicateFn | | The predicate to check or user id / array of user id's | |
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
(static) action(triggers, …fns) → {Middleware}
Generates middleware that execute given middlewares will only be executed for certain callback queries, i.e. the updates that
Telegram delivers to your bot when a user clicks an inline button (that is a button under a message).
This method is essentially the same as calling
bot.on('callback_query', ctx => { ... })
but it also allows you to match the query data against a given text or regular expression.
// Create an inline keyboard
const keyboard = Markup.inlineKeyboard([
Markup.callbackButton('Go!', 'button-payload')
])
// Send a message with the keyboard
await bot.telegram.sendMessage(chat_id, 'Press a button!', keyboard.extra())
// Listen to users pressing buttons with that specific payload
bot.use(
Composer.action('button-payload', ctx => { ... })
)
// Listen to users pressing any button your bot ever sent
bot.on('callback_query', ctx => { ... })
Always remember to call Telegram#answerCbQuery or OpengramContext#answerCbQuery — even if you don't perform any action: https://core.telegram.org/bots/api#answercallbackquery
bot.on('callback_query', async ctx => {
await ctx.answerCbQuery()
})
You can pass one or an array of triggers (Regexp / strings). Your middleware(s) will be executed if at least one of them matches.
Note how
ctx.match
will contain the result of the regular expression. Soctx.match[1]
refers to the part of the regexp that was matched by([0-9]+)
, i.e. the text that comes after "button:".const mw = Composer.action(/button:([0-9]+)/, ctx => ctx.reply(`You choose button with number ${ctx.match[1]} in payload`)) const keyboard = Markup.inlineKeyboard([ Markup.callbackButton('Button 1', 'button:1'), Markup.callbackButton('Button 2', 'button:2'), Markup.callbackButton('Button 3', 'button:3') ]) bot.use(mw) await bot.telegram.sendMessage(chat_id, 'Press a button!', keyboard.extra())
You can also paste function (or array of functions) that takes the value and context as arguments and returns true or false (or some Truthy
result) based on them. This can be used, for example, for dynamic text matching at i18n. The result returned by the function will be available from ctx.match
bot.use(
Composer.action(
(value, ctx) => {
//... some checks ...
return ['some', 'data']
},
// Show cb query answer for all queries with "I love some data"
ctx => ctx.answerCbQuery(`I love ${ctx.match[0]} ${ctx.match[1]}`)
)
)
Name | Type | Attributes | Description |
---|---|---|---|
triggers | Trigger | | One or an array of regular expressions / strings to search in the payload | |
fns | Middleware | <repeatable> | The middleware(s) to register as arguments |
- Source
- Type:
- Middleware
(static) admin(…fns) → {Middleware}
Generates and returns a middleware that runs the given middleware(s) only for updates if member status = creator
or 'administrator'
Usage example:
bot.use(
Composer.admin(
Composer.reply('I work only when called by chat creator and administrator ')
)
)
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
(static) branch(predicate, trueMiddleware, falseMiddlewareopt) → {Middleware}
Allows you to branch between two cases for a given context object.
This method takes a predicate function that is tested once per context object. If it returns true
, the first supplied middleware is executed. If it returns false
, the second supplied middleware is executed. Note that the predicate may be asynchronous, i.e. it can return a Promise of a boolean.
bot.use(
Composer.branch(
(ctx) => ctx.from.is_premium,
(ctx) => ctx.reply('This mw executed only for premium users'),
(ctx) => ctx.reply('Buy premium :(')
)
)
Name | Type | Attributes | Description |
---|---|---|---|
predicate | PredicateFn | | The predicate to check. Can be async, returns boolean or Promise with boolean | |
trueMiddleware | Middleware | The middleware for the | |
falseMiddleware | Middleware | <optional> | The middleware for the |
- Source
- Type:
- Middleware
(static) catch(errorHandler, …fns) → {Middleware}
Generates middleware that catches all errors in the middleware(s) given to it and calls given error handler
Name | Type | Attributes | Description |
---|---|---|---|
errorHandler | function | Error handler which takes error and context object as arguments | |
fns | Middleware | <repeatable> | Middleware(s) |
- Source
- Type:
- Middleware
(static) catchAll(…fns) → {Middleware}
Generates middleware that catches all errors in the middleware(s) given to it and outputs them to the console
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | Middlewares |
- Source
- Type:
- Middleware
(static) chatType(type, …fns) → {Middleware}
Registers some middleware for certain chat types only.
For example, you can use this method to only receive updates from private chats. The four chat types are channel
, supergroup
, group
, and private
. This is especially useful when combined with other filtering logic.
For example, this is how can you respond to /start commands only from private chats:
Usage example:
const privateZone = new Composer()
privateZone.command("start", ctx => { ... })
bot.use(
Composer.chatType('private', privateZone)
)
bot.use(
Composer.chatType('supergroup', Composer.reply('I work only in supergroups chats'))
)
bot.use(
Composer.chatType(['supergroup', 'group'], Composer.reply('I work only in supergroup + group chats'))
)
const onlyGroup = new Composer()
onlyGroup.hears(...)
onlyGroup.command(...)
// ...
bot.use(
Composer.chatType('group', onlyGroup)
)
Name | Type | Attributes | Description |
---|---|---|---|
type | Array.<ChatType> | | Chat type or array of shat types | |
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
(static) command(command, …fns)
Generates middleware that execute given middlewares will only be executed if a certain command is found.
// Reacts to /start commands
bot.use(
Composer.command('start', ctx => { ... })
)
// Reacts to /help commands
bot.use(
Composer.command('help', ctx => { ... })
)
Note: Commands are not matched in the middle of the text.
bot.use(
Composer.command('start', ctx => { ... })
)
// ... does not match:
// A message saying: “some text /start some more text”
// A photo message with the caption “some text /start some more text”
By default, commands are detected in channel posts and media captions, too. This means that ctx.message
for channel post or ctx.message.text
for media is potentially undefined
, so you should use ctx.channelPost
and ctx.message.caption
accordingly for channel posts. Alternatively, if you want to limit your bot to finding commands only in private and group chats, you can use
const { Opengram, Composer: { command } } = require('opengram')
// ...
bot.on('message', command('start', ctx => ctx.reply('Only private / group messages or media with caption')))`
or using Composer.chatType:
const { Opengram, Composer, Composer: { command } } = require('opengram')
// ...
bot.use(
Composer.chatType(
["private", "group", "supergroup"],
command('start', ctx => ctx.reply('Only private / group messages or media with caption'))
)
)
for match all message exclude channel posts, or
const { Opengram, Composer: { command } } = require('opengram')
// ...
bot.on('text', command('start', ctx => ctx.reply('Math commands only text, not media captions')))
for match only text message, not media caption or even store a message-only version of your bot in a variable like so:
Be careful, the example above may not work as expected if
channelMode
is enabled.By default
text
type not match channel posts, butchannel_post
matched astext
type andctx.message
potentiallyundefined
whenchannelMode
enabled. You can add additional chat type check for this case
Name | Type | Attributes | Description |
---|---|---|---|
command | string | | The command or array of commands to look for | |
fns | Middleware | <repeatable> | The middleware(s) to register as arguments |
- Source
(static) compose(middlewares) → {Middleware}
Used for compose array of middlewares
Name | Type | Description |
---|---|---|
middlewares | Array.<Middleware> | The middlewares for compose |
- Source
- Type:
- Middleware
(static) creator(…fns) → {Middleware}
Generates and returns a middleware that runs the given middleware(s) only for updates if member status = creator
Usage example:
bot.use(
Composer.creator(
Composer.reply('I work only when called by chat creator')
)
)
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
(static) drop(predicate) → {Middleware}
Generates middleware behind a custom filter function that operates on the context object and decides whether to execute the middleware.
In other words, the middleware(s) after that middleware will only be executed if the given predicate returns false
for the given context object. Note that the predicate may be asynchronous, i.e. it can return a Promise of a boolean.
This method is the same using filter
(normal usage) with a negated predicate.
// Drop all message updates sent more than 6 hr in all middlewares / handlers registered after bot.drop(...)
const mw = Composer.drop(ctx => {
if(!ctx.message) return false // Drop only messages
return (Date.now() / 1000) - ctx.message.date < 60 * 60 * 6
})
// Called only for messages with date < 6 hr after send
bot.on('message', mw, () => ctx.reply('Good, update date less then 6 hours!'))
Name | Type | Description |
---|---|---|
predicate | PredicateFn | | The predicate to check. Can be async, returns boolean or Promise with boolean |
- Source
- Type:
- Middleware
(static) entity(predicate, …fns) → {Middleware}
Generates middleware that execute given middlewares if a certain entity is present in the update
This method matches entity in channel post, message and media caption
Name | Type | Attributes | Description |
---|---|---|---|
predicate | EntityPredicate | The predicate to check. Entity name or predicate function. If function provided, it can be sync only and returns boolean | |
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
(static) filter(predicate) → {Middleware}
Generates middleware behind a custom filter function that operates on the context object and decides whether to execute the middleware. In other words, the middleware will only be executed if the given predicate returns true
for the given context object. Otherwise, it will be skipped and the next middleware will be executed.
In other words, the middleware after that middleware will only be executed if the given predicate returns true
for the given context object. Note that the predicate may be asynchronous, i.e. it can return a Promise of a boolean.
// Only process every second update
bot.on(
'message',
Composer.filter(ctx => ctx.update.update_id % 2 === 0)
ctx => ctx.reply('Update id of this message is divided by two without a remainder')
)
Name | Type | Description |
---|---|---|
predicate | PredicateFn | | The predicate to check. Can be async, returns boolean or Promise with boolean |
- Source
- Type:
- Middleware
(static) fork(middleware) → {Middleware}
Registers some middleware that runs concurrently to the executing middleware stack. Runs the middleware at the next event loop using setImmediate and force call next()
For example, you can use that method for saving metrics and other non-priority or optional features in background
❗️ If you call next in this middleware, then nothing will happen, it will be ignored
Name | Type | Description |
---|---|---|
middleware | Middleware | The middleware to run concurrently |
- Source
- Type:
- Middleware
(static) groupChat(…fns) → {Middleware}
Creates and returns a middleware that runs the given middleware only for updates from "group" and "supergroup".
Usage example:
// Send message with text "I do not support group chats" when receive update from group chat
bot.use(
Composer.groupChat(Composer.reply('I do not support group chats'))
)
Isolate group commands:
const group = new Composer()
group.hears(...)
group.command(...)
bot.use(
Composer.groupChat(group)
)
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
(static) hears(triggers, …fns)
Generates middleware that execute given middlewares when the message / channel post contains some text (in media caption too). Is it possible to pass a regular expression to match:
// Match some text (exact match)
bot.use(
Composer.hears('I love anime', ctx => ctx.reply('I love too'))
)
// Match a regular expression
bot.use(
Composer.hears(/\/echo (.+)/, ctx => ctx.reply(ctx.match[1]))
)
Note how
ctx.match
will contain the result of the regular expression. Soctx.match[1]
refers to the part of the regex that was matched by(.+)
, i.e. the text that comes after "/echo".
You can also paste function (or array of functions) that takes the value and context as arguments and returns true or false (or some Truthy
result) based on them. This can be used, for example, for dynamic text matching at i18n. The result returned by the function will be available from ctx.match
bot.use(
Composer.hears(
(value, ctx) => {
//... some checks ...
return ['some', 'data']
},
ctx => ctx.reply(`I love ${ctx.match[0]} ${ctx.match[1]}`) // Replies at all with "I love some data"
)
)
You can pass an array of triggers. Your middleware will be executed if at least one of them matches.
Both text and captions of the received messages will be scanned. For example, when a photo is sent to the chat and its caption matches the trigger, your middleware will be executed.
If you only want to match text messages and not captions, you can do this:
// Only matches text messages for the regex
bot.on('text', Composer.hears(/\/echo (.+)/, ctx => { ... }))
Be careful, the example above may not work as expected if
channelMode
is enabled.By default
text
type not match channel posts, butchannel_post
matched astext
type andctx.message
potentiallyundefined
whenchannelMode
enabled. You can add additional chat type check for this case
Name | Type | Attributes | Description |
---|---|---|---|
triggers | Trigger | | The text / array of texts / regex / function to look for | |
fns | Middleware | <repeatable> | The middleware(s) to register as argument(s) |
- Source
(static) inlineQuery(triggers, …fns) → {Middleware}
Generates middleware that execute given middleware(s) will only be executed for certain inline queries. Telegram sends an inline query to your bot whenever a user types @your_bot_name ...
into a text field in Telegram.
Your bot will then receive the entered search query and can respond with a number of results (text, images, etc.) that the user can pick from to send a message via your bot to the respective chat. Check here to read more about inline bots.
Note that you have to enable inline mode for you bot by contacting @BotFather first.
// Listen for users typing `@your_bot_name query`
bot.use(
Composer.inlineQuery('query', async ctx => {
// Answer the inline query, confer https://core.telegram.org/bots/api#answerinlinequery
await ctx.answerInlineQuery( ... )
})
)
You can pass one or an array of triggers (Regexp / strings). Your middleware(s) will be executed if at least one of them matches.
Note how
ctx.match
will contain the result of the regular expression. Soctx.match[1]
refers to the part of the regexp that was matched by([0-9]+)
, i.e. the text that comes after "query:".
// Listen for users typing `@your_bot_name query`
bot.use(
Composer.inlineQuery(/query:([0-9]+)/, async ctx => {
// Answer the inline query, confer https://core.telegram.org/bots/api#answerinlinequery
await ctx.answerInlineQuery([{
type: 'article',
id: Math.random(),
title: 'Regex test',
cache_time: 1,
description: `Query Regex result: ${ctx.match[1]}`,
input_message_content: {
message_text: `Query Regex result: ${ctx.match[1]}`,
}
}])
})
)
You can also paste function (or array of functions) that takes the value and context as arguments and returns true or false (or some Truthy
result) based on them. This can be used, for example, for dynamic text matching at i18n. The result returned by the function will be available from ctx.match
bot.inlineQuery(
(value, ctx) => {
//... some checks ...
return ['some', 'data']
},
// Show cb query answer for all queries with "I love some data"
ctx => ctx.answerInlineQuery([{
type: 'article',
id: Math.random(),
title: 'Regex test',
cache_time: 1,
description: `I love ${ctx.match[0]} ${ctx.match[1]}`,
input_message_content: {
message_text: `I love ${ctx.match[0]} ${ctx.match[1]}`,
}
}])
})
Name | Type | Attributes | Description |
---|---|---|---|
triggers | Trigger | | The inline query text or array of text to match | |
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
(static) lazy(factoryFn) → {Middleware.<Promise>}
Lazily asynchronously returns some middleware that can be generated on the fly for each context. Pass a factory function that creates some middleware
The factory function will be called once per context, and its result will be executed with the context object.
// The middleware returned by `createMyMiddleware` will be used only once
bot.use(
Composer.lazy(ctx => createMyMiddleware(ctx))
)
You may generate this middleware in an async
fashion.
Name | Type | Description |
---|---|---|
factoryFn | function | The factory function creating the middleware |
- Source
- Type:
- Middleware.<Promise>
(static) log(logFn) → {Middleware}
Method that generates a middleware to output the content of the context with indented beautiful in console using serialization
The default for logs is console.log
, you can pass your own log function in argument:
const myOwnLogFn = (data) => console.log('[Logs]', data)
bot.use(Composer.log(myOwnLogFn))
Name | Type | Description |
---|---|---|
logFn | function | Custom log function |
- Source
- Type:
- Middleware
(static) match(triggers, …fns)
Generates middleware that execute given middlewares when some given trigger(s) returns true
Triggers are executed for channel post / message text / callback query / inline query
Example:
Composer.match (/[a-z]/, ...fns)
Composer.match ([/[a-z]/, /[0-9]/], ...fns)
Composer.match ((value, context) => {
// ...checks...
} , ...fns)
Composer.match (
(value, context) => {
// ...checks...
},
(value, context) => {
// ...checks...
},
...fns
)
Name | Type | Attributes | Description |
---|---|---|---|
triggers | Trigger | | The text / array of texts / regex / function to look for | |
fns | Middleware | <repeatable> | The middleware(s) to register as argument(s) |
- Source
(static) memberStatus(status, …fns) → {Middleware}
Generates and returns a middleware that runs the given middleware(s) only for updates user has one of given member statuses of chat
Usage example:
bot.use(
Composer.memberStatus(
["creator", "administrator"],
Composer.reply('I work only for chat creator and administrator ')
)
)
Name | Type | Attributes | Description |
---|---|---|---|
status | Array.<ChatMemberStatus> | | Member status of array of statuses | |
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
(static) mount(updateType, …fns) → {Middleware}
Generates middleware that execute given middleware(s) only for some specific updates, namely those matching the provided filter query. Filter queries are a concise way to specify which updates you are interested in.
Here are some examples of valid filter queries:
// All kinds of message updates
bot.use(
Composer.mount('message', ctx => { ... })
)
// Text messages
bot.use(
Composer.mount('text', ctx => { ... })
)
// Messages with document
bot.use(
Composer.mount('document', ctx => { ... })
)
It is possible to pass multiple filter queries in an array, i.e.
// Matches all messages that contain a video or audio
bot.use(
Composer.mount(['audio', 'video'], ctx => { ... })
)
Your middleware will be executed if any of the provided filter queries matches (logical OR).
Name | Type | Attributes | Description |
---|---|---|---|
updateType | UpdateType | | The update type or array of update types to use, may also be an array or string | |
fns | Middleware | <repeatable> | The middleware(s) to register with the given types as argument(s) |
- Source
- Type:
- Middleware
(static) optional(predicate, …fns) → {Middleware}
Generates middleware that makes given middleware(s) optional
Example
bot.use(
Composer.optional(
(ctx) => ctx.from.is_premium, // Check premium
// The handlers from below will be executed only if predict returns true
async (ctx, next) => {
await ctx.reply('This mw and below will be executed only for premium users')
return next()
},
(ctx) => {
// ...other middleware.. ...code...,
},
(ctx) => {
// ...other middleware.. ...code...,
},
)
)
Name | Type | Attributes | Description |
---|---|---|---|
predicate | PredicateFn | | The predicate to check. Can be async, returns boolean or Promise with boolean | |
fns | Middleware | <repeatable> | Middleware(s) |
- Source
- Type:
- Middleware
(static) passThru() → {Middleware}
Generates middleware which call next middleware
For example, you can use it with Composer.branch or other to skip middleware (make middleware optional)
- Source
- Type:
- Middleware
(static) privateChat(…fns) → {Middleware}
Generates and returns a middleware that runs the given middleware only for updates from "private" (DM)
Usage example:
// Send message with text "I do not support group chats" when receive update from group chat
bot.use(
Composer.privateChat(Composer.reply('I work only in group chats'))
)
Isolate private commands:
const private = new Composer()
private.hears(...)
private.command(...)
bot.use(
Composer.privateChat(private)
)
Name | Type | Attributes | Description |
---|---|---|---|
fns | Middleware | <repeatable> | The middleware(s) to register |
- Source
- Type:
- Middleware
(static) reply(text, extraopt) → {Middleware.<Promise.<Message>>}
Generates and return middleware for reply with given arguments, has same arguments like in Opengram, context method reply
Usage example:
// Send message with text "I do not support group chats" when receive update from group chat
bot.use(
Composer.groupChat(Composer.reply('I do not support group chats'))
)
Name | Type | Attributes | Description |
---|---|---|---|
text | string | Text of the message to be sent, 1-4096 characters after entities parsing | |
extra | ExtraSendMessage | | <optional> | Other parameters |
- Source
- Type:
- Middleware.<Promise.<Message>>
(static) safePassThru() → {Middleware}
Generates middleware which call next middleware if next
function exists or returns empty resolved promise
This method is similar to Composer.passThru()
, but calls next
if exists, otherwise returns resolved promise
- Source
- Type:
- Middleware
(static) tap(middleware) → {Middleware}
Middleware that calls a middleware or chain of middleware and calls the next
, whether it called next
or not. Allows you to execute some code and continue execution regardless of its result.
Name | Type | Description |
---|---|---|
middleware | Middleware | The middleware to run without access to next |
- Source
- Type:
- Middleware
(static) unwrap(handler) → {Middleware}
Method used for unwrapping middleware, when middleware has method with name middleware
(middleware factory) Composer.unwrap calls him and return result
This method used in some other Composer methods, like Composer.compose, Composer.lazy and other
Name | Type | Description |
---|---|---|
handler | Middleware | The middleware for unwrap |
- Source
- Type:
- Middleware