Skip to content

Commit c84df4b

Browse files
committedNov 19, 2022
create telegram-bot-vercel-boilerplate
0 parents  commit c84df4b

18 files changed

+2973
-0
lines changed
 

‎.env-sample

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
BOT_TOKEN=""
2+
3+
VERCEL_URL=""
4+
PORT=""
5+
NODE_ENV=""

‎.gitignore

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# dependencies
2+
/node_modules
3+
4+
# testing
5+
/coverage
6+
7+
# production
8+
/build
9+
/dist
10+
/public
11+
12+
# misc
13+
.DS_Store
14+
.env*
15+
!.env-sample
16+
17+
npm-debug.log*
18+
yarn-debug.log*
19+
yarn-error.log*

‎.prettierrc

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"tabWidth": 2,
3+
"useTabs": false,
4+
"semi": true,
5+
"singleQuote": true
6+
}

‎LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Mark Pavlov https://github.com/m7mark.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎README.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Telegram Bot Vercel Boilerplate
2+
3+
Telegram Bot Vercel Boilerplate based on Node.js and [Telegraf](https://github.com/telegraf/telegraf) framework.
4+
5+
This template inspired by [Telegram Bot Boilerplate](https://github.com/yakovlevyuri/telegram-bot-boilerplate) for easily deploy to [Vercel](https://vercel.com).
6+
7+
## Before you start
8+
9+
First rename `.env-sample` file to `.env` and fill in all necessary values.
10+
11+
```
12+
BOT_TOKEN="<YOUR_BOT_API_TOKEN>"
13+
```
14+
15+
## Start your server
16+
17+
```
18+
npm install
19+
npm dev
20+
```
21+
22+
## Production
23+
24+
You can fork this template and do the necessary changes you need. Then you when are done with your changes simply goto [vercel git import](https://vercel.com/import/git).
25+
26+
## Demo
27+
28+
You can see a working version of the bot at [@Node_api_m_bot](https://t.me/Node_api_m_bot)

‎api/index.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { VercelRequest, VercelResponse } from '@vercel/node';
2+
import { startVercel } from '../src';
3+
4+
export default async function handle(req: VercelRequest, res: VercelResponse) {
5+
try {
6+
await startVercel(req, res);
7+
} catch (e: any) {
8+
res.statusCode = 500;
9+
res.setHeader('Content-Type', 'text/html');
10+
res.end('<h1>Server Error</h1><p>Sorry, there was a problem</p>');
11+
console.error(e.message);
12+
}
13+
}

‎package-lock.json

+2,705
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "telegram-bot-vercel-boilerplate",
3+
"version": "1.1.0",
4+
"description": "Telegram Bot Vercel Boilerplate",
5+
"main": "src/index.ts",
6+
"author": "Mark Pavlov (https://github.com/m7mark)",
7+
"homepage": "https://github.com/m7mark/telegram-bot-vercel-boilerplate",
8+
"dependencies": {
9+
"@vercel/node": "^2.6.3",
10+
"dotenv-cli": "^6.0.0",
11+
"telegraf": "^4.10.0"
12+
},
13+
"devDependencies": {
14+
"@types/debug": "^4.1.7",
15+
"@types/node": "^18.11.9",
16+
"@vercel/ncc": "^0.34.0",
17+
"debug": "^4.3.4",
18+
"nodemon": "^2.0.20",
19+
"prettier": "^2.7.1",
20+
"ts-node": "^10.9.1",
21+
"typescript": "^4.9.3"
22+
},
23+
"scripts": {
24+
"dev": "DEBUG=bot* dotenv -- nodemon -e ts -x ts-node src/index.ts",
25+
"devWindows": "@powershell -Command $env:DEBUG='bot*';dotenv -- -- nodemon -e ts -x ts-node src/index.ts",
26+
"start": "NODE_ENV=production node public/index.js",
27+
"build": "ncc build src/index.ts -o public -m",
28+
"prettier": "prettier --write 'src/**/*.ts'"
29+
}
30+
}

‎src/commands/about.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Context } from 'telegraf';
2+
import createDebug from 'debug';
3+
4+
import { author, name, version } from '../../package.json';
5+
6+
const debug = createDebug('bot:about_command');
7+
8+
const about = () => async (ctx: Context) => {
9+
const message = `*${name} ${version}*\n${author}`;
10+
debug(`Triggered "about" command with message \n${message}`);
11+
await ctx.replyWithMarkdownV2(message, { parse_mode: 'Markdown' });
12+
};
13+
14+
export { about };

‎src/commands/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './about';

‎src/core/development.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Context, Telegraf } from 'telegraf';
2+
import { Update } from 'telegraf/typings/core/types/typegram';
3+
import createDebug from 'debug';
4+
5+
const debug = createDebug('bot:dev');
6+
7+
const development = async (bot: Telegraf<Context<Update>>) => {
8+
const botInfo = (await bot.telegram.getMe()).username;
9+
10+
debug('Bot runs in development mode');
11+
debug(`${botInfo} deleting webhook`);
12+
await bot.telegram.deleteWebhook();
13+
debug(`${botInfo} starting polling`);
14+
15+
await bot.launch();
16+
17+
process.once('SIGINT', () => bot.stop('SIGINT'));
18+
process.once('SIGTERM', () => bot.stop('SIGTERM'));
19+
};
20+
21+
export { development };

‎src/core/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './development';
2+
export * from './production';

‎src/core/production.ts

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { VercelRequest, VercelResponse } from '@vercel/node';
2+
import createDebug from 'debug';
3+
import { Context, Telegraf } from 'telegraf';
4+
import { Update } from 'telegraf/typings/core/types/typegram';
5+
import { BOT_TOKEN } from '..';
6+
7+
const debug = createDebug('bot:dev');
8+
9+
const PORT = (process.env.PORT && parseInt(process.env.PORT, 10)) || 3000;
10+
const VERCEL_URL = `${process.env.VERCEL_URL}/bot${BOT_TOKEN}`;
11+
12+
const production = async (
13+
req: VercelRequest,
14+
res: VercelResponse,
15+
bot: Telegraf<Context<Update>>
16+
) => {
17+
debug('Bot runs in production mode');
18+
debug(`setting webhook: ${VERCEL_URL}`);
19+
20+
if (!VERCEL_URL) {
21+
throw new Error('VERCEL_URL is not set.');
22+
}
23+
24+
const getWebhookInfo = await bot.telegram.getWebhookInfo();
25+
if (getWebhookInfo.url !== VERCEL_URL + '/api') {
26+
debug(`deleting webhook ${VERCEL_URL}`);
27+
await bot.telegram.deleteWebhook();
28+
debug(`setting webhook: ${VERCEL_URL}/api`);
29+
await bot.telegram.setWebhook(`${VERCEL_URL}/api`);
30+
}
31+
32+
if (req.method === 'POST') {
33+
await bot.handleUpdate(req.body as unknown as Update, res);
34+
} else {
35+
res.status(200).json('Listening to bot events...');
36+
}
37+
debug(`starting webhook on port: ${PORT}`);
38+
};
39+
export { production };

‎src/index.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Telegraf } from 'telegraf';
2+
3+
import { about } from './commands';
4+
import { greeting } from './text';
5+
import { VercelRequest, VercelResponse } from '@vercel/node';
6+
import { development, production } from './core';
7+
8+
export const BOT_TOKEN = process.env.BOT_TOKEN || '';
9+
const ENVIRONMENT = process.env.NODE_ENV || '';
10+
11+
const bot = new Telegraf(BOT_TOKEN);
12+
13+
bot.command('about', about());
14+
bot.on('text', greeting());
15+
16+
//prod mode (Vercel)
17+
export const startVercel = async (req: VercelRequest, res: VercelResponse) => {
18+
await production(req, res, bot);
19+
};
20+
//dev mode
21+
ENVIRONMENT !== 'production' && development(bot);

‎src/text/greeting.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Context } from 'telegraf';
2+
import createDebug from 'debug';
3+
4+
const debug = createDebug('bot:greeting_text');
5+
6+
const replyToMessage = (ctx: Context, messageId: number, string: string) =>
7+
ctx.reply(string, {
8+
reply_to_message_id: messageId,
9+
});
10+
11+
const greeting = () => async (ctx: Context) => {
12+
debug('Triggered "greeting" text command');
13+
14+
const messageId = ctx.message?.message_id;
15+
const userName = `${ctx.message?.from.first_name} ${ctx.message?.from.last_name}`;
16+
17+
if (messageId) {
18+
await replyToMessage(ctx, messageId, `Hello, ${userName}!`);
19+
}
20+
};
21+
22+
export { greeting };

‎src/text/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './greeting';

‎tsconfig.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"compilerOptions": {
3+
"strict": true,
4+
"target": "esnext",
5+
"moduleResolution": "node",
6+
"module": "commonjs",
7+
"skipLibCheck": true,
8+
"sourceMap": true,
9+
"outDir": "public",
10+
"lib": ["esnext", "dom"],
11+
"resolveJsonModule": true
12+
},
13+
"exclude": ["node_modules"]
14+
}

‎vercel.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"version": 2,
3+
"public": true,
4+
"rewrites": [
5+
{
6+
"source": "/(.*)",
7+
"destination": "api/index.ts"
8+
}
9+
],
10+
"redirects": [{ "source": "/", "destination": "/api", "permanent": false }]
11+
}

1 commit comments

Comments
 (1)

vercel[bot] commented on Nov 19, 2022

@vercel[bot]
Please sign in to comment.