Skip to content

grammY

Overview

grammY is a modern framework for building Telegram bots. It is designed to be simple to use, efficient in performance, and easy to extend.

Installation

To use grammY with Storona, you need to install grammy & @storona/grammy packages:

sh
$ npm install grammy storona @storona/grammy
sh
$ yarn add grammy storona @storona/grammy
sh
$ pnpm add grammy storona @storona/grammy
sh
$ bun add grammy storona @storona/grammy

Usage

In order to setup router, you need to initialize a bot and pass it to the createRouter function:

ts
import { 
Bot
} from "grammy";
import {
createRouter
} from "storona";
import {
adapter
} from "@storona/grammy";
const
bot
= new
Bot
("[YOUR TOKEN]");
// Await router first, before starting the bot await
createRouter
(
bot
, {
directory
: "src/routes",
adapter
:
adapter
({
// Set to false, if you want storona to not register command list
setMyCommands
: true,
}),
quiet
: false,
});
bot
.
start
();

This will look for routes in the src/routes directory and create routes based on the file structure.

Result

WARNING

Since telegram does not support subcommands, commands will be registered based on the file name rather than the file structure.

For example, the file src/routes/directory/help.command.ts will be registered as /help command.

.
└─ src
   ├─ routes
   │  ├─ directory
   │  │  ├─ help.command.ts          --> COMMAND  /help
   │  │  └─ index.inline_query.mjs   --> INLINE_QUERY
   │  ├─ apple.message.js            --> MESSAGE
   │  └─ index.hears.jsx             --> HEARS
   └─ index.ts

Note that the routes can use any file extension, but the file structure must be consistent with the method and route.

Example

For an example of @storona/grammy usage in a real-world application, see following repositories:

  • The list is empty for now...

NOTE

You can add your project to this list by submitting a pull request to the official repository!

Supported Methods

Adapter supports command and hears filter as well as all L1 queries:

  • message e.g. src/routes/index.message.ts
  • edited_message e.g. src/routes/index.edited_message.ts
  • channel_post e.g. src/routes/index.channel_post.ts
  • edited_channel_post e.g. src/routes/index.edited_channel_post.ts
  • business_connection e.g. src/routes/index.business_connection.ts
  • business_message e.g. src/routes/index.business_message.ts
  • edited_business_message e.g. src/routes/index.edited_business_message.ts
  • deleted_business_messages e.g. src/routes/index.deleted_business_messages.ts
  • message_reaction e.g. src/routes/index.message_reaction.ts
  • message_reaction_count e.g. src/routes/index.message_reaction_count.ts
  • inline_query e.g. src/routes/index.inline_query.ts
  • chosen_inline_result e.g. src/routes/index.chosen_inline_result.ts
  • callback_query e.g. src/routes/index.callback_query.ts
  • shipping_query e.g. src/routes/index.shipping_query.ts
  • pre_checkout_query e.g. src/routes/index.pre_checkout_query.ts
  • poll e.g. src/routes/index.poll.ts
  • poll_answer e.g. src/routes/index.poll_answer.ts
  • my_chat_member e.g. src/routes/index.my_chat_member.ts
  • chat_member e.g. src/routes/index.chat_member.ts
  • chat_join_request e.g. src/routes/index.chat_join_request.ts
  • chat_boost e.g. src/routes/index.chat_boost.ts
  • removed_chat_boost e.g. src/routes/index.removed_chat_boost.ts
  • purchased_paid_media e.g. src/routes/index.purchased_paid_media.ts

Signature Function

In order to declare a route, you need to export a function with the following signature:

ts
import { 
define
} from "@storona/grammy";
export default
define
((
ctx
) => {
ctx
.
reply
("Hello, World!");
});

The define function is a wrapper around the grammY route handler. It provides a way to define a route handler in a more declarative way.

In case you want to strictly type the context object, you can use the supported generic parameter of the define function:

ts
import { 
define
} from "@storona/grammy";
// Explicitly define the query type export default
define
<"edited_message">((
ctx
) => {
ctx
.
update
.
edited_message
; // not undefined
});
ts
import { 
define
} from "@storona/grammy";
export default
define
((
ctx
) => {
ctx
.
update
.
edited_message
; // can be undefined
});
ts
import { 
define
} from "@storona/grammy";
export default
define
<"message:entities:mention">((
ctx
) => {
ctx
.
update
.
message
.
entities
; // not undefined
});
ts
import { 
define
} from "@storona/grammy";
export const
method
= ["channel_post", ":forward_origin"];
export default
define
<"channel_post" | ":forward_origin">((
ctx
) => {
ctx
.
update
.
channel_post
; // not undefined
ctx
.
update
.
message
?.
forward_origin
; // not undefined
});

Overrides

grammY adapter allows overriding both of the variables - route and method.

For more information on how to override these variables, check Export Overrides documentation:

ts
import { 
define
} from "@storona/grammy";
export const
route
= "/hello";
export const
method
= "command";
export default
define
((
ctx
) => {
ctx
.
reply
("Hello, World!");
});

Command Requisites

In case you want to register commands via setMyCommands, grammY adapter supports defining command requisites:

ts
import { 
define
} from "@storona/grammy";
export const
description
= "Greets the user";
export const
scope
= "all_private_chats";
// Alternative to language_code key in the command object export const
language
= "en";
export default
define
((
ctx
) => {
ctx
.
reply
("Hello!");
});

This way you can set the command description and scope, which will be used when registering the command via setMyCommands.

Setting the language variable will override the language_code key in the command object. Additionally you can use subdirectory after the language code in your file structure e.g. src/routes/en/hello.command.ts.

Scope Values

Besides the default scope values, you can use the following values:

  • default - The default scope value, accessible in all chats
  • all_private_chats - The command is available in all private chats
  • all_group_chats - The command is available in all group chats
  • all_chat_administrators - The command is available to all chat administrators
  • chat:[number or @string] - The command is available in the specified chat
    • chat:123456789
    • chat:@chatname
  • chat_administrators:[number or @string] - The command is available to chat administrators in the specified chat
    • chat_administrators:123456789
    • chat_administrators:@chatname
  • chat_member:[number or @string]:[number] - The command is available to the specified chat member in the specified chat
    • chat_member:123456789:987654321 - Chat member with the ID 987654321 in the chat with the ID 123456789
    • chat_member:@chatname:987654321 - Chat member with the ID 987654321 in the chat with the tag @chatname

Options

setMyCommands

You can register a command list based on the command exported variables. This is done by setting the setMyCommands option to true:

ts
import { 
Bot
} from "grammy";
import {
createRouter
} from "storona";
import {
adapter
} from "@storona/grammy";
const
bot
= new
Bot
("[YOUR TOKEN]");
// Await router first, before starting the bot await
createRouter
(
bot
, {
directory
: "src/routes",
adapter
:
adapter
({
// Default value is true
setMyCommands
: true,
}),
quiet
: false,
});
bot
.
start
();

Released under the MIT License.