# 🔌 Creating Plugins Complete guide to creating plugins in ManyBot. --- ## 📑 Index - [Basic Structure](#basic-structure) - [Plugin Manifest](#plugin-manifest-manyplug-json) - [Creating Your First Plugin](#creating-your-first-plugin) - [Object API](#object-api) - [Exposing API](#exposing-api-to-other-plugins) - [Translating Your Plugin](#translating-your-plugin) - [Error Handling](#error-handling) --- ## Basic Structure ``` src/plugins/ └── my-plugin/ ├── index.js ├── manyplug.json └── locale/ (optional) ├── en.json ├── pt.json └── es.json ``` `index.js` must export a `default` function that receives `{ msg, api }`: ```javascript export default async function ({ msg, api }) { // Your logic here } ``` --- ## Plugin Manifest (manyplug.json) Every plugin should have a `manyplug.json` at its root. It describes the plugin and declares any extra npm dependencies it needs. ```json { "name": "my-plugin", "version": "1.0.0", "category": "utility", "service": false, "dependencies": {} } ``` ### Fields | Field | Type | Description | |-------|------|-------------| | `name` | `string` | Plugin identifier, must match the folder name | | `version` | `string` | Semantic version (e.g., `"1.0.0"`) | | `category` | `string` | Plugin category: `utility`, `media`, `game`, `humor`, `info` | | `service` | `boolean` | `true` if the plugin runs in the background (scheduler, listener). `false` if triggered by a command or event | | `dependencies` | `object` | Extra npm packages required by the plugin, same format as `package.json` | ### Example with dependencies ```json { "name": "weather", "version": "1.0.0", "category": "utility", "service": false, "dependencies": { "axios": "^1.6.0" } } ``` After adding dependencies, run `npm install` at the project root to install them. --- ## Creating Your First Plugin ### Example 1: Simple command ```javascript // plugins/greeting/index.js import { CMD_PREFIX } from "../../config.js"; export default async function ({ msg, api }) { // Only responds if the message starts with "!hi" if (!msg.is(CMD_PREFIX + "hi")) return; await msg.reply("Hello! 👋"); } ``` ### Example 2: Command with arguments ```javascript // plugins/calculate/index.js import { CMD_PREFIX } from "../../config.js"; export default async function ({ msg, api }) { if (!msg.is(CMD_PREFIX + "calculate")) return; // msg.args = ["!calculate", "5", "+", "3"] const [, a, operator, b] = msg.args; let result; switch (operator) { case "+": result = Number(a) + Number(b); break; case "-": result = Number(a) - Number(b); break; case "*": result = Number(a) * Number(b); break; case "/": result = Number(a) / Number(b); break; default: return msg.reply("Invalid operator!"); } await msg.reply(`Result: ${result}`); } ``` ### Example 3: Processing media ```javascript // plugins/echo-media/index.js import { CMD_PREFIX } from "../../config.js"; export default async function ({ msg, api }) { if (!msg.is(CMD_PREFIX + "echo")) return; // Checks if the message has media if (!msg.hasMedia) { return msg.reply("Send a media file with the command!"); } // Downloads the media const media = await msg.downloadMedia(); // Resends in the chat await api.sendSticker(media.data); } ``` --- ## Object API ### `msg` Object | Property | Type | Description | |----------|------|-------------| | `msg.body` | `string` | Message text | | `msg.args` | `string[]` | Message tokens | | `msg.type` | `string` | Type: `chat`, `image`, `video`, `audio`, `sticker` | | `msg.sender` | `string` | Sender ID | | `msg.senderName` | `string` | Sender name | | `msg.fromMe` | `boolean` | Whether the bot sent it | | `msg.hasMedia` | `boolean` | Whether it has media | | `msg.hasReply` | `boolean` | Whether it is a reply | | `msg.isGif` | `boolean` | Whether it is a GIF | | `msg.is(cmd)` | `function` | Checks if starts with command | | `msg.reply(text)` | `function` | Replies with quote | | `msg.downloadMedia()` | `function` | Returns `{ mimetype, data }` | | `msg.getReply()` | `function` | Returns quoted message | ### `api` Object | Method | Description | |--------|-------------| | `api.send(text)` | Sends text | | `api.sendVideo(path)` | Sends video | | `api.sendAudio(path)` | Sends audio (voice) | | `api.sendImage(path, caption?)` | Sends image | | `api.sendSticker(bufferOrPath)` | Sends sticker | | `api.getPlugin(name)` | Accesses another plugin | | `api.chat.id` | Chat ID | | `api.chat.name` | Chat name | | `api.chat.isGroup` | Whether it is a group | | `api.log.info(...)` | Info log | | `api.log.warn(...)` | Warning log | | `api.log.error(...)` | Error log | --- ## Exposing API to Other Plugins A plugin can export functions for others to use: ```javascript // plugins/utilities/index.js // Public API export const api = { formatDate: (date) => date.toLocaleDateString("en-US"), formatCurrency: (value) => `$${value.toFixed(2)}`, wait: (ms) => new Promise(resolve => setTimeout(resolve, ms)) }; // Normal plugin logic export default async function ({ msg }) { if (msg.is("!ping")) { await msg.reply("pong!"); } } ``` Another plugin using it: ```javascript // plugins/other/index.js export default async function ({ msg, api }) { const utils = api.getPlugin("utilities"); const date = utils.formatDate(new Date()); await msg.reply(`Today is ${date}`); } ``` --- ## Translating Your Plugin Each plugin can have its own translations, completely independent from the bot core. The bot locale (set in `manybot.conf`) is used automatically. ### Structure ``` src/plugins/ └── my-plugin/ ├── index.js └── locale/ ├── en.json ├── pt.json └── es.json ``` ### locale/en.json ```json { "hello": "Hello, {{name}}! 👋", "error": { "notFound": "Item not found." } } ``` ### index.js ```javascript import { CMD_PREFIX } from "../../config.js"; import { createPluginI18n } from "../../utils/pluginI18n.js"; const { t } = createPluginI18n(import.meta.url); export default async function ({ msg }) { if (!msg.is(CMD_PREFIX + "hi")) return; // Simple key await msg.reply(t("hello", { name: msg.senderName })); // Nested key await msg.reply(t("error.notFound")); } ``` ### Notes - If the configured locale has no translation file, falls back to `en.json`. - If the key doesn't exist in any file, the key itself is returned as-is. - Use `{{variable}}` syntax for interpolation. - Each plugin manages its own translations — never import `t` from the bot core. --- ## Error Handling If a plugin throws an error, the kernel automatically disables it: ```javascript export default async function ({ msg, api }) { try { // Code that might fail const result = await somethingRisky(); await msg.reply(result); } catch (error) { // Logs the error and notifies api.log.error("Plugin error:", error); await msg.reply("Oops! Something went wrong."); } } ``` --- ## Enabling the Plugin After creating it, add to `manybot.conf`: ```bash PLUGINS=[ # ... other plugins my-plugin ] ``` Restart the bot to load it. --- ## See Also - [API Reference](./API.md) - [Plugin examples](../src/plugins/)