Package Exports
- offdjs
- offdjs/lib/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (offdjs) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
About
offdjs is a small framework that uses discord.js created to solve the needs and simplify the development of the Oneki bot made public so that anyone can create their own bot in a few lines of code
- little
- fast
- easy to use
- 0 config
Installation
Node.js 18.12 or newer is required.
npm install offdjs
Example usage
Set your token in an .env file at the root of the project (according to discord.js specs)
DISCORD_TOKEN="your_discord_token"
At this point you can run your script from the root of your project and the bot will turn on without requiring any configuration or installing anything at all.
npx offdjs
You can also install offdjs locally and add it to your scripts in the
package.json
.
{
"scripts": {
"start": "offdjs"
}
}
Events
To load events you just need to create a folder in the root called events
and offdjs will read all the .js
files; (custom events also work). offdjs can read subfolders inside the events
folder for easy event organisation. offdjs will register the file name as event name.
example:
.
├── events
│ ├── ready.js
│ └── guild
│ ├── guildMemberAdd.js
│ └── guildMemberRemove.js
├── node_modules
│ └── ...
├── .env
└── package.json
The script must export a handler
function to be executed with the parameters of such an event
// events/ready.js
export function handler(client) {
console.log('ready')
}
Optionally, you can export an once
constant with true
or false
if you require it to be recorded as a once event. If you need to register several handlers for the same event you also have the option of exporting a name constant where you will explicitly declare the name of the event you need to subscribe to and offdjs will omit the file name and replace it with that constant.
// events/other_ready.js
import { Events } from 'discord.js'
export const name = Events.ClientReady
export const once = true
export function handler(client) {
console.log('ready again')
}
Interactions
Receiving interactions is similar to events. You need to export a handler
function that will receive the interaction as a parameter.
You also need to export a constant name
which can be of type string
or RegExp
; this constant, similar to events, will be compared with the id of the interaction or name of the command.
If the interaction has a custom id, the handler receives as parameters the id separated by :
.
The name of the folder depends on the type of interaction y al igual que los eventos, los scripts pueden estar dentro de subcarpetas. Here are examples of the different types:
Buttons
For buttons, the folder name is buttons
.
.
├── buttons
│ └── confirm_ban.js
├── node_modules
│ └── ...
├── .env
└── package.json
// confirm_ban.js
export const name = /ban:\d{18,19}/
/**
* @param {ButtonInteraction} interaction - djs interaction object
* @param {'ban'} _ - in this case always is 'ban'
* @param {string} id - the id of the member to ban
*/
export function handler(interaction, _, id) {
// example code
const user = interaction.guild?.members.ban(id)
interaction.reply({
content: `User ${user} banned successfully`,
})
}
Select Menus
For selection menus, the folder name is menus
, they receive any selectable menu, whether string, channel, role, user and mentionable menus.
.
├── menus
│ └── config
│ └── welcome_channel.js
├── node_modules
│ └── ...
├── .env
└── package.json
// welcome_channel.js
export const name = 'config:welcome_channel'
/**
* @param {AnySelectMenuInteraction} interaction - djs interaction object
*/
export function handler(interaction) {
// example code
if (!interaction.isChannelSelectMenu()) return
const channel = interaction.channels.first()
interaction.client.configWelcomeChannel(channel)
interaction.reply({
content: `welcomes are now displayed in ${channel}`,
})
}
Modals
For modals it is very similar to buttons and the name of the folder is surprisingly modals
.
.
├── modals
│ └── secret.js
├── node_modules
│ └── ...
├── .env
└── package.json
// secret.js
export const name = 'secret'
/**
* @param {ModalSubmitInteraction} interaction - djs interaction object
*/
export function handler(interaction) {
// example code
const secret = interaction.fields.getTextInputValue('secret')
interaction.client.publishSecret(secret)
interaction.reply({
content: 'Your secret was published anonymously',
ephemeral: true,
})
}
Context Menus
For context menu commands the folder shall be named context
and shall receive both user context interactions and message context interactions.
.
├── contexts
│ └── warn.js
├── node_modules
│ └── ...
├── .env
└── package.json
// warn.js
export const name = 'warn'
/**
* @param {ContextMenuCommandInteraction} interaction - djs interaction object
*/
export function handler(interaction) {
// example code
interaction.showModal(
new ModalBuilder()
.setTitle(`Warn ${interaction.target.displayName}`)
.setCustomId(`warn:${interaction.target.id}`)
.setComponents(
new ActionRowBuilder<TextInputBuilder>().setComponents(
new TextInputBuilder()
.setCustomId('reason')
.setLabel('Reason')
.setRequired()
.setStyle(TextInputStyle.Paragraph)
)
)
)
}
Commands
For commands the folder is called commands
, these can export a third property called command
of type ApplicationCommandDataResolvable
which will be the command that the client will automatically register in each of the guilds. The command
property is optional. The command name, subcommand and group shall also be received in the function parameters as a custom id. If the command contains subcommands and/or groups, the name
property separates them with :
as if they were buttons.
.
├── commands
│ └── poll.js
├── node_modules
│ └── ...
├── .env
└── package.json
// secret.js
export const name = /poll:(create|finish)/
export const command =
new SlashCommandBuilder()
.setName('poll')
.setDescription('Create or finish a poll')
.addSubcommand(subcommand =>
subcommand
.setName('create')
.setDescription('Create a poll')
.addStringOption(option =>
option
.setName('question')
.setDescription('The question to ask')
.setRequired(true)
)
)
.addSubcommand(subcommand =>
subcommand
.setName('finish')
.setDescription('Finish a poll')
.addStringOption(option =>
option
.setName('poll')
.setDescription('The id of the poll to finish')
.setRequired(true)
.setAutocomplete(true)
)
)
/**
* @param {ChatInputCommandInteraction} interaction - djs interaction object
* @param {'poll'} _ - in this case always is 'poll'
* @param {'create' | 'finish'} subcommand - the id of the member to ban
*/
export function handler(interaction, _, subcommand) {
// example code
if (subcommand === 'create') return interaction.client.newPoll(interaction)
const pollId = interaction.options.getString('poll')
interaction.client.finishPoll(pollId)
interaction.reply({
'Poll finished'
})
}
Autocompletes
For autocompletes the folder is called autocompletes
and they behave similar to commands except that they do not export the command
property. If the command contains subcommands and/or groups, the name
property separates them with :
as if they were buttons. The name of the command, subcommand and group will also be received in the function parameters as a custom id.
.
├── commands
│ └── poll.js
├── node_modules
│ └── ...
├── .env
└── package.json
// secret.js
export const name = 'poll:finish'
/**
* @param {AutocompleteInteraction} interaction - djs interaction object
*/
export function handler(interaction) {
// example code
const polls = interaction.client.polls
.search(interaction.options.getFocused())
.map(p => ({ value: p.id, name: p.name }))
interaction.respond(polls)
}