{"id":15133871,"url":"https://github.com/bifot/botact","last_synced_at":"2025-10-04T23:42:50.165Z","repository":{"id":74809840,"uuid":"89710619","full_name":"bifot/botact","owner":"bifot","description":"🤖 A library for creating VK bots on Node.js","archived":false,"fork":false,"pushed_at":"2018-07-31T02:30:22.000Z","size":1583,"stargazers_count":19,"open_issues_count":1,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-30T17:38:25.209Z","etag":null,"topics":["bot","bot-framework","callback","vk","vk-api","vkontakte","vkontakte-api"],"latest_commit_sha":null,"homepage":"https://npmjs.com/package/botact","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bifot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-04-28T13:52:26.000Z","updated_at":"2022-11-27T04:13:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"d5649acc-790b-4d0e-a7bb-6a616c130434","html_url":"https://github.com/bifot/botact","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bifot%2Fbotact","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bifot%2Fbotact/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bifot%2Fbotact/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bifot%2Fbotact/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bifot","download_url":"https://codeload.github.com/bifot/botact/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237807458,"owners_count":19369595,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot","bot-framework","callback","vk","vk-api","vkontakte","vkontakte-api"],"created_at":"2024-09-26T05:01:37.638Z","updated_at":"2025-10-04T23:42:50.066Z","avatar_url":"https://github.com/bifot.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![botact](https://img.shields.io/npm/v/botact.svg?style=flat-square)](https://www.npmjs.com/package/botact/) [![botact](https://img.shields.io/node/v/botact.svg?style=flat-square)](https://nodejs.org/en/) [![botact](https://img.shields.io/npm/dm/botact.svg?style=flat-square)](https://www.npmjs.com/package/botact/) [![botact](https://img.shields.io/travis/bifot/botact.svg?branch=master\u0026style=flat-square)](https://travis-ci.org/bifot/botact/) [![botact](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](http://standardjs.com/)\n\n# botact.js\n\nBotact enables developers to focus on writing reusable application logic instead of spending time building infrastructure.\n\n## Table of content\n\n- [Install](#install)\n- [Usage](#usage)\n- [Botact API](#botact-api)\n- [Botact Flow API](#botact-flow-api)\n- [TypeScript](#typescript)\n- [Tests](#tests)\n- [License](#license)\n\n## Install\n\n**via npm:**\n\n```sh\n$ npm i botact -S\n```\n\n**via yarn:**\n\n```sh\n$ yarn add botact\n```\n\n## Examples\n\n**express:**\n\n```javascript\nconst express = require('express')\nconst bodyParser = require('body-parser')\nconst { Botact } = require('botact')\n\nconst app = express()\nconst bot = new Botact({\n  confirmation: process.env.CONFIRMATION,\n  token: process.env.TOKEN\n})\n\n// User wrote command 'start'\nbot.command('start', ({ reply }) =\u003e {\n  reply('This is start!')\n})\n\n// User wrote message which contains 'car' or 'tesla'\nbot.hears(/(car|tesla)/, ({ reply }) =\u003e {\n  reply('I love Tesla!')\n})\n\n// User joined in the group\nbot.event('group_join', ({ reply }) =\u003e {\n  reply('Thanks!')\n})\n\n// User wrote any message\nbot.on(({ reply }) =\u003e {\n  reply('What?')\n})\n\n// Parser request body\napp.use(bodyParser.json())\n\n// Bot's endpoint\napp.post('/', bot.listen)\n\n// Start listen on 3000\napp.listen(process.env.PORT)\n```\n\n**koa:**\n\n```js\nconst Koa = require('koa')\nconst Router = require('koa-router')\nconst bodyParser = require('koa-bodyparser')\nconst { Botact } = require('botact')\n\nconst app = new Koa()\nconst router = new Router()\nconst bot = new Botact({\n  confirmation: process.env.CONFIRMATION,\n  token: process.env.TOKEN,\n  framework: 'koa'\n})\n\n// User wrote command 'start'\nbot.command('start', ({ reply }) =\u003e {\n  reply('This is start!')\n})\n\n// User wrote message which contains 'car' or 'tesla'\nbot.hears(/(car|tesla)/, ({ reply }) =\u003e {\n  reply('I love Tesla!')\n})\n\n// User joined in the group\nbot.event('group_join', ({ reply }) =\u003e {\n  reply('Thanks!')\n})\n\n// User wrote any message\nbot.on(({ reply }) =\u003e {\n  reply('What?')\n})\n\n// Bot's endpoint\nrouter.post('/', bot.listen)\n\n// Parser request body\napp.use(bodyParser())\n// Connect routes\napp.use(router.routes())\n\n// Start listen on 3000\napp.listen(3000)\n```\n\n## Botact API\n\n## Methods\n\n### Core\n\n- [constructor(settings)](#constructorsettings)\n- [.api(method, settings)](#apimethod-settings)\n- [.execute(method, settings, callback)](#executemethod-settings-callback)\n- [.reply(userId, message, attachment, keyboard)](#replyuserid-message-attachment-keyboard)\n- [.listen(...args)](#listenargs)\n\n### Actions\n\n- [.command(command, callback)](#commandcommand-callback)\n- [.event(event, callback)](#eventevent-callback)\n- [.hears(command, callback)](#hearscommand-callback)\n- [.on(type, callback)](#ontype-callback)\n- [.use(callback)](#usecallback)\n\n### Options\n\n- [[getter] options](#getter-options)\n- [[setter] options](#setter-options)\n\n### Upload helpers\n\n- [.uploadCover(file, settings)](#uploadcoverfile-settings)\n- [.uploadDocument(file, peerId, type)](#uploaddocumentfile-peerid-type)\n- [.uploadPhoto(file, peerId)](#uploadphotofile-peerid)\n\n### Error Handling\n\n- [.catch(handler)](#catchhandler)\n- [.throw(error)](#throwerror)\n- [.assert(value, message)](#assertvalue-message)\n\n--------------------------------------------------------------------------------\n\n## Botact API: Core [↑](#botact-api)\n\n### constructor(settings)\n\nCreate bot.\n\n**Definition:**\n\n```typescript\nconstructor (settings: {\n  confirmation: string;   // required\n  token: string;          // required\n  group_id?: number;\n  framework?: string;     // Server framework (express/koa)\n\n  // Flow Settings\n  flowTimeout?: number;   // Document expire time, in seconds\n  redis?: boolean;        // false by default\n  redisConfig?: object;   // {} by default\n})\n```\n\n**Usage:**\n\n```javascript\nconst { Botact } = require('botact')\n\nconst bot = new Botact({\n  confirmation: process.env.CONFIRMATION,\n  token: process.env.TOKEN\n})\n```\n\n### .api(method, settings)\n\nCall API method (\u003chttps://vk.com/dev/methods\u003e).\n\n**Definition:**\n\n```typescript\nasync api (\n  method: string,        // required\n  options?: object,      // api call parameters\n): Promise\u003cany\u003e;         // Promise with response/error\n```\n\n**Usage:**\n\n```javascript\nconst data = await bot.api('users.get', {\n  user_ids: 1\n})\n```\n\n### .execute(method, settings, callback)\n\nCall API by [execute](https://vk.com/dev/execute).\n\n**Definition:**\n\n```typescript\nasync execute (\n  method: string,        // required\n  options?: object,      // api call  parameters\n  callback?: function    \n): Promise\u003cany\u003e;         // Promise with response/error\n```\n\n**Usage:**\n\n```javascript\nbot.execute('users.get', {\n  user_ids: 1\n}, (body) =\u003e {\n  // {\n  //   response: [{\n  //     id: 1,\n  //     first_name: 'Павел',\n  //     last_name: 'Дуров'\n  //   }]\n  // }\n})\n```\n\n### .reply(userId, message, attachment, keyboard)\n\nSends message to user\n\n**Definition:**\n\n```typescript\nasync reply (\n  userId: number,\n  message: string,      // required, if attachment not setten\n  attachment: string,   // required, if message not setten\n  keyboard: Object      // optional\n): Promise\u003cany\u003e         // Promise with response/error\n```\n\n**Usage:**\n\n```javascript\nbot.command('start', (ctx) =\u003e {\n  // via shortcut from context\n  ctx.reply('Hi, this is start!')\n  // via shortcut with keyboard\n  ctx.reply('Yo, this is keyboard?', null, {\n    one_time: false,\n    buttons: [\n      [\n        {\n          action: {\n            type: 'text',\n            payload: {\n              button: 'Hello, world!'\n            },\n            label: 'Hello, world!'\n          },\n          color: 'primary'\n        }\n      ]\n    ]\n  })\n  // via function from context\n  ctx.sendMessage(ctx.user_id, 'Hi, this is start!')\n  // via function from instance\n  bot.reply(ctx.user_id, 'Hi, this is start!')\n  // to multiple users\n  bot.reply([ ctx.user_id, 1 ], 'Hi, this is start!')\n})\n```\n\n### .listen(...args)\n\nStart listen.\n\n**Definition:**\n\nexpress:\n\n```typescript\nlisten (\n  req: any,           // Express request, required\n  res: any            // Express response, required\n  callback: function  // Callback for errors\n)\n```\n\nkoa:\n\n```typescript\nlisten (\n  ctx: object,        // Koa object, required\n  callback: function  // Callback for errors\n)\n```\n\n**Usage:**\n\n```javascript\n// express\nbot.listen(req, res, (error) =\u003e {\n  res.status(500).json({\n    error: 'Server error'\n  })\n})\n\n// koa\nbot.listen(ctx, (error) =\u003e {\n  ctx.throw(500, 'Server error')\n})\n```\n\n## Botact API: Actions [↑](#botact-api)\n\n### .command(command, callback)\n\nAdd command w/ strict match.\n\n**Definition:**\n\n```typescript\ncommand (\n  command: string | string[],\n  callback: function\n): Botact\n```\n\n**Usage:**\n\n```javascript\nbot.command('start', ({ reply }) =\u003e reply('This is start!'))\n```\n\n### .event(event, callback)\n\nAdd [event](https://vk.com/dev/groups_events) handler .\n\n**Definition:**\n\n```typescript\nevent (\n  event: string | string[],\n  callback: function\n): Botact;\n```\n\n**Usage:**\n\n```javascript\nbot.event('group_join', ({ reply }) =\u003e reply('Thanks!'))\n```\n\n### .hears(command, callback)\n\nAdd command w/ match like RegEx.\n\n**Definition:**\n\n```typescript\nhears (\n  hear: string | RegExp | (string | RegExp)[],\n  callback: function\n): Botact;\n```\n\n**Usage:**\n\n```javascript\nbot.hears(/(car|tesla)/, ({ reply }) =\u003e reply('I love Tesla!'))\n```\n\n### .on(type, callback)\n\nAdd reserved callback.\n\n**Definition:**\n\n```typescript\non (\n  type: string,\n  callback: function\n): Botact;\n\nOR\n\non (\n  callback: function\n): Botact;\n```\n\n**Usage:**\n\n```javascript\nbot.on(({ reply }) =\u003e reply('What?'))\nbot.on('audio', ({ reply }) =\u003e reply('Great music!'))\n```\n\n### .use(callback)\n\nAdd middleware.\n\n**Definition:**\n\n```typescript\nuse (\n  callback: function\n): Botact\n```\n\n**Usage:**\n\n```javascript\nbot.use(ctx =\u003e ctx.date = new Date())\n\nbot.on(({ date }) =\u003e {\n  // Fri Nov 24 2017 16:00:21 GMT+0300 (MSK)\n})\n```\n\n## Botact API: Options [↑](#botact-api)\n\n### [getter] options\n\nGet options.\n\n```javascript\nbot.options\n// {\n//   confirmation: '12345',\n//   token: 'abcde...'\n// }\n```\n\n### [setter] options\n\nSet options.\n\n```javascript\nbot.options = { foo: 'bar' }\n// {\n//   confirmation: '12345',\n//   token: 'abcde...',\n//   foo: 'bar'\n// }\n```\n\n## Botact API: Upload helpers [↑](#botact-api)\n\n### .uploadCover(file, settings)\n\nUpload and save cover. See detailed settings [here](https://vk.com/dev/photos.getOwnerCoverPhotoUploadServer).\n\n**Definition:**\n\n```typescript\nasync uploadCover (\n  filepath: string,    // Path to file with cover\n  settings?: object\n): Promise\u003cany\u003e        // Promise with response/error\n```\n\n**Usage:**\n\n```javascript\nawait bot.uploadCover('./cover.jpg', { crop_x2: 1590 })\n// {\n//   images: [\n//     {\n//       url: \"URL\",\n//       width: 1920,\n//       height: 1080\n//     },\n//     [Object],\n//     [Object],\n//     [Object],\n//     [Object]\n//   ]\n// }\n```\n\n### .uploadDocument(file, peer_id, type)\n\nUploads document to peer.\n\n**Definition:**\n\n```typescript\nasync uploadDocument (\n  filepath: string,               // Path to file\n  peer_id: number,\n  type: 'doc' | 'audio_message'   // 'doc' by default\n): Promise\u003cany\u003e;                  // Promise with response/error\n```\n\n**Usage:**\n\n```javascript\nawait bot.uploadDocument('./book.pdf', 1234)\n// {\n//   response:\n//     [{\n//       id: 1234,\n//       owner_id: 1234,\n//       title: \"\",\n//       ...\n//     }]\n// }\n```\n\n### .uploadPhoto(file, peer_id)\n\nUploads photo to peer.\n\n**Definition:**\n\n```typescript\nasync uploadPhoto (\n  filepath: string,   // Path to picture\n  peer_id: number\n): Promise\u003cany\u003e       // Promise with response/error\n```\n\n**Usage:**\n\n```javascript\nawait bot.uploadPhoto('./picture.png', 1234)\n// {\n//   id: 1234,\n//   album_id: 1234,\n//   owner_id: 1234,\n//   ...\n// }\n```\n\n## Botact API: Error Handling [↑](#botact-api)\n\n### .catch(handler)\n\nAdd catch handler for errors.\n\n**Default handler:**\n\n```js\nconsole.error(`❌ Botact Error: ${typeof err === 'object' ? JSON.stringify(err) : err}`)\n```\n\n**Usage:**\n\n```js\n// Handle all botact errors here\nbot.catch((ctx, err) =\u003e {\n  // ctx - user's context\n  // err - throwed error\n  console.error(ctx, err)\n})\n\nbot.on((ctx) =\u003e {\n  if (ctx.peer_id !== 1) {\n    // Throw error to the .catch handler\n    return ctx.throw('User is not Pavel Durov')\n  }\n})\n```\n\n### .throw(error)\n\nThrow error.\n\n**Usage:**\n\n```js\nbot.catch((ctx, err) =\u003e {\n  console.error(ctx, err)\n})\n\nbot.command('start', (ctx) =\u003e {\n  if (ctx.peer_id === 301361473) {\n    return ctx.throw('User is blocked')\n  }\n  \n  ctx.reply('Hello, how are you?')\n})\n```\n\n### .assert(value, message)\n\nHelper method to throw an error similar to .throw() when !value.\n\n```js\nbot.catch((ctx, err) =\u003e {\n  console.error(ctx, err)\n})\n\nbot.command('start', (ctx) =\u003e {\n  ctx.assert(ctx.peer_id !== 301361473, 'User is blocked')\n  ctx.reply('Hello, how are you?')\n})\n```\n\n--------------------------------------------------------------------------------\n\n## Botact Flow API\n\n### Usage\n\n```javascript\nconst bot = new Botact({\n  ...,\n  redis: true       // enable redis\n  flowTimeout: 20   // timeout for delete documents\n  redisConfig: {    // redis config\n    port: 1234\n  }\n})\n```\n\n```sh\n$ redis-server\n```\n\n### Methods\n\n- [.addScene(name, ...callbacks)](#addscenename-callbacks)\n- [.joinScene(ctx, scene, session, step, now)](#joinscenectx-scene-session-step-now)\n- [.nextScene(ctx, body)](#nextscenectx-body)\n- [.leaveScene(ctx)](#leavescenectx)\n\n### Example\n\n```javascript\nconst bodyParser = require('body-parser')\nconst express = require('express')\nconst { Botact } = require('botact')\n\nconst app = express()\nconst bot = new Botact({\n  confirmation: process.env.CONFIRMATION,\n  token: process.env.TOKEN,\n  redis: true,\n  flowTimeout: 20,      // document will be deleted after 20 secs\n  redisConfig: {\n    host: '127.0.0.1',  // default host for redis\n    port: 8080          // custom port for redis\n  },\n})\n\nbot.addScene('wizard',\n  ({ reply, scene: { next } }) =\u003e {\n    next()\n    reply('Write me something!')\n   },\n  ({ reply, body, scene: { leave } }) =\u003e {\n    leave()\n    reply(`You wrote: ${body}`)\n  }\n)\n\nbot.command('join', ({ scene: { join } }) =\u003e join('wizard'))\n\napp.use(bodyParser.json())\napp.post('/', bot.listen)\napp.listen(process.env.PORT)\n```\n\n## Botact Flow API: Methods\n\n### .addScene(name, ...callbacks)\n\nAdd scene.\n\n**Definition:**\n\n```typescript\naddScene (\n  name: string,\n  ...args: function[]\n): Botact;\n```\n\n**Usage:**\n\n```javascript\nbot.addScene('wizard',\n  ({ reply, scene: { next } }) =\u003e {\n    next()\n    reply('Write me something!')\n  },\n  ({ reply, body, scene: { leave } }) =\u003e {\n    leave()\n    reply(`You wrote: ${body}`)\n  }\n)\n```\n\n### .joinScene(ctx, scene, session, step, now)\n\nEnter scene.\n\n**Definition:**\n\n```typescript\nasync joinScene (\n  ctx: object,\n  scene: string,\n  session?: object,      // {} by default\n  step?: number,         // 0 by default\n  instantly?: boolean    // true by default\n): Promise\u003cBotact\u003e;\n```\n\n**Usage:**\n\n```javascript\nbot.command('join', (ctx) =\u003e {\n  // with shortcut without additional settings\n  ctx.scene.join('wizard')\n  // simple usage with additional settings\n  bot.joinScene(ctx, 'wizard', { foo: 'bar' })\n})\n```\n\n### .nextScene(ctx, body)\n\nNavigate scene.\n\n**Definition:**\n\n```typescript\nasync nextScene (\n  ctx: object,\n  session?: object,      // {} by default\n): Promise\u003cBotact\u003e;\n```\n\n**Usage:**\n\n```javascript\nbot.addScene('wizard',\n  (ctx) =\u003e {\n    // with shortcut without additional settings\n    ctx.scene.next({ foo: 'bar' })\n    // simple usage with additional settings\n    bot.nextScene(ctx, { foo: 'bar' })\n  }\n)\n```\n\n### .leaveScene(ctx)\n\nLeave scene.\n\n**Definition:**\n\n```typescript\nasync leaveScene(\n  ctx: object\n): Promise\u003cBotact\u003e;\n```\n\n**Usage:**\n\n```javascript\nbot.addScene('wizard',\n  (ctx) =\u003e {\n    // with shortcut\n    ctx.scene.leave()\n    // simple usage\n    bot.leaveScene(ctx)\n  }\n)\n```\n\n--------------------------------------------------------------------------------\n\n## TypeScript\n\nBotact includes [TypeScript](https://www.typescriptlang.org/) definitions.\n\n## Tests\n\n**via npm:**\n\n```sh\n$ npm test\n```\n\n**via yarn:**\n\n```sh\n$ yarn test\n```\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbifot%2Fbotact","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbifot%2Fbotact","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbifot%2Fbotact/lists"}