Plugin API¶
The Plugin API provides the foundation for creating modular extensions for @axrxvm/betterdiscordjs bots. All plugins must extend the BasePlugin class.
BasePlugin Class¶
Constructor¶
new BasePlugin(bot, pluginManager)¶
Creates a new plugin instance.
Parameters:
- bot
(Bot) - The bot instance
- pluginManager
(PluginManager) - The plugin manager instance
Example:
const { BasePlugin } = require('@axrxvm/betterdiscordjs');
class MyPlugin extends BasePlugin {
constructor(bot, pluginManager) {
super(bot, pluginManager);
this.name = 'myplugin';
this.version = '1.0.0';
this.description = 'My awesome plugin';
}
}
Required Properties¶
plugin.name¶
- Type:
string
- Description: Unique plugin identifier
- Required: Yes
plugin.version¶
- Type:
string
- Description: Plugin version (semantic versioning recommended)
- Required: Yes
Optional Properties¶
plugin.description¶
- Type:
string
- Description: Plugin description
plugin.author¶
- Type:
string
- Description: Plugin author name
plugin.website¶
- Type:
string
- Description: Plugin website or repository URL
plugin.dependencies¶
- Type:
string[]
- Description: Array of required plugin names
plugin.enabled¶
- Type:
boolean
- Description: Whether plugin is enabled (default: true)
Available Properties¶
plugin.bot¶
- Type:
Bot
- Description: Access to the main bot instance
plugin.logger¶
- Type:
object
- Description: Plugin-specific logger with info, warn, error methods
plugin.config¶
- Type:
object
- Description: Plugin configuration manager
Lifecycle Methods¶
plugin.onLoad()¶
Called when the plugin is loaded. Use for initialization.
Returns: Promise<void>
Example:
async onLoad() {
this.logger.info(`${this.name} plugin loading...`);
// Initialize plugin resources
this.data = new Map();
// Register commands
this.registerCommand('mycommand', this.myCommandHandler.bind(this), {
description: 'My plugin command'
});
// Register events
this.registerEvent('messageCreate', this.onMessage.bind(this));
this.logger.info(`${this.name} plugin loaded successfully`);
}
plugin.onUnload()¶
Called when the plugin is unloaded. Use for cleanup.
Returns: Promise<void>
Example:
async onUnload() {
this.logger.info(`${this.name} plugin unloading...`);
// Cleanup resources
if (this.interval) {
clearInterval(this.interval);
}
// Close connections
if (this.connection) {
await this.connection.close();
}
this.logger.info(`${this.name} plugin unloaded`);
}
plugin.onEnable()¶
Called when the plugin is enabled.
Returns: Promise<void>
plugin.onDisable()¶
Called when the plugin is disabled.
Returns: Promise<void>
plugin.onReload()¶
Called when the plugin is reloaded.
Returns: Promise<void>
Command Registration¶
plugin.registerCommand(name, handler, options)¶
Register a command from within the plugin.
Parameters:
- name
(string) - Command name
- handler
(function) - Command handler function
- options
(object, optional) - Command options
Example:
this.registerCommand('weather', async (ctx) => {
const location = ctx.args.join(' ');
const weather = await this.getWeather(location);
await ctx.reply(`Weather in ${location}: ${weather}`);
}, {
description: 'Get weather information',
cooldown: '30s',
options: [{
name: 'location',
description: 'Location to get weather for',
type: 3,
required: true
}],
slash: true
});
plugin.unregisterCommand(name)¶
Remove a command registered by this plugin.
Parameters:
- name
(string) - Command name to remove
Event Registration¶
plugin.registerEvent(eventName, handler)¶
Register an event listener from within the plugin.
Parameters:
- eventName
(string) - Discord event name
- handler
(function) - Event handler function
Example:
this.registerEvent('guildMemberAdd', async (ctx) => {
const member = ctx.raw;
const welcomeChannel = member.guild.channels.cache.find(ch => ch.name === 'welcome');
if (welcomeChannel) {
await welcomeChannel.send(`Welcome ${member.user.tag}!`);
}
});
plugin.unregisterEvent(eventName, handler)¶
Remove an event listener registered by this plugin.
Parameters:
- eventName
(string) - Event name
- handler
(function) - Handler function to remove
Configuration Management¶
plugin.config.get(key, defaultValue)¶
Get a configuration value.
Parameters:
- key
(string) - Configuration key
- defaultValue
(any, optional) - Default value if key doesn't exist
Returns: any
Example:
const apiKey = this.config.get('apiKey', 'default-key');
const settings = this.config.get('settings', {
enabled: true,
timeout: 5000
});
plugin.config.set(key, value)¶
Set a configuration value.
Parameters:
- key
(string) - Configuration key
- value
(any) - Value to set
Example:
this.config.set('lastUpdate', Date.now());
this.config.set('userPreferences', {
theme: 'dark',
notifications: true
});
plugin.config.save()¶
Save configuration to disk.
Returns: Promise<void>
Example:
this.config.set('newSetting', 'value');
await this.config.save();
plugin.config.delete(key)¶
Delete a configuration key.
Parameters:
- key
(string) - Key to delete
plugin.config.has(key)¶
Check if configuration key exists.
Parameters:
- key
(string) - Key to check
Returns: boolean
Plugin Communication¶
plugin.getPlugin(name)¶
Get another plugin instance.
Parameters:
- name
(string) - Plugin name
Returns: BasePlugin | undefined
Example:
const economyPlugin = this.getPlugin('economy');
if (economyPlugin) {
const balance = await economyPlugin.getBalance(userId);
}
plugin.isPluginLoaded(name)¶
Check if a plugin is loaded.
Parameters:
- name
(string) - Plugin name
Returns: boolean
plugin.waitForPlugin(name, timeout)¶
Wait for a plugin to be loaded.
Parameters:
- name
(string) - Plugin name
- timeout
(number, optional) - Timeout in milliseconds
Returns: Promise<BasePlugin>
Database Integration¶
plugin.db¶
Access to the bot's database system (if available).
Example:
// Get user data
const userData = await this.bot.db.getUserData(userId);
// Set guild configuration
await this.bot.db.setGuildConfig(guildId, 'pluginSettings', settings);
Scheduling¶
plugin.schedule(interval, callback)¶
Schedule a recurring task.
Parameters:
- interval
(string|number) - Interval (e.g., '5m', 30000)
- callback
(function) - Function to execute
Returns: number
- Interval ID
Example:
// Schedule task every 5 minutes
this.schedule('5m', async () => {
await this.performMaintenance();
});
// Schedule task every 30 seconds
this.schedule(30000, () => {
this.updateStats();
});
plugin.scheduleOnce(delay, callback)¶
Schedule a one-time task.
Parameters:
- delay
(string|number) - Delay before execution
- callback
(function) - Function to execute
Returns: number
- Timeout ID
Error Handling¶
plugin.handleError(error, context)¶
Handle plugin errors gracefully.
Parameters:
- error
(Error) - The error that occurred
- context
(string, optional) - Error context
Example:
async myCommandHandler(ctx) {
try {
await this.performRiskyOperation();
} catch (error) {
this.handleError(error, 'myCommandHandler');
await ctx.error('Something went wrong!');
}
}
handleError(error, context = 'unknown') {
this.logger.error(`Error in ${context}:`, error);
// Optional: Send to error reporting service
if (this.config.get('errorReporting', false)) {
this.reportError(error, context);
}
}
Plugin Hooks¶
plugin.beforeCommand(handler)¶
Register before-command hook for this plugin.
Parameters:
- handler
(function) - Hook function
plugin.afterCommand(handler)¶
Register after-command hook for this plugin.
Parameters:
- handler
(function) - Hook function
Complete Plugin Example¶
const { BasePlugin } = require('@axrxvm/betterdiscordjs');
class WeatherPlugin extends BasePlugin {
constructor(bot, pluginManager) {
super(bot, pluginManager);
this.name = 'weather';
this.version = '1.2.0';
this.description = 'Weather information plugin';
this.author = 'Your Name';
this.dependencies = ['database'];
this.apiKey = null;
this.cache = new Map();
}
async onLoad() {
this.logger.info('Loading weather plugin...');
// Load configuration
this.apiKey = this.config.get('apiKey');
if (!this.apiKey) {
throw new Error('Weather API key not configured');
}
// Register commands
this.registerCommand('weather', this.weatherCommand.bind(this), {
description: 'Get weather information',
options: [{
name: 'location',
description: 'Location to get weather for',
type: 3,
required: true
}],
slash: true,
cooldown: '30s'
});
this.registerCommand('forecast', this.forecastCommand.bind(this), {
description: 'Get weather forecast',
options: [{
name: 'location',
description: 'Location to get forecast for',
type: 3,
required: true
}],
slash: true,
cooldown: '1m'
});
// Schedule cache cleanup every hour
this.schedule('1h', () => {
this.cleanupCache();
});
this.logger.info('Weather plugin loaded successfully');
}
async onUnload() {
this.logger.info('Unloading weather plugin...');
// Clear cache
this.cache.clear();
this.logger.info('Weather plugin unloaded');
}
async weatherCommand(ctx) {
const location = ctx.getOption('location');
try {
const weather = await this.getWeather(location);
const embed = ctx.embed()
.title(`🌤️ Weather in ${weather.location}`)
.field('Temperature', `${weather.temp}°C`, true)
.field('Condition', weather.condition, true)
.field('Humidity', `${weather.humidity}%`, true)
.field('Wind', `${weather.windSpeed} km/h`, true)
.color('blue')
.timestamp();
await embed.send();
} catch (error) {
this.handleError(error, 'weatherCommand');
await ctx.error('Failed to get weather information. Please try again.');
}
}
async forecastCommand(ctx) {
const location = ctx.getOption('location');
try {
const forecast = await this.getForecast(location);
const embed = ctx.embed()
.title(`📅 5-Day Forecast for ${forecast.location}`)
.color('blue');
forecast.days.forEach(day => {
embed.field(
day.date,
`${day.condition}\n${day.high}°C / ${day.low}°C`,
true
);
});
await embed.send();
} catch (error) {
this.handleError(error, 'forecastCommand');
await ctx.error('Failed to get weather forecast. Please try again.');
}
}
async getWeather(location) {
// Check cache first
const cacheKey = `weather:${location.toLowerCase()}`;
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < 600000) { // 10 minutes
return cached.data;
}
}
// Fetch from API
const response = await fetch(
`https://api.weather.com/v1/current?location=${encodeURIComponent(location)}&key=${this.apiKey}`
);
if (!response.ok) {
throw new Error(`Weather API error: ${response.status}`);
}
const data = await response.json();
// Cache the result
this.cache.set(cacheKey, {
data,
timestamp: Date.now()
});
return data;
}
async getForecast(location) {
// Similar implementation to getWeather but for forecast
// ... implementation details
}
cleanupCache() {
const now = Date.now();
const maxAge = 3600000; // 1 hour
for (const [key, value] of this.cache.entries()) {
if (now - value.timestamp > maxAge) {
this.cache.delete(key);
}
}
this.logger.info(`Cache cleanup completed. ${this.cache.size} entries remaining.`);
}
handleError(error, context) {
this.logger.error(`Weather plugin error in ${context}:`, error);
// Increment error counter
const errorCount = this.config.get('errorCount', 0) + 1;
this.config.set('errorCount', errorCount);
this.config.save();
}
}
module.exports = WeatherPlugin;
Best Practices¶
- Always call super() in constructor
- Handle errors gracefully in all methods
- Clean up resources in onUnload()
- Use plugin-specific logger for debugging
- Validate dependencies in onLoad()
- Use meaningful plugin names and versions
- Document your plugin's configuration options
- Implement proper error handling
- Use caching for expensive operations
- Follow semantic versioning for plugin versions## Ne xt Steps
Ready to build amazing plugins?
- 🔌 Creating Plugins - Step-by-step plugin development
- 📚 Plugin Examples - Real-world plugin implementations
- 🏗️ Built-in Plugins - Explore existing plugins
- 🚀 Advanced Use Cases - Complex plugin architectures