Scenes. BaseScene

BaseScene class

Basic example:

const { Scenes: { BaseScene }, Stage, session, Opengram } = require('opengram')

// Scene
const firstScene = new BaseScene('FIRST_SCENE')

// Enter handler called when user enters to scene
firstScene.enter(async ctx => {
  await ctx.reply('Hi')
})

// Enter handler called when user leave scene or TTL expired
firstScene.leave(async ctx => {
  await ctx.reply('Bye')
})

// You can use all Composer methods like action, hears, on, filter, etc.
// Scenes handlers just middlewares and can use next function
firstScene.hears('hi', async ctx => {
  await ctx.reply('Hello')
})

firstScene.hears('/cancel', async ctx => {
  await ctx.scene.leave()
})

// if message not contains "hi" and "/cancel"
firstScene.on('message', async ctx => {
  await ctx.replyWithMarkdown('Send `hi` or /cancel')
})

const bot = new Opengram(process.env.BOT_TOKEN)

// Create Stage instance, register scenes (scenes MUST be registered before bot starts)
const stage = new Stage([firstScene], {
  // Defines scenes TTL, after expires leave handler called & user removed from scene
  ttl: 10
})

// Register session middleware (Stage uses session for saving state, sessions MUST be registered before Stage)
bot.use(session())
bot.use(stage) // Register stage middleware
bot.command('myscene', ctx => ctx.scene.enter('FIRST_SCENE'))
bot.on('message', ctx => ctx.reply('Try /myscene'))

bot.launch()

Constructor

new BaseScene()

Extends

Members

id :string

Type:
  • string

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. So ctx.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]}`)
)
Parameters:
NameTypeAttributesDescription
triggersTrigger | Array.<Trigger>

One or an array of regular expressions / strings to search in the payload

fnsMiddleware<repeatable>

The middleware(s) to register as arguments

Returns:
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

Parameters:
NameTypeAttributesDescription
argsMiddleware<repeatable>

The middleware(s) to register

Returns:
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, but channel_post matched as text type and ctx.message potentially undefined when channelMode enabled. You can add additional chat type check for this case

Parameters:
NameTypeAttributesDescription
commandsstring | Array.<string> | 'start' | 'settings' | 'help'

The command or array of commands to look for

fnsMiddleware<repeatable>

The middleware(s) to register as arguments

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

Parameters:
NameTypeAttributesDescription
argsMiddleware<repeatable>

The middleware(s) to register

Returns:
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!'))
Parameters:
NameTypeDescription
predicatePredicateFn | boolean

The predicate to check. Can be async, returns boolean or Promise with boolean

Overrides
Returns:
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

Parameters:
NameTypeAttributesDescription
argsMiddleware<repeatable>

The middleware(s) to register

Returns:
Type: 
Composer

enter(…fns) → {BaseScene}

Registers enter handler(s) for scene

Parameters:
NameTypeAttributesDescription
fnsMiddleware<repeatable>

Middleware(s) to register

Returns:
Type: 
BaseScene

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

Parameters:
NameTypeAttributesDescription
predicateEntityPredicate

The predicate to check. Can be async, returns boolean or Promise with boolean

fnsMiddleware<repeatable>

The middleware(s) to register

Returns:
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'))
Parameters:
NameTypeDescription
predicatePredicateFn | boolean

The predicate to check. Can be async, returns boolean or Promise with boolean

Returns:
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) {
   ...
 }
})
Parameters:
NameTypeAttributesDescription
fnsMiddleware<repeatable>

The middleware to register as arguments

Returns:
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

Parameters:
NameTypeAttributesDescription
argsMiddleware<repeatable>

The middleware(s) to register

Returns:
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. So ctx.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, but channel_post matched as text type and ctx.message potentially undefined when channelMode enabled. You can add additional chat type check for this case

Parameters:
NameTypeAttributesDescription
triggersTrigger | Array.<Trigger>

The text / array of texts / regex / function to look for

fnsMiddleware<repeatable>

The middleware(s) to register as argument(s)

help(…fns) → {Middleware}

Registers some middleware that will only be executed when /help command is found.

Shortcut to Composer.command('help', ...)

Parameters:
NameTypeAttributesDescription
fnsMiddleware<repeatable>

The middleware(s) to register

Overrides
Returns:
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. So ctx.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]}`,
    }
  }])
})
Parameters:
NameTypeAttributesDescription
triggersTrigger | Array.<Trigger>

The inline query text or array of text to match

fnsMiddleware<repeatable>

The middleware(s) to register

Returns:
Type: 
Composer

leave(…fns) → {BaseScene}

Registers leave handler(s) for scene

Parameters:
NameTypeAttributesDescription
fnsMiddleware<repeatable>

Middleware(s) to register

Returns:
Type: 
BaseScene

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

Parameters:
NameTypeAttributesDescription
argsMiddleware<repeatable>

The middleware(s) to register

Returns:
Type: 
Composer

middleware() → {Middleware}

Returns the middleware to embed

Returns:
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.

Parameters:
NameTypeAttributesDescription
updateTypesUpdateType | UpdateSubtype | Array.<(UpdateType|UpdateSubtype)>

The update type or array of update types to use, may also be an array or string

fnsMiddleware<repeatable>

The middleware(s) to register with the given types as argument(s)

Overrides
Returns:
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

Parameters:
NameTypeAttributesDescription
argsMiddleware<repeatable>

The middleware(s) to register

Returns:
Type: 
Composer

settings(…fns) → {Middleware}

Registers some middleware that will only be executed when /settings command is found.

Shortcut to Composer.command('settings', ...)

Parameters:
NameTypeAttributesDescription
fnsMiddleware<repeatable>

The middleware(s) to register

Returns:
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

Parameters:
NameTypeAttributesDescription
argsMiddleware<repeatable>

The middleware(s) to register

Returns:
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"
Parameters:
NameTypeAttributesDescription
fnsMiddleware<repeatable>

The middleware(s) to register

Returns:
Type: 
Middleware

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

Parameters:
NameTypeAttributesDescription
argsMiddleware<repeatable>

The middleware(s) to register

Returns:
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

Parameters:
NameTypeAttributesDescription
argsMiddleware<repeatable>

The middleware(s) to register

Returns:
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

Parameters:
NameTypeAttributesDescription
argsMiddleware<repeatable>

The middleware(s) to register

Overrides
Returns:
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.

Parameters:
NameTypeAttributesDescription
fnsMiddleware<repeatable>

The middleware(s) to register as arguments

Overrides
Returns:
Type: 
Composer