Add full JSDocs for the plugin API
parent
60ae79d4e4
commit
d5219556a7
|
@ -7,17 +7,11 @@ The path is relative to the bot's folder.
|
||||||
Plugins are automatically loaded on bot startup.
|
Plugins are automatically loaded on bot startup.
|
||||||
|
|
||||||
## Creating a plugin
|
## Creating a plugin
|
||||||
Create a `.js` file that exports a function.
|
Plugins are simply `.js` files that export a function that gets called when the plugin is loaded.
|
||||||
This function will be called when the plugin is loaded, with 1 argument: an object that has the following properties:
|
|
||||||
* `bot` - the [Eris Client object](https://abal.moe/Eris/docs/Client)
|
|
||||||
* `knex` - the [Knex database object](https://knexjs.org/#Builder)
|
|
||||||
* `config` - the loaded config
|
|
||||||
* `commands` - an object with functions to add and manage commands
|
|
||||||
* `attachments` - an object with functions to save attachments and manage attachment storage types
|
|
||||||
|
|
||||||
See [src/plugins.js#L4](../src/plugins.js#L4) for more details
|
For details about the function arguments, see [Plugin API](#plugin-api) below.
|
||||||
|
|
||||||
### Example plugin file
|
### Example plugin
|
||||||
This example adds a command `!mycommand` that replies with `"Reply from my custom plugin!"` when the command is used inside a modmail inbox thread channel.
|
This example adds a command `!mycommand` that replies with `"Reply from my custom plugin!"` when the command is used inside a modmail inbox thread channel.
|
||||||
```js
|
```js
|
||||||
module.exports = function({ bot, knex, config, commands }) {
|
module.exports = function({ bot, knex, config, commands }) {
|
||||||
|
@ -40,6 +34,36 @@ module.exports = function({ attachments }) {
|
||||||
```
|
```
|
||||||
To use this custom attachment storage type, you would set the `attachmentStorage` config option to `"original"`.
|
To use this custom attachment storage type, you would set the `attachmentStorage` config option to `"original"`.
|
||||||
|
|
||||||
|
### Plugin API
|
||||||
|
The first and only argument to the plugin function is an object with the following properties:
|
||||||
|
|
||||||
|
| Property | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `bot` | [Eris Client instance](https://abal.moe/Eris/docs/Client) |
|
||||||
|
| `knex` | [Knex database object](https://knexjs.org/#Builder) |
|
||||||
|
| `config` | The loaded config |
|
||||||
|
| `commands` | An object with functions to add and manage commands |
|
||||||
|
| `attachments` | An object with functions to save attachments and manage attachment storage types |
|
||||||
|
| — `addStorageType(name, handler)` | Function to add a new attachment storage type |
|
||||||
|
| — `downloadAttachment(attachment)` | Function to add a new attachment storage type |
|
||||||
|
|
||||||
|
* `bot` - the [Eris Client object](https://abal.moe/Eris/docs/Client)
|
||||||
|
* `knex` - the [Knex database object](https://knexjs.org/#Builder)
|
||||||
|
* `config` - the loaded config
|
||||||
|
* `commands` - an object with functions to add and manage commands
|
||||||
|
* `attachments` - an object with functions to save attachments and manage attachment storage types
|
||||||
|
* `attachments.addStorageType(name, handler)`
|
||||||
|
|
||||||
|
Create a `.js` file that exports a function.
|
||||||
|
This function will be called when the plugin is loaded, with 1 argument: an object that has the following properties:
|
||||||
|
* `bot` - the [Eris Client object](https://abal.moe/Eris/docs/Client)
|
||||||
|
* `knex` - the [Knex database object](https://knexjs.org/#Builder)
|
||||||
|
* `config` - the loaded config
|
||||||
|
* `commands` - an object with functions to add and manage commands
|
||||||
|
* `attachments` - an object with functions to save attachments and manage attachment storage types
|
||||||
|
|
||||||
|
See [src/plugins.js#L4](../src/plugins.js#L4) for more details
|
||||||
|
|
||||||
## Work in progress
|
## Work in progress
|
||||||
The current plugin API is fairly rudimentary and will be expanded on in the future.
|
The current plugin API is fairly rudimentary and will be expanded on in the future.
|
||||||
The API can change in non-major releases during this early stage. Keep an eye on [CHANGELOG.md](../CHANGELOG.md) for any changes.
|
The API can change in non-major releases during this early stage. Keep an eye on [CHANGELOG.md](../CHANGELOG.md) for any changes.
|
||||||
|
|
|
@ -5,6 +5,51 @@ const utils = require("./utils");
|
||||||
const threads = require("./data/threads");
|
const threads = require("./data/threads");
|
||||||
const Thread = require("./data/Thread");
|
const Thread = require("./data/Thread");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback CommandFn
|
||||||
|
* @param {Eris.Message} msg
|
||||||
|
* @param {object} args
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback InboxThreadCommandHandler
|
||||||
|
* @param {Eris.Message} msg
|
||||||
|
* @param {object} args
|
||||||
|
* @param {Thread} thread
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback AddGlobalCommandFn
|
||||||
|
* @param {string} trigger
|
||||||
|
* @param {string} parameters
|
||||||
|
* @param {CommandFn} handler
|
||||||
|
* @param {ICommandConfig} commandConfig
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback AddInboxServerCommandFn
|
||||||
|
* @param {string} trigger
|
||||||
|
* @param {string} parameters
|
||||||
|
* @param {CommandFn} handler
|
||||||
|
* @param {ICommandConfig} commandConfig
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback AddInboxThreadCommandFn
|
||||||
|
* Add a command that can only be invoked in a thread on the inbox server
|
||||||
|
*
|
||||||
|
* @param {string} trigger
|
||||||
|
* @param {string} parameters
|
||||||
|
* @param {InboxThreadCommandHandler} handler
|
||||||
|
* @param {ICommandConfig} commandConfig
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback AddAliasFn
|
||||||
|
* @param {string} originalCmd
|
||||||
|
* @param {string} alias
|
||||||
|
*/
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createCommandManager(bot) {
|
createCommandManager(bot) {
|
||||||
const manager = new CommandManager({
|
const manager = new CommandManager({
|
||||||
|
@ -52,6 +97,7 @@ module.exports = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a command that can be invoked anywhere
|
* Add a command that can be invoked anywhere
|
||||||
|
* @type {AddGlobalCommandFn}
|
||||||
*/
|
*/
|
||||||
const addGlobalCommand = (trigger, parameters, handler, commandConfig = {}) => {
|
const addGlobalCommand = (trigger, parameters, handler, commandConfig = {}) => {
|
||||||
let aliases = aliasMap.has(trigger) ? [...aliasMap.get(trigger)] : [];
|
let aliases = aliasMap.has(trigger) ? [...aliasMap.get(trigger)] : [];
|
||||||
|
@ -63,6 +109,7 @@ module.exports = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a command that can only be invoked on the inbox server
|
* Add a command that can only be invoked on the inbox server
|
||||||
|
* @type {AddInboxServerCommandFn}
|
||||||
*/
|
*/
|
||||||
const addInboxServerCommand = (trigger, parameters, handler, commandConfig = {}) => {
|
const addInboxServerCommand = (trigger, parameters, handler, commandConfig = {}) => {
|
||||||
const aliases = aliasMap.has(trigger) ? [...aliasMap.get(trigger)] : [];
|
const aliases = aliasMap.has(trigger) ? [...aliasMap.get(trigger)] : [];
|
||||||
|
@ -86,19 +133,9 @@ module.exports = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @callback InboxThreadCommandHandler
|
|
||||||
* @param {Eris.Message} msg
|
|
||||||
* @param {object} args
|
|
||||||
* @param {Thread} thread
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a command that can only be invoked in a thread on the inbox server
|
* Add a command that can only be invoked in a thread on the inbox server
|
||||||
* @param {string|RegExp} trigger
|
* @type {AddInboxThreadCommandFn}
|
||||||
* @param {string|IParameter[]} parameters
|
|
||||||
* @param {InboxThreadCommandHandler} handler
|
|
||||||
* @param {ICommandConfig} commandConfig
|
|
||||||
*/
|
*/
|
||||||
const addInboxThreadCommand = (trigger, parameters, handler, commandConfig = {}) => {
|
const addInboxThreadCommand = (trigger, parameters, handler, commandConfig = {}) => {
|
||||||
const aliases = aliasMap.has(trigger) ? [...aliasMap.get(trigger)] : [];
|
const aliases = aliasMap.has(trigger) ? [...aliasMap.get(trigger)] : [];
|
||||||
|
@ -124,6 +161,9 @@ module.exports = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {AddAliasFn}
|
||||||
|
*/
|
||||||
const addAlias = (originalCmd, alias) => {
|
const addAlias = (originalCmd, alias) => {
|
||||||
if (! aliasMap.has(originalCmd)) {
|
if (! aliasMap.has(originalCmd)) {
|
||||||
aliasMap.set(originalCmd, new Set());
|
aliasMap.set(originalCmd, new Set());
|
||||||
|
|
|
@ -26,21 +26,54 @@ function getErrorResult(msg = null) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An attachment storage option that simply forwards the original attachment URL
|
* @callback AddAttachmentStorageTypeFn
|
||||||
* @param {Eris.Attachment} attachment
|
* @param {string} name
|
||||||
* @returns {{url: string}}
|
* @param {AttachmentStorageTypeHandler} handler
|
||||||
*/
|
*/
|
||||||
function passthroughOriginalAttachment(attachment) {
|
|
||||||
|
/**
|
||||||
|
* @callback AttachmentStorageTypeHandler
|
||||||
|
* @param {Eris.Attachment} attachment
|
||||||
|
* @return {AttachmentStorageTypeResult|Promise<AttachmentStorageTypeResult>}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} AttachmentStorageTypeResult
|
||||||
|
* @property {string} url
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback DownloadAttachmentFn
|
||||||
|
* @param {Eris.Attachment} attachment
|
||||||
|
* @param {number?} tries Used internally, don't pass
|
||||||
|
* @return {Promise<DownloadAttachmentResult>}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} DownloadAttachmentResult
|
||||||
|
* @property {string} path
|
||||||
|
* @property {DownloadAttachmentCleanupFn} cleanup
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback DownloadAttachmentCleanupFn
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {AttachmentStorageTypeHandler}
|
||||||
|
*/
|
||||||
|
let passthroughOriginalAttachment; // Workaround to inconsistent IDE bug with @type and anonymous functions
|
||||||
|
passthroughOriginalAttachment = (attachment) => {
|
||||||
return { url: attachment.url };
|
return { url: attachment.url };
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An attachment storage option that downloads each attachment and serves them from a local web server
|
* An attachment storage option that downloads each attachment and serves them from a local web server
|
||||||
* @param {Eris.Attachment} attachment
|
* @type {AttachmentStorageTypeHandler}
|
||||||
* @param {Number=0} tries
|
|
||||||
* @returns {Promise<{ url: string }>}
|
|
||||||
*/
|
*/
|
||||||
async function saveLocalAttachment(attachment) {
|
let saveLocalAttachment; // Workaround to inconsistent IDE bug with @type and anonymous functions
|
||||||
|
saveLocalAttachment = async (attachment) => {
|
||||||
const targetPath = getLocalAttachmentPath(attachment.id);
|
const targetPath = getLocalAttachmentPath(attachment.id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -60,14 +93,12 @@ async function saveLocalAttachment(attachment) {
|
||||||
const url = await getLocalAttachmentUrl(attachment.id, attachment.filename);
|
const url = await getLocalAttachmentUrl(attachment.id, attachment.filename);
|
||||||
|
|
||||||
return { url };
|
return { url };
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Eris.Attachment} attachment
|
* @type {DownloadAttachmentFn}
|
||||||
* @param {Number} tries
|
|
||||||
* @returns {Promise<{ path: string, cleanup: function }>}
|
|
||||||
*/
|
*/
|
||||||
function downloadAttachment(attachment, tries = 0) {
|
const downloadAttachment = (attachment, tries = 0) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (tries > 3) {
|
if (tries > 3) {
|
||||||
console.error("Attachment download failed after 3 tries:", attachment);
|
console.error("Attachment download failed after 3 tries:", attachment);
|
||||||
|
@ -94,7 +125,7 @@ function downloadAttachment(attachment, tries = 0) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the filesystem path for the given attachment id
|
* Returns the filesystem path for the given attachment id
|
||||||
|
@ -119,10 +150,10 @@ function getLocalAttachmentUrl(attachmentId, desiredName = null) {
|
||||||
/**
|
/**
|
||||||
* An attachment storage option that downloads each attachment and re-posts them to a specified Discord channel.
|
* An attachment storage option that downloads each attachment and re-posts them to a specified Discord channel.
|
||||||
* The re-posted attachment is then linked in the actual thread.
|
* The re-posted attachment is then linked in the actual thread.
|
||||||
* @param {Eris.Attachment} attachment
|
* @type {AttachmentStorageTypeHandler}
|
||||||
* @returns {Promise<{ url: string }>}
|
|
||||||
*/
|
*/
|
||||||
async function saveDiscordAttachment(attachment) {
|
let saveDiscordAttachment; // Workaround to inconsistent IDE bug with @type and anonymous functions
|
||||||
|
saveDiscordAttachment = async (attachment) => {
|
||||||
if (attachment.size > 1024 * 1024 * 8) {
|
if (attachment.size > 1024 * 1024 * 8) {
|
||||||
return getErrorResult("attachment too large (max 8MB)");
|
return getErrorResult("attachment too large (max 8MB)");
|
||||||
}
|
}
|
||||||
|
@ -144,7 +175,7 @@ async function saveDiscordAttachment(attachment) {
|
||||||
if (! savedAttachment) return getErrorResult();
|
if (! savedAttachment) return getErrorResult();
|
||||||
|
|
||||||
return { url: savedAttachment.url };
|
return { url: savedAttachment.url };
|
||||||
}
|
};
|
||||||
|
|
||||||
async function createDiscordAttachmentMessage(channel, file, tries = 0) {
|
async function createDiscordAttachmentMessage(channel, file, tries = 0) {
|
||||||
tries++;
|
tries++;
|
||||||
|
@ -197,9 +228,12 @@ function saveAttachment(attachment) {
|
||||||
return attachmentSavePromises[attachment.id];
|
return attachmentSavePromises[attachment.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
function addStorageType(name, handler) {
|
/**
|
||||||
|
* @type AddAttachmentStorageTypeFn
|
||||||
|
*/
|
||||||
|
const addStorageType = (name, handler) => {
|
||||||
attachmentStorageTypes[name] = handler;
|
attachmentStorageTypes[name] = handler;
|
||||||
}
|
};
|
||||||
|
|
||||||
addStorageType("original", passthroughOriginalAttachment);
|
addStorageType("original", passthroughOriginalAttachment);
|
||||||
addStorageType("local", saveLocalAttachment);
|
addStorageType("local", saveLocalAttachment);
|
||||||
|
|
|
@ -212,6 +212,20 @@ const defaultFormatters = {
|
||||||
*/
|
*/
|
||||||
const formatters = { ...defaultFormatters };
|
const formatters = { ...defaultFormatters };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} FormattersExport
|
||||||
|
* @property {MessageFormatters} formatters Read only
|
||||||
|
* @property {function(FormatStaffReplyDM): void} setStaffReplyDMFormatter
|
||||||
|
* @property {function(FormatStaffReplyThreadMessage): void} setStaffReplyThreadMessageFormatter
|
||||||
|
* @property {function(FormatUserReplyThreadMessage): void} setUserReplyThreadMessageFormatter
|
||||||
|
* @property {function(FormatStaffReplyEditNotificationThreadMessage): void} setStaffReplyEditNotificationThreadMessageFormatter
|
||||||
|
* @property {function(FormatStaffReplyDeletionNotificationThreadMessage): void} setStaffReplyDeletionNotificationThreadMessageFormatter
|
||||||
|
* @property {function(FormatLog): void} setLogFormatter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {FormattersExport}
|
||||||
|
*/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
formatters: new Proxy(formatters, {
|
formatters: new Proxy(formatters, {
|
||||||
set() {
|
set() {
|
||||||
|
@ -219,50 +233,26 @@ module.exports = {
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {FormatStaffReplyDM} fn
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
setStaffReplyDMFormatter(fn) {
|
setStaffReplyDMFormatter(fn) {
|
||||||
formatters.formatStaffReplyDM = fn;
|
formatters.formatStaffReplyDM = fn;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {FormatStaffReplyThreadMessage} fn
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
setStaffReplyThreadMessageFormatter(fn) {
|
setStaffReplyThreadMessageFormatter(fn) {
|
||||||
formatters.formatStaffReplyThreadMessage = fn;
|
formatters.formatStaffReplyThreadMessage = fn;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {FormatUserReplyThreadMessage} fn
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
setUserReplyThreadMessageFormatter(fn) {
|
setUserReplyThreadMessageFormatter(fn) {
|
||||||
formatters.formatUserReplyThreadMessage = fn;
|
formatters.formatUserReplyThreadMessage = fn;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {FormatStaffReplyEditNotificationThreadMessage} fn
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
setStaffReplyEditNotificationThreadMessageFormatter(fn) {
|
setStaffReplyEditNotificationThreadMessageFormatter(fn) {
|
||||||
formatters.formatStaffReplyEditNotificationThreadMessage = fn;
|
formatters.formatStaffReplyEditNotificationThreadMessage = fn;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {FormatStaffReplyDeletionNotificationThreadMessage} fn
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
setStaffReplyDeletionNotificationThreadMessageFormatter(fn) {
|
setStaffReplyDeletionNotificationThreadMessageFormatter(fn) {
|
||||||
formatters.formatStaffReplyDeletionNotificationThreadMessage = fn;
|
formatters.formatStaffReplyDeletionNotificationThreadMessage = fn;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {FormatLog} fn
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
setLogFormatter(fn) {
|
setLogFormatter(fn) {
|
||||||
formatters.formatLog = fn;
|
formatters.formatLog = fn;
|
||||||
},
|
},
|
||||||
|
|
|
@ -26,17 +26,24 @@ const Eris = require("eris");
|
||||||
* @return {void|Promise<void>}
|
* @return {void|Promise<void>}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback AddBeforeNewThreadHookFn
|
||||||
|
* @param {BeforeNewThreadHookData} fn
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type BeforeNewThreadHookData[]
|
* @type BeforeNewThreadHookData[]
|
||||||
*/
|
*/
|
||||||
const beforeNewThreadHooks = [];
|
const beforeNewThreadHooks = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {BeforeNewThreadHookData} fn
|
* @type {AddBeforeNewThreadHookFn}
|
||||||
*/
|
*/
|
||||||
function beforeNewThread(fn) {
|
let beforeNewThread; // Workaround to inconsistent IDE bug with @type and anonymous functions
|
||||||
|
beforeNewThread = (fn) => {
|
||||||
beforeNewThreadHooks.push(fn);
|
beforeNewThreadHooks.push(fn);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {{
|
* @param {{
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
const { CommandManager } = require("knub-command-manager");
|
||||||
|
const { Client } = require("eris");
|
||||||
|
const Knex = require("knex");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} PluginAPI
|
||||||
|
* @property {Client} bot
|
||||||
|
* @property {Knex} knex
|
||||||
|
* @property {ModmailConfig} config
|
||||||
|
* @property {PluginCommandsAPI} commands
|
||||||
|
* @property {PluginAttachmentsAPI} attachments
|
||||||
|
* @property {PluginHooksAPI} hooks
|
||||||
|
* @property {FormattersExport} formats
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} PluginCommandsAPI
|
||||||
|
* @property {CommandManager} manager
|
||||||
|
* @property {AddGlobalCommandFn} addGlobalCommand
|
||||||
|
* @property {AddInboxServerCommandFn} addInboxServerCommand
|
||||||
|
* @property {AddInboxThreadCommandFn} addInboxThreadCommand
|
||||||
|
* @property {AddAliasFn} addAlias
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} PluginAttachmentsAPI
|
||||||
|
* @property {AddAttachmentStorageTypeFn} addStorageType
|
||||||
|
* @property {DownloadAttachmentFn} downloadAttachment
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} PluginHooksAPI
|
||||||
|
* @property {AddBeforeNewThreadHookFn} beforeNewThread
|
||||||
|
*/
|
|
@ -3,6 +3,13 @@ const { beforeNewThread } = require("./hooks/beforeNewThread");
|
||||||
const formats = require("./formatters");
|
const formats = require("./formatters");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* @param bot
|
||||||
|
* @param knex
|
||||||
|
* @param config
|
||||||
|
* @param commands
|
||||||
|
* @returns {PluginAPI}
|
||||||
|
*/
|
||||||
getPluginAPI({ bot, knex, config, commands }) {
|
getPluginAPI({ bot, knex, config, commands }) {
|
||||||
return {
|
return {
|
||||||
bot,
|
bot,
|
||||||
|
|
Loading…
Reference in New Issue