Skip to main content

Plugin data

Many functions, such as beforeLoad(), afterLoad(), command run(), event listener listener(), etc. receive an object called pluginData as one of their arguments.

This object is the "heart" of a plugin. It contains:

  • The plugin's config (pluginData.config)
  • Helpers (pluginData.locks, pluginData.cooldowns)
  • Access plugin dependencies (pluginData.getPlugin())
  • Any custom internal state (pluginData.state)

If a function your plugin uses requires access to e.g. the plugin's config, you can pass this object to it.

Config

You can use the pluginData.config object to access the plugin's config. This object contains several functions that can be used to get the config with or without overrides applied:

pluginData.config.get(): config

Returns the plugin's config without any overrides applied

pluginData.config.getForMessage(message): Promise<config>

(Async) Returns the plugin's config with overrides applied based on the input message

pluginData.config.getForChannel(channel): Promise<config>

(Async) Returns the plugin's config with overrides applied based on the input channel

pluginData.config.getForUser(user): Promise<config>

(Async) Returns the plugin's config with overrides applied based on the input user

pluginData.config.getForMember(member): Promise<config>

(Async) Returns the plugin's config with overrides applied based on the input member

pluginData.config.getMatchingConfig(matchParams): Promise<config>

(Async) Returns the plugin's config with overrides applied based on the supplied match parameters. See the type of matchParams for more details on what data can be passed.

Custom state

One point mentioned above was custom internal state. In many cases, you want to store some state with your plugin. This state can be accessed via pluginData.state and you can use a PluginType type to specify its type:

import { BasePluginType, guildPluginSlashCommand, guildPlugin } from "knub";

interface MyPluginType extends BasePluginType {
state: {
counter: number;
};
}

const counterCmd = guildPluginSlashCommand({
name: "counter",
description: "Add one to the counter",
signature: [],
run({ interaction, pluginData }) {
// Increment the counter in the plugin's internal state
pluginData.state.counter++;
// Report the current value back to the command user
interaction.reply(`The counter is now: ${pluginData.state.counter}`);
},
});

const counterPlugin = guildPlugin<MyPluginType>()({
name: "counter",
slashCommands: [
counterCmd,
],
beforeLoad(pluginData) {
// Initialize the counter
pluginData.state.counter = 0;
},
});

Remember to initialize the state in beforeLoad() to avoid runtime errors!

Note: The state is only stored in memory and lost any time the plugin is reloaded or the bot is restarted, so don't use it for long-term storage.

When passing the pluginData object around, you want to make sure you still get full type checks everywhere. To do this, you can use the GuildPluginData<T> type in your function parameters:

import { BasePluginType, GuildPluginData, guildPluginSlashCommand } from "knub";

interface MyPluginType extends BasePluginType {
state: {
counter: number;
};
}

function incrementCounter(pluginData: GuildPluginData<MyPluginType>) {
// The type of "pluginData.state" is now based on MyPluginType
pluginData.state.counter++;
}

const counterCmd = guildPluginSlashCommand({
name: "counter",
description: "Add one to the counter",
signature: [],
run({ interaction, pluginData }) {
// Call our increment function instead
incrementCounter(pluginData);
// Report the current value back to the command user
interaction.reply(`The counter is now: ${pluginData.state.counter}`);
},
});