From cf6553b82f05065028f46a7f94bf7465939a2563 Mon Sep 17 00:00:00 2001 From: deptyped Date: Thu, 10 Aug 2023 14:13:05 +0300 Subject: [PATCH] Add Vercel setup --- .gitignore | 5 ++++- .vercelignore | 1 + README.md | 52 +++++++++++++++++++++++++++++---------------- api/index.ts | 22 +++++++++++++++++++ src/config.ts | 1 - src/server/index.ts | 18 ++++++++++++++++ tsconfig.json | 1 + vercel.json | 12 +++++++++++ 8 files changed, 92 insertions(+), 20 deletions(-) create mode 100644 .vercelignore create mode 100644 api/index.ts create mode 100644 vercel.json diff --git a/.gitignore b/.gitignore index 9170b038..9506f5e8 100644 --- a/.gitignore +++ b/.gitignore @@ -135,4 +135,7 @@ data/ # Ignore SQLite database *.db -*.db-journal \ No newline at end of file +*.db-journal + +# Vercel project configuration +.vercel diff --git a/.vercelignore b/.vercelignore new file mode 100644 index 00000000..e6905a23 --- /dev/null +++ b/.vercelignore @@ -0,0 +1 @@ +.env* \ No newline at end of file diff --git a/README.md b/README.md index 06e9df56..2f174040 100644 --- a/README.md +++ b/README.md @@ -54,20 +54,46 @@ Follow these steps to set up and run your bot using this template: npm run dev ``` - **Production Mode:** + **Production Mode:** - Install only production dependencies: + Install Vercel CLI: ```bash - npm install --only=prod + npm i -g vercel ``` - Set `DEBUG` environment variable to `false` in your `.env` file. + Create a project: + ```bash + vercel link + ``` - Start the bot in production mode: + Set `NODEJS_HELPERS` environment variable to `0`: ```bash - npm run start:force # skip type checking and start - # or - npm start # with type checking (requires development dependencies) + vercel env add NODEJS_HELPERS + ``` + + Set `BOT_MODE` environment variable to `webhook`: + ```bash + vercel env add BOT_MODE + ``` + + Set `BOT_TOKEN` environment variable: + ```bash + vercel env add BOT_TOKEN --sensitive + ``` + + Set `BOT_WEBHOOK_SECRET` environment variable to a random secret token: + ```bash + vercel env add BOT_WEBHOOK_SECRET --sensitive + ``` + + Deploy your bot: + ```bash + vercel + ``` + + After successful deployment, set up a webhook to connect your Vercel app with Telegram, modify the below URL to your credentials and visit it from your browser: + ``` + https://APP_NAME.vercel.app/BOT_TOKEN ``` ### List of Available Commands @@ -302,16 +328,6 @@ bun add -d @types/bun Enables debug mode. You may use config.isDebug flag to enable debugging functions. - - BOT_WEBHOOK - - String - - - Optional in polling mode. - Webhook endpoint URL, used to configure webhook. - - BOT_WEBHOOK_SECRET diff --git a/api/index.ts b/api/index.ts new file mode 100644 index 00000000..82acd24a --- /dev/null +++ b/api/index.ts @@ -0,0 +1,22 @@ +import process from 'node:process' +import { handle } from '@hono/node-server/vercel' +import { createBot } from '#root/bot/index.js' +import { createConfig } from '#root/config.js' +import { createServer } from '#root/server/index.js' +import { createLogger } from '#root/logger.js' + +// @ts-expect-error create config from environment variables +const config = createConfig(convertKeysToCamelCase(process.env)) +const logger = createLogger(config) + +const bot = createBot(config.botToken, { + config, + logger, +}) +const server = createServer({ + bot, + config, + logger, +}) + +export default handle(server) diff --git a/src/config.ts b/src/config.ts index aee61c40..0c9c051e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -29,7 +29,6 @@ const configSchema = v.variant('botMode', [ v.object({ botMode: v.literal('webhook'), ...baseConfigSchema.entries, - botWebhook: v.pipe(v.string(), v.url()), botWebhookSecret: v.pipe(v.string(), v.minLength(12)), serverHost: v.optional(v.string(), '0.0.0.0'), serverPort: v.optional(v.pipe(v.string(), v.transform(Number), v.number()), '80'), diff --git a/src/server/index.ts b/src/server/index.ts index 715c04ae..37d2c6b9 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -57,6 +57,24 @@ export function createServer(dependencies: Dependencies) { server.get('/', c => c.json({ status: true })) if (config.isWebhookMode) { + server.get(`/${bot.token}`, async (c) => { + const hostname = c.req.header('x-forwarded-host') + if (typeof hostname === 'string') { + const webhookUrl = new URL('webhook', `https://${hostname}`).href + await bot.api.setWebhook(webhookUrl, { + allowed_updates: config.botAllowedUpdates, + secret_token: config.botWebhookSecret, + }) + return c.json({ + status: true, + }) + } + c.status(500) + return c.json({ + status: false, + }) + }) + server.post( '/webhook', webhookCallback(bot, 'hono', { diff --git a/tsconfig.json b/tsconfig.json index a95cd27b..ca9baa47 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,7 @@ "preserveWatchOutput": true }, "include": [ + "api/**/*", "src/**/*" ] } diff --git a/vercel.json b/vercel.json new file mode 100644 index 00000000..f96d4935 --- /dev/null +++ b/vercel.json @@ -0,0 +1,12 @@ +{ + "installCommand": "npm install", + "buildCommand": "npm run build", + "devCommand": "npm run dev", + "outputDirectory": "build", + "rewrites": [ + { + "source": "/(.*)", + "destination": "/api" + } + ] +} \ No newline at end of file